From febe1ff5683a65da8937fbf5b8bbf2ffa7876fe6 Mon Sep 17 00:00:00 2001 From: Maurice Makaay Date: Fri, 28 Jun 2019 08:23:43 +0000 Subject: [PATCH] Bits of code cleanup, no functional changes. --- ast/ast.go | 4 ++-- ast/ast_test.go | 6 +++--- ast/string_test.go | 4 ++-- cmd/toml-test-decoder/main.go | 2 +- parse/keyvaluepair.go | 9 +++------ parse/parse.go | 11 +++++------ parse/value_array.go | 2 +- parse/value_boolean.go | 4 ++-- parse/value_string.go | 34 ++++++++++++++++++---------------- parse/value_table.go | 14 +++++++------- 10 files changed, 44 insertions(+), 46 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index 52d4d14..c651f9c 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -65,8 +65,8 @@ const ( // TypeFloat identifies a floating point number (10.1234, 143E-12, 43.28377e+4, +inf, -inf, nan). TypeFloat ValueType = "float" - // TypeBoolean identifies a boolean value (true or false). - TypeBoolean ValueType = "boolean" + // TypeBool identifies a boolean value (true or false). + TypeBool ValueType = "bool" // TypeOffsetDateTime identifies a date/time value, including timezone info (2019-06-18 10:32:15.173645362+0200). TypeOffsetDateTime ValueType = "datetime" diff --git a/ast/ast_test.go b/ast/ast_test.go index 3de9859..96c9e81 100644 --- a/ast/ast_test.go +++ b/ast/ast_test.go @@ -12,8 +12,8 @@ func Test_ConstructSlightlyComplexStructure(t *testing.T) { p.SetKeyValuePair(ast.NewKey("ding"), ast.NewValue(ast.TypeInteger, 10)) p.SetKeyValuePair(ast.NewKey("dong"), ast.NewValue(ast.TypeString, "not a song")) p.OpenTable(ast.NewKey("key1", "key2 a")) - p.SetKeyValuePair(ast.NewKey("dooh"), ast.NewValue(ast.TypeBoolean, true)) - p.SetKeyValuePair(ast.NewKey("dah"), ast.NewValue(ast.TypeBoolean, false)) + p.SetKeyValuePair(ast.NewKey("dooh"), ast.NewValue(ast.TypeBool, true)) + p.SetKeyValuePair(ast.NewKey("dah"), ast.NewValue(ast.TypeBool, false)) p.OpenTable(ast.NewKey("key1", "key2 b")) p.SetKeyValuePair(ast.NewKey("dieh"), ast.NewValue(ast.TypeFloat, 1.111)) p.SetKeyValuePair(ast.NewKey("duh"), ast.NewValue(ast.TypeFloat, 1.18e-12)) @@ -188,7 +188,7 @@ func Test_GivenExistingValueAtDeepKeyFromSubTable_CreatingTableAtSameKey_Returns p := ast.NewDocument() p.OpenTable(ast.NewKey("deep", "table")) p.SetKeyValuePair(ast.NewKey("key1", "key2"), ast.NewValue(ast.TypeInteger, 0)) - return p.SetKeyValuePair(ast.NewKey("key1", "key2"), ast.NewValue(ast.TypeBoolean, true)), p + return p.SetKeyValuePair(ast.NewKey("key1", "key2"), ast.NewValue(ast.TypeBool, true)), p }, // This test mainly tests the formatting of [deep->table->key1->key2], being a concatenation // of the currently active table plus the multipart key for SetKeyValuePair(). diff --git a/ast/string_test.go b/ast/string_test.go index 22c57f3..4e1a742 100644 --- a/ast/string_test.go +++ b/ast/string_test.go @@ -10,13 +10,13 @@ import ( func Test_StringFormatting(t *testing.T) { testAST(t, func() (error, *ast.Document) { tableData := make(ast.Table) - tableData["x"] = ast.NewValue(ast.TypeBoolean, true) + tableData["x"] = ast.NewValue(ast.TypeBool, true) tableData["y"] = ast.NewValue(ast.TypeInteger, 42) dateTime, _ := time.Parse(time.RFC3339Nano, "2003-11-01T01:02:03.999999999+10:00") doc := ast.NewDocument() doc.SetKeyValuePair(ast.NewKey("a"), ast.NewValue(ast.TypeInteger, 1)) doc.SetKeyValuePair(ast.NewKey("b"), ast.NewValue(ast.TypeFloat, 2.3)) - doc.SetKeyValuePair(ast.NewKey("c"), ast.NewValue(ast.TypeBoolean, true)) + doc.SetKeyValuePair(ast.NewKey("c"), ast.NewValue(ast.TypeBool, true)) doc.SetKeyValuePair(ast.NewKey("d"), ast.NewValue(ast.TypeString, "foo")) doc.SetKeyValuePair(ast.NewKey("e"), ast.NewValue(ast.TypeArray, ast.NewValue(ast.TypeInteger, 1), ast.NewValue(ast.TypeInteger, 2))) doc.SetKeyValuePair(ast.NewKey("f"), ast.NewValue(ast.TypeTable, tableData)) diff --git a/cmd/toml-test-decoder/main.go b/cmd/toml-test-decoder/main.go index 0bc155d..b3ca2de 100644 --- a/cmd/toml-test-decoder/main.go +++ b/cmd/toml-test-decoder/main.go @@ -53,7 +53,7 @@ func makeSushi(value *ast.Value) string { return renderValue("integer", fmt.Sprintf("%d", value.Data[0].(int64))) case ast.TypeFloat: return renderValue("float", fmt.Sprintf("%v", value.Data[0].(float64))) - case ast.TypeBoolean: + case ast.TypeBool: return renderValue("bool", fmt.Sprintf("%t", value.Data[0].(bool))) case ast.TypeOffsetDateTime: return renderValue("datetime", value.Data[0].(time.Time).Format(time.RFC3339Nano)) diff --git a/parse/keyvaluepair.go b/parse/keyvaluepair.go index 6b65d12..94c6266 100644 --- a/parse/keyvaluepair.go +++ b/parse/keyvaluepair.go @@ -12,7 +12,7 @@ var ( // Blank is ignored around key names and values. The key, equals // sign, and value must be on the same line (though some values can be // broken over multiple lines). - keyAssignment = c.Seq(dropBlanks, a.Equal, dropBlanks) + keyAssignment = c.Seq(optionalBlanks, a.Equal, optionalBlanks) // A key may be either bare, quoted or dotted. Bare keys may only // contain ASCII letters, ASCII digits, underscores, and dashes @@ -31,10 +31,7 @@ var ( // This allows for grouping similar properties together. Blanks // around dot-separated parts are ignored, however, best practice is to // not use any extraneous blanks. - keySeparatorDot = c.Seq(dropBlanks, a.Dot, dropBlanks) - - // After a value, the line must end. There can be an optional comment. - endOfLineAfterValue = c.Seq(dropBlanks, a.EndOfLine.Or(comment)) + keySeparatorDot = c.Seq(optionalBlanks, a.Dot, optionalBlanks) ) func (t *parser) startKeyValuePair(p *parse.API) { @@ -44,7 +41,7 @@ func (t *parser) startKeyValuePair(p *parse.API) { err := t.SetKeyValuePair(key, value) if err != nil { p.Error("%s", err) - } else if !p.Accept(endOfLineAfterValue) { + } else if !p.Accept(endOfLineOrComment) { p.Expected("end of line") } } diff --git a/parse/parse.go b/parse/parse.go index 613f640..73cefaf 100644 --- a/parse/parse.go +++ b/parse/parse.go @@ -16,7 +16,6 @@ var ( blank = a.Runes('\t', ' ') blanks = c.OneOrMore(blank) optionalBlanks = c.ZeroOrMore(blank) - dropBlanks = m.Drop(optionalBlanks) // Newline means LF (0x0A) or CRLF (0x0D0A). // This matches the default newline as defined by parsekit. @@ -25,15 +24,15 @@ var ( // Whitespace is defined as blanks + newlines. whitespace = c.OneOrMore(blank.Or(newline)) optionalWhitespace = c.ZeroOrMore(blank.Or(newline)) - dropWhitespace = m.Drop(optionalWhitespace) // A '#' hash symbol marks the rest of the line as a comment. // All characters up to the end of the line are included in the comment. - comment = c.Seq(a.Hash, c.ZeroOrMore(c.Not(a.EndOfLine)), m.Drop(a.EndOfLine)) + comment = c.Seq(a.Hash, c.ZeroOrMore(c.Not(a.EndOfLine))) + optionalComment = c.Optional(comment) - endOfLineOrComment = optionalBlanks.Then(a.EndOfLine.Or(comment)) - whitespaceOrComment = c.OneOrMore(c.Any(blank, newline, comment)) - optionalWhitespaceOrComment = c.Optional(whitespaceOrComment) + endOfLineOrComment = c.Seq(optionalBlanks, optionalComment, a.EndOfLine) + whitespaceOrComment = whitespace.Or(comment) + optionalWhitespaceOrComment = c.ZeroOrMore(whitespaceOrComment) ) // parser embeds the TOML ast.Document, so it can be extended with methods diff --git a/parse/value_array.go b/parse/value_array.go index bf6c85d..c73abf9 100644 --- a/parse/value_array.go +++ b/parse/value_array.go @@ -33,7 +33,7 @@ import ( var ( arrayOpen = a.SquareOpen.Then(optionalWhitespaceOrComment) arraySeparator = c.Seq(optionalWhitespaceOrComment, a.Comma, optionalWhitespaceOrComment) - arrayClose = c.Seq(c.Optional(optionalWhitespaceOrComment.Then(a.Comma)), optionalWhitespaceOrComment, a.SquareClose) + arrayClose = c.Seq(optionalWhitespaceOrComment, a.Comma.Optional(), optionalWhitespaceOrComment, a.SquareClose) ) func (t *parser) parseArray(p *parse.API) (*ast.Value, bool) { diff --git a/parse/value_boolean.go b/parse/value_boolean.go index 88a8191..fddfb1f 100644 --- a/parse/value_boolean.go +++ b/parse/value_boolean.go @@ -5,8 +5,8 @@ import ( "git.makaay.nl/mauricem/go-toml/ast" ) -var falseValue = ast.NewValue(ast.TypeBoolean, false) -var trueValue = ast.NewValue(ast.TypeBoolean, true) +var falseValue = ast.NewValue(ast.TypeBool, false) +var 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) { diff --git a/parse/value_string.go b/parse/value_string.go index 6902b8a..b32f947 100644 --- a/parse/value_string.go +++ b/parse/value_string.go @@ -40,11 +40,11 @@ var ( // "line ending backslash". When the last non-whitespace character on a line is // a \, it will be trimmed along with all whitespace (including newlines) up to // the next non-whitespace character or closing delimiter. - lineEndingBackslash = a.Backslash.Then(dropBlanks).Then(newline).Then(dropWhitespace) + lineEndingBackslash = c.Seq(a.Backslash, optionalBlanks, newline, optionalWhitespace) ) // 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. +// multi-line literal. All strings must parse/value_array.gocontain only valid UTF-8 characters. func (t *parser) parseString(p *parse.API) (*ast.Value, bool) { var value string var ok bool @@ -89,13 +89,8 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) { p.Error("invalid character in %s: %q (must be escaped)", name, p.Result().Rune(0)) return sb.String(), false case p.Accept(tok.StrInterpreted(nil, validEscape)): - s := p.Result().Value(0).(string) - for _, r := range s { - if r == utf8.RuneError { - p.Error("invalid UTF8 rune") - return sb.String(), false - } - sb.WriteRune(r) + if !appendStrInterpreted(p, sb) { + return sb.String(), false } case p.Peek(a.Backslash): p.Error("invalid escape sequence") @@ -185,13 +180,8 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { p.Error("invalid character in multi-line basic string: %q (must be escaped)", p.Result().Rune(0)) return sb.String(), false case p.Accept(tok.StrInterpreted(nil, c.OneOrMore(validEscape))): - s := p.Result().Value(0).(string) - for _, r := range s { - if r == utf8.RuneError { - p.Error("invalid UTF8 rune") - return sb.String(), false - } - sb.WriteRune(r) + if !appendStrInterpreted(p, sb) { + return sb.String(), false } case p.Accept(lineEndingBackslash): // NOOP, the line-ending backslash sequence is skipped. @@ -212,6 +202,18 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) { } } +func appendStrInterpreted(p *parse.API, sb *strings.Builder) bool { + s := p.Result().Value(0).(string) + for _, r := range s { + if r == utf8.RuneError { + p.Error("invalid UTF8 rune") + return false + } + sb.WriteRune(r) + } + return true +} + // Specific handling of input for multi-line literal strings. // // • Multi-line literal strings are surrounded by three single quotes on diff --git a/parse/value_table.go b/parse/value_table.go index 0281046..4a17e3b 100644 --- a/parse/value_table.go +++ b/parse/value_table.go @@ -7,17 +7,17 @@ import ( var ( // Opener and closer for [table]. - tableOpen = c.Seq(dropBlanks, a.SquareOpen, dropBlanks) - tableClose = c.Seq(dropBlanks, a.SquareClose, dropBlanks) + tableOpen = c.Seq(optionalBlanks, a.SquareOpen, optionalBlanks) + tableClose = c.Seq(optionalBlanks, a.SquareClose, optionalBlanks) // Opener and closer for [[array.of.tables]]. - tableArrayOpen = c.Seq(dropBlanks, a.SquareOpen, a.SquareOpen, dropBlanks) - tableArrayClose = c.Seq(dropBlanks, a.SquareClose, a.SquareClose, dropBlanks) + tableArrayOpen = c.Seq(optionalBlanks, a.SquareOpen, a.SquareOpen, optionalBlanks) + tableArrayClose = c.Seq(optionalBlanks, a.SquareClose, a.SquareClose, optionalBlanks) // Opener, separator and closer for { inline: "tables" }. - inlineTableOpen = c.Seq(dropBlanks, a.CurlyOpen, dropBlanks) - inlineTableSeparator = c.Seq(dropBlanks, a.Comma, dropBlanks) - inlineTableClose = c.Seq(dropBlanks, a.CurlyClose, dropBlanks) + inlineTableOpen = c.Seq(optionalBlanks, a.CurlyOpen, optionalBlanks) + inlineTableSeparator = c.Seq(optionalBlanks, a.Comma, optionalBlanks) + inlineTableClose = c.Seq(optionalBlanks, a.CurlyClose, optionalBlanks) ) func (t *parser) startTable(p *parse.API) {