Initial working stage, but not with all tests, because IF NOT EXISTS is not implemented
This commit is contained in:
79
cmd/sqv/main.go
Normal file
79
cmd/sqv/main.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.pablu.de/pablu/sqv-engine/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := `
|
||||||
|
CREATE TABLE TEST(
|
||||||
|
ID text PRIMARY KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE sessions (
|
||||||
|
session_id text PRIMARY KEY,
|
||||||
|
access_token text NOT NULL,
|
||||||
|
user_email text NOT NULL,
|
||||||
|
FOREIGN KEY(user_email) REFERENCES users(email)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
email text PRIMARY KEY,
|
||||||
|
username text
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
|
session_id text PRIMARY KEY,
|
||||||
|
access_token text NOT NULL,
|
||||||
|
user_email text NOT NULL,
|
||||||
|
FOREIGN KEY(user_email) REFERENCES users(email)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS game_settings (
|
||||||
|
lobby_id text PRIMARY KEY,
|
||||||
|
max_players integer,
|
||||||
|
game_mode text,
|
||||||
|
selected_playlist_id text
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS lobbys (
|
||||||
|
lobby_id text PRIMARY KEY,
|
||||||
|
host_email text,
|
||||||
|
game_settings_id text,
|
||||||
|
FOREIGN KEY(game_settings_id) REFERENCES game_settings(lobby_id),
|
||||||
|
FOREIGN KEY(host_email) REFERENCES users(email)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS users_in_lobbys (
|
||||||
|
user_email text PRIMARY KEY,
|
||||||
|
lobby_id text,
|
||||||
|
FOREIGN KEY(user_email) REFERENCES users(email),
|
||||||
|
FOREIGN KEY(lobby_id) REFERENCES lobbys(lobby_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS auth_states (
|
||||||
|
state_id text PRIMARY KEY,
|
||||||
|
code_verifier text NOT NULL
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
parser := sql.NewParser(strings.NewReader(s))
|
||||||
|
|
||||||
|
for {
|
||||||
|
stmt, err := parser.Parse()
|
||||||
|
if err != nil && errors.Is(err, io.EOF) {
|
||||||
|
fmt.Println("Finished parsing")
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt.Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
6
go.mod
Normal file
6
go.mod
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module git.pablu.de/pablu/sqv-engine
|
||||||
|
|
||||||
|
go 1.25.3
|
||||||
|
|
||||||
|
require github.com/rqlite/sql v0.0.0-20250623131620-453fa49cad04
|
||||||
|
|
||||||
32
go.sum
Normal file
32
go.sum
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
github.com/AllenDang/cimgui-go v1.3.2-0.20250409185506-6b2ff1aa26b5 h1:IulPfLSfrjCzSr7TOn7777rl5qRMu39gEOxSTDm2wes=
|
||||||
|
github.com/AllenDang/cimgui-go v1.3.2-0.20250409185506-6b2ff1aa26b5/go.mod h1:Fg1LjMFQs91yohW3SccUhqUeuNQEeL5KX3mgEjnDh7A=
|
||||||
|
github.com/AllenDang/giu v0.14.1 h1:SqMt2peaqb3wWPkZ7m+dnJX4LddZNDduYz5jpo+LOxQ=
|
||||||
|
github.com/AllenDang/giu v0.14.1/go.mod h1:gD5hmav1LbkjL2/1O3Mpohl2Lb/uqrrOKSeZFeqQjD0=
|
||||||
|
github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8 h1:dKZMqib/yUDoCFigmz2agG8geZ/e3iRq304/KJXqKyw=
|
||||||
|
github.com/AllenDang/go-findfont v0.0.0-20200702051237-9f180485aeb8/go.mod h1:b4uuDd0s6KRIPa84cEEchdQ9ICh7K0OryZHbSzMca9k=
|
||||||
|
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
|
||||||
|
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
|
||||||
|
github.com/gucio321/glm-go v0.0.0-20241029220517-e1b5a3e011c8 h1:aczNwZRrReVWrZcqxvDjDmxP1NFISTAu+1Cp+3OCbUg=
|
||||||
|
github.com/gucio321/glm-go v0.0.0-20241029220517-e1b5a3e011c8/go.mod h1:Z3+NtD1rjXUVZg97dojhs70i5oneOrZ1xcFKfF/c2Ts=
|
||||||
|
github.com/mazznoer/csscolorparser v0.1.6 h1:uK6p5zBA8HaQZJSInHgHVmkVBodUAy+6snSmKJG7pqA=
|
||||||
|
github.com/mazznoer/csscolorparser v0.1.6/go.mod h1:OQRVvgCyHDCAquR1YWfSwwaDcM0LhnSffGnlbOew/3I=
|
||||||
|
github.com/napsy/go-css v1.0.0 h1:I1EiqpOJqo8eshGhm6OQXefXOfNgnp1SLOVfqcTeY2U=
|
||||||
|
github.com/napsy/go-css v1.0.0/go.mod h1:HqZYcKcNnv50fgOTdGUn9YbJa2qC9oJ3kLnyrwwVzUI=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
|
github.com/rqlite/sql v0.0.0-20250623131620-453fa49cad04 h1:bjr7gZERAJhYhqkLHXbkBSpjbB+PlgW6e9CRCJ2+J/w=
|
||||||
|
github.com/rqlite/sql v0.0.0-20250623131620-453fa49cad04/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
|
golang.design/x/hotkey v0.4.1 h1:zLP/2Pztl4WjyxURdW84GoZ5LUrr6hr69CzJFJ5U1go=
|
||||||
|
golang.design/x/hotkey v0.4.1/go.mod h1:M8SGcwFYHnKRa83FpTFQoZvPO5vVT+kWPztFqTQKmXA=
|
||||||
|
golang.design/x/mainthread v0.3.0 h1:UwFus0lcPodNpMOGoQMe87jSFwbSsEY//CA7yVmu4j8=
|
||||||
|
golang.design/x/mainthread v0.3.0/go.mod h1:vYX7cF2b3pTJMGM/hc13NmN6kblKnf4/IyvHeu259L0=
|
||||||
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
|
golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc=
|
||||||
|
gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU=
|
||||||
24
sql/ast.go
Normal file
24
sql/ast.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package sql
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type CreateTableStatement struct {
|
||||||
|
TableName string
|
||||||
|
Columns []Column
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CreateTableStatement) Print() {
|
||||||
|
fmt.Printf("Name: %v\nColumns:\n", c.TableName)
|
||||||
|
for _, column := range c.Columns {
|
||||||
|
fmt.Printf("- Name: %v\n Type: %v\n Extras:\n", column.Name, column.Type)
|
||||||
|
for _, extra := range column.Extra {
|
||||||
|
fmt.Printf(" - %v\n", extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Column struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Extra []string
|
||||||
|
}
|
||||||
143
sql/lexer.go
Normal file
143
sql/lexer.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Token int
|
||||||
|
|
||||||
|
const (
|
||||||
|
EOF Token = iota
|
||||||
|
ILLEGAL
|
||||||
|
IDENT
|
||||||
|
|
||||||
|
SEMI
|
||||||
|
LPAREN
|
||||||
|
RPAREN
|
||||||
|
COMMA
|
||||||
|
|
||||||
|
CREATE
|
||||||
|
TABLE
|
||||||
|
|
||||||
|
PRIMARY
|
||||||
|
FOREIGN
|
||||||
|
REFERENCES
|
||||||
|
KEY
|
||||||
|
NOT
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
208
sql/parser.go
Normal file
208
sql/parser.go
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
s *Lexer
|
||||||
|
last struct {
|
||||||
|
pos Position
|
||||||
|
tok Token
|
||||||
|
lit string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParser(r io.Reader) *Parser {
|
||||||
|
return &Parser{s: NewLexer(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) Parse() (*CreateTableStatement, error) {
|
||||||
|
tok, ok := p.expectOne(CREATE, EOF)
|
||||||
|
if !ok {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
} else if tok == EOF {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.expectNext(TABLE) {
|
||||||
|
return nil, errors.New("Expect TABLE token")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.expectNext(IDENT) {
|
||||||
|
return nil, errors.New("Expect IDENT token")
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := CreateTableStatement{
|
||||||
|
TableName: p.last.lit,
|
||||||
|
Columns: make([]Column, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, tok, _ = p.scan()
|
||||||
|
if tok != LPAREN {
|
||||||
|
return nil, errors.New("Expect LPAREN token")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
lastTok := p.last.tok
|
||||||
|
_, tok, _ := p.scan()
|
||||||
|
|
||||||
|
switch tok {
|
||||||
|
case IDENT:
|
||||||
|
column, err := p.parseColumn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stmt.Columns = append(stmt.Columns, column)
|
||||||
|
|
||||||
|
case RPAREN:
|
||||||
|
if !p.expectNext(SEMI) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
return &stmt, nil
|
||||||
|
|
||||||
|
case SEMI:
|
||||||
|
if lastTok != RPAREN {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &stmt, nil
|
||||||
|
|
||||||
|
case FOREIGN:
|
||||||
|
if !p.expectNext(KEY) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
if !p.expectNext(LPAREN) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.expectNext(IDENT) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
columnName := p.last.lit
|
||||||
|
|
||||||
|
if !p.expectNext(RPAREN) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.expectNext(REFERENCES) {
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := p.references()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
column := slices.IndexFunc(stmt.Columns, func(c Column) bool {
|
||||||
|
return c.Name == columnName
|
||||||
|
})
|
||||||
|
|
||||||
|
stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, ref)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseColumn() (Column, error) {
|
||||||
|
column := Column{Name: p.last.lit, Extra: make([]string, 0)}
|
||||||
|
|
||||||
|
_, tok, lit := p.scan()
|
||||||
|
switch tok {
|
||||||
|
case TEXT:
|
||||||
|
fallthrough
|
||||||
|
case INTEGER:
|
||||||
|
column.Type = lit
|
||||||
|
default:
|
||||||
|
return Column{}, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, tok, lit := p.scan()
|
||||||
|
switch tok {
|
||||||
|
case COMMA:
|
||||||
|
fallthrough
|
||||||
|
case RPAREN:
|
||||||
|
return column, nil
|
||||||
|
|
||||||
|
case PRIMARY:
|
||||||
|
fallthrough
|
||||||
|
case NOT:
|
||||||
|
if _, ok := p.expectOne(NULL, KEY); !ok {
|
||||||
|
return Column{}, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
column.Extra = append(column.Extra, fmt.Sprintf("%v_%v", lit, p.last.lit))
|
||||||
|
|
||||||
|
case REFERENCES:
|
||||||
|
ref, err := p.references()
|
||||||
|
if err != nil {
|
||||||
|
return Column{}, err
|
||||||
|
}
|
||||||
|
column.Extra = append(column.Extra, ref)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Column{}, p.unexpectedToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) unexpectedToken() error {
|
||||||
|
return fmt.Errorf("Encountered unexpected token: %v lit: '%v' on pos: %v", p.last.tok, p.last.lit, p.last.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) references() (string, error) {
|
||||||
|
if !p.expectNext(IDENT) {
|
||||||
|
return "", p.unexpectedToken()
|
||||||
|
}
|
||||||
|
referenceTableName := p.last.lit
|
||||||
|
|
||||||
|
if !p.expectNext(LPAREN) {
|
||||||
|
return "", p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.expectNext(IDENT) {
|
||||||
|
return "", p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceColumnName := p.last.lit
|
||||||
|
|
||||||
|
if !p.expectNext(RPAREN) {
|
||||||
|
return "", p.unexpectedToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("ref %v.%v", referenceTableName, referenceColumnName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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) scan() (Position, Token, string) {
|
||||||
|
pos, tok, lit := p.s.Lex()
|
||||||
|
// fmt.Printf("Scanning next Token: %v | pos: %v | lit: %v\n", tok, pos, lit)
|
||||||
|
|
||||||
|
p.last = struct {
|
||||||
|
pos Position
|
||||||
|
tok Token
|
||||||
|
lit string
|
||||||
|
}{
|
||||||
|
pos,
|
||||||
|
tok,
|
||||||
|
lit,
|
||||||
|
}
|
||||||
|
return pos, tok, lit
|
||||||
|
}
|
||||||
34
table.go
Normal file
34
table.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package engine
|
||||||
|
|
||||||
|
type Table struct {
|
||||||
|
Name string
|
||||||
|
TableValues []TableValue
|
||||||
|
Rows []Row
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValueFlags uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
PRIMARY_KEY ValueFlags = 1 << iota
|
||||||
|
FOREIGN_KEY
|
||||||
|
NOT_NULL
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v ValueFlags) Has(flag ValueFlags) bool {
|
||||||
|
return v&flag == flag
|
||||||
|
}
|
||||||
|
|
||||||
|
type TableValue struct {
|
||||||
|
Type string
|
||||||
|
Name string
|
||||||
|
Reference *TableValue
|
||||||
|
Flags ValueFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
type Value interface {
|
||||||
|
Representation() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Row struct {
|
||||||
|
Values map[TableValue]Value
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user