Alejandro Mery
3 years ago
1 changed files with 104 additions and 0 deletions
@ -0,0 +1,104 @@
|
||||
package lexer |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"asciigoat.org/core/runes" |
||||
) |
||||
|
||||
// state function
|
||||
type StateFn func(Lexer) StateFn |
||||
|
||||
type Lexer interface { |
||||
Run() // run state machine
|
||||
|
||||
Position() TokenPosition // base for the next token
|
||||
Tokens() <-chan Token // tokens output
|
||||
|
||||
NewLine() |
||||
Step(n int) |
||||
|
||||
Emit(TokenType) |
||||
EmitError(error) |
||||
EmitErrorf(string, ...interface{}) |
||||
EmitSyntaxError(string, ...interface{}) |
||||
} |
||||
|
||||
type lexer struct { |
||||
start StateFn // initial state
|
||||
|
||||
in *runes.Feeder // runes source
|
||||
pos TokenPosition // base for the next token
|
||||
cursor int // look ahead pointer
|
||||
tokens chan Token // tokens output
|
||||
} |
||||
|
||||
func NewLexer(start StateFn, in *runes.Feeder, tokens int) Lexer { |
||||
return &lexer{ |
||||
start: start, |
||||
in: in, |
||||
pos: TokenPosition{1, 1}, |
||||
tokens: make(chan Token, tokens), |
||||
} |
||||
} |
||||
|
||||
func (lex *lexer) Run() { |
||||
defer close(lex.tokens) |
||||
|
||||
for state := lex.start; state != nil; { |
||||
state = state(lex) |
||||
} |
||||
} |
||||
|
||||
func (lex *lexer) Position() TokenPosition { |
||||
return lex.pos |
||||
} |
||||
|
||||
func (lex *lexer) Step(n int) { |
||||
lex.cursor += n |
||||
} |
||||
|
||||
func (lex *lexer) NewLine() { |
||||
lex.pos.NewLine() |
||||
} |
||||
|
||||
func (lex *lexer) Tokens() <-chan Token { |
||||
return lex.tokens |
||||
} |
||||
|
||||
func (lex *lexer) Emit(typ TokenType) { |
||||
var text []rune |
||||
|
||||
pos := lex.pos |
||||
|
||||
// extract text to emit, and update cursor for the next
|
||||
if n := lex.cursor; n > 0 { |
||||
text = lex.in.Runes()[:n] |
||||
lex.in.Skip(n) |
||||
lex.pos.Step(n) |
||||
lex.cursor = 0 |
||||
} |
||||
|
||||
lex.tokens <- NewToken(typ, text, pos) |
||||
} |
||||
|
||||
func (lex *lexer) EmitError(err error) { |
||||
lex.tokens <- NewErrorToken(err, lex.pos) |
||||
} |
||||
|
||||
func (lex *lexer) EmitErrorf(s string, args ...interface{}) { |
||||
if len(args) > 0 { |
||||
s = fmt.Sprintf(s, args...) |
||||
} |
||||
|
||||
lex.tokens <- NewErrorToken(errors.New(s), lex.pos) |
||||
} |
||||
|
||||
func (lex *lexer) EmitSyntaxError(s string, args ...interface{}) { |
||||
if len(args) > 0 { |
||||
s = fmt.Sprintf(s, args...) |
||||
} |
||||
|
||||
lex.tokens <- NewSyntaxErrorToken(s, lex.pos, lex.cursor, lex.in.Runes()) |
||||
} |
Loading…
Reference in new issue