diff --git a/rdf/parse.go b/rdf/parse.go index de9661e7d994a8ea874820a09a3a1c9cf3e5d619..b9412d36bf82b514a2af917d1366338f3ef7e953 100644 --- a/rdf/parse.go +++ b/rdf/parse.go @@ -45,6 +45,7 @@ func Parse(line string) (rnq NQuad, rerr error) { l := lex.NewLexer(line) go run(l) var oval string + var vend bool for item := range l.Items { if item.Typ == itemSubject { rnq.Subject = stripBracketsIfPresent(item.Val) @@ -62,12 +63,22 @@ func Parse(line string) (rnq NQuad, rerr error) { rnq.Language = item.Val } if item.Typ == itemObjectType { + // TODO: Strictly parse common types like integers, floats etc. if len(oval) == 0 { glog.Fatalf( "itemObject should be emitted before itemObjectType. Input: %q", line) } oval += "@@" + stripBracketsIfPresent(item.Val) } + if item.Typ == lex.ItemError { + return rnq, fmt.Errorf(item.Val) + } + if item.Typ == itemValidEnd { + vend = true + } + } + if !vend { + return rnq, fmt.Errorf("Invalid end of input") } if len(oval) > 0 { rnq.ObjectValue = oval diff --git a/rdf/parse_test.go b/rdf/parse_test.go index 2d26986c81cff2f3d8da5249591970c4c24f6071..fa14448ec573c27a1d122642c553266d381879c8 100644 --- a/rdf/parse_test.go +++ b/rdf/parse_test.go @@ -100,6 +100,56 @@ var testNQuads = []struct { ObjectValue: nil, }, }, + { + input: "_:alice .", + hasErr: true, + }, + { + input: "_:alice knows .", + hasErr: true, + }, + { + input: `_:alice "knows" stuff .`, + hasErr: true, + }, + { + input: "_:alice <knows> stuff .", + hasErr: true, + }, + { + input: "_:alice <knows> <stuff>", + hasErr: true, + }, + { + input: `"_:alice" <knows> <stuff> .`, + hasErr: true, + }, + { + input: `_:alice <knows> "stuff .`, + hasErr: true, + }, + { + input: `_:alice <knows> "stuff"@-en .`, + hasErr: true, + }, + { + input: `_:alice <knows> "stuff"^<string> .`, + hasErr: true, + }, + { + input: `_:alice <knows> "stuff"^^xs:string .`, + hasErr: true, + }, + { + input: `_:alice <knows> "stuff"^^<xs:string> .`, + nq: NQuad{ + Subject: "_:alice", + Predicate: "knows", + ObjectId: "", + ObjectValue: "stuff@@xs:string", + }, + hasErr: false, + }, } func TestLex(t *testing.T) { @@ -107,9 +157,15 @@ func TestLex(t *testing.T) { rnq, err := Parse(test.input) if test.hasErr { if err == nil { - t.Errorf("Expected error for input: %q", test.input) + t.Errorf("Expected error for input: %q. Output: %+v", test.input, rnq) + } + continue + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) } } + if !reflect.DeepEqual(rnq, test.nq) { t.Errorf("Expected %v. Got: %v", test.nq, rnq) } diff --git a/rdf/state.go b/rdf/state.go index ca8af39329eaabc1fcfbcd519ac85252a7abffb2..bc4d89255207d4c928df133959d3ad105d1e03ed 100644 --- a/rdf/state.go +++ b/rdf/state.go @@ -32,6 +32,7 @@ const ( itemLiteral // literal, 10 itemLanguage // language, 11 itemObjectType // object type, 12 + itemValidEnd // end with dot, 13 ) const ( @@ -82,7 +83,13 @@ Loop: l.Emit(itemText) return lexObject - case r == '.' || r == lex.EOF: + case r == lex.EOF: + break Loop + + case r == '.': + if l.Depth > AT_OBJECT { + l.Emit(itemValidEnd) + } break Loop } }