158 lines
2.7 KiB
Go
158 lines
2.7 KiB
Go
package sql
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
)
|
|
|
|
type Parser struct {
|
|
s *Lexer
|
|
buf LexRes
|
|
}
|
|
|
|
type LexRes struct {
|
|
pos Position
|
|
tok Token
|
|
lit string
|
|
avail bool
|
|
}
|
|
|
|
func NewParser(r io.Reader) *Parser {
|
|
return &Parser{s: NewLexer(r)}
|
|
}
|
|
|
|
func (p *Parser) Parse() (Statement, error) {
|
|
tok, ok := p.expectOne(CREATE, EOF, SELECT, INSERT, DELETE)
|
|
if !ok {
|
|
return nil, p.unexpectedToken(CREATE, EOF, SELECT, INSERT, DELETE)
|
|
} else if tok == EOF {
|
|
return nil, io.EOF
|
|
}
|
|
|
|
switch tok {
|
|
case EOF:
|
|
return nil, io.EOF
|
|
case CREATE:
|
|
return p.parseCreateTable()
|
|
case SELECT:
|
|
return p.parseSelect()
|
|
case INSERT:
|
|
return p.parseInsert()
|
|
case DELETE:
|
|
return p.parseDelete()
|
|
default:
|
|
panic("SHOULD NEVER BE REACHED")
|
|
}
|
|
}
|
|
|
|
func (p *Parser) unexpectedToken(expected ...Token) error {
|
|
l := len(expected)
|
|
pos, tok, lit := p.rescan()
|
|
if l <= 0 {
|
|
return fmt.Errorf("Encountered unexpected token: %v lit: '%v' on pos: %v", tok, lit, pos)
|
|
} else if l == 1 {
|
|
return fmt.Errorf(
|
|
"Encountered unexpected token: %v lit: '%v' on pos: %v, expected %v",
|
|
tok,
|
|
lit,
|
|
pos,
|
|
expected[0],
|
|
)
|
|
} else {
|
|
return fmt.Errorf(
|
|
"Encountered unexpected token: %v lit: '%v' on pos: %v, expected one of '%v'",
|
|
tok,
|
|
lit,
|
|
pos,
|
|
arrayToString(expected, ", "),
|
|
)
|
|
}
|
|
}
|
|
|
|
func (p *Parser) expectSequence(token ...Token) bool {
|
|
for _, tok := range token {
|
|
if !p.expectNext(tok) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (p *Parser) expectNext(token Token) bool {
|
|
_, tok, _ := p.scan()
|
|
return tok == token
|
|
}
|
|
|
|
func (p *Parser) expectOne(token ...Token) (Token, bool) {
|
|
_, tok, _ := p.scan()
|
|
ok := slices.ContainsFunc(token, func(t Token) bool {
|
|
return tok == t
|
|
})
|
|
return tok, ok
|
|
}
|
|
|
|
func (p *Parser) consumeUntilOne(max int, token ...Token) bool {
|
|
for range max {
|
|
_, tok, _ := p.scan()
|
|
if slices.ContainsFunc(token, func(t Token) bool {
|
|
return tok == t
|
|
}) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (p *Parser) consumeUntil(token Token, max int) bool {
|
|
for range max {
|
|
_, tok, _ := p.scan()
|
|
if tok == token {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (p *Parser) consumeIfOne(token ...Token) {
|
|
_, tok, _ := p.scan()
|
|
if slices.ContainsFunc(token, func(t Token) bool {
|
|
return tok == t
|
|
}) {
|
|
return
|
|
}
|
|
|
|
p.unscan()
|
|
}
|
|
|
|
func (p *Parser) consumeIf(token Token) {
|
|
_, tok, _ := p.scan()
|
|
if tok == token {
|
|
return
|
|
}
|
|
|
|
p.unscan()
|
|
}
|
|
|
|
func (p *Parser) scan() (Position, Token, string) {
|
|
if p.buf.avail {
|
|
p.buf.avail = false
|
|
return p.buf.pos, p.buf.tok, p.buf.lit
|
|
}
|
|
|
|
pos, tok, lit := p.s.Lex()
|
|
|
|
p.buf.pos, p.buf.tok, p.buf.lit = pos, tok, lit
|
|
return pos, tok, lit
|
|
}
|
|
|
|
func (p *Parser) unscan() {
|
|
p.buf.avail = true
|
|
}
|
|
|
|
func (p *Parser) rescan() (Position, Token, string) {
|
|
p.unscan()
|
|
return p.scan()
|
|
}
|