3
0
corteza/pkg/ql/parser_nodes.go
2022-05-20 15:37:33 +02:00

212 lines
4.1 KiB
Go

package ql
import (
"fmt"
"strings"
)
// SelectStatement represents a SQL SELECT statement.
type (
parserNode interface {
fmt.Stringer
Validate() error
ToAST() *ASTNode
}
parserNodeSet []parserNode // Stream of comma delimited nodes
parserNodes []parserNode // Stream of space delimited nodes
lNull struct{}
lBoolean struct{ value bool }
lString struct {
value string
args []interface{}
}
lNumber struct {
value string
}
operator struct {
kind string
}
Ident struct {
Value string
args []interface{}
}
keyword struct {
keyword string
}
interval struct {
value string
unit string
}
function struct {
name string
arguments parserNodeSet
}
opDef struct {
name string
weight int
}
)
var (
ops = map[string]opDef{
// generic comparison
`=`: {name: `eq`, weight: 40},
`==`: {name: `eq`, weight: 40},
`===`: {name: `eq`, weight: 40},
`!=`: {name: `ne`, weight: 40},
`!==`: {name: `ne`, weight: 40},
`<>`: {name: `ne`, weight: 40},
`<`: {name: `lt`, weight: 30},
`<=`: {name: `le`, weight: 30},
`>`: {name: `gt`, weight: 30},
`>=`: {name: `ge`, weight: 30},
`IS`: {name: `is`, weight: 40},
`IS NOT`: {name: `nis`, weight: 40},
// conjunction
`AND`: {name: `and`, weight: 50},
`&&`: {name: `and`, weight: 50},
`OR`: {name: `or`, weight: 60},
`||`: {name: `or`, weight: 60},
`XOR`: {name: `xor`, weight: 60},
// math
`+`: {name: `add`, weight: 20},
`-`: {name: `sub`, weight: 20},
`*`: {name: `mult`, weight: 10},
`/`: {name: `div`, weight: 10},
// modifiers
`!`: {name: `not`, weight: 0},
// str comp.
`LIKE`: {name: `like`, weight: 40},
`NOT LIKE`: {name: `nlike`, weight: 40},
}
)
func isUnary(s string) bool {
return s == "!" || s == "not"
}
func getOp(op string) *opDef {
o, ok := ops[strings.ToUpper(op)]
if !ok {
return nil
}
return &o
}
func (n lNull) Validate() (err error) { return }
func (n lNull) String() string { return "NULL" }
func (n lBoolean) Validate() (err error) { return }
func (n lBoolean) String() string {
if n.value {
return "TRUE"
} else {
return "FALSE"
}
}
func (n lString) Validate() (err error) { return }
func (n lString) String() string { return fmt.Sprintf("%q", n.value) }
func (n lNumber) Validate() (err error) { return }
func (n lNumber) String() string { return n.value }
func (n operator) Validate() (err error) {
if getOp(n.kind) == nil {
return fmt.Errorf("unknown operator '%s'", n.kind)
}
return
}
func (n operator) String() string { return n.kind }
func (n keyword) Validate() (err error) { return }
func (n keyword) String() string { return n.keyword }
func (n interval) Validate() (err error) { return }
func (n interval) String() string { return fmt.Sprintf("INTERVAL %s %s", n.value, n.unit) }
func (n function) Validate() (err error) { return }
func (n function) String() string { return fmt.Sprintf("%s(%s)", n.name, n.arguments) }
func (n Ident) Validate() (err error) { return }
func (n Ident) String() string { return n.Value }
func (nn parserNodes) Validate() (err error) {
if err = validate(nn); err != nil {
return
}
l := len(nn)
if l == 0 {
return fmt.Errorf("empty set")
}
if op, ok := nn[0].(operator); ok && !isUnary(op.kind) {
return fmt.Errorf("malformed expression, unexpected operator '%s' at first node", op)
}
if l > 1 {
if op, ok := nn[l-1].(operator); ok {
return fmt.Errorf("malformed expression, unexpected operator '%s' at last node", op)
}
}
return
}
func (nn parserNodes) String() (out string) {
for i, n := range nn {
if i > 0 {
out = out + " "
}
out = out + n.String()
}
return
}
func (nn parserNodeSet) Validate() (err error) {
return validate(nn)
}
func (nn parserNodeSet) String() (out string) {
for i, n := range nn {
if i > 0 {
out = out + ", "
}
out = out + n.String()
}
return
}
func validate(nn []parserNode) (err error) {
if len(nn) == 0 {
return fmt.Errorf("empty node set")
}
for _, n := range nn {
if err = n.Validate(); err != nil {
return
}
}
return
}