diff --git a/.gitignore b/.gitignore index 718bcff..38f2d52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .dub __* +*.a diff --git a/README.md b/README.md index ae4a091..b1c5801 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -======= toml.d. A TOML Parser for D ============================ @@ -36,7 +35,6 @@ auto config = parseFile("/path/to/toml.conf"); TODO -------------- -1) Date support -2) Tables in tables +1) Tables in tables diff --git a/dub.json b/dub.json index a7442d8..9fa5a05 100644 --- a/dub.json +++ b/dub.json @@ -6,6 +6,6 @@ "license": "BSL-1.0", "targetType" : "library", "dependencies": { - "pegged": "0.2.1" + "pegged": "~>0.3.3" } } diff --git a/source/toml/grammar.d b/source/toml/grammar.d index c254587..5ae510f 100644 --- a/source/toml/grammar.d +++ b/source/toml/grammar.d @@ -47,7 +47,10 @@ TOML: # DateTime # ------------------------------------------- - DatetimeValue <~ ([1-9] digit digit digit) "-" (digit digit) "-" (digit digit) "T" (digit digit) ":" (digit digit) ":" (digit digit) "Z" + DatetimeValue <~ ([1-9] digit digit digit) "-" (digit digit) "-" (digit digit) + "T" (digit digit) ":" (digit digit) ":" (digit digit) + ("." digit digit digit digit digit digit)? + (("-" / "+") (digit digit) ":" (digit digit) / "Z")? # # Boolean @@ -186,6 +189,8 @@ unittest { key_string_array = ["abc","cde"] arrayOfArrays = [[1,2], ["a","b"], [1.2, 1.2]] date = 1979-05-27T07:32:00Z + date_two = 1979-05-27T00:32:00-07:00 + anotherdate = 1979-05-27T00:32:00.999999-07:00 multistring = " hello \tworld this is a big diff --git a/source/toml/parser.d b/source/toml/parser.d index 7f6992b..553125b 100644 --- a/source/toml/parser.d +++ b/source/toml/parser.d @@ -3,8 +3,10 @@ module toml.parser; import toml.grammar; import pegged.grammar; import std.array: split; +import std.datetime : SysTime; import std.exception; import std.file : readText; +import std.conv : to; enum TOMLType { String, @@ -29,7 +31,7 @@ struct TOMLValue { union Store { string stringv; long intv; - float floatv; + double floatv; bool boolv; TOMLValue[] arrayv; TOMLValue[string] keygroups; @@ -44,20 +46,27 @@ struct TOMLValue { static if( is(T: string) ) { _store.stringv = val; _type = TOMLType.String; - } - else static if ( is(T: long) ) { - _store.intv = val; - _type = TOMLType.Integer; } + // bool needs to to be assigned before long, because long eats bool! else static if ( is(T: bool) ) { _store.boolv = val; _type = TOMLType.Boolean; } - else static if ( is(T: float) ) { + else static if ( is(T: long) ) { + _store.intv = val; + _type = TOMLType.Integer; + } + else static if ( is(T: double) ) { _store.floatv = val; _type = TOMLType.Float; } - else + else static if ( is(T: SysTime) ) { + // Hack: store the datetime in string representation, SysTime + // cannot be part of Store as it has no default initializer + _store.stringv = val.toISOExtString(); + _type = TOMLType.Datetime; + } + else static assert(0, "Unknown type"); } @@ -132,6 +141,21 @@ struct TOMLValue { return _store.intv; } + double floating() { + enforceTOML(_type==TOMLType.Float); + return _store.floatv; + } + + bool boolean() { + enforceTOML(_type==TOMLType.Boolean); + return _store.boolv; + } + + SysTime datetime() { + enforceTOML(_type==TOMLType.Datetime); + return SysTime.fromISOExtString(_store.stringv); + } + TOMLValue[] array() { enforceTOML(_type==TOMLType.Array); return _store.arrayv; @@ -159,9 +183,11 @@ void _toTOMLDictionary(ParseTree p, ref TOMLValue root, string current_header=nu case "TOML.StringValue": return TOMLValue(v.to!string); case "TOML.FloatValue": - return TOMLValue(v.to!float); + return TOMLValue(v.to!double); case "TOML.BooleanValue": return TOMLValue(v.to!bool); + case "TOML.DatetimeValue": + return TOMLValue(SysTime.fromISOExtString(v.to!string)); case "TOML.Array": TOMLValue[] vals; //first children is the typed array match @@ -221,27 +247,39 @@ TOMLValue parseFile(string filename) { } unittest { + import std.datetime: DateTime, UTC; import std.stdio; enum TEST1 = ` key_string = "string_value" key_array = ["string_1", "string_2"] + float_value = 17.23 [servers] a = 12 + managed = true + last_reboot = 2011-02-23T22:11:43Z [servers.test] a = 12 ports = [1,2,3] + operational = false `; auto d = parse(TEST1); assert(d["key_string"].str == "string_value"); + assert(d["float_value"].floating == 17.23f); writefln("Servers: %s", d["servers"].keys); writefln("All: %s", d.keys); assert(d["servers"]["a"].integer == 12); + assert(d["servers"]["managed"].boolean == true); + writefln("last_reboot: %s", d["servers"]["last_reboot"].datetime.toISOExtString); + assert(d["servers"]["last_reboot"].datetime == + SysTime(DateTime(2011, 2, 23, 22, 11, 43), UTC())); assert(d["servers"]["test"]["a"].integer == 12); + assert(d["servers"]["test"]["ports"].array[0].integer == 1); assert(d["servers"]["test"]["ports"].array[2].integer == 3); + assert(d["servers"]["test"]["operational"].boolean == false); }