From 5ccb16f38f1c8329339fa802a9b4ca475db1ccd0 Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Mon, 22 Jul 2019 23:27:59 +0000 Subject: [PATCH] Backup work. --- cmd/burntsushi-tester/Makefile | 10 ++ cmd/burntsushi-tester/testfile2.toml | 245 +++++++++++++++++++++++++++ parse/document.go | 4 +- parse/value_boolean.go | 12 +- parse/value_number.go | 6 +- parse/value_string.go | 34 ++-- parse2/profile.sh | 3 +- 7 files changed, 294 insertions(+), 20 deletions(-) create mode 100644 cmd/burntsushi-tester/testfile2.toml diff --git a/cmd/burntsushi-tester/Makefile b/cmd/burntsushi-tester/Makefile index 6f5a47a..bd934d9 100644 --- a/cmd/burntsushi-tester/Makefile +++ b/cmd/burntsushi-tester/Makefile @@ -6,8 +6,18 @@ a: go build mv burntsushi-tester A +a-l: + go build -gcflags=all=-l + mv burntsushi-tester A + +b-l: + go build -gcflags=all=-l + mv burntsushi-tester B + test: test-a test-b test-sushi +profile: profile-a profile-b + test-a: numactl --physcpubind=+1 bash -c "time ./A < testfile.toml" diff --git a/cmd/burntsushi-tester/testfile2.toml b/cmd/burntsushi-tester/testfile2.toml new file mode 100644 index 0000000..7f61496 --- /dev/null +++ b/cmd/burntsushi-tester/testfile2.toml @@ -0,0 +1,245 @@ +################################################################################ +## 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 = 1e0_1_0 + + +################################################################################ +## 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" + diff --git a/parse/document.go b/parse/document.go index 53cdf9c..2ef0324 100644 --- a/parse/document.go +++ b/parse/document.go @@ -10,12 +10,14 @@ var ( // Both [tables] and [[arrays of tables]] start with a square open bracket. detectTable = a.SquareOpen + + whiteSpaceNewlinesAndComments = whitespaceInclNewlines.Or(comment) ) func (t *parser) startDocument(p *parse.API) { for { switch { - case p.Accept(whitespaceInclNewlines.Or(comment)): + case p.Accept(whiteSpaceNewlinesAndComments): // NOOP case p.Peek(detectTable): p.Handle(t.startTable) diff --git a/parse/value_boolean.go b/parse/value_boolean.go index fddfb1f..f576004 100644 --- a/parse/value_boolean.go +++ b/parse/value_boolean.go @@ -5,15 +5,19 @@ import ( "git.makaay.nl/mauricem/go-toml/ast" ) -var falseValue = ast.NewValue(ast.TypeBool, false) -var trueValue = ast.NewValue(ast.TypeBool, true) +var ( + trueStr = a.Str("true") + falseStr = a.Str("false") + falseValue = ast.NewValue(ast.TypeBool, false) + trueValue = ast.NewValue(ast.TypeBool, true) +) // Booleans are just the tokens you're used to. Always lowercase. func (t *parser) parseBoolean(p *parse.API) (*ast.Value, bool) { switch { - case p.Accept(a.Str("true")): + case p.Accept(trueStr): return trueValue, true - case p.Accept(a.Str("false")): + case p.Accept(falseStr): return falseValue, true default: p.Expected("true or false") diff --git a/parse/value_number.go b/parse/value_number.go index 751cef6..2dbf4bc 100644 --- a/parse/value_number.go +++ b/parse/value_number.go @@ -20,6 +20,7 @@ var ( underscoreDigits = m.Drop(a.Underscore).Then(a.Digits) integerSuffix = c.ZeroOrMore(underscoreDigits) integer = integerPrefix.Then(integerSuffix) + integerToken = tok.Int64(nil, integer) // Integer values -0 and +0 are valid and identical to an unprefixed zero. plusZero = a.Plus.Then(a.Zero) @@ -59,6 +60,7 @@ var ( // fractional part must precede the exponent part. fractAndOrExp = c.Any(fractionalPart.Then(c.Optional(exponentPart)), exponentPart) float = integer.Then(fractAndOrExp) + floatToken = tok.Float64(nil, float) // Float values -0.0 and +0.0 are valid and should map according to IEEE 754. zeroFloat = a.Signed(a.Str("0.0")) @@ -70,7 +72,7 @@ var ( func (t *parser) parseNumber(p *parse.API) (*ast.Value, bool) { switch { - case p.Accept(tok.Float64(nil, float)): + case p.Accept(floatToken): return ast.NewValue(ast.TypeFloat, p.Result.Tokens[0].Value.(float64)), true case p.Accept(nan): return ast.NewValue(ast.TypeFloat, math.NaN()), true @@ -81,7 +83,7 @@ func (t *parser) parseNumber(p *parse.API) (*ast.Value, bool) { 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)): + case p.Accept(integerToken): return ast.NewValue(ast.TypeInteger, p.Result.Tokens[0].Value.(int64)), true default: p.Expected("a number") diff --git a/parse/value_string.go b/parse/value_string.go index 1bf3bf6..b4d7196 100644 --- a/parse/value_string.go +++ b/parse/value_string.go @@ -14,11 +14,21 @@ var ( // Multi-line basic strings are surrounded by three quotation marks on each // side and allow newlines. - doubleQuote3 = a.Str(`"""`) + doubleQuote3 = a.Str(`"""`) + openingMultiLineBasicString = doubleQuote3.Then(newline.Optional()) + closingMultiLineBasicString = m.Drop(doubleQuote3) // Multi-line literal strings are surrounded by three single quotes on each side and allow newlines. - singleQuote3 = a.Str(`'''`) + singleQuote3 = a.Str(`'''`) + openingMultiLineLiteralString = singleQuote3.Then(newline.Optional()) + closingMultiLineLiteralString = m.Drop(singleQuote3) + + // Closing character for basic strings. + closingDoubleQuote = m.Drop(a.DoubleQuote) + + // Closing character for literal strings. + closingSingleQuote = m.Drop(a.SingleQuote) // Control characters as defined by TOML (U+0000 to U+001F, U+007F) @@ -93,7 +103,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) { sb := &strings.Builder{} for { switch { - case p.Peek(controlCharacter): + case p.PeekWithResult(controlCharacter): p.Error("invalid character in %s: %q (must be escaped)", name, p.Result.Runes[0]) return sb.String(), false case p.Accept(validEscape): @@ -103,7 +113,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) { case p.Peek(a.Backslash): p.Error("invalid escape sequence") return sb.String(), false - case p.Accept(m.Drop(a.DoubleQuote)): + case p.Accept(closingDoubleQuote): return sb.String(), true case p.Peek(a.InvalidRune): p.Error("invalid UTF8 rune") @@ -132,11 +142,11 @@ func (t *parser) parseLiteralString(name string, p *parse.API) (string, bool) { sb := &strings.Builder{} for { switch { - case p.Accept(m.Drop(a.SingleQuote)): + case p.Accept(closingSingleQuote): return sb.String(), true case p.Accept(a.Tab): sb.WriteString("\t") - case p.Peek(controlCharacter): + case p.PeekWithResult(controlCharacter): 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): @@ -175,7 +185,7 @@ func (t *parser) parseLiteralString(name string, p *parse.API) (string, bool) { // a \, it will be trimmed along with all whitespace (including newlines) up to // the next non-whitespace character or closing delimiter. func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { - if !p.Accept(doubleQuote3.Then(newline.Optional())) { + if !p.Accept(openingMultiLineBasicString) { p.Expected("opening three quotation marks") return "", false } @@ -184,7 +194,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { switch { case p.Accept(newline): sb.WriteString("\n") - case p.Peek(controlCharacter): + case p.PeekWithResult(controlCharacter): 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): @@ -196,7 +206,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { case p.Peek(a.Backslash): p.Error("invalid escape sequence") return sb.String(), false - case p.Accept(m.Drop(doubleQuote3)): + case p.Accept(closingMultiLineBasicString): return sb.String(), true case p.Accept(a.ValidRune): sb.WriteString(p.Result.String()) @@ -255,20 +265,20 @@ func appendEscapedRune(p *parse.API, sb *strings.Builder) bool { // // • Control characters other than tab and newline are not permitted in a multi-line literal string. func (t *parser) parseMultiLineLiteralString(p *parse.API) (string, bool) { - if !p.Accept(singleQuote3.Then(newline.Optional())) { + if !p.Accept(openingMultiLineLiteralString) { p.Expected("opening three single quotes") return "", false } sb := &strings.Builder{} for { switch { - case p.Accept(m.Drop(singleQuote3)): + case p.Accept(closingMultiLineLiteralString): return sb.String(), true case p.Accept(a.Tab): sb.WriteString("\t") case p.Accept(newline): sb.WriteString("\n") - case p.Peek(controlCharacter): + case p.PeekWithResult(controlCharacter): 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): diff --git a/parse2/profile.sh b/parse2/profile.sh index 8ed51ff..eef0679 100755 --- a/parse2/profile.sh +++ b/parse2/profile.sh @@ -9,7 +9,8 @@ #ppfile=` | ./parse2 2>&1 | grep "cpu profiling enabled" | cut -d, -f2` -go build +#go build -gcflags=all=-l -v +go build -v ppfile=`cat long.toml | ./parse2 -p 25 2>&1 | grep "profiling enabled" | cut -d, -f2` go tool pprof -http 0.0.0.0:8888 ./parse2 $ppfile