Skip to content

Commit 0a373a0

Browse files
committed
feat: add parseIntegerLiteral
1 parent d5c8429 commit 0a373a0

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

ast/ast.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type Program struct {
2727
Statements []Statement // A program is a list of statements
2828
}
2929

30+
// TokenLiteral return the token literal of the first statement on ast
3031
func (p *Program) TokenLiteral() string {
3132
if len(p.Statements) > 0 {
3233
return p.Statements[0].TokenLiteral()
@@ -111,3 +112,12 @@ type Identifier struct {
111112
func (i *Identifier) expressionNode() {}
112113
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
113114
func (i *Identifier) String() string { return i.Value }
115+
116+
type IntegerLiteral struct {
117+
Token token.Token // the token.INT token
118+
Value int64
119+
}
120+
121+
func (il *IntegerLiteral) expressionNode() {}
122+
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
123+
func (il *IntegerLiteral) String() string { return il.Token.Literal }

parser/parser.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"monkey/ast"
66
"monkey/lexer"
77
"monkey/token"
8+
"strconv"
89
)
910

1011
type Parser struct {
@@ -28,6 +29,7 @@ func New(l *lexer.Lexer) *Parser {
2829

2930
p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
3031
p.registerPrefix(token.IDENT, p.parseIdentifier)
32+
p.registerPrefix(token.INT, p.parseIntegerLiteral)
3133

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

121+
func (p *Parser) parseIntegerLiteral() ast.Expression {
122+
lit := &ast.IntegerLiteral{Token: p.curToken}
123+
value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
124+
if err != nil {
125+
msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal)
126+
p.errors = append(p.errors, msg)
127+
return nil
128+
}
129+
lit.Value = value
130+
return lit
131+
}
132+
119133
func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
120134
stmt := &ast.ExpressionStatement{Token: p.curToken}
121135

parser/parser_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,34 @@ func TestIdentifierExpression(t *testing.T) {
123123
}
124124
}
125125

126+
func TestIntegerLiteralExpression(t *testing.T) {
127+
input := "5;"
128+
l := lexer.New(input)
129+
p := New(l)
130+
program := p.ParseProgram()
131+
checkParserErrors(t, p)
132+
if len(program.Statements) != 1 {
133+
t.Fatalf("program has not enough statements. got=%d",
134+
len(program.Statements))
135+
}
136+
stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
137+
if !ok {
138+
t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
139+
program.Statements[0])
140+
}
141+
literal, ok := stmt.Expression.(*ast.IntegerLiteral)
142+
if !ok {
143+
t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression)
144+
}
145+
if literal.Value != 5 {
146+
t.Errorf("literal.Value not %d. got=%d", 5, literal.Value)
147+
}
148+
if literal.TokenLiteral() != "5" {
149+
t.Errorf("literal.TokenLiteral not %s. got=%s", "5",
150+
literal.TokenLiteral())
151+
}
152+
}
153+
126154
func checkParserErrors(t *testing.T, p *Parser) {
127155
errors := p.Errors()
128156
if len(errors) == 0 {

0 commit comments

Comments
 (0)