aboutsummaryrefslogtreecommitdiff
path: root/pkg/lang
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-08-08 23:46:09 +0000
committerMel <einebeere@gmail.com>2022-08-08 23:46:09 +0000
commit7717384414926eaa5821f04a08ee0d198f7b786f (patch)
tree0b667518eba4c8d023d39a70fecf153a795a7f9c /pkg/lang
parente0161c493867e788ad9db208247f3275e2d057dc (diff)
downloadjinx-7717384414926eaa5821f04a08ee0d198f7b786f.tar.zst
jinx-7717384414926eaa5821f04a08ee0d198f7b786f.zip
Produce (slightly) better parser errors
Diffstat (limited to 'pkg/lang')
-rw-r--r--pkg/lang/parser/errors.go60
-rw-r--r--pkg/lang/parser/exprs.go8
-rw-r--r--pkg/lang/parser/parser.go7
-rw-r--r--pkg/lang/parser/stmts.go8
-rw-r--r--pkg/lang/scanner/token/token.go72
5 files changed, 145 insertions, 10 deletions
diff --git a/pkg/lang/parser/errors.go b/pkg/lang/parser/errors.go
new file mode 100644
index 0000000..a020e01
--- /dev/null
+++ b/pkg/lang/parser/errors.go
@@ -0,0 +1,60 @@
+package parser
+
+import (
+ "fmt"
+ "jinx/pkg/lang/scanner/token"
+ "jinx/pkg/libs/source"
+)
+
+type ErrFunctionNoThisAllowed struct {
+ At source.Loc
+}
+
+func (e ErrFunctionNoThisAllowed) Error() string {
+ return fmt.Sprintf("non-method function cannot have 'this' as parameter at %v", e.At)
+}
+
+type ErrFunctionLiteralNoThisAllowed struct {
+ At source.Loc
+}
+
+func (e ErrFunctionLiteralNoThisAllowed) Error() string {
+ return fmt.Sprintf("function literal cannot have 'this' as parameter at %v", e.At)
+}
+
+type ErrExpectedToken struct {
+ At source.Loc
+ Wanted token.TokenKind
+ Got token.Token
+}
+
+func (e ErrExpectedToken) Error() string {
+ return fmt.Sprintf("unexpected token %v, wanted %v at %v", e.Got, e.Wanted, e.At)
+}
+
+type ErrExpectedStatementEnd struct {
+ At source.Loc
+ Got token.Token
+}
+
+func (e ErrExpectedStatementEnd) Error() string {
+ return fmt.Sprintf("expected statement end, got %v at %v", e.Got, e.At)
+}
+
+type ErrExpectedUnitExpressionStart struct {
+ At source.Loc
+ Got token.Token
+}
+
+func (e ErrExpectedUnitExpressionStart) Error() string {
+ return fmt.Sprintf("unexpected token %v, wanted unit expression start at %v", e.Got, e.At)
+}
+
+type ErrExpectedValueLiteral struct {
+ At source.Loc
+ Got token.Token
+}
+
+func (e ErrExpectedValueLiteral) Error() string {
+ return fmt.Sprintf("unexpected token %v, wanted value literal %v", e.Got, e.At)
+}
diff --git a/pkg/lang/parser/exprs.go b/pkg/lang/parser/exprs.go
index 48d1a8c..1603838 100644
--- a/pkg/lang/parser/exprs.go
+++ b/pkg/lang/parser/exprs.go
@@ -1,7 +1,6 @@
package parser
import (
- "fmt"
"jinx/pkg/lang/ast"
"jinx/pkg/lang/scanner/token"
)
@@ -207,7 +206,8 @@ func (p *Parser) parseUnitExpr() (ast.Expr, error) {
case token.KwTrue, token.KwFalse, token.KwNull, token.KwThis:
return p.parseValueLitExpr()
default:
- panic(fmt.Errorf("unexpected token '%v', wanted unit expression start", p.peek().Kind))
+ tok := p.peek()
+ return ast.Expr{}, ErrExpectedUnitExpressionStart{tok.At, tok}
}
}
@@ -250,7 +250,7 @@ func (p *Parser) parseFnLitExpr() (ast.Expr, error) {
}
if hasThis {
- return ast.Expr{}, fmt.Errorf("function literal cannot have 'this' parameter")
+ return ast.Expr{}, ErrFunctionLiteralNoThisAllowed{fnTok.At}
}
// TODO: Also parse just an expression
@@ -406,6 +406,6 @@ func (p *Parser) parseValueLitExpr() (ast.Expr, error) {
Value: ast.ExprThis{},
}, nil
default:
- panic(fmt.Errorf("unexpected token '%v', wanted value literal", tok))
+ return ast.Expr{}, ErrExpectedValueLiteral{At: tok.At, Got: tok}
}
}
diff --git a/pkg/lang/parser/parser.go b/pkg/lang/parser/parser.go
index 0ff4b09..d939e4b 100644
--- a/pkg/lang/parser/parser.go
+++ b/pkg/lang/parser/parser.go
@@ -1,7 +1,6 @@
package parser
import (
- "fmt"
"jinx/pkg/lang/ast"
"jinx/pkg/lang/scanner/token"
)
@@ -88,7 +87,11 @@ func (p *Parser) next() token.Token {
func (p *Parser) expect(kind token.TokenKind) (token.Token, error) {
tok := p.next()
if tok.Kind != kind {
- return token.Token{}, fmt.Errorf("expected '%v', got '%v'", kind, tok.Kind)
+ return token.Token{}, ErrExpectedToken{
+ At: tok.At,
+ Wanted: kind,
+ Got: tok,
+ }
}
return tok, nil
diff --git a/pkg/lang/parser/stmts.go b/pkg/lang/parser/stmts.go
index c20f7a0..fe5c65b 100644
--- a/pkg/lang/parser/stmts.go
+++ b/pkg/lang/parser/stmts.go
@@ -1,7 +1,6 @@
package parser
import (
- "fmt"
"jinx/pkg/lang/ast"
"jinx/pkg/lang/scanner/token"
)
@@ -154,7 +153,7 @@ func (p *Parser) parseFnDeclStmt() (ast.Stmt, error) {
}
if hasThis {
- return ast.Stmt{}, fmt.Errorf("function cannot have 'this' as a parameter")
+ return ast.Stmt{}, ErrFunctionNoThisAllowed{At: fnTok.At}
}
block, err := p.parseBlock()
@@ -640,7 +639,10 @@ func (p *Parser) parseEmptyStmt() (ast.Stmt, error) {
func (p *Parser) parseStmtEnd() error {
tok := p.peek()
if !tok.CanEndStmt() {
- return fmt.Errorf("wanted statement end, received: '%v'", tok.Kind)
+ return ErrExpectedStatementEnd{
+ At: tok.At,
+ Got: tok,
+ }
}
p.next()
return nil
diff --git a/pkg/lang/scanner/token/token.go b/pkg/lang/scanner/token/token.go
index a39df8a..9fee730 100644
--- a/pkg/lang/scanner/token/token.go
+++ b/pkg/lang/scanner/token/token.go
@@ -1,6 +1,9 @@
package token
-import "jinx/pkg/libs/source"
+import (
+ "fmt"
+ "jinx/pkg/libs/source"
+)
type Token struct {
Kind TokenKind
@@ -31,3 +34,70 @@ func (t Token) CanEndStmt() bool {
return false
}
}
+
+func (t Token) String() string {
+ switch t.Kind {
+ case EOF, EOL:
+ return t.Kind.String()
+
+ case KwVar,
+ KwFn,
+ KwType,
+ KwIf,
+ KwElif,
+ KwElse,
+ KwFor,
+ KwTry,
+ KwCatch,
+ KwFinally,
+ KwReturn,
+ KwContinue,
+ KwBreak,
+ KwThrow,
+ KwIn,
+ KwNull,
+ KwTrue,
+ KwFalse,
+ KwThis,
+ KwUse,
+ KwFrom,
+ KwBy,
+ KwGlobal:
+ return fmt.Sprintf("keyword '%v'", t.Kind)
+
+ case Ident:
+ return fmt.Sprintf("identifier '%v'", t.Data)
+ case Int:
+ return fmt.Sprintf("integer '%v'", t.Data)
+ case Float:
+ return fmt.Sprintf("float '%v'", t.Data)
+ case String:
+ return fmt.Sprintf("string '%v'", t.Data)
+
+ case Assign,
+ Plus,
+ Minus,
+ Star,
+ Slash,
+ Percent,
+ Bang,
+ Eq,
+ Neq,
+ Lt,
+ Gt,
+ Lte,
+ Gte,
+ LParen,
+ RParen,
+ LBrace,
+ RBrace,
+ LBracket,
+ RBracket,
+ Comma,
+ Dot,
+ SemiColon:
+ return fmt.Sprintf("'%v'", t.Kind)
+ default:
+ return "unknown token"
+ }
+}