private static object ReadMethodCall(SimpleParser parser, object prevData, string name) { using (var la = parser.LookAround()) { parser.SkipSpaces(); if (parser.ReadChar('(')) { var prevExecutor = (INode)prevData; var type = prevData == null ? parser.GlobalType : prevExecutor.Compile(parser.GlobalType); var isMethodGroup = type.GetMethods().Any(m => m.Name == name); if (isMethodGroup) { var paramValues = parser.ReadList <ValueBuilder, INode>(ReadListSeparator); if (paramValues.Count == 1 && paramValues[0] == null) { paramValues.Clear(); } parser.SkipSpaces(); if (parser.ReadChar(')')) { la.Success(); return(new Call { Element = prevExecutor, Name = name, Parameters = paramValues }); } } } return(null); } }
private static bool ReadListSeparator(SimpleParser parser) { parser.SkipSpaces(); return(parser.ReadChar(',')); }
/// <summary> /// Reads the code trying to extract the AST from it. /// </summary> /// <param name="parser">The parser object used to read the code.</param> /// <param name="prevData">Previously parsed result. This is used to chain results together.</param> /// <returns>Returns an object that results from parsing the code.</returns> public override object Read(SimpleParser parser, object prevData) { var prevExecutor = (INode)prevData; parser.SkipSpaces(); if (prevExecutor == null) { var name = this.ReadName(parser); // this is a direct method call in the root var call = ReadMethodCall(parser, null, name); if (call != null) { return(call); } // this is a global property if (!string.IsNullOrWhiteSpace(name)) { return new PropertyGet { Name = name, Element = null } } ; // this is an array construct if (parser.ReadChar('{')) { var values = parser.ReadList <ValueBuilder, INode>(ReadListSeparator); if (values.Count > 0) { parser.SkipSpaces(); if (!parser.ReadChar('}')) { return(new Exception("Unterminated array construct.")); } return(new ArrayConstruct { Values = values }); } } // this is a precedence operator if (parser.ReadChar('(')) { var value = parser.Read <ValueBuilder, INode>(); if (value == null) { return(new Exception("Syntax error.")); } parser.SkipSpaces(); if (!parser.ReadChar(')')) { return(new Exception("Unterminated precedence construct.")); } return(value); } // this is a number literal var number = parser.ReadWhileCharOrEof(char.IsNumber); if (number.Length > 0) { return new NumberLiteral { Data = number } } ; // this is a string literal if (parser.ReadChar('"')) { var strBuilder = new StringBuilder(); while (true) { strBuilder.Append(parser.ReadWhileCharOrEof(ch => ch != '\\' && ch != '"')); if (parser.Eof) { return(new InvalidOperationException("String literal not terminated.")); } if (parser.ReadChar('\\')) { if (parser.ReadChar('0')) { strBuilder.Append('\0'); } else if (parser.ReadChar('n')) { strBuilder.Append('\n'); } else if (parser.ReadChar('r')) { strBuilder.Append('\r'); } else if (parser.ReadChar('\\')) { strBuilder.Append('\\'); } else if (parser.ReadChar('"')) { strBuilder.Append('"'); } else { return(new InvalidOperationException("Escape sequence not recognized.")); } } if (parser.ReadChar('"')) { break; } } return(new StringLiteral { Data = strBuilder.ToString() }); } } else { if (parser.ReadChar('.')) { var name = this.ReadName(parser); // this is a direct method call in the previous element var call = ReadMethodCall(parser, prevExecutor, name); if (call != null) { return(call); } if (!string.IsNullOrWhiteSpace(name)) { return new PropertyGet { Name = name, Element = prevExecutor } } ; } // indexer property if (parser.ReadChar('[')) { var indexValues = parser.ReadList <ValueBuilder, INode>(ReadListSeparator); if (indexValues.Count == 0) { return(new Exception("Index is missing.")); } parser.SkipSpaces(); if (!parser.ReadChar(']')) { return(new Exception("Unterminated indexer.")); } return(new IndexerGet { Element = prevExecutor, Indexes = indexValues }); } // this only happens when calling a delegate // direct method calls never fall here if (parser.ReadChar('(')) { var paramValues = parser.ReadList <ValueBuilder, INode>(ReadListSeparator); parser.SkipSpaces(); if (parser.ReadChar(')')) { return new Call { Element = prevExecutor, Name = "Invoke", Parameters = paramValues } } ; } if (parser.ReadChar('?')) { var trueValue = parser.Read <ValueBuilder, INode>(); parser.SkipSpaces(); if (!parser.ReadChar(':')) { throw new Exception("Missing ':' for ternary operator a?b:c."); } parser.SkipSpaces(); var falseValue = parser.Read <ValueBuilder, INode>(); return(new TernaryInlineIf { Condition = prevExecutor, TrueValue = trueValue, FalseValue = falseValue }); } var binOp = parser.ReadAnyStringAlternative("==", "!=", ">", "<", ">=", "<=", "&&", "||"); if (binOp != null) { var valueB = parser.Read <ValueBuilder, INode>(); return(new BinaryBoolOps { ValueA = prevExecutor, ValueB = valueB, Operator = binOp }); } } return(null); }