From 2742c41e985d17cd7376e12d8cef4d75d7a2c1ae Mon Sep 17 00:00:00 2001 From: Tommy Parnell Date: Sat, 30 Dec 2017 16:23:30 -0500 Subject: [PATCH] parse let expressions, handle syntax errors --- Readme.md | 2 +- parser/parser.go | 17 ++++++++++++++++- parser/parser_test.go | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 6af820f..a9e54d9 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -These are my source files for working on Thorsten Ball's [Writing an interpreter in go](https://interpreterbook.com/) book. The ultimate goal of this source code is to interpret, and execute code written in a language called monkey. +These are my source files for working on Thorsten Ball's [Writing an interpreter in go](https://interpreterbook.com/) book. The ultimate goal of this source code is to interpret, and execute code written in a language called monkey. I'm still going through the book so this repo maybe incomplete. An example of monkey is below. Monkey is a c-like language with closures, first class functions, and variable bindings. diff --git a/parser/parser.go b/parser/parser.go index df11aa2..cb41c26 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,6 +1,7 @@ package parser import ( + "fmt" "monkey/ast" "monkey/lexer" "monkey/token" @@ -11,10 +12,14 @@ type Parser struct { curToken token.Token peekToken token.Token + errors []string } func New(l *lexer.Lexer) *Parser { - p := &Parser{l: l} + p := &Parser{ + l: l, + errors: []string{}, + } // Read two tokens, so curToken and peekToken are both set p.nextToken() @@ -86,6 +91,16 @@ func (p *Parser) expectPeek(t token.TokenType) bool { p.nextToken() return true } else { + p.peekError(t) return false } } +func (p *Parser) Errors() []string { + return p.errors +} + +func (p *Parser) peekError(t token.TokenType) { + msg := fmt.Sprintf("expected next token to be %s, got %s instead", + t, p.peekToken.Type) + p.errors = append(p.errors, msg) +} diff --git a/parser/parser_test.go b/parser/parser_test.go index cc494ff..9dbe14c 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -16,6 +16,8 @@ let foobar = 838383; p := New(l) program := p.ParseProgram() + checkParserErrors(t, p) + if program == nil { t.Fatalf("ParseProgram() returned nil") } @@ -40,6 +42,19 @@ let foobar = 838383; } } +func checkParserErrors(t *testing.T, p *Parser) { + errors := p.Errors() + if len(errors) == 0 { + return + } + + t.Errorf("parser has %d errors", len(errors)) + for _, msg := range errors { + t.Errorf("parser error: %q", msg) + } + t.FailNow() +} + 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())