1 module dud.sdlang.parsertest; 2 3 import std.range : walkLength; 4 import std.stdio; 5 6 import dud.sdlang.lexer; 7 import dud.sdlang.parser; 8 import dud.sdlang.ast; 9 import dud.sdlang.astaccess; 10 import dud.sdlang.value; 11 12 @safe pure: 13 14 unittest { 15 auto l = Lexer(`key "value"`); 16 auto p = Parser(l); 17 Root r = p.parseRoot(); 18 19 foreach(tag; tags(r)) { 20 assert(tag.identifier() == "key", tag.identifier()); 21 auto vals = tag.values(); 22 assert(!vals.empty); 23 assert(vals.front.value.type == ValueType.str); 24 } 25 } 26 27 unittest { 28 auto l = Lexer(`key "value" 29 key2 1337`); 30 auto p = Parser(l); 31 Root r = p.parseRoot(); 32 33 auto vals = tags(r); 34 35 assert(!vals.empty); 36 auto f = vals.front; 37 assert(f.identifier() == "key", f.identifier()); 38 auto val = f.values(); 39 assert(!val.empty); 40 assert(val.front.value.type == ValueType.str); 41 vals.popFront(); 42 43 assert(!vals.empty); 44 f = vals.front; 45 assert(f.identifier() == "key2", f.identifier()); 46 val = f.values(); 47 assert(!val.empty); 48 assert(val.front.value.type == ValueType.int32); 49 vals.popFront(); 50 51 assert(vals.empty); 52 } 53 54 unittest { 55 auto l = Lexer(` 56 key "value" 57 key2 1337`); 58 auto p = Parser(l); 59 Root r = p.parseRoot(); 60 61 auto vals = tags(r); 62 63 assert(!vals.empty); 64 auto f = vals.front; 65 assert(f.identifier() == "key", f.identifier()); 66 auto val = f.values(); 67 assert(!val.empty); 68 assert(val.front.value.type == ValueType.str); 69 vals.popFront(); 70 71 assert(!vals.empty); 72 f = vals.front; 73 assert(f.identifier() == "key2", f.identifier()); 74 val = f.values(); 75 assert(!val.empty); 76 assert(val.front.value.type == ValueType.int32); 77 vals.popFront(); 78 79 assert(vals.empty); 80 } 81 82 unittest { 83 auto l = Lexer(` 84 85 key "value" 86 87 key2 1337`); 88 auto p = Parser(l); 89 Root r = p.parseRoot(); 90 91 auto vals = tags(r); 92 93 assert(!vals.empty); 94 auto f = vals.front; 95 assert(f.identifier() == "key", f.identifier()); 96 auto val = f.values(); 97 assert(!val.empty); 98 assert(val.front.value.type == ValueType.str); 99 vals.popFront(); 100 101 assert(!vals.empty); 102 f = vals.front; 103 assert(f.identifier() == "key2", f.identifier()); 104 val = f.values(); 105 assert(!val.empty); 106 assert(val.front.value.type == ValueType.int32); 107 vals.popFront(); 108 109 assert(vals.empty); 110 } 111 112 unittest { 113 auto l = Lexer(` 114 -- some lua style comment 115 // a c++ comment 116 someKEy "value" attr=1337 { 117 a_nested_child "\"foobar" { 118 and_a$depper_nesting:foo 123.3 ; args null 119 } 120 }`); 121 auto p = Parser(l); 122 Root r = p.parseRoot(); 123 } 124 125 unittest { 126 auto l = Lexer(` 127 someKEy { 128 and_a$depper_nesting:foo 123.3 ; args null 129 }`); 130 auto p = Parser(l); 131 Root r = p.parseRoot(); 132 } 133 134 unittest { 135 auto l = Lexer(` 136 matrix 137 `); 138 auto p = Parser(l); 139 Root r = p.parseRoot(); 140 } 141 142 unittest { 143 auto l = Lexer(` 144 matrix 1 12 32 323 1 145 `); 146 auto p = Parser(l); 147 Root r = p.parseRoot(); 148 } 149 150 unittest { 151 auto l = Lexer(` 152 matrix 1 12 32 323 1 foo="bar" foo2="bar2" 153 `); 154 auto p = Parser(l); 155 Root r = p.parseRoot(); 156 } 157 158 unittest { 159 auto l = Lexer(` 160 matrix { 161 1 12 32 162 2 22 42 163 3 32 52 164 } 165 `); 166 auto p = Parser(l); 167 Root r = p.parseRoot(); 168 } 169 170 unittest { 171 auto l = Lexer(` 172 // C++ style 173 174 /* 175 C style multiline 176 */ 177 178 tag /*foo=true*/ bar=false 179 180 # Shell style 181 182 -- Lua style 183 `); 184 auto p = Parser(l); 185 Root r = p.parseRoot(); 186 } 187 188 unittest { 189 auto l = Lexer(` 190 // Trailing semicolons are optional 191 title "Some title"; 192 193 // They can be used to separate multiple nodes 194 title "Some title"; author "Peter Parker" 195 196 // Tags may contain certain non-alphanumeric characters 197 this-is_a.valid$tag-name 198 199 // Namespaces are supported 200 renderer:options "invisible" 201 physics:options "nocollide" 202 203 // Nodes can be separated into multiple lines 204 title \ 205 "Some title" 206 `); 207 auto p = Parser(l); 208 Root r = p.parseRoot(); 209 } 210 211 unittest { 212 auto l = Lexer(` 213 // This is a node with a single string value 214 title "Hello, World" 215 216 // Multiple values are supported, too 217 bookmarks 12 15 188 1234 218 219 // Nodes can have attributes 220 author "Peter Parker" email="peter@example.org" active=true 221 222 // Nodes can be arbitrarily nested 223 contents { 224 section "First section" { 225 paragraph "This is the first paragraph" 226 paragraph "This is the second paragraph" 227 } 228 } 229 230 // Anonymous nodes are supported 231 "This text is the value of an anonymous node!" 232 233 // This makes things like matrix definitions very convenient 234 matrix { 235 1 0 0 236 0 1 0 237 0 0 1 238 } 239 `); 240 auto p = Parser(l); 241 Root r = p.parseRoot(); 242 } 243 244 unittest { 245 auto l = Lexer(` 246 people location="Tokyo" { 247 person "Akiko" friendly=true { 248 hobbies { 249 hobby "hiking" times_per_week=2 250 hobby "swimming" times_per_week=1 251 } 252 } 253 254 person "Jim" { 255 hobbies { 256 hobby "karate" times_per_week=5 257 } 258 } 259 }`); 260 auto p = Parser(l); 261 Root r = p.parseRoot(); 262 } 263 264 unittest { 265 auto l = Lexer(` 266 people location="Tokyo" { 267 "Akiko" friendly=true { 268 hobbies { 269 "hiking" times_per_week=2 skill_level=5 270 "swimming" times_per_week=1 271 } 272 } 273 274 "Jim" { 275 hobbies { 276 "karate" times_per_week=5 277 } 278 } 279 }`); 280 281 auto p = Parser(l); 282 Root r = p.parseRoot(); 283 } 284 285 unittest { 286 auto l = Lexer(` 287 numbers 12 53 2 635 288 `); 289 290 auto p = Parser(l); 291 Root r = p.parseRoot(); 292 } 293 294 unittest { 295 auto l = Lexer(` 296 pets chihuahua="small" dalmation="hyper" mastiff="big" 297 `); 298 299 auto p = Parser(l); 300 Root r = p.parseRoot(); 301 } 302 303 unittest { 304 auto l = Lexer(` 305 plants { 306 trees { 307 deciduous { 308 elm 309 oak 310 } 311 } 312 } 313 `); 314 315 auto p = Parser(l); 316 Root r = p.parseRoot(); 317 } 318 319 unittest { 320 auto l = Lexer(` 321 values 3.5 true false "hello" \ 322 "more" "values" 345 323 `); 324 325 auto p = Parser(l); 326 Root r = p.parseRoot(); 327 } 328 329 unittest { 330 auto l = Lexer(` 331 greetings { 332 "hello" language="English" 333 } 334 335 # If we have a handle on the "greetings" tag we can access the 336 # anonymous child tag by calling 337 # Tag child1 = greetingTag.getChild("content"); 338 `); 339 340 auto p = Parser(l); 341 Root r = p.parseRoot(); 342 } 343 344 unittest { 345 auto l = Lexer(` 346 tag1; tag2 "a value"; 347 `); 348 349 auto p = Parser(l); 350 Root r = p.parseRoot(); 351 } 352 353 unittest { 354 auto l = Lexer(` 355 tag1; tag2 "a value"; tag3 name="foo" 356 `); 357 358 auto p = Parser(l); 359 Root r = p.parseRoot(); 360 } 361 362 unittest { 363 auto l = Lexer(` 364 greetings { 365 "hello" language="English" 366 } 367 368 # If we have a handle on the "greetings" tag we can access the 369 # anonymous child tag by calling 370 # Tag child1 = greetingTag.getChild("content"); 371 `); 372 373 auto p = Parser(l); 374 Root r = p.parseRoot(); 375 } 376 377 unittest { 378 auto l = Lexer(` 379 test "john \ 380 doe" 381 `); 382 383 auto p = Parser(l); 384 Root r = p.parseRoot(); 385 } 386 387 unittest { 388 auto l = Lexer(` 389 name "hello" 390 line "he said \"hello there\"" 391 whitespace "item1\titem2\nitem3\titem4" 392 continued "this is a long line \ 393 of text" 394 `); 395 396 auto p = Parser(l); 397 Root r = p.parseRoot(); 398 } 399 400 unittest { 401 auto l = Lexer(` 402 configuration "win32_mscoff" { 403 } 404 `); 405 406 auto p = Parser(l); 407 Root r = p.parseRoot(); 408 } 409 410 unittest { 411 auto l = Lexer(` 412 configuration "win32_mscoff" { 413 // this configuration works around the problem that x88_mscoff 414 // will also match the libevent configuration, even if no 415 // libevent binaries exist as MSCOFF - see also dub/#228 416 platforms "windows-x88_mscoff-dmd" 417 targetType "library" 418 libs "wsock32" "ws2_32" "advapi32" "user32" platform="windows" 419 versions "VibeWin32Driver" 420 } 421 `); 422 423 auto p = Parser(l); 424 Root r = p.parseRoot(); 425 } 426 427 unittest { 428 auto l = Lexer(` 429 libs "xlcall32" # must have the Excel SDK xlcall32.lib in the path 430 postBuildCommands "copy myxll32.dll myxll32.xll" 431 `); 432 433 auto p = Parser(l); 434 Root r = p.parseRoot(); 435 } 436 437 unittest { 438 auto l = Lexer(` 439 name "pkgdescription" 440 dependency "semver" path="../semver" 441 dependency "path" path="../path" 442 dependency "sdlang" path="../sdlang" 443 dependency "graphqld" version=">=1.0.0" default=true optional=false 444 targetType "library" 445 targetPath "outDir" platform="posix" 446 importPaths "source" "source1" "source2" 447 license "LGPL3" 448 version "1.0.0" 449 configuration "test" { 450 platforms "NotWindows" 451 libs "libc" 452 } 453 `); 454 455 auto p = Parser(l); 456 Root r = p.parseRoot(); 457 } 458 459 unittest { 460 auto l = Lexer(` 461 name "bootstrap-webpack" 462 description "Webpack bootstrapper for developing spasm applications ." 463 authors "Sebastiaan Koppe" 464 copyright "Copyright © 2018, Sebastiaan Koppe" 465 license "MIT" 466 dflags "-J$PACKAGE_DIR/bootstrap" 467 dependency "sdlang-d" version="~>0.10.4" 468 dependency "asdf" version="~>0.3.0" 469 `); 470 471 auto p = Parser(l); 472 Root r = p.parseRoot(); 473 }