Skip to content

Commit

Permalink
feat: add parseIntegerLiteral
Browse files Browse the repository at this point in the history
  • Loading branch information
estevanbs committed Jul 21, 2024
1 parent d5c8429 commit 0a373a0
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
10 changes: 10 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Program struct {
Statements []Statement // A program is a list of statements
}

// TokenLiteral return the token literal of the first statement on ast
func (p *Program) TokenLiteral() string {
if len(p.Statements) > 0 {
return p.Statements[0].TokenLiteral()
Expand Down Expand Up @@ -111,3 +112,12 @@ type Identifier struct {
func (i *Identifier) expressionNode() {}
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
func (i *Identifier) String() string { return i.Value }

type IntegerLiteral struct {
Token token.Token // the token.INT 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 }
14 changes: 14 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"monkey/ast"
"monkey/lexer"
"monkey/token"
"strconv"
)

type Parser struct {
Expand All @@ -28,6 +29,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)

// Read two tokens, so curToken and peekToken are both set
p.nextToken()
Expand Down Expand Up @@ -116,6 +118,18 @@ func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
return stmt
}

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
}

func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
stmt := &ast.ExpressionStatement{Token: p.curToken}

Expand Down
28 changes: 28 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,34 @@ func TestIdentifierExpression(t *testing.T) {
}
}

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())
}
}

func checkParserErrors(t *testing.T, p *Parser) {
errors := p.Errors()
if len(errors) == 0 {
Expand Down

0 comments on commit 0a373a0

Please sign in to comment.