parse let expressions, handle syntax errors

This commit is contained in:
Tommy Parnell
2017-12-30 16:23:30 -05:00
parent 725e4dc5bf
commit 2742c41e98
3 changed files with 32 additions and 2 deletions

View File

@@ -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. An example of monkey is below. Monkey is a c-like language with closures, first class functions, and variable bindings.

View File

@@ -1,6 +1,7 @@
package parser package parser
import ( import (
"fmt"
"monkey/ast" "monkey/ast"
"monkey/lexer" "monkey/lexer"
"monkey/token" "monkey/token"
@@ -11,10 +12,14 @@ type Parser struct {
curToken token.Token curToken token.Token
peekToken token.Token peekToken token.Token
errors []string
} }
func New(l *lexer.Lexer) *Parser { 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 // Read two tokens, so curToken and peekToken are both set
p.nextToken() p.nextToken()
@@ -86,6 +91,16 @@ func (p *Parser) expectPeek(t token.TokenType) bool {
p.nextToken() p.nextToken()
return true return true
} else { } else {
p.peekError(t)
return false 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)
}

View File

@@ -16,6 +16,8 @@ let foobar = 838383;
p := New(l) p := New(l)
program := p.ParseProgram() program := p.ParseProgram()
checkParserErrors(t, p)
if program == nil { if program == nil {
t.Fatalf("ParseProgram() returned 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 { func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
if s.TokenLiteral() != "let" { if s.TokenLiteral() != "let" {
t.Errorf("s.TokenLiteral not 'let'. got=%q", s.TokenLiteral()) t.Errorf("s.TokenLiteral not 'let'. got=%q", s.TokenLiteral())