commit 8885f23423bb7f442000fab6261d9fb427b930e9
parent 734ab8682a5f8bcff89e9bf5f344852d9e849929
Author: bsandro <email@bsandro.tech>
Date: Mon, 13 Jun 2022 18:34:51 +0300
parser: integer literal support
Diffstat:
3 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/ast/ast.go b/ast/ast.go
@@ -109,3 +109,16 @@ func (p *Program) String() string {
}
return out.String()
}
+
+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
@@ -5,6 +5,7 @@ import (
"interp/ast"
"interp/lexer"
"interp/token"
+ "strconv"
)
const (
@@ -41,6 +42,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
}
@@ -129,6 +131,18 @@ 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}
+ value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
+ if err != nil {
+ msg := fmt.Sprintf("error parsing %q as int64", p.curToken.Literal)
+ p.errors = append(p.errors, msg)
+ return nil
+ }
+ lit.Value = value
+ return lit
+}
+
func (p *Parser) curTokenIs(t token.TokenType) bool {
return p.curToken.Type == t
}
diff --git a/parser/parser_test.go b/parser/parser_test.go
@@ -135,3 +135,33 @@ func TestIdentifierExpression(t *testing.T) {
t.Errorf("ident.TokenLiteral() is not 'foo' but %s", ident.TokenLiteral())
}
}
+
+func TestIntegerLiteralExpression(t *testing.T) {
+ input := "8;"
+ l := lexer.New(input)
+ p := New(l)
+ prg := p.ParseProgram()
+ checkParserErrors(t, p)
+
+ if len(prg.Statements) != 1 {
+ t.Fatalf("statements count is not 1 but %d", len(prg.Statements))
+ }
+
+ statement, ok := prg.Statements[0].(*ast.ExpressionStatement)
+ if !ok {
+ t.Fatalf("prg.Statements[0] is not ExpressionStatement but %T", prg.Statements[0])
+ }
+
+ literal, ok := statement.Expression.(*ast.IntegerLiteral)
+ if !ok {
+ t.Fatalf("statement.Expression is not IntegerLiteral but %T", statement.Expression)
+ }
+
+ if literal.Value != 8 {
+ t.Errorf("literal.Value is not 8 but %d", literal.Value)
+ }
+
+ if literal.TokenLiteral() != "8" {
+ t.Errorf("literal.TokenLiteral is not '8' but %s", literal.TokenLiteral())
+ }
+}