public Parser(Lexer lex) { if (lex == null) throw new ArgumentNullException("lex"); this.lex = lex; this.tok = null; }
public ListExpr(Token start, Token end, params SExpr[] items) : base(SExprKind.List, start, end) { Items = items; }
public NullExpr(Token token) : base(SExprKind.Null, token, token) { if (token.Type != TokenType.Null) throw new ArgumentException("token must be of type Null for a NullExpr"); }
public InvocationExpr(Token start, Token end, IdentifierExpr identifier, params SExpr[] parameters) : base(SExprKind.Invocation, start, end) { Identifier = identifier; Parameters = parameters; }
public Token Next() { // Only read the first char on the first call to Next(): if (c == -2) c = Read(); do { // EOF: if (c == -1 || c == 0) return new Token(pos, TokenType.EOF, null); // Skip whitespace (commas are whitespace too): if (c == ' ' || c == '\t' || c == ',' || c == '\n' || c == '\r') { c = Read(); continue; } // TODO(jsd): comments! // Curlies and parens are equivalent in this LISP: if (c == (int)'(' || c == (int)'{') { var tok = new Token(lpos, TokenType.ParenOpen, ((char)c).ToString()); c = Read(); return tok; } else if (c == (int)')' || c == (int)'}') { var tok = new Token(lpos, TokenType.ParenClose, ((char)c).ToString()); c = Read(); return tok; } // Square brackets denote plain lists of data, not to be eval'd: else if (c == (int)'[') { var tok = new Token(lpos, TokenType.BracketOpen, ((char)c).ToString()); c = Read(); return tok; } else if (c == (int)']') { var tok = new Token(lpos, TokenType.BracketClose, ((char)c).ToString()); c = Read(); return tok; } // Punctuation: else if (c == (int)'~') { var tok = new Token(lpos, TokenType.Quote, ((char)c).ToString()); c = Read(); return tok; } else if (c == '.') { var tok = new Token(lpos, TokenType.Dot, ((char)c).ToString()); c = Read(); return tok; } else if (c == '/') { var tok = new Token(lpos, TokenType.Slash, ((char)c).ToString()); c = Read(); return tok; } // Keywords or unquoted strings: else if (Char.IsLetter((char)c) || c == '_') { // Parse an unquoted string ([A-Za-z_][A-Za-z0-9\-_]*): int spos = lpos; var sb = new StringBuilder(10); do { sb.Append((char)c); c = Read(); if (c == -1) break; } while (Char.IsLetterOrDigit((char)c) || c == '-' || c == '_'); var ident = sb.ToString(); if (String.Equals(ident, "true")) return new Token(spos, TokenType.Boolean, ident); else if (String.Equals(ident, "false")) return new Token(spos, TokenType.Boolean, ident); else if (String.Equals(ident, "null")) return new Token(spos, TokenType.Null, ident); else return new Token(spos, TokenType.Identifier, sb.ToString()); } // Quoted string literals: else if (c == (int)'\'') { int spos = lpos; var sb = new StringBuilder(10); do { c = Read(); if (c == -1) return new Token(pos, TokenType.Error, "Unexpected end"); else if (c == '\'') break; else if (c == '\\') { c = Read(); if (c == -1) return new Token(pos, TokenType.Error, "Unexpected end"); else if (c == '\'') sb.Append('\''); else if (c == '\\') sb.Append('\\'); else if (c == 'n') sb.Append('\n'); else if (c == 'r') sb.Append('\r'); else if (c == 't') sb.Append('\t'); else return new Token(pos, TokenType.Error, "Unknown backslash escape character '{0}'".F((char)c)); } else sb.Append((char)c); } while (true); c = Read(); return new Token(spos, TokenType.String, sb.ToString()); } // Raw string literals: else if (c == (int)'`') { int spos = lpos; var sb = new StringBuilder(10); do { c = Read(); if (c == -1) return new Token(pos, TokenType.Error, "Unexpected end"); // TODO(jsd): Any escape sequences? else if (c == '`') break; else sb.Append((char)c); } while (true); c = Read(); return new Token(spos, TokenType.String, sb.ToString()); } // Numerics: else if (Char.IsDigit((char)c) || c == '-') { // Simple/stupid numeric parser [0-9]+(\.[0-9]+)?: int spos = lpos; bool hasDecimal = false; var sb = new StringBuilder(10); do { sb.Append((char)c); c = Read(); if (c == -1) break; if (c == '.') hasDecimal = true; } while (Char.IsDigit((char)c) || c == '.'); // Determine the type of number by suffix or presence of decimal point: var type = TokenType.Integer; if (c == 'd') { c = Read(); type = TokenType.Double; } else if (c == 'f') { c = Read(); type = TokenType.Float; } else if (hasDecimal) { // Default to decimal type if have a decimal point: type = TokenType.Decimal; } return new Token(spos, type, sb.ToString()); } else { return new Token(lpos, TokenType.Error, "Unexpected character '{0}'".F((char)c)); } } while (c != -1); return new Token(pos, TokenType.EOF, null); }
public ParserError(Token where, string message) : base(SExprKind.Error, where, where) { Message = message; }
public ScopedIdentifierExpr(Token ident) : base(SExprKind.ScopedIdentifier, ident, ident) { Name = ident; }
public FloatExpr(Token token, float value) : base(SExprKind.Float, token, token) { if (token.Type != TokenType.Float) throw new ArgumentException("token must be of type Float for a FloatExpr"); Value = value; }
protected IdentifierExpr(SExprKind kind, Token start, Token end) : base(kind, start, end) { }
public StringExpr(Token token) : base(SExprKind.String, token, token) { if (token.Type != TokenType.String) throw new ArgumentException("token must be of type String for a StringExpr"); Value = token.Text; }
public DoubleExpr(Token token, double value) : base(SExprKind.Double, token, token) { if (token.Type != TokenType.Double) throw new ArgumentException("token must be of type Double for a DoubleExpr"); Value = value; }
public StaticMemberIdentifierExpr(Token[] @typeName, Token ident) : base(SExprKind.StaticMemberIdentifier, @typeName[0], ident) { TypeName = @typeName; Name = ident; }
public DecimalExpr(Token token, decimal value) : base(SExprKind.Decimal, token, token) { if (token.Type != TokenType.Decimal) throw new ArgumentException("token must be of type Decimal for a DecimalExpr"); Value = value; }
protected SExpr(SExprKind kind, Token start, Token end) { Kind = kind; StartToken = start; EndToken = end; }
public BooleanExpr(Token token, bool value) : base(SExprKind.Boolean, token, token) { if (token.Type != TokenType.Boolean) throw new ArgumentException("token must be of type Boolean for a BooleanExpr"); Value = value; }
public InstanceMemberIdentifierExpr(Token dot, Token ident) : base(SExprKind.InstanceMemberIdentifier, dot, ident) { Name = ident; }
void Next() { if (hold) { hold = false; return; } tok = lex.Next(); if (tok.Type == TokenType.EOF) next = new ParserError(tok, "Unexpected end"); else if (tok.Type == TokenType.Error) next = new ParserError(tok, tok.Text); else next = tok; }
public IntegerExpr(Token token, long value) : base(SExprKind.Integer, token, token) { if (token.Type != TokenType.Integer) throw new ArgumentException("token must be of type Integer for an IntegerExpr"); Value = value; }
public ParserException(Token tok, string message) : base("MiniLISP error(pos {0}): {1}".F(tok.Position, message)) { Token = tok; }
public QuoteExpr(Token start, Token end, SExpr sexpr) : base(SExprKind.Quote, start, end) { SExpr = sexpr; }