Skip to content

Commit

Permalink
Rewrite CONSTRUCT query
Browse files Browse the repository at this point in the history
  • Loading branch information
apr94 committed Apr 10, 2017
1 parent 435a932 commit 728c937
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 13 deletions.
97 changes: 88 additions & 9 deletions bql/grammar/grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,15 +204,6 @@ func BQL() *Grammar {
},
},
},
"CONSTRUCT_FACTS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemLBracket),
NewSymbol("CLAUSES"),
NewTokenType(lexer.ItemRBracket),
},
},
},
"CLAUSES": []*Clause{
{
Elements: []Element{
Expand Down Expand Up @@ -755,6 +746,94 @@ func BQL() *Grammar {
},
{},
},
"CONSTRUCT_FACTS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemLBracket),
NewSymbol("CONSTRUCT_TRIPLES"),
NewTokenType(lexer.ItemRBracket),
},
},
},
"CONSTRUCT_TRIPLES": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemNode),
NewSymbol("CONSTRUCT_PREDICATE"),
NewSymbol("CONSTRUCT_OBJECT"),
NewSymbol("MORE_CONSTRUCT_TRIPLES"),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBlankNode),
NewSymbol("CONSTRUCT_PREDICATE"),
NewSymbol("CONSTRUCT_OBJECT"),
NewSymbol("MORE_CONSTRUCT_TRIPLES"),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
NewSymbol("CONSTRUCT_PREDICATE"),
NewSymbol("CONSTRUCT_OBJECT"),
NewSymbol("MORE_CONSTRUCT_TRIPLES"),
},
},
},
"CONSTRUCT_PREDICATE": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemPredicate),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemPredicateBound),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
},
},
},
"CONSTRUCT_OBJECT": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemNode),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemPredicate),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemPredicateBound),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemLiteral),
},
},
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
},
},
},
"MORE_CONSTRUCT_TRIPLES": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemDot),
NewSymbol("CONSTRUCT_TRIPLES"),
},
},
{},
},
}
}

Expand Down
13 changes: 13 additions & 0 deletions bql/grammar/grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ func TestAcceptByParse(t *testing.T) {
// Test Construct clause.
`construct {?s "foo"@[,] ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`,
`construct {?s "foo"@[,] ?o} into ?a from ?b where {?s "foo"@[,] ?o};`,
`construct {?s ?p ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`,
`construct {?s ?p ?o.
_:v "_subject"@[] ?s.
_:v "_predicate"@[] ?p.
_:v "_object"@[] ?o.
_:v "some_pred"@[] ?k } into ?a from ?b where {?s "foo"@[,] ?o};`,

}
p, err := NewParser(BQL())
Expand Down Expand Up @@ -215,6 +221,13 @@ func TestRejectByParse(t *testing.T) {
`construct {?s "foo"@[,] ?o} into ?a where{?s "foo"@[,] ?o} having ?s = ?o;`,
// Construct clause without destination.
`construct {?s "foo"@[,] ?o} from ?b where{?s "foo"@[,] ?o} having ?s = ?o;`,
// Construct clause with badly formed blank node.
`construct {?s ?p ?o.
_v "some_pred"@[] ?k } into ?a from ?b where {?s "foo"@[,] ?o};`,
// Construct clause with badle formed triple.
`construct {?s ?p ?o.
_:v "some_pred"@[]} into ?a from ?b where {?s "foo"@[,] ?o};`,

}
p, err := NewParser(BQL())
if err != nil {
Expand Down
28 changes: 24 additions & 4 deletions bql/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ const (
ItemError TokenType = iota
// ItemEOF indicates end of input to be scanned in BQL.
ItemEOF

// ItemQuery represents the select keyword in BQL.
ItemQuery
// ItemInsert represents insert keyword in BQL.
Expand Down Expand Up @@ -90,19 +89,18 @@ const (
ItemDesc
// ItemLimit represents the limit clause in BQL.
ItemLimit

// ItemBinding represents a variable binding in BQL.
ItemBinding

// ItemNode represents a BadWolf node in BQL.
ItemNode
// ItemBlankNode represents a blank BadWolf node in BQL.
ItemBlankNode
// ItemLiteral represents a BadWolf literal in BQL.
ItemLiteral
// ItemPredicate represents a BadWolf predicates in BQL.
ItemPredicate
// ItemPredicateBound represents a BadWolf predicate bound in BQL.
ItemPredicateBound

// ItemLBracket represents the left opening bracket token in BQL.
ItemLBracket
// ItemRBracket represents the right opening bracket token in BQL.
Expand Down Expand Up @@ -189,6 +187,8 @@ func (tt TokenType) String() string {
return "BINDING"
case ItemNode:
return "NODE"
case ItemBlankNode:
return "BLANK_NODE"
case ItemLiteral:
return "LITERAL"
case ItemPredicate:
Expand Down Expand Up @@ -248,6 +248,7 @@ const (
semicolon = rune(';')
comma = rune(',')
slash = rune('/')
underscore = rune('_')
backSlash = rune('\\')
lt = rune('<')
gt = rune('>')
Expand Down Expand Up @@ -356,6 +357,9 @@ func lexToken(l *lexer) stateFn {
return lexBinding
case slash:
return lexNode
case underscore:
l.next()
return lexBlankNode
case quote:
return lexPredicateOrLiteral
}
Expand Down Expand Up @@ -612,6 +616,22 @@ func lexNode(l *lexer) stateFn {
return lexSpace
}

// lexBlankNode tries to lex a blank node out of the input
func lexBlankNode(l *lexer) stateFn {
if r := l.next(); r != colon {
l.emitError("blank node should start with _:")
return nil
}
for {
if r := l.next(); !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != rune('_') || r == eof {
l.backup()
l.emit(ItemBlankNode)
break
}
}
return lexSpace
}

// lexPredicateOrLiteral tries to lex a predicate or a literal out of the input.
func lexPredicateOrLiteral(l *lexer) stateFn {
text := l.input[l.pos:]
Expand Down
16 changes: 16 additions & 0 deletions bql/lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ func TestIndividualTokens(t *testing.T) {
{Type: ItemError, Text: "/_<foo",
ErrorMessage: "[lexer:0:6] node is not properly terminated; missing final > delimiter"},
{Type: ItemEOF}}},
{"_:v1 _:foo_bar",
[]Token{
{Type: ItemBlankNode, Text: "_:v1"},
{Type: ItemBlankNode, Text: "_:foo_bar"},
{Type: ItemEOF}}},
{"_v1",
[]Token{
{Type: ItemError, Text: "_v",
ErrorMessage: "[lexer:0:2] blank node should start with _:"},
{Type: ItemEOF}}},
{`"true"^^type:bool "1"^^type:int64"2"^^type:float64"t"^^type:text`,
[]Token{
{Type: ItemLiteral, Text: `"true"^^type:bool`},
Expand Down Expand Up @@ -214,6 +224,12 @@ func TestValidTokenQuery(t *testing.T) {
ItemRBracket, ItemInto, ItemBinding, ItemFrom, ItemBinding, ItemWhere,
ItemLBracket, ItemBinding, ItemPredicateBound, ItemBinding, ItemRBracket,
ItemSemicolon, ItemEOF}},
{`construct {_:v1 "predicate"@[] ?p.
_:v1 "object"@[,] ?o} into ?a from ?b where {?s "foo"@[,] ?o};`, []TokenType{
ItemConstruct, ItemLBracket, ItemBlankNode, ItemPredicate, ItemBinding, ItemDot,
ItemBlankNode, ItemPredicateBound, ItemBinding, ItemRBracket, ItemInto, ItemBinding,
ItemFrom, ItemBinding, ItemWhere, ItemLBracket, ItemBinding, ItemPredicateBound,
ItemBinding, ItemRBracket, ItemSemicolon, ItemEOF}},
}
for _, test := range table {
_, c := lex(test.input, 0)
Expand Down

0 comments on commit 728c937

Please sign in to comment.