diff --git a/parse/keyvaluepair.go b/parse/keyvaluepair.go index 09f1491..7fcc350 100644 --- a/parse/keyvaluepair.go +++ b/parse/keyvaluepair.go @@ -67,7 +67,7 @@ func (t *parser) parseKey(p *parse.API, key ast.Key) (ast.Key, bool) { var ok bool switch { case p.Accept(bareKey): - keyPart, ok = p.Result().String(), true + keyPart, ok = p.Result.String(), true case p.Peek(a.SingleQuote): keyPart, ok = t.parseLiteralString("key", p) case p.Peek(a.DoubleQuote): diff --git a/parse/value_datetime.go b/parse/value_datetime.go index 751dc5c..0201fa2 100644 --- a/parse/value_datetime.go +++ b/parse/value_datetime.go @@ -91,16 +91,15 @@ func (t *parser) parseDateTime(p *parse.API) (*ast.Value, bool) { p.Expected("a date and/or time") return nil, false } - result := p.Result() - token := result.Token(0) + token := p.Result.Tokens[0] layout := "" for _, l := range token.Value.([]tokenize.Token) { layout += l.Type.(string) } - value, err := time.Parse(layout, string(token.Runes)) + value, err := time.Parse(layout, p.Result.String()) if err != nil { - p.Error("invalid date/time value %s: %s", string(token.Runes), err) + p.Error("invalid date/time value %s: %s", p.Result.String(), err) return nil, false } diff --git a/parse/value_datetime_test.go b/parse/value_datetime_test.go index 24b6ac3..06da496 100644 --- a/parse/value_datetime_test.go +++ b/parse/value_datetime_test.go @@ -14,7 +14,7 @@ func TestStartDateTime(t *testing.T) { func TestDateTime(t *testing.T) { for _, test := range []parseTest{ - {`x=1979-05-27`, `{"x": 1979-05-27}`, ``}, + {`x=1978-05-27`, `{"x": 1978-05-27}`, ``}, {`x=00:00:00`, `{"x": 00:00:00}`, ``}, {`x=23:59:59`, `{"x": 23:59:59}`, ``}, {`x=12:10:08.12121212121212`, `{"x": 12:10:08.121212121}`, ``}, diff --git a/parse/value_number.go b/parse/value_number.go index c94711b..751cef6 100644 --- a/parse/value_number.go +++ b/parse/value_number.go @@ -71,18 +71,18 @@ var ( func (t *parser) parseNumber(p *parse.API) (*ast.Value, bool) { switch { case p.Accept(tok.Float64(nil, float)): - return ast.NewValue(ast.TypeFloat, p.Result().Value(0).(float64)), true + return ast.NewValue(ast.TypeFloat, p.Result.Tokens[0].Value.(float64)), true case p.Accept(nan): return ast.NewValue(ast.TypeFloat, math.NaN()), true case p.Accept(inf): - if p.Result().Rune(0) == '-' { + if p.Result.Runes[0] == '-' { return ast.NewValue(ast.TypeFloat, math.Inf(-1)), true } return ast.NewValue(ast.TypeFloat, math.Inf(+1)), true case p.Accept(a.Zero): return t.parseIntegerStartingWithZero(p) case p.Accept(tok.Int64(nil, integer)): - return ast.NewValue(ast.TypeInteger, p.Result().Value(0).(int64)), true + return ast.NewValue(ast.TypeInteger, p.Result.Tokens[0].Value.(int64)), true default: p.Expected("a number") return nil, false @@ -94,17 +94,17 @@ func (t *parser) parseIntegerStartingWithZero(p *parse.API) (*ast.Value, bool) { var err error switch { case p.Accept(hexadecimal): - value, err = strconv.ParseInt(p.Result().Value(0).(string), 16, 64) + value, err = strconv.ParseInt(p.Result.Tokens[0].Value.(string), 16, 64) case p.Accept(octal): - value, err = strconv.ParseInt(p.Result().Value(0).(string), 8, 64) + value, err = strconv.ParseInt(p.Result.Tokens[0].Value.(string), 8, 64) case p.Accept(binary): - value, err = strconv.ParseInt(p.Result().Value(0).(string), 2, 64) + value, err = strconv.ParseInt(p.Result.Tokens[0].Value.(string), 2, 64) default: return ast.NewValue(ast.TypeInteger, int64(0)), true } if err == nil { return ast.NewValue(ast.TypeInteger, value), true } - p.Error("invalid integer value 0%s: %s", p.Result().String(), err) + p.Error("invalid integer value 0%s: %s", p.Result.String(), err) return nil, false } diff --git a/parse/value_string.go b/parse/value_string.go index 7815d0b..d8ed7b7 100644 --- a/parse/value_string.go +++ b/parse/value_string.go @@ -93,7 +93,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) { for { switch { case p.Peek(controlCharacter): - p.Error("invalid character in %s: %q (must be escaped)", name, p.Result().Rune(0)) + p.Error("invalid character in %s: %q (must be escaped)", name, p.Result.Runes[0]) return sb.String(), false case p.Accept(validEscape): if !appendEscapedRune(p, sb) { @@ -108,7 +108,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) { p.Error("invalid UTF8 rune") return sb.String(), false case p.Accept(a.ValidRune): - sb.WriteString(p.Result().String()) + sb.WriteString(p.Result.String()) default: p.Expected(`closing quotation marks`) return sb.String(), false @@ -136,13 +136,13 @@ func (t *parser) parseLiteralString(name string, p *parse.API) (string, bool) { case p.Accept(a.Tab): sb.WriteString("\t") case p.Peek(controlCharacter): - p.Error("invalid character in %s: %q (no control chars allowed, except for tab)", name, p.Result().Rune(0)) + p.Error("invalid character in %s: %q (no control chars allowed, except for tab)", name, p.Result.Runes[0]) return sb.String(), false case p.Peek(a.InvalidRune): p.Error("invalid UTF8 rune") return sb.String(), false case p.Accept(a.ValidRune): - sb.WriteString(p.Result().String()) + sb.WriteString(p.Result.String()) default: p.Expected("closing single quote") return sb.String(), false @@ -184,7 +184,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { case p.Accept(newline): sb.WriteString("\n") case p.Peek(controlCharacter): - p.Error("invalid character in multi-line basic string: %q (must be escaped)", p.Result().Rune(0)) + p.Error("invalid character in multi-line basic string: %q (must be escaped)", p.Result.Runes[0]) return sb.String(), false case p.Accept(validEscape): if !appendEscapedRune(p, sb) { @@ -198,7 +198,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { case p.Accept(m.Drop(doubleQuote3)): return sb.String(), true case p.Accept(a.ValidRune): - sb.WriteString(p.Result().String()) + sb.WriteString(p.Result.String()) case p.Peek(a.InvalidRune): p.Error("invalid UTF8 rune") return sb.String(), false @@ -210,7 +210,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { } func appendEscapedRune(p *parse.API, sb *strings.Builder) bool { - s := p.Result().String() + s := p.Result.String() switch s { case `\b`: sb.WriteRune('\b') @@ -268,10 +268,10 @@ func (t *parser) parseMultiLineLiteralString(p *parse.API) (string, bool) { case p.Accept(newline): sb.WriteString("\n") case p.Peek(controlCharacter): - p.Error("invalid character in literal string: %q (no control chars allowed, except for tab and newline)", p.Result().Rune(0)) + p.Error("invalid character in literal string: %q (no control chars allowed, except for tab and newline)", p.Result.Runes[0]) return sb.String(), false case p.Accept(a.ValidRune): - sb.WriteString(p.Result().String()) + sb.WriteString(p.Result.String()) case p.Peek(a.InvalidRune): p.Error("invalid UTF8 rune") return sb.String(), false diff --git a/parse2/grammar.go b/parse2/grammar.go index a404c97..79377b1 100644 --- a/parse2/grammar.go +++ b/parse2/grammar.go @@ -12,20 +12,27 @@ import ( "github.com/pkg/profile" ) +const runProfiler = false + func main() { bytes, _ := ioutil.ReadAll(os.Stdin) input := string(bytes) toml := BuildGrammar() - t := profile.Start() //profile.CPUProfile) - var result *tokenize.Result + var result *tokenize.API var err error - for i := 0; i < 10; i++ { - fmt.Printf(".") + + if runProfiler { + t := profile.Start() //profile.CPUProfile) + for i := 0; i < 20; i++ { + fmt.Printf(".") + result, err = toml.Match(input) + } + t.Stop() + } else { result, err = toml.Match(input) } - t.Stop() if err != nil { log.Fatalf("Error in parsing TOML: %s\n", err) @@ -49,7 +56,7 @@ func (g Grammar) Get(name string) tokenize.Handler { if handler, ok := g[name]; ok { return handler } - return func(t tokenize.API) bool { + return func(t *tokenize.API) bool { if handler, ok := g[name]; ok { return handler(t) } @@ -186,8 +193,8 @@ func BuildGrammar() tokenize.Handler { R("float", c.Any( tok.Float64("float", G("standard-float")), - tok.ByCallback("float", G("inf-float"), func(t tokenize.API) interface{} { - if t.Result().Rune(0) == '-' { + tok.ByCallback("float", G("inf-float"), func(t *tokenize.API) interface{} { + if t.Rune(0) == '-' { return math.Inf(-1) } return math.Inf(+1) @@ -229,14 +236,14 @@ func BuildGrammar() tokenize.Handler { R("local-date", G("date")) R("local-time", G("time")) - makeDateTimeValue := func(t tokenize.API) interface{} { + makeDateTimeValue := func(t *tokenize.API) interface{} { layout := "" input := "" - for _, t := range t.Result().Tokens() { + for _, t := range t.Tokens() { layout += t.Type.(string) input += t.Value.(string) } - t.Result().ClearTokens() + t.ClearTokens() value, err := time.Parse(layout, input) if err != nil { panic(fmt.Sprintf("Ow, we must implement a way to report date parse errors: %s", err)) diff --git a/parse2/long.toml b/parse2/long.toml index af201a8..10f62e5 100644 --- a/parse2/long.toml +++ b/parse2/long.toml @@ -9999,6 +9999,297 @@ # -------------------------------------------------------------------------------- +# From: https://github.com/toml-lang/toml/blob/master/examples/example-v0.3.0.toml +################################################################################ +## Comment + +# Speak your mind with the hash symbol. They go from the symbol to the end of +# the line. + + +################################################################################ +## Table + +# Tables (also known as hash tables or dictionaries) are collections of +# key/value pairs. They appear in square brackets on a line by themselves. + +[table] + +key = "value" # Yeah, you can do this. + +# Nested tables are denoted by table names with dots in them. Name your tables +# whatever crap you please, just don't use #, ., [ or ]. + +[table.subtable] + +key = "another value" + +# You don't need to specify all the super-tables if you don't want to. TOML +# knows how to do it for you. + +# [x] you +# [x.y] don't +# [x.y.z] need these +[x.y.z.w] # for this to work + + +################################################################################ +## Inline Table + +# Inline tables provide a more compact syntax for expressing tables. They are +# especially useful for grouped data that can otherwise quickly become verbose. +# Inline tables are enclosed in curly braces `{` and `}`. No newlines are +# allowed between the curly braces unless they are valid within a value. + +[table.inline] + +name = { first = "Tom", last = "Preston-Werner" } +point = { x = 1, y = 2 } + + +################################################################################ +## String + +# There are four ways to express strings: basic, multi-line basic, literal, and +# multi-line literal. All strings must contain only valid UTF-8 characters. + +[string.basic] + +basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." + +[string.multiline] + +# The following strings are byte-for-byte equivalent: +key1 = "One\nTwo" +key2 = """One\nTwo""" +key3 = """ +One +Two""" + +[string.multiline.continued] + +# The following strings are byte-for-byte equivalent: +key1 = "The quick brown fox jumps over the lazy dog." + +key2 = """ +The quick brown \ + fox jumps over \ + the lazy dog.""" + +key3 = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """ + +[string.literal] + +# What you see is what you get. +winpath = 'C:\Users\nodejs\templates' +winpath2 = '\\ServerX\admin$\system32\' +quoted = 'Tom "Dubs" Preston-Werner' +regex = '<\i\c*\s*>' + + +[string.literal.multiline] + +regex2 = '''I [dw]on't need \d{2} apples''' +lines = ''' +The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +''' + + +################################################################################ +## Integer + +# Integers are whole numbers. Positive numbers may be prefixed with a plus sign. +# Negative numbers are prefixed with a minus sign. + +[integer] + +key1 = +99 +key2 = 42 +key3 = 0 +key4 = -17 + +[integer.underscores] + +# For large numbers, you may use underscores to enhance readability. Each +# underscore must be surrounded by at least one digit. +key1 = 1_000 +key2 = 5_349_221 +key3 = 1_2_3_4_5 # valid but inadvisable + + +################################################################################ +## Float + +# A float consists of an integer part (which may be prefixed with a plus or +# minus sign) followed by a fractional part and/or an exponent part. + +[float.fractional] + +key1 = +1.0 +key2 = 3.1415 +key3 = -0.01 + +[float.exponent] + +key1 = 5e+22 +key2 = 1e6 +key3 = -2E-2 + +[float.both] + +key = 6.626e-34 + +[float.underscores] + +key1 = 9_224_617.445_991_228_313 +key2 = 1e1_00 # modified by mmakaay, because 1e1000 yields an out of range error + +################################################################################ +## Boolean + +# Booleans are just the tokens you're used to. Always lowercase. + +[boolean] + +True = true +False = false + + +################################################################################ +## Datetime + +# Datetimes are RFC 3339 dates. + +[datetime] + +key1 = 1979-05-27T07:32:00Z +key2 = 1979-05-27T00:32:00-07:00 +key3 = 1979-05-27T00:32:00.999999-07:00 + + +################################################################################ +## Array + +# Arrays are square brackets with other primitives inside. Whitespace is +# ignored. Elements are separated by commas. Data types may not be mixed. + +[array] + +key1 = [ 1, 2, 3 ] +key2 = [ "red", "yellow", "green" ] +key3 = [ [ 1, 2 ], [3, 4, 5] ] +key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok + +# Arrays can also be multiline. So in addition to ignoring whitespace, arrays +# also ignore newlines between the brackets. Terminating commas are ok before +# the closing bracket. + +key5 = [ + 1, 2, 3 +] +key6 = [ + 1, + 2, # this is ok +] + + +################################################################################ +## Array of Tables + +# These can be expressed by using a table name in double brackets. Each table +# with the same double bracketed name will be an element in the array. The +# tables are inserted in the order encountered. + +[[products]] + +name = "Hammer" +sku = 738594937 + +[[products]] + +[[products]] + +name = "Nail" +sku = 284758393 +color = "gray" + + +# You can create nested arrays of tables as well. + +[[fruit]] + name = "apple" + + [fruit.physical] + color = "red" + shape = "round" + + [[fruit.variety]] + name = "red delicious" + + [[fruit.variety]] + name = "granny smith" + +[[fruit]] + name = "banana" + + [[fruit.variety]] + name = "plantain" + +[int.special] + +no1 = [] +no2 = [ ] +no3 = [ + ] +go1 = [1,2,3,] +go2 = [ +1, +2, +3,] +go3 = [ 1, #one + 2, #two + 3 #three + ] + +go4 =[ + + + +1 , + + + + 2, + + + + + 3, + + + +# hi +# hi +# hi +] + +k="kaka" + +[date.types] +the.d1=2019-01-01 +the.d2=2019-01-01 12:12:12 +the.d3=2019-01-01T12:12:12 +the.d4=2019-01-01T12:12:12Z +the.d5=2019-01-01 12:12:12Z +the.d6=2019-01-01 12:12:12+03:45 + # -------------------------------------------------------------------------------- # -------------------------------------------------------------------------------- # -------------------------------------------------------------------------------- diff --git a/parse2/parse2 b/parse2/parse2 deleted file mode 100755 index 790d473..0000000 Binary files a/parse2/parse2 and /dev/null differ