Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 47 additions & 2 deletions bql/grammar/grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,13 +827,52 @@ func BQL() *Grammar {
{
Elements: []Element{
NewTokenType(lexer.ItemSemicolon),
NewSymbol("CONSTRUCT_PREDICATE"),
NewSymbol("CONSTRUCT_OBJECT"),
NewSymbol("REIFICATION_PREDICATE"),
NewSymbol("REIFICATION_OBJECT"),
NewSymbol("REIFICATION_CLAUSE"),
},
},
{},
},
"REIFICATION_PREDICATE": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemPredicate),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
},
},
},
"REIFICATION_OBJECT": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemNode),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBlankNode),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemPredicate),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemLiteral),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
},
},
},
"MORE_CONSTRUCT_TRIPLES": []*Clause{
{
Elements: []Element{
Expand Down Expand Up @@ -960,11 +999,17 @@ func SemanticBQL() *Grammar {
// CONSTRUCT clause semantic hooks.
setClauseHook(semanticBQL, []semantic.Symbol{"CONSTRUCT"}, nil, semantic.TypeBindingClauseHook(semantic.Construct))
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)

setClauseHook(semanticBQL, []semantic.Symbol{"REIFICATION_CLAUSE"}, semantic.NextWorkingReificationClauseHook(), semantic.NextWorkingReificationClauseHook())
setElementHook(semanticBQL, []semantic.Symbol{"REIFICATION_PREDICATE"}, semantic.ReificationPredicateClauseHook(), nil)
setElementHook(semanticBQL, []semantic.Symbol{"REIFICATION_OBJECT"}, semantic.ReificationObjectClauseHook(), nil)

return semanticBQL
}
144 changes: 130 additions & 14 deletions bql/grammar/grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ func TestAcceptByParse(t *testing.T) {
}
p, err := NewParser(BQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, input := range table {
if err := p.Parse(NewLLk(input, 1), &semantic.Statement{}); err != nil {
t.Errorf("Parser.consume: failed to accept input %q with error %v", input, err)
t.Errorf("Parser.consume: Failed to accept input %q with error %v", input, err)
}
}
}
Expand Down Expand Up @@ -246,11 +246,11 @@ func TestRejectByParse(t *testing.T) {
}
p, err := NewParser(BQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, input := range table {
if err := p.Parse(NewLLk(input, 1), &semantic.Statement{}); err == nil {
t.Errorf("Parser.consume: failed to reject input %q with parsing error", input)
t.Errorf("Parser.consume: Failed to reject input %q with parsing error", input)
}
}
}
Expand Down Expand Up @@ -288,18 +288,18 @@ func TestAcceptOpsByParseAndSemantic(t *testing.T) {
}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, entry := range table {
st := &semantic.Statement{}
if err := p.Parse(NewLLk(entry.query, 1), st); err != nil {
t.Errorf("Parser.consume: failed to accept entry %q with error %v", entry, err)
t.Errorf("Parser.consume: Failed to accept entry %q with error %v", entry, err)
}
if got, want := len(st.GraphNames()), entry.graphs; got != want {
t.Errorf("Parser.consume: failed to collect right number of graphs for case %v; got %d, want %d", entry, got, want)
t.Errorf("Parser.consume: Failed to collect right number of graphs for case %v; got %d, want %d", entry, got, want)
}
if got, want := len(st.Data()), entry.triples; got != want {
t.Errorf("Parser.consume: failed to collect right number of triples for case %v; got %d, want %d", entry, got, want)
t.Errorf("Parser.consume: Failed to collect right number of triples for case %v; got %d, want %d", entry, got, want)
}
}
}
Expand Down Expand Up @@ -339,11 +339,11 @@ func TestAcceptQueryBySemanticParse(t *testing.T) {
}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, input := range table {
if err := p.Parse(NewLLk(input, 1), &semantic.Statement{}); err != nil {
t.Errorf("Parser.consume: failed to accept input %q with error %v", input, err)
t.Errorf("Parser.consume: Failed to accept input %q with error %v", input, err)
}
}
}
Expand All @@ -370,12 +370,12 @@ func TestRejectByParseAndSemantic(t *testing.T) {
}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, entry := range table {
st := &semantic.Statement{}
if err := p.Parse(NewLLk(entry, 1), st); err == nil {
t.Errorf("Parser.consume: failed to reject invalid semantic entry %q", entry)
t.Errorf("Parser.consume: Failed to reject invalid semantic entry %q", entry)
}
}
}
Expand All @@ -400,15 +400,131 @@ func TestSemanticStatementGraphClausesLengthCorrectness(t *testing.T) {
}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: should have produced a valid BQL parser, %v", err)
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, entry := range table {
st := &semantic.Statement{}
if err := p.Parse(NewLLk(entry.query, 1), st); err != nil {
t.Errorf("Parser.consume: failed to accept valid semantic entry %q", entry.query)
t.Errorf("Parser.consume: Failed to accept valid semantic entry %q", entry.query)
}
if got, want := len(st.GraphPatternClauses()), entry.want; got != want {
t.Errorf("Invalid number of graph pattern clauses for query %q; got %d, want %d; %v", entry.query, got, want, st.GraphPatternClauses())
}
}
}

func TestSemanticStatementConstructClausesLengthCorrectness(t *testing.T) {
table := []struct {
query string
want int
}{
{
query: `construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
want: 1,
},
{
query: `construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2.
?s "predicate_3"@[] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
want: 2,
},
}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, entry := range table {
st := &semantic.Statement{}
if err := p.Parse(NewLLk(entry.query, 1), st); err != nil {
t.Errorf("Parser.consume: Failed to accept valid semantic entry %q", entry.query)
}
if got, want := len(st.ConstructClauses()), entry.want; got != want {
t.Errorf("Invalid number of construct clauses for query %q; got %d, want %d; %v", entry.query, got, want, st.ConstructClauses())
}
}
}

func TestSemanticStatementReificationClausesLengthCorrectness(t *testing.T) {
table := []struct {
query string
want_one int
want_two int
}{
{
query: `construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2.
?s "predicate_3"@[] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
want_one: 1,
want_two: 0,
},
{
query: `construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2;
"predicate_3"@[] ?o3.
?s1 "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2;
"predicate_3"@[] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s1 "old_predicate_3"@[,] ?o3};`,
want_one: 2,
want_two: 2,
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please repeat the tests using temporal predicates.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
query: `construct {?s "predicate_1"@[2015-07-19T13:12:04.669618843-07:00] ?o1;
"predicate_2"@[2015-07-19T13:12:04.669618843-07:00] ?o2.
?s "predicate_3"@[2015-07-19T13:12:04.669618843-07:00] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
want_one: 1,
want_two: 0,
},
{
query: `construct {?s "predicate_1"@[2015-07-19T13:12:04.669618843-07:00] ?o1;
"predicate_2"@[2015-07-19T13:12:04.669618843-07:00] ?o2;
"predicate_3"@[2015-07-19T13:12:04.669618843-07:00] ?o3.
?s1 "predicate_1"@[2015-07-19T13:12:04.669618843-07:00] ?o1;
"predicate_2"@[2015-07-19T13:12:04.669618843-07:00] ?o2;
"predicate_3"@[2015-07-19T13:12:04.669618843-07:00] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s1 "old_predicate_3"@[,] ?o3};`,
want_one: 2,
want_two: 2,
},
{
query: `construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2;
"predicate_3"@[?t] ?o3.
?s1 "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2;
"predicate_3"@[?t] ?o3} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s1 "old_predicate_3"@[,] AT ?t ?o3};`,
want_one: 2,
want_two: 2,
},

}
p, err := NewParser(SemanticBQL())
if err != nil {
t.Errorf("grammar.NewParser: Should have produced a valid BQL parser, %v", err)
}
for _, entry := range table {
st := &semantic.Statement{}
if err := p.Parse(NewLLk(entry.query, 1), st); err != nil {
t.Errorf("Parser.consume: Failed to accept valid semantic entry %q", entry.query)
}
if got, want := len(st.ConstructClauses()[0].ReificationClauses()), entry.want_one; got != want {
t.Errorf("Invalid number of reification clauses for query %q; got %d, want %d; %v", entry.query, got, want, st.ConstructClauses()[0].ReificationClauses())
}
if got, want := len(st.ConstructClauses()[1].ReificationClauses()), entry.want_two; got != want {
t.Errorf("Invalid number of reification clauses for query %q; got %d, want %d; %v", entry.query, got, want, st.ConstructClauses()[0].ReificationClauses())
}
}
}
Loading