public SExpr ParseExpr() { Next(); if (next.IsRight) { return(next.Right); } if (tok.Type == TokenType.ParenOpen) { var start = tok; // NOTE(jsd): Built-in identifier expression parser here. Probably should extract this for general purpose usage. // Expect function name: ExpectOr(TokenType.Identifier, TokenType.Dot); if (next.IsRight) { return(next.Right); } var identStart = tok; IdentifierExpr ident; // "memberName" // ".memberName" // "namespace.Type/memberName" if (next.Left.Type == TokenType.Dot) { // ".memberName": Expect(TokenType.Identifier); if (next.IsRight) { return(next.Right); } ident = new InstanceMemberIdentifierExpr(identStart, next.Left); Next(); if (next.IsRight) { return(next.Right); } } else { // "memberName" var typeNameParts = new List <Token>(5); typeNameParts.Add(next.Left); // "namespace.typeName" ? Next(); while (!next.IsRight && next.Left.Type == TokenType.Dot) { Next(); if (next.Left.Type == TokenType.Slash) { break; } if (next.Left.Type != TokenType.Identifier) { break; } typeNameParts.Add(next.Left); Next(); } ; if (next.IsRight) { return(next.Right); } // Determine what type of identifier: if (next.Left.Type == TokenType.Slash) { // "namespace.typeName/memberName" Expect(TokenType.Identifier); if (next.IsRight) { return(next.Right); } ident = new StaticMemberIdentifierExpr(typeNameParts.ToArray(), next.Left); Next(); if (next.IsRight) { return(next.Right); } } else { if (typeNameParts.Count != 1) { return(new ParserError(tok, "Scoped identifier expression must have only one identifier part")); } ident = new ScopedIdentifierExpr(typeNameParts[0]); } } // Parse parameters: List <SExpr> parameters; if (tok.Type == TokenType.ParenClose) { // No parameters: parameters = new List <SExpr>(0); } else { // At least one parameter: parameters = new List <SExpr>(); do { Hold(); var expr = ParseExpr(); Debug.Assert(expr != null); if (expr.Kind == SExprKind.Error) { return(expr); } parameters.Add(expr); Next(); } while (tok.Type != TokenType.ParenClose); } var end = tok; return(new InvocationExpr(start, end, ident, parameters.ToArray())); } else if (tok.Type == TokenType.BracketOpen) { var start = tok; // Parse items: List <SExpr> items; Next(); if (next.IsRight) { return(next.Right); } if (tok.Type == TokenType.BracketClose) { // No items: items = new List <SExpr>(0); } else { // At least one item: items = new List <SExpr>(); do { Hold(); var expr = ParseExpr(); Debug.Assert(expr != null); if (expr.Kind == SExprKind.Error) { return(expr); } items.Add(expr); Next(); } while (tok.Type != TokenType.BracketClose); } var end = tok; return(new ListExpr(start, end, items.ToArray())); } else if (tok.Type == TokenType.Quote) { var start = tok; var expr = ParseExpr(); if (expr.Kind == SExprKind.Error) { return(expr); } var end = tok; return(new QuoteExpr(start, end, expr)); } else if (tok.Type == TokenType.Identifier) { var expr = new ScopedIdentifierExpr(tok); return(expr); } else if (tok.Type == TokenType.Integer) { long val; if (!Int64.TryParse(tok.Text, out val)) { return(new ParserError(tok, "Could not parse '{0}' as an Int64".F(tok.Text))); } var expr = new IntegerExpr(tok, val); return(expr); } else if (tok.Type == TokenType.String) { var expr = new StringExpr(tok); return(expr); } else if (tok.Type == TokenType.Boolean) { bool val; if (!Boolean.TryParse(tok.Text, out val)) { return(new ParserError(tok, "Could not parse '{0}' as a boolean".F(tok.Text))); } var expr = new BooleanExpr(tok, val); return(expr); } else if (tok.Type == TokenType.Null) { var expr = new NullExpr(tok); return(expr); } else if (tok.Type == TokenType.Decimal) { decimal val; if (!Decimal.TryParse(tok.Text, out val)) { return(new ParserError(tok, "Could not parse '{0}' as a decimal".F(tok.Text))); } var expr = new DecimalExpr(tok, val); return(expr); } else if (tok.Type == TokenType.Double) { double val; if (!Double.TryParse(tok.Text, out val)) { return(new ParserError(tok, "Could not parse '{0}' as a double".F(tok.Text))); } var expr = new DoubleExpr(tok, val); return(expr); } else if (tok.Type == TokenType.Float) { float val; if (!Single.TryParse(tok.Text, out val)) { return(new ParserError(tok, "Could not parse '{0}' as a float".F(tok.Text))); } var expr = new FloatExpr(tok, val); return(expr); } return(new ParserError(tok, "Unexpected token '{0}'".F(tok.Type))); }
public SExpr ParseExpr() { Next(); if (next.IsRight) return next.Right; if (tok.Type == TokenType.ParenOpen) { var start = tok; // NOTE(jsd): Built-in identifier expression parser here. Probably should extract this for general purpose usage. // Expect function name: ExpectOr(TokenType.Identifier, TokenType.Dot); if (next.IsRight) return next.Right; var identStart = tok; IdentifierExpr ident; // "memberName" // ".memberName" // "namespace.Type/memberName" if (next.Left.Type == TokenType.Dot) { // ".memberName": Expect(TokenType.Identifier); if (next.IsRight) return next.Right; ident = new InstanceMemberIdentifierExpr(identStart, next.Left); Next(); if (next.IsRight) return next.Right; } else { // "memberName" var typeNameParts = new List<Token>(5); typeNameParts.Add(next.Left); // "namespace.typeName" ? Next(); while (!next.IsRight && next.Left.Type == TokenType.Dot) { Next(); if (next.Left.Type == TokenType.Slash) break; if (next.Left.Type != TokenType.Identifier) break; typeNameParts.Add(next.Left); Next(); }; if (next.IsRight) return next.Right; // Determine what type of identifier: if (next.Left.Type == TokenType.Slash) { // "namespace.typeName/memberName" Expect(TokenType.Identifier); if (next.IsRight) return next.Right; ident = new StaticMemberIdentifierExpr(typeNameParts.ToArray(), next.Left); Next(); if (next.IsRight) return next.Right; } else { if (typeNameParts.Count != 1) return new ParserError(tok, "Scoped identifier expression must have only one identifier part"); ident = new ScopedIdentifierExpr(typeNameParts[0]); } } // Parse parameters: List<SExpr> parameters; if (tok.Type == TokenType.ParenClose) { // No parameters: parameters = new List<SExpr>(0); } else { // At least one parameter: parameters = new List<SExpr>(); do { Hold(); var expr = ParseExpr(); Debug.Assert(expr != null); if (expr.Kind == SExprKind.Error) return expr; parameters.Add(expr); Next(); } while (tok.Type != TokenType.ParenClose); } var end = tok; return new InvocationExpr(start, end, ident, parameters.ToArray()); } else if (tok.Type == TokenType.BracketOpen) { var start = tok; // Parse items: List<SExpr> items; Next(); if (next.IsRight) return next.Right; if (tok.Type == TokenType.BracketClose) { // No items: items = new List<SExpr>(0); } else { // At least one item: items = new List<SExpr>(); do { Hold(); var expr = ParseExpr(); Debug.Assert(expr != null); if (expr.Kind == SExprKind.Error) return expr; items.Add(expr); Next(); } while (tok.Type != TokenType.BracketClose); } var end = tok; return new ListExpr(start, end, items.ToArray()); } else if (tok.Type == TokenType.Quote) { var start = tok; var expr = ParseExpr(); if (expr.Kind == SExprKind.Error) return expr; var end = tok; return new QuoteExpr(start, end, expr); } else if (tok.Type == TokenType.Identifier) { var expr = new ScopedIdentifierExpr(tok); return expr; } else if (tok.Type == TokenType.Integer) { long val; if (!Int64.TryParse(tok.Text, out val)) return new ParserError(tok, "Could not parse '{0}' as an Int64".F(tok.Text)); var expr = new IntegerExpr(tok, val); return expr; } else if (tok.Type == TokenType.String) { var expr = new StringExpr(tok); return expr; } else if (tok.Type == TokenType.Boolean) { bool val; if (!Boolean.TryParse(tok.Text, out val)) return new ParserError(tok, "Could not parse '{0}' as a boolean".F(tok.Text)); var expr = new BooleanExpr(tok, val); return expr; } else if (tok.Type == TokenType.Null) { var expr = new NullExpr(tok); return expr; } else if (tok.Type == TokenType.Decimal) { decimal val; if (!Decimal.TryParse(tok.Text, out val)) return new ParserError(tok, "Could not parse '{0}' as a decimal".F(tok.Text)); var expr = new DecimalExpr(tok, val); return expr; } else if (tok.Type == TokenType.Double) { double val; if (!Double.TryParse(tok.Text, out val)) return new ParserError(tok, "Could not parse '{0}' as a double".F(tok.Text)); var expr = new DoubleExpr(tok, val); return expr; } else if (tok.Type == TokenType.Float) { float val; if (!Single.TryParse(tok.Text, out val)) return new ParserError(tok, "Could not parse '{0}' as a float".F(tok.Text)); var expr = new FloatExpr(tok, val); return expr; } return new ParserError(tok, "Unexpected token '{0}'".F(tok.Type)); }