From 08e47b4a9eb0091d823dca411ad09001dbca4c4a Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 21 Aug 2014 15:23:30 +0930 Subject: [PATCH 1/8] Do tagger copying with less iteration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes minimal difference to the benchmarks in cayley_test.go (a variable ±5% on the bigger cases). --- graph/iterator.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 { From 631188c626bf81d52421aea5315c04808bca9049 Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 21 Aug 2014 15:55:05 +0930 Subject: [PATCH 2/8] Fix error in REPL term shutdown leaving tty unsane Previously we did not close the liner term unless a SIGINT or SIGKILL was received. This left the terminal in raw. Fix that. --- db/repl.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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() } From 93c981414750c44e6c478d389cfa34c13922448c Mon Sep 17 00:00:00 2001 From: kortschak Date: Thu, 21 Aug 2014 19:33:00 +0930 Subject: [PATCH 3/8] Quieten go vet in mongo --- graph/mongo/iterator.go | 6 +++--- graph/mongo/triplestore.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) 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 { From df2c5e3c2a32293e11f7c22023e68056a376a5c7 Mon Sep 17 00:00:00 2001 From: kortschak Date: Fri, 22 Aug 2014 09:56:36 +0930 Subject: [PATCH 4/8] Move flag handling out of config into main This places all the flag definitions together, making them easier to find, and makes it possible (in the future) to use db for convenience functions when we have a Go API, without having flag space contaminated by cayley main flags. --- cayley.go | 73 ++++++++++++++++++++++++++++++++++++++++++---- config/config.go | 88 +++++++------------------------------------------------- 2 files changed, 77 insertions(+), 84 deletions(-) diff --git a/cayley.go b/cayley.go index d7364b9..fa4b5c0 100644 --- a/cayley.go +++ b/cayley.go @@ -29,6 +29,7 @@ import ( "os" "path/filepath" "runtime" + "time" "github.com/barakmich/glog" @@ -50,11 +51,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`"`. @@ -78,6 +87,58 @@ func Usage() { flag.PrintDefaults() } +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 { @@ -98,7 +159,7 @@ func main() { glog.Infoln(buildString) } - cfg := config.ParseConfigFromFlagsAndFile(*configFile) + cfg := configFrom(*configFile) if os.Getenv("GOMAXPROCS") == "" { runtime.GOMAXPROCS(runtime.NumCPU()) 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 } From 318edfc3c76e1c394d7f72966aca608ea52f1980 Mon Sep 17 00:00:00 2001 From: kortschak Date: Fri, 22 Aug 2014 16:27:52 +0930 Subject: [PATCH 5/8] Clean up usage * Use raw strings. * Hook usage into flag. * Print banner to stderr as flag.PrintDefaults does. * Use the cayley usage rather than the flag ussage when command is unknown. * Simplify args handling. --- cayley.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/cayley.go b/cayley.go index d7364b9..a9879ec 100644 --- a/cayley.go +++ b/cayley.go @@ -63,33 +63,36 @@ 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, `Cayley is a graph store and graph query layer. + +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 main() { // No command? It's time for usage. if len(os.Args) == 1 { - Usage() + 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 @@ -183,7 +186,7 @@ func main() { default: fmt.Println("No command", cmd) - flag.Usage() + usage() } if err != nil { glog.Errorln(err) From d9096d6d9f87a8b55506ed3866f8b68fcfa1f82b Mon Sep 17 00:00:00 2001 From: kortschak Date: Fri, 22 Aug 2014 16:40:22 +0930 Subject: [PATCH 6/8] Make usage cayley intro banner contextual Only provide it when people run cayley without any other args. --- cayley.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cayley.go b/cayley.go index a9879ec..d3f0cca 100644 --- a/cayley.go +++ b/cayley.go @@ -64,8 +64,7 @@ var ( ) func usage() { - fmt.Fprintln(os.Stderr, `Cayley is a graph store and graph query layer. - + fmt.Fprintln(os.Stderr, ` Usage: cayley COMMAND [flags] @@ -87,6 +86,7 @@ func init() { func main() { // No command? It's time for usage. if len(os.Args) == 1 { + fmt.Fprintln(os.Stderr, "Cayley is a graph store and graph query layer.") usage() os.Exit(1) } From d7e4aff72d8e2eefef2b0166a1b3614a55a640f6 Mon Sep 17 00:00:00 2001 From: kortschak Date: Sat, 23 Aug 2014 10:57:49 +0930 Subject: [PATCH 7/8] Fix IRIRef defintions Literal `"` is not allowed in an IRIRef. Fix this. --- quad/cquads/cquads.rl | 3 ++- quad/nquads/nquads.rl | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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/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 = '<' ( - '!' .. ';' + '!' + | '#' .. ';' | '=' | '?' .. '[' | ']' From 49961a50d78fb6f81ed22aa570dfb62dad044819 Mon Sep 17 00:00:00 2001 From: kortschak Date: Sat, 23 Aug 2014 11:08:02 +0930 Subject: [PATCH 8/8] Generate parser and add tests ragel -Z -G2 parse.rl ragel version 6.8 --- quad/cquads/cquads_test.go | 24 +++++++++ quad/cquads/parse.go | 128 ++++++++++++++++++++++++++------------------- quad/nquads/nquads_test.go | 13 +++++ quad/nquads/parse.go | 90 ++++++++++++++++++------------- 4 files changed, 164 insertions(+), 91 deletions(-) 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_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" } }