private Ast.Expression ParseExpression(bool allowIndirectIdentifier = false) { Ast.Expression expression = null; var token = currentToken; switch (token.Type) { case TokenType.Identifier: if (token.Value == "true") expression = new Ast.LiteralExpression(new Ast.Literal(true) {Span = token.Span}) {Span = token.Span}; else if (token.Value == "false") expression = new Ast.LiteralExpression(new Ast.Literal(false) {Span = token.Span}) {Span = token.Span}; else if (string.Compare(token.Value, "null", StringComparison.OrdinalIgnoreCase) == 0) expression = new Ast.LiteralExpression(new Ast.Literal(null) {Span = token.Span}) {Span = token.Span}; else if (token.Value == "compile") { expression = ParseCompileExpression(); } else { var nextIdentifier = ParseIdentifier(token, true); // check next token BeginPreviewToken(); var nextToken = NextToken(); EndPreviewToken(); switch (nextToken.Type) { case TokenType.LeftParent: var methodExpression = ParseMethodExpression(); methodExpression.Name = nextIdentifier; expression = methodExpression; break; case TokenType.Equal: var assignExpression = ParseAssignExpression(); assignExpression.Name = nextIdentifier; expression = assignExpression; break; default: expression = new Ast.IdentifierExpression(nextIdentifier) {Span = token.Span}; break; } } break; case TokenType.LeftParent: expression = ParseArrayInitializerExpression(TokenType.RightParent); //expression = ParseExpression(); //ExpectNext(TokenType.RightParent); break; case TokenType.String: // TODO doesn't support escaped strings var str = token.Value.Substring(1, token.Value.Length - 2); // Temporary escape str = str.Replace("\\r\\n", "\r\n"); str = str.Replace("\\n", "\n"); str = str.Replace("\\t", "\t"); expression = new Ast.LiteralExpression(new Ast.Literal(str) {Span = token.Span}) {Span = token.Span}; break; case TokenType.Number: var numberStr = token.Value.Replace(" ", ""); object numberValue; if (numberStr.EndsWith("f", false, CultureInfo.InvariantCulture) || numberStr.Contains("e") || numberStr.Contains("E") || numberStr.Contains(".")) { var floatStr = numberStr.TrimEnd('f'); numberValue = float.Parse(floatStr, NumberStyles.Float, CultureInfo.InvariantCulture); } else { numberValue = int.Parse(numberStr, NumberStyles.Integer, CultureInfo.InvariantCulture); } expression = new Ast.LiteralExpression(new Ast.Literal(numberValue) {Span = token.Span}) {Span = token.Span}; break; case TokenType.Hexa: var intValue = int.Parse(token.Value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); expression = new Ast.LiteralExpression(new Ast.Literal(intValue) {Span = token.Span}) {Span = token.Span}; break; case TokenType.LeftCurlyBrace: expression = ParseArrayInitializerExpression(TokenType.RightCurlyBrace); break; default: if (token.Type == TokenType.LessThan && allowIndirectIdentifier) { NextToken(); var identifierExpression = ParseExpression() as Ast.IdentifierExpression; bool isClosedIndirect = ExpectNext(TokenType.GreaterThan); if (identifierExpression == null) { Logger.Error("Unexpected expression inside indirect reference.", token.Span); } else { identifierExpression.Name.IsIndirect = isClosedIndirect; expression = identifierExpression; } } else { Logger.Error("Unexpected token [{0}]. Expecting tokens ['identifier', 'string', 'number', '{{']", currentToken.Span, currentToken); } break; } return expression; }
private Ast.Expression ParseExpression(bool allowIndirectIdentifier = false) { Ast.Expression expression = null; var token = currentToken; switch (token.Type) { case TokenType.Identifier: if (token.Value == "true") { expression = new Ast.LiteralExpression(new Ast.Literal(true) { Span = token.Span }) { Span = token.Span } } ; else if (token.Value == "false") { expression = new Ast.LiteralExpression(new Ast.Literal(false) { Span = token.Span }) { Span = token.Span } } ; else if (string.Compare(token.Value, "null", StringComparison.OrdinalIgnoreCase) == 0) { expression = new Ast.LiteralExpression(new Ast.Literal(null) { Span = token.Span }) { Span = token.Span } } ; else if (token.Value == "compile") { expression = ParseCompileExpression(); } else { var nextIdentifier = ParseIdentifier(token, true); // check next token BeginPreviewToken(); var nextToken = NextToken(); EndPreviewToken(); switch (nextToken.Type) { case TokenType.LeftParent: var methodExpression = ParseMethodExpression(); methodExpression.Name = nextIdentifier; expression = methodExpression; break; case TokenType.Equal: var assignExpression = ParseAssignExpression(); assignExpression.Name = nextIdentifier; expression = assignExpression; break; default: expression = new Ast.IdentifierExpression(nextIdentifier) { Span = token.Span }; break; } } break; case TokenType.LeftParent: expression = ParseArrayInitializerExpression(TokenType.RightParent); //expression = ParseExpression(); //ExpectNext(TokenType.RightParent); break; case TokenType.String: // TODO doesn't support escaped strings var str = token.Value.Substring(1, token.Value.Length - 2); // Temporary escape str = str.Replace("\\r\\n", "\r\n"); str = str.Replace("\\n", "\n"); str = str.Replace("\\t", "\t"); expression = new Ast.LiteralExpression(new Ast.Literal(str) { Span = token.Span }) { Span = token.Span }; break; case TokenType.Number: var numberStr = token.Value.Replace(" ", ""); object numberValue; if (numberStr.EndsWith("f", false, CultureInfo.InvariantCulture) || numberStr.Contains("e") || numberStr.Contains("E") || numberStr.Contains(".")) { var floatStr = numberStr.TrimEnd('f'); numberValue = float.Parse(floatStr, NumberStyles.Float, CultureInfo.InvariantCulture); } else { numberValue = int.Parse(numberStr, NumberStyles.Integer, CultureInfo.InvariantCulture); } expression = new Ast.LiteralExpression(new Ast.Literal(numberValue) { Span = token.Span }) { Span = token.Span }; break; case TokenType.Hexa: var intValue = int.Parse(token.Value.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); expression = new Ast.LiteralExpression(new Ast.Literal(intValue) { Span = token.Span }) { Span = token.Span }; break; case TokenType.LeftCurlyBrace: expression = ParseArrayInitializerExpression(TokenType.RightCurlyBrace); break; default: if (token.Type == TokenType.LessThan && allowIndirectIdentifier) { NextToken(); var identifierExpression = ParseExpression() as Ast.IdentifierExpression; bool isClosedIndirect = ExpectNext(TokenType.GreaterThan); if (identifierExpression == null) { Logger.Error("Unexpected expression inside indirect reference.", token.Span); } else { identifierExpression.Name.IsIndirect = isClosedIndirect; expression = identifierExpression; } } else { Logger.Error("Unexpected token [{0}]. Expecting tokens ['identifier', 'string', 'number', '{{']", currentToken.Span, currentToken); } break; } return(expression); }