spot_feel 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +183 -0
- data/Rakefile +11 -0
- data/lib/spot_feel/configuration.rb +12 -0
- data/lib/spot_feel/dmn/decision.rb +50 -0
- data/lib/spot_feel/dmn/decision_table.rb +53 -0
- data/lib/spot_feel/dmn/definitions.rb +68 -0
- data/lib/spot_feel/dmn/information_requirement.rb +29 -0
- data/lib/spot_feel/dmn/input.rb +28 -0
- data/lib/spot_feel/dmn/literal_expression.rb +370 -0
- data/lib/spot_feel/dmn/output.rb +29 -0
- data/lib/spot_feel/dmn/rule.rb +63 -0
- data/lib/spot_feel/dmn/unary_tests.rb +27 -0
- data/lib/spot_feel/dmn/variable.rb +27 -0
- data/lib/spot_feel/dmn.rb +17 -0
- data/lib/spot_feel/nodes.rb +684 -0
- data/lib/spot_feel/parser.rb +29 -0
- data/lib/spot_feel/spot_feel.treetop +659 -0
- data/lib/spot_feel/version.rb +5 -0
- data/lib/spot_feel.rb +63 -0
- metadata +317 -0
@@ -0,0 +1,659 @@
|
|
1
|
+
grammar SpotFeel
|
2
|
+
|
3
|
+
rule start
|
4
|
+
expression_or_tests
|
5
|
+
end
|
6
|
+
|
7
|
+
rule expression_or_tests
|
8
|
+
simple_expression /
|
9
|
+
simple_unary_tests
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# 1. expression =
|
14
|
+
# 1.a textual expression |
|
15
|
+
# 1.b boxed expression ;
|
16
|
+
#
|
17
|
+
rule expression
|
18
|
+
simple_expression
|
19
|
+
end
|
20
|
+
|
21
|
+
rule bracketed_expression
|
22
|
+
"(" __ expression __ ")" {
|
23
|
+
def eval(context={})
|
24
|
+
expression.eval(context)
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# 2. textual expression =
|
31
|
+
# 2.a function definition | for expression | if expression | quantified expression |
|
32
|
+
# 2.b disjunction |
|
33
|
+
# 2.c conjunction |
|
34
|
+
# 2.d comparison |
|
35
|
+
# 2.e arithmetic expression |
|
36
|
+
# 2.f instance of |
|
37
|
+
# 2.g path expression |
|
38
|
+
# 2.h filter expression | function invocation |
|
39
|
+
# 2.i literal | simple positive unary test | name | "(" , textual expression , ")" ;
|
40
|
+
#
|
41
|
+
|
42
|
+
#
|
43
|
+
# 3. textual expressions = textual expression , { "," , textual expression } ;
|
44
|
+
#
|
45
|
+
|
46
|
+
#
|
47
|
+
# 4. arithmetic expression =
|
48
|
+
# 4.a addition | subtraction |
|
49
|
+
# 4.b multiplication | division |
|
50
|
+
# 4.c exponentiation |
|
51
|
+
# 4.d arithmetic negation ;
|
52
|
+
#
|
53
|
+
rule arithmetic_expression
|
54
|
+
addition /
|
55
|
+
subtraction /
|
56
|
+
multiplication /
|
57
|
+
division /
|
58
|
+
exponentiation /
|
59
|
+
arithmetic_negation /
|
60
|
+
bracketed_arithmetic_expression
|
61
|
+
end
|
62
|
+
|
63
|
+
rule bracketed_arithmetic_expression
|
64
|
+
"(" __ arithmetic_expression __ ")" {
|
65
|
+
def eval(context={})
|
66
|
+
arithmetic_expression.eval(context)
|
67
|
+
end
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# 5. simple expression = arithmetic expression | simple value ;
|
73
|
+
#
|
74
|
+
# Note: added boxed_expression here to support list and context
|
75
|
+
#
|
76
|
+
rule simple_expression
|
77
|
+
expanded_simple_expression /
|
78
|
+
arithmetic_expression /
|
79
|
+
comparison /
|
80
|
+
simple_value /
|
81
|
+
bracketed_expression
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# NOTE: these rules go beyond S-FEEL spec
|
86
|
+
#
|
87
|
+
rule expanded_simple_expression
|
88
|
+
if_expression /
|
89
|
+
comparison /
|
90
|
+
boxed_expression
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# 6. simple expressions = simple expression , { "," , simple expression } ;
|
95
|
+
#
|
96
|
+
rule simple_expressions
|
97
|
+
expr:simple_expression more_exprs:(__ "," __ simple_expression)* <SimpleExpressions>
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# 7. simple positive unary test =
|
102
|
+
# 7.a [ "<" | "<=" | ">" | ">=" ] , endpoint |
|
103
|
+
# 7.b interval ;
|
104
|
+
#
|
105
|
+
rule simple_positive_unary_test
|
106
|
+
head:((unary_operator / "not") __)? tail:endpoint <SimplePositiveUnaryTest> /
|
107
|
+
interval
|
108
|
+
end
|
109
|
+
|
110
|
+
rule unary_operator
|
111
|
+
"<=" /
|
112
|
+
">=" /
|
113
|
+
"<" /
|
114
|
+
">"
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# 8. interval = ( open interval start | closed interval start ) , endpoint , ".." , endpoint , ( open interval end | closed interval end ) ;
|
119
|
+
#
|
120
|
+
rule interval
|
121
|
+
start_token:("(" / "]") __ first:endpoint __ ".." __ second:endpoint __ end_token:(")" / "[") <Interval> /
|
122
|
+
start_token:"[" __ first:endpoint __ ".." __ second:endpoint __ end_token:"]" <Interval>
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# 9. open interval start = "(" | "]" ;
|
127
|
+
#
|
128
|
+
rule open_interval_start
|
129
|
+
"(" <OpenIntervalStart> /
|
130
|
+
"]" <OpenIntervalStart>
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# 10. closed interval start = "[" ;
|
135
|
+
#
|
136
|
+
rule closed_interval_start
|
137
|
+
"[" <ClosedIntervalStart>
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# 11. open interval end = ")" | "[" ;
|
142
|
+
#
|
143
|
+
rule open_interval_end
|
144
|
+
")" <OpenIntervalEnd> /
|
145
|
+
"[" <OpenIntervalEnd>
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# 12. closed interval end = "]" ;
|
150
|
+
#
|
151
|
+
rule closed_interval_end
|
152
|
+
"]" <ClosedIntervalEnd>
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# 13. simple positive unary tests = simple positive unary test , { "," , simple positive unary test } ;
|
157
|
+
#
|
158
|
+
rule simple_positive_unary_tests
|
159
|
+
test:simple_positive_unary_test more_tests:(__ "," __ simple_positive_unary_test)* <SimplePositiveUnaryTests>
|
160
|
+
end
|
161
|
+
|
162
|
+
#
|
163
|
+
# 14. simple unary tests =
|
164
|
+
# 14.a simple positive unary tests |
|
165
|
+
# 14.b "not", "(", simple positive unary tests, ")" |
|
166
|
+
# 14.c "-";
|
167
|
+
#
|
168
|
+
rule simple_unary_tests
|
169
|
+
expr:simple_positive_unary_tests <SimpleUnaryTests> /
|
170
|
+
negate:"not" __ "(" __ expr:simple_positive_unary_tests __ ")" <SimpleUnaryTests> /
|
171
|
+
"-" <SimpleUnaryTests>
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# 15. positive unary test = simple positive unary test | "null" ;
|
176
|
+
#
|
177
|
+
rule positive_unary_test
|
178
|
+
simple_positive_unary_test /
|
179
|
+
null_literal
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# 16. positive unary tests = positive unary test , { "," , positive unary test } ;
|
184
|
+
#
|
185
|
+
rule positive_unary_tests
|
186
|
+
test:positive_unary_test more_tests:(__ "," __ positive_unary_test)* <PositiveUnaryTests>
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# 17. unary tests =
|
191
|
+
# 17.a positive unary tests |
|
192
|
+
# 17.b "not", " (", positive unary tests, ")" |
|
193
|
+
# 17.c "-"
|
194
|
+
#
|
195
|
+
|
196
|
+
#
|
197
|
+
# 18. endpoint = simple value ;
|
198
|
+
#
|
199
|
+
rule endpoint
|
200
|
+
arithmetic_expression /
|
201
|
+
simple_value
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
# 19. simple value = qualified name | simple literal ;
|
206
|
+
#
|
207
|
+
# Note: dmn-eval = simple literal | qualified name | function invocation
|
208
|
+
#
|
209
|
+
rule simple_value
|
210
|
+
literal /
|
211
|
+
function_invocation /
|
212
|
+
qualified_name
|
213
|
+
end
|
214
|
+
|
215
|
+
#
|
216
|
+
# 20. qualified name = name , { "." , name } ;
|
217
|
+
#
|
218
|
+
rule qualified_name
|
219
|
+
head:name tail:(__ "." __ name)* <QualifiedName>
|
220
|
+
end
|
221
|
+
|
222
|
+
#
|
223
|
+
# 21. addition = expression , "+" , expression ;
|
224
|
+
#
|
225
|
+
rule addition
|
226
|
+
head:non_recursive_simple_expression_for_arithmetic_expression __ "+" __ tail:expression <Addition>
|
227
|
+
end
|
228
|
+
|
229
|
+
rule non_recursive_simple_expression_for_arithmetic_expression
|
230
|
+
bracketed_arithmetic_expression /
|
231
|
+
simple_value
|
232
|
+
end
|
233
|
+
|
234
|
+
rule non_recursive_simple_expression_for_comparison
|
235
|
+
arithmetic_expression /
|
236
|
+
simple_value
|
237
|
+
end
|
238
|
+
|
239
|
+
#
|
240
|
+
# 22. subtraction = expression , "-" , expression ;
|
241
|
+
#
|
242
|
+
rule subtraction
|
243
|
+
head:non_recursive_simple_expression_for_arithmetic_expression __ "-" __ tail:expression <Subtraction>
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# 23. multiplication = expression , "\*" , expression ;
|
248
|
+
#
|
249
|
+
rule multiplication
|
250
|
+
head:non_recursive_simple_expression_for_arithmetic_expression __ "*" __ tail:expression <Multiplication>
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# 24. division = expression , "/" , expression ;
|
255
|
+
#
|
256
|
+
rule division
|
257
|
+
head:non_recursive_simple_expression_for_arithmetic_expression __ "/" __ tail:expression <Division>
|
258
|
+
end
|
259
|
+
|
260
|
+
#
|
261
|
+
# 25. exponentiation = expression, "\*\*", expression ;
|
262
|
+
#
|
263
|
+
rule exponentiation
|
264
|
+
head:non_recursive_simple_expression_for_arithmetic_expression __ "**" __ tail:expression <Exponentiation>
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
# 26. arithmetic negation = "-" , expression ;
|
269
|
+
#
|
270
|
+
rule arithmetic_negation
|
271
|
+
"not" __ "(" __ expr:expression __ ")" {
|
272
|
+
def eval(context={})
|
273
|
+
-expr.eval(context)
|
274
|
+
end
|
275
|
+
}
|
276
|
+
end
|
277
|
+
|
278
|
+
#
|
279
|
+
# 27. name = name start , { name part | additional name symbols } ;
|
280
|
+
#
|
281
|
+
rule name
|
282
|
+
head:name_start tail:(__ name_part)* <Name>
|
283
|
+
end
|
284
|
+
|
285
|
+
rule reserved_word
|
286
|
+
keyword /
|
287
|
+
date_time_keyword /
|
288
|
+
null_literal /
|
289
|
+
boolean_literal
|
290
|
+
end
|
291
|
+
|
292
|
+
#
|
293
|
+
# 28. name start = name start char, { name part char } ;
|
294
|
+
#
|
295
|
+
rule name_start
|
296
|
+
head:name_start_char tail:(name_part_char)* {
|
297
|
+
def eval(context={})
|
298
|
+
head + tail.map{|t| t[1]}.join("")
|
299
|
+
end
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
#
|
304
|
+
# 29. name part = name part char , { name part char } ;
|
305
|
+
#
|
306
|
+
rule name_part
|
307
|
+
head:name_part_char tail:(__ name_part_char)* {
|
308
|
+
def eval(context={})
|
309
|
+
head + tail.map{|t| t[1]}.join("")
|
310
|
+
end
|
311
|
+
}
|
312
|
+
end
|
313
|
+
|
314
|
+
#
|
315
|
+
# 30. name start char = "?" | [A-Z] | "\_" | [a-z] | [\uC0-\uD6] | [\uD8-\uF6] | [\uF8-\u2FF] | [\u370-\u37D] | [\u37F-\u1FFF] | [\u200C-\u200D] | [\u2070-\u218F] | [\u2C00-\u2FEF] | [\u3001-\uD7FF] | [\uF900-\uFDCF] | [\uFDF0-\uFFFD] | [\u10000-\uEFFFF] ;
|
316
|
+
#
|
317
|
+
rule name_start_char
|
318
|
+
[A-Z] / [a-z] / "_" / name_start_unicode_char
|
319
|
+
end
|
320
|
+
|
321
|
+
rule name_start_unicode_char
|
322
|
+
[\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]
|
323
|
+
end
|
324
|
+
|
325
|
+
#
|
326
|
+
# 31. name part char = name start char | digit | \uB7 | [\u0300-\u036F] | [\u203F-\u2040] ;
|
327
|
+
#
|
328
|
+
rule name_part_char
|
329
|
+
name_start_char /
|
330
|
+
digit /
|
331
|
+
name_part_unicode_char /
|
332
|
+
"'"
|
333
|
+
end
|
334
|
+
|
335
|
+
rule name_part_unicode_char
|
336
|
+
[\u0B70\u0300-\u036F\u203F-\u2040]
|
337
|
+
end
|
338
|
+
|
339
|
+
#
|
340
|
+
# 32. additional name symbols = "." | "/" | "-" | "’" | "+" | "\*" ;
|
341
|
+
#
|
342
|
+
rule additional_name_symbols
|
343
|
+
"." / "/" / "-" / "'" / "+" / "*"
|
344
|
+
end
|
345
|
+
|
346
|
+
#
|
347
|
+
# 33. literal = simple literal | "null" ;
|
348
|
+
#
|
349
|
+
rule literal
|
350
|
+
simple_literal /
|
351
|
+
null_literal
|
352
|
+
end
|
353
|
+
|
354
|
+
#
|
355
|
+
# 34. simple literal = numeric literal | string literal | boolean literal | date time literal ;
|
356
|
+
#
|
357
|
+
rule simple_literal
|
358
|
+
numeric_literal /
|
359
|
+
string_literal /
|
360
|
+
boolean_literal /
|
361
|
+
date_time_literal
|
362
|
+
end
|
363
|
+
|
364
|
+
#
|
365
|
+
# 35. string literal = '"' , { character – ('"' | vertical space) }, '"' ;
|
366
|
+
#
|
367
|
+
rule string_literal
|
368
|
+
'"' chars:double_string_character* '"' <StringLiteral> /
|
369
|
+
"'" chars:single_string_character* "'" <StringLiteral>
|
370
|
+
end
|
371
|
+
|
372
|
+
rule double_string_character
|
373
|
+
!('"' / "\\" / line_terminator) source_character /
|
374
|
+
"\\" escape_sequence /
|
375
|
+
line_continuation
|
376
|
+
end
|
377
|
+
|
378
|
+
rule single_string_character
|
379
|
+
!("'" / "\\" / line_terminator) source_character /
|
380
|
+
"\\" escape_sequence /
|
381
|
+
line_continuation
|
382
|
+
end
|
383
|
+
|
384
|
+
rule source_character
|
385
|
+
.
|
386
|
+
end
|
387
|
+
|
388
|
+
rule line_continuation
|
389
|
+
"\\" __ line_terminator_sequence __
|
390
|
+
end
|
391
|
+
|
392
|
+
rule escape_sequence
|
393
|
+
character_escape_sequence
|
394
|
+
end
|
395
|
+
|
396
|
+
rule character_escape_sequence
|
397
|
+
single_escape_character
|
398
|
+
end
|
399
|
+
|
400
|
+
rule single_escape_character
|
401
|
+
"'" / '"' / "\\"
|
402
|
+
end
|
403
|
+
|
404
|
+
rule line_terminator
|
405
|
+
line_terminator_sequence
|
406
|
+
end
|
407
|
+
|
408
|
+
rule line_terminator_sequence
|
409
|
+
"\n" / "\r" / "\r\n"
|
410
|
+
end
|
411
|
+
|
412
|
+
#
|
413
|
+
# 36. Boolean literal = "true" | "false" ;
|
414
|
+
#
|
415
|
+
rule boolean_literal
|
416
|
+
"true" <BooleanLiteral> /
|
417
|
+
"false" <BooleanLiteral>
|
418
|
+
end
|
419
|
+
|
420
|
+
#
|
421
|
+
# 37. numeric literal = [ "-" ] , ( digits , [ ".", digits ] | "." , digits ) ;
|
422
|
+
#
|
423
|
+
rule numeric_literal
|
424
|
+
'-'? digits ('.' digits)? <NumericLiteral>
|
425
|
+
end
|
426
|
+
|
427
|
+
rule null_literal
|
428
|
+
"null" <NullLiteral>
|
429
|
+
end
|
430
|
+
|
431
|
+
#
|
432
|
+
# 38. digit = [0-9] ;
|
433
|
+
#
|
434
|
+
rule digit
|
435
|
+
[0-9]
|
436
|
+
end
|
437
|
+
|
438
|
+
#
|
439
|
+
# 39. digits = digit , {digit} ;
|
440
|
+
#
|
441
|
+
rule digits
|
442
|
+
digit+
|
443
|
+
end
|
444
|
+
|
445
|
+
#
|
446
|
+
# 40. function invocation = expression , parameters ;
|
447
|
+
#
|
448
|
+
rule function_invocation
|
449
|
+
fn_name:(!reserved_word qualified_name) __ "(" __ params:(positional_parameters)? __ ")" <FunctionInvocation>
|
450
|
+
end
|
451
|
+
|
452
|
+
#
|
453
|
+
# 41. parameters = "(" , ( named parameters | positional parameters ) , ")" ;
|
454
|
+
#
|
455
|
+
|
456
|
+
#
|
457
|
+
# 42. named parameters = parameter name , ":" , expression , { "," , parameter name , ":" , expression } ;
|
458
|
+
#
|
459
|
+
|
460
|
+
#
|
461
|
+
# 43. parameter name = name ;
|
462
|
+
#
|
463
|
+
|
464
|
+
#
|
465
|
+
# 44. positional parameters = [ expression , { "," , expression } ] ;
|
466
|
+
#
|
467
|
+
rule positional_parameters
|
468
|
+
expression __ more_expressions:(__ "," __ expression)* <PositionalParameters>
|
469
|
+
end
|
470
|
+
|
471
|
+
#
|
472
|
+
# 45. path expression = expression , "." , name ;
|
473
|
+
#
|
474
|
+
rule path_expression
|
475
|
+
expression __ "." __ name:name <PathExpression>
|
476
|
+
end
|
477
|
+
|
478
|
+
#
|
479
|
+
# 46. for expression = "for" , name , "in" , expression { "," , name , "in" , expression } , "return" , expression ;
|
480
|
+
#
|
481
|
+
rule for_expression
|
482
|
+
"for" __ name:name __ "in" __ expression __ more_for_expressions:(__ "," __ name:name __ "in" __ expression)* __ "return" __ return_expression:expression <ForExpression>
|
483
|
+
end
|
484
|
+
|
485
|
+
#
|
486
|
+
# 47. if expression = "if" , expression , "then" , expression , "else" expression ;
|
487
|
+
#
|
488
|
+
rule if_expression
|
489
|
+
"if" __ condition:expression __ "then" __ true_case:expression __ "else" __ false_case:expression <IfExpression>
|
490
|
+
end
|
491
|
+
|
492
|
+
#
|
493
|
+
# 48. quantified expression = ("some" | "every") , name , "in" , expression , { name , "in" , expression } , "satisfies" , expression ;
|
494
|
+
#
|
495
|
+
rule quantified_expression
|
496
|
+
quantifier:("some" / "every") __ name:name __ "in" __ expression __ more_quantifiers:(__ name:name __ "in" __ expression)* __ "satisfies" __ satisfies:expression <QuantifiedExpression>
|
497
|
+
end
|
498
|
+
|
499
|
+
#
|
500
|
+
# 49. disjunction = expression , "or" , expression ;
|
501
|
+
#
|
502
|
+
rule disjunction
|
503
|
+
head:expression tail:(__ "or" __ expression)+ <Disjunction>
|
504
|
+
end
|
505
|
+
|
506
|
+
#
|
507
|
+
# 50. conjunction = expression , "and" , expression ;
|
508
|
+
#
|
509
|
+
rule conjunction
|
510
|
+
head:expression tail:(__ "and" __ expression)+ <Conjunction>
|
511
|
+
end
|
512
|
+
|
513
|
+
#
|
514
|
+
# 51. comparison =
|
515
|
+
# 51.a expression , ( "=" | "!=" | "<" | "<=" | ">" | ">=" ) , expression |
|
516
|
+
# 51.b expression , "between" , expression , "and" , expression |
|
517
|
+
# 51.c expression , "in" , positive unary test ;
|
518
|
+
# 51.d expression , "in" , " (", positive unary tests, ")" ;
|
519
|
+
#
|
520
|
+
rule comparison
|
521
|
+
left:non_recursive_simple_expression_for_comparison __ operator:comparision_operator __ right:expression <Comparison>
|
522
|
+
end
|
523
|
+
|
524
|
+
rule non_recursive_simple_expression_for_comparison
|
525
|
+
arithmetic_expression /
|
526
|
+
simple_value
|
527
|
+
end
|
528
|
+
|
529
|
+
#
|
530
|
+
# 52. filter expression = expression , "[" , expression , "]" ;
|
531
|
+
#
|
532
|
+
rule filter_expression
|
533
|
+
expression __ "[" __ filter:expression __ "]" <FilterExpression>
|
534
|
+
end
|
535
|
+
|
536
|
+
rule comparision_operator
|
537
|
+
"=" / "!=" / "<=" / ">=" / "<" / ">"
|
538
|
+
end
|
539
|
+
|
540
|
+
#
|
541
|
+
# 53. instance of = expression , "instance" , "of" , type ;
|
542
|
+
#
|
543
|
+
rule instance_of
|
544
|
+
expression __ "instance" __ "of" __ type <InstanceOf>
|
545
|
+
end
|
546
|
+
|
547
|
+
#
|
548
|
+
# 54. type = qualified name ;
|
549
|
+
#
|
550
|
+
rule type
|
551
|
+
qualified_name
|
552
|
+
end
|
553
|
+
|
554
|
+
#
|
555
|
+
# 55. boxed expression = list | function definition | context ;
|
556
|
+
#
|
557
|
+
# Note: function definition not supported yet
|
558
|
+
#
|
559
|
+
rule boxed_expression
|
560
|
+
list /
|
561
|
+
context
|
562
|
+
end
|
563
|
+
|
564
|
+
#
|
565
|
+
# 56. list = "[" [ expression , { "," , expression } ] , "]" ;
|
566
|
+
#
|
567
|
+
rule list
|
568
|
+
'[' __ list_entries __ ']' <List>
|
569
|
+
/
|
570
|
+
'[]' <List>
|
571
|
+
end
|
572
|
+
|
573
|
+
rule list_entries
|
574
|
+
expression more_expressions:(__ ',' __ expression)* <ListEntries>
|
575
|
+
end
|
576
|
+
|
577
|
+
#
|
578
|
+
# 57. function definition = "function" , "(" , [ formal parameter { "," , formal parameter } ] , ")" , [ "external" ] , expression ;
|
579
|
+
#
|
580
|
+
rule function_definition
|
581
|
+
"function" __ "(" __ formal_parameters:(formal_parameter_list)? __ ")" __ external:(__ "external")? __ expression <FunctionDefinition>
|
582
|
+
end
|
583
|
+
|
584
|
+
#
|
585
|
+
# 58. formal parameter = parameter name ;
|
586
|
+
#
|
587
|
+
rule formal_parameter
|
588
|
+
parameter_name:name <FormalParameter>
|
589
|
+
end
|
590
|
+
|
591
|
+
#
|
592
|
+
# 59. context = "{" , [context entry , { "," , context entry } ] , "}" ;
|
593
|
+
#
|
594
|
+
rule context
|
595
|
+
'{' __ entries:(context_entry_list)? __ '}' <Context>
|
596
|
+
/
|
597
|
+
'{}' <Context>
|
598
|
+
end
|
599
|
+
|
600
|
+
rule context_entry_list
|
601
|
+
context_entry tail:(__ ',' __ context_entry)* ','? <ContextEntryList>
|
602
|
+
end
|
603
|
+
|
604
|
+
#
|
605
|
+
# 60. context entry = key , ":" , expression ;
|
606
|
+
#
|
607
|
+
rule context_entry
|
608
|
+
context_key:expression __ ':' __ context_value:expression <ContextEntry>
|
609
|
+
end
|
610
|
+
|
611
|
+
#
|
612
|
+
# 61. key = name | string literal ;
|
613
|
+
#
|
614
|
+
|
615
|
+
#
|
616
|
+
# 62. date time literal = ( "date" | "time" | "date and time" | "duration" ) , "(" , string literal , ")" ;
|
617
|
+
#
|
618
|
+
rule date_time_literal
|
619
|
+
keyword:date_time_keyword __ "(" __ head:expression __ tail:("," __ expression)* __ ")" <DateTimeLiteral>
|
620
|
+
end
|
621
|
+
|
622
|
+
rule date_time_keyword
|
623
|
+
"date and time" /
|
624
|
+
"time" /
|
625
|
+
"date" /
|
626
|
+
"duration"
|
627
|
+
end
|
628
|
+
|
629
|
+
rule keyword
|
630
|
+
true_token /
|
631
|
+
false_token /
|
632
|
+
null_token /
|
633
|
+
not_token
|
634
|
+
end
|
635
|
+
|
636
|
+
rule not_token
|
637
|
+
"not"
|
638
|
+
end
|
639
|
+
|
640
|
+
rule true_token
|
641
|
+
"true" / "TRUE" / "True" !name_part_char
|
642
|
+
end
|
643
|
+
|
644
|
+
rule false_token
|
645
|
+
"false" / "FALSE" / "False" !name_part_char
|
646
|
+
end
|
647
|
+
|
648
|
+
rule null_token
|
649
|
+
"null" !name_part_char
|
650
|
+
end
|
651
|
+
|
652
|
+
rule __
|
653
|
+
white_space*
|
654
|
+
end
|
655
|
+
|
656
|
+
rule white_space
|
657
|
+
" " / "\t" / "\n" / "\r"
|
658
|
+
end
|
659
|
+
end
|
data/lib/spot_feel.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "spot_feel/version"
|
4
|
+
|
5
|
+
require "awesome_print"
|
6
|
+
|
7
|
+
require "active_support"
|
8
|
+
require "active_support/duration"
|
9
|
+
require "active_support/time"
|
10
|
+
require "active_support/core_ext/hash"
|
11
|
+
require "active_support/core_ext/object/json"
|
12
|
+
require "active_support/configurable"
|
13
|
+
|
14
|
+
require "treetop"
|
15
|
+
require "xmlhasher"
|
16
|
+
|
17
|
+
require "spot_feel/configuration"
|
18
|
+
require "spot_feel/nodes"
|
19
|
+
require "spot_feel/parser"
|
20
|
+
|
21
|
+
require "spot_feel/dmn"
|
22
|
+
|
23
|
+
module SpotFeel
|
24
|
+
class SyntaxError < StandardError; end
|
25
|
+
class EvaluationError < StandardError; end
|
26
|
+
|
27
|
+
def self.evaluate(expression_text, variables: {})
|
28
|
+
literal_expression = Dmn::LiteralExpression.new(text: expression_text)
|
29
|
+
raise SyntaxError, "Expression is not valid" unless literal_expression.valid?
|
30
|
+
literal_expression.evaluate(variables)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.test(input, unary_tests_text, variables: {})
|
34
|
+
unary_tests = Dmn::UnaryTests.new(text: unary_tests_text)
|
35
|
+
raise SyntaxError, "Unary tests are not valid" unless unary_tests.valid?
|
36
|
+
unary_tests.test(input, variables)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.decide(decision_id, definitions: nil, definitions_json: nil, definitions_xml: nil, variables: {})
|
40
|
+
if definitions_xml.present?
|
41
|
+
definitions = Dmn::Definitions.from_xml(definitions_xml)
|
42
|
+
elsif definitions_json.present?
|
43
|
+
definitions = Dmn::Definitions.from_json(definitions_json)
|
44
|
+
end
|
45
|
+
definitions.evaluate(decision_id, variables: variables)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.definitions_from_xml(xml)
|
49
|
+
Dmn::Definitions.from_xml(xml)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.definitions_from_json(json)
|
53
|
+
Dmn::Definitions.from_json(json)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.config
|
57
|
+
@config ||= Configuration.new
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.configure
|
61
|
+
yield(config)
|
62
|
+
end
|
63
|
+
end
|