private Node ReadNestable(ReadParams p, DataType refDataType, Span openSpan, string text, string[] stopStrings) { GroupNode groupNode; string endText; switch (text) { case "(": groupNode = new BracketsNode(p.Statement, openSpan); endText = ")"; break; default: throw new ArgumentOutOfRangeException("text"); } if (stopStrings == null) { stopStrings = new string[] { endText } } ; else { stopStrings = stopStrings.Concat(new string[] { endText }).ToArray(); } while (!p.Code.EndOfFile) { if (p.Code.ReadExact(endText)) { groupNode.Span = groupNode.Span.Envelope(p.Code.Span); break; } var exp = ExpressionNode.Read(p, refDataType, stopStrings); if (exp == null) { break; } groupNode.AddChild(exp); } return(groupNode); }
public static ConditionalNode Read(ReadParams p, DataType refDataType, Span opSpan, string[] stopStrings) { var code = p.Code; var ret = new ConditionalNode(p.Statement, opSpan); var condStopStrings = stopStrings == null || stopStrings.Length == 0 ? s_stopStrings : stopStrings.Concat(s_stopStrings).ToArray(); var trueExp = ExpressionNode.Read(p, refDataType, condStopStrings); if (trueExp == null) { p.Statement.ReportError(new Span(code.Position, code.Position + 1), CAError.CA0042); // Expected value to follow conditional '?'. return(ret); } ret._trueExp = trueExp; if (!code.ReadExact(':')) { p.Statement.ReportError(new Span(code.Position, code.Position + 1), CAError.CA0041); // Expected ':' to follow conditional result. return(ret); } var falseExp = ExpressionNode.Read(p, refDataType, condStopStrings); if (falseExp == null) { p.Statement.ReportError(new Span(code.Position, code.Position + 1), CAError.CA0043); // Expected value to follow conditional ':'. return(ret); } if (code.ReadExact('?')) { // Stacked conditional var group = new GroupNode(p.Statement, null); group.AddChild(falseExp); group.AddChild(ConditionalNode.Read(p, refDataType, code.Span, stopStrings)); ret._falseExp = group; } else { ret._falseExp = falseExp; } return(ret); }
private IdentifierNode TryReadSubscript(ReadParams p, Span nameSpan, string name, Definition def) { if (def.DataType == null || def.DataType.AllowsSubscript == false) { return(new IdentifierNode(p.Statement, nameSpan, name, def)); } var code = p.Code; var resetPos = code.Position; if (code.ReadExact('[')) { var exp1 = ExpressionNode.Read(p, null, "]", ","); if (exp1 != null) { if (code.ReadExact(',')) { var exp2 = ExpressionNode.Read(p, null, "]", ","); if (exp2 != null) { if (code.ReadExact(']')) { return(new IdentifierNode(p.Statement, nameSpan, name, def, subscriptAccessExps: new ExpressionNode[] { exp1, exp2 })); } } } else if (code.ReadExact(']')) { return(new IdentifierNode(p.Statement, nameSpan, name, def, subscriptAccessExps: new ExpressionNode[] { exp1 })); } } } // No match; reset back to before the array accessors started code.Position = resetPos; return(new IdentifierNode(p.Statement, nameSpan, name, def)); }
public static AggregateFunctionCallNode Read(ReadParams p, Span funcNameSpan, string funcName) { var ret = new AggregateFunctionCallNode(p.Statement, funcNameSpan, funcName); var code = p.Code; if (funcName == "count") { if (!code.ReadExact('*')) { ret.ReportError(CAError.CA0060); // Expected '*' in count(). return(ret); } } else { var exp = ExpressionNode.Read(p, null, ",", ")"); if (exp == null) { ret.ReportError(CAError.CA0061); // Expected aggregate expression. return(ret); } ret._aggExp = exp; } while (!code.EndOfFile) { if (code.ReadExact(')')) { break; } if (code.ReadExact(',')) { if (code.ReadExactWholeWord("where")) { var exp = ExpressionNode.Read(p, null, ",", ")"); if (exp == null) { ret.ReportError(code.Span, CAError.CA0062, "where"); // Expected expression to follow '{0}'. return(ret); } ret._whereExp = exp; } else if (code.ReadExactWholeWord("group")) { var startPos = code.Position; if (code.ReadWord()) { var tableDef = (from d in p.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetGlobalFromAnywhere(code.Text) where d is TableDefinition || d is ExtractTableDefinition select d).FirstOrDefault(); if (tableDef == null) { ret.ReportError(code.Span, CAError.CA0064, code.Text); // Table '{0}' does not exist. return(ret); } if (!code.ReadExact('.')) { ret.ReportError(code.Span, CAError.CA0066); // Expected '.' return(ret); } Definition fieldDef = null; if (!code.ReadWord() || (fieldDef = tableDef.GetChildDefinitions(code.Text).FirstOrDefault()) == null) { ret.ReportError(code.Span, CAError.CA0067); // Expected column name. return(ret); } } else { ret.ReportError(code.Span, CAError.CA0065); // Expected table name to follow 'group'. return(ret); } } else if (code.ReadExactWholeWord("all")) { // Nothing follows 'all' } else if (code.ReadExactWholeWord("in")) { if (!code.ReadStringLiteral()) { ret.ReportError(code.Span, CAError.CA0068); // Expected select name to follow 'in'. return(ret); } } } else { ret.ReportError(CAError.CA0063); // Expected ')'. } } return(ret); }
public static ExpressionNode Read(ReadParams p, DataType refDataType, bool stayOnSameLine, params string[] stopStrings) { ExpressionNode exp = null; var code = p.Code; var lastPos = code.Position; var parseDataType = refDataType; while (!code.EndOfFile) { switch (code.PeekChar()) { case ';': case '{': case '}': return(exp); } if (stopStrings != null) { foreach (var str in stopStrings) { if (str.IsWord()) { if (code.PeekExactWholeWord(str)) { return(exp); } } else { if (code.PeekExact(str)) { return(exp); } } } } if (!code.Read()) { break; } if (stayOnSameLine) { if (code.PositionsAreOnDifferentLines(lastPos, code.TokenStartPostion)) { code.Position = code.TokenStartPostion; break; } lastPos = code.Position; } if (exp == null) { exp = new ExpressionNode(p.Statement); } switch (code.Type) { case CodeType.Number: exp.AddChild(new NumberNode(p.Statement, code.Span, code.Text)); break; case CodeType.StringLiteral: if (code.Text.StartsWith("'")) { exp.AddChild(new CharLiteralNode(p.Statement, code.Span, CodeParser.StringLiteralToString(code.Text))); } else { exp.AddChild(new StringLiteralNode(p.Statement, code.Span, CodeParser.StringLiteralToString(code.Text))); } break; case CodeType.Word: exp.AddChild(exp.ReadWord(p, parseDataType)); break; case CodeType.Operator: switch (code.Text) { case "(": { var opText = code.Text; var startPos = code.Span.Start; var resumePos = code.Position; var dataType = DataType.TryParse(new DataType.ParseArgs { Code = code, Flags = DataType.ParseFlag.Strict, DataTypeCallback = name => { return(p.Statement.CodeAnalyzer.PreprocessorModel.DefinitionProvider. GetAny <DataTypeDefinition>(startPos + p.FuncOffset, name).FirstOrDefault()); }, VariableCallback = name => { return(p.Statement.CodeAnalyzer.PreprocessorModel.DefinitionProvider. GetAny <VariableDefinition>(startPos + p.FuncOffset, name).FirstOrDefault()); }, TableFieldCallback = (tableName, fieldName) => { foreach (var tableDef in p.Statement.CodeAnalyzer.PreprocessorModel.DefinitionProvider.GetGlobalFromFile(tableName)) { if (tableDef.AllowsChild) { foreach (var fieldDef in tableDef.GetChildDefinitions(fieldName)) { return(new Definition[] { tableDef, fieldDef }); } } } return(null); }, VisibleModel = false }); if (dataType != null && code.ReadExact(')')) { // This is a cast var span = new Span(startPos, code.Span.End); exp.AddChild(new CastNode(p.Statement, span, dataType, ExpressionNode.Read(p, dataType, stayOnSameLine, stopStrings))); } else { code.Position = resumePos; exp.AddChild(exp.ReadNestable(p, parseDataType, code.Span, opText, null)); } } break; //case "[": // exp.AddChild(exp.ReadNestable(p, code.Span, code.Text, stopStrings)); // break; case "-": { var lastNode = exp.LastChild; if (lastNode == null || lastNode is OperatorNode) { exp.AddChild(new OperatorNode(p.Statement, code.Span, code.Text, SpecialOperator.UnaryMinus)); } else { exp.AddChild(new OperatorNode(p.Statement, code.Span, code.Text, null)); } } break; case "?": parseDataType = refDataType; exp.AddChild(ConditionalNode.Read(p, parseDataType, code.Span, stopStrings)); break; case "=": { var rDataType = exp.NumChildren > 0 ? exp.LastChild.DataType : null; exp.AddChild(new OperatorNode(p.Statement, code.Span, code.Text, null)); exp.AddChild(ExpressionNode.Read(p, rDataType, stopStrings)); } break; case "==": case "!=": case "<": case "<=": case ">": case ">=": { if (exp.NumChildren > 0) { var dt = exp.LastChild.DataType; if (dt != null) { parseDataType = dt; } } exp.AddChild(new OperatorNode(p.Statement, code.Span, code.Text, null)); } break; default: exp.AddChild(new OperatorNode(p.Statement, code.Span, code.Text, null)); break; } break; default: exp.ReportError(code.Span, CAError.CA0001, code.Text); // Unknown '{0}'. exp.AddChild(new UnknownNode(p.Statement, code.Span, code.Text)); break; } } return(exp); }
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); }
private static FunctionCallNode ParseArguments(ReadParams p, Span funcNameSpan, string funcName, Definition funcDef) { var funcCallNode = new FunctionCallNode(p.Statement, funcNameSpan, funcName, funcDef); var code = p.Code; var resetPos = code.Position; var commaExpected = false; var closed = false; var argIndex = 0; var args = new List <GroupNode>(); var argDefs = funcDef.Arguments.ToArray(); if (code.ReadExact(')')) { closed = true; } else { while (!code.EndOfFile) { if (commaExpected) { if (code.ReadExact(')')) { closed = true; break; } if (!code.ReadExact(',')) { code.Position = resetPos; return(null); } commaExpected = false; } else { var argDef = argDefs != null && argIndex < argDefs.Length ? argDefs[argIndex] : null; var arg = ExpressionNode.Read(p, argDef != null ? argDef.DataType : null, ",", ")"); if (arg != null) { funcCallNode.AddArgument(arg); } commaExpected = true; argIndex++; } } } if (!closed) { code.Position = resetPos; return(null); } //if (argDefs.Length != funcCallNode.NumArguments) //{ // code.Position = resetPos; // return null; //} return(funcCallNode); }