Optimization round completed (for now :-) All tests successful.
This commit is contained in:
parent
30a0d80d84
commit
be5f3b6f55
|
|
@ -67,7 +67,7 @@ func (t *parser) parseKey(p *parse.API, key ast.Key) (ast.Key, bool) {
|
||||||
var ok bool
|
var ok bool
|
||||||
switch {
|
switch {
|
||||||
case p.Accept(bareKey):
|
case p.Accept(bareKey):
|
||||||
keyPart, ok = p.Result().String(), true
|
keyPart, ok = p.Result.String(), true
|
||||||
case p.Peek(a.SingleQuote):
|
case p.Peek(a.SingleQuote):
|
||||||
keyPart, ok = t.parseLiteralString("key", p)
|
keyPart, ok = t.parseLiteralString("key", p)
|
||||||
case p.Peek(a.DoubleQuote):
|
case p.Peek(a.DoubleQuote):
|
||||||
|
|
|
||||||
|
|
@ -91,16 +91,15 @@ func (t *parser) parseDateTime(p *parse.API) (*ast.Value, bool) {
|
||||||
p.Expected("a date and/or time")
|
p.Expected("a date and/or time")
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
result := p.Result()
|
token := p.Result.Tokens[0]
|
||||||
token := result.Token(0)
|
|
||||||
|
|
||||||
layout := ""
|
layout := ""
|
||||||
for _, l := range token.Value.([]tokenize.Token) {
|
for _, l := range token.Value.([]tokenize.Token) {
|
||||||
layout += l.Type.(string)
|
layout += l.Type.(string)
|
||||||
}
|
}
|
||||||
value, err := time.Parse(layout, string(token.Runes))
|
value, err := time.Parse(layout, p.Result.String())
|
||||||
if err != nil {
|
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
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func TestStartDateTime(t *testing.T) {
|
||||||
|
|
||||||
func TestDateTime(t *testing.T) {
|
func TestDateTime(t *testing.T) {
|
||||||
for _, test := range []parseTest{
|
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=00:00:00`, `{"x": 00:00:00}`, ``},
|
||||||
{`x=23:59:59`, `{"x": 23:59:59}`, ``},
|
{`x=23:59:59`, `{"x": 23:59:59}`, ``},
|
||||||
{`x=12:10:08.12121212121212`, `{"x": 12:10:08.121212121}`, ``},
|
{`x=12:10:08.12121212121212`, `{"x": 12:10:08.121212121}`, ``},
|
||||||
|
|
|
||||||
|
|
@ -71,18 +71,18 @@ var (
|
||||||
func (t *parser) parseNumber(p *parse.API) (*ast.Value, bool) {
|
func (t *parser) parseNumber(p *parse.API) (*ast.Value, bool) {
|
||||||
switch {
|
switch {
|
||||||
case p.Accept(tok.Float64(nil, float)):
|
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):
|
case p.Accept(nan):
|
||||||
return ast.NewValue(ast.TypeFloat, math.NaN()), true
|
return ast.NewValue(ast.TypeFloat, math.NaN()), true
|
||||||
case p.Accept(inf):
|
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
|
||||||
}
|
}
|
||||||
return ast.NewValue(ast.TypeFloat, math.Inf(+1)), true
|
return ast.NewValue(ast.TypeFloat, math.Inf(+1)), true
|
||||||
case p.Accept(a.Zero):
|
case p.Accept(a.Zero):
|
||||||
return t.parseIntegerStartingWithZero(p)
|
return t.parseIntegerStartingWithZero(p)
|
||||||
case p.Accept(tok.Int64(nil, integer)):
|
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:
|
default:
|
||||||
p.Expected("a number")
|
p.Expected("a number")
|
||||||
return nil, false
|
return nil, false
|
||||||
|
|
@ -94,17 +94,17 @@ func (t *parser) parseIntegerStartingWithZero(p *parse.API) (*ast.Value, bool) {
|
||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case p.Accept(hexadecimal):
|
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):
|
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):
|
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:
|
default:
|
||||||
return ast.NewValue(ast.TypeInteger, int64(0)), true
|
return ast.NewValue(ast.TypeInteger, int64(0)), true
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return ast.NewValue(ast.TypeInteger, value), true
|
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
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) {
|
||||||
for {
|
for {
|
||||||
switch {
|
switch {
|
||||||
case p.Peek(controlCharacter):
|
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
|
return sb.String(), false
|
||||||
case p.Accept(validEscape):
|
case p.Accept(validEscape):
|
||||||
if !appendEscapedRune(p, sb) {
|
if !appendEscapedRune(p, sb) {
|
||||||
|
|
@ -108,7 +108,7 @@ func (t *parser) parseBasicString(name string, p *parse.API) (string, bool) {
|
||||||
p.Error("invalid UTF8 rune")
|
p.Error("invalid UTF8 rune")
|
||||||
return sb.String(), false
|
return sb.String(), false
|
||||||
case p.Accept(a.ValidRune):
|
case p.Accept(a.ValidRune):
|
||||||
sb.WriteString(p.Result().String())
|
sb.WriteString(p.Result.String())
|
||||||
default:
|
default:
|
||||||
p.Expected(`closing quotation marks`)
|
p.Expected(`closing quotation marks`)
|
||||||
return sb.String(), false
|
return sb.String(), false
|
||||||
|
|
@ -136,13 +136,13 @@ func (t *parser) parseLiteralString(name string, p *parse.API) (string, bool) {
|
||||||
case p.Accept(a.Tab):
|
case p.Accept(a.Tab):
|
||||||
sb.WriteString("\t")
|
sb.WriteString("\t")
|
||||||
case p.Peek(controlCharacter):
|
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
|
return sb.String(), false
|
||||||
case p.Peek(a.InvalidRune):
|
case p.Peek(a.InvalidRune):
|
||||||
p.Error("invalid UTF8 rune")
|
p.Error("invalid UTF8 rune")
|
||||||
return sb.String(), false
|
return sb.String(), false
|
||||||
case p.Accept(a.ValidRune):
|
case p.Accept(a.ValidRune):
|
||||||
sb.WriteString(p.Result().String())
|
sb.WriteString(p.Result.String())
|
||||||
default:
|
default:
|
||||||
p.Expected("closing single quote")
|
p.Expected("closing single quote")
|
||||||
return sb.String(), false
|
return sb.String(), false
|
||||||
|
|
@ -184,7 +184,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) {
|
||||||
case p.Accept(newline):
|
case p.Accept(newline):
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
case p.Peek(controlCharacter):
|
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
|
return sb.String(), false
|
||||||
case p.Accept(validEscape):
|
case p.Accept(validEscape):
|
||||||
if !appendEscapedRune(p, sb) {
|
if !appendEscapedRune(p, sb) {
|
||||||
|
|
@ -198,7 +198,7 @@ func (t *parser) parseMultiLineBasicString(p *parse.API) (string, bool) {
|
||||||
case p.Accept(m.Drop(doubleQuote3)):
|
case p.Accept(m.Drop(doubleQuote3)):
|
||||||
return sb.String(), true
|
return sb.String(), true
|
||||||
case p.Accept(a.ValidRune):
|
case p.Accept(a.ValidRune):
|
||||||
sb.WriteString(p.Result().String())
|
sb.WriteString(p.Result.String())
|
||||||
case p.Peek(a.InvalidRune):
|
case p.Peek(a.InvalidRune):
|
||||||
p.Error("invalid UTF8 rune")
|
p.Error("invalid UTF8 rune")
|
||||||
return sb.String(), false
|
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 {
|
func appendEscapedRune(p *parse.API, sb *strings.Builder) bool {
|
||||||
s := p.Result().String()
|
s := p.Result.String()
|
||||||
switch s {
|
switch s {
|
||||||
case `\b`:
|
case `\b`:
|
||||||
sb.WriteRune('\b')
|
sb.WriteRune('\b')
|
||||||
|
|
@ -268,10 +268,10 @@ func (t *parser) parseMultiLineLiteralString(p *parse.API) (string, bool) {
|
||||||
case p.Accept(newline):
|
case p.Accept(newline):
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
case p.Peek(controlCharacter):
|
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
|
return sb.String(), false
|
||||||
case p.Accept(a.ValidRune):
|
case p.Accept(a.ValidRune):
|
||||||
sb.WriteString(p.Result().String())
|
sb.WriteString(p.Result.String())
|
||||||
case p.Peek(a.InvalidRune):
|
case p.Peek(a.InvalidRune):
|
||||||
p.Error("invalid UTF8 rune")
|
p.Error("invalid UTF8 rune")
|
||||||
return sb.String(), false
|
return sb.String(), false
|
||||||
|
|
|
||||||
|
|
@ -12,20 +12,27 @@ import (
|
||||||
"github.com/pkg/profile"
|
"github.com/pkg/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const runProfiler = false
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
bytes, _ := ioutil.ReadAll(os.Stdin)
|
bytes, _ := ioutil.ReadAll(os.Stdin)
|
||||||
input := string(bytes)
|
input := string(bytes)
|
||||||
|
|
||||||
toml := BuildGrammar()
|
toml := BuildGrammar()
|
||||||
|
|
||||||
t := profile.Start() //profile.CPUProfile)
|
var result *tokenize.API
|
||||||
var result *tokenize.Result
|
|
||||||
var err error
|
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)
|
result, err = toml.Match(input)
|
||||||
}
|
}
|
||||||
t.Stop()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error in parsing TOML: %s\n", err)
|
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 {
|
if handler, ok := g[name]; ok {
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
return func(t tokenize.API) bool {
|
return func(t *tokenize.API) bool {
|
||||||
if handler, ok := g[name]; ok {
|
if handler, ok := g[name]; ok {
|
||||||
return handler(t)
|
return handler(t)
|
||||||
}
|
}
|
||||||
|
|
@ -186,8 +193,8 @@ func BuildGrammar() tokenize.Handler {
|
||||||
|
|
||||||
R("float", c.Any(
|
R("float", c.Any(
|
||||||
tok.Float64("float", G("standard-float")),
|
tok.Float64("float", G("standard-float")),
|
||||||
tok.ByCallback("float", G("inf-float"), func(t tokenize.API) interface{} {
|
tok.ByCallback("float", G("inf-float"), func(t *tokenize.API) interface{} {
|
||||||
if t.Result().Rune(0) == '-' {
|
if t.Rune(0) == '-' {
|
||||||
return math.Inf(-1)
|
return math.Inf(-1)
|
||||||
}
|
}
|
||||||
return math.Inf(+1)
|
return math.Inf(+1)
|
||||||
|
|
@ -229,14 +236,14 @@ func BuildGrammar() tokenize.Handler {
|
||||||
R("local-date", G("date"))
|
R("local-date", G("date"))
|
||||||
R("local-time", G("time"))
|
R("local-time", G("time"))
|
||||||
|
|
||||||
makeDateTimeValue := func(t tokenize.API) interface{} {
|
makeDateTimeValue := func(t *tokenize.API) interface{} {
|
||||||
layout := ""
|
layout := ""
|
||||||
input := ""
|
input := ""
|
||||||
for _, t := range t.Result().Tokens() {
|
for _, t := range t.Tokens() {
|
||||||
layout += t.Type.(string)
|
layout += t.Type.(string)
|
||||||
input += t.Value.(string)
|
input += t.Value.(string)
|
||||||
}
|
}
|
||||||
t.Result().ClearTokens()
|
t.ClearTokens()
|
||||||
value, err := time.Parse(layout, input)
|
value, err := time.Parse(layout, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Ow, we must implement a way to report date parse errors: %s", err))
|
panic(fmt.Sprintf("Ow, we must implement a way to report date parse errors: %s", err))
|
||||||
|
|
|
||||||
291
parse2/long.toml
291
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
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
BIN
parse2/parse2
BIN
parse2/parse2
Binary file not shown.
Loading…
Reference in New Issue