private Node ReadWord(ReadParams p, DataType refDataType) { var code = p.Code; var word = code.Text; var wordSpan = code.Span; if (code.ReadExact('(')) { // This is a function call switch (word) { case "avg": case "count": case "sum": case "max": case "min": return(AggregateFunctionCallNode.Read(p, wordSpan, word)); } return(FunctionCallNode.Read(p, wordSpan, word)); } if (code.ReadExact('.')) { var dotSpan = code.Span; if (code.ReadWord()) { var childWord = code.Text; var combinedWord = string.Concat(word, ".", childWord); var combinedSpan = wordSpan.Envelope(code.Span); if (code.ReadExact('(')) { foreach (var parentDef in (from d in p.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetAny(code.Position + p.FuncOffset, word) where d.AllowsChild select d)) { var childDef = parentDef.ChildDefinitions.FirstOrDefault(c => c.Name == childWord && c.ArgumentsRequired); if (childDef != null) { return(FunctionCallNode.Read(p, combinedSpan, combinedWord, childDef)); } } ReportError(combinedSpan, CAError.CA0003, combinedWord); // Function '{0}' not found. return(new UnknownNode(p.Statement, combinedSpan, combinedWord)); } else // No opening bracket { foreach (var parentDef in (from d in p.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetAny(code.Position + p.FuncOffset, word) where d.AllowsChild select d)) { var childDef = parentDef.ChildDefinitions.FirstOrDefault(c => c.Name == childWord && !c.ArgumentsRequired); if (childDef != null) { return(TryReadSubscript(p, combinedSpan, combinedWord, childDef)); } } ReportError(combinedSpan, CAError.CA0001, combinedWord); // Unknown '{0}'. return(new UnknownNode(p.Statement, combinedSpan, combinedWord)); } } else // No word after dot { ReportError(dotSpan, CAError.CA0004); // Expected identifier to follow '.' return(new UnknownNode(p.Statement, wordSpan.Envelope(dotSpan), string.Concat(word, "."))); } } // Try to read array accessor if (code.PeekExact('[')) { // Read a list of array accessors with a single expression var arrayResetPos = code.TokenStartPostion; var arrayExps = new List <ExpressionNode[]>(); var lastArrayStartPos = code.Position; while (!code.EndOfFile) { lastArrayStartPos = code.Position; if (code.ReadExact('[')) { var exp1 = ExpressionNode.Read(p, null, "]", ","); if (exp1 != null) { if (code.ReadExact(']')) { // Brackets with single expression arrayExps.Add(new ExpressionNode[] { exp1 }); } else if (code.ReadExact(',')) { var exp2 = ExpressionNode.Read(p, null, "]"); if (exp2 != null) { if (code.ReadExact(']')) { arrayExps.Add(new ExpressionNode[] { exp1, exp2 }); } else { code.Position = lastArrayStartPos; break; } } else { code.Position = lastArrayStartPos; break; } } else { code.Position = lastArrayStartPos; break; } } else { code.Position = lastArrayStartPos; break; } } else { break; } } var defs = p.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetAny(code.Position + p.FuncOffset, word).ToArray(); // Try to match to a variable defined as an array if (arrayExps.Count > 0) { // Check if it's a variable being accessed foreach (var def in defs) { if (def is VariableDefinition) { var vardef = def as VariableDefinition; var arrayLengths = vardef.ArrayLengths; if (arrayLengths == null) { continue; } if (arrayLengths.Length == arrayExps.Count && arrayExps.All(x => x.Length == 1)) { return(new IdentifierNode(p.Statement, wordSpan, word, def, (from e in arrayExps select e[0]))); } else if (arrayLengths.Length == arrayExps.Count - 1 && vardef.DataType != null && vardef.DataType.AllowsSubscript && arrayExps.Take(arrayLengths.Length).All(x => x.Length == 1)) { // Last array accessor is a string subscript return(new IdentifierNode(p.Statement, wordSpan, word, def, (from e in arrayExps.Take(arrayExps.Count - 1) select e[0]), arrayExps.Last())); } } } } // Try to match to a string that allows a subscript with 1 or 2 arguments code.Position = arrayResetPos; var subDef = (from d in defs where d.DataType != null && d.DataType.AllowsSubscript select d).FirstOrDefault(); if (subDef != null) { return(TryReadSubscript(p, wordSpan, word, subDef)); } } if (refDataType != null) { if (refDataType.HasCompletionOptions) { var enumOptDef = refDataType.GetEnumOption(word); if (enumOptDef != null) { return(new IdentifierNode(p.Statement, wordSpan, word, enumOptDef)); } } switch (refDataType.ValueType) { case ValType.Table: { var table = DkDict.Dict.GetTable(word); if (table != null) { return(new IdentifierNode(p.Statement, wordSpan, word, table.Definition)); } var indrel = DkDict.Dict.GetRelInd(word); if (indrel != null) { return(new IdentifierNode(p.Statement, wordSpan, word, indrel.Definition)); } } break; case ValType.IndRel: { var indrel = DkDict.Dict.GetRelInd(word); if (indrel != null) { return(new IdentifierNode(p.Statement, wordSpan, word, indrel.Definition)); } } break; } } var wordDefs = (from d in p.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetAny(code.Position + p.FuncOffset, word) where !d.RequiresChild && !d.ArgumentsRequired && !d.RequiresRefDataType orderby d.SelectionOrder descending select d).ToArray(); if (wordDefs.Length > 0) { return(new IdentifierNode(p.Statement, wordSpan, word, wordDefs[0])); } return(new UnknownNode(p.Statement, wordSpan, word)); // Single word. Don't attempt to find the definition now because it could be an enum option. //return new IdentifierNode(p.Statement, wordSpan, word, null); }