From d6f0f9c4c016260439ace89b37ea91ae6ea311f2 Mon Sep 17 00:00:00 2001 From: nibral Date: Sat, 12 Jan 2019 20:29:02 +0900 Subject: [PATCH] 2.6: Add parser of integer literal --- ast/ast.go | 9 +++++++++ parser/parser.go | 17 +++++++++++++++++ parser/parser_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/ast/ast.go b/ast/ast.go index 63787ab..ce9bc28 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -101,3 +101,12 @@ func (es *ExpressionStatement) String() string { } return "" } + +type IntegerLiteral struct { + Token token.Token + Value int64 +} + +func (il *IntegerLiteral) expressionNode() {} +func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal } +func (il *IntegerLiteral) String() string { return il.Token.Literal } diff --git a/parser/parser.go b/parser/parser.go index c8504bb..be358c2 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -5,6 +5,7 @@ import ( "monkey_interpreter/ast" "monkey_interpreter/lexer" "monkey_interpreter/token" + "strconv" ) const ( @@ -47,6 +48,7 @@ func New(l *lexer.Lexer) *Parser { p.prefixParseFns = make(map[token.TokenType]prefixParseFn) p.registerPrefix(token.IDENT, p.parseIdentifier) + p.registerPrefix(token.INT, p.parseIntegerLiteral) return p } @@ -180,3 +182,18 @@ func (p *Parser) parseIdentifier() ast.Expression { Value: p.curToken.Literal, } } + +func (p *Parser) parseIntegerLiteral() ast.Expression { + lit := &ast.IntegerLiteral{Token: p.curToken} + + value, err := strconv.ParseInt(p.curToken.Literal, 0, 64) + if err != nil { + msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal) + p.errors = append(p.errors, msg) + return nil + } + + lit.Value = value + + return lit +} diff --git a/parser/parser_test.go b/parser/parser_test.go index f0b0d06..ef3d0a8 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -131,3 +131,34 @@ func TestIdentifierExpression(t *testing.T) { t.Errorf("ident.TokenLiteral not %s. got=%s", "foobar", ident.TokenLiteral()) } } + +func TestIntegerLiteralExpression(t *testing.T) { + input := "5;" + + l := lexer.New(input) + p := New(l) + program := p.ParseProgram() + checkParserErrors(t, p) + + if len(program.Statements) != 1 { + t.Fatalf("program has not enough statements. got=%d", + len(program.Statements)) + } + stmt, ok := program.Statements[0].(*ast.ExpressionStatement) + if !ok { + t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T", + program.Statements[0]) + } + + literal, ok := stmt.Expression.(*ast.IntegerLiteral) + if !ok { + t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression) + } + if literal.Value != 5 { + t.Errorf("literal.Value not %d. got=%d", 5, literal.Value) + } + if literal.TokenLiteral() != "5" { + t.Errorf("literal.TokenLiteral not %s. got=%s", "5", + literal.TokenLiteral()) + } +}