asciigoat's core library
https://asciigoat.org/core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
1.7 KiB
125 lines
1.7 KiB
package lexer |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
"io" |
|
) |
|
|
|
var ( |
|
EOF = io.EOF // EOF marker |
|
) |
|
|
|
// Token type |
|
type TokenType int |
|
|
|
const ( |
|
TokenError TokenType = iota |
|
) |
|
|
|
// Token Position |
|
type TokenPosition struct { |
|
Line int |
|
Row int |
|
} |
|
|
|
func (pos *TokenPosition) Reset() { |
|
pos.Line = 1 |
|
pos.Row = 1 |
|
} |
|
|
|
func (pos *TokenPosition) Step(n int) { |
|
pos.Row += n |
|
} |
|
|
|
func (pos *TokenPosition) NewLine() { |
|
pos.Line += 1 |
|
pos.Row = 1 |
|
} |
|
|
|
// Token |
|
type Token interface { |
|
Type() TokenType |
|
String() string |
|
Position() TokenPosition |
|
} |
|
|
|
type token struct { |
|
typ TokenType |
|
pos TokenPosition |
|
val string |
|
} |
|
|
|
func NewToken(typ TokenType, val []rune, pos TokenPosition) Token { |
|
return &token{ |
|
typ: typ, |
|
val: string(val), |
|
pos: pos, |
|
} |
|
} |
|
|
|
func (t token) Type() TokenType { |
|
return t.typ |
|
} |
|
|
|
func (t token) Position() TokenPosition { |
|
return t.pos |
|
} |
|
|
|
func (t token) String() string { |
|
return t.val |
|
} |
|
|
|
// ErrorToken |
|
type ErrorToken interface { |
|
Token |
|
Error() string |
|
Unwrap() error |
|
} |
|
|
|
type errorToken struct { |
|
token |
|
err error |
|
} |
|
|
|
func NewErrorToken(err error, pos TokenPosition) ErrorToken { |
|
return &errorToken{ |
|
token: token{ |
|
typ: TokenError, |
|
val: err.Error(), |
|
pos: pos, |
|
}, |
|
err: err, |
|
} |
|
} |
|
|
|
func (t errorToken) Error() string { |
|
return t.err.Error() |
|
} |
|
|
|
func (t errorToken) Unwrap() error { |
|
return t.err |
|
} |
|
|
|
// SyntaxErrorToken |
|
type SyntaxErrorToken struct { |
|
ErrorToken |
|
|
|
Cursor int |
|
Buffer string |
|
} |
|
|
|
func NewSyntaxErrorToken(msg string, pos TokenPosition, cur int, buffer []rune) *SyntaxErrorToken { |
|
s := fmt.Sprintf("Syntax Error at %v.%v+%v", pos.Line, pos.Row, cur) |
|
|
|
if len(msg) > 0 { |
|
s = fmt.Sprintf("%s: %s", s, msg) |
|
} |
|
|
|
return &SyntaxErrorToken{ |
|
ErrorToken: NewErrorToken(errors.New(s), pos), |
|
|
|
Cursor: cur, |
|
Buffer: string(buffer), |
|
} |
|
}
|
|
|