Make parser send error upwards instead of panicing
This commit is contained in:
parent
402644d219
commit
6b90cc488e
5 changed files with 246 additions and 129 deletions
26
cli/main.go
26
cli/main.go
|
|
@ -59,24 +59,11 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
||||||
log.Println("Initialized parser")
|
log.Println("Initialized parser")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
tree, err := p.Parse()
|
||||||
if r := recover(); r != nil {
|
|
||||||
if r != "no more tokens" { // if the panic was not caused by the parser, it should not be recovered.
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
for _, e := range p.Errors {
|
|
||||||
print(e.Format([]rune(src)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
tree := p.Parse()
|
|
||||||
|
|
||||||
// if there were parsing errors, print them out
|
// if there were parsing errors, print them out
|
||||||
if len(p.Errors) > 0 {
|
if err != nil {
|
||||||
for _, e := range p.Errors {
|
print(err.(*core.ParsingError).Format([]rune(src)))
|
||||||
print(e.Format([]rune(src)))
|
|
||||||
}
|
|
||||||
log.Fatal("Parsing had errors")
|
log.Fatal("Parsing had errors")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +152,12 @@ func (cmd *CompileCmd) Compile(ctx *Context) error {
|
||||||
if ctx.Debug {
|
if ctx.Debug {
|
||||||
log.Println("Parsing tree")
|
log.Println("Parsing tree")
|
||||||
}
|
}
|
||||||
tree := p.Parse()
|
|
||||||
|
tree, err := p.Parse()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
print(err.(*core.ParsingError).Format([]rune(src)))
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.Debug {
|
if ctx.Debug {
|
||||||
log.Println("Initialized compiler")
|
log.Println("Initialized compiler")
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,11 @@ func TestAll(t *testing.T) {
|
||||||
p := NewParser(tokens)
|
p := NewParser(tokens)
|
||||||
|
|
||||||
t.Log("Parsing tokens")
|
t.Log("Parsing tokens")
|
||||||
tree := p.Parse()
|
tree, err := p.Parse()
|
||||||
|
|
||||||
if p.hadError {
|
if err != nil {
|
||||||
for _, e := range p.Errors {
|
print(err.(*ParsingError).Format([]rune(tc.src)))
|
||||||
print(e.Format(tc.src))
|
t.Fatalf("parser had an error")
|
||||||
}
|
|
||||||
t.Fatalf("parser had error(s)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Log("Initializing compiler")
|
t.Log("Initializing compiler")
|
||||||
|
|
@ -82,7 +80,7 @@ func BenchmarkAll(b *testing.B) {
|
||||||
tokens, _ := l.Tokenize()
|
tokens, _ := l.Tokenize()
|
||||||
|
|
||||||
p := NewParser(tokens)
|
p := NewParser(tokens)
|
||||||
tree := p.Parse()
|
tree, _ := p.Parse()
|
||||||
|
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
c.Compile(tree)
|
c.Compile(tree)
|
||||||
|
|
|
||||||
311
core/parser.go
311
core/parser.go
|
|
@ -13,6 +13,10 @@ type ParsingError struct {
|
||||||
Causer *Token
|
Causer *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ParsingError) Error() string {
|
||||||
|
return p.Description
|
||||||
|
}
|
||||||
|
|
||||||
// Print a rich and informative error
|
// Print a rich and informative error
|
||||||
func (p *ParsingError) Format(src []rune) string {
|
func (p *ParsingError) Format(src []rune) string {
|
||||||
builder := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
|
|
@ -58,21 +62,16 @@ type Parser struct {
|
||||||
prev *Token
|
prev *Token
|
||||||
curr *Token
|
curr *Token
|
||||||
pos Pos
|
pos Pos
|
||||||
|
|
||||||
hadError bool
|
|
||||||
Errors []ParsingError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewParser(tokens []Token) *Parser {
|
func NewParser(tokens []Token) *Parser {
|
||||||
return &Parser{
|
return &Parser{
|
||||||
tokens: tokens,
|
tokens: tokens,
|
||||||
pos: 0,
|
pos: 0,
|
||||||
hadError: false,
|
|
||||||
Errors: make([]ParsingError, 0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) Parse() Node {
|
func (p *Parser) Parse() (Node, error) {
|
||||||
// top level statements
|
// top level statements
|
||||||
statements := make([]Node, 0)
|
statements := make([]Node, 0)
|
||||||
|
|
||||||
|
|
@ -80,12 +79,18 @@ func (p *Parser) Parse() Node {
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
for int(p.pos) < len(p.tokens) && p.curr.Type != TokenEOF {
|
for int(p.pos) < len(p.tokens) && p.curr.Type != TokenEOF {
|
||||||
statements = append(statements, p.block(true))
|
b, err := p.block(true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
statements = append(statements, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BlockNode{
|
return &BlockNode{
|
||||||
statements: statements,
|
statements: statements,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) accept(tokenType TokenType) bool {
|
func (p *Parser) accept(tokenType TokenType) bool {
|
||||||
|
|
@ -102,11 +107,11 @@ func (p *Parser) accept(tokenType TokenType) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) expect(tokenType TokenType) {
|
func (p *Parser) expect(tokenType TokenType) error {
|
||||||
if !p.accept(tokenType) {
|
if !p.accept(tokenType) {
|
||||||
p.error("Expected token "+tokenType.String()+", got "+p.curr.Type.String(), p.curr)
|
return p.error("Expected token "+tokenType.String()+", got "+p.curr.Type.String(), p.curr)
|
||||||
p.advance()
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) peek() (Token, error) {
|
func (p *Parser) peek() (Token, error) {
|
||||||
|
|
@ -128,103 +133,125 @@ func (p *Parser) advance() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) error(error string, causer *Token) {
|
func (p *Parser) error(error string, causer *Token) error {
|
||||||
p.hadError = true
|
return &ParsingError{
|
||||||
p.Errors = append(p.Errors, ParsingError{
|
|
||||||
Description: error,
|
Description: error,
|
||||||
Causer: causer,
|
Causer: causer,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) factor() Node {
|
func (p *Parser) factor() (Node, error) {
|
||||||
switch (*p.curr).Type {
|
switch (*p.curr).Type {
|
||||||
case TokenString:
|
case TokenString:
|
||||||
p.advance()
|
p.advance()
|
||||||
return &StringNode{
|
return &StringNode{
|
||||||
(*p.prev).Lexeme[1 : len((*p.prev).Lexeme)-1],
|
(*p.prev).Lexeme[1 : len((*p.prev).Lexeme)-1],
|
||||||
(*p.prev).Lexeme,
|
(*p.prev).Lexeme,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenNumber:
|
case TokenNumber:
|
||||||
p.advance()
|
p.advance()
|
||||||
num, err := strconv.ParseFloat((*p.prev).Lexeme, NumberSize)
|
num, err := strconv.ParseFloat((*p.prev).Lexeme, NumberSize)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.error(fmt.Sprintf("Error parsing number: %v", err), p.prev)
|
return nil, p.error(fmt.Sprintf("Error parsing number: %v", err), p.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NumberNode{
|
return &NumberNode{
|
||||||
NumberValue(num),
|
NumberValue(num),
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenTrue:
|
case TokenTrue:
|
||||||
p.advance()
|
p.advance()
|
||||||
return &BooleanNode{
|
return &BooleanNode{
|
||||||
true,
|
true,
|
||||||
}
|
}, nil
|
||||||
case TokenFalse:
|
case TokenFalse:
|
||||||
p.advance()
|
p.advance()
|
||||||
return &BooleanNode{
|
return &BooleanNode{
|
||||||
false,
|
false,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenNil:
|
case TokenNil:
|
||||||
p.advance()
|
p.advance()
|
||||||
return &NilNode{}
|
return &NilNode{}, nil
|
||||||
|
|
||||||
// unary minus
|
// unary minus
|
||||||
case TokenMinus:
|
case TokenMinus:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
f, err := p.factor()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &BinaryNode{
|
return &BinaryNode{
|
||||||
BinarySubtraction,
|
BinarySubtraction,
|
||||||
&NumberNode{NumberValue(0)},
|
&NumberNode{NumberValue(0)},
|
||||||
p.factor(),
|
f,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenName:
|
case TokenName:
|
||||||
p.advance()
|
p.advance()
|
||||||
name := (*p.prev).Lexeme
|
name := (*p.prev).Lexeme
|
||||||
|
|
||||||
if p.curr.Type == TokenOpenParenthesis {
|
if p.curr.Type == TokenOpenParenthesis {
|
||||||
args := p.parseArgs()
|
args, err := p.parseArgs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &CallNode{
|
return &CallNode{
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
true,
|
true,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ReferenceNode{
|
return &ReferenceNode{
|
||||||
name,
|
name,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenFunc:
|
case TokenFunc:
|
||||||
p.advance()
|
p.advance()
|
||||||
params := p.parseParams()
|
params, err := p.parseParams()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := p.block(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &FunctionNode{
|
return &FunctionNode{
|
||||||
"*",
|
"*",
|
||||||
params,
|
params,
|
||||||
p.block(false),
|
b,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenOpenParenthesis:
|
case TokenOpenParenthesis:
|
||||||
p.advance()
|
p.advance()
|
||||||
v := p.condition()
|
v, err := p.condition()
|
||||||
p.expect(TokenCloseParenthesis)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return v, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.error("invalid factor", p.curr)
|
err := p.error("invalid factor", p.curr)
|
||||||
p.advance()
|
p.advance()
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) product() Node {
|
func (p *Parser) product() (Node, error) {
|
||||||
left := p.factor()
|
left, err := p.factor()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for p.accept(TokenStar) || p.accept(TokenSlash) {
|
for p.accept(TokenStar) || p.accept(TokenSlash) {
|
||||||
op := BinaryMultiplication
|
op := BinaryMultiplication
|
||||||
|
|
@ -233,18 +260,26 @@ func (p *Parser) product() Node {
|
||||||
op = BinaryDivision
|
op = BinaryDivision
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f, err := p.factor()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
left = &BinaryNode{
|
left = &BinaryNode{
|
||||||
op,
|
op,
|
||||||
left,
|
left,
|
||||||
p.factor(),
|
f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) term() Node {
|
func (p *Parser) term() (Node, error) {
|
||||||
left := p.product()
|
left, err := p.product()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for p.accept(TokenPlus) || p.accept(TokenMinus) {
|
for p.accept(TokenPlus) || p.accept(TokenMinus) {
|
||||||
op := BinaryAddition
|
op := BinaryAddition
|
||||||
|
|
@ -253,18 +288,28 @@ func (p *Parser) term() Node {
|
||||||
op = BinarySubtraction
|
op = BinarySubtraction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pr, err := p.product()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
left = &BinaryNode{
|
left = &BinaryNode{
|
||||||
op,
|
op,
|
||||||
left,
|
left,
|
||||||
p.product(),
|
pr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return left
|
return left, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) comparison() (Node, error) {
|
||||||
|
left, err := p.term()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) comparison() Node {
|
|
||||||
left := p.term()
|
|
||||||
op := BinaryEquality
|
op := BinaryEquality
|
||||||
|
|
||||||
switch (*p.curr).Type {
|
switch (*p.curr).Type {
|
||||||
|
|
@ -281,20 +326,30 @@ func (p *Parser) comparison() Node {
|
||||||
case TokenGreaterThanOrEqual:
|
case TokenGreaterThanOrEqual:
|
||||||
op = BinaryGreaterEqual
|
op = BinaryGreaterEqual
|
||||||
default:
|
default:
|
||||||
return left
|
return left, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
|
t, err := p.term()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &BinaryNode{
|
return &BinaryNode{
|
||||||
op,
|
op,
|
||||||
left,
|
left,
|
||||||
p.term(),
|
t,
|
||||||
}
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) condition() (Node, error) {
|
||||||
|
left, err := p.comparison()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) condition() Node {
|
|
||||||
left := p.comparison()
|
|
||||||
op := BinaryEquality
|
op := BinaryEquality
|
||||||
|
|
||||||
switch (*p.curr).Type {
|
switch (*p.curr).Type {
|
||||||
|
|
@ -303,57 +358,80 @@ func (p *Parser) condition() Node {
|
||||||
case TokenDoublePipe:
|
case TokenDoublePipe:
|
||||||
op = BinaryOr
|
op = BinaryOr
|
||||||
default:
|
default:
|
||||||
return left
|
return left, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
|
c, err := p.comparison()
|
||||||
|
if err != nil {
|
||||||
|
return left, err
|
||||||
|
}
|
||||||
|
|
||||||
return &BinaryNode{
|
return &BinaryNode{
|
||||||
op,
|
op,
|
||||||
left,
|
left,
|
||||||
p.comparison(),
|
c,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) statement() Node {
|
func (p *Parser) statement() (Node, error) {
|
||||||
switch (*p.curr).Type {
|
switch (*p.curr).Type {
|
||||||
case TokenIf:
|
case TokenIf:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
condition := p.condition()
|
condition, err := p.condition()
|
||||||
then := p.block(false)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
then, err := p.block(false)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var otherwise Node
|
var otherwise Node
|
||||||
|
|
||||||
if p.accept(TokenElse) {
|
if p.accept(TokenElse) {
|
||||||
otherwise = p.block(false)
|
otherwise, err = p.block(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ConditionalNode{
|
return &ConditionalNode{
|
||||||
condition,
|
condition,
|
||||||
then,
|
then,
|
||||||
otherwise,
|
otherwise,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenName:
|
case TokenName:
|
||||||
p.advance()
|
p.advance()
|
||||||
name := (*p.prev).Lexeme
|
name := (*p.prev).Lexeme
|
||||||
|
|
||||||
if p.curr.Type == TokenOpenParenthesis {
|
if p.curr.Type == TokenOpenParenthesis {
|
||||||
args := p.parseArgs()
|
args, err := p.parseArgs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &CallNode{
|
return &CallNode{
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
false,
|
false,
|
||||||
}
|
}, nil
|
||||||
} else if p.accept(TokenAssign) || p.accept(TokenDeclare) {
|
} else if p.accept(TokenAssign) || p.accept(TokenDeclare) {
|
||||||
isDeclaration := p.prev.Type == TokenDeclare
|
isDeclaration := p.prev.Type == TokenDeclare
|
||||||
|
c, err := p.condition()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &AssignNode{
|
return &AssignNode{
|
||||||
name,
|
name,
|
||||||
p.condition(),
|
c,
|
||||||
isDeclaration,
|
isDeclaration,
|
||||||
}
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
return p.condition()
|
return p.condition()
|
||||||
}
|
}
|
||||||
|
|
@ -361,101 +439,154 @@ func (p *Parser) statement() Node {
|
||||||
case TokenFunc:
|
case TokenFunc:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
p.expect(TokenName)
|
if err := p.expect(TokenName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
name := p.prev.Lexeme
|
name := p.prev.Lexeme
|
||||||
|
|
||||||
params := p.parseParams()
|
params, err := p.parseParams()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := p.block(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &AssignNode{
|
return &AssignNode{
|
||||||
name,
|
name,
|
||||||
&FunctionNode{
|
&FunctionNode{
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
p.block(false),
|
b,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
case TokenWhile:
|
case TokenWhile:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
return &LoopNode{
|
c, err := p.condition()
|
||||||
p.condition(),
|
if err != nil {
|
||||||
p.block(false),
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b, err := p.block(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LoopNode{
|
||||||
|
c,
|
||||||
|
b,
|
||||||
|
}, nil
|
||||||
|
|
||||||
case TokenReturn:
|
case TokenReturn:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
return &ReturnNode{
|
c, err := p.condition()
|
||||||
p.condition(),
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return &ReturnNode{
|
||||||
|
c,
|
||||||
|
}, nil
|
||||||
|
|
||||||
case TokenBreakpoint:
|
case TokenBreakpoint:
|
||||||
p.advance()
|
p.advance()
|
||||||
|
|
||||||
return &BreakpointNode{}
|
return &BreakpointNode{}, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.error("invalid statement", p.curr)
|
err := p.error("invalid statement", p.curr)
|
||||||
p.advance()
|
p.advance()
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) block(canBeStatement bool) Node {
|
func (p *Parser) block(canBeStatement bool) (Node, error) {
|
||||||
if canBeStatement {
|
if canBeStatement {
|
||||||
if !p.accept(TokenOpenBrace) {
|
if !p.accept(TokenOpenBrace) {
|
||||||
return p.statement()
|
return p.statement()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.expect(TokenOpenBrace)
|
if err := p.expect(TokenOpenBrace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statements := make([]Node, 0)
|
statements := make([]Node, 0)
|
||||||
|
|
||||||
for !p.accept(TokenCloseBrace) {
|
for !p.accept(TokenCloseBrace) {
|
||||||
statements = append(statements, p.statement())
|
s, err := p.statement()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
statements = append(statements, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BlockNode{
|
return &BlockNode{
|
||||||
statements,
|
statements,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseArgs() []Node {
|
func (p *Parser) parseArgs() ([]Node, error) {
|
||||||
args := make([]Node, 0)
|
args := make([]Node, 0)
|
||||||
|
|
||||||
p.expect(TokenOpenParenthesis)
|
if err := p.expect(TokenOpenParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if !p.accept(TokenCloseParenthesis) {
|
if !p.accept(TokenCloseParenthesis) {
|
||||||
args = append(args, p.condition())
|
c, err := p.condition()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args = append(args, c)
|
||||||
for !p.accept(TokenCloseParenthesis) {
|
for !p.accept(TokenCloseParenthesis) {
|
||||||
p.expect(TokenComma)
|
if err := p.expect(TokenComma); err != nil {
|
||||||
args = append(args, p.condition())
|
return nil, err
|
||||||
|
}
|
||||||
|
c, err = p.condition()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args = append(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return args
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseParams parse parameters and parentheses
|
// parseParams parse parameters and parentheses
|
||||||
func (p *Parser) parseParams() []string {
|
func (p *Parser) parseParams() ([]string, error) {
|
||||||
p.expect(TokenOpenParenthesis)
|
if err := p.expect(TokenOpenParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
params := make([]string, 0)
|
params := make([]string, 0)
|
||||||
|
|
||||||
if p.accept(TokenName) {
|
if p.accept(TokenName) {
|
||||||
name := (*p.prev).Lexeme
|
name := (*p.prev).Lexeme
|
||||||
params = append(params, name)
|
params = append(params, name)
|
||||||
for !p.accept(TokenCloseParenthesis) {
|
for !p.accept(TokenCloseParenthesis) {
|
||||||
p.expect(TokenComma)
|
if err := p.expect(TokenComma); err != nil {
|
||||||
p.expect(TokenName)
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := p.expect(TokenName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
name = (*p.prev).Lexeme
|
name = (*p.prev).Lexeme
|
||||||
params = append(params, name)
|
params = append(params, name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.expect(TokenCloseParenthesis)
|
if err := p.expect(TokenCloseParenthesis); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,6 @@ func TestNewParser(t *testing.T) {
|
||||||
t.Fatal("parser should not be nil")
|
t.Fatal("parser should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.hadError {
|
|
||||||
t.Error("parser should not when initialized report an error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.pos != 0 {
|
if p.pos != 0 {
|
||||||
t.Error("parser should initialize position at 0")
|
t.Error("parser should initialize position at 0")
|
||||||
}
|
}
|
||||||
|
|
@ -602,10 +598,10 @@ func TestParser_Parse(t *testing.T) {
|
||||||
p := NewParser(data.tokens)
|
p := NewParser(data.tokens)
|
||||||
|
|
||||||
t.Logf("Parsing main")
|
t.Logf("Parsing main")
|
||||||
tree := p.Parse()
|
tree, err := p.Parse()
|
||||||
|
|
||||||
if p.hadError {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error(s): %s", p.Errors)
|
t.Fatalf("Unexpected error(s): %s", err.(*ParsingError).Format([]rune{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Checking parsed tree")
|
t.Logf("Checking parsed tree")
|
||||||
|
|
@ -622,7 +618,7 @@ func BenchmarkParser_Parse(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
p := NewParser(data.tokens)
|
p := NewParser(data.tokens)
|
||||||
|
|
||||||
_ = p.Parse()
|
_, _ = p.Parse()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
wasm/wasm.go
10
wasm/wasm.go
|
|
@ -39,14 +39,14 @@ func run(this js.Value, args []js.Value) interface{} {
|
||||||
|
|
||||||
parser := core.NewParser(tokens)
|
parser := core.NewParser(tokens)
|
||||||
|
|
||||||
tree := parser.Parse()
|
tree, err := parser.Parse()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return jsErrorOfString(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Parsed tree: %s", tree.String())
|
log.Printf("Parsed tree: %s", tree.String())
|
||||||
|
|
||||||
if len(parser.Errors) > 0 {
|
|
||||||
return jsErrorOfString(parser.Errors[0].Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler := core.NewCompiler()
|
compiler := core.NewCompiler()
|
||||||
|
|
||||||
compiler.Compile(tree)
|
compiler.Compile(tree)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue