Files
sqv-engine/sql/parser.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()
}