summaryrefslogtreecommitdiff
path: root/parser/parser_test.go
diff options
context:
space:
mode:
authorMichael Tews <michael@tews.dev>2024-12-13 07:16:00 +0100
committerMichael Tews <michael@tews.dev>2026-04-12 11:11:02 +0200
commit68ff1414130b7bdd9cbfe0e5c1fc60278f9a48fd (patch)
tree5baeea833552b3f60f2c9f5dbf7d82492e066358 /parser/parser_test.go
parent0f51131eedb73d371bcf4d4868cb784f3592d08c (diff)
feat(parser): expressions, literalsHEADmain
Signed-off-by: Michael Tews <michael@tews.dev>
Diffstat (limited to 'parser/parser_test.go')
-rw-r--r--parser/parser_test.go171
1 files changed, 170 insertions, 1 deletions
diff --git a/parser/parser_test.go b/parser/parser_test.go
index f7158bf..be49bf5 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -1,9 +1,11 @@
package parser
import (
+ "fmt"
+ "testing"
+
"github.com/mewsen/interpreter/ast"
"github.com/mewsen/interpreter/lexer"
- "testing"
)
func TestLetStatements(t *testing.T) {
@@ -64,3 +66,170 @@ func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
return true
}
+
+func TestReturnStatement(t *testing.T) {
+ input := `
+return 5;
+return 10;
+return 993322;
+ `
+
+ l := lexer.New(input)
+ p := New(l)
+
+ program := p.ParseProgram()
+
+ checkParserErrors(t, p)
+
+ if len(program.Statements) != 3 {
+ t.Fatalf("program.Statements does not contain 3 statement. got=%d", len(program.Statements))
+ }
+
+ for _, stmt := range program.Statements {
+ returnStmt, ok := stmt.(*ast.ReturnStatement)
+ if !ok {
+ t.Errorf("stmt not *ast.returnStatement, got=%T", stmt)
+ continue
+ }
+ if returnStmt.TokenLiteral() != "return" {
+ t.Errorf("returnStmt.TokenLiteral not 'return', got=%q", returnStmt.TokenLiteral())
+ }
+ }
+}
+
+func TestIdentifierExpression(t *testing.T) {
+ input := "foobar;"
+
+ 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])
+ }
+
+ ident, ok := stmt.Expression.(*ast.Identifier)
+ if !ok {
+ t.Fatalf("exp not *ast.Identifier. got=%T", stmt.Expression)
+ }
+
+ if ident.Value != "foobar" {
+ t.Errorf("ident.Value not %s. got=%s", "foobar", ident.Value)
+ }
+
+ if ident.TokenLiteral() != "foobar" {
+ t.Errorf("ident.TokenLiteral not %s. got=%s", "foobar",
+ ident.TokenLiteral())
+ }
+}
+
+func checkParserErrors(t *testing.T, p *Parser) {
+ for _, err := range p.errors {
+ t.Fatal(err)
+ }
+}
+
+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("exp not *ast.IntergerLiteral. got=%T", program.Statements[0])
+ }
+
+ literal, ok := stmt.Expression.(*ast.IntegerLiteral)
+ if !ok {
+ t.Fatalf("literal.Value not %d, got=%d", 5, 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 TestParsingPrefixExpressions(t *testing.T) {
+ prefixTests := []struct {
+ input string
+ operator string
+ integerValue int64
+ }{
+ {"!5", "!", 5},
+ {"-15", "-", 15},
+ }
+
+ for _, tt := range prefixTests {
+ l := lexer.New(tt.input)
+ p := New(l)
+ program := p.ParseProgram()
+ checkParserErrors(t, p)
+
+ if len(program.Statements) != 1 {
+ t.Fatalf("program.Statements does not contain %d statements. got=%d\n",
+ 1, 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])
+ }
+
+ exp, ok := stmt.Expression.(*ast.PrefixExpression)
+ if !ok {
+ t.Fatalf("stmt is not ast.PrefixExpression. got=%T", stmt.Expression)
+ }
+
+ if exp.Operator != tt.operator {
+ t.Fatalf("exp.Operator is not %s. got=%s",
+ tt.operator, exp.Operator)
+ }
+
+ if !testIntegerLiteral(t, exp.Right, tt.integerValue) {
+ return
+ }
+ }
+}
+
+func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
+ integ, ok := il.(*ast.IntegerLiteral)
+ if !ok {
+ t.Errorf("il not *ast.IntegerLiteral. got=%T", il)
+ return false
+ }
+
+ if integ.Value != value {
+ t.Errorf("integ.Value not %d. got=%d", value, integ.Value)
+ return false
+ }
+
+ if integ.TokenLiteral() != fmt.Sprintf("%d", value) {
+ t.Errorf("integ.TokenLiteral not %d. got=%s", value,
+ integ.TokenLiteral())
+ return false
+ }
+
+ return true
+}