149 lines
2.2 KiB
Go
149 lines
2.2 KiB
Go
package sql
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
type Token int
|
|
|
|
const (
|
|
EOF Token = iota
|
|
ILLEGAL
|
|
IDENT
|
|
|
|
SEMI
|
|
LPAREN
|
|
RPAREN
|
|
COMMA
|
|
|
|
// Keywords
|
|
CREATE
|
|
TABLE
|
|
|
|
PRIMARY
|
|
FOREIGN
|
|
REFERENCES
|
|
KEY
|
|
NOT
|
|
IF
|
|
EXISTS
|
|
|
|
TEXT
|
|
INTEGER
|
|
NULL
|
|
)
|
|
|
|
var keywords map[string]Token = map[string]Token{
|
|
"CREATE": CREATE,
|
|
"TABLE": TABLE,
|
|
"PRIMARY": PRIMARY,
|
|
"FOREIGN": FOREIGN,
|
|
"REFERENCES": REFERENCES,
|
|
"KEY": KEY,
|
|
"NOT": NOT,
|
|
"TEXT": TEXT,
|
|
"INTEGER": INTEGER,
|
|
"NULL": NULL,
|
|
"IF": IF,
|
|
"EXISTS": EXISTS,
|
|
}
|
|
|
|
type Position struct {
|
|
line int
|
|
column int
|
|
}
|
|
|
|
type Lexer struct {
|
|
pos Position
|
|
reader *bufio.Reader
|
|
}
|
|
|
|
func NewLexer(reader io.Reader) *Lexer {
|
|
return &Lexer{
|
|
pos: Position{line: 1, column: 0},
|
|
reader: bufio.NewReader(reader),
|
|
}
|
|
}
|
|
|
|
func (l *Lexer) Lex() (Position, Token, string) {
|
|
for {
|
|
r, _, err := l.reader.ReadRune()
|
|
if err != nil && errors.Is(err, io.EOF) {
|
|
return l.pos, EOF, ""
|
|
} else if err != nil {
|
|
// Change this
|
|
panic(err)
|
|
}
|
|
|
|
l.pos.column++
|
|
switch r {
|
|
case '\n':
|
|
l.resetPosition()
|
|
case ';':
|
|
return l.pos, SEMI, ";"
|
|
case ',':
|
|
return l.pos, COMMA, ","
|
|
case '(':
|
|
return l.pos, LPAREN, "("
|
|
case ')':
|
|
return l.pos, RPAREN, ")"
|
|
default:
|
|
if unicode.IsSpace(r) {
|
|
continue
|
|
} else if unicode.IsLetter(r) {
|
|
startPos := l.pos
|
|
l.backup()
|
|
lit := l.lexIdent()
|
|
|
|
litUpper := strings.ToUpper(lit)
|
|
if token, ok := keywords[litUpper]; ok {
|
|
return startPos, token, litUpper
|
|
}
|
|
|
|
return startPos, IDENT, lit
|
|
} else {
|
|
return l.pos, ILLEGAL, string(r)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (l *Lexer) lexIdent() string {
|
|
var lit string
|
|
for {
|
|
r, _, err := l.reader.ReadRune()
|
|
if err != nil && errors.Is(err, io.EOF) {
|
|
return lit
|
|
} else if err != nil {
|
|
// Change this
|
|
panic(err)
|
|
}
|
|
|
|
l.pos.column++
|
|
if unicode.IsLetter(r) || unicode.IsNumber(r) || r == '_' {
|
|
// Change this to stringstream or something similar
|
|
lit = lit + string(r)
|
|
} else {
|
|
l.backup()
|
|
return lit
|
|
}
|
|
}
|
|
}
|
|
|
|
func (l *Lexer) backup() {
|
|
if err := l.reader.UnreadRune(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
l.pos.column--
|
|
}
|
|
|
|
func (l *Lexer) resetPosition() {
|
|
l.pos.line++
|
|
l.pos.column = 0
|
|
}
|