slidefield 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +674 -0
  5. data/README.md +254 -0
  6. data/Rakefile +7 -0
  7. data/bin/slidefield +89 -0
  8. data/examples/complete/assets/K2.jpg +0 -0
  9. data/examples/complete/assets/gobi.jpg +0 -0
  10. data/examples/complete/assets/mount_everest.jpg +0 -0
  11. data/examples/complete/assets/sahara.jpg +0 -0
  12. data/examples/complete/main.sfp +7 -0
  13. data/examples/complete/slides/deserts.sfi +19 -0
  14. data/examples/complete/slides/mountains.sfi +25 -0
  15. data/examples/complete/templates.sfi +95 -0
  16. data/examples/complete/variables.sfi +6 -0
  17. data/examples/minimal/main.sfp +43 -0
  18. data/examples/minimal/ruby-logo.png +0 -0
  19. data/lib/slidefield/animator.rb +104 -0
  20. data/lib/slidefield/errors.rb +6 -0
  21. data/lib/slidefield/interpreter.rb +414 -0
  22. data/lib/slidefield/object_data.rb +78 -0
  23. data/lib/slidefield/object_manager.rb +29 -0
  24. data/lib/slidefield/object_rules.rb +79 -0
  25. data/lib/slidefield/objects/_base.rb +29 -0
  26. data/lib/slidefield/objects/_root.rb +10 -0
  27. data/lib/slidefield/objects/animation.rb +10 -0
  28. data/lib/slidefield/objects/debug.rb +18 -0
  29. data/lib/slidefield/objects/image.rb +47 -0
  30. data/lib/slidefield/objects/include.rb +9 -0
  31. data/lib/slidefield/objects/layout.rb +10 -0
  32. data/lib/slidefield/objects/rect.rb +44 -0
  33. data/lib/slidefield/objects/slide.rb +43 -0
  34. data/lib/slidefield/objects/song.rb +31 -0
  35. data/lib/slidefield/objects/text.rb +57 -0
  36. data/lib/slidefield/parser.rb +99 -0
  37. data/lib/slidefield/version.rb +3 -0
  38. data/lib/slidefield/viewer.rb +89 -0
  39. data/lib/slidefield.rb +27 -0
  40. data/slidefield.gemspec +27 -0
  41. data/test/helper.rb +11 -0
  42. data/test/resources/include_sub.sfp +1 -0
  43. data/test/resources/parse_error.sfp +1 -0
  44. data/test/resources/recursive_include.sfp +1 -0
  45. data/test/resources/sub/include_parent.sfp +1 -0
  46. data/test/resources/unclosed_object.sfp +2 -0
  47. data/test/resources/unknown_object.sfp +1 -0
  48. data/test/resources/wrong_template.sfp +4 -0
  49. data/test/test_animator.rb +244 -0
  50. data/test/test_examples.rb +29 -0
  51. data/test/test_interpreter.rb +1766 -0
  52. data/test/test_object_data.rb +108 -0
  53. data/test/test_object_manager.rb +48 -0
  54. data/test/test_object_rules.rb +87 -0
  55. data/test/test_parser.rb +408 -0
  56. metadata +199 -0
@@ -0,0 +1,1766 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ module SlideField::ObjectRules
4
+ class Parent < Base
5
+ def rules
6
+ child :child
7
+ child :value
8
+ child :aaaa
9
+ end
10
+ end
11
+
12
+ class Child < Base
13
+ end
14
+
15
+ class Type < Base
16
+ def rules
17
+ property :test, :point, [0,0]
18
+ end
19
+ end
20
+
21
+ class Value < Base
22
+ def rules
23
+ property :num, :integer, 0
24
+ property :num2, :integer, 0
25
+ property :str, :string, ""
26
+ end
27
+ end
28
+
29
+ class Picky < Base
30
+ def rules
31
+ property :king_name, :string
32
+ child :minOne, 1
33
+ child :minTwo, 2
34
+ child :maxOne, 1, 1
35
+ end
36
+ end
37
+ end
38
+
39
+ class TestInterpreter < MiniTest::Test
40
+ def setup
41
+ @col_cache = []
42
+ @interpreter = SlideField::Interpreter.new
43
+ @path = File.expand_path 'resources', __dir__
44
+ end
45
+
46
+ def slice(val, line)
47
+ @col_cache[line] = 0 unless @col_cache[line]
48
+ col = @col_cache[line] += 1
49
+
50
+ line_cache = MiniTest::Mock.new
51
+ line_cache.expect :line_and_column, [line, col], [Object]
52
+
53
+ pos = Parslet::Position.new val, 0
54
+ Parslet::Slice.new pos, val, line_cache
55
+ end
56
+
57
+ def test_excerpt_parse_error
58
+ error = assert_raises SlideField::ParseError do
59
+ @interpreter.run_string '"'
60
+ end
61
+
62
+ assert_match /\A\[input\] /, error.message
63
+ refute_match /\A\[input\] \[input\]/, error.message
64
+ assert_match /\n\t"\n\t\^\Z/, error.message
65
+ end
66
+
67
+ def test_excerpt_interpreter_error
68
+ error = assert_raises SlideField::InterpreterError do
69
+ @interpreter.run_string "\\object\n"
70
+ end
71
+
72
+ assert_match /\A\[input\] /, error.message
73
+ assert_match /\n\t\\object\n\t \^\Z/, error.message
74
+ end
75
+
76
+ def test_strip_excerpt
77
+ error = assert_raises SlideField::InterpreterError do
78
+ @interpreter.run_string "\t\t\t\t \t \\object"
79
+ end
80
+
81
+ assert_match /\A\[input\] /, error.message
82
+ assert_match /\n\t\\object\n\t \^\Z/, error.message
83
+ end
84
+
85
+ def test_run_interpreter_validation
86
+ error = assert_raises SlideField::InterpreterError do
87
+ @interpreter.run_string "% nothing\n"
88
+ end
89
+
90
+ assert_match /\A\[input\] /, error.message
91
+ assert_match /line 0 char 0\Z/, error.message
92
+ end
93
+
94
+ def test_empty_tree
95
+ o = SlideField::ObjectData.new :parent, 'loc'
96
+ @interpreter.interpret_tree "", o
97
+ end
98
+
99
+ def test_unsupported_object
100
+ tokens = [
101
+ {:object=>{:type=>slice('aaaa', 1)}},
102
+ ]
103
+
104
+ o = SlideField::ObjectData.new :parent, 'loc'
105
+ error = assert_raises RuntimeError do
106
+ @interpreter.interpret_tree tokens, o
107
+ end
108
+
109
+ assert_equal "Unsupported object 'aaaa'", error.message
110
+ end
111
+
112
+ def test_unsupported_statement
113
+ tokens = [
114
+ {:hello_world=>{}},
115
+ ]
116
+
117
+ o = SlideField::ObjectData.new :child, 'loc'
118
+ error = assert_raises RuntimeError do
119
+ @interpreter.interpret_tree tokens, o
120
+ end
121
+
122
+ assert_equal "Unsupported statement 'hello_world'", error.message
123
+ end
124
+
125
+ def test_unsupported_type
126
+ tokens = [
127
+ {:assignment=>{
128
+ :variable=>slice('var', 1),
129
+ :operator=>slice('=', 1),
130
+ :value=>{:filters=>[], :dog_food=>slice('yum', 1)}
131
+ }},
132
+ ]
133
+
134
+ o = SlideField::ObjectData.new :child, 'loc'
135
+ error = assert_raises RuntimeError do
136
+ @interpreter.interpret_tree tokens, o
137
+ end
138
+
139
+ assert_equal "Unsupported type 'dog_food' at line 1 char 3", error.message
140
+ end
141
+
142
+ def test_unsupported_operator
143
+ tokens = [
144
+ {:assignment=>{
145
+ :variable=>slice('var', 1),
146
+ :operator=>slice('baconize', 1),
147
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
148
+ }},
149
+ ]
150
+
151
+ o = SlideField::ObjectData.new :child, 'loc'
152
+ error = assert_raises RuntimeError do
153
+ @interpreter.interpret_tree tokens, o
154
+ end
155
+
156
+ assert_equal "Unsupported operator 'baconize' at line 1 char 2", error.message
157
+ end
158
+
159
+ def test_set_already_defined
160
+ tokens = [
161
+ {:assignment=>{
162
+ :variable=>slice('var', 1),
163
+ :operator=>slice('=', 1),
164
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
165
+ }},
166
+ ]
167
+
168
+ o = SlideField::ObjectData.new :child, 'loc'
169
+ o.set :var, 1
170
+
171
+ error = assert_raises SlideField::InterpreterError do
172
+ @interpreter.interpret_tree tokens, o
173
+ end
174
+
175
+ assert_equal "Variable 'var' is already defined at line 1 char 1", error.message
176
+ end
177
+
178
+ def test_set_integer
179
+ tokens = [
180
+ {:assignment=>{
181
+ :variable=>slice('var', 1),
182
+ :operator=>slice('=', 1),
183
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
184
+ }},
185
+ ]
186
+
187
+ o = SlideField::ObjectData.new :child, 'loc'
188
+ @interpreter.interpret_tree tokens, o
189
+
190
+ assert_equal 42, o.get(:var)
191
+ assert_equal :integer, o.var_type(:var)
192
+ assert_equal 'line 1 char 3', o.var_loc(:var)
193
+ end
194
+
195
+ def test_set_point
196
+ tokens = [
197
+ {:assignment=>{
198
+ :variable=>slice('var', 1),
199
+ :operator=>slice('=', 1),
200
+ :value=>{:filters=>[], :point=>slice('12x34', 1)}
201
+ }},
202
+ ]
203
+
204
+ o = SlideField::ObjectData.new :child, 'loc'
205
+ @interpreter.interpret_tree tokens, o
206
+
207
+ assert_equal [12,34], o.get(:var)
208
+ assert_equal :point, o.var_type(:var)
209
+ assert_equal 'line 1 char 3', o.var_loc(:var)
210
+ end
211
+
212
+ def test_set_string
213
+ tokens = [
214
+ {:assignment=>{
215
+ :variable=>slice('var', 1),
216
+ :operator=>slice('=', 1),
217
+ :value=>{:filters=>[], :string=>slice('"hello"', 1)}
218
+ }},
219
+ ]
220
+
221
+ o = SlideField::ObjectData.new :child, 'loc'
222
+ @interpreter.interpret_tree tokens, o
223
+
224
+ assert_equal 'hello', o.get(:var)
225
+ assert_equal :string, o.var_type(:var)
226
+ assert_equal 'line 1 char 3', o.var_loc(:var)
227
+ end
228
+
229
+ def test_set_color
230
+ tokens = [
231
+ {:assignment=>{
232
+ :variable=>slice('var', 1),
233
+ :operator=>slice('=', 1),
234
+ :value=>{:filters=>[], :color=>slice('#C0FF33FF', 1)}
235
+ }},
236
+ ]
237
+
238
+ o = SlideField::ObjectData.new :child, 'loc'
239
+ @interpreter.interpret_tree tokens, o
240
+
241
+ assert_equal [192, 255, 51, 255], o.get(:var)
242
+ assert_equal :color, o.var_type(:var)
243
+ assert_equal 'line 1 char 3', o.var_loc(:var)
244
+ end
245
+
246
+ def test_set_boolean
247
+ tokens = [
248
+ {:assignment=>{
249
+ :variable=>slice('var', 1),
250
+ :operator=>slice('=', 1),
251
+ :value=>{:filters=>[], :boolean=>slice(':true', 1)}
252
+ }},
253
+ ]
254
+
255
+ o = SlideField::ObjectData.new :child, 'loc'
256
+ @interpreter.interpret_tree tokens, o
257
+
258
+ assert_equal true, o.get(:var)
259
+ assert_equal :boolean, o.var_type(:var)
260
+ assert_equal 'line 1 char 3', o.var_loc(:var)
261
+ end
262
+
263
+ def test_set_object
264
+ object = {
265
+ :type=>slice('type', 2),
266
+ :value=>{:filters=>[], :point=>slice('42x42', 2)}
267
+ }
268
+
269
+ tokens = [{
270
+ :assignment=>{
271
+ :variable=>slice('var', 1),
272
+ :operator=>slice('=', 1),
273
+ :value=>{:filters=>[], :object=>object}
274
+ }
275
+ }]
276
+
277
+ o = SlideField::ObjectData.new :child, 'loc'
278
+ o.include_path = 'include/path/'
279
+ o.context = 'the/file.sfp'
280
+
281
+ @interpreter.interpret_tree tokens, o
282
+ val = o.get(:var)
283
+
284
+ assert_equal object, o.get(:var)
285
+ assert_equal :object, o.var_type(:var)
286
+ assert_equal 'line 2 char 1', o.var_loc(:var)
287
+ end
288
+
289
+ def test_set_identifier
290
+ tokens = [
291
+ {:assignment=>{
292
+ :variable=>slice('var', 1),
293
+ :operator=>slice('=', 1),
294
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
295
+ }},
296
+ ]
297
+
298
+ o = SlideField::ObjectData.new :child, 'loc'
299
+ o.set :test, 'hello', 'loc', :string
300
+
301
+ @interpreter.interpret_tree tokens, o
302
+ assert_equal 'hello', o.get(:var)
303
+ assert_equal :string, o.var_type(:var)
304
+ assert_equal 'line 1 char 3', o.var_loc(:var)
305
+ end
306
+
307
+ def test_set_undefined_identifier
308
+ tokens = [
309
+ {:assignment=>{
310
+ :variable=>slice('var', 1),
311
+ :operator=>slice('=', 1),
312
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
313
+ }},
314
+ ]
315
+
316
+ o = SlideField::ObjectData.new :child, 'loc'
317
+ error = assert_raises SlideField::InterpreterError do
318
+ @interpreter.interpret_tree tokens, o
319
+ end
320
+
321
+ assert_equal "Undefined variable 'test' at line 1 char 3", error.message
322
+ end
323
+
324
+
325
+ def test_set_wrong_type
326
+ tokens = [
327
+ {:assignment=>{
328
+ :variable=>slice('test', 1),
329
+ :operator=>slice('=', 1),
330
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
331
+ }},
332
+ ]
333
+
334
+ o = SlideField::ObjectData.new :type, 'loc'
335
+ error = assert_raises SlideField::InterpreterError do
336
+ @interpreter.interpret_tree tokens, o
337
+ end
338
+
339
+ assert_equal "Unexpected 'integer', expecting 'point' for property 'test' at line 1 char 3", error.message
340
+ end
341
+
342
+ def test_add_undefined
343
+ tokens = [
344
+ {:assignment=>{
345
+ :variable=>slice('var', 1),
346
+ :operator=>slice('+=', 1),
347
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
348
+ }},
349
+ ]
350
+
351
+ o = SlideField::ObjectData.new :child, 'loc'
352
+ error = assert_raises SlideField::InterpreterError do
353
+ @interpreter.interpret_tree tokens, o
354
+ end
355
+
356
+ assert_equal "Undefined variable 'var' at line 1 char 1", error.message
357
+ end
358
+
359
+ def test_add_incompatible
360
+ tokens = [
361
+ {:assignment=>{
362
+ :variable=>slice('var', 1),
363
+ :operator=>slice('+=', 1),
364
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
365
+ }},
366
+ ]
367
+
368
+ o = SlideField::ObjectData.new :child, 'loc'
369
+ o.set :var, 'test', 'loc', :string
370
+
371
+ error = assert_raises SlideField::InterpreterError do
372
+ @interpreter.interpret_tree tokens, o
373
+ end
374
+
375
+ assert_equal "Unexpected 'integer', expecting 'string' for variable or property 'var' at line 1 char 3", error.message
376
+ end
377
+
378
+ def test_add_integer
379
+ tokens = [
380
+ {:assignment=>{
381
+ :variable=>slice('var', 1),
382
+ :operator=>slice('+=', 1),
383
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
384
+ }},
385
+ ]
386
+
387
+ o = SlideField::ObjectData.new :child, 'loc'
388
+ o.set :var, 42, 'loc', :integer
389
+
390
+ @interpreter.interpret_tree tokens, o
391
+ assert_equal 84, o.get(:var)
392
+ assert_equal :integer, o.var_type(:var)
393
+ assert_equal 'line 1 char 3', o.var_loc(:var)
394
+ end
395
+
396
+ def test_add_point
397
+ tokens = [
398
+ {:assignment=>{
399
+ :variable=>slice('var', 1),
400
+ :operator=>slice('+=', 1),
401
+ :value=>{:filters=>[], :point=>slice('42x42', 1)}
402
+ }},
403
+ ]
404
+
405
+ o = SlideField::ObjectData.new :child, 'loc'
406
+ o.set :var, [42,42], 'loc', :point
407
+
408
+ @interpreter.interpret_tree tokens, o
409
+ assert_equal [84,84], o.get(:var)
410
+ assert_equal :point, o.var_type(:var)
411
+ assert_equal 'line 1 char 3', o.var_loc(:var)
412
+ end
413
+
414
+ def test_add_string
415
+ tokens = [
416
+ {:assignment=>{
417
+ :variable=>slice('var', 1),
418
+ :operator=>slice('+=', 1),
419
+ :value=>{:filters=>[], :string=>slice('" world"', 1)}
420
+ }},
421
+ ]
422
+
423
+ o = SlideField::ObjectData.new :child, 'loc'
424
+ o.set :var, 'hello', 'loc', :string
425
+
426
+ @interpreter.interpret_tree tokens, o
427
+ assert_equal 'hello world', o.get(:var)
428
+ assert_equal :string, o.var_type(:var)
429
+ assert_equal 'line 1 char 3', o.var_loc(:var)
430
+ end
431
+
432
+ def test_add_color
433
+ tokens = [
434
+ {:assignment=>{
435
+ :variable=>slice('var', 1),
436
+ :operator=>slice('+=', 1),
437
+ :value=>{:filters=>[], :color=>slice('#01010101', 1)}
438
+ }},
439
+ ]
440
+
441
+ o = SlideField::ObjectData.new :child, 'loc'
442
+ o.set :var, [0, 0, 0, 0], 'loc', :color
443
+
444
+ @interpreter.interpret_tree tokens, o
445
+ assert_equal [1, 1, 1, 1], o.get(:var)
446
+ assert_equal :color, o.var_type(:var)
447
+ assert_equal 'line 1 char 3', o.var_loc(:var)
448
+ end
449
+
450
+ def test_add_color_overflow
451
+ tokens = [
452
+ {:assignment=>{
453
+ :variable=>slice('var', 1),
454
+ :operator=>slice('+=', 1),
455
+ :value=>{:filters=>[], :color=>slice('#01010101', 1)}
456
+ }},
457
+ ]
458
+
459
+ o = SlideField::ObjectData.new :child, 'loc'
460
+ o.set :var, [255, 255, 255, 255], 'loc', :color
461
+
462
+ @interpreter.interpret_tree tokens, o
463
+ assert_equal [255, 255, 255, 255], o.get(:var)
464
+ assert_equal :color, o.var_type(:var)
465
+ assert_equal 'line 1 char 3', o.var_loc(:var)
466
+ end
467
+
468
+ def test_add_boolean
469
+ tokens = [
470
+ {:assignment=>{
471
+ :variable=>slice('var', 1),
472
+ :operator=>slice('+=', 1),
473
+ :value=>{:filters=>[], :boolean=>slice(':true', 1)}
474
+ }},
475
+ ]
476
+
477
+ o = SlideField::ObjectData.new :child, 'loc'
478
+ o.set :var, true, 'loc', :boolean
479
+
480
+ error = assert_raises SlideField::InterpreterError do
481
+ @interpreter.interpret_tree tokens, o
482
+ end
483
+
484
+ assert_equal "Invalid operator '+=' for type 'boolean' at line 1 char 2", error.message
485
+ end
486
+
487
+ def test_add_identifier
488
+ tokens = [
489
+ {:assignment=>{
490
+ :variable=>slice('var', 1),
491
+ :operator=>slice('+=', 1),
492
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
493
+ }},
494
+ ]
495
+
496
+ o = SlideField::ObjectData.new :child, 'loc'
497
+ o.set :var, 'hello', 'loc', :string
498
+ o.set :test, ' world', 'loc', :string
499
+
500
+ @interpreter.interpret_tree tokens, o
501
+ assert_equal 'hello world', o.get(:var)
502
+ assert_equal :string, o.var_type(:var)
503
+ assert_equal 'line 1 char 3', o.var_loc(:var)
504
+ end
505
+
506
+ def test_sub_undefined
507
+ tokens = [
508
+ {:assignment=>{
509
+ :variable=>slice('var', 1),
510
+ :operator=>slice('-=', 1),
511
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
512
+ }},
513
+ ]
514
+
515
+ o = SlideField::ObjectData.new :child, 'loc'
516
+ error = assert_raises SlideField::InterpreterError do
517
+ @interpreter.interpret_tree tokens, o
518
+ end
519
+
520
+ assert_equal "Undefined variable 'var' at line 1 char 1", error.message
521
+ end
522
+
523
+ def test_sub_incompatible
524
+ tokens = [
525
+ {:assignment=>{
526
+ :variable=>slice('var', 1),
527
+ :operator=>slice('-=', 1),
528
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
529
+ }},
530
+ ]
531
+
532
+ o = SlideField::ObjectData.new :child, 'loc'
533
+ o.set :var, 'test', 'loc', :string
534
+
535
+ error = assert_raises SlideField::InterpreterError do
536
+ @interpreter.interpret_tree tokens, o
537
+ end
538
+
539
+ assert_equal "Unexpected 'integer', expecting 'string' for variable or property 'var' at line 1 char 3", error.message
540
+ end
541
+
542
+ def test_sub_integer
543
+ tokens = [
544
+ {:assignment=>{
545
+ :variable=>slice('var', 1),
546
+ :operator=>slice('-=', 1),
547
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
548
+ }},
549
+ ]
550
+
551
+ o = SlideField::ObjectData.new :child, 'loc'
552
+ o.set :var, 44, 'loc', :integer
553
+
554
+ @interpreter.interpret_tree tokens, o
555
+ assert_equal 2, o.get(:var)
556
+ assert_equal :integer, o.var_type(:var)
557
+ assert_equal 'line 1 char 3', o.var_loc(:var)
558
+ end
559
+
560
+ def test_sub_point
561
+ tokens = [
562
+ {:assignment=>{
563
+ :variable=>slice('var', 1),
564
+ :operator=>slice('-=', 1),
565
+ :value=>{:filters=>[], :point=>slice('42x42', 1)}
566
+ }},
567
+ ]
568
+
569
+ o = SlideField::ObjectData.new :child, 'loc'
570
+ o.set :var, [46,44], 'loc', :point
571
+
572
+ @interpreter.interpret_tree tokens, o
573
+ assert_equal [4,2], o.get(:var)
574
+ assert_equal :point, o.var_type(:var)
575
+ assert_equal 'line 1 char 3', o.var_loc(:var)
576
+ end
577
+
578
+ def test_sub_string
579
+ tokens = [
580
+ {:assignment=>{
581
+ :variable=>slice('var', 1),
582
+ :operator=>slice('-=', 1),
583
+ :value=>{:filters=>[], :string=>slice('" world"', 1)}
584
+ }},
585
+ {:assignment=>{
586
+ :variable=>slice('var', 2),
587
+ :operator=>slice('-=', 2),
588
+ :value=>{:filters=>[], :string=>slice('"test"', 2)}
589
+ }},
590
+ ]
591
+
592
+ o = SlideField::ObjectData.new :child, 'loc'
593
+ o.set :var, 'hello world world', 'loc', :string
594
+
595
+ @interpreter.interpret_tree tokens, o
596
+ assert_equal 'hello', o.get(:var)
597
+ assert_equal :string, o.var_type(:var)
598
+ assert_equal 'line 2 char 3', o.var_loc(:var)
599
+ end
600
+
601
+ def test_sub_color
602
+ tokens = [
603
+ {:assignment=>{
604
+ :variable=>slice('var', 1),
605
+ :operator=>slice('-=', 1),
606
+ :value=>{:filters=>[], :color=>slice('#01010101', 1)}
607
+ }},
608
+ ]
609
+
610
+ o = SlideField::ObjectData.new :child, 'loc'
611
+ o.set :var, [1, 1, 1, 1], 'loc', :color
612
+
613
+ @interpreter.interpret_tree tokens, o
614
+ assert_equal [0, 0, 0, 0], o.get(:var)
615
+ assert_equal :color, o.var_type(:var)
616
+ assert_equal 'line 1 char 3', o.var_loc(:var)
617
+ end
618
+
619
+ def test_sub_color_underflow
620
+ tokens = [
621
+ {:assignment=>{
622
+ :variable=>slice('var', 1),
623
+ :operator=>slice('-=', 1),
624
+ :value=>{:filters=>[], :color=>slice('#01010101', 1)}
625
+ }},
626
+ ]
627
+
628
+ o = SlideField::ObjectData.new :child, 'loc'
629
+ o.set :var, [0, 0, 0, 0], 'loc', :color
630
+
631
+ @interpreter.interpret_tree tokens, o
632
+ assert_equal [0, 0, 0, 0], o.get(:var)
633
+ assert_equal :color, o.var_type(:var)
634
+ assert_equal 'line 1 char 3', o.var_loc(:var)
635
+ end
636
+
637
+ def test_sub_boolean
638
+ tokens = [
639
+ {:assignment=>{
640
+ :variable=>slice('var', 1),
641
+ :operator=>slice('-=', 1),
642
+ :value=>{:filters=>[], :boolean=>slice(':true', 1)}
643
+ }},
644
+ ]
645
+
646
+ o = SlideField::ObjectData.new :child, 'loc'
647
+ o.set :var, true, 'loc', :boolean
648
+
649
+ error = assert_raises SlideField::InterpreterError do
650
+ @interpreter.interpret_tree tokens, o
651
+ end
652
+
653
+ assert_equal "Invalid operator '-=' for type 'boolean' at line 1 char 2", error.message
654
+ end
655
+
656
+ def test_sub_identifier
657
+ tokens = [
658
+ {:assignment=>{
659
+ :variable=>slice('var', 1),
660
+ :operator=>slice('-=', 1),
661
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
662
+ }},
663
+ ]
664
+
665
+ o = SlideField::ObjectData.new :child, 'loc'
666
+ o.set :var, 3, 'loc', :integer
667
+ o.set :test, 2, 'loc', :integer
668
+
669
+ @interpreter.interpret_tree tokens, o
670
+ assert_equal 1, o.get(:var)
671
+ assert_equal :integer, o.var_type(:var)
672
+ assert_equal 'line 1 char 3', o.var_loc(:var)
673
+ end
674
+
675
+ def test_mul_undefined
676
+ tokens = [
677
+ {:assignment=>{
678
+ :variable=>slice('var', 1),
679
+ :operator=>slice('*=', 1),
680
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
681
+ }},
682
+ ]
683
+
684
+ o = SlideField::ObjectData.new :child, 'loc'
685
+ error = assert_raises SlideField::InterpreterError do
686
+ @interpreter.interpret_tree tokens, o
687
+ end
688
+
689
+ assert_equal "Undefined variable 'var' at line 1 char 1", error.message
690
+ end
691
+
692
+ def test_mul_incompatible
693
+ tokens = [
694
+ {:assignment=>{
695
+ :variable=>slice('var', 1),
696
+ :operator=>slice('*=', 1),
697
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
698
+ }},
699
+ ]
700
+
701
+ o = SlideField::ObjectData.new :child, 'loc'
702
+ o.set :var, 'test', 'loc', :string
703
+
704
+ error = assert_raises SlideField::InterpreterError do
705
+ @interpreter.interpret_tree tokens, o
706
+ end
707
+
708
+ assert_equal "Unexpected 'integer', expecting 'string' for variable or property 'var' at line 1 char 3", error.message
709
+ end
710
+
711
+ def test_mul_integer
712
+ tokens = [
713
+ {:assignment=>{
714
+ :variable=>slice('var', 1),
715
+ :operator=>slice('*=', 1),
716
+ :value=>{:filters=>[], :integer=>slice('4', 1)}
717
+ }},
718
+ ]
719
+
720
+ o = SlideField::ObjectData.new :child, 'loc'
721
+ o.set :var, 4, 'loc', :integer
722
+
723
+ @interpreter.interpret_tree tokens, o
724
+ assert_equal 16, o.get(:var)
725
+ assert_equal :integer, o.var_type(:var)
726
+ assert_equal 'line 1 char 3', o.var_loc(:var)
727
+ end
728
+
729
+ def test_mul_point
730
+ tokens = [
731
+ {:assignment=>{
732
+ :variable=>slice('var', 1),
733
+ :operator=>slice('*=', 1),
734
+ :value=>{:filters=>[], :point=>slice('4x2', 1)}
735
+ }},
736
+ ]
737
+
738
+ o = SlideField::ObjectData.new :child, 'loc'
739
+ o.set :var, [4,2], 'loc', :point
740
+
741
+ @interpreter.interpret_tree tokens, o
742
+ assert_equal [16,4], o.get(:var)
743
+ assert_equal :point, o.var_type(:var)
744
+ assert_equal 'line 1 char 3', o.var_loc(:var)
745
+ end
746
+
747
+ def test_mul_string
748
+ tokens = [
749
+ {:assignment=>{
750
+ :variable=>slice('var', 1),
751
+ :operator=>slice('*=', 1),
752
+ :value=>{:filters=>[], :string=>slice('"3"', 1)}
753
+ }},
754
+ ]
755
+
756
+ o = SlideField::ObjectData.new :child, 'loc'
757
+ o.set :var, 'test', 'loc', :string
758
+
759
+ @interpreter.interpret_tree tokens, o
760
+ assert_equal 'testtesttest', o.get(:var)
761
+ assert_equal :string, o.var_type(:var)
762
+ assert_equal 'line 1 char 3', o.var_loc(:var)
763
+ end
764
+
765
+ def test_mul_string_invalid
766
+ tokens = [
767
+ {:assignment=>{
768
+ :variable=>slice('var', 1),
769
+ :operator=>slice('*=', 1),
770
+ :value=>{:filters=>[], :string=>slice('"aaaa"', 1)}
771
+ }},
772
+ ]
773
+
774
+ o = SlideField::ObjectData.new :child, 'loc'
775
+ o.set :var, 'test', 'loc', :string
776
+
777
+ error = assert_raises SlideField::InterpreterError do
778
+ @interpreter.interpret_tree tokens, o
779
+ end
780
+
781
+ assert_equal "Invalid string multiplier 'aaaa', integer > 0 required at line 1 char 3", error.message
782
+ end
783
+
784
+ def test_mul_color
785
+ tokens = [
786
+ {:assignment=>{
787
+ :variable=>slice('var', 1),
788
+ :operator=>slice('*=', 1),
789
+ :value=>{:filters=>[], :color=>slice('#02020202', 1)}
790
+ }},
791
+ ]
792
+
793
+ o = SlideField::ObjectData.new :child, 'loc'
794
+ o.set :var, [4, 4, 4, 4], 'loc', :color
795
+
796
+ error = assert_raises SlideField::InterpreterError do
797
+ @interpreter.interpret_tree tokens, o
798
+ end
799
+
800
+ assert_equal "Invalid operator '*=' for type 'color' at line 1 char 2", error.message
801
+ end
802
+
803
+ def test_mul_boolean
804
+ tokens = [
805
+ {:assignment=>{
806
+ :variable=>slice('var', 1),
807
+ :operator=>slice('*=', 1),
808
+ :value=>{:filters=>[], :boolean=>slice(':true', 1)}
809
+ }},
810
+ ]
811
+
812
+ o = SlideField::ObjectData.new :child, 'loc'
813
+ o.set :var, true, 'loc', :boolean
814
+
815
+ error = assert_raises SlideField::InterpreterError do
816
+ @interpreter.interpret_tree tokens, o
817
+ end
818
+
819
+ assert_equal "Invalid operator '*=' for type 'boolean' at line 1 char 2", error.message
820
+ end
821
+
822
+ def test_mul_identifier
823
+ tokens = [
824
+ {:assignment=>{
825
+ :variable=>slice('var', 1),
826
+ :operator=>slice('*=', 1),
827
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
828
+ }},
829
+ ]
830
+
831
+ o = SlideField::ObjectData.new :child, 'loc'
832
+ o.set :var, 3, 'loc', :integer
833
+ o.set :test, 2, 'loc', :integer
834
+
835
+ @interpreter.interpret_tree tokens, o
836
+ assert_equal 6, o.get(:var)
837
+ assert_equal :integer, o.var_type(:var)
838
+ assert_equal 'line 1 char 3', o.var_loc(:var)
839
+ end
840
+
841
+ def test_div_undefined
842
+ tokens = [
843
+ {:assignment=>{
844
+ :variable=>slice('var', 1),
845
+ :operator=>slice('/=', 1),
846
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
847
+ }},
848
+ ]
849
+
850
+ o = SlideField::ObjectData.new :child, 'loc'
851
+ error = assert_raises SlideField::InterpreterError do
852
+ @interpreter.interpret_tree tokens, o
853
+ end
854
+
855
+ assert_equal "Undefined variable 'var' at line 1 char 1", error.message
856
+ end
857
+
858
+ def test_div_incompatible
859
+ tokens = [
860
+ {:assignment=>{
861
+ :variable=>slice('var', 1),
862
+ :operator=>slice('/=', 1),
863
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
864
+ }},
865
+ ]
866
+
867
+ o = SlideField::ObjectData.new :child, 'loc'
868
+ o.set :var, 'test', 'loc', :string
869
+
870
+ error = assert_raises SlideField::InterpreterError do
871
+ @interpreter.interpret_tree tokens, o
872
+ end
873
+
874
+ assert_equal "Unexpected 'integer', expecting 'string' for variable or property 'var' at line 1 char 3", error.message
875
+ end
876
+
877
+ def test_div_integer
878
+ tokens = [
879
+ {:assignment=>{
880
+ :variable=>slice('var', 1),
881
+ :operator=>slice('/=', 1),
882
+ :value=>{:filters=>[], :integer=>slice('2', 1)}
883
+ }},
884
+ ]
885
+
886
+ o = SlideField::ObjectData.new :child, 'loc'
887
+ o.set :var, 7, 'loc', :integer
888
+
889
+ @interpreter.interpret_tree tokens, o
890
+ assert_equal 3, o.get(:var)
891
+ assert_equal :integer, o.var_type(:var)
892
+ assert_equal 'line 1 char 3', o.var_loc(:var)
893
+ end
894
+
895
+ def test_div_integer_by_zero
896
+ tokens = [
897
+ {:assignment=>{
898
+ :variable=>slice('var', 1),
899
+ :operator=>slice('/=', 1),
900
+ :value=>{:filters=>[], :integer=>slice('0', 1)}
901
+ }},
902
+ ]
903
+
904
+ o = SlideField::ObjectData.new :child, 'loc'
905
+ o.set :var, 42, 'loc', :integer
906
+
907
+ error = assert_raises SlideField::InterpreterError do
908
+ @interpreter.interpret_tree tokens, o
909
+ end
910
+
911
+ assert_equal "divided by zero at line 1 char 3", error.message
912
+ end
913
+
914
+ def test_div_point
915
+ tokens = [
916
+ {:assignment=>{
917
+ :variable=>slice('var', 1),
918
+ :operator=>slice('/=', 1),
919
+ :value=>{:filters=>[], :point=>slice('2x3', 1)}
920
+ }},
921
+ ]
922
+
923
+ o = SlideField::ObjectData.new :child, 'loc'
924
+ o.set :var, [7,42], 'loc', :point
925
+
926
+ @interpreter.interpret_tree tokens, o
927
+ assert_equal [3,14], o.get(:var)
928
+ assert_equal :point, o.var_type(:var)
929
+ assert_equal 'line 1 char 3', o.var_loc(:var)
930
+ end
931
+
932
+ def test_div_point_by_zero
933
+ tokens = [
934
+ {:assignment=>{
935
+ :variable=>slice('var', 1),
936
+ :operator=>slice('/=', 1),
937
+ :value=>{:filters=>[], :point=>slice('2x0', 1)}
938
+ }},
939
+ ]
940
+
941
+ o = SlideField::ObjectData.new :child, 'loc'
942
+ o.set :var, [42,42], 'loc', :point
943
+
944
+ error = assert_raises SlideField::InterpreterError do
945
+ @interpreter.interpret_tree tokens, o
946
+ end
947
+
948
+ assert_equal "divided by zero at line 1 char 3", error.message
949
+ end
950
+
951
+ def test_div_string
952
+ tokens = [
953
+ {:assignment=>{
954
+ :variable=>slice('var', 1),
955
+ :operator=>slice('/=', 1),
956
+ :value=>{:filters=>[], :string=>slice('" world"', 1)}
957
+ }},
958
+ ]
959
+
960
+ o = SlideField::ObjectData.new :child, 'loc'
961
+ o.set :var, 'hello world', 'loc', :string
962
+
963
+ error = assert_raises SlideField::InterpreterError do
964
+ @interpreter.interpret_tree tokens, o
965
+ end
966
+
967
+ assert_equal "Invalid operator '/=' for type 'string' at line 1 char 2", error.message
968
+ end
969
+
970
+ def test_div_color
971
+ tokens = [
972
+ {:assignment=>{
973
+ :variable=>slice('var', 1),
974
+ :operator=>slice('/=', 1),
975
+ :value=>{:filters=>[], :color=>slice('#02020202', 1)}
976
+ }},
977
+ ]
978
+
979
+ o = SlideField::ObjectData.new :child, 'loc'
980
+ o.set :var, [4, 4, 4, 4], 'loc', :color
981
+
982
+ error = assert_raises SlideField::InterpreterError do
983
+ @interpreter.interpret_tree tokens, o
984
+ end
985
+
986
+ assert_equal "Invalid operator '/=' for type 'color' at line 1 char 2", error.message
987
+ end
988
+
989
+ def test_div_boolean
990
+ tokens = [
991
+ {:assignment=>{
992
+ :variable=>slice('var', 1),
993
+ :operator=>slice('/=', 1),
994
+ :value=>{:filters=>[], :boolean=>slice(':true', 1)}
995
+ }},
996
+ ]
997
+
998
+ o = SlideField::ObjectData.new :child, 'loc'
999
+ o.set :var, true, 'loc', :boolean
1000
+
1001
+ error = assert_raises SlideField::InterpreterError do
1002
+ @interpreter.interpret_tree tokens, o
1003
+ end
1004
+
1005
+ assert_equal "Invalid operator '/=' for type 'boolean' at line 1 char 2", error.message
1006
+ end
1007
+
1008
+ def test_div_identifier
1009
+ tokens = [
1010
+ {:assignment=>{
1011
+ :variable=>slice('var', 1),
1012
+ :operator=>slice('/=', 1),
1013
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
1014
+ }},
1015
+ ]
1016
+
1017
+ o = SlideField::ObjectData.new :child, 'loc'
1018
+ o.set :var, 6, 'loc', :integer
1019
+ o.set :test, 2, 'loc', :integer
1020
+
1021
+ @interpreter.interpret_tree tokens, o
1022
+ assert_equal 3, o.get(:var)
1023
+ assert_equal :integer, o.var_type(:var)
1024
+ assert_equal 'line 1 char 3', o.var_loc(:var)
1025
+ end
1026
+
1027
+ def test_children
1028
+ tokens = [
1029
+ {:object=>{:type=>slice('child', 1), :body=>[
1030
+ {:assignment=>{
1031
+ :variable=>slice('var', 1),
1032
+ :operator=>slice('=', 1),
1033
+ :value=>{:filters=>[], :identifier=>slice('parent_var', 1)}
1034
+ }},
1035
+ ]}},
1036
+ ]
1037
+
1038
+ o = SlideField::ObjectData.new :parent, 'loc'
1039
+ o.set :parent_var, 'hello', 'loc', :string
1040
+
1041
+ @interpreter.interpret_tree tokens, o
1042
+ assert_equal 1, o.children.count
1043
+ assert_equal 'hello', o[:child][0].get(:var)
1044
+ end
1045
+
1046
+ def test_object_value
1047
+ tokens = [
1048
+ {:object=>{
1049
+ :type=>slice('value', 1),
1050
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
1051
+ }},
1052
+ ]
1053
+
1054
+ o = SlideField::ObjectData.new :parent, 'loc'
1055
+
1056
+ @interpreter.interpret_tree tokens, o
1057
+ assert_equal 1, o.children.count
1058
+ assert_equal 42, o[:value][0].get(:num)
1059
+ end
1060
+
1061
+ def test_object_identifier_value
1062
+ tokens = [
1063
+ {:object=>{
1064
+ :type=>slice('value', 1),
1065
+ :value=>{:filters=>[], :identifier=>slice('test', 1)}
1066
+ }},
1067
+ ]
1068
+
1069
+ o = SlideField::ObjectData.new :parent, 'loc'
1070
+ o.set :test, 42, 'loc', :integer
1071
+
1072
+ @interpreter.interpret_tree tokens, o
1073
+ assert_equal 1, o.children.count
1074
+ assert_equal 42, o[:value][0].get(:num)
1075
+ end
1076
+
1077
+ def test_object_invalid_value
1078
+ tokens = [
1079
+ {:object=>{
1080
+ :type=>slice('value', 1),
1081
+ :value=>{:filters=>[], :point=>slice('12x3', 1)}
1082
+ }},
1083
+ ]
1084
+
1085
+ o = SlideField::ObjectData.new :parent, 'loc'
1086
+ error = assert_raises SlideField::InterpreterError do
1087
+ @interpreter.interpret_tree tokens, o
1088
+ end
1089
+
1090
+ assert_equal "Unexpected 'point', expecting one of [:integer, :string] at line 1 char 2", error.message
1091
+ end
1092
+
1093
+ def test_unknown_object
1094
+ tokens = [
1095
+ {:object=>{:type=>slice('qwfpgjluy', 1)}},
1096
+ ]
1097
+
1098
+ o = SlideField::ObjectData.new :parent, 'loc'
1099
+ error = assert_raises SlideField::InterpreterError do
1100
+ @interpreter.interpret_tree tokens, o
1101
+ end
1102
+
1103
+ assert_equal "Unexpected object 'qwfpgjluy', expecting one of [:aaaa, :child, :value] at line 1 char 1", error.message
1104
+ end
1105
+
1106
+ def test_missing_variable
1107
+ o = SlideField::ObjectData.new :picky, 'location'
1108
+
1109
+ error = assert_raises SlideField::InterpreterError do
1110
+ @interpreter.interpret_tree [], o
1111
+ end
1112
+
1113
+ assert_equal "Missing property 'king_name' for object 'picky' at location", error.message
1114
+ end
1115
+
1116
+ def test_missing_child
1117
+ o = SlideField::ObjectData.new :picky, 'location'
1118
+ o.set :king_name, 'value', 'var loc', :string
1119
+
1120
+ error = assert_raises SlideField::InterpreterError do
1121
+ @interpreter.interpret_tree [], o
1122
+ end
1123
+
1124
+ assert_equal "Object 'picky' must have at least 1 'minOne', 0 found at location", error.message
1125
+
1126
+ c1 = SlideField::ObjectData.new :minOne, 'location'
1127
+ o << c1
1128
+
1129
+ c2 = SlideField::ObjectData.new :minTwo, 'location'
1130
+ o << c2
1131
+
1132
+ error = assert_raises SlideField::InterpreterError do
1133
+ @interpreter.interpret_tree [], o
1134
+ end
1135
+
1136
+ assert_equal "Object 'picky' must have at least 2 'minTwo', 1 found at location", error.message
1137
+ end
1138
+
1139
+ def test_child_overdose
1140
+ o = SlideField::ObjectData.new :picky, 'location'
1141
+ o.set :king_name, 'value', 'var loc', :string
1142
+
1143
+ c1 = SlideField::ObjectData.new :minOne, 'location'
1144
+ o << c1
1145
+
1146
+ c2 = SlideField::ObjectData.new :minTwo, 'location'
1147
+ o << c2
1148
+ o << c2
1149
+
1150
+ c3 = SlideField::ObjectData.new :maxOne, 'location'
1151
+ o << c3
1152
+ o << c3
1153
+
1154
+ error = assert_raises SlideField::InterpreterError do
1155
+ @interpreter.interpret_tree [], o
1156
+ end
1157
+
1158
+ assert_equal "Object 'picky' can not have more than 1 'maxOne', 2 found at location", error.message
1159
+ end
1160
+
1161
+ def test_file_not_found
1162
+ i = @interpreter
1163
+ error = assert_raises SlideField::InterpreterError do
1164
+ i.run_file 'no.entry'
1165
+ end
1166
+
1167
+ assert_equal "No such file or directory @ rb_sysopen - no.entry", error.message
1168
+ end
1169
+
1170
+ def test_include_not_found
1171
+ i = @interpreter
1172
+ error = assert_raises SlideField::InterpreterError do
1173
+ i.run_string '\\include "/hello"'
1174
+ end
1175
+
1176
+ assert_equal "[input] No such file or directory @ rb_sysopen - /hello", error.message
1177
+ end
1178
+
1179
+ def test_escape_sequence
1180
+ tokens = [
1181
+ {:assignment=>{
1182
+ :variable=>slice('var', 1),
1183
+ :operator=>slice('=', 1),
1184
+ :value=>{:filters=>[], :string=>slice('"\\\\ \\"\\n\\s"', 1)}
1185
+ }},
1186
+ ]
1187
+
1188
+ o = SlideField::ObjectData.new :child, 'loc'
1189
+ @interpreter.interpret_tree tokens, o
1190
+
1191
+ assert_equal "\\ \"\ns", o.get(:var)
1192
+ assert_equal :string, o.var_type(:var)
1193
+ assert_equal 'line 1 char 3', o.var_loc(:var)
1194
+ end
1195
+
1196
+ def test_default_value
1197
+ o = SlideField::ObjectData.new :type, 'loc'
1198
+ @interpreter.interpret_tree [], o
1199
+
1200
+ assert_equal [0,0], o.get(:test)
1201
+ assert_equal :point, o.var_type(:test)
1202
+ assert_equal 'default', o.var_loc(:test)
1203
+ end
1204
+
1205
+ def test_default_value_parent
1206
+ p = SlideField::ObjectData.new :type, 'loc'
1207
+ p.set :test, [1,1], 'loc', :point
1208
+
1209
+ o = SlideField::ObjectData.new :type, 'loc'
1210
+ o.parent = p
1211
+
1212
+ @interpreter.interpret_tree [], o
1213
+
1214
+ assert_equal [1,1], o.get(:test)
1215
+ assert_equal :point, o.var_type(:test)
1216
+ assert_equal 'loc', o.var_loc(:test)
1217
+ end
1218
+
1219
+ def test_template
1220
+ tokens = [{
1221
+ :object=>{:template=>slice('&', 1), :type=>slice('var_name', 1)}
1222
+ }]
1223
+
1224
+ o = SlideField::ObjectData.new :parent, 'loc'
1225
+ o.set :var_name, {:type=>slice('child', 2)}, 'loc', :object
1226
+
1227
+ @interpreter.interpret_tree tokens, o
1228
+
1229
+ assert_equal 1, o[:child].count
1230
+ assert_equal 'line 1 char 2', o[:child].first.loc
1231
+ end
1232
+
1233
+ def test_template_upstream_body
1234
+ template = {
1235
+ :type=>slice('child', 1),
1236
+ :body=>[
1237
+ {:assignment=>{
1238
+ :variable=>slice('var', 1),
1239
+ :operator=>slice('=', 1),
1240
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
1241
+ }},
1242
+ ]
1243
+ }
1244
+
1245
+ tokens = [{
1246
+ :object=>{
1247
+ :template=>slice('&', 2),
1248
+ :type=>slice('var_name', 2),
1249
+ }
1250
+ }]
1251
+
1252
+ o = SlideField::ObjectData.new :parent, 'loc'
1253
+ o.set :var_name, template, 'loc', :object
1254
+
1255
+ @interpreter.interpret_tree tokens, o
1256
+ copy = o[:child].first
1257
+
1258
+ assert_equal 42, copy.get(:var)
1259
+ assert_equal :integer, copy.var_type(:var)
1260
+ assert_equal 'line 2 char 1', copy.var_loc(:var)
1261
+ end
1262
+
1263
+ def test_template_downstream_body
1264
+ template = {
1265
+ :type=>slice('child', 1),
1266
+ }
1267
+
1268
+ tokens = [{
1269
+ :object=>{
1270
+ :template=>slice('&', 2),
1271
+ :type=>slice('var_name', 2),
1272
+ :body=>[
1273
+ {:assignment=>{
1274
+ :variable=>slice('var', 3),
1275
+ :operator=>slice('=', 3),
1276
+ :value=>{:filters=>[], :integer=>slice('42', 3)}
1277
+ }},
1278
+ ]
1279
+ }
1280
+ }]
1281
+
1282
+ o = SlideField::ObjectData.new :parent, 'loc'
1283
+ o.set :var_name, template, 'loc', :object
1284
+
1285
+ @interpreter.interpret_tree tokens, o
1286
+ copy = o[:child].first
1287
+
1288
+ assert_equal 42, copy.get(:var)
1289
+ assert_equal :integer, copy.var_type(:var)
1290
+ assert_equal 'line 3 char 3', copy.var_loc(:var)
1291
+ end
1292
+
1293
+ def test_template_merge_bodies
1294
+ template = {
1295
+ :type=>slice('child', 1),
1296
+ :body=>[
1297
+ {:assignment=>{
1298
+ :variable=>slice('var', 1),
1299
+ :operator=>slice('+=', 1),
1300
+ :value=>{:filters=>[], :integer=>slice('2', 1)}
1301
+ }},
1302
+ ]
1303
+ }
1304
+
1305
+ tokens = [{
1306
+ :object=>{
1307
+ :template=>slice('&', 2),
1308
+ :type=>slice('var_name', 2),
1309
+ :body=>[
1310
+ {:assignment=>{
1311
+ :variable=>slice('var', 3),
1312
+ :operator=>slice('=', 3),
1313
+ :value=>{:filters=>[], :integer=>slice('42', 3)}
1314
+ }},
1315
+ ]
1316
+ }
1317
+ }]
1318
+
1319
+ o = SlideField::ObjectData.new :parent, 'loc'
1320
+ o.set :var_name, template, 'loc', :object
1321
+
1322
+ @interpreter.interpret_tree tokens, o
1323
+ copy = o[:child].first
1324
+
1325
+ assert_equal 44, copy.get(:var)
1326
+ assert_equal :integer, copy.var_type(:var)
1327
+ assert_equal 'line 2 char 1', copy.var_loc(:var)
1328
+ end
1329
+
1330
+ def test_template_upstream_value
1331
+ template = {
1332
+ :type=>slice('value', 1),
1333
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
1334
+ }
1335
+
1336
+ tokens = [{
1337
+ :object=>{
1338
+ :template=>slice('&', 2),
1339
+ :type=>slice('var_name', 2),
1340
+ }
1341
+ }]
1342
+
1343
+ o = SlideField::ObjectData.new :parent, 'loc'
1344
+ o.set :var_name, template, 'loc', :object
1345
+
1346
+ @interpreter.interpret_tree tokens, o
1347
+ copy = o[:value].first
1348
+
1349
+ assert_equal 42, copy.get(:num)
1350
+ assert_equal :integer, copy.var_type(:num)
1351
+ assert_equal 'line 2 char 1', copy.var_loc(:num)
1352
+ end
1353
+
1354
+ def test_template_downstream_value
1355
+ template = {
1356
+ :type=>slice('value', 1),
1357
+ }
1358
+
1359
+ tokens = [{
1360
+ :object=>{
1361
+ :template=>slice('&', 2),
1362
+ :type=>slice('var_name', 2),
1363
+ :value=>{:filters=>[], :integer=>slice('42', 2)}
1364
+ }
1365
+ }]
1366
+
1367
+ o = SlideField::ObjectData.new :parent, 'loc'
1368
+ o.set :var_name, template, 'loc', :object
1369
+
1370
+ @interpreter.interpret_tree tokens, o
1371
+ copy = o[:value].first
1372
+
1373
+ assert_equal 42, copy.get(:num)
1374
+ assert_equal :integer, copy.var_type(:num)
1375
+ assert_equal 'line 2 char 3', copy.var_loc(:num)
1376
+ end
1377
+
1378
+ def test_template_double_value
1379
+ template = {
1380
+ :type=>slice('value', 1),
1381
+ :value=>{:filters=>[], :integer=>slice('42', 1)}
1382
+ }
1383
+
1384
+ tokens = [{
1385
+ :object=>{
1386
+ :template=>slice('&', 2),
1387
+ :type=>slice('var_name', 2),
1388
+ :value=>{:filters=>[], :integer=>slice('42', 2)}
1389
+ }
1390
+ }]
1391
+
1392
+ o = SlideField::ObjectData.new :parent, 'loc'
1393
+ o.set :var_name, template, 'loc', :object
1394
+
1395
+ error = assert_raises SlideField::InterpreterError do
1396
+ @interpreter.interpret_tree tokens, o
1397
+ end
1398
+
1399
+ assert_equal "Variable 'num' is already defined at line 2 char 3", error.message
1400
+ end
1401
+
1402
+ def test_template_of_template
1403
+ tokens = [
1404
+ {:assignment=>{
1405
+ :variable=>slice('alias', 1),
1406
+ :operator=>slice('=', 1),
1407
+ :value=>{
1408
+ :filters=>[],
1409
+ :object=>{:template=>slice('&', 1), :type=>slice('template', 1)}
1410
+ }
1411
+ }},
1412
+ {:object=>{:template=>slice('&', 2), :type=>slice('alias', 2)}}
1413
+ ]
1414
+
1415
+ o = SlideField::ObjectData.new :parent, 'loc'
1416
+ o.set :template, {:type=>slice('child', 2)}, 'loc', :object
1417
+
1418
+ error = assert_raises SlideField::InterpreterError do
1419
+ @interpreter.interpret_tree tokens, o
1420
+ end
1421
+
1422
+ assert_equal "Unexpected template reference at line 1 char 4", error.message
1423
+ end
1424
+
1425
+ def test_undefined_template
1426
+ tokens = [{
1427
+ :object=>{:template=>slice('&', 1), :type=>slice('var_name', 1)}
1428
+ }]
1429
+
1430
+ o = SlideField::ObjectData.new :parent, 'loc'
1431
+
1432
+ error = assert_raises SlideField::InterpreterError do
1433
+ @interpreter.interpret_tree tokens, o
1434
+ end
1435
+
1436
+ assert_equal "Undefined variable 'var_name' at line 1 char 2", error.message
1437
+ end
1438
+
1439
+ def test_invalid_template
1440
+ tokens = [{
1441
+ :object=>{:template=>slice('&', 1), :type=>slice('var_name', 1)}
1442
+ }]
1443
+
1444
+ o = SlideField::ObjectData.new :parent, 'loc'
1445
+ o.set :var_name, 42, 'loc', :integer
1446
+
1447
+ error = assert_raises SlideField::InterpreterError do
1448
+ @interpreter.interpret_tree tokens, o
1449
+ end
1450
+
1451
+ assert_equal "Unexpected 'integer', expecting 'object' at line 1 char 2", error.message
1452
+ end
1453
+
1454
+ def test_filter_point_x
1455
+ tokens = [
1456
+ {:assignment=>{
1457
+ :variable=>slice('var', 1),
1458
+ :operator=>slice('=', 1),
1459
+ :value=>{
1460
+ :filters=>[{:name=>slice('x', 1)}],
1461
+ :point=>slice('12x34', 1)
1462
+ }
1463
+ }},
1464
+ ]
1465
+
1466
+ o = SlideField::ObjectData.new :child, 'loc'
1467
+ @interpreter.interpret_tree tokens, o
1468
+
1469
+ assert_equal :integer, o.var_type(:var)
1470
+ assert_equal 12, o.get(:var)
1471
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1472
+ end
1473
+
1474
+ def test_filter_point_y
1475
+ tokens = [
1476
+ {:assignment=>{
1477
+ :variable=>slice('var', 1),
1478
+ :operator=>slice('=', 1),
1479
+ :value=>{
1480
+ :filters=>[{:name=>slice('y', 1)}],
1481
+ :point=>slice('12x34', 1)
1482
+ }
1483
+ }},
1484
+ ]
1485
+
1486
+ o = SlideField::ObjectData.new :child, 'loc'
1487
+ @interpreter.interpret_tree tokens, o
1488
+
1489
+ assert_equal :integer, o.var_type(:var)
1490
+ assert_equal 34, o.get(:var)
1491
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1492
+ end
1493
+
1494
+ def test_filter_integer_x
1495
+ tokens = [
1496
+ {:assignment=>{
1497
+ :variable=>slice('var', 1),
1498
+ :operator=>slice('=', 1),
1499
+ :value=>{
1500
+ :filters=>[{:name=>slice('x', 1)}],
1501
+ :integer=>slice('1', 1)
1502
+ }
1503
+ }},
1504
+ ]
1505
+
1506
+ o = SlideField::ObjectData.new :child, 'loc'
1507
+ @interpreter.interpret_tree tokens, o
1508
+
1509
+ assert_equal :point, o.var_type(:var)
1510
+ assert_equal [1,0], o.get(:var)
1511
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1512
+ end
1513
+
1514
+ def test_filter_integer_y
1515
+ tokens = [
1516
+ {:assignment=>{
1517
+ :variable=>slice('var', 1),
1518
+ :operator=>slice('=', 1),
1519
+ :value=>{
1520
+ :filters=>[{:name=>slice('y', 1)}],
1521
+ :integer=>slice('1', 1)
1522
+ }
1523
+ }},
1524
+ ]
1525
+
1526
+ o = SlideField::ObjectData.new :child, 'loc'
1527
+ @interpreter.interpret_tree tokens, o
1528
+
1529
+ assert_equal :point, o.var_type(:var)
1530
+ assert_equal [0,1], o.get(:var)
1531
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1532
+ end
1533
+
1534
+ def test_filter_string_lines
1535
+ tokens = [
1536
+ {:assignment=>{
1537
+ :variable=>slice('var', 1),
1538
+ :operator=>slice('=', 1),
1539
+ :value=>{
1540
+ :filters=>[{:name=>slice('lines', 1)}],
1541
+ :string=>slice('first\\nsecond', 1)
1542
+ }
1543
+ }},
1544
+ ]
1545
+
1546
+ o = SlideField::ObjectData.new :child, 'loc'
1547
+ @interpreter.interpret_tree tokens, o
1548
+
1549
+ assert_equal :integer, o.var_type(:var)
1550
+ assert_equal 2, o.get(:var)
1551
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1552
+ end
1553
+
1554
+ def test_filters_order
1555
+ tokens = [
1556
+ {:assignment=>{
1557
+ :variable=>slice('var', 1),
1558
+ :operator=>slice('=', 1),
1559
+ :value=>{
1560
+ :filters=>[
1561
+ {:name=>slice('y', 1)},
1562
+ {:name=>slice('x', 1)}
1563
+ ],
1564
+ :point=>slice('42x24', 1)
1565
+ }
1566
+ }},
1567
+ ]
1568
+
1569
+ o = SlideField::ObjectData.new :child, 'loc'
1570
+ @interpreter.interpret_tree tokens, o
1571
+
1572
+ assert_equal :point, o.var_type(:var)
1573
+ assert_equal [0,42], o.get(:var)
1574
+ assert_equal 'line 1 char 5', o.var_loc(:var)
1575
+ end
1576
+
1577
+ def test_filter_identifier
1578
+ tokens = [
1579
+ {:assignment=>{
1580
+ :variable=>slice('var', 1),
1581
+ :operator=>slice('=', 1),
1582
+ :value=>{
1583
+ :filters=>[{:name=>slice('x', 1)}],
1584
+ :identifier=>slice('test', 1)
1585
+ }
1586
+ }},
1587
+ ]
1588
+
1589
+ o = SlideField::ObjectData.new :child, 'loc'
1590
+ o.set :test, [12,21], 'loc', :point
1591
+
1592
+ @interpreter.interpret_tree tokens, o
1593
+
1594
+ assert_equal :integer, o.var_type(:var)
1595
+ assert_equal 12, o.get(:var)
1596
+ assert_equal 'line 1 char 4', o.var_loc(:var)
1597
+ end
1598
+
1599
+ def test_unknown_filter
1600
+ tokens = [
1601
+ {:assignment=>{
1602
+ :variable=>slice('var', 1),
1603
+ :operator=>slice('=', 1),
1604
+ :value=>{
1605
+ :filters=>[{:name=>slice('aaaa', 1)}],
1606
+ :integer=>slice('1', 1)
1607
+ }
1608
+ }},
1609
+ ]
1610
+
1611
+ o = SlideField::ObjectData.new :child, 'loc'
1612
+ error = assert_raises SlideField::InterpreterError do
1613
+ @interpreter.interpret_tree tokens, o
1614
+ end
1615
+
1616
+ assert_equal "Invalid filter 'aaaa' for type 'integer' at line 1 char 3", error.message
1617
+ end
1618
+
1619
+ def test_filter_lost_in_template
1620
+ template = {
1621
+ :type=>slice('child', 1),
1622
+ :body=>[
1623
+ {:assignment=>{
1624
+ :variable=>slice('var', 1),
1625
+ :operator=>slice('=', 1),
1626
+ :value=>{
1627
+ :filters=>[{:name=>slice('x', 1)}],
1628
+ :point=>slice('1x1', 1)
1629
+ }
1630
+ }},
1631
+ ]
1632
+ }
1633
+
1634
+ tokens = [
1635
+ {:object=>{
1636
+ :template=>slice('&', 2),
1637
+ :type=>slice('var_name', 2),
1638
+ }},
1639
+ {:object=>{
1640
+ :template=>slice('&', 3),
1641
+ :type=>slice('var_name', 3),
1642
+ }}
1643
+ ]
1644
+
1645
+ o = SlideField::ObjectData.new :parent, 'loc'
1646
+ o.set :var_name, template, 'loc', :object
1647
+
1648
+ @interpreter.interpret_tree tokens, o
1649
+
1650
+ assert_equal 2, o[:child].count
1651
+
1652
+ first = o[:child][0]
1653
+ second = o[:child][1]
1654
+
1655
+ assert_equal :integer, first.var_type(:var)
1656
+ assert_equal 1, first.get(:var)
1657
+ assert_equal 'line 2 char 1', first.var_loc(:var)
1658
+
1659
+ assert_equal :integer, second.var_type(:var)
1660
+ assert_equal 1, second.get(:var)
1661
+ assert_equal 'line 3 char 1', second.var_loc(:var)
1662
+ end
1663
+
1664
+ def test_debug
1665
+ tokens = [
1666
+ {:object=>{
1667
+ :type=>slice('debug', 1),
1668
+ :value=>{:filters=>[], :string=>slice('"i haz bugs"', 1)}
1669
+ }}
1670
+ ]
1671
+
1672
+ o = SlideField::ObjectData.new :child, 'loc'
1673
+ o.context = 'parent context'
1674
+
1675
+ pretty, err = capture_io do
1676
+ ap :type=>:string, :value=>'i haz bugs'
1677
+ end
1678
+
1679
+ assert_output "DEBUG in local context at line 1 char 1:\n#{pretty}\n" do
1680
+ @interpreter.interpret_tree tokens, o, nil, 'local context'
1681
+ end
1682
+
1683
+ assert_empty o[:debug]
1684
+ end
1685
+
1686
+ def test_parse_error
1687
+ error = assert_raises SlideField::ParseError do
1688
+ @interpreter.run_file @path + '/parse_error.sfp'
1689
+ end
1690
+
1691
+ assert_match /\A\[parse_error.sfp\] /, error.message
1692
+ end
1693
+
1694
+ def test_include_relative
1695
+ @interpreter.run_string '\\include "../../examples/minimal/main.sfp"', @path
1696
+ end
1697
+
1698
+ def test_include_absolute
1699
+ ex_path = File.expand_path '../examples', __dir__
1700
+ @interpreter.run_string '\\include "' + ex_path + '/minimal/main.sfp"'
1701
+ end
1702
+
1703
+ def test_include_parse_error
1704
+ error = assert_raises SlideField::ParseError do
1705
+ @interpreter.run_string '\\include "parse_error.sfp"', @path
1706
+ end
1707
+
1708
+ assert_match /\A\[input\] \[parse_error.sfp\] /, error.message
1709
+ refute_match /\\include/, error.message
1710
+ end
1711
+
1712
+ def test_reparse
1713
+ ex_path = File.expand_path '../examples', __dir__
1714
+ @interpreter.run_file ex_path + '/minimal/main.sfp'
1715
+
1716
+ error = assert_raises SlideField::InterpreterError do
1717
+ @interpreter.run_file ex_path + '/minimal/main.sfp'
1718
+ end
1719
+
1720
+ assert_equal "File already interpreted: '#{ex_path}/minimal/main.sfp'", error.message
1721
+ end
1722
+
1723
+ def test_recursive_include
1724
+ error = assert_raises SlideField::InterpreterError do
1725
+ @interpreter.run_file @path + '/recursive_include.sfp'
1726
+ end
1727
+
1728
+ assert_equal "[recursive_include.sfp] File already interpreted: '#{@path}/recursive_include.sfp'", error.message
1729
+ end
1730
+
1731
+ def test_include_parent_folder
1732
+ error = assert_raises SlideField::InterpreterError do
1733
+ @interpreter.run_file @path + '/sub/include_parent.sfp'
1734
+ end
1735
+
1736
+ assert_match /\A\[include_parent.sfp\] \[..\/unknown_object.sfp\] /, error.message
1737
+
1738
+ error = assert_raises SlideField::ParseError do
1739
+ @interpreter.run_file @path + '/parse_error.sfp'
1740
+ end
1741
+
1742
+ assert_match /\A\[parse_error.sfp\] /, error.message
1743
+ end
1744
+
1745
+ def test_include_subfolder
1746
+ error = assert_raises SlideField::InterpreterError do
1747
+ @interpreter.run_file @path + '/include_sub.sfp'
1748
+ end
1749
+
1750
+ assert_match /\A\[include_sub.sfp\] \[sub\/include_parent.sfp\] \[unknown_object.sfp\] /, error.message
1751
+ end
1752
+
1753
+ def test_include_wrong_template
1754
+ error = assert_raises SlideField::InterpreterError do
1755
+ @interpreter.run_string '\\include "wrong_template.sfp"; \\&wrong_template', @path
1756
+ end
1757
+
1758
+ assert_match /&wrong_template/, error.message
1759
+ end
1760
+
1761
+ def test_include_unclosed_object
1762
+ assert_raises SlideField::ParseError do
1763
+ @interpreter.run_string '\\include "unclosed_object.sfp"', @path
1764
+ end
1765
+ end
1766
+ end