parse calls, returns, and expressions
This commit is contained in:
261
parser/parser.go
261
parser/parser.go
@@ -17,6 +17,7 @@ const (
|
||||
PRODUCT // *
|
||||
PREFIX // -X or !X
|
||||
CALL // myFunction(X)
|
||||
INDEX // array[index]
|
||||
)
|
||||
|
||||
var precedences = map[token.TokenType]int{
|
||||
@@ -28,8 +29,14 @@ var precedences = map[token.TokenType]int{
|
||||
token.MINUS: SUM,
|
||||
token.SLASH: PRODUCT,
|
||||
token.ASTERISK: PRODUCT,
|
||||
token.LPAREN: CALL,
|
||||
}
|
||||
|
||||
type (
|
||||
prefixParseFn func() ast.Expression
|
||||
infixParseFn func(ast.Expression) ast.Expression
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
l *lexer.Lexer
|
||||
errors []string
|
||||
@@ -41,16 +48,6 @@ type Parser struct {
|
||||
infixParseFns map[token.TokenType]infixParseFn
|
||||
}
|
||||
|
||||
type (
|
||||
prefixParseFn func() ast.Expression
|
||||
infixParseFn func(expression ast.Expression) ast.Expression
|
||||
)
|
||||
|
||||
func (p *Parser) nextToken() {
|
||||
p.curToken = p.peekToken
|
||||
p.peekToken = p.l.NextToken()
|
||||
}
|
||||
|
||||
func New(l *lexer.Lexer) *Parser {
|
||||
p := &Parser{
|
||||
l: l,
|
||||
@@ -66,6 +63,7 @@ func New(l *lexer.Lexer) *Parser {
|
||||
p.registerPrefix(token.FALSE, p.parseBoolean)
|
||||
p.registerPrefix(token.LPAREN, p.parseGroupedExpression)
|
||||
p.registerPrefix(token.IF, p.parseIfExpression)
|
||||
p.registerPrefix(token.FUNCTION, p.parseFunctionLiteral)
|
||||
|
||||
p.infixParseFns = make(map[token.TokenType]infixParseFn)
|
||||
p.registerInfix(token.PLUS, p.parseInfixExpression)
|
||||
@@ -77,13 +75,53 @@ func New(l *lexer.Lexer) *Parser {
|
||||
p.registerInfix(token.LT, p.parseInfixExpression)
|
||||
p.registerInfix(token.GT, p.parseInfixExpression)
|
||||
|
||||
// Read two token, so curToken and peekToken are both set
|
||||
p.registerInfix(token.LPAREN, p.parseCallExpression)
|
||||
|
||||
// Read two tokens, so curToken and peekToken are both set
|
||||
p.nextToken()
|
||||
p.nextToken()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Parser) nextToken() {
|
||||
p.curToken = p.peekToken
|
||||
p.peekToken = p.l.NextToken()
|
||||
}
|
||||
|
||||
func (p *Parser) curTokenIs(t token.TokenType) bool {
|
||||
return p.curToken.Type == t
|
||||
}
|
||||
|
||||
func (p *Parser) peekTokenIs(t token.TokenType) bool {
|
||||
return p.peekToken.Type == t
|
||||
}
|
||||
|
||||
func (p *Parser) expectPeek(t token.TokenType) bool {
|
||||
if p.peekTokenIs(t) {
|
||||
p.nextToken()
|
||||
return true
|
||||
} else {
|
||||
p.peekError(t)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) Errors() []string {
|
||||
return p.errors
|
||||
}
|
||||
|
||||
func (p *Parser) peekError(t token.TokenType) {
|
||||
msg := fmt.Sprintf("expected next token to be %s, got %s instead",
|
||||
t, p.peekToken.Type)
|
||||
p.errors = append(p.errors, msg)
|
||||
}
|
||||
|
||||
func (p *Parser) noPrefixParseFnError(t token.TokenType) {
|
||||
msg := fmt.Sprintf("no prefix parse function for %s found", t)
|
||||
p.errors = append(p.errors, msg)
|
||||
}
|
||||
|
||||
func (p *Parser) ParseProgram() *ast.Program {
|
||||
program := &ast.Program{}
|
||||
program.Statements = []ast.Statement{}
|
||||
@@ -106,7 +144,7 @@ func (p *Parser) parseStatement() ast.Statement {
|
||||
case token.RETURN:
|
||||
return p.parseReturnStatement()
|
||||
default:
|
||||
return p.parseExpressionsStatement()
|
||||
return p.parseExpressionStatement()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,65 +155,38 @@ func (p *Parser) parseLetStatement() *ast.LetStatement {
|
||||
return nil
|
||||
}
|
||||
|
||||
stmt.Name = &ast.Identifier{
|
||||
Token: p.curToken,
|
||||
Value: p.curToken.Literal,
|
||||
}
|
||||
stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
|
||||
|
||||
if !p.expectPeek(token.ASSIGN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: We're skipping expressions until we
|
||||
// encounter a semicolon
|
||||
for !p.curTokenIs(token.SEMICOLON) {
|
||||
p.nextToken()
|
||||
|
||||
stmt.Value = p.parseExpression(LOWEST)
|
||||
|
||||
if p.peekTokenIs(token.SEMICOLON) {
|
||||
p.nextToken()
|
||||
}
|
||||
|
||||
return stmt
|
||||
}
|
||||
|
||||
func (p *Parser) expectPeek(t token.TokenType) bool {
|
||||
if p.peekTokenIs(t) {
|
||||
p.nextToken()
|
||||
return true
|
||||
} else {
|
||||
p.peekError(t)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) curTokenIs(t token.TokenType) bool {
|
||||
return p.curToken.Type == t
|
||||
}
|
||||
|
||||
func (p *Parser) peekTokenIs(t token.TokenType) bool {
|
||||
return p.peekToken.Type == t
|
||||
}
|
||||
|
||||
func (p *Parser) Errors() []string {
|
||||
return p.errors
|
||||
}
|
||||
|
||||
func (p *Parser) peekError(t token.TokenType) {
|
||||
msg := fmt.Sprintf("expected next token to be %s, got %s instead", t, p.peekToken.Type)
|
||||
p.errors = append(p.errors, msg)
|
||||
}
|
||||
|
||||
func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
|
||||
stmt := &ast.ReturnStatement{Token: p.curToken}
|
||||
|
||||
p.nextToken()
|
||||
|
||||
// TODO: We're skipping the expression until we encounter a semicolon
|
||||
for !p.curTokenIs(token.SEMICOLON) {
|
||||
stmt.ReturnValue = p.parseExpression(LOWEST)
|
||||
|
||||
if p.peekTokenIs(token.SEMICOLON) {
|
||||
p.nextToken()
|
||||
}
|
||||
|
||||
return stmt
|
||||
}
|
||||
|
||||
func (p *Parser) parseExpressionsStatement() *ast.ExpressionStatement {
|
||||
func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
|
||||
stmt := &ast.ExpressionStatement{Token: p.curToken}
|
||||
|
||||
stmt.Expression = p.parseExpression(LOWEST)
|
||||
@@ -209,6 +220,26 @@ func (p *Parser) parseExpression(precedence int) ast.Expression {
|
||||
return leftExp
|
||||
}
|
||||
|
||||
func (p *Parser) peekPrecedence() int {
|
||||
if p, ok := precedences[p.peekToken.Type]; ok {
|
||||
return p
|
||||
}
|
||||
|
||||
return LOWEST
|
||||
}
|
||||
|
||||
func (p *Parser) curPrecedence() int {
|
||||
if p, ok := precedences[p.curToken.Type]; ok {
|
||||
return p
|
||||
}
|
||||
|
||||
return LOWEST
|
||||
}
|
||||
|
||||
func (p *Parser) parseIdentifier() ast.Expression {
|
||||
return &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
|
||||
}
|
||||
|
||||
func (p *Parser) parseIntegerLiteral() ast.Expression {
|
||||
lit := &ast.IntegerLiteral{Token: p.curToken}
|
||||
|
||||
@@ -224,26 +255,6 @@ func (p *Parser) parseIntegerLiteral() ast.Expression {
|
||||
return lit
|
||||
}
|
||||
|
||||
func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) {
|
||||
p.prefixParseFns[tokenType] = fn
|
||||
}
|
||||
|
||||
func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {
|
||||
p.infixParseFns[tokenType] = fn
|
||||
}
|
||||
|
||||
func (p *Parser) parseIdentifier() ast.Expression {
|
||||
return &ast.Identifier{
|
||||
Token: p.curToken,
|
||||
Value: p.curToken.Literal,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) noPrefixParseFnError(t token.TokenType) {
|
||||
msg := fmt.Sprintf("no prefix parse function for %s found", t)
|
||||
p.errors = append(p.errors, msg)
|
||||
}
|
||||
|
||||
func (p *Parser) parsePrefixExpression() ast.Expression {
|
||||
expression := &ast.PrefixExpression{
|
||||
Token: p.curToken,
|
||||
@@ -257,22 +268,6 @@ func (p *Parser) parsePrefixExpression() ast.Expression {
|
||||
return expression
|
||||
}
|
||||
|
||||
func (p *Parser) peekPrecedence() int {
|
||||
if p, ok := precedences[p.peekToken.Type]; ok {
|
||||
return p
|
||||
}
|
||||
|
||||
return LOWEST
|
||||
}
|
||||
|
||||
func (p *Parser) curPrecedence() int {
|
||||
if p, ok := precedences[p.curToken.Type]; ok {
|
||||
return p
|
||||
}
|
||||
|
||||
return LOWEST
|
||||
}
|
||||
|
||||
func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {
|
||||
expression := &ast.InfixExpression{
|
||||
Token: p.curToken,
|
||||
@@ -288,10 +283,7 @@ func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {
|
||||
}
|
||||
|
||||
func (p *Parser) parseBoolean() ast.Expression {
|
||||
return &ast.Boolean{
|
||||
Token: p.curToken,
|
||||
Value: p.curTokenIs(token.TRUE),
|
||||
}
|
||||
return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)}
|
||||
}
|
||||
|
||||
func (p *Parser) parseGroupedExpression() ast.Expression {
|
||||
@@ -299,7 +291,7 @@ func (p *Parser) parseGroupedExpression() ast.Expression {
|
||||
|
||||
exp := p.parseExpression(LOWEST)
|
||||
|
||||
if p.expectPeek(token.RPAREN) {
|
||||
if !p.expectPeek(token.RPAREN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -324,7 +316,7 @@ func (p *Parser) parseIfExpression() ast.Expression {
|
||||
return nil
|
||||
}
|
||||
|
||||
expression.Consequence = p.parseBlockExpression()
|
||||
expression.Consequence = p.parseBlockStatement()
|
||||
|
||||
if p.peekTokenIs(token.ELSE) {
|
||||
p.nextToken()
|
||||
@@ -333,13 +325,13 @@ func (p *Parser) parseIfExpression() ast.Expression {
|
||||
return nil
|
||||
}
|
||||
|
||||
expression.Alternative = p.parseBlockExpression()
|
||||
expression.Alternative = p.parseBlockStatement()
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
func (p *Parser) parseBlockExpression() *ast.BlockStatement {
|
||||
func (p *Parser) parseBlockStatement() *ast.BlockStatement {
|
||||
block := &ast.BlockStatement{Token: p.curToken}
|
||||
block.Statements = []ast.Statement{}
|
||||
|
||||
@@ -355,3 +347,86 @@ func (p *Parser) parseBlockExpression() *ast.BlockStatement {
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
func (p *Parser) parseFunctionLiteral() ast.Expression {
|
||||
lit := &ast.FunctionLiteral{Token: p.curToken}
|
||||
|
||||
if !p.expectPeek(token.LPAREN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lit.Parameters = p.parseFunctionParameters()
|
||||
|
||||
if !p.expectPeek(token.LBRACE) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lit.Body = p.parseBlockStatement()
|
||||
|
||||
return lit
|
||||
}
|
||||
|
||||
func (p *Parser) parseFunctionParameters() []*ast.Identifier {
|
||||
identifiers := []*ast.Identifier{}
|
||||
|
||||
if p.peekTokenIs(token.RPAREN) {
|
||||
p.nextToken()
|
||||
return identifiers
|
||||
}
|
||||
|
||||
p.nextToken()
|
||||
|
||||
ident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
|
||||
identifiers = append(identifiers, ident)
|
||||
|
||||
for p.peekTokenIs(token.COMMA) {
|
||||
p.nextToken()
|
||||
p.nextToken()
|
||||
ident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
|
||||
identifiers = append(identifiers, ident)
|
||||
}
|
||||
|
||||
if !p.expectPeek(token.RPAREN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return identifiers
|
||||
}
|
||||
|
||||
func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression {
|
||||
exp := &ast.CallExpression{Token: p.curToken, Function: function}
|
||||
exp.Arguments = p.parseExpressionList(token.RPAREN)
|
||||
return exp
|
||||
}
|
||||
|
||||
func (p *Parser) parseExpressionList(end token.TokenType) []ast.Expression {
|
||||
list := []ast.Expression{}
|
||||
|
||||
if p.peekTokenIs(end) {
|
||||
p.nextToken()
|
||||
return list
|
||||
}
|
||||
|
||||
p.nextToken()
|
||||
list = append(list, p.parseExpression(LOWEST))
|
||||
|
||||
for p.peekTokenIs(token.COMMA) {
|
||||
p.nextToken()
|
||||
p.nextToken()
|
||||
list = append(list, p.parseExpression(LOWEST))
|
||||
}
|
||||
|
||||
if !p.expectPeek(end) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) {
|
||||
p.prefixParseFns[tokenType] = fn
|
||||
}
|
||||
|
||||
func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {
|
||||
p.infixParseFns[tokenType] = fn
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user