parse let expressions, handle syntax errors
This commit is contained in:
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user