Add more syntax to lexer and parser, and make improvements to tview
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
engine "git.pablu.de/pablu/sqv-engine"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
// "github.com/uaraven/logview"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -24,6 +25,8 @@ func main() {
|
||||
tableView.Clear()
|
||||
})
|
||||
|
||||
// logView := logview.NewLogView().SetTitle("Logs")
|
||||
|
||||
verticalFlex := tview.NewFlex().
|
||||
AddItem(menuView, 0, 1, true).
|
||||
AddItem(tableView, 0, 3, false)
|
||||
@@ -32,12 +35,16 @@ func main() {
|
||||
SetDirection(tview.FlexRow).
|
||||
AddItem(verticalFlex, 0, 4, true).
|
||||
AddItem(sqlEditor, 0, 1, false)
|
||||
// AddItem(logView, 0, 0, false)
|
||||
|
||||
m, err := engine.NewManager("db.sqlite")
|
||||
if err != nil {
|
||||
log.Fatalf("Ran into an error on opening Manager, err: %v\n", err)
|
||||
}
|
||||
m.Start()
|
||||
err = m.Start()
|
||||
if err != nil {
|
||||
log.Fatalf("Ran into an error on starting Manager, err: %v\n", err)
|
||||
}
|
||||
|
||||
tables := m.GetTables()
|
||||
|
||||
@@ -60,14 +67,15 @@ func main() {
|
||||
|
||||
err = m.LoadTable(&t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Error while loading Table, err: %v\n", err)
|
||||
}
|
||||
|
||||
for ri, r := range t.Rows {
|
||||
for rc, c := range r.Values {
|
||||
tableView.SetCell(ri+1, rc, tview.NewTableCell(c).SetTextColor(tcell.ColorWhite).SetAlign(tview.AlignCenter))
|
||||
tableView.SetCell(ri+1, rc, tview.NewTableCell(c).SetTextColor(tcell.ColorWhite).SetAlign(tview.AlignLeft).SetMaxWidth(30))
|
||||
}
|
||||
}
|
||||
tableView.ScrollToBeginning()
|
||||
})
|
||||
|
||||
// Idk this shouldnt be needed imo but with only 0 it doesnt work, and with 1, well we are on Table 1 not zero, WHICH WE CANT ALWAYS SAY THERE IS
|
||||
@@ -131,6 +139,8 @@ func main() {
|
||||
|
||||
menuHidden := false
|
||||
editorHidden := false
|
||||
// logHidden := true
|
||||
|
||||
horizontalFlex.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch event.Key() {
|
||||
case tcell.KeyCtrlH:
|
||||
@@ -151,6 +161,13 @@ func main() {
|
||||
app.SetFocus(sqlEditor)
|
||||
}
|
||||
editorHidden = !editorHidden
|
||||
// case tcell.KeyCtrlD:
|
||||
// if !logHidden {
|
||||
// horizontalFlex.ResizeItem(logView, 0, 0)
|
||||
// } else {
|
||||
// horizontalFlex.ResizeItem(logView, 0, 1)
|
||||
// }
|
||||
// logHidden = !logHidden
|
||||
}
|
||||
|
||||
return event
|
||||
|
||||
3
go.mod
3
go.mod
@@ -10,12 +10,14 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
code.rocketnine.space/tslocum/cbind v0.1.5 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
@@ -26,6 +28,7 @@ require (
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/uaraven/logview v0.1.1 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
|
||||
15
go.sum
15
go.sum
@@ -1,3 +1,5 @@
|
||||
code.rocketnine.space/tslocum/cbind v0.1.5 h1:i6NkeLLNPNMS4NWNi3302Ay3zSU6MrqOT+yJskiodxE=
|
||||
code.rocketnine.space/tslocum/cbind v0.1.5/go.mod h1:LtfqJTzM7qhg88nAvNhx+VnTjZ0SXBJtxBObbfBWo/M=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
@@ -22,19 +24,25 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payR
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||
github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
||||
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
||||
@@ -47,10 +55,13 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c=
|
||||
github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/uaraven/logview v0.1.1 h1:0y2CXMKUqmNnHdj3oRwSn+TrJAoESDBkgqn23aJ5YP4=
|
||||
github.com/uaraven/logview v0.1.1/go.mod h1:87JVTmYbK2ku6znEfUERs/+C3ZYmW8RO9ylpdA7vC64=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@@ -83,6 +94,7 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -98,6 +110,8 @@ golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
@@ -108,6 +122,7 @@ golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
|
||||
71
manager.go
71
manager.go
@@ -51,9 +51,10 @@ func NewManager(path string) (*Manager, error) {
|
||||
sqls = append(sqls, sql)
|
||||
}
|
||||
|
||||
schema := strings.Join(sqls, ";")
|
||||
schema := strings.Join(sqls, ";\n")
|
||||
schema += ";"
|
||||
// fmt.Println(schema)
|
||||
|
||||
fmt.Println(schema)
|
||||
|
||||
return &Manager{
|
||||
parser: engine.NewParser(strings.NewReader(schema)),
|
||||
@@ -219,8 +220,8 @@ func (m *Manager) GetTable(name string) (Table, bool) {
|
||||
return table, true
|
||||
}
|
||||
|
||||
func (m *Manager) LoadTable(table *Table) error {
|
||||
rows, err := m.conn.Query(fmt.Sprintf("SELECT * FROM %v", table.Name))
|
||||
func (m *Manager) loadTableRaw(table *Table, s string, args ...any) error {
|
||||
rows, err := m.conn.Query(s, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -229,6 +230,7 @@ func (m *Manager) LoadTable(table *Table) error {
|
||||
for rows.Next() {
|
||||
cols := make([]any, len(table.Columns))
|
||||
for i, column := range table.Columns {
|
||||
if column.Flags.Has(NOT_NULL) {
|
||||
switch column.Type {
|
||||
case BLOB:
|
||||
cols[i] = new([]byte)
|
||||
@@ -241,6 +243,20 @@ func (m *Manager) LoadTable(table *Table) error {
|
||||
default:
|
||||
panic("THIS SHOULD NEVER HAPPEN, WE HIT AN UNKNOWN COLUMN.TYPE")
|
||||
}
|
||||
} else {
|
||||
switch column.Type {
|
||||
case BLOB:
|
||||
cols[i] = new([]byte)
|
||||
case TEXT:
|
||||
cols[i] = new(sql.NullString)
|
||||
case INTEGER:
|
||||
cols[i] = new(sql.NullInt64)
|
||||
case REAL:
|
||||
cols[i] = new(sql.NullFloat64)
|
||||
default:
|
||||
panic("THIS SHOULD NEVER HAPPEN, WE HIT AN UNKNOWN COLUMN.TYPE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = rows.Scan(cols...)
|
||||
@@ -256,6 +272,16 @@ func (m *Manager) LoadTable(table *Table) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) LoadTableMaxRows(table *Table, maxRows int) error {
|
||||
sql := fmt.Sprintf("SELECT * FROM %v LIMIT ?", table.Name)
|
||||
return m.loadTableRaw(table, sql, maxRows)
|
||||
}
|
||||
|
||||
func (m *Manager) LoadTable(table *Table) error {
|
||||
sql := fmt.Sprintf("SELECT * FROM %v", table.Name)
|
||||
return m.loadTableRaw(table, sql)
|
||||
}
|
||||
|
||||
func anyToStr(a []any) []string {
|
||||
res := make([]string, len(a))
|
||||
|
||||
@@ -268,7 +294,30 @@ func anyToStr(a []any) []string {
|
||||
case *float64:
|
||||
res[i] = strconv.FormatFloat(*v, 'f', 2, 64)
|
||||
case *[]byte:
|
||||
res[i] = hex.EncodeToString(*v)
|
||||
buf := *v
|
||||
if len(buf) > 512 {
|
||||
buf = buf[0:512]
|
||||
}
|
||||
res[i] = hex.EncodeToString(buf)
|
||||
case *sql.NullInt64:
|
||||
if v.Valid {
|
||||
res[i] = strconv.Itoa(int(v.Int64))
|
||||
} else {
|
||||
res[i] = "NULL"
|
||||
}
|
||||
case *sql.NullFloat64:
|
||||
if v.Valid {
|
||||
res[i] = strconv.FormatFloat(v.Float64, 'f', 2, 64)
|
||||
} else {
|
||||
res[i] = "NULL"
|
||||
}
|
||||
case *sql.NullString:
|
||||
if v.Valid {
|
||||
res[i] = v.String
|
||||
} else {
|
||||
res[i] = "NULL"
|
||||
}
|
||||
|
||||
default:
|
||||
panic("THIS SHOULD NEVER HAPPEN, WE GOT SERVED AN UNKNOWN TYPE")
|
||||
}
|
||||
@@ -301,15 +350,17 @@ func (m *Manager) convertCreateTableStatementToTable(cts *engine.CreateTableStat
|
||||
refTable, ok := m.GetTable(tableName)
|
||||
if !ok {
|
||||
fmt.Println(m.tables)
|
||||
return Table{}, fmt.Errorf("Reference table '%v' not found", tableName)
|
||||
}
|
||||
|
||||
fmt.Println(res)
|
||||
fmt.Println("Reference was skipped")
|
||||
// return Table{}, fmt.Errorf("Reference table '%v' not found", tableName)
|
||||
} else {
|
||||
colIndex := slices.IndexFunc(refTable.Columns, func(c Column) bool {
|
||||
return c.Name == columnName
|
||||
})
|
||||
|
||||
ref = &refTable.Columns[colIndex]
|
||||
}
|
||||
}
|
||||
|
||||
var columnType ColumnType
|
||||
switch column.Type {
|
||||
@@ -319,7 +370,7 @@ func (m *Manager) convertCreateTableStatementToTable(cts *engine.CreateTableStat
|
||||
columnType = BLOB
|
||||
case "TEXT":
|
||||
columnType = TEXT
|
||||
case "INTEGER":
|
||||
case "INTEGER", "NUMERIC":
|
||||
columnType = INTEGER
|
||||
default:
|
||||
panic("This shouldnt happen")
|
||||
@@ -348,6 +399,8 @@ func extrasToFlags(extras []string) ColumnFlag {
|
||||
res |= FOREIGN_KEY
|
||||
case "NOT_NULL":
|
||||
res |= NOT_NULL
|
||||
case "AUTOINCREMENT":
|
||||
res |= AUTO_INCREMENT
|
||||
default:
|
||||
log.Panicf("NOT IMPLEMENTED EXTRA: %v", extra)
|
||||
}
|
||||
|
||||
15
sql/lexer.go
15
sql/lexer.go
@@ -21,6 +21,9 @@ const (
|
||||
COMMA
|
||||
ASTERIKS
|
||||
ASSIGN
|
||||
BACKQUOTE
|
||||
QUOTE
|
||||
SINGLE_QUOTE
|
||||
|
||||
// Keywords
|
||||
CREATE
|
||||
@@ -41,12 +44,15 @@ const (
|
||||
NOT
|
||||
IF
|
||||
EXISTS
|
||||
AUTOINCREMENT
|
||||
CONSTRAINT
|
||||
|
||||
TEXT
|
||||
INTEGER
|
||||
NULL
|
||||
REAL
|
||||
BLOB
|
||||
NUMERIC
|
||||
)
|
||||
|
||||
var keywords map[string]Token = map[string]Token{
|
||||
@@ -71,6 +77,9 @@ var keywords map[string]Token = map[string]Token{
|
||||
"TOP": TOP,
|
||||
"REAL": REAL,
|
||||
"BLOB": BLOB,
|
||||
"AUTOINCREMENT": AUTOINCREMENT,
|
||||
"CONSTRAINT": CONSTRAINT,
|
||||
"NUMERIC": NUMERIC,
|
||||
}
|
||||
|
||||
type Position struct {
|
||||
@@ -116,6 +125,12 @@ func (l *Lexer) Lex() (Position, Token, string) {
|
||||
return l.pos, ASTERIKS, "*"
|
||||
case '=':
|
||||
return l.pos, ASSIGN, "="
|
||||
case '`':
|
||||
return l.pos, BACKQUOTE, "`"
|
||||
case '"':
|
||||
return l.pos, QUOTE, "\""
|
||||
case '\'':
|
||||
return l.pos, SINGLE_QUOTE, "'"
|
||||
default:
|
||||
if unicode.IsSpace(r) {
|
||||
continue
|
||||
|
||||
@@ -91,12 +91,23 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
tok, ok := p.expectOne(IDENT, IF)
|
||||
tok, ok := p.expectOne(QUOTE, SINGLE_QUOTE, BACKQUOTE, IDENT, IF)
|
||||
if !ok {
|
||||
return nil, p.unexpectedToken(IDENT, IF)
|
||||
} else if tok == IF && !p.expectSequence(NOT, EXISTS, IDENT) {
|
||||
}
|
||||
|
||||
switch tok {
|
||||
case IF:
|
||||
if !p.expectSequence(NOT, EXISTS) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
fallthrough
|
||||
case QUOTE, SINGLE_QUOTE, BACKQUOTE:
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
}
|
||||
_, _, lit := p.rescan()
|
||||
|
||||
stmt := CreateTableStatement{
|
||||
@@ -104,11 +115,13 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
Columns: make([]Column, 0),
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(LPAREN) {
|
||||
return nil, p.unexpectedToken(LPAREN)
|
||||
}
|
||||
|
||||
for {
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
_, tok, _ := p.scan()
|
||||
|
||||
switch tok {
|
||||
@@ -125,12 +138,29 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
}
|
||||
stmt.Columns = append(stmt.Columns, column)
|
||||
|
||||
// TODO: HANDLE AND SAVE CONSTRAINTS
|
||||
case CONSTRAINT:
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
// _, _, constraintName := p.rescan()
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
case FOREIGN:
|
||||
if !p.expectSequence(KEY, LPAREN, IDENT) {
|
||||
if !p.expectSequence(KEY, LPAREN) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
_, _, columnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectSequence(RPAREN, REFERENCES) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
@@ -147,12 +177,19 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
stmt.Columns[column].Extra = append(stmt.Columns[column].Extra, ref)
|
||||
|
||||
case PRIMARY:
|
||||
if !p.expectSequence(KEY, LPAREN, IDENT) {
|
||||
if !p.expectSequence(KEY, LPAREN) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
primaryKeyNames := make([]string, 0)
|
||||
_, _, columnName := p.rescan()
|
||||
primaryKeyNames = append(primaryKeyNames, columnName)
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
for {
|
||||
tok, ok := p.expectOne(RPAREN, COMMA)
|
||||
@@ -163,11 +200,14 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
break
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return nil, p.unexpectedToken()
|
||||
}
|
||||
|
||||
_, _, columnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
primaryKeyNames = append(primaryKeyNames, columnName)
|
||||
}
|
||||
|
||||
@@ -190,9 +230,10 @@ func (p *Parser) parseCreateTable() (*CreateTableStatement, error) {
|
||||
func (p *Parser) parseColumn() (Column, error) {
|
||||
_, _, lit := p.rescan()
|
||||
column := Column{Name: lit, Extra: make([]string, 0)}
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if _, ok := p.expectOne(TEXT, INTEGER, REAL, BLOB); !ok {
|
||||
return Column{}, p.unexpectedToken(TEXT, INTEGER, REAL, BLOB)
|
||||
if _, ok := p.expectOne(TEXT, INTEGER, REAL, BLOB, NUMERIC); !ok {
|
||||
return Column{}, p.unexpectedToken(TEXT, INTEGER, REAL, BLOB, NUMERIC)
|
||||
}
|
||||
_, _, column.Type = p.rescan()
|
||||
|
||||
@@ -222,6 +263,9 @@ func (p *Parser) parseColumn() (Column, error) {
|
||||
column.Extra = append(column.Extra, ref)
|
||||
fmt.Println(ref)
|
||||
|
||||
case AUTOINCREMENT:
|
||||
column.Extra = append(column.Extra, "AUTOINCREMENT")
|
||||
|
||||
default:
|
||||
return Column{}, p.unexpectedToken(COMMA, RPAREN, PRIMARY, NOT, REFERENCES)
|
||||
}
|
||||
@@ -253,17 +297,26 @@ func (p *Parser) unexpectedToken(expected ...Token) error {
|
||||
}
|
||||
|
||||
func (p *Parser) references() (string, error) {
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
if !p.expectNext(IDENT) {
|
||||
return "", p.unexpectedToken(IDENT)
|
||||
}
|
||||
_, _, referenceTableName := p.rescan()
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectSequence(LPAREN, IDENT) {
|
||||
if !p.expectNext(LPAREN) {
|
||||
return "", p.unexpectedToken()
|
||||
}
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(IDENT) {
|
||||
return "", p.unexpectedToken()
|
||||
}
|
||||
_, _, referenceColumnName := p.rescan()
|
||||
|
||||
p.consumeIfOne(QUOTE, SINGLE_QUOTE, BACKQUOTE)
|
||||
|
||||
if !p.expectNext(RPAREN) {
|
||||
return "", p.unexpectedToken(RPAREN)
|
||||
}
|
||||
@@ -316,6 +369,26 @@ func (p *Parser) consumeUntil(token Token, max int) bool {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user