1 module toml.grammar; 2 3 import pegged.grammar; 4 5 enum PEG = ` 6 TOML: 7 8 Document <- (ValueLine)* KeyGroup* 9 10 KeyGroup <- Header ValueLine* 11 12 Header <- ignore "[" HeaderName "]" line_end 13 HeaderName <- qualifiedIdentifier 14 15 ValueLine <- :ignore Name :ws :"=" :ws Value line_end 16 Name <- identifier 17 Value <- DatetimeValue / StringValue / FloatValue / IntegerValue / BooleanValue / Array 18 19 20 # 21 # Strings 22 # ----------------------------------------------------------------- 23 24 StringValue <~ :doublequote (!doublequote Char)* :doublequote 25 Char <~ backslash ( doublequote # '\' Escapes 26 / quote 27 / backslash 28 / [bfnrt] 29 / [0-2][0-7][0-7] 30 / [0-7][0-7]? 31 / 'x' Hex Hex 32 / 'u' Hex Hex Hex Hex 33 / 'U' Hex Hex Hex Hex Hex Hex Hex Hex 34 ) 35 / . # Or any char, really 36 Hex <- [0-9a-fA-F] 37 38 # 39 # Numbers 40 # ------------------------------------------- 41 42 Digit <- [0-9] 43 IntegerValue <~ "-"? [1-9] digit* 44 FloatValue <~ IntegerValue "." digit+ 45 46 # 47 # DateTime 48 # ------------------------------------------- 49 50 DatetimeValue <~ ([1-9] digit digit digit) "-" (digit digit) "-" (digit digit) "T" (digit digit) ":" (digit digit) ":" (digit digit) "Z" 51 52 # 53 # Boolean 54 # ------------------------------------------- 55 56 BooleanValue <- ("true" / "false") 57 58 # 59 # Arrays 60 # ------------------------------------------- 61 62 Array <- EmptyArray / DatetimeArray / StringArray / IntegerArray / FloatArray / ArrayOfArray 63 EmptyArray <- :"[" ws :"]" 64 StringArray <- :"[" ws StringValue (ws :"," ws StringValue)* ws :"]" 65 IntegerArray <- :"[" ws IntegerValue (ws :"," ws IntegerValue)* ws :"]" 66 FloatArray <- :"[" ws FloatValue (ws :"," ws FloatValue)* ws :"]" 67 DatetimeArray <- :"[" ws DatetimeValue (ws :"," ws DatetimeValue)* ws :"]" 68 ArrayOfArray <- :"[" ws Array (ws :"," ws Array)* ws :"]" 69 70 71 # 72 # Helpers 73 # ----------------------------------------- 74 75 line_end <- ws comment? !(!eol .) 76 ignore <- :(comment / space / eol)* 77 comment <- "#" (!eol .)* 78 ws <- :space* 79 80 81 `; 82 83 //pragma(msg, grammar(PEG)); 84 85 mixin(grammar(PEG)); 86 87 unittest { 88 import std.stdio; 89 import pegged.tester.grammartester; 90 91 auto grtest = new GrammarTester!(TOML, "Document"); 92 93 grtest.assertSimilar(`key = 1`, ` 94 Document -> { 95 ValueLine -> { 96 Name 97 Value -> { 98 IntegerValue 99 } 100 } 101 } 102 `); 103 104 grtest.assertSimilar(`key = "hello world"`, ` 105 Document -> { 106 ValueLine -> { 107 Name 108 Value -> { 109 StringValue 110 } 111 } 112 } 113 `); 114 115 auto header_checker = new GrammarTester!(TOML, "Header"); 116 header_checker.assertSimilar("[test]", ` 117 Header -> 118 HeaderName 119 `); 120 121 auto intArray = new GrammarTester!(TOML, "IntegerArray"); 122 intArray.assertSimilar(`[1,2]`,` 123 IntegerArray -> { 124 IntegerValue 125 IntegerValue 126 } 127 `); 128 129 auto emptyarray = new GrammarTester!(TOML, "EmptyArray"); 130 emptyarray.assertSimilar(`[ ]`,` 131 EmptyArray 132 `); 133 134 135 auto arrayOfArray = new GrammarTester!(TOML, "ArrayOfArray"); 136 arrayOfArray.assertSimilar(`[[1,2] ]`,` 137 ArrayOfArray -> { 138 Array -> { 139 IntegerArray -> { 140 IntegerValue 141 IntegerValue 142 } 143 } 144 } 145 `); 146 147 auto keygroup_checker = new GrammarTester!(TOML, "KeyGroup"); 148 keygroup_checker.assertSimilar(` 149 [test] 150 key = 1 151 `, ` 152 KeyGroup -> { 153 Header -> { 154 HeaderName 155 } 156 ValueLine -> { 157 Name 158 Value -> { 159 IntegerValue 160 } 161 } 162 } 163 `); 164 165 auto date_checker = new GrammarTester!(TOML, "DatetimeValue"); 166 date_checker.assertSimilar("1979-05-27T07:32:00Z", ` 167 DatetimeValue 168 `); 169 170 171 enum TEST1 = ` 172 key_string = "hello" 173 key_integer = 10 174 key_bool = true 175 `; 176 177 auto test1 = TOML(TEST1); 178 writeln(test1); 179 180 enum TEST2 = ` 181 key_1 = "test" 182 [keygroup] 183 key_string = "hello" 184 key_integer = 10 185 key_bool = true 186 key_string_array = ["abc","cde"] 187 arrayOfArrays = [[1,2], ["a","b"], [1.2, 1.2]] 188 date = 1979-05-27T07:32:00Z 189 multistring = " 190 hello \tworld 191 this is a big 192 multiline 193 string 194 " 195 196 [servers] 197 198 [servers.alpha] 199 z = 1 200 `; 201 202 auto test2 = TOML(TEST2); 203 writeln(test2); 204 }