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 }