drivers/golang/age/builder.go (222 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package age
import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/apache/age/drivers/golang/parser"
)
const MaxUint = ^uint(0)
const MaxInt = int(MaxUint >> 1)
const MinUint = 0
const MinInt = -MaxInt - 1
type Unmarshaller interface {
unmarshal(text string) (Entity, error)
}
type AGUnmarshaler struct {
Unmarshaller
ageParser *parser.AgeParser
visitor parser.AgeVisitor
errListener *AGErrorListener
vcache map[int64]interface{}
}
func NewAGUnmarshaler() *AGUnmarshaler {
vcache := make(map[int64]interface{})
m := &AGUnmarshaler{ageParser: parser.NewAgeParser(nil),
visitor: &UnmarshalVisitor{vcache: vcache},
errListener: NewAGErrorListener(),
vcache: vcache,
}
m.ageParser.AddErrorListener(m.errListener)
return m
}
func (p *AGUnmarshaler) unmarshal(text string) (Entity, error) {
if len(text) == 0 {
return NewSimpleEntity(nil), nil
}
input := antlr.NewInputStream(text)
lexer := parser.NewAgeLexer(input)
stream := antlr.NewCommonTokenStream(lexer, 0)
p.ageParser.SetInputStream(stream)
tree := p.ageParser.Ageout()
rst := tree.Accept(p.visitor)
if len(p.errListener.errList) > 0 {
var ape *AgeParseError = nil
errs := make([]string, len(p.errListener.errList))
for idx, re := range p.errListener.errList {
errs[idx] = re.GetMessage()
fmt.Println(re)
}
p.errListener.clearErrs()
ape = &AgeParseError{msg: "Cypher query:" + text, errors: errs}
return nil, ape
}
if !IsEntity(rst) {
rst = NewSimpleEntity(rst)
}
return rst.(Entity), nil
}
type AGErrorListener struct {
*antlr.DefaultErrorListener
errList []antlr.RecognitionException
}
func NewAGErrorListener() *AGErrorListener {
return &AGErrorListener{DefaultErrorListener: &antlr.DefaultErrorListener{}, errList: []antlr.RecognitionException{}}
}
func (el *AGErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
el.errList = append(el.errList, e)
}
func (el *AGErrorListener) getErrs() []antlr.RecognitionException {
return el.errList
}
func (el *AGErrorListener) clearErrs() {
el.errList = []antlr.RecognitionException{}
}
type UnmarshalVisitor struct {
parser.AgeVisitor
vcache map[int64]interface{}
}
func (v *UnmarshalVisitor) Visit(tree antlr.ParseTree) interface{} { return nil }
func (v *UnmarshalVisitor) VisitChildren(node antlr.RuleNode) interface{} {
var rtn interface{}
for _, c := range node.GetChildren() {
pt := c.(antlr.ParseTree)
rtn = pt.Accept(v)
}
return rtn
}
func (v *UnmarshalVisitor) VisitTerminal(node antlr.TerminalNode) interface{} { return nil }
func (v *UnmarshalVisitor) VisitErrorNode(node antlr.ErrorNode) interface{} { return nil }
func (v *UnmarshalVisitor) VisitAgeout(ctx *parser.AgeoutContext) interface{} {
rtn := v.VisitChildren(ctx)
return rtn
}
// Visit a parse tree produced by AgeParser#vertex.
func (v *UnmarshalVisitor) VisitVertex(ctx *parser.VertexContext) interface{} {
propCtx := ctx.Properties()
props := propCtx.Accept(v).(map[string]interface{})
// fmt.Println(" * VisitVertex:", props)
vid := int64(props["id"].(int64))
vertex, ok := v.vcache[vid]
if !ok {
vertex = NewVertex(vid, props["label"].(string), props["properties"].(map[string]interface{}))
v.vcache[vid] = vertex
}
return vertex
}
// Visit a parse tree produced by AgeParser#edge.
func (v *UnmarshalVisitor) VisitEdge(ctx *parser.EdgeContext) interface{} {
propCtx := ctx.Properties()
props := propCtx.Accept(v).(map[string]interface{})
// fmt.Println(" * VisitEdge:", props)
edge := NewEdge(int64(props["id"].(int64)), props["label"].(string),
int64(props["start_id"].(int64)), int64(props["end_id"].(int64)),
props["properties"].(map[string]interface{}))
return edge
}
// Visit a parse tree produced by AgeParser#path.
func (v *UnmarshalVisitor) VisitPath(ctx *parser.PathContext) interface{} {
entities := []Entity{}
for _, child := range ctx.GetChildren() {
switch child.(type) {
case *parser.VertexContext:
v := child.(*parser.VertexContext).Accept(v)
// fmt.Println(v)
entities = append(entities, v.(Entity))
case *parser.EdgeContext:
e := child.(*parser.EdgeContext).Accept(v)
// fmt.Println(e)
entities = append(entities, e.(Entity))
default:
}
}
path := NewPath(entities)
return path
}
// Visit a parse tree produced by AgeParser#value.
func (v *UnmarshalVisitor) VisitValue(ctx *parser.ValueContext) interface{} {
child := ctx.GetChild(0)
switch child.(type) {
case *antlr.TerminalNodeImpl:
rtn, err := unmarshalTerm(child.(*antlr.TerminalNodeImpl))
if err != nil {
panic(err)
}
return rtn
default:
return child.(antlr.ParserRuleContext).Accept(v)
}
}
// Visit a parse tree produced by AgeParser#properties.
func (v *UnmarshalVisitor) VisitProperties(ctx *parser.PropertiesContext) interface{} {
props := make(map[string]interface{})
for _, pairCtx := range ctx.AllPair() {
pairCtx.Accept(v)
pair := pairCtx.(*parser.PairContext)
key := strings.Trim(pair.STRING().GetText(), "\"")
// fmt.Println("Pair KEY:", key)
value := pair.Value().Accept(v)
props[key] = value
}
return props
}
// Visit a parse tree produced by AgeParser#pair.
func (v *UnmarshalVisitor) VisitPair(ctx *parser.PairContext) interface{} {
return nil
}
// Visit a parse tree produced by AgeParser#arr.
func (v *UnmarshalVisitor) VisitArr(ctx *parser.ArrContext) interface{} {
var arr []interface{}
for _, child := range ctx.GetChildren() {
switch child.(type) {
case *antlr.TerminalNodeImpl:
// skip
break
default:
el := child.(antlr.ParserRuleContext).Accept(v)
arr = append(arr, el)
}
}
return arr
}
func unmarshalTerm(ctx *antlr.TerminalNodeImpl) (interface{}, error) {
txt := ctx.GetText()
switch ctx.GetSymbol().GetTokenType() {
case parser.AgeLexerSTRING:
return strings.Trim(txt, "\""), nil
case parser.AgeLexerNUMERIC:
numStr := txt[:len(txt)-9]
// fmt.Println("txt ", txt)
// fmt.Println("numStr", numStr)
if strings.Contains(numStr, ".") {
bi := new(big.Float)
bi, ok := bi.SetString(numStr)
if !ok {
return nil, &AgeParseError{msg: "Parse big float " + txt}
}
return bi, nil
} else {
bi := new(big.Int)
bi, ok := bi.SetString(numStr, 10)
if !ok {
return nil, &AgeParseError{msg: "Parse big int " + txt}
}
return bi, nil
}
case parser.AgeLexerNUMBER:
if strings.Contains(txt, ".") {
return strconv.ParseFloat(txt, 64)
} else {
return strconv.ParseInt(txt, 10, 64)
}
case parser.AgeLexerFLOAT_EXPR:
switch txt {
case "NaN":
return math.NaN(), nil
case "-Infinity":
return math.Inf(-1), nil
case "Infinity":
return math.Inf(1), nil
default:
return nil, &AgeParseError{msg: "Unknown float expression" + txt}
}
case parser.AgeLexerBOOL:
s, err := strconv.ParseBool(txt)
if err != nil {
return nil, err
} else {
return s, nil
}
case parser.AgeLexerNULL:
return nil, nil
default:
return nil, nil
}
}