super-graph/core/internal/qcode/parse.go

730 lines
12 KiB
Go
Raw Normal View History

2019-03-24 14:57:29 +01:00
package qcode
import (
"errors"
"fmt"
"hash/maphash"
"sync"
2019-06-15 04:17:21 +02:00
"unsafe"
2019-03-24 14:57:29 +01:00
)
var (
errEOT = errors.New("end of tokens")
)
2019-06-08 02:53:08 +02:00
type parserType int32
2019-03-24 14:57:29 +01:00
const (
maxFields = 1200
2020-03-14 06:35:42 +01:00
maxArgs = 25
)
2019-04-19 07:55:03 +02:00
const (
2019-03-24 14:57:29 +01:00
parserError parserType = iota
parserEOF
opQuery
opMutate
opSub
NodeStr
NodeInt
NodeFloat
NodeBool
NodeObj
NodeList
NodeVar
2019-03-24 14:57:29 +01:00
)
type SelectionSet struct {
Name string
Args []Arg
argsA [10]Arg
Fields []Field
fieldsA [10]Field
2019-03-24 14:57:29 +01:00
}
type Operation struct {
Type parserType
SelectionSet
}
var zeroOperation = Operation{}
func (o *Operation) Reset() {
*o = zeroOperation
2019-03-24 14:57:29 +01:00
}
type Fragment struct {
Name string
On string
SelectionSet
}
var zeroFragment = Fragment{}
func (f *Fragment) Reset() {
*f = zeroFragment
}
2019-03-24 14:57:29 +01:00
type Field struct {
2019-06-08 02:53:08 +02:00
ID int32
ParentID int32
Name string
Alias string
Args []Arg
2019-06-15 04:17:21 +02:00
argsA [5]Arg
2019-06-08 02:53:08 +02:00
Children []int32
2019-06-15 04:17:21 +02:00
childrenA [5]int32
2019-03-24 14:57:29 +01:00
}
type Arg struct {
Name string
Val *Node
2020-06-09 01:28:22 +02:00
df bool
2019-03-24 14:57:29 +01:00
}
type Node struct {
Type parserType
Name string
Val string
Parent *Node
Children []*Node
exp *Exp
2019-03-24 14:57:29 +01:00
}
var zeroNode = Node{}
func (n *Node) Reset() {
*n = zeroNode
}
2019-03-24 14:57:29 +01:00
type Parser struct {
frags map[uint64]*Fragment
h maphash.Hash
2019-06-15 04:17:21 +02:00
input []byte // the string being scanned
2019-03-24 14:57:29 +01:00
pos int
items []item
err error
}
var nodePool = sync.Pool{
New: func() interface{} { return new(Node) },
}
var opPool = sync.Pool{
New: func() interface{} { return new(Operation) },
}
var fragPool = sync.Pool{
New: func() interface{} { return new(Fragment) },
}
var lexPool = sync.Pool{
New: func() interface{} { return new(lexer) },
}
2019-06-15 04:17:21 +02:00
func Parse(gql []byte) (*Operation, error) {
var err error
if len(gql) == 0 {
return nil, errors.New("blank query")
}
2019-03-24 14:57:29 +01:00
l := lexPool.Get().(*lexer)
l.Reset()
defer lexPool.Put(l)
if err = lex(l, gql); err != nil {
2019-03-24 14:57:29 +01:00
return nil, err
}
2019-06-15 04:17:21 +02:00
2019-03-24 14:57:29 +01:00
p := &Parser{
2019-06-15 04:17:21 +02:00
input: l.input,
2019-03-24 14:57:29 +01:00
pos: -1,
items: l.items,
}
op := opPool.Get().(*Operation)
op.Reset()
op.Fields = op.fieldsA[:0]
2019-03-24 14:57:29 +01:00
s := -1
qf := false
2019-06-15 04:17:21 +02:00
for {
if p.peek(itemEOF) {
p.ignore()
break
}
2019-06-15 04:17:21 +02:00
if p.peek(itemFragment) {
p.ignore()
if err = p.parseFragment(op); err != nil {
return nil, err
}
} else {
if !qf && p.peek(itemQuery, itemMutation, itemSub, itemObjOpen) {
s = p.pos
qf = true
}
p.ignore()
}
}
p.reset(s)
if err := p.parseOp(op); err != nil {
2019-03-24 14:57:29 +01:00
return nil, err
}
2019-06-15 04:17:21 +02:00
return op, nil
}
2019-06-15 04:17:21 +02:00
func (p *Parser) parseFragment(op *Operation) error {
frag := fragPool.Get().(*Fragment)
frag.Reset()
2019-06-15 04:17:21 +02:00
2020-06-09 01:28:22 +02:00
frag.Fields = frag.SelectionSet.fieldsA[:0]
frag.Args = frag.SelectionSet.argsA[:0]
if p.peek(itemName) {
frag.Name = p.val(p.next())
}
if p.peek(itemOn) {
2019-09-05 06:09:56 +02:00
p.ignore()
} else {
return errors.New("fragment: missing 'on' keyword")
2019-11-19 06:47:55 +01:00
}
2019-09-05 06:09:56 +02:00
if p.peek(itemName) {
frag.On = p.vall(p.next())
} else {
return errors.New("fragment: missing table name after 'on' keyword")
2019-06-15 04:17:21 +02:00
}
if p.peek(itemObjOpen) {
2020-01-16 07:44:19 +01:00
p.ignore()
} else {
return fmt.Errorf("fragment: expecting a '{', got: %s", p.next())
2020-01-16 07:44:19 +01:00
}
if err := p.parseSelectionSet(&frag.SelectionSet); err != nil {
return fmt.Errorf("fragment: %v", err)
2019-06-15 04:17:21 +02:00
}
if p.frags == nil {
p.frags = make(map[uint64]*Fragment)
}
2020-01-16 07:44:19 +01:00
_, _ = p.h.WriteString(frag.Name)
k := p.h.Sum64()
p.h.Reset()
2019-03-24 14:57:29 +01:00
p.frags[k] = frag
2019-03-24 14:57:29 +01:00
return nil
2019-03-24 14:57:29 +01:00
}
func (p *Parser) parseOp(op *Operation) error {
var err error
var typeSet bool
2020-01-16 07:44:19 +01:00
if p.peek(itemQuery, itemMutation, itemSub) {
err = p.parseOpTypeAndArgs(op)
2020-05-31 23:11:28 +02:00
if err != nil {
return fmt.Errorf("%s: %v", op.Type, err)
}
typeSet = true
2019-03-24 14:57:29 +01:00
}
if p.peek(itemObjOpen) {
p.ignore()
if !typeSet {
op.Type = opQuery
2019-03-24 14:57:29 +01:00
}
for {
if p.peek(itemEOF, itemFragment) {
p.ignore()
break
}
err = p.parseSelectionSet(&op.SelectionSet)
if err != nil {
return fmt.Errorf("%s: %v", op.Type, err)
}
}
} else {
return fmt.Errorf("expecting a query, mutation or subscription, got: %s", p.next())
2019-03-24 14:57:29 +01:00
}
return nil
2019-03-24 14:57:29 +01:00
}
func (p *Parser) parseOpTypeAndArgs(op *Operation) error {
2019-06-15 04:17:21 +02:00
item := p.next()
2019-12-25 07:24:30 +01:00
switch item._type {
2019-06-15 04:17:21 +02:00
case itemQuery:
op.Type = opQuery
case itemMutation:
op.Type = opMutate
case itemSub:
op.Type = opSub
}
2020-06-09 01:28:22 +02:00
op.Args = op.SelectionSet.argsA[:0]
2019-03-24 14:57:29 +01:00
var err error
if p.peek(itemName) {
2019-06-15 04:17:21 +02:00
op.Name = p.val(p.next())
2019-03-24 14:57:29 +01:00
}
if p.peek(itemArgsOpen) {
p.ignore()
2020-03-14 06:35:42 +01:00
op.Args, err = p.parseOpParams(op.Args)
2019-03-24 14:57:29 +01:00
if err != nil {
return err
2019-03-24 14:57:29 +01:00
}
}
return nil
}
2019-11-19 06:47:55 +01:00
func (p *Parser) parseSelectionSet(selset *SelectionSet) error {
var err error
2019-11-19 06:47:55 +01:00
selset.Fields, err = p.parseFields(selset.Fields)
if err != nil {
return err
2019-11-19 06:47:55 +01:00
}
return nil
2019-11-19 06:47:55 +01:00
}
func ParseArgValue(argVal string) (*Node, error) {
l := lexPool.Get().(*lexer)
l.Reset()
2019-11-19 06:47:55 +01:00
if err := lex(l, []byte(argVal)); err != nil {
return nil, err
}
2019-11-19 06:47:55 +01:00
p := &Parser{
input: l.input,
pos: -1,
items: l.items,
2019-03-24 14:57:29 +01:00
}
op, err := p.parseValue()
lexPool.Put(l)
2019-03-24 14:57:29 +01:00
return op, err
2019-03-24 14:57:29 +01:00
}
func (p *Parser) parseFields(fields []Field) ([]Field, error) {
st := NewStack()
if !p.peek(itemName, itemSpread) {
return nil, fmt.Errorf("unexpected token: %s", p.peekNext())
}
2019-03-24 14:57:29 +01:00
for {
if p.peek(itemEOF) {
p.ignore()
return nil, errors.New("invalid query")
2019-05-13 01:27:26 +02:00
}
if p.peek(itemObjClose) {
2019-03-24 14:57:29 +01:00
p.ignore()
if st.Len() != 0 {
st.Pop()
2020-01-16 07:44:19 +01:00
continue
} else {
break
2019-03-24 14:57:29 +01:00
}
}
if len(fields) >= maxFields {
return nil, fmt.Errorf("too many fields (max %d)", maxFields)
2019-03-24 14:57:29 +01:00
}
isFrag := false
2019-06-15 04:17:21 +02:00
if p.peek(itemSpread) {
p.ignore()
isFrag = true
}
2019-03-24 14:57:29 +01:00
if !p.peek(itemName) {
if isFrag {
return nil, fmt.Errorf("expecting a fragment name, got: %s", p.next())
} else {
return nil, fmt.Errorf("expecting an alias or field name, got: %s", p.next())
}
2019-05-13 01:27:26 +02:00
}
2019-03-24 14:57:29 +01:00
var f *Field
if isFrag {
name := p.val(p.next())
2020-06-09 01:28:22 +02:00
_, _ = p.h.WriteString(name)
id := p.h.Sum64()
p.h.Reset()
2020-06-09 01:28:22 +02:00
fr, ok := p.frags[id]
if !ok {
return nil, fmt.Errorf("no fragment named '%s' defined", name)
}
n := int32(len(fields))
fields = append(fields, fr.Fields...)
2020-06-07 23:03:09 +02:00
for i := 0; i < len(fr.Fields); i++ {
k := (n + int32(i))
f := &fields[k]
f.ID = int32(k)
// If this is the top-level point the parent to the parent of the
// previous field.
if f.ParentID == -1 {
pid := st.Peek()
f.ParentID = pid
if f.ParentID != -1 {
fields[pid].Children = append(fields[f.ParentID].Children, f.ID)
}
// Update all the other parents id's by our new place in this new array
} else {
f.ParentID += n
}
2020-06-07 23:03:09 +02:00
f.Children = make([]int32, len(f.Children))
copy(f.Children, fr.Fields[i].Children)
2020-06-09 01:28:22 +02:00
f.Args = make([]Arg, len(f.Args))
copy(f.Args, fr.Fields[i].Args)
// Update all the children which is needed.
for j := range f.Children {
f.Children[j] += n
}
}
2019-11-19 06:47:55 +01:00
} else {
fields = append(fields, Field{ID: int32(len(fields))})
f = &fields[(len(fields) - 1)]
f.Args = f.argsA[:0]
f.Children = f.childrenA[:0]
// Parse the field
if err := p.parseField(f); err != nil {
return nil, err
}
if st.Len() == 0 {
f.ParentID = -1
} else {
pid := st.Peek()
f.ParentID = pid
fields[pid].Children = append(fields[pid].Children, f.ID)
}
2019-03-24 14:57:29 +01:00
}
2020-01-16 07:44:19 +01:00
// The first opening curley brackets after this
// comes the columns or child fields
2019-03-24 14:57:29 +01:00
if p.peek(itemObjOpen) {
p.ignore()
2019-05-13 01:27:26 +02:00
st.Push(f.ID)
2019-03-24 14:57:29 +01:00
}
}
2019-05-13 01:27:26 +02:00
return fields, nil
2019-03-24 14:57:29 +01:00
}
2019-05-13 01:27:26 +02:00
func (p *Parser) parseField(f *Field) error {
2019-03-24 14:57:29 +01:00
var err error
2020-01-08 06:48:04 +01:00
v := p.next()
2019-03-24 14:57:29 +01:00
if p.peek(itemColon) {
p.ignore()
if p.peek(itemName) {
2020-01-08 06:48:04 +01:00
f.Alias = p.val(v)
f.Name = p.vall(p.next())
2019-03-24 14:57:29 +01:00
} else {
2019-05-13 01:27:26 +02:00
return errors.New("expecting an aliased field name")
2019-03-24 14:57:29 +01:00
}
2020-01-08 06:48:04 +01:00
} else {
f.Name = p.vall(v)
2019-03-24 14:57:29 +01:00
}
if p.peek(itemArgsOpen) {
p.ignore()
if f.Args, err = p.parseArgs(f.Args); err != nil {
2019-05-13 01:27:26 +02:00
return err
2019-03-24 14:57:29 +01:00
}
}
2019-05-13 01:27:26 +02:00
return nil
2019-03-24 14:57:29 +01:00
}
2020-03-14 06:35:42 +01:00
func (p *Parser) parseOpParams(args []Arg) ([]Arg, error) {
for {
if len(args) >= maxArgs {
return nil, fmt.Errorf("too many args (max %d)", maxArgs)
}
2020-05-31 23:11:28 +02:00
if p.peek(itemEOF, itemArgsClose) {
2020-03-14 06:35:42 +01:00
p.ignore()
break
}
p.next()
}
return args, nil
}
func (p *Parser) parseArgs(args []Arg) ([]Arg, error) {
2019-03-24 14:57:29 +01:00
var err error
for {
if len(args) >= maxArgs {
return nil, fmt.Errorf("too many args (max %d)", maxArgs)
}
2020-05-31 23:11:28 +02:00
if p.peek(itemEOF, itemArgsClose) {
2019-03-24 14:57:29 +01:00
p.ignore()
break
}
2020-03-14 06:35:42 +01:00
if !p.peek(itemName) {
2019-03-24 14:57:29 +01:00
return nil, errors.New("expecting an argument name")
}
2019-06-15 04:17:21 +02:00
args = append(args, Arg{Name: p.val(p.next())})
arg := &args[(len(args) - 1)]
2019-03-24 14:57:29 +01:00
if !p.peek(itemColon) {
2019-03-24 14:57:29 +01:00
return nil, errors.New("missing ':' after argument name")
}
p.ignore()
arg.Val, err = p.parseValue()
if err != nil {
return nil, err
}
}
return args, nil
}
func (p *Parser) parseList() (*Node, error) {
nodes := []*Node{}
parent := nodePool.Get().(*Node)
parent.Reset()
2019-03-24 14:57:29 +01:00
var ty parserType
2019-03-24 14:57:29 +01:00
for {
if p.peek(itemListClose) {
p.ignore()
break
}
node, err := p.parseValue()
if err != nil {
return nil, err
}
if ty == 0 {
ty = node.Type
} else {
if ty != node.Type {
return nil, errors.New("All values in a list must be of the same type")
}
}
node.Parent = parent
2019-03-24 14:57:29 +01:00
nodes = append(nodes, node)
}
if len(nodes) == 0 {
return nil, errors.New("List cannot be empty")
}
parent.Type = NodeList
2019-03-24 14:57:29 +01:00
parent.Children = nodes
return parent, nil
2019-03-24 14:57:29 +01:00
}
func (p *Parser) parseObj() (*Node, error) {
nodes := []*Node{}
parent := nodePool.Get().(*Node)
parent.Reset()
2019-03-24 14:57:29 +01:00
for {
2020-05-31 23:11:28 +02:00
if p.peek(itemEOF, itemObjClose) {
2019-03-24 14:57:29 +01:00
p.ignore()
break
}
if !p.peek(itemName) {
2019-03-24 14:57:29 +01:00
return nil, errors.New("expecting an argument name")
}
2019-06-15 04:17:21 +02:00
nodeName := p.val(p.next())
2019-03-24 14:57:29 +01:00
if !p.peek(itemColon) {
2019-03-24 14:57:29 +01:00
return nil, errors.New("missing ':' after Field argument name")
}
p.ignore()
node, err := p.parseValue()
if err != nil {
return nil, err
}
node.Name = nodeName
node.Parent = parent
nodes = append(nodes, node)
}
parent.Type = NodeObj
2019-03-24 14:57:29 +01:00
parent.Children = nodes
return parent, nil
2019-03-24 14:57:29 +01:00
}
func (p *Parser) parseValue() (*Node, error) {
if p.peek(itemListOpen) {
p.ignore()
return p.parseList()
2019-03-24 14:57:29 +01:00
}
if p.peek(itemObjOpen) {
p.ignore()
return p.parseObj()
2019-03-24 14:57:29 +01:00
}
item := p.next()
node := nodePool.Get().(*Node)
node.Reset()
2019-03-24 14:57:29 +01:00
2019-12-25 07:24:30 +01:00
switch item._type {
case itemIntVal:
node.Type = NodeInt
case itemFloatVal:
node.Type = NodeFloat
case itemStringVal:
node.Type = NodeStr
case itemBoolVal:
node.Type = NodeBool
case itemName:
node.Type = NodeStr
case itemVariable:
node.Type = NodeVar
default:
2019-06-15 04:17:21 +02:00
return nil, fmt.Errorf("expecting a number, string, object, list or variable as an argument value (not %s)", p.val(p.next()))
}
2019-06-15 04:17:21 +02:00
node.Val = p.val(item)
2019-03-24 14:57:29 +01:00
return node, nil
}
2019-06-15 04:17:21 +02:00
func (p *Parser) val(v item) string {
return b2s(p.input[v.pos:v.end])
}
func (p *Parser) vall(v item) string {
lowercase(p.input, v.pos, v.end)
return b2s(p.input[v.pos:v.end])
}
func (p *Parser) peek(types ...itemType) bool {
n := p.pos + 1
l := len(types)
// if p.items[n]._type == itemEOF {
// return false
// }
if n >= len(p.items) {
return types[0] == itemEOF
}
if l == 1 {
return p.items[n]._type == types[0]
}
for i := 0; i < l; i++ {
if p.items[n]._type == types[i] {
return true
}
}
return false
}
func (p *Parser) next() item {
n := p.pos + 1
if n >= len(p.items) {
p.err = errEOT
return item{_type: itemEOF}
}
p.pos = n
return p.items[p.pos]
}
func (p *Parser) ignore() {
n := p.pos + 1
if n >= len(p.items) {
p.err = errEOT
return
}
p.pos = n
}
func (p *Parser) peekNext() string {
item := p.items[p.pos+1]
return b2s(p.input[item.pos:item.end])
}
func (p *Parser) reset(to int) {
p.pos = to
}
2019-06-15 04:17:21 +02:00
func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
func (t parserType) String() string {
var v string
switch t {
case parserEOF:
v = "EOF"
case parserError:
v = "error"
case opQuery:
v = "query"
case opMutate:
v = "mutation"
case opSub:
v = "subscription"
case NodeStr:
v = "node-string"
case NodeInt:
v = "node-int"
case NodeFloat:
v = "node-float"
case NodeBool:
v = "node-bool"
case NodeVar:
v = "node-var"
case NodeObj:
v = "node-obj"
case NodeList:
v = "node-list"
}
return v
}
2020-06-09 01:28:22 +02:00
func FreeNode(n *Node) {
nodePool.Put(n)
}