From c2c634d757d1b98674eaf58bcf0d346a23bedecb Mon Sep 17 00:00:00 2001 From: Mark Bates Date: Fri, 22 Dec 2017 15:07:30 -0500 Subject: [PATCH] added support for line numbers in errors fixes #3 --- ast/array_literal.go | 11 +---- ast/ast.go | 15 +++++++ ast/ast_test.go | 10 ++--- ast/block_statement.go | 11 +---- ast/boolean.go | 11 +---- ast/call_expression.go | 11 +---- ast/expression_statement.go | 11 +---- ast/float_literal.go | 11 +---- ast/for_expression.go | 11 +---- ast/function_literal.go | 10 +---- ast/hash_literal.go | 10 +---- ast/html_literal.go | 11 +---- ast/identifier.go | 11 +---- ast/if_expression.go | 10 +---- ast/index_expression.go | 10 +---- ast/infix_expression.go | 11 +---- ast/integer_literal.go | 11 +---- ast/let_statement.go | 10 +---- ast/prefix_expression.go | 10 +---- ast/return_statement.go | 11 +---- ast/string_literal.go | 11 +---- compiler.go | 2 +- lexer/lexer.go | 89 ++++++++++++++++++++----------------- parser/parser.go | 76 +++++++++++++++---------------- token/token.go | 5 ++- 25 files changed, 148 insertions(+), 252 deletions(-) diff --git a/ast/array_literal.go b/ast/array_literal.go index 1788a58..18f4942 100644 --- a/ast/array_literal.go +++ b/ast/array_literal.go @@ -3,21 +3,14 @@ package ast import ( "bytes" "strings" - - "github.com/gobuffalo/plush/token" ) type ArrayLiteral struct { - Token token.Token + TokenAble Elements []Expression } -func (al *ArrayLiteral) expressionNode() { -} - -func (al *ArrayLiteral) TokenLiteral() string { - return al.Token.Literal -} +func (al *ArrayLiteral) expressionNode() {} func (al *ArrayLiteral) String() string { var out bytes.Buffer diff --git a/ast/ast.go b/ast/ast.go index 0ce7163..81b8404 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -1,11 +1,26 @@ package ast +import "github.com/gobuffalo/plush/token" + +type TokenAble struct { + token.Token +} + +func (t TokenAble) T() token.Token { + return t.Token +} + +func (t TokenAble) TokenLiteral() string { + return t.Token.Literal +} + type Printable interface { Printable() bool } // The base Node interface type Node interface { + T() token.Token TokenLiteral() string String() string } diff --git a/ast/ast_test.go b/ast/ast_test.go index 3e73c2c..2b56b81 100644 --- a/ast/ast_test.go +++ b/ast/ast_test.go @@ -12,14 +12,14 @@ func Test_Program_String(t *testing.T) { program := &Program{ Statements: []Statement{ &LetStatement{ - Token: token.Token{Type: token.LET, Literal: "let"}, + TokenAble: TokenAble{token.Token{Type: token.LET, Literal: "let"}}, Name: &Identifier{ - Token: token.Token{Type: token.IDENT, Literal: "myVar"}, - Value: "myVar", + TokenAble: TokenAble{token.Token{Type: token.IDENT, Literal: "myVar"}}, + Value: "myVar", }, Value: &Identifier{ - Token: token.Token{Type: token.IDENT, Literal: "anotherVar"}, - Value: "anotherVar", + TokenAble: TokenAble{token.Token{Type: token.IDENT, Literal: "anotherVar"}}, + Value: "anotherVar", }, }, }, diff --git a/ast/block_statement.go b/ast/block_statement.go index 40befb3..4149d22 100644 --- a/ast/block_statement.go +++ b/ast/block_statement.go @@ -2,21 +2,14 @@ package ast import ( "bytes" - - "github.com/gobuffalo/plush/token" ) type BlockStatement struct { - Token token.Token + TokenAble Statements []Statement } -func (bs *BlockStatement) statementNode() { -} - -func (bs *BlockStatement) TokenLiteral() string { - return bs.Token.Literal -} +func (bs *BlockStatement) statementNode() {} func (bs *BlockStatement) String() string { var out bytes.Buffer diff --git a/ast/boolean.go b/ast/boolean.go index c06a5f3..2529609 100644 --- a/ast/boolean.go +++ b/ast/boolean.go @@ -1,18 +1,11 @@ package ast -import "github.com/gobuffalo/plush/token" - type Boolean struct { - Token token.Token + TokenAble Value bool } -func (b *Boolean) expressionNode() { -} - -func (b *Boolean) TokenLiteral() string { - return b.Token.Literal -} +func (b *Boolean) expressionNode() {} func (b *Boolean) String() string { return b.Token.Literal diff --git a/ast/call_expression.go b/ast/call_expression.go index 656401b..5da240c 100644 --- a/ast/call_expression.go +++ b/ast/call_expression.go @@ -3,12 +3,10 @@ package ast import ( "bytes" "strings" - - "github.com/gobuffalo/plush/token" ) type CallExpression struct { - Token token.Token + TokenAble Callee Expression Function Expression Arguments []Expression @@ -16,12 +14,7 @@ type CallExpression struct { ElseBlock *BlockStatement } -func (ce *CallExpression) expressionNode() { -} - -func (ce *CallExpression) TokenLiteral() string { - return ce.Token.Literal -} +func (ce *CallExpression) expressionNode() {} func (ce *CallExpression) String() string { var out bytes.Buffer diff --git a/ast/expression_statement.go b/ast/expression_statement.go index 7909b5a..2e79cab 100644 --- a/ast/expression_statement.go +++ b/ast/expression_statement.go @@ -1,18 +1,11 @@ package ast -import "github.com/gobuffalo/plush/token" - type ExpressionStatement struct { - Token token.Token + TokenAble Expression Expression } -func (es *ExpressionStatement) statementNode() { -} - -func (es *ExpressionStatement) TokenLiteral() string { - return es.Token.Literal -} +func (es *ExpressionStatement) statementNode() {} func (es *ExpressionStatement) String() string { if es.Expression != nil { diff --git a/ast/float_literal.go b/ast/float_literal.go index d14d992..1697af5 100644 --- a/ast/float_literal.go +++ b/ast/float_literal.go @@ -1,18 +1,11 @@ package ast -import "github.com/gobuffalo/plush/token" - type FloatLiteral struct { - Token token.Token + TokenAble Value float64 } -func (il *FloatLiteral) expressionNode() { -} - -func (il *FloatLiteral) TokenLiteral() string { - return il.Token.Literal -} +func (il *FloatLiteral) expressionNode() {} func (il *FloatLiteral) String() string { return il.Token.Literal diff --git a/ast/for_expression.go b/ast/for_expression.go index bf187e2..292c679 100644 --- a/ast/for_expression.go +++ b/ast/for_expression.go @@ -2,24 +2,17 @@ package ast import ( "bytes" - - "github.com/gobuffalo/plush/token" ) type ForExpression struct { - Token token.Token + TokenAble KeyName string ValueName string Block *BlockStatement Iterable Expression } -func (fe *ForExpression) expressionNode() { -} - -func (fe *ForExpression) TokenLiteral() string { - return fe.Token.Literal -} +func (fe *ForExpression) expressionNode() {} func (fe *ForExpression) String() string { var out bytes.Buffer diff --git a/ast/function_literal.go b/ast/function_literal.go index 2be6a74..862db9c 100644 --- a/ast/function_literal.go +++ b/ast/function_literal.go @@ -2,22 +2,16 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" "strings" ) type FunctionLiteral struct { - Token token.Token + TokenAble Parameters []*Identifier Block *BlockStatement } -func (fl *FunctionLiteral) expressionNode() { -} - -func (fl *FunctionLiteral) TokenLiteral() string { - return fl.Token.Literal -} +func (fl *FunctionLiteral) expressionNode() {} func (fl *FunctionLiteral) String() string { var out bytes.Buffer diff --git a/ast/hash_literal.go b/ast/hash_literal.go index 8e78525..c11f5ee 100644 --- a/ast/hash_literal.go +++ b/ast/hash_literal.go @@ -2,21 +2,15 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" "strings" ) type HashLiteral struct { - Token token.Token + TokenAble Pairs map[Expression]Expression } -func (hl *HashLiteral) expressionNode() { -} - -func (hl *HashLiteral) TokenLiteral() string { - return hl.Token.Literal -} +func (hl *HashLiteral) expressionNode() {} func (hl *HashLiteral) String() string { var out bytes.Buffer diff --git a/ast/html_literal.go b/ast/html_literal.go index 03795b2..065d1b8 100644 --- a/ast/html_literal.go +++ b/ast/html_literal.go @@ -1,9 +1,7 @@ package ast -import "github.com/gobuffalo/plush/token" - type HTMLLiteral struct { - Token token.Token + TokenAble Value string } @@ -11,12 +9,7 @@ func (hl *HTMLLiteral) Printable() bool { return true } -func (hl *HTMLLiteral) expressionNode() { -} - -func (hl *HTMLLiteral) TokenLiteral() string { - return hl.Token.Literal -} +func (hl *HTMLLiteral) expressionNode() {} func (hl *HTMLLiteral) String() string { return hl.Token.Literal diff --git a/ast/identifier.go b/ast/identifier.go index 19dc099..137a444 100644 --- a/ast/identifier.go +++ b/ast/identifier.go @@ -2,22 +2,15 @@ package ast import ( "bytes" - - "github.com/gobuffalo/plush/token" ) type Identifier struct { - Token token.Token + TokenAble Callee *Identifier Value string } -func (i *Identifier) expressionNode() { -} - -func (i *Identifier) TokenLiteral() string { - return i.Token.Literal -} +func (i *Identifier) expressionNode() {} func (i *Identifier) String() string { out := &bytes.Buffer{} diff --git a/ast/if_expression.go b/ast/if_expression.go index 04b0ab7..eb309f4 100644 --- a/ast/if_expression.go +++ b/ast/if_expression.go @@ -2,22 +2,16 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" ) type IfExpression struct { - Token token.Token + TokenAble Condition Expression Block *BlockStatement ElseBlock *BlockStatement } -func (ie *IfExpression) expressionNode() { -} - -func (ie *IfExpression) TokenLiteral() string { - return ie.Token.Literal -} +func (ie *IfExpression) expressionNode() {} func (ie *IfExpression) String() string { var out bytes.Buffer diff --git a/ast/index_expression.go b/ast/index_expression.go index 5dcc592..cc86f5d 100644 --- a/ast/index_expression.go +++ b/ast/index_expression.go @@ -2,21 +2,15 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" ) type IndexExpression struct { - Token token.Token + TokenAble Left Expression Index Expression } -func (ie *IndexExpression) expressionNode() { -} - -func (ie *IndexExpression) TokenLiteral() string { - return ie.Token.Literal -} +func (ie *IndexExpression) expressionNode() {} func (ie *IndexExpression) String() string { var out bytes.Buffer diff --git a/ast/infix_expression.go b/ast/infix_expression.go index 9efccf7..72c8b65 100644 --- a/ast/infix_expression.go +++ b/ast/infix_expression.go @@ -2,23 +2,16 @@ package ast import ( "bytes" - - "github.com/gobuffalo/plush/token" ) type InfixExpression struct { - Token token.Token + TokenAble Left Expression Operator string Right Expression } -func (oe *InfixExpression) expressionNode() { -} - -func (oe *InfixExpression) TokenLiteral() string { - return oe.Token.Literal -} +func (oe *InfixExpression) expressionNode() {} func (oe *InfixExpression) String() string { var out bytes.Buffer diff --git a/ast/integer_literal.go b/ast/integer_literal.go index 0fb168c..8ea6787 100644 --- a/ast/integer_literal.go +++ b/ast/integer_literal.go @@ -1,18 +1,11 @@ package ast -import "github.com/gobuffalo/plush/token" - type IntegerLiteral struct { - Token token.Token + TokenAble Value int } -func (il *IntegerLiteral) expressionNode() { -} - -func (il *IntegerLiteral) TokenLiteral() string { - return il.Token.Literal -} +func (il *IntegerLiteral) expressionNode() {} func (il *IntegerLiteral) String() string { return il.Token.Literal diff --git a/ast/let_statement.go b/ast/let_statement.go index 67de7f2..3e33656 100644 --- a/ast/let_statement.go +++ b/ast/let_statement.go @@ -2,21 +2,15 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" ) type LetStatement struct { - Token token.Token + TokenAble Name *Identifier Value Expression } -func (ls *LetStatement) statementNode() { -} - -func (ls *LetStatement) TokenLiteral() string { - return ls.Token.Literal -} +func (ls *LetStatement) statementNode() {} func (ls *LetStatement) String() string { var out bytes.Buffer diff --git a/ast/prefix_expression.go b/ast/prefix_expression.go index 39c18a1..b996266 100644 --- a/ast/prefix_expression.go +++ b/ast/prefix_expression.go @@ -2,21 +2,15 @@ package ast import ( "bytes" - "github.com/gobuffalo/plush/token" ) type PrefixExpression struct { - Token token.Token + TokenAble Operator string Right Expression } -func (pe *PrefixExpression) expressionNode() { -} - -func (pe *PrefixExpression) TokenLiteral() string { - return pe.Token.Literal -} +func (pe *PrefixExpression) expressionNode() {} func (pe *PrefixExpression) String() string { var out bytes.Buffer diff --git a/ast/return_statement.go b/ast/return_statement.go index 9ff98b8..c12a31e 100644 --- a/ast/return_statement.go +++ b/ast/return_statement.go @@ -2,12 +2,10 @@ package ast import ( "bytes" - - "github.com/gobuffalo/plush/token" ) type ReturnStatement struct { - Token token.Token + TokenAble ReturnValue Expression } @@ -15,12 +13,7 @@ func (rs *ReturnStatement) Printable() bool { return true } -func (rs *ReturnStatement) statementNode() { -} - -func (rs *ReturnStatement) TokenLiteral() string { - return rs.Token.Literal -} +func (rs *ReturnStatement) statementNode() {} func (rs *ReturnStatement) String() string { var out bytes.Buffer diff --git a/ast/string_literal.go b/ast/string_literal.go index 94e4b92..df4ac1f 100644 --- a/ast/string_literal.go +++ b/ast/string_literal.go @@ -1,18 +1,11 @@ package ast -import "github.com/gobuffalo/plush/token" - type StringLiteral struct { - Token token.Token + TokenAble Value string } -func (sl *StringLiteral) expressionNode() { -} - -func (sl *StringLiteral) TokenLiteral() string { - return sl.Token.Literal -} +func (sl *StringLiteral) expressionNode() {} func (sl *StringLiteral) String() string { return sl.Token.Literal diff --git a/compiler.go b/compiler.go index 1950b7d..d1394de 100644 --- a/compiler.go +++ b/compiler.go @@ -37,7 +37,7 @@ func (c *compiler) compile() (string, error) { res, err = c.evalLetStatement(node) } if err != nil { - return "", errors.WithStack(err) + return "", errors.WithStack(errors.Wrapf(err, "line %d", stmt.T().LineNumber)) } c.write(bb, res) diff --git a/lexer/lexer.go b/lexer/lexer.go index f427dc4..5c33cde 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -13,11 +13,12 @@ type Lexer struct { readPosition int // current reading position in input (after current char) ch byte // current char under examination inside bool + curLine int } // New Lexer from the input string func New(input string) *Lexer { - l := &Lexer{input: input} + l := &Lexer{input: input, curLine: 1} l.readChar() return l } @@ -33,6 +34,7 @@ func (l *Lexer) NextToken() token.Token { if l.ch == 0 { tok.Literal = "" tok.Type = token.EOF + tok.LineNumber = l.curLine return tok } @@ -43,6 +45,7 @@ func (l *Lexer) NextToken() token.Token { tok.Type = token.HTML tok.Literal = l.readHTML() + tok.LineNumber = l.curLine return tok } @@ -56,9 +59,9 @@ func (l *Lexer) nextInsideToken() token.Token { if l.peekChar() == '=' { ch := l.ch l.readChar() - tok = token.Token{Type: token.EQ, Literal: string(ch) + string(l.ch)} + tok = token.Token{Type: token.EQ, Literal: string(ch) + string(l.ch), LineNumber: l.curLine} } else { - tok = newToken(token.ASSIGN, l.ch) + tok = l.newToken(token.ASSIGN) } case '.': if isDigit(l.peekChar()) { @@ -66,7 +69,7 @@ func (l *Lexer) nextInsideToken() token.Token { tokSplit := strings.Split(tok.Literal, ".") switch { case len(tokSplit) > 2: - return newIllegalTokenLiteral(token.ILLEGAL, tok.Literal) + return l.newIllegalTokenLiteral(token.ILLEGAL, tok.Literal) case len(tokSplit) == 2: tok.Type = "FLOAT" default: @@ -75,46 +78,46 @@ func (l *Lexer) nextInsideToken() token.Token { return tok } - tok = newToken(token.DOT, l.ch) + tok = l.newToken(token.DOT) return tok case '+': - tok = newToken(token.PLUS, l.ch) + tok = l.newToken(token.PLUS) case '&': if l.peekChar() == '&' { l.readChar() - tok = token.Token{Type: token.AND, Literal: "&&"} + tok = token.Token{Type: token.AND, Literal: "&&", LineNumber: l.curLine} break } - tok = newToken(token.ILLEGAL, l.ch) + tok = l.newToken(token.ILLEGAL) case '|': if l.peekChar() == '|' { l.readChar() - tok = token.Token{Type: token.OR, Literal: "||"} + tok = token.Token{Type: token.OR, Literal: "||", LineNumber: l.curLine} break } - tok = newToken(token.ILLEGAL, l.ch) + tok = l.newToken(token.ILLEGAL) case '-': - tok = newToken(token.MINUS, l.ch) + tok = l.newToken(token.MINUS) case '!': if l.peekChar() == '=' { ch := l.ch l.readChar() - tok = token.Token{Type: token.NOT_EQ, Literal: string(ch) + string(l.ch)} + tok = token.Token{Type: token.NOT_EQ, Literal: string(ch) + string(l.ch), LineNumber: l.curLine} } else { - tok = newToken(token.BANG, l.ch) + tok = l.newToken(token.BANG) } case '/': - tok = newToken(token.SLASH, l.ch) + tok = l.newToken(token.SLASH) case '*': - tok = newToken(token.ASTERISK, l.ch) + tok = l.newToken(token.ASTERISK) case '%': if l.peekChar() == '>' { l.inside = false l.readChar() - tok = token.Token{Type: token.E_END, Literal: "%>"} + tok = token.Token{Type: token.E_END, Literal: "%>", LineNumber: l.curLine} break } - tok = newToken(token.ILLEGAL, l.ch) + tok = l.newToken(token.ILLEGAL) case '<': if l.peekChar() == '%' { l.inside = true @@ -122,56 +125,56 @@ func (l *Lexer) nextInsideToken() token.Token { switch l.peekChar() { case '#': l.readChar() - tok = token.Token{Type: token.C_START, Literal: "<%#"} + tok = token.Token{Type: token.C_START, Literal: "<%#", LineNumber: l.curLine} case '=': l.readChar() - tok = token.Token{Type: token.E_START, Literal: "<%="} + tok = token.Token{Type: token.E_START, Literal: "<%=", LineNumber: l.curLine} default: - tok = token.Token{Type: token.S_START, Literal: "<%"} + tok = token.Token{Type: token.S_START, Literal: "<%", LineNumber: l.curLine} } break } if l.peekChar() == '=' { l.readChar() - tok = token.Token{Type: token.LTEQ, Literal: "<="} + tok = token.Token{Type: token.LTEQ, Literal: "<=", LineNumber: l.curLine} break } - tok = newToken(token.LT, l.ch) + tok = l.newToken(token.LT) case '~': if l.peekChar() == '=' { l.readChar() - tok = token.Token{Type: token.MATCHES, Literal: "~="} + tok = token.Token{Type: token.MATCHES, Literal: "~=", LineNumber: l.curLine} break } - tok = newToken(token.MATCHES, l.ch) + tok = l.newToken(token.MATCHES) case '>': if l.peekChar() == '=' { l.readChar() - tok = token.Token{Type: token.GTEQ, Literal: ">="} + tok = token.Token{Type: token.GTEQ, Literal: ">=", LineNumber: l.curLine} break } - tok = newToken(token.GT, l.ch) + tok = l.newToken(token.GT) case ';': - tok = newToken(token.SEMICOLON, l.ch) + tok = l.newToken(token.SEMICOLON) case ':': - tok = newToken(token.COLON, l.ch) + tok = l.newToken(token.COLON) case ',': - tok = newToken(token.COMMA, l.ch) + tok = l.newToken(token.COMMA) case '{': - tok = newToken(token.LBRACE, l.ch) + tok = l.newToken(token.LBRACE) case '}': - tok = newToken(token.RBRACE, l.ch) + tok = l.newToken(token.RBRACE) case '(': - tok = newToken(token.LPAREN, l.ch) + tok = l.newToken(token.LPAREN) case ')': - tok = newToken(token.RPAREN, l.ch) + tok = l.newToken(token.RPAREN) case '"': tok.Type = token.STRING tok.Literal = l.readString() case '[': - tok = newToken(token.LBRACKET, l.ch) + tok = l.newToken(token.LBRACKET) case ']': - tok = newToken(token.RBRACKET, l.ch) + tok = l.newToken(token.RBRACKET) case 0: tok.Literal = "" tok.Type = token.EOF @@ -185,7 +188,7 @@ func (l *Lexer) nextInsideToken() token.Token { tokSplit := strings.Split(tok.Literal, ".") switch { case len(tokSplit) > 2: - return newIllegalTokenLiteral(token.ILLEGAL, tok.Literal) + return l.newIllegalTokenLiteral(token.ILLEGAL, tok.Literal) case len(tokSplit) == 2: tok.Type = "FLOAT" default: @@ -194,11 +197,12 @@ func (l *Lexer) nextInsideToken() token.Token { return tok } else { - tok = newToken(token.ILLEGAL, l.ch) + tok = l.newToken(token.ILLEGAL) } } l.readChar() + tok.LineNumber = l.curLine return tok } @@ -214,6 +218,9 @@ func (l *Lexer) readChar() { } else { l.ch = l.input[l.readPosition] } + if l.ch == '\n' { + l.curLine++ + } l.position = l.readPosition l.readPosition++ } @@ -288,10 +295,10 @@ func isDot(ch byte) bool { return '.' == ch } -func newToken(tokenType token.Type, ch byte) token.Token { - return token.Token{Type: tokenType, Literal: string(ch)} +func (l *Lexer) newToken(tokenType token.Type) token.Token { + return token.Token{Type: tokenType, Literal: string(l.ch), LineNumber: l.curLine} } -func newIllegalTokenLiteral(tokenType token.Type, literal string) token.Token { - return token.Token{Type: tokenType, Literal: literal} +func (l *Lexer) newIllegalTokenLiteral(tokenType token.Type, literal string) token.Token { + return token.Token{Type: tokenType, Literal: literal, LineNumber: l.curLine} } diff --git a/parser/parser.go b/parser/parser.go index ee433c8..c072348 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -131,12 +131,12 @@ func (p *parser) expectPeek(t token.Type) bool { } func (p *parser) peekError(t token.Type) { - msg := fmt.Sprintf("expected next token to be %s, got %s instead", t, p.peekToken.Type) + msg := fmt.Sprintf("expected next token to be %s, got %s instead [line: %d]", t, p.peekToken.Type, p.curToken.LineNumber) p.errors = append(p.errors, msg) } func (p *parser) noPrefixParseFnError(t token.Type) { - msg := fmt.Sprintf("no prefix parse function for %s found", t) + msg := fmt.Sprintf("no prefix parse function for %s found [line: %d]", t, p.curToken.LineNumber) p.errors = append(p.errors, msg) } @@ -164,7 +164,7 @@ func (p *parser) parseStatement() ast.Statement { func (p *parser) parseReturnStatement() *ast.ReturnStatement { // fmt.Println("parseReturnStatement") - stmt := &ast.ReturnStatement{Token: p.curToken} + stmt := &ast.ReturnStatement{TokenAble: ast.TokenAble{p.curToken}} p.nextToken() @@ -179,13 +179,13 @@ func (p *parser) parseReturnStatement() *ast.ReturnStatement { func (p *parser) parseLetStatement() *ast.LetStatement { // fmt.Println("parseLetStatement") - stmt := &ast.LetStatement{Token: p.curToken} + stmt := &ast.LetStatement{TokenAble: ast.TokenAble{p.curToken}} if !p.expectPeek(token.IDENT) { return nil } - stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} + stmt.Name = &ast.Identifier{TokenAble: ast.TokenAble{p.curToken}, Value: p.curToken.Literal} if !p.expectPeek(token.ASSIGN) { return nil @@ -204,7 +204,7 @@ func (p *parser) parseLetStatement() *ast.LetStatement { func (p *parser) parseExpressionStatement() *ast.ExpressionStatement { // fmt.Println("parseExpressionStatement") - stmt := &ast.ExpressionStatement{Token: p.curToken} + stmt := &ast.ExpressionStatement{TokenAble: ast.TokenAble{p.curToken}} stmt.Expression = p.parseExpression(LOWEST) if p.peekTokenIs(token.SEMICOLON) { @@ -257,20 +257,20 @@ func (p *parser) curPrecedence() int { func (p *parser) parseIdentifier() ast.Expression { // fmt.Println("parseIdentifier") - id := &ast.Identifier{Token: p.curToken} + id := &ast.Identifier{TokenAble: ast.TokenAble{p.curToken}} ss := strings.Split(p.curToken.Literal, ".") id.Value = ss[0] for i := 1; i < len(ss); i++ { s := ss[i] - id = &ast.Identifier{Token: p.curToken, Value: s, Callee: id} + id = &ast.Identifier{TokenAble: ast.TokenAble{p.curToken}, Value: s, Callee: id} } return id } func (p *parser) parseIntegerLiteral() ast.Expression { // fmt.Println("parseIntegerLiteral") - lit := &ast.IntegerLiteral{Token: p.curToken} + lit := &ast.IntegerLiteral{TokenAble: ast.TokenAble{p.curToken}} value, err := strconv.Atoi(p.curToken.Literal) if err != nil { @@ -286,7 +286,7 @@ func (p *parser) parseIntegerLiteral() ast.Expression { func (p *parser) parseFloatLiteral() ast.Expression { // fmt.Println("parseFloatLiteral") - lit := &ast.FloatLiteral{Token: p.curToken} + lit := &ast.FloatLiteral{TokenAble: ast.TokenAble{p.curToken}} value, err := strconv.ParseFloat(p.curToken.Literal, 64) if err != nil { @@ -302,7 +302,7 @@ func (p *parser) parseFloatLiteral() ast.Expression { func (p *parser) parseStringLiteral() ast.Expression { // fmt.Println("parseStringLiteral") - return &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal} + return &ast.StringLiteral{TokenAble: ast.TokenAble{p.curToken}, Value: p.curToken.Literal} } func (p *parser) parseCommentLiteral() ast.Expression { @@ -310,19 +310,19 @@ func (p *parser) parseCommentLiteral() ast.Expression { for p.curToken.Type != token.E_END { p.nextToken() } - return &ast.StringLiteral{Token: p.curToken, Value: ""} + return &ast.StringLiteral{TokenAble: ast.TokenAble{p.curToken}, Value: ""} } func (p *parser) parseHTMLLiteral() ast.Expression { // fmt.Println("parseHTMLLiteral") - return &ast.HTMLLiteral{Token: p.curToken, Value: p.curToken.Literal} + return &ast.HTMLLiteral{TokenAble: ast.TokenAble{p.curToken}, Value: p.curToken.Literal} } func (p *parser) parsePrefixExpression() ast.Expression { // fmt.Println("parsePrefixExpression") expression := &ast.PrefixExpression{ - Token: p.curToken, - Operator: p.curToken.Literal, + TokenAble: ast.TokenAble{p.curToken}, + Operator: p.curToken.Literal, } p.nextToken() @@ -335,9 +335,9 @@ func (p *parser) parsePrefixExpression() ast.Expression { func (p *parser) parseInfixExpression(left ast.Expression) ast.Expression { // fmt.Println("parseInfixExpression") expression := &ast.InfixExpression{ - Token: p.curToken, - Operator: p.curToken.Literal, - Left: left, + TokenAble: ast.TokenAble{p.curToken}, + Operator: p.curToken.Literal, + Left: left, } precedence := p.curPrecedence() @@ -349,7 +349,7 @@ func (p *parser) parseInfixExpression(left ast.Expression) ast.Expression { func (p *parser) parseBoolean() ast.Expression { // fmt.Println("parseBoolean") - return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)} + return &ast.Boolean{TokenAble: ast.TokenAble{p.curToken}, Value: p.curTokenIs(token.TRUE)} } func (p *parser) parseGroupedExpression() ast.Expression { @@ -368,7 +368,7 @@ func (p *parser) parseGroupedExpression() ast.Expression { func (p *parser) parseForExpression() ast.Expression { // fmt.Println("parseForExpression") expression := &ast.ForExpression{ - Token: p.curToken, + TokenAble: ast.TokenAble{p.curToken}, KeyName: "_", ValueName: "@value", } @@ -422,7 +422,7 @@ func (p *parser) parseForExpression() ast.Expression { func (p *parser) parseIfExpression() ast.Expression { // fmt.Println("parseIfExpression") - expression := &ast.IfExpression{Token: p.curToken} + expression := &ast.IfExpression{TokenAble: ast.TokenAble{p.curToken}} if !p.expectPeek(token.LPAREN) { return nil @@ -456,7 +456,7 @@ func (p *parser) parseIfExpression() ast.Expression { func (p *parser) parseBlockStatement() *ast.BlockStatement { // fmt.Println("parseBlockStatement") - block := &ast.BlockStatement{Token: p.curToken} + block := &ast.BlockStatement{TokenAble: ast.TokenAble{p.curToken}} block.Statements = []ast.Statement{} p.nextToken() @@ -478,7 +478,7 @@ func (p *parser) parseBlockStatement() *ast.BlockStatement { func (p *parser) parseFunctionLiteral() ast.Expression { // fmt.Println("parseFunctionLiteral") - lit := &ast.FunctionLiteral{Token: p.curToken} + lit := &ast.FunctionLiteral{TokenAble: ast.TokenAble{p.curToken}} if !p.expectPeek(token.LPAREN) { return nil @@ -506,13 +506,13 @@ func (p *parser) parseFunctionParameters() []*ast.Identifier { p.nextToken() - ident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} + ident := &ast.Identifier{TokenAble: ast.TokenAble{p.curToken}, Value: p.curToken.Literal} identifiers = append(identifiers, ident) for p.peekTokenIs(token.COMMA) { p.nextToken() p.nextToken() - ident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} + ident := &ast.Identifier{TokenAble: ast.TokenAble{p.curToken}, Value: p.curToken.Literal} identifiers = append(identifiers, ident) } @@ -526,27 +526,27 @@ func (p *parser) parseFunctionParameters() []*ast.Identifier { func (p *parser) parseCallExpression(function ast.Expression) ast.Expression { // fmt.Println("parseCallExpression") exp := &ast.CallExpression{ - Token: p.curToken, - Function: function, + TokenAble: ast.TokenAble{p.curToken}, + Function: function, } ss := strings.Split(function.String(), ".") if len(ss) > 1 { exp.Callee = &ast.Identifier{ - Token: token.Token{Type: token.IDENT, Literal: ss[0]}, - Value: ss[0], + TokenAble: ast.TokenAble{token.Token{Type: token.IDENT, Literal: ss[0]}}, + Value: ss[0], } for i := 1; i < len(ss)-1; i++ { c := &ast.Identifier{ - Token: token.Token{Type: token.IDENT, Literal: ss[i]}, - Value: ss[i], - Callee: exp.Callee.(*ast.Identifier), + TokenAble: ast.TokenAble{token.Token{Type: token.IDENT, Literal: ss[i]}}, + Value: ss[i], + Callee: exp.Callee.(*ast.Identifier), } exp.Callee = c } exp.Function = &ast.Identifier{ - Token: token.Token{Type: token.IDENT, Literal: ss[len(ss)-1]}, - Value: ss[len(ss)-1], - Callee: exp.Callee.(*ast.Identifier), + TokenAble: ast.TokenAble{token.Token{Type: token.IDENT, Literal: ss[len(ss)-1]}}, + Value: ss[len(ss)-1], + Callee: exp.Callee.(*ast.Identifier), } } exp.Arguments = p.parseExpressionList(token.RPAREN) @@ -586,7 +586,7 @@ func (p *parser) parseExpressionList(end token.Type) []ast.Expression { func (p *parser) parseArrayLiteral() ast.Expression { // fmt.Println("parseArrayLiteral") - array := &ast.ArrayLiteral{Token: p.curToken} + array := &ast.ArrayLiteral{TokenAble: ast.TokenAble{p.curToken}} array.Elements = p.parseExpressionList(token.RBRACKET) @@ -595,7 +595,7 @@ func (p *parser) parseArrayLiteral() ast.Expression { func (p *parser) parseIndexExpression(left ast.Expression) ast.Expression { // fmt.Println("parseIndexExpression") - exp := &ast.IndexExpression{Token: p.curToken, Left: left} + exp := &ast.IndexExpression{TokenAble: ast.TokenAble{p.curToken}, Left: left} p.nextToken() exp.Index = p.parseExpression(LOWEST) @@ -609,7 +609,7 @@ func (p *parser) parseIndexExpression(left ast.Expression) ast.Expression { func (p *parser) parseHashLiteral() ast.Expression { // fmt.Println("parseHashLiteral") - hash := &ast.HashLiteral{Token: p.curToken} + hash := &ast.HashLiteral{TokenAble: ast.TokenAble{p.curToken}} hash.Pairs = make(map[ast.Expression]ast.Expression) for !p.peekTokenIs(token.RBRACE) { diff --git a/token/token.go b/token/token.go index 10c124c..07e0b9f 100644 --- a/token/token.go +++ b/token/token.go @@ -5,8 +5,9 @@ type Type string // Token of a section of input source. type Token struct { - Type Type - Literal string + Type Type + Literal string + LineNumber int } var keywords = map[string]Type{