Skip to content

Commit

Permalink
Initial commit, definitions of constructSubjectClause, constructPredi…
Browse files Browse the repository at this point in the history
…cateClause and constructObjectClause
  • Loading branch information
apr94 committed May 25, 2017
1 parent 5ad7a18 commit 1a3352e
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 34 deletions.
9 changes: 8 additions & 1 deletion bql/grammar/grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,11 @@ func BQL() *Grammar {
NewTokenType(lexer.ItemNode),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBlankNode),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemPredicate),
Expand Down Expand Up @@ -957,7 +962,9 @@ func SemanticBQL() *Grammar {
setClauseHook(semanticBQL, []semantic.Symbol{"CONSTRUCT_FACTS"}, semantic.InitWorkingConstructClauseHook(), nil)
constructTriplesSymbols := []semantic.Symbol{"CONSTRUCT_TRIPLES", "MORE_CONSTRUCT_TRIPLES"}
setClauseHook(semanticBQL, constructTriplesSymbols, semantic.NextWorkingConstructClauseHook(), semantic.NextWorkingConstructClauseHook())

setElementHook(semanticBQL, []semantic.Symbol{"CONSTRUCT_TRIPLES"}, semantic.ConstructSubjectClauseHook(), nil)
setElementHook(semanticBQL, []semantic.Symbol{"CONSTRUCT_PREDICATE"}, semantic.ConstructPredicateClauseHook(), nil)
setElementHook(semanticBQL, []semantic.Symbol{"CONSTRUCT_OBJECT"}, semantic.ConstructObjectClauseHook(), nil)

return semanticBQL
}
2 changes: 1 addition & 1 deletion bql/semantic/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func ToNode(ce ConsumedElement) (*node.Node, error) {
return nil, fmt.Errorf("semantic.ToNode cannot convert symbol %v to a node", ce)
}
tkn := ce.Token()
if tkn.Type != lexer.ItemNode {
if tkn.Type != lexer.ItemNode && tkn.Type != lexer.ItemBlankNode {
return nil, fmt.Errorf("semantic.ToNode cannot convert token type %s to a node", tkn.Type)
}
return node.Parse(tkn.Text)
Expand Down
161 changes: 141 additions & 20 deletions bql/semantic/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ func NextWorkingConstructClauseHook() ClauseHook {
return NextWorkingConstructClause()
}

// ConstructSubjectClauseHook returns the singleton for populating the subject in the
// working construct clause.
func ConstructSubjectClauseHook() ElementHook {
return constructSubjectClause()
}

// ConstructPredicateClauseHook returns the singleton for populating the predicate in the
// working construct clause.
func ConstructPredicateClauseHook() ElementHook {
return constructPredicateClause()
}

// ConstructObjectClauseHook returns the singleton for populating the object in the
// working construct clause.
func ConstructObjectClauseHook() ElementHook {
return constructObjectClause()
}

// TypeBindingClauseHook returns a ClauseHook that sets the binding type.
func TypeBindingClauseHook(t StatementType) ClauseHook {
var f ClauseHook
Expand Down Expand Up @@ -298,23 +316,23 @@ func whereSubjectClause() ElementHook {
}
if lastNopToken.Type == lexer.ItemAs {
if c.SAlias != "" {
return nil, fmt.Errorf("AS alias binding for subject has already being assined on %v", st)
return nil, fmt.Errorf("AS alias binding for subject has already being assigned on %v", st)
}
c.SAlias = tkn.Text
lastNopToken = nil
return f, nil
}
if lastNopToken.Type == lexer.ItemType {
if c.STypeAlias != "" {
return nil, fmt.Errorf("TYPE alias binding for subject has already being assined on %v", st)
return nil, fmt.Errorf("TYPE alias binding for subject has already being assigned on %v", st)
}
c.STypeAlias = tkn.Text
lastNopToken = nil
return f, nil
}
if c.SIDAlias == "" && lastNopToken.Type == lexer.ItemID {
if c.SIDAlias != "" {
return nil, fmt.Errorf("ID alias binding for subject has already being assined on %v", st)
return nil, fmt.Errorf("ID alias binding for subject has already being assigned on %v", st)
}
c.SIDAlias = tkn.Text
lastNopToken = nil
Expand All @@ -327,9 +345,8 @@ func whereSubjectClause() ElementHook {
return f
}

// processPredicate updates the working graph clause if there is an available
// predicate.
func processPredicate(c *GraphClause, ce ConsumedElement, lastNopToken *lexer.Token) (*predicate.Predicate, string, string, bool, error) {
// processPredicate parses a consumed element and returns a predicate and its attributes if possible.
func processPredicate(ce ConsumedElement) (*predicate.Predicate, string, string, bool, error) {
var (
nP *predicate.Predicate
pID string
Expand Down Expand Up @@ -357,9 +374,8 @@ func processPredicate(c *GraphClause, ce ConsumedElement, lastNopToken *lexer.To
return nil, pID, pAnchorBinding, temporal, nil
}

// processPredicateBound updates the working graph clause if there is an
// available predicate bound.
func processPredicateBound(c *GraphClause, ce ConsumedElement, lastNopToken *lexer.Token) (string, string, string, *time.Time, *time.Time, bool, error) {
// processPredicate parses a consumed element and returns a bound predicate and its attributes if possible.
func processPredicateBound(ce ConsumedElement) (string, string, string, *time.Time, *time.Time, bool, error) {
var (
pID string
pLowerBoundAlias string
Expand Down Expand Up @@ -428,7 +444,7 @@ func wherePredicateClause() ElementHook {
if c.P != nil {
return nil, fmt.Errorf("invalid predicate %s on graph clause since already set to %s", tkn.Text, c.P)
}
p, pID, pAnchorBinding, pTemporal, err := processPredicate(c, ce, lastNopToken)
p, pID, pAnchorBinding, pTemporal, err := processPredicate(ce)
if err != nil {
return nil, err
}
Expand All @@ -439,7 +455,7 @@ func wherePredicateClause() ElementHook {
if c.PLowerBound != nil || c.PUpperBound != nil || c.PLowerBoundAlias != "" || c.PUpperBoundAlias != "" {
return nil, fmt.Errorf("invalid predicate bound %s on graph clause since already set to %s", tkn.Text, c.P)
}
pID, pLowerBoundAlias, pUpperBoundAlias, pLowerBound, pUpperBound, pTemp, err := processPredicateBound(c, ce, lastNopToken)
pID, pLowerBoundAlias, pUpperBoundAlias, pLowerBound, pUpperBound, pTemp, err := processPredicateBound(ce)
if err != nil {
return nil, err
}
Expand All @@ -456,17 +472,17 @@ func wherePredicateClause() ElementHook {
switch lastNopToken.Type {
case lexer.ItemAs:
if c.PAlias != "" {
return nil, fmt.Errorf("AS alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("AS alias binding for predicate has already being assigned on %v", st)
}
c.PAlias = tkn.Text
case lexer.ItemID:
if c.PIDAlias != "" {
return nil, fmt.Errorf("ID alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("ID alias binding for predicate has already being assigned on %v", st)
}
c.PIDAlias = tkn.Text
case lexer.ItemAt:
if c.PAnchorAlias != "" {
return nil, fmt.Errorf("AT alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("AT alias binding for predicate has already being assigned on %v", st)
}
c.PAnchorAlias = tkn.Text
default:
Expand Down Expand Up @@ -515,7 +531,7 @@ func whereObjectClause() ElementHook {
pred *predicate.Predicate
err error
)
pred, c.OID, c.OAnchorBinding, c.OTemporal, err = processPredicate(c, ce, lastNopToken)
pred, c.OID, c.OAnchorBinding, c.OTemporal, err = processPredicate(ce)
if err != nil {
return nil, err
}
Expand All @@ -528,7 +544,7 @@ func whereObjectClause() ElementHook {
if c.OLowerBound != nil || c.OUpperBound != nil || c.OLowerBoundAlias != "" || c.OUpperBoundAlias != "" {
return nil, fmt.Errorf("invalid predicate bound %s on graph clause since already set to %s", tkn.Text, c.O)
}
oID, oLowerBoundAlias, oUpperBoundAlias, oLowerBound, oUpperBound, oTemp, err := processPredicateBound(c, ce, lastNopToken)
oID, oLowerBoundAlias, oUpperBoundAlias, oLowerBound, oUpperBound, oTemp, err := processPredicateBound(ce)
if err != nil {
return nil, err
}
Expand All @@ -548,22 +564,22 @@ func whereObjectClause() ElementHook {
switch lastNopToken.Type {
case lexer.ItemAs:
if c.OAlias != "" {
return nil, fmt.Errorf("AS alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("AS alias binding for predicate has already being assigned on %v", st)
}
c.OAlias = tkn.Text
case lexer.ItemType:
if c.OTypeAlias != "" {
return nil, fmt.Errorf("TYPE alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("TYPE alias binding for predicate has already being assigned on %v", st)
}
c.OTypeAlias = tkn.Text
case lexer.ItemID:
if c.OIDAlias != "" {
return nil, fmt.Errorf("ID alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("ID alias binding for predicate has already being assigned on %v", st)
}
c.OIDAlias = tkn.Text
case lexer.ItemAt:
if c.OAnchorAlias != "" {
return nil, fmt.Errorf("AT alias binding for predicate has already being assined on %v", st)
return nil, fmt.Errorf("AT alias binding for predicate has already being assigned on %v", st)
}
c.OAnchorAlias = tkn.Text
default:
Expand Down Expand Up @@ -895,3 +911,108 @@ func NextWorkingConstructClause() ClauseHook {
}
return f
}

// constructSubjectClause returns an element hook that updates the subject
// modifiers on the working construct clause.
func constructSubjectClause() ElementHook {
var f ElementHook
f = func(st *Statement, ce ConsumedElement) (ElementHook, error) {
if ce.IsSymbol() {
return f, nil
}
tkn := ce.Token()
c := st.workingConstructClause
if c.S != nil {
return nil, fmt.Errorf("invalid subject %v in construct clause, subject already set to %v", tkn.Type, c.S)
}
if c.SBinding != "" {
return nil, fmt.Errorf("invalid subject %v in construct clause, subject already set to %v", tkn.Type, c.SBinding)
}
switch tkn.Type {
case lexer.ItemNode, lexer.ItemBlankNode:
n, err := ToNode(ce)
if err != nil {
return nil, err
}
c.S = n
case lexer.ItemBinding:
c.SBinding = tkn.Text
}
return f, nil
}
return f
}

// constructPredicateClause returns an element hook that updates the predicate
// modifiers on the working construct clause.
func constructPredicateClause() ElementHook {
var f ElementHook
f = func(st *Statement, ce ConsumedElement) (ElementHook, error) {
if ce.IsSymbol() {
return f, nil
}
tkn := ce.Token()
c := st.workingConstructClause
if c.P != nil {
return nil, fmt.Errorf("invalid predicate %v in construct clause, predicate already set to %v", tkn.Type, c.P)
}
if c.PBinding != "" {
return nil, fmt.Errorf("invalid predicate %v in construct clause, predicate already set to %v", tkn.Type, c.PBinding)
}
switch tkn.Type {
case lexer.ItemPredicate:
p, pID, pAnchorBinding, pTemporal, err := processPredicate(ce)
if err != nil {
return nil, err
}
c.P, c.PID, c.PAnchorBinding, c.PTemporal = p, pID, pAnchorBinding, pTemporal
case lexer.ItemBinding:
c.PBinding = tkn.Text
}
return f, nil
}
return f
}

// constructObjectClause returns an element hook that updates the object
// modifiers on the working graph clause.
func constructObjectClause() ElementHook {
var f ElementHook
f = func(st *Statement, ce ConsumedElement) (ElementHook, error) {
if ce.IsSymbol() {
return f, nil
}
tkn := ce.Token()
c := st.WorkingClause()
if c.O != nil {
return nil, fmt.Errorf("invalid object %v in construct clause, object already set to %v", tkn.Text, c.O)
}
if c.OBinding != "" {
return nil, fmt.Errorf("invalid object %v in construct clause, object already set to %v", tkn.Type, c.OBinding)
}
switch tkn.Type {
case lexer.ItemNode, lexer.ItemBlankNode, lexer.ItemLiteral:
obj, err := triple.ParseObject(tkn.Text, literal.DefaultBuilder())
if err != nil {
return nil, err
}
c.O = obj
case lexer.ItemPredicate:
var (
pred *predicate.Predicate
err error
)
pred, c.OID, c.OAnchorBinding, c.OTemporal, err = processPredicate(ce)
if err != nil {
return nil, err
}
if pred != nil {
c.O = triple.NewPredicateObject(pred)
}
case lexer.ItemBinding:
c.OBinding = tkn.Text
}
return f, nil
}
return f
}
18 changes: 13 additions & 5 deletions bql/semantic/semantic.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,15 @@ type ConstructClause struct {

P *predicate.Predicate
PBinding string
PID string
PAnchorBinding string
PTemporal bool

O *triple.Object
OBinding string
O *triple.Object
OBinding string
OID string
OAnchorBinding string
OTemporal bool

ReificationClauses []*ReificationClause
}
Expand All @@ -148,11 +152,15 @@ type ConstructClause struct {
type ReificationClause struct {
P *predicate.Predicate
PBinding string
PID string
PAnchorBinding string
PTemporal bool

O *triple.Object
OBinding string
O *triple.Object
OBinding string
OID string
OAnchorBinding string
OTemporal bool
}

// String returns a readable representation of a graph clause.
Expand Down Expand Up @@ -385,7 +393,7 @@ func (s *Statement) Type() StatementType {
return s.sType
}

// AddGraph adds a graph to a given https://critique.corp.google.com/#review/101398527statement.
// AddGraph adds a graph to a given statement.
func (s *Statement) AddGraph(g string) {
s.graphNames = append(s.graphNames, g)
}
Expand Down
12 changes: 6 additions & 6 deletions triple/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,29 +86,29 @@ func Parse(s string) (*Node, error) {
case slash:
idx := strings.Index(raw, "<")
if idx < 0 {
return nil, fmt.Errorf("node.Parser: invalid format, could not find ID in %v", raw)
return nil, fmt.Errorf("node.Parse: invalid format, could not find ID in %v", raw)
}
t, err := NewType(raw[:idx])
if err != nil {
return nil, fmt.Errorf("node.Parser: invalid type %q, %v", raw[:idx], err)
return nil, fmt.Errorf("node.Parse: invalid type %q, %v", raw[:idx], err)
}
if raw[len(raw)-1] != '>' {
return nil, fmt.Errorf("node.Parser: pretty printing should finish with '>' in %q", raw)
return nil, fmt.Errorf("node.Parse: pretty printing should finish with '>' in %q", raw)
}
id, err := NewID(raw[idx+1 : len(raw)-1])
if err != nil {
return nil, fmt.Errorf("node.Parser: invalid ID in %q, %v", raw, err)
return nil, fmt.Errorf("node.Parse: invalid ID in %q, %v", raw, err)
}
return NewNode(t, id), nil
case underscore:
id, err := NewID(raw[2:len(raw)])
if err != nil {
return nil, fmt.Errorf("node.Parser: invalid ID in %q, %v", raw, err)
return nil, fmt.Errorf("node.Parse: invalid ID in %q, %v", raw, err)
}
t, _ := NewType("/_")
return NewNode(t, id), nil
default:
return nil, fmt.Errorf("node.Parser: node representation should start with '/' or '_' in %v", raw)
return nil, fmt.Errorf("node.Parse: node representation should start with '/' or '_' in %v", raw)
}
}

Expand Down
1 change: 0 additions & 1 deletion triple/triple.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ func ParseObject(s string, b literal.Builder) (*Object, error) {
}
o, err := predicate.Parse(s)
if err == nil {

return NewPredicateObject(o), nil
}
return nil, err
Expand Down

0 comments on commit 1a3352e

Please sign in to comment.