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() }