diff --git a/parser/parser.go b/parser/parser.go new file mode 100644 index 0000000..24a2412 --- /dev/null +++ b/parser/parser.go @@ -0,0 +1,35 @@ +package parser + +import ( + "monkey/ast" + "monkey/lexer" + "monkey/token" +) + +type Parser struct { + lexer *lexer.Lexer + + current_token token.Token + peek_token token.Token +} + +func New(l_lexer *lexer.Lexer) *Parser { + l_parser := &Parser{lexer: l_lexer} + + // Read two tokens, one for curren_token and another for peek_token + l_parser.next_token() + l_parser.next_token() + + return l_parser +} + +// When this is first called, current_token and peek_token should point to the same +// token +func (l_parser *Parser) next_token() { + l_parser.current_token = l_parser.peek_token + l_parser.peek_token = l_parser.lexer.NextToken() +} + +func (l_parser *Parser) ParseProgram() *ast.Program { + return nil +} diff --git a/parser/parser_test.go b/parser/parser_test.go new file mode 100644 index 0000000..7b78698 --- /dev/null +++ b/parser/parser_test.go @@ -0,0 +1,64 @@ +package parser + +import ( + "monkey/ast" + "monkey/lexer" + "testing" +) + +func TestLetStatements(t *testing.T) { + input := ` + let x = 5; + let y = 10; + let foobar = 839893; + ` + + l_lexer := lexer.New(input) + l_parser := New(l_lexer) + + program := l_parser.ParseProgram() + if program == nil { + t.Fatalf("ParseProgram() returned nil") + } + + if len(program.Statements) != 3 { + t.Fatalf("program.Statements does not contail 3 statements, got=%d", len(program.Statements)) + } + + tests := []struct { + expectedIdentifier string + }{ + {"x"}, {"y"}, {"foobar"}, + } + + for i, tt := range tests { + stmt := program.Statements[i] + if !testLetStatement(t, stmt, tt.expectedIdentifier) { + return + } + } +} + +func testLetStatement(t *testing.T, s ast.Statement, name string) bool { + if s.TokenLiteral() != "let" { + t.Errorf("s.TokenLiteral not 'let', got=%q", s.TokenLiteral()) + return false + } + + letStmt, ok := s.(*ast.LetStatement) + if !ok { + t.Errorf("s not *ast.LetStatement, got=%T", s) + return false + } + + if letStmt.Name.TokenLiteral() != name { + t.Errorf("letStmt.Name.TokenLiteral() not '%s', got =%s", name, letStmt.Name.TokenLiteral()) + return false + } + + if letStmt.Name.Value != name { + t.Errorf("letStmt.Name.Value not '%s', got =%s", name, letStmt.Name.Value) + return false + } + return true +}