Remove last, add unscan and rescan, add handle for if not exist, just gets skipped for now

This commit is contained in:
Pablu
2025-10-28 13:16:19 +01:00
parent cd5f72bfbe
commit 396b531013
4 changed files with 69 additions and 58 deletions

View File

@@ -74,5 +74,6 @@ CREATE TABLE IF NOT EXISTS auth_states (
} }
stmt.Print() stmt.Print()
fmt.Println()
} }
} }

3
go.mod
View File

@@ -1,6 +1,3 @@
module git.pablu.de/pablu/sqv-engine module git.pablu.de/pablu/sqv-engine
go 1.25.3 go 1.25.3
require github.com/rqlite/sql v0.0.0-20250623131620-453fa49cad04

View File

@@ -20,6 +20,7 @@ const (
RPAREN RPAREN
COMMA COMMA
// Keywords
CREATE CREATE
TABLE TABLE
@@ -47,6 +48,8 @@ var keywords map[string]Token = map[string]Token{
"TEXT": TEXT, "TEXT": TEXT,
"INTEGER": INTEGER, "INTEGER": INTEGER,
"NULL": NULL, "NULL": NULL,
"IF": IF,
"EXISTS": EXISTS,
} }
type Position struct { type Position struct {

View File

@@ -7,12 +7,15 @@ import (
) )
type Parser struct { type Parser struct {
s *Lexer s *Lexer
last struct { buf LexRes
pos Position }
tok Token
lit string type LexRes struct {
} pos Position
tok Token
lit string
avail bool
} }
func NewParser(r io.Reader) *Parser { func NewParser(r io.Reader) *Parser {
@@ -27,25 +30,37 @@ func (p *Parser) Parse() (*CreateTableStatement, error) {
return nil, io.EOF return nil, io.EOF
} }
if !p.expectSequence(TABLE, IDENT) { if !p.expectNext(TABLE) {
return nil, p.unexpectedToken() return nil, p.unexpectedToken()
} }
tok, ok = p.expectOne(IDENT, IF)
if !ok {
return nil, p.unexpectedToken(IDENT, IF)
} else if tok == IF && !p.expectSequence(NOT, EXISTS, IDENT) {
return nil, p.unexpectedToken()
}
_, _, lit := p.rescan()
stmt := CreateTableStatement{ stmt := CreateTableStatement{
TableName: p.last.lit, TableName: lit,
Columns: make([]Column, 0), Columns: make([]Column, 0),
} }
if !p.expectNext(LPAREN) { if !p.expectNext(LPAREN) {
return nil, p.unexpectedToken(LPAREN) return nil, p.unexpectedToken(LPAREN)
} }
for { for {
lastTok := p.last.tok
_, tok, _ := p.scan() _, tok, _ := p.scan()
switch tok { switch tok {
case RPAREN:
if !p.expectNext(SEMI) {
return nil, p.unexpectedToken(SEMI)
}
return &stmt, nil
case IDENT: case IDENT:
column, err := p.parseColumn() column, err := p.parseColumn()
if err != nil { if err != nil {
@@ -53,24 +68,11 @@ func (p *Parser) Parse() (*CreateTableStatement, error) {
} }
stmt.Columns = append(stmt.Columns, column) stmt.Columns = append(stmt.Columns, column)
case RPAREN:
if !p.expectNext(SEMI) {
return nil, p.unexpectedToken(SEMI)
}
return &stmt, nil
case SEMI:
if lastTok != RPAREN {
return nil, p.unexpectedToken(RPAREN)
}
return &stmt, nil
case FOREIGN: case FOREIGN:
if !p.expectSequence(KEY, LPAREN, IDENT) { if !p.expectSequence(KEY, LPAREN, IDENT) {
return nil, p.unexpectedToken() return nil, p.unexpectedToken()
} }
columnName := p.last.lit _, _, columnName := p.rescan()
if !p.expectSequence(RPAREN, REFERENCES) { if !p.expectSequence(RPAREN, REFERENCES) {
return nil, p.unexpectedToken() return nil, p.unexpectedToken()
@@ -87,31 +89,31 @@ func (p *Parser) Parse() (*CreateTableStatement, error) {
stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, ref) stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, ref)
case COMMA:
continue
default: default:
return nil, p.unexpectedToken(IDENT, RPAREN, SEMI, FOREIGN) return nil, p.unexpectedToken(IDENT, RPAREN, FOREIGN, COMMA)
} }
} }
} }
func (p *Parser) parseColumn() (Column, error) { func (p *Parser) parseColumn() (Column, error) {
column := Column{Name: p.last.lit, Extra: make([]string, 0)} _, _, lit := p.rescan()
column := Column{Name: lit, Extra: make([]string, 0)}
_, tok, lit := p.scan() if _, ok := p.expectOne(TEXT, INTEGER); !ok {
switch tok {
case TEXT:
fallthrough
case INTEGER:
column.Type = lit
default:
return Column{}, p.unexpectedToken(TEXT, INTEGER) return Column{}, p.unexpectedToken(TEXT, INTEGER)
} }
_, _, column.Type = p.rescan()
for { for {
_, tok, lit := p.scan() _, tok, lit := p.scan()
switch tok { switch tok {
case COMMA: case COMMA:
fallthrough return column, nil
case RPAREN: case RPAREN:
p.unscan()
return column, nil return column, nil
case PRIMARY: case PRIMARY:
@@ -120,7 +122,8 @@ func (p *Parser) parseColumn() (Column, error) {
if _, ok := p.expectOne(NULL, KEY); !ok { if _, ok := p.expectOne(NULL, KEY); !ok {
return Column{}, p.unexpectedToken(NULL, KEY) return Column{}, p.unexpectedToken(NULL, KEY)
} }
column.Extra = append(column.Extra, fmt.Sprintf("%v_%v", lit, p.last.lit)) _, _, rlit := p.rescan()
column.Extra = append(column.Extra, fmt.Sprintf("%v_%v", lit, rlit))
case REFERENCES: case REFERENCES:
ref, err := p.references() ref, err := p.references()
@@ -128,6 +131,7 @@ func (p *Parser) parseColumn() (Column, error) {
return Column{}, err return Column{}, err
} }
column.Extra = append(column.Extra, ref) column.Extra = append(column.Extra, ref)
fmt.Println(ref)
default: default:
return Column{}, p.unexpectedToken(COMMA, RPAREN, PRIMARY, NOT, REFERENCES) return Column{}, p.unexpectedToken(COMMA, RPAREN, PRIMARY, NOT, REFERENCES)
@@ -137,22 +141,23 @@ func (p *Parser) parseColumn() (Column, error) {
func (p *Parser) unexpectedToken(expected ...Token) error { func (p *Parser) unexpectedToken(expected ...Token) error {
l := len(expected) l := len(expected)
pos, tok, lit := p.rescan()
if l <= 0 { if l <= 0 {
return fmt.Errorf("Encountered unexpected token: %v lit: '%v' on pos: %v", p.last.tok, p.last.lit, p.last.pos) return fmt.Errorf("Encountered unexpected token: %v lit: '%v' on pos: %v", tok, lit, pos)
} else if l == 1 { } else if l == 1 {
return fmt.Errorf( return fmt.Errorf(
"Encountered unexpected token: %v lit: '%v' on pos: %v, expected %v", "Encountered unexpected token: %v lit: '%v' on pos: %v, expected %v",
p.last.tok, tok,
p.last.lit, lit,
p.last.pos, pos,
expected[0], expected[0],
) )
} else { } else {
return fmt.Errorf( return fmt.Errorf(
"Encountered unexpected token: %v lit: '%v' on pos: %v, expected one of '%v'", "Encountered unexpected token: %v lit: '%v' on pos: %v, expected one of '%v'",
p.last.tok, tok,
p.last.lit, lit,
p.last.pos, pos,
arrayToString(expected, ", "), arrayToString(expected, ", "),
) )
} }
@@ -162,13 +167,13 @@ func (p *Parser) references() (string, error) {
if !p.expectNext(IDENT) { if !p.expectNext(IDENT) {
return "", p.unexpectedToken(IDENT) return "", p.unexpectedToken(IDENT)
} }
referenceTableName := p.last.lit _, _, referenceTableName := p.rescan()
if !p.expectSequence(LPAREN, IDENT) { if !p.expectSequence(LPAREN, IDENT) {
return "", p.unexpectedToken() return "", p.unexpectedToken()
} }
referenceColumnName := p.last.lit _, _, referenceColumnName := p.rescan()
if !p.expectNext(RPAREN) { if !p.expectNext(RPAREN) {
return "", p.unexpectedToken(RPAREN) return "", p.unexpectedToken(RPAREN)
@@ -201,17 +206,22 @@ func (p *Parser) expectOne(token ...Token) (Token, bool) {
} }
func (p *Parser) scan() (Position, Token, string) { func (p *Parser) scan() (Position, Token, string) {
pos, tok, lit := p.s.Lex() if p.buf.avail {
// fmt.Printf("Scanning next Token: %v | pos: %v | lit: %v\n", tok, pos, lit) p.buf.avail = false
return p.buf.pos, p.buf.tok, p.buf.lit
p.last = struct {
pos Position
tok Token
lit string
}{
pos,
tok,
lit,
} }
pos, tok, lit := p.s.Lex()
p.buf.pos, p.buf.tok, p.buf.lit = pos, tok, lit
return 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()
}