diff --git a/cayley.go b/cayley.go index 2e7522c..8e16be1 100644 --- a/cayley.go +++ b/cayley.go @@ -29,6 +29,7 @@ import ( "os" "path/filepath" "runtime" + "time" "github.com/barakmich/glog" @@ -51,11 +52,19 @@ import ( ) var ( - tripleFile = flag.String("triples", "", "Triple File to load before going to REPL.") - tripleType = flag.String("format", "cquad", `Triple format to use for loading ("cquad" or "nquad").`) - cpuprofile = flag.String("prof", "", "Output profiling file.") - queryLanguage = flag.String("query_lang", "gremlin", "Use this parser as the query language.") - configFile = flag.String("config", "", "Path to an explicit configuration file.") + tripleFile = flag.String("triples", "", "Triple File to load before going to REPL.") + tripleType = flag.String("format", "cquad", `Triple format to use for loading ("cquad" or "nquad").`) + cpuprofile = flag.String("prof", "", "Output profiling file.") + queryLanguage = flag.String("query_lang", "gremlin", "Use this parser as the query language.") + configFile = flag.String("config", "", "Path to an explicit configuration file.") + databasePath = flag.String("dbpath", "/tmp/testdb", "Path to the database.") + databaseBackend = flag.String("db", "memstore", "Database Backend.") + replicationBackend = flag.String("replication", "single", "Replication method.") + host = flag.String("host", "127.0.0.1", "Host to listen on (defaults to all).") + loadSize = flag.Int("load_size", 10000, "Size of triplesets to load") + port = flag.String("port", "64210", "Port to listen on.") + readOnly = flag.Bool("read_only", false, "Disable writing via HTTP.") + timeout = flag.Duration("timeout", 30*time.Second, "Elapsed time until an individual query times out.") ) // Filled in by `go build ldflags="-X main.VERSION `ver`"`. @@ -64,33 +73,88 @@ var ( VERSION string ) -func Usage() { - fmt.Println("Cayley is a graph store and graph query layer.") - fmt.Println("\nUsage:") - fmt.Println(" cayley COMMAND [flags]") - fmt.Println("\nCommands:") - fmt.Println(" init Create an empty database.") - fmt.Println(" load Bulk-load a triple file into the database.") - fmt.Println(" http Serve an HTTP endpoint on the given host and port.") - fmt.Println(" repl Drop into a REPL of the given query language.") - fmt.Println(" version Version information.") - fmt.Println("\nFlags:") - flag.Parse() +func usage() { + fmt.Fprintln(os.Stderr, ` +Usage: + cayley COMMAND [flags] + +Commands: + init Create an empty database. + load Bulk-load a triple file into the database. + http Serve an HTTP endpoint on the given host and port. + repl Drop into a REPL of the given query language. + version Version information. + +Flags:`) flag.PrintDefaults() } +func init() { + flag.Usage = usage +} + +func configFrom(file string) *config.Config { + // Find the file... + if file != "" { + if _, err := os.Stat(file); os.IsNotExist(err) { + glog.Fatalln("Cannot find specified configuration file", file, ", aborting.") + } + } else if _, err := os.Stat(os.Getenv("CAYLEY_CFG")); err == nil { + file = os.Getenv("CAYLEY_CFG") + } else if _, err := os.Stat("/etc/cayley.cfg"); err == nil { + file = "/etc/cayley.cfg" + } + if file == "" { + glog.Infoln("Couldn't find a config file in either $CAYLEY_CFG or /etc/cayley.cfg. Going by flag defaults only.") + } + cfg, err := config.Load(file) + if err != nil { + glog.Fatalln(err) + } + + if cfg.DatabasePath == "" { + cfg.DatabasePath = *databasePath + } + + if cfg.DatabaseType == "" { + cfg.DatabaseType = *databaseBackend + } + + if cfg.ReplicationType == "" { + cfg.ReplicationType = *replicationBackend + } + + if cfg.ListenHost == "" { + cfg.ListenHost = *host + } + + if cfg.ListenPort == "" { + cfg.ListenPort = *port + } + + if cfg.Timeout == 0 { + cfg.Timeout = *timeout + } + + if cfg.LoadSize == 0 { + cfg.LoadSize = *loadSize + } + + cfg.ReadOnly = cfg.ReadOnly || *readOnly + + return cfg +} + func main() { // No command? It's time for usage. if len(os.Args) == 1 { - Usage() + fmt.Fprintln(os.Stderr, "Cayley is a graph store and graph query layer.") + usage() os.Exit(1) } cmd := os.Args[1] - var newargs []string - newargs = append(newargs, os.Args[0]) - newargs = append(newargs, os.Args[2:]...) - os.Args = newargs + os.Args = append(os.Args[:1], os.Args[2:]...) flag.Parse() var buildString string @@ -99,7 +163,7 @@ func main() { glog.Infoln(buildString) } - cfg := config.ParseConfigFromFlagsAndFile(*configFile) + cfg := configFrom(*configFile) if os.Getenv("GOMAXPROCS") == "" { runtime.GOMAXPROCS(runtime.NumCPU()) @@ -184,7 +248,7 @@ func main() { default: fmt.Println("No command", cmd) - flag.Usage() + usage() } if err != nil { glog.Errorln(err) diff --git a/config/config.go b/config/config.go index 26b68ac..90f7741 100644 --- a/config/config.go +++ b/config/config.go @@ -16,15 +16,13 @@ package config import ( "encoding/json" - "flag" "fmt" "os" "strconv" "time" - - "github.com/barakmich/glog" ) +// Config defines the behavior of cayley database instances. type Config struct { DatabaseType string DatabasePath string @@ -122,89 +120,23 @@ func (d *duration) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf("%q", *d)), nil } -var ( - databasePath = flag.String("dbpath", "/tmp/testdb", "Path to the database.") - databaseBackend = flag.String("db", "memstore", "Database Backend.") - replicationBackend = flag.String("replication", "single", "Replication method.") - host = flag.String("host", "127.0.0.1", "Host to listen on (defaults to all).") - loadSize = flag.Int("load_size", 10000, "Size of triplesets to load") - port = flag.String("port", "64210", "Port to listen on.") - readOnly = flag.Bool("read_only", false, "Disable writing via HTTP.") - timeout = flag.Duration("timeout", 30*time.Second, "Elapsed time until an individual query times out.") -) - -func ParseConfigFromFile(filename string) *Config { +// Load reads a JSON-encoded config contained in the given file. A zero value +// config is returned if the filename is empty. +func Load(file string) (*Config, error) { config := &Config{} - if filename == "" { - return config + if file == "" { + return config, nil } - f, err := os.Open(filename) + f, err := os.Open(file) if err != nil { - glog.Fatalln("Couldn't open config file", filename) + return nil, fmt.Errorf("could not open config file %q: %v", file, err) } - defer f.Close() dec := json.NewDecoder(f) err = dec.Decode(config) if err != nil { - glog.Fatalln("Couldn't read config file:", err) + return nil, fmt.Errorf("could not parse config file %q: %v", file, err) } - return config -} - -func ParseConfigFromFlagsAndFile(fileFlag string) *Config { - // Find the file... - var trueFilename string - if fileFlag != "" { - if _, err := os.Stat(fileFlag); os.IsNotExist(err) { - glog.Fatalln("Cannot find specified configuration file", fileFlag, ", aborting.") - } else { - trueFilename = fileFlag - } - } else { - if _, err := os.Stat(os.Getenv("CAYLEY_CFG")); err == nil { - trueFilename = os.Getenv("CAYLEY_CFG") - } else { - if _, err := os.Stat("/etc/cayley.cfg"); err == nil { - trueFilename = "/etc/cayley.cfg" - } - } - } - if trueFilename == "" { - glog.Infoln("Couldn't find a config file in either $CAYLEY_CFG or /etc/cayley.cfg. Going by flag defaults only.") - } - config := ParseConfigFromFile(trueFilename) - - if config.DatabasePath == "" { - config.DatabasePath = *databasePath - } - - if config.DatabaseType == "" { - config.DatabaseType = *databaseBackend - } - - if config.ReplicationType == "" { - config.ReplicationType = *replicationBackend - } - - if config.ListenHost == "" { - config.ListenHost = *host - } - - if config.ListenPort == "" { - config.ListenPort = *port - } - - if config.Timeout == 0 { - config.Timeout = *timeout - } - - if config.LoadSize == 0 { - config.LoadSize = *loadSize - } - - config.ReadOnly = config.ReadOnly || *readOnly - - return config + return config, nil } diff --git a/db/repl.go b/db/repl.go index ac36ea4..da3aff9 100644 --- a/db/repl.go +++ b/db/repl.go @@ -104,6 +104,7 @@ func Repl(h *graph.Handle, queryLanguage string, cfg *config.Config) error { line, err := term.Prompt(prompt) if err != nil { if err == io.EOF { + fmt.Println() return nil } return err @@ -170,9 +171,7 @@ func terminal(path string) (*liner.State, error) { signal.Notify(c, os.Interrupt, os.Kill) <-c - persist(term, history) - - err := term.Close() + err := persist(term, history) if err != nil { fmt.Fprintf(os.Stderr, "failed to properly clean up terminal: %v\n", err) os.Exit(1) @@ -200,5 +199,5 @@ func persist(term *liner.State, path string) error { if err != nil { return fmt.Errorf("could not write history to %q: %v", path, err) } - return nil + return term.Close() } diff --git a/graph/iterator.go b/graph/iterator.go index ca17cb5..83f1999 100644 --- a/graph/iterator.go +++ b/graph/iterator.go @@ -51,14 +51,16 @@ func (t *Tagger) Fixed() map[string]Value { } func (t *Tagger) CopyFrom(src Iterator) { - for _, tag := range src.Tagger().Tags() { - t.Add(tag) - } + st := src.Tagger() - for k, v := range src.Tagger().Fixed() { - t.AddFixed(k, v) - } + t.tags = append(t.tags, st.tags...) + if t.fixedTags == nil { + t.fixedTags = make(map[string]Value, len(st.fixedTags)) + } + for k, v := range st.fixedTags { + t.fixedTags[k] = v + } } type Iterator interface { diff --git a/graph/mongo/iterator.go b/graph/mongo/iterator.go index 3356974..78237ab 100644 --- a/graph/mongo/iterator.go +++ b/graph/mongo/iterator.go @@ -130,9 +130,9 @@ func (it *Iterator) Clone() graph.Iterator { func (it *Iterator) Next() bool { var result struct { - Id string "_id" - Added []int64 "Added" - Deleted []int64 "Deleted" + Id string `bson:"_id"` + Added []int64 `bson:"Added"` + Deleted []int64 `bson:"Deleted"` } found := it.iter.Next(&result) if !found { diff --git a/graph/mongo/triplestore.go b/graph/mongo/triplestore.go index 03c4c93..87adf7d 100644 --- a/graph/mongo/triplestore.go +++ b/graph/mongo/triplestore.go @@ -121,15 +121,15 @@ func (qs *TripleStore) convertStringToByteHash(s string) string { } type MongoNode struct { - Id string "_id" - Name string "Name" - Size int "Size" + Id string `bson:"_id"` + Name string `bson:"Name"` + Size int `bson:"Size"` } type MongoLogEntry struct { - LogID int64 "LogID" - Action string "Action" - Key string "Key" + LogID int64 `bson:"LogID"` + Action string `bson:"Action"` + Key string `bson:"Key"` Timestamp int64 } @@ -175,8 +175,8 @@ func (qs *TripleStore) updateQuad(q quad.Quad, id int64, proc graph.Procedure) e func (qs *TripleStore) checkValid(key string) bool { var indexEntry struct { - Added []int64 "Added" - Deleted []int64 "Deleted" + Added []int64 `bson:"Added"` + Deleted []int64 `bson:"Deleted"` } err := qs.db.C("quads").FindId(key).One(&indexEntry) if err == mgo.ErrNotFound { diff --git a/quad/cquads/cquads.rl b/quad/cquads/cquads.rl index cce8f27..53104f0 100644 --- a/quad/cquads/cquads.rl +++ b/quad/cquads/cquads.rl @@ -73,7 +73,8 @@ ; IRIREF = '<' ( - '!' .. ';' + '!' + | '#' .. ';' | '=' | '?' .. '[' | ']' diff --git a/quad/cquads/cquads_test.go b/quad/cquads/cquads_test.go index 8d12ca7..4aee70c 100644 --- a/quad/cquads/cquads_test.go +++ b/quad/cquads/cquads_test.go @@ -569,6 +569,30 @@ var testNTriples = []struct { }, err: quad.ErrIncomplete, }, + + // Example quad from issue #140 in two forms: strict N-Quads and as quoted in issue. + { + message: "parse incomplete quad", + input: "\t\t.", + expect: quad.Quad{ + Subject: "ns:m.0y_chx", + Predicate: "ns:music.recording.lyrics_website..common.webpage.uri", + Object: ".", + expect: quad.Quad{ + Subject: "ns:m.0y_chx", + Predicate: "ns:music.recording.lyrics_website..common.webpage.uri", + Object: " 93: @@ -2123,7 +2125,7 @@ tr82: goto _test_eof30 } st_case_30: -// line 2127 "parse.go" +// line 2129 "parse.go" switch data[p] { case 9: goto tr37 @@ -2145,7 +2147,7 @@ tr83: goto _test_eof31 } st_case_31: -// line 2149 "parse.go" +// line 2151 "parse.go" switch data[p] { case 85: goto st32 @@ -2303,6 +2305,8 @@ tr83: } st_case_40: switch data[p] { + case 33: + goto tr81 case 62: goto tr82 case 92: @@ -2314,7 +2318,7 @@ tr83: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr81 } case data[p] > 93: @@ -2342,7 +2346,7 @@ tr89: goto _test_eof41 } st_case_41: -// line 2346 "parse.go" +// line 2350 "parse.go" switch data[p] { case 34: goto st42 @@ -2546,7 +2550,7 @@ tr36: goto _test_eof51 } st_case_51: -// line 2550 "parse.go" +// line 2554 "parse.go" switch data[p] { case 9: goto tr37 @@ -2604,7 +2608,7 @@ tr102: goto _test_eof196 } st_case_196: -// line 2608 "parse.go" +// line 2612 "parse.go" switch data[p] { case 9: goto st178 @@ -2646,7 +2650,7 @@ tr273: goto _test_eof197 } st_case_197: -// line 2650 "parse.go" +// line 2654 "parse.go" switch data[p] { case 9: goto tr274 @@ -2702,7 +2706,7 @@ tr327: goto _test_eof198 } st_case_198: -// line 2706 "parse.go" +// line 2710 "parse.go" switch data[p] { case 9: goto st198 @@ -2747,7 +2751,7 @@ tr314: goto _test_eof199 } st_case_199: -// line 2751 "parse.go" +// line 2755 "parse.go" switch data[p] { case 34: goto st200 @@ -2779,7 +2783,7 @@ tr315: goto _test_eof200 } st_case_200: -// line 2783 "parse.go" +// line 2787 "parse.go" switch data[p] { case 9: goto tr287 @@ -2907,8 +2911,10 @@ tr308: goto _test_eof207 } st_case_207: -// line 2911 "parse.go" +// line 2915 "parse.go" switch data[p] { + case 33: + goto st207 case 62: goto st208 case 92: @@ -2920,7 +2926,7 @@ tr308: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st207 } case data[p] > 93: @@ -2948,7 +2954,7 @@ tr309: goto _test_eof208 } st_case_208: -// line 2952 "parse.go" +// line 2958 "parse.go" switch data[p] { case 9: goto tr253 @@ -2970,7 +2976,7 @@ tr310: goto _test_eof209 } st_case_209: -// line 2974 "parse.go" +// line 2980 "parse.go" switch data[p] { case 85: goto st210 @@ -3128,6 +3134,8 @@ tr310: } st_case_218: switch data[p] { + case 33: + goto tr308 case 62: goto tr309 case 92: @@ -3139,7 +3147,7 @@ tr310: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr308 } case data[p] > 93: @@ -3167,7 +3175,7 @@ tr316: goto _test_eof219 } st_case_219: -// line 3171 "parse.go" +// line 3179 "parse.go" switch data[p] { case 34: goto st220 @@ -3371,7 +3379,7 @@ tr283: goto _test_eof229 } st_case_229: -// line 3375 "parse.go" +// line 3383 "parse.go" switch data[p] { case 9: goto tr253 @@ -3429,7 +3437,7 @@ tr329: goto _test_eof230 } st_case_230: -// line 3433 "parse.go" +// line 3441 "parse.go" switch data[p] { case 9: goto st183 @@ -3487,7 +3495,7 @@ tr330: goto _test_eof232 } st_case_232: -// line 3491 "parse.go" +// line 3499 "parse.go" switch data[p] { case 34: goto st233 @@ -3693,7 +3701,7 @@ tr24: goto _test_eof52 } st_case_52: -// line 3697 "parse.go" +// line 3705 "parse.go" switch data[p] { case 33: goto st6 @@ -3730,7 +3738,7 @@ tr103: goto _test_eof53 } st_case_53: -// line 3734 "parse.go" +// line 3742 "parse.go" switch data[p] { case 34: goto st54 @@ -3943,7 +3951,7 @@ tr140: goto _test_eof63 } st_case_63: -// line 3947 "parse.go" +// line 3955 "parse.go" switch data[p] { case 34: goto st64 @@ -3975,7 +3983,7 @@ tr141: goto _test_eof64 } st_case_64: -// line 3979 "parse.go" +// line 3987 "parse.go" switch data[p] { case 9: goto tr113 @@ -4103,8 +4111,10 @@ tr134: goto _test_eof71 } st_case_71: -// line 4107 "parse.go" +// line 4115 "parse.go" switch data[p] { + case 33: + goto st71 case 62: goto st72 case 92: @@ -4116,7 +4126,7 @@ tr134: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st71 } case data[p] > 93: @@ -4144,7 +4154,7 @@ tr135: goto _test_eof72 } st_case_72: -// line 4148 "parse.go" +// line 4158 "parse.go" switch data[p] { case 9: goto tr27 @@ -4166,7 +4176,7 @@ tr136: goto _test_eof73 } st_case_73: -// line 4170 "parse.go" +// line 4180 "parse.go" switch data[p] { case 85: goto st74 @@ -4324,6 +4334,8 @@ tr136: } st_case_82: switch data[p] { + case 33: + goto tr134 case 62: goto tr135 case 92: @@ -4335,7 +4347,7 @@ tr136: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr134 } case data[p] > 93: @@ -4363,7 +4375,7 @@ tr142: goto _test_eof83 } st_case_83: -// line 4367 "parse.go" +// line 4379 "parse.go" switch data[p] { case 34: goto st84 @@ -4567,7 +4579,7 @@ tr26: goto _test_eof93 } st_case_93: -// line 4571 "parse.go" +// line 4583 "parse.go" switch data[p] { case 9: goto tr27 @@ -4610,7 +4622,7 @@ tr154: goto _test_eof94 } st_case_94: -// line 4614 "parse.go" +// line 4626 "parse.go" switch data[p] { case 33: goto st4 @@ -4647,7 +4659,7 @@ tr155: goto _test_eof95 } st_case_95: -// line 4651 "parse.go" +// line 4663 "parse.go" switch data[p] { case 34: goto st96 @@ -4860,7 +4872,7 @@ tr190: goto _test_eof105 } st_case_105: -// line 4864 "parse.go" +// line 4876 "parse.go" switch data[p] { case 34: goto st106 @@ -4892,7 +4904,7 @@ tr191: goto _test_eof106 } st_case_106: -// line 4896 "parse.go" +// line 4908 "parse.go" switch data[p] { case 9: goto tr165 @@ -5014,8 +5026,10 @@ tr184: goto _test_eof113 } st_case_113: -// line 5018 "parse.go" +// line 5030 "parse.go" switch data[p] { + case 33: + goto st113 case 62: goto st114 case 92: @@ -5027,7 +5041,7 @@ tr184: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st113 } case data[p] > 93: @@ -5055,7 +5069,7 @@ tr185: goto _test_eof114 } st_case_114: -// line 5059 "parse.go" +// line 5073 "parse.go" switch data[p] { case 9: goto tr17 @@ -5075,7 +5089,7 @@ tr186: goto _test_eof115 } st_case_115: -// line 5079 "parse.go" +// line 5093 "parse.go" switch data[p] { case 85: goto st116 @@ -5233,6 +5247,8 @@ tr186: } st_case_124: switch data[p] { + case 33: + goto tr184 case 62: goto tr185 case 92: @@ -5244,7 +5260,7 @@ tr186: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr184 } case data[p] > 93: @@ -5272,7 +5288,7 @@ tr192: goto _test_eof125 } st_case_125: -// line 5276 "parse.go" +// line 5292 "parse.go" switch data[p] { case 34: goto st126 @@ -5476,7 +5492,7 @@ tr16: goto _test_eof135 } st_case_135: -// line 5480 "parse.go" +// line 5496 "parse.go" switch data[p] { case 9: goto tr17 @@ -5519,7 +5535,7 @@ tr204: goto _test_eof136 } st_case_136: -// line 5523 "parse.go" +// line 5539 "parse.go" switch data[p] { case 33: goto st2 @@ -5556,7 +5572,7 @@ tr205: goto _test_eof137 } st_case_137: -// line 5560 "parse.go" +// line 5576 "parse.go" switch data[p] { case 34: goto st138 @@ -5769,7 +5785,7 @@ tr240: goto _test_eof147 } st_case_147: -// line 5773 "parse.go" +// line 5789 "parse.go" switch data[p] { case 34: goto st148 @@ -5801,7 +5817,7 @@ tr241: goto _test_eof148 } st_case_148: -// line 5805 "parse.go" +// line 5821 "parse.go" switch data[p] { case 9: goto tr215 @@ -5923,8 +5939,10 @@ tr234: goto _test_eof155 } st_case_155: -// line 5927 "parse.go" +// line 5943 "parse.go" switch data[p] { + case 33: + goto st155 case 62: goto st156 case 92: @@ -5936,7 +5954,7 @@ tr234: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st155 } case data[p] > 93: @@ -5964,7 +5982,7 @@ tr235: goto _test_eof156 } st_case_156: -// line 5968 "parse.go" +// line 5986 "parse.go" switch data[p] { case 9: goto tr7 @@ -5984,7 +6002,7 @@ tr236: goto _test_eof157 } st_case_157: -// line 5988 "parse.go" +// line 6006 "parse.go" switch data[p] { case 85: goto st158 @@ -6142,6 +6160,8 @@ tr236: } st_case_166: switch data[p] { + case 33: + goto tr234 case 62: goto tr235 case 92: @@ -6153,7 +6173,7 @@ tr236: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr234 } case data[p] > 93: @@ -6181,7 +6201,7 @@ tr242: goto _test_eof167 } st_case_167: -// line 6185 "parse.go" +// line 6205 "parse.go" switch data[p] { case 34: goto st168 @@ -6385,7 +6405,7 @@ tr6: goto _test_eof177 } st_case_177: -// line 6389 "parse.go" +// line 6409 "parse.go" switch data[p] { case 9: goto tr7 @@ -6684,7 +6704,7 @@ tr6: return q, nil -// line 6688 "parse.go" +// line 6708 "parse.go" } } diff --git a/quad/nquads/nquads.rl b/quad/nquads/nquads.rl index b5b3529..78a047e 100644 --- a/quad/nquads/nquads.rl +++ b/quad/nquads/nquads.rl @@ -64,7 +64,8 @@ ; IRIREF = '<' ( - '!' .. ';' + '!' + | '#' .. ';' | '=' | '?' .. '[' | ']' diff --git a/quad/nquads/nquads_test.go b/quad/nquads/nquads_test.go index aaac549..5b9c437 100644 --- a/quad/nquads/nquads_test.go +++ b/quad/nquads/nquads_test.go @@ -420,6 +420,19 @@ var testNTriples = []struct { }, err: fmt.Errorf("%v: unexpected rune '.' at 78", quad.ErrInvalid), }, + + // Example quad from issue #140. + { + message: "parse incomplete quad", + input: "\t\t.", + expect: quad.Quad{ + Subject: "", + Predicate: "", + Object: "", + Label: "", + }, + err: fmt.Errorf("%v: unexpected rune '\"' at 99", quad.ErrInvalid), + }, } func TestParse(t *testing.T) { diff --git a/quad/nquads/parse.go b/quad/nquads/parse.go index 8ea0c2c..991f932 100644 --- a/quad/nquads/parse.go +++ b/quad/nquads/parse.go @@ -317,6 +317,8 @@ tr120: st_case_2: // line 319 "parse.go" switch data[p] { + case 33: + goto st2 case 62: goto st3 case 92: @@ -328,7 +330,7 @@ tr120: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st2 } case data[p] > 93: @@ -356,7 +358,7 @@ tr121: goto _test_eof3 } st_case_3: -// line 360 "parse.go" +// line 362 "parse.go" switch data[p] { case 9: goto tr7 @@ -382,7 +384,7 @@ tr7: goto _test_eof4 } st_case_4: -// line 386 "parse.go" +// line 388 "parse.go" switch data[p] { case 9: goto st4 @@ -427,8 +429,10 @@ tr108: goto _test_eof5 } st_case_5: -// line 431 "parse.go" +// line 433 "parse.go" switch data[p] { + case 33: + goto st5 case 62: goto st6 case 92: @@ -440,7 +444,7 @@ tr108: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st5 } case data[p] > 93: @@ -468,7 +472,7 @@ tr109: goto _test_eof6 } st_case_6: -// line 472 "parse.go" +// line 476 "parse.go" switch data[p] { case 9: goto tr14 @@ -498,7 +502,7 @@ tr14: goto _test_eof7 } st_case_7: -// line 502 "parse.go" +// line 506 "parse.go" switch data[p] { case 9: goto st7 @@ -547,7 +551,7 @@ tr79: goto _test_eof8 } st_case_8: -// line 551 "parse.go" +// line 555 "parse.go" switch data[p] { case 34: goto st9 @@ -579,7 +583,7 @@ tr80: goto _test_eof9 } st_case_9: -// line 583 "parse.go" +// line 587 "parse.go" switch data[p] { case 9: goto tr25 @@ -633,7 +637,7 @@ tr96: goto _test_eof10 } st_case_10: -// line 637 "parse.go" +// line 641 "parse.go" switch data[p] { case 9: goto st10 @@ -674,7 +678,7 @@ tr39: goto _test_eof88 } st_case_88: -// line 678 "parse.go" +// line 682 "parse.go" switch data[p] { case 9: goto st88 @@ -695,7 +699,7 @@ tr127: goto _test_eof89 } st_case_89: -// line 699 "parse.go" +// line 703 "parse.go" goto st89 tr27: // line 54 "actions.rl" @@ -732,8 +736,10 @@ tr50: goto _test_eof11 } st_case_11: -// line 736 "parse.go" +// line 740 "parse.go" switch data[p] { + case 33: + goto st11 case 62: goto st12 case 92: @@ -745,7 +751,7 @@ tr50: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st11 } case data[p] > 93: @@ -773,7 +779,7 @@ tr51: goto _test_eof12 } st_case_12: -// line 777 "parse.go" +// line 783 "parse.go" switch data[p] { case 9: goto tr38 @@ -799,7 +805,7 @@ tr38: goto _test_eof13 } st_case_13: -// line 803 "parse.go" +// line 809 "parse.go" switch data[p] { case 9: goto st13 @@ -821,7 +827,7 @@ tr52: goto _test_eof14 } st_case_14: -// line 825 "parse.go" +// line 831 "parse.go" switch data[p] { case 85: goto st15 @@ -979,6 +985,8 @@ tr52: } st_case_23: switch data[p] { + case 33: + goto tr50 case 62: goto tr51 case 92: @@ -990,7 +998,7 @@ tr52: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr50 } case data[p] > 93: @@ -1034,7 +1042,7 @@ tr34: goto _test_eof24 } st_case_24: -// line 1038 "parse.go" +// line 1046 "parse.go" if data[p] == 58 { goto st25 } @@ -1216,7 +1224,7 @@ tr55: goto _test_eof90 } st_case_90: -// line 1220 "parse.go" +// line 1228 "parse.go" switch data[p] { case 9: goto st88 @@ -1527,8 +1535,10 @@ tr73: goto _test_eof34 } st_case_34: -// line 1531 "parse.go" +// line 1539 "parse.go" switch data[p] { + case 33: + goto st34 case 62: goto st35 case 92: @@ -1540,7 +1550,7 @@ tr73: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto st34 } case data[p] > 93: @@ -1568,7 +1578,7 @@ tr74: goto _test_eof35 } st_case_35: -// line 1572 "parse.go" +// line 1582 "parse.go" switch data[p] { case 9: goto tr25 @@ -1594,7 +1604,7 @@ tr75: goto _test_eof36 } st_case_36: -// line 1598 "parse.go" +// line 1608 "parse.go" switch data[p] { case 85: goto st37 @@ -1752,6 +1762,8 @@ tr75: } st_case_45: switch data[p] { + case 33: + goto tr73 case 62: goto tr74 case 92: @@ -1763,7 +1775,7 @@ tr75: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr73 } case data[p] > 93: @@ -1791,7 +1803,7 @@ tr81: goto _test_eof46 } st_case_46: -// line 1795 "parse.go" +// line 1807 "parse.go" switch data[p] { case 34: goto st47 @@ -2011,7 +2023,7 @@ tr21: goto _test_eof56 } st_case_56: -// line 2015 "parse.go" +// line 2027 "parse.go" if data[p] == 58 { goto st57 } @@ -2195,7 +2207,7 @@ tr90: goto _test_eof91 } st_case_91: -// line 2199 "parse.go" +// line 2211 "parse.go" switch data[p] { case 9: goto st88 @@ -2382,7 +2394,7 @@ tr91: goto _test_eof60 } st_case_60: -// line 2386 "parse.go" +// line 2398 "parse.go" switch data[p] { case 9: goto tr25 @@ -2587,7 +2599,7 @@ tr95: goto _test_eof62 } st_case_62: -// line 2591 "parse.go" +// line 2603 "parse.go" switch data[p] { case 9: goto tr96 @@ -2696,7 +2708,7 @@ tr97: goto _test_eof92 } st_case_92: -// line 2700 "parse.go" +// line 2712 "parse.go" switch data[p] { case 9: goto st88 @@ -2874,7 +2886,7 @@ tr110: goto _test_eof64 } st_case_64: -// line 2878 "parse.go" +// line 2890 "parse.go" switch data[p] { case 85: goto st65 @@ -3032,6 +3044,8 @@ tr110: } st_case_73: switch data[p] { + case 33: + goto tr108 case 62: goto tr109 case 92: @@ -3043,7 +3057,7 @@ tr110: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr108 } case data[p] > 93: @@ -3071,7 +3085,7 @@ tr122: goto _test_eof74 } st_case_74: -// line 3075 "parse.go" +// line 3089 "parse.go" switch data[p] { case 85: goto st75 @@ -3229,6 +3243,8 @@ tr122: } st_case_83: switch data[p] { + case 33: + goto tr120 case 62: goto tr121 case 92: @@ -3240,7 +3256,7 @@ tr122: } switch { case data[p] < 61: - if 33 <= data[p] && data[p] <= 59 { + if 35 <= data[p] && data[p] <= 59 { goto tr120 } case data[p] > 93: @@ -3268,7 +3284,7 @@ tr3: goto _test_eof84 } st_case_84: -// line 3272 "parse.go" +// line 3288 "parse.go" if data[p] == 58 { goto st85 } @@ -3644,7 +3660,7 @@ tr3: return q, nil -// line 3648 "parse.go" +// line 3664 "parse.go" } }