//this is very similar to parseFunctionParameters. Difference being in parseFunctionParameters, we expect the parameters to be //identifiers wherease here when we are calling/invoking that function the arguments passed to those parameters can be Expressions such as //(5, foobar, foobar+5) private List <AST_Helper.Expression> parseExpressionList(TokenHelper.TokenType endToken) { List <AST_Helper.Expression> args = new List <AST_Helper.Expression>(); if (this.peekTokenIs(endToken)) { this.nextToken(); return(args); } this.nextToken(); args.Add(this.parseExpression(Parser_Helper.precedence.LOWEST)); while (this.peekTokenIs(TokenHelper.TokenType.COMMA)) { this.nextToken(); this.nextToken(); args.Add(this.parseExpression(Parser_Helper.precedence.LOWEST)); } if (!this.expectPeek(endToken)) { return(null); } return(args); }
private bool expectPeek(TokenHelper.TokenType t) //if the expected token is present, this also advances the cursor to next token { if (this.peekTokenIs(t)) //and this should be reflected in the func name. { this.nextToken(); return(true); } else { this.peekError(t); return(false); } }
public Token(TokenHelper.TokenType type, string literal) { Type = type; Literal = literal; }
void registerInfix(TokenHelper.TokenType t, Parser_Helper.infixParseFn fn) { this.infixParseFns[t] = fn; }
void registerPrefix(TokenHelper.TokenType t, Parser_Helper.prefixParserFn fn) { this.prefixParseFns[t] = fn; }
void peekError(TokenHelper.TokenType t) { string message = string.Format("expected next token to be {0}, got {1} instead", t, this.peekToken.Type); this.errors.Add(message); }
private bool curTokenIs(TokenHelper.TokenType t) { return(this.curToken.Type == t); }
private bool peekTokenIs(TokenHelper.TokenType t) { return(this.peekToken.Type == t); }
private void noPrefixParseFnError(TokenHelper.TokenType type) { string message = string.Format("no prefix parse function for {0} found", type); this.errors.Add(message); }
public Token NextToken() { Token tok; this.skipWhiteSpace(); switch (this.ch) { case '"': tok = new Token(TokenHelper.TokenType.STRING, this.readString()); //even though we have already read the next char in readString, we still want to call readchar() again(below). Therefore, in this case, do not return here. break; case '=': if (this.peekChar() == '=') { var temp_ch = this.ch; this.readChar(); string literal = temp_ch.ToString() + this.ch.ToString(); tok = new Token(TokenHelper.TokenType.EQ, literal); } else { tok = new Token(TokenHelper.TokenType.ASSIGN, this.ch.ToString()); } break; case ';': tok = new Token(TokenHelper.TokenType.SEMICOLON, this.ch.ToString()); break; case ':': tok = new Token(TokenHelper.TokenType.COLON, this.ch.ToString()); break; case '(': tok = new Token(TokenHelper.TokenType.LPAREN, this.ch.ToString()); break; case ')': tok = new Token(TokenHelper.TokenType.RPAREN, this.ch.ToString()); break; case ',': tok = new Token(TokenHelper.TokenType.COMMA, this.ch.ToString()); break; case '+': tok = new Token(TokenHelper.TokenType.PLUS, this.ch.ToString()); break; case '{': tok = new Token(TokenHelper.TokenType.LBRACE, this.ch.ToString()); break; case '}': tok = new Token(TokenHelper.TokenType.RBRACE, this.ch.ToString()); break; case '[': tok = new Token(TokenHelper.TokenType.LBRACKET, this.ch.ToString()); break; case ']': tok = new Token(TokenHelper.TokenType.RBRACKET, this.ch.ToString()); break; case '-': tok = new Token(TokenHelper.TokenType.MINUS, this.ch.ToString()); break; case '!': if (this.peekChar() == '=') { var temp_ch = this.ch; this.readChar(); string literal = temp_ch.ToString() + this.ch.ToString(); tok = new Token(TokenHelper.TokenType.NOT_EQ, literal); } else { tok = new Token(TokenHelper.TokenType.BANG, this.ch.ToString()); } break; case '/': tok = new Token(TokenHelper.TokenType.SLASH, this.ch.ToString()); break; case '*': tok = new Token(TokenHelper.TokenType.ASTERISK, this.ch.ToString()); break; case '<': tok = new Token(TokenHelper.TokenType.LT, this.ch.ToString()); break; case '>': tok = new Token(TokenHelper.TokenType.GT, this.ch.ToString()); break; case '\0': tok = new Token(TokenHelper.TokenType.EOF, this.ch.ToString()); //todo:?? break; default: if (this.isLetter(this.ch)) { string literal = this.readIdentifier(); TokenHelper.TokenType type = TokenHelper.LookupIdent(literal); tok = new Token(type, literal); //we don't want to call readchar() again(below) as we have already read the next char in readIdentifier. Therefore return here. return(tok); } else if (this.isDigit(this.ch)) { string literal = this.readNumber(); TokenHelper.TokenType type = TokenHelper.TokenType.INT; tok = new Token(type, literal); //we don't want to call readchar() again(below) as we have already read the next char in readNumber. Therefore return here. return(tok); } else { tok = new Token(TokenHelper.TokenType.ILLEGAL, this.ch.ToString()); } break; } this.readChar(); return(tok); }