From ab0ef3f4f5790fc1e5abebeab67e2c7b2188b19c Mon Sep 17 00:00:00 2001 From: DustTheory Date: Tue, 5 Sep 2023 17:08:20 +0200 Subject: [PATCH 1/2] savestate --- ast/ast.go | 164 ++++++++++++-------- ast/types.go | 1 + lexer/lexer.go | 28 ++-- lexer/util.go | 11 +- parser/parse_const_declaration_statement.go | 5 +- parser/parser.go | 6 + token/token.go | 2 + 7 files changed, 132 insertions(+), 85 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index 2946dfb..354a2c8 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -3,13 +3,19 @@ package ast import ( "bytes" "strings" + + "github.com/0xM-D/interpreter/token" ) func (p *Program) TokenLiteral() string { + return p.TokenValue().Literal +} + +func (p *Program) TokenValue() token.Token { if len(p.Statements) > 0 { - return p.Statements[0].TokenLiteral() + return p.Statements[0].TokenValue() } else { - return "" + return token.Token{Type: token.EOF, Literal: "", Linen: 0, Coln: 0} } } @@ -23,8 +29,9 @@ func (p *Program) String() string { return out.String() } -func (ls *LetStatement) statementNode() {} -func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal } +func (ls *LetStatement) statementNode() {} +func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal } +func (ls *LetStatement) TokenValue() token.Token { return ls.Token } func (ls *LetStatement) String() string { var out bytes.Buffer @@ -41,12 +48,14 @@ func (ls *LetStatement) String() string { return out.String() } -func (i *Identifier) expressionNode() {} -func (i *Identifier) TokenLiteral() string { return i.Token.Literal } -func (i *Identifier) String() string { return i.Value } +func (i *Identifier) expressionNode() {} +func (i *Identifier) TokenLiteral() string { return i.Token.Literal } +func (i *Identifier) TokenValue() token.Token { return i.Token } +func (i *Identifier) String() string { return i.Value } -func (rs *ReturnStatement) statementNode() {} -func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal } +func (rs *ReturnStatement) statementNode() {} +func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal } +func (rs *ReturnStatement) TokenValue() token.Token { return rs.Token } func (rs *ReturnStatement) String() string { var out bytes.Buffer @@ -60,8 +69,9 @@ func (rs *ReturnStatement) String() string { return out.String() } -func (es *ExpressionStatement) statementNode() {} -func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal } +func (es *ExpressionStatement) statementNode() {} +func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal } +func (es *ExpressionStatement) TokenValue() token.Token { return es.Token } func (es *ExpressionStatement) String() string { if es.Expression != nil { return es.Expression.String() @@ -69,26 +79,30 @@ func (es *ExpressionStatement) String() string { return "" } -func (il *IntegerLiteral) expressionNode() {} -func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal } +func (il *IntegerLiteral) expressionNode() {} +func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal } +func (il *IntegerLiteral) TokenValue() token.Token { return il.Token } func (il *IntegerLiteral) String() string { return il.Token.Literal } -func (fp *Float64Literal) expressionNode() {} -func (fp *Float64Literal) TokenLiteral() string { return fp.Token.Literal } +func (fp *Float64Literal) expressionNode() {} +func (fp *Float64Literal) TokenLiteral() string { return fp.Token.Literal } +func (fp *Float64Literal) TokenValue() token.Token { return fp.Token } func (fp *Float64Literal) String() string { return fp.Token.Literal } -func (fp *Float32Literal) expressionNode() {} -func (fp *Float32Literal) TokenLiteral() string { return fp.Token.Literal } +func (fp *Float32Literal) expressionNode() {} +func (fp *Float32Literal) TokenLiteral() string { return fp.Token.Literal } +func (fp *Float32Literal) TokenValue() token.Token { return fp.Token } func (fp *Float32Literal) String() string { return fp.Token.Literal } -func (pe *PrefixExpression) expressionNode() {} -func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal } +func (pe *PrefixExpression) expressionNode() {} +func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal } +func (pe *PrefixExpression) TokenValue() token.Token { return pe.Token } func (pe *PrefixExpression) String() string { var out bytes.Buffer @@ -100,26 +114,29 @@ func (pe *PrefixExpression) String() string { return out.String() } -func (oe *InfixExpression) expressionNode() {} -func (oe *InfixExpression) TokenLiteral() string { return oe.Token.Literal } -func (oe *InfixExpression) String() string { +func (ie *InfixExpression) expressionNode() {} +func (ie *InfixExpression) TokenLiteral() string { return ie.Token.Literal } +func (ie *InfixExpression) TokenValue() token.Token { return ie.Token } +func (ie *InfixExpression) String() string { var out bytes.Buffer out.WriteString("(") - out.WriteString(oe.Left.String() + " ") - out.WriteString(oe.Operator + " ") - out.WriteString(oe.Right.String()) + out.WriteString(ie.Left.String() + " ") + out.WriteString(ie.Operator + " ") + out.WriteString(ie.Right.String()) out.WriteString(")") return out.String() } -func (b *Boolean) expressionNode() {} -func (b *Boolean) TokenLiteral() string { return b.Token.Literal } -func (b *Boolean) String() string { return b.Token.Literal } +func (b *Boolean) expressionNode() {} +func (b *Boolean) TokenLiteral() string { return b.Token.Literal } +func (b *Boolean) TokenValue() token.Token { return b.Token } +func (b *Boolean) String() string { return b.Token.Literal } -func (ie *IfExpression) expressionNode() {} -func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal } +func (ie *IfExpression) expressionNode() {} +func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal } +func (ie *IfExpression) TokenValue() token.Token { return ie.Token } func (ie *IfExpression) String() string { var out bytes.Buffer @@ -137,8 +154,9 @@ func (ie *IfExpression) String() string { } -func (bs *BlockStatement) statementNode() {} -func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal } +func (bs *BlockStatement) statementNode() {} +func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal } +func (bs *BlockStatement) TokenValue() token.Token { return bs.Token } func (bs *BlockStatement) String() string { var out bytes.Buffer for _, s := range bs.Statements { @@ -147,8 +165,9 @@ func (bs *BlockStatement) String() string { return out.String() } -func (fl *FunctionLiteral) expressionNode() {} -func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal } +func (fl *FunctionLiteral) expressionNode() {} +func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal } +func (fl *FunctionLiteral) TokenValue() token.Token { return fl.Token } func (fl *FunctionLiteral) String() string { var out bytes.Buffer @@ -169,8 +188,9 @@ func (fl *FunctionLiteral) String() string { return out.String() } -func (ce *CallExpression) expressionNode() {} -func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal } +func (ce *CallExpression) expressionNode() {} +func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal } +func (ce *CallExpression) TokenValue() token.Token { return ce.Token } func (ce *CallExpression) String() string { var out bytes.Buffer args := []string{} @@ -184,12 +204,14 @@ func (ce *CallExpression) String() string { return out.String() } -func (sl *StringLiteral) expressionNode() {} -func (sl *StringLiteral) TokenLiteral() string { return sl.Token.Literal } -func (sl *StringLiteral) String() string { return sl.Token.Literal } +func (sl *StringLiteral) expressionNode() {} +func (sl *StringLiteral) TokenLiteral() string { return sl.Token.Literal } +func (sl *StringLiteral) TokenValue() token.Token { return sl.Token } +func (sl *StringLiteral) String() string { return sl.Token.Literal } -func (al *ArrayLiteral) expressionNode() {} -func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal } +func (al *ArrayLiteral) expressionNode() {} +func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal } +func (al *ArrayLiteral) TokenValue() token.Token { return al.Token } func (al *ArrayLiteral) String() string { var out bytes.Buffer elements := []string{} @@ -205,8 +227,9 @@ func (al *ArrayLiteral) String() string { return out.String() } -func (ie *IndexExpression) expressionNode() {} -func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal } +func (ie *IndexExpression) expressionNode() {} +func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal } +func (ie *IndexExpression) TokenValue() token.Token { return ie.Token } func (ie *IndexExpression) String() string { var out bytes.Buffer @@ -220,8 +243,9 @@ func (ie *IndexExpression) String() string { return out.String() } -func (ae *AccessExpression) expressionNode() {} -func (ae *AccessExpression) TokenLiteral() string { return ae.Token.Literal } +func (ae *AccessExpression) expressionNode() {} +func (ae *AccessExpression) TokenLiteral() string { return ae.Token.Literal } +func (ae *AccessExpression) TokenValue() token.Token { return ae.Token } func (ae *AccessExpression) String() string { var out bytes.Buffer @@ -232,8 +256,9 @@ func (ae *AccessExpression) String() string { return out.String() } -func (hl *HashLiteral) expressionNode() {} -func (hl *HashLiteral) TokenLiteral() string { return hl.Token.Literal } +func (hl *HashLiteral) expressionNode() {} +func (hl *HashLiteral) TokenLiteral() string { return hl.Token.Literal } +func (hl *HashLiteral) TokenValue() token.Token { return hl.Token } func (hl *HashLiteral) String() string { var out bytes.Buffer @@ -249,8 +274,9 @@ func (hl *HashLiteral) String() string { return out.String() } -func (td *TypedDeclarationStatement) statementNode() {} -func (td *TypedDeclarationStatement) TokenLiteral() string { return td.Token.Literal } +func (td *TypedDeclarationStatement) statementNode() {} +func (td *TypedDeclarationStatement) TokenLiteral() string { return td.Token.Literal } +func (td *TypedDeclarationStatement) TokenValue() token.Token { return td.Token } func (td *TypedDeclarationStatement) String() string { var out bytes.Buffer @@ -264,8 +290,9 @@ func (td *TypedDeclarationStatement) String() string { return out.String() } -func (ad *AssignmentDeclarationStatement) statementNode() {} -func (ad *AssignmentDeclarationStatement) TokenLiteral() string { return ad.Token.Literal } +func (ad *AssignmentDeclarationStatement) statementNode() {} +func (ad *AssignmentDeclarationStatement) TokenLiteral() string { return ad.Token.Literal } +func (ad *AssignmentDeclarationStatement) TokenValue() token.Token { return ad.Token } func (ad *AssignmentDeclarationStatement) String() string { var out bytes.Buffer @@ -277,8 +304,9 @@ func (ad *AssignmentDeclarationStatement) String() string { return out.String() } -func (vu *VariableUpdateStatement) statementNode() {} -func (vu *VariableUpdateStatement) TokenLiteral() string { return vu.Token.Literal } +func (vu *VariableUpdateStatement) statementNode() {} +func (vu *VariableUpdateStatement) TokenLiteral() string { return vu.Token.Literal } +func (vu *VariableUpdateStatement) TokenValue() token.Token { return vu.Token } func (vu *VariableUpdateStatement) String() string { var out bytes.Buffer @@ -291,8 +319,9 @@ func (vu *VariableUpdateStatement) String() string { return out.String() } -func (ht HashType) typeNode() {} -func (ht HashType) TokenLiteral() string { return ht.Token.Literal } +func (ht HashType) typeNode() {} +func (ht HashType) TokenLiteral() string { return ht.Token.Literal } +func (ht HashType) TokenValue() token.Token { return ht.Token } func (ht HashType) String() string { var out bytes.Buffer out.WriteString("map{ ") @@ -304,16 +333,20 @@ func (ht HashType) String() string { return out.String() } -func (at ArrayType) typeNode() {} -func (at ArrayType) TokenLiteral() string { return at.Token.Literal } -func (at ArrayType) String() string { return at.ElementType.String() + "[]" } +func (at ArrayType) typeNode() {} +func (at ArrayType) TokenLiteral() string { return at.Token.Literal } +func (at ArrayType) TokenValue() token.Token { return at.Token } + +func (at ArrayType) String() string { return at.ElementType.String() + "[]" } -func (it NamedType) typeNode() {} -func (it NamedType) TokenLiteral() string { return it.Token.Literal } -func (it NamedType) String() string { return it.TypeName.String() } +func (nt NamedType) typeNode() {} +func (nt NamedType) TokenLiteral() string { return nt.Token.Literal } +func (nt NamedType) TokenValue() token.Token { return nt.Token } +func (nt NamedType) String() string { return nt.TypeName.String() } -func (ft FunctionType) typeNode() {} -func (ft FunctionType) TokenLiteral() string { return ft.Token.Literal } +func (ft FunctionType) typeNode() {} +func (ft FunctionType) TokenLiteral() string { return ft.Token.Literal } +func (ft FunctionType) TokenValue() token.Token { return ft.Token } func (ft FunctionType) String() string { var out bytes.Buffer @@ -330,8 +363,9 @@ func (ft FunctionType) String() string { return out.String() } -func (fs *ForStatement) statementNode() {} -func (fs *ForStatement) TokenLiteral() string { return fs.Token.Literal } +func (fs *ForStatement) statementNode() {} +func (fs *ForStatement) TokenLiteral() string { return fs.Token.Literal } +func (fs *ForStatement) TokenValue() token.Token { return fs.Token } func (fs *ForStatement) String() string { var out bytes.Buffer diff --git a/ast/types.go b/ast/types.go index e34b6d7..6abaa8e 100644 --- a/ast/types.go +++ b/ast/types.go @@ -7,6 +7,7 @@ import ( type Node interface { TokenLiteral() string String() string + TokenValue() token.Token } type Statement interface { diff --git a/lexer/lexer.go b/lexer/lexer.go index ed67c88..cbcfff7 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -9,6 +9,8 @@ type Lexer struct { position int readPosition int ch byte + linen int + coln int } func New(input string) *Lexer { @@ -26,17 +28,17 @@ func (l *Lexer) NextToken() token.Token { case '=': tok = l.getTokenWithPeek(token.ASSIGN, TokenMapping{'=', token.EQ}) case ';': - tok = newToken(token.SEMICOLON, l.ch) + tok = l.newToken(token.SEMICOLON, string(l.ch)) case '(': - tok = newToken(token.LPAREN, l.ch) + tok = l.newToken(token.LPAREN, string(l.ch)) case ')': - tok = newToken(token.RPAREN, l.ch) + tok = l.newToken(token.RPAREN, string(l.ch)) case ',': - tok = newToken(token.COMMA, l.ch) + tok = l.newToken(token.COMMA, string(l.ch)) case '+': tok = l.getTokenWithPeek(token.PLUS, TokenMapping{'=', token.PLUS_ASSIGN}) case '-': - tok = newToken(token.PLUS, l.ch) + tok = l.newToken(token.PLUS, string(l.ch)) switch l.peekChar() { case '=': ch := l.ch @@ -47,7 +49,7 @@ func (l *Lexer) NextToken() token.Token { l.readChar() tok = token.Token{Type: token.DASH_ARROW, Literal: string(ch) + string(l.ch)} default: - tok = newToken(token.MINUS, l.ch) + tok = l.newToken(token.MINUS, string(l.ch)) } case '!': tok = l.getTokenWithPeek(token.BANG, TokenMapping{'=', token.NOT_EQ}) @@ -60,21 +62,21 @@ func (l *Lexer) NextToken() token.Token { case '>': tok = l.getTokenWithPeek(token.GT, TokenMapping{'=', token.GTE}, TokenMapping{'>', token.B_SHIFT_R}) case '{': - tok = newToken(token.LBRACE, l.ch) + tok = l.newToken(token.LBRACE, string(l.ch)) case '}': - tok = newToken(token.RBRACE, l.ch) + tok = l.newToken(token.RBRACE, string(l.ch)) case '"': tok.Type = token.STRING tok.Literal = l.readString() case '[': tok = l.getTokenWithPeek(token.LBRACKET, TokenMapping{']', token.ARRAY_TYPE}) case ']': - tok = newToken(token.RBRACKET, l.ch) + tok = l.newToken(token.RBRACKET, string(l.ch)) case '.': if isDigit(l.peekChar()) { tok.Type, tok.Literal = l.readNumber() } else { - tok = newToken(token.ACCESS, l.ch) + tok = l.newToken(token.ACCESS, string(l.ch)) } case ':': tok = l.getTokenWithPeek(token.COLON, TokenMapping{'=', token.DECL_ASSIGN}) @@ -83,9 +85,9 @@ func (l *Lexer) NextToken() token.Token { case '|': tok = l.getTokenWithPeek(token.B_OR, TokenMapping{'|', token.OR}) case '^': - tok = newToken(token.B_XOR, l.ch) + tok = l.newToken(token.B_XOR, string(l.ch)) case '~': - tok = newToken(token.B_INV, l.ch) + tok = l.newToken(token.B_INV, string(l.ch)) default: if isLetter(l.ch) { tok.Literal = l.readIdentifier() @@ -95,7 +97,7 @@ func (l *Lexer) NextToken() token.Token { tok.Type, tok.Literal = l.readNumber() return tok } else { - tok = newToken(token.ILLEGAL, l.ch) + tok = l.newToken(token.ILLEGAL, string(l.ch)) } case 0: tok.Literal = "" diff --git a/lexer/util.go b/lexer/util.go index bc1f7cd..ec7c413 100644 --- a/lexer/util.go +++ b/lexer/util.go @@ -6,6 +6,7 @@ func (l *Lexer) readChar() { l.ch = l.peekChar() l.position = l.readPosition l.readPosition++ + l.coln++ } func (l *Lexer) peekChar() byte { @@ -19,11 +20,15 @@ func (l *Lexer) peekChar() byte { func (l *Lexer) skipWhitespace() { for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' { l.readChar() + if l.ch == '\n' { + l.linen++ + l.coln = 0 + } } } -func newToken(tokenType token.TokenType, ch byte) token.Token { - return token.Token{Type: tokenType, Literal: string(ch)} +func (l *Lexer) newToken(tokenType token.TokenType, literal string) token.Token { + return token.Token{Type: tokenType, Literal: literal, Linen: l.linen, Coln: l.coln} } func (l *Lexer) readIdentifier() string { @@ -91,5 +96,5 @@ func (l *Lexer) getTokenWithPeek(defaultToken token.TokenType, tokenMappings ... } } - return newToken(defaultToken, l.ch) + return l.newToken(defaultToken, string(l.ch)) } diff --git a/parser/parse_const_declaration_statement.go b/parser/parse_const_declaration_statement.go index ec10626..e319d62 100644 --- a/parser/parse_const_declaration_statement.go +++ b/parser/parse_const_declaration_statement.go @@ -1,8 +1,6 @@ package parser import ( - "fmt" - "github.com/0xM-D/interpreter/ast" ) @@ -17,8 +15,7 @@ func (p *Parser) parseConstDeclarationStatement() ast.Statement { case *ast.AssignmentDeclarationStatement: declStmt.IsConstant = true default: - msg := fmt.Sprintf("const cannot be applied to statement of type %T", declStmt) - p.errors = append(p.errors, msg) + p.newError("const cannot be applied to statement of type %T", declStmt) } return stmt diff --git a/parser/parser.go b/parser/parser.go index f4dac24..c2821e4 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,6 +1,8 @@ package parser import ( + "fmt" + "github.com/0xM-D/interpreter/ast" "github.com/0xM-D/interpreter/lexer" "github.com/0xM-D/interpreter/token" @@ -96,6 +98,10 @@ func (p *Parser) Errors() []string { return p.errors } +func (p *Parser) newError(format string, a ...interface{}) { + p.errors = append(p.errors, fmt.Sprintf(format, a...)) +} + func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) { p.prefixParseFns[tokenType] = fn } diff --git a/token/token.go b/token/token.go index f1d9557..974b733 100644 --- a/token/token.go +++ b/token/token.go @@ -5,6 +5,8 @@ type TokenType string type Token struct { Type TokenType Literal string + Linen int + Coln int } const ( From 2695ee0dcbe7d935ccbbd8af66b855f7cdba1540 Mon Sep 17 00:00:00 2001 From: DustTheory Date: Thu, 7 Sep 2023 08:38:21 +0200 Subject: [PATCH 2/2] better errors --- ast/ast.go | 21 +++++++++++ lexer/util.go | 39 ++++++++++++++++++++- parser/parse_const_declaration_statement.go | 2 +- parser/parse_expression_statement.go | 9 +---- parser/parse_for_statement.go | 4 +-- parser/parse_integer_literal.go | 4 +-- parser/parse_typed_declaration_statement.go | 9 +---- parser/parser.go | 14 +++++--- parser/prase_float_literal.go | 7 ++-- parser/util.go | 9 ++--- repl/repl.go | 2 +- 11 files changed, 83 insertions(+), 37 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index 354a2c8..6875f3e 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -274,6 +274,27 @@ func (hl *HashLiteral) String() string { return out.String() } +func (ds *DeclarationStatement) statementNode() {} +func (ds *DeclarationStatement) TokenLiteral() string { return ds.Token.Literal } +func (ds *DeclarationStatement) TokenValue() token.Token { return ds.Token } +func (ds *DeclarationStatement) String() string { + var out bytes.Buffer + + if ds.IsConstant { + out.WriteString("const ") + } + if ds.Type != nil { + out.WriteString(ds.Type.String()) + out.WriteString(" ") + } + out.WriteString(ds.Name.String()) + out.WriteString(" = ") + out.WriteString(ds.Value.String()) + out.WriteString(";") + + return out.String() +} + func (td *TypedDeclarationStatement) statementNode() {} func (td *TypedDeclarationStatement) TokenLiteral() string { return td.Token.Literal } func (td *TypedDeclarationStatement) TokenValue() token.Token { return td.Token } diff --git a/lexer/util.go b/lexer/util.go index ec7c413..d3489af 100644 --- a/lexer/util.go +++ b/lexer/util.go @@ -1,6 +1,12 @@ package lexer -import "github.com/0xM-D/interpreter/token" +import ( + "bytes" + "fmt" + "strings" + + "github.com/0xM-D/interpreter/token" +) func (l *Lexer) readChar() { l.ch = l.peekChar() @@ -82,6 +88,14 @@ func (l *Lexer) readString() string { return l.input[position:l.position] } +func (l *Lexer) GetLocation() (int, int) { + return l.linen, l.coln +} + +func (l *Lexer) GetLine(linen int) string { + return strings.Split(l.input, "\n")[linen] +} + type TokenMapping struct { byte token.TokenType @@ -98,3 +112,26 @@ func (l *Lexer) getTokenWithPeek(defaultToken token.TokenType, tokenMappings ... return l.newToken(defaultToken, string(l.ch)) } + +func NewError(linen int, coln int, line string, format string, a ...interface{}) string { + var out bytes.Buffer + + out.WriteString(fmt.Sprintf("Parser error at line %d, column %d:\n", linen, coln)) + out.WriteString(line) + out.WriteByte('\n') + out.WriteString(getAsciiArrow(line, coln)) + out.WriteString(fmt.Sprintf(format, a...)) + out.WriteByte('\n') + + return out.String() +} + +func getAsciiArrow(line string, coln int) string { + var out bytes.Buffer + for i := 0; i < coln-1; i++ { + out.WriteByte(' ') + } + out.WriteByte('^') + out.WriteByte('\n') + return out.String() +} diff --git a/parser/parse_const_declaration_statement.go b/parser/parse_const_declaration_statement.go index e319d62..0ac2e16 100644 --- a/parser/parse_const_declaration_statement.go +++ b/parser/parse_const_declaration_statement.go @@ -15,7 +15,7 @@ func (p *Parser) parseConstDeclarationStatement() ast.Statement { case *ast.AssignmentDeclarationStatement: declStmt.IsConstant = true default: - p.newError("const cannot be applied to statement of type %T", declStmt) + p.newError(stmt, "const cannot be applied to statement of type %T", declStmt) } return stmt diff --git a/parser/parse_expression_statement.go b/parser/parse_expression_statement.go index 1dcfb33..b0edc2a 100644 --- a/parser/parse_expression_statement.go +++ b/parser/parse_expression_statement.go @@ -1,8 +1,6 @@ package parser import ( - "fmt" - "github.com/0xM-D/interpreter/ast" "github.com/0xM-D/interpreter/token" ) @@ -23,7 +21,7 @@ func (p *Parser) parseExpression(precedence int) ast.Expression { prefix := p.prefixParseFns[p.curToken.Type] if prefix == nil { - p.noPrefixParseFnError(p.curToken.Type) + p.newError(&ast.ExpressionStatement{Token: p.curToken}, "no prefix parse function for %s found", p.curToken.Literal) return nil } leftExp := prefix() @@ -43,8 +41,3 @@ func (p *Parser) parseExpression(precedence int) ast.Expression { return leftExp } - -func (p *Parser) noPrefixParseFnError(t token.TokenType) { - msg := fmt.Sprintf("no prefix parse function for %s found", t) - p.errors = append(p.errors, msg) -} diff --git a/parser/parse_for_statement.go b/parser/parse_for_statement.go index dee4970..5617edb 100644 --- a/parser/parse_for_statement.go +++ b/parser/parse_for_statement.go @@ -20,7 +20,7 @@ func (p *Parser) parseForStatement() ast.Statement { if p.curTokenIs(token.SEMICOLON) { p.nextToken() } else { - p.errors = append(p.errors, "Expected ;") + p.newError(stmt, "Expected ;") return nil } @@ -34,7 +34,7 @@ func (p *Parser) parseForStatement() ast.Statement { if p.curTokenIs(token.SEMICOLON) { p.nextToken() } else { - p.errors = append(p.errors, "Expected ;") + p.newError(stmt, "Expected ;") return nil } stmt.AfterThought = p.parseStatement() diff --git a/parser/parse_integer_literal.go b/parser/parse_integer_literal.go index db054d9..514486b 100644 --- a/parser/parse_integer_literal.go +++ b/parser/parse_integer_literal.go @@ -1,7 +1,6 @@ package parser import ( - "fmt" "strconv" "github.com/0xM-D/interpreter/ast" @@ -12,8 +11,7 @@ func (p *Parser) parseIntegerLiteral() ast.Expression { value, err := strconv.ParseInt(p.curToken.Literal, 0, 64) if err != nil { - msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal) - p.errors = append(p.errors, msg) + p.newError(lit, "could not parse %q as integer", p.curToken.Literal) return nil } diff --git a/parser/parse_typed_declaration_statement.go b/parser/parse_typed_declaration_statement.go index cc9bdfc..41ce7c2 100644 --- a/parser/parse_typed_declaration_statement.go +++ b/parser/parse_typed_declaration_statement.go @@ -1,8 +1,6 @@ package parser import ( - "fmt" - "github.com/0xM-D/interpreter/ast" "github.com/0xM-D/interpreter/token" ) @@ -16,7 +14,7 @@ func (p *Parser) parseTypedDeclarationStatement() *ast.TypedDeclarationStatement stmt.Name = p.parseIdentifier().(*ast.Identifier) if p.peekToken.Type != token.ASSIGN { - p.invalidTokenInTypedDeclarationStatement(p.peekToken) + p.newError(stmt, "invalid token in typed declaration statement. expected=%q got=%q", "=", p.peekToken.Literal) return nil } @@ -31,8 +29,3 @@ func (p *Parser) parseTypedDeclarationStatement() *ast.TypedDeclarationStatement return &ast.TypedDeclarationStatement{DeclarationStatement: *stmt} } - -func (p *Parser) invalidTokenInTypedDeclarationStatement(token token.Token) { - msg := fmt.Sprintf("invalid token in typed declaration statement. expected=%q got=%q", "=", p.peekToken.Literal) - p.errors = append(p.errors, msg) -} diff --git a/parser/parser.go b/parser/parser.go index c2821e4..381bf38 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,8 +1,6 @@ package parser import ( - "fmt" - "github.com/0xM-D/interpreter/ast" "github.com/0xM-D/interpreter/lexer" "github.com/0xM-D/interpreter/token" @@ -98,8 +96,16 @@ func (p *Parser) Errors() []string { return p.errors } -func (p *Parser) newError(format string, a ...interface{}) { - p.errors = append(p.errors, fmt.Sprintf(format, a...)) +func (p *Parser) newError(node ast.Node, format string, a ...interface{}) { + var linen, coln int + if node == nil { + linen, coln = p.l.GetLocation() + } else { + linen = node.TokenValue().Linen + coln = node.TokenValue().Coln + } + + p.errors = append(p.errors, lexer.NewError(linen, coln, p.getLine(linen), format, a...)) } func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) { diff --git a/parser/prase_float_literal.go b/parser/prase_float_literal.go index 47bc2cf..734fc6c 100644 --- a/parser/prase_float_literal.go +++ b/parser/prase_float_literal.go @@ -1,7 +1,6 @@ package parser import ( - "fmt" "strconv" "strings" @@ -13,8 +12,7 @@ func (p *Parser) parseFloat32Literal() ast.Expression { value, err := strconv.ParseFloat(strings.TrimSuffix(p.curToken.Literal, "f"), 32) if err != nil { - msg := fmt.Sprintf("could not parse %q as float32", p.curToken.Literal) - p.errors = append(p.errors, msg) + p.newError(lit, "could not parse %q as float32", p.curToken.Literal) return nil } @@ -28,8 +26,7 @@ func (p *Parser) parseFloat64Literal() ast.Expression { value, err := strconv.ParseFloat(p.curToken.Literal, 64) if err != nil { - msg := fmt.Sprintf("could not parse %q as float64", p.curToken.Literal) - p.errors = append(p.errors, msg) + p.newError(lit, "could not parse %q as float64", p.curToken.Literal) return nil } diff --git a/parser/util.go b/parser/util.go index 0e71528..1ce0d92 100644 --- a/parser/util.go +++ b/parser/util.go @@ -1,14 +1,11 @@ package parser import ( - "fmt" - "github.com/0xM-D/interpreter/token" ) 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) + p.newError(nil, "expected next token to be %s, got %s instead", t, p.peekToken.Type) } func (p *Parser) nextToken() { @@ -47,3 +44,7 @@ func (p *Parser) curPrecedence() int { } return LOWEST } + +func (p *Parser) getLine(linen int) string { + return p.l.GetLine(linen) +} diff --git a/repl/repl.go b/repl/repl.go index 4275efe..eabc9be 100644 --- a/repl/repl.go +++ b/repl/repl.go @@ -43,6 +43,6 @@ func Start(in io.Reader, out io.Writer) { } func printParserErrors(out io.Writer, errors []string) { for _, msg := range errors { - io.WriteString(out, "\t"+msg+"\n") + io.WriteString(out, msg) } }