pg-verify 0.1.0

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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +98 -0
  5. data/README.md +29 -0
  6. data/Rakefile +62 -0
  7. data/bin/console +15 -0
  8. data/bin/pg-verify.rb +18 -0
  9. data/bin/setup +8 -0
  10. data/calc.ebnf +21 -0
  11. data/data/config/pg-verify.yml +66 -0
  12. data/data/nusmv.sample.smv +179 -0
  13. data/data/project-template/.gitignore.resource +4 -0
  14. data/data/project-template/.pg-verify.yml +0 -0
  15. data/data/project-template/README.md +18 -0
  16. data/data/project-template/addon/.keep +0 -0
  17. data/data/project-template/program-graph.rb.resource +103 -0
  18. data/devpg +5 -0
  19. data/doc/examples/railroad_crossing.rb +61 -0
  20. data/doc/examples/train-tree.rb +43 -0
  21. data/doc/examples/weidezaun.rb +99 -0
  22. data/doc/examples/weidezaun.txt +29 -0
  23. data/doc/expose/definition.png +0 -0
  24. data/doc/expose/diagram.png +0 -0
  25. data/doc/expose/expose.md +359 -0
  26. data/doc/expose/validity.png +0 -0
  27. data/exe/pg-verify +4 -0
  28. data/integration_tests/ruby_dsl/001_states.rb +10 -0
  29. data/integration_tests/ruby_dsl/002_transitions.rb +10 -0
  30. data/integration_tests/ruby_dsl/003_actions.rb +14 -0
  31. data/integration_tests/ruby_dsl/004_guards.rb +18 -0
  32. data/integration_tests/ruby_dsl/005_variables.rb +16 -0
  33. data/integration_tests/ruby_dsl/006_state_variables.rb +26 -0
  34. data/integration_tests/ruby_dsl/007_variable_initialization.rb +28 -0
  35. data/integration_tests/ruby_dsl/008_state_initialization.rb +19 -0
  36. data/integration_tests/ruby_dsl/009_shared_variables.rb +26 -0
  37. data/integration_tests/ruby_dsl/010_complex_guards.rb +18 -0
  38. data/integration_tests/ruby_dsl/011_complex_actions.rb +16 -0
  39. data/integration_tests/ruby_dsl/012_error_components.rb +9 -0
  40. data/integration_tests/ruby_dsl/013_hazards.rb +25 -0
  41. data/integration_tests/ruby_dsl/014_tau_transitions.rb +26 -0
  42. data/integration_tests/ruby_dsl/015_basic_dcca.rb +19 -0
  43. data/integration_tests/ruby_dsl/016_pressure_tank.rb +146 -0
  44. data/lib/pg-verify/cli/cli.rb +235 -0
  45. data/lib/pg-verify/core/cmd_runner.rb +151 -0
  46. data/lib/pg-verify/core/core.rb +38 -0
  47. data/lib/pg-verify/core/extensions/array_extensions.rb +11 -0
  48. data/lib/pg-verify/core/extensions/enumerable_extensions.rb +19 -0
  49. data/lib/pg-verify/core/extensions/nil_extensions.rb +7 -0
  50. data/lib/pg-verify/core/extensions/string_extensions.rb +84 -0
  51. data/lib/pg-verify/core/shell/colorizer.rb +136 -0
  52. data/lib/pg-verify/core/shell/shell.rb +0 -0
  53. data/lib/pg-verify/core/util.rb +146 -0
  54. data/lib/pg-verify/doctor/doctor.rb +180 -0
  55. data/lib/pg-verify/ebnf_parser/ast.rb +31 -0
  56. data/lib/pg-verify/ebnf_parser/ebnf_parser.rb +26 -0
  57. data/lib/pg-verify/ebnf_parser/expression_parser.rb +177 -0
  58. data/lib/pg-verify/ebnf_parser/expression_parser2.rb +422 -0
  59. data/lib/pg-verify/ebnf_parser/expressions.ebnf +33 -0
  60. data/lib/pg-verify/ebnf_parser/expressions.peg +52 -0
  61. data/lib/pg-verify/ebnf_parser/parser_result.rb +26 -0
  62. data/lib/pg-verify/interpret/component_context.rb +125 -0
  63. data/lib/pg-verify/interpret/graph_context.rb +85 -0
  64. data/lib/pg-verify/interpret/interpret.rb +142 -0
  65. data/lib/pg-verify/interpret/pg_script.rb +72 -0
  66. data/lib/pg-verify/interpret/spec/ltl_builder.rb +90 -0
  67. data/lib/pg-verify/interpret/spec/spec_context.rb +32 -0
  68. data/lib/pg-verify/interpret/spec/spec_set_context.rb +67 -0
  69. data/lib/pg-verify/interpret/transition_context.rb +55 -0
  70. data/lib/pg-verify/model/allocation_set.rb +28 -0
  71. data/lib/pg-verify/model/assignment.rb +34 -0
  72. data/lib/pg-verify/model/component.rb +40 -0
  73. data/lib/pg-verify/model/dcca/hazard.rb +16 -0
  74. data/lib/pg-verify/model/dcca.rb +67 -0
  75. data/lib/pg-verify/model/expression.rb +106 -0
  76. data/lib/pg-verify/model/graph.rb +58 -0
  77. data/lib/pg-verify/model/model.rb +10 -0
  78. data/lib/pg-verify/model/parsed_expression.rb +77 -0
  79. data/lib/pg-verify/model/simulation/trace.rb +43 -0
  80. data/lib/pg-verify/model/simulation/variable_state.rb +23 -0
  81. data/lib/pg-verify/model/source_location.rb +45 -0
  82. data/lib/pg-verify/model/specs/spec.rb +44 -0
  83. data/lib/pg-verify/model/specs/spec_result.rb +25 -0
  84. data/lib/pg-verify/model/specs/spec_set.rb +43 -0
  85. data/lib/pg-verify/model/specs/specification.rb +50 -0
  86. data/lib/pg-verify/model/transition.rb +41 -0
  87. data/lib/pg-verify/model/validation/assignment_to_state_variable_validation.rb +26 -0
  88. data/lib/pg-verify/model/validation/empty_state_set_validation.rb +18 -0
  89. data/lib/pg-verify/model/validation/errors.rb +119 -0
  90. data/lib/pg-verify/model/validation/foreign_assignment_validation.rb +30 -0
  91. data/lib/pg-verify/model/validation/unknown_token_validation.rb +35 -0
  92. data/lib/pg-verify/model/validation/validation.rb +23 -0
  93. data/lib/pg-verify/model/variable.rb +47 -0
  94. data/lib/pg-verify/model/variable_set.rb +84 -0
  95. data/lib/pg-verify/nusmv/nusmv.rb +23 -0
  96. data/lib/pg-verify/nusmv/runner.rb +124 -0
  97. data/lib/pg-verify/puml/puml.rb +23 -0
  98. data/lib/pg-verify/shell/loading/line_animation.rb +36 -0
  99. data/lib/pg-verify/shell/loading/loading_animation.rb +80 -0
  100. data/lib/pg-verify/shell/loading/loading_prompt.rb +43 -0
  101. data/lib/pg-verify/shell/loading/no_animation.rb +20 -0
  102. data/lib/pg-verify/shell/shell.rb +30 -0
  103. data/lib/pg-verify/simulation/simulation.rb +7 -0
  104. data/lib/pg-verify/simulation/simulator.rb +90 -0
  105. data/lib/pg-verify/simulation/state.rb +53 -0
  106. data/lib/pg-verify/transform/hash_transformation.rb +104 -0
  107. data/lib/pg-verify/transform/nusmv_transformation.rb +261 -0
  108. data/lib/pg-verify/transform/puml_transformation.rb +89 -0
  109. data/lib/pg-verify/transform/transform.rb +8 -0
  110. data/lib/pg-verify/version.rb +5 -0
  111. data/lib/pg-verify.rb +47 -0
  112. data/pg-verify.gemspec +38 -0
  113. data/sig/pg-verify.rbs +4 -0
  114. metadata +226 -0
@@ -0,0 +1,422 @@
1
+ module PgVerify
2
+ module EbnfParser
3
+
4
+ class ExpressionParser2
5
+ include EBNF::PEG::Parser
6
+
7
+ # Abstract syntax tree from parse
8
+ attr_reader :ast
9
+ attr_accessor :rules
10
+ attr_accessor :options
11
+ attr_accessor :type
12
+
13
+ # Rule: '[20] CMPOP ::= "<=" | ">=" | "<" | ">" | "==" | "!="'
14
+ production(:CMPOP) do |input|
15
+ output = input
16
+ puts "CMPOP: '#{input}' -> '#{output}'"
17
+ output
18
+ end
19
+
20
+ # Rule: '[19.2] _VARIABLE_2 ::= [a-zA-Z_]'
21
+ production(:_VARIABLE_2) do |input|
22
+ output = input
23
+ puts "_VARIABLE_2: '#{input}' -> '#{output}'"
24
+ output
25
+ end
26
+
27
+ # Rule: '[19.6] _VARIABLE_6 ::= [a-zA-Z0-9_]'
28
+ production(:_VARIABLE_6) do |input|
29
+ output = input
30
+ puts "_VARIABLE_6: '#{input}' -> '#{output}'"
31
+ output
32
+ end
33
+
34
+ # Rule: '[19.5] _VARIABLE_5 ::= _VARIABLE_6*'
35
+ production(:_VARIABLE_5) do |input|
36
+ output = input
37
+ puts "_VARIABLE_5: '#{input}' -> '#{output}'"
38
+ output
39
+ end
40
+
41
+ # Rule: '[19.4] _VARIABLE_4 ::= [a-zA-Z_]'
42
+ production(:_VARIABLE_4) do |input|
43
+ output = input
44
+ puts "_VARIABLE_4: '#{input}' -> '#{output}'"
45
+ output
46
+ end
47
+
48
+ # Rule: '[19.3] _VARIABLE_3 ::= [^('true'#x20|#x20'false')]'
49
+ production(:_VARIABLE_3) do |input|
50
+ output = input
51
+ puts "_VARIABLE_3: '#{input}' -> '#{output}'"
52
+ output
53
+ end
54
+
55
+ # Rule: '[19.1] _VARIABLE_1 ::= _VARIABLE_3 _VARIABLE_4 _VARIABLE_5'
56
+ production(:_VARIABLE_1) do |input|
57
+ output = input
58
+ puts "_VARIABLE_1: '#{input}' -> '#{output}'"
59
+ output
60
+ end
61
+
62
+ # Rule: '[19] VARIABLE ::= _VARIABLE_1 | _VARIABLE_2'
63
+ production(:VARIABLE) do |input|
64
+ output = input
65
+ puts "VARIABLE: '#{input}' -> '#{output}'"
66
+ output
67
+ end
68
+
69
+ # Rule: '[18.1] _BOOL_1 ::= "(" BoolExpr ")"'
70
+ production(:_BOOL_1) do |input|
71
+ output = input
72
+ puts "_BOOL_1: '#{input}' -> '#{output}'"
73
+ output
74
+ end
75
+
76
+ # Rule: '[18] BOOL ::= "true" | "false" | _BOOL_1'
77
+ production(:BOOL) do |input|
78
+ output = input
79
+ puts "BOOL: '#{input}' -> '#{output}'"
80
+ output
81
+ end
82
+
83
+ # Rule: '[17.3] _NUMBER_3 ::= [0-9]'
84
+ production(:_NUMBER_3) do |input|
85
+ output = input
86
+ puts "_NUMBER_3: '#{input}' -> '#{output}'"
87
+ output
88
+ end
89
+
90
+ # Rule: '[17.2] _NUMBER_2 ::= _NUMBER_3+'
91
+ production(:_NUMBER_2) do |input|
92
+ output = input
93
+ puts "_NUMBER_2: '#{input}' -> '#{output}'"
94
+ output
95
+ end
96
+
97
+ # Rule: '[17.1] _NUMBER_1 ::= "-"?'
98
+ production(:_NUMBER_1) do |input|
99
+ output = input
100
+ puts "_NUMBER_1: '#{input}' -> '#{output}'"
101
+ output
102
+ end
103
+
104
+ # Rule: '[17] NUMBER ::= _NUMBER_1 _NUMBER_2'
105
+ production(:NUMBER) do |input|
106
+ output = input
107
+ puts "NUMBER: '#{input}' -> '#{output}'"
108
+ output
109
+ end
110
+
111
+ # Rule: '[16.1] _Value_1 ::= "(" Expression ")"'
112
+ production(:_Value_1) do |input|
113
+ output = input
114
+ puts "_Value_1: '#{input}' -> '#{output}'"
115
+ output
116
+ end
117
+
118
+ # Rule: '[16] Value ::= NUMBER | VARIABLE | _Value_1'
119
+ production(:Value) do |input|
120
+ output = input
121
+ puts "Value: '#{input}' -> '#{output}'"
122
+ output
123
+ end
124
+
125
+ # Rule: '[15.3] _Product_3 ::= "*" | "/"'
126
+ production(:_Product_3) do |input|
127
+ output = input
128
+ puts "_Product_3: '#{input}' -> '#{output}'"
129
+ output
130
+ end
131
+
132
+ # Rule: '[15.2] _Product_2 ::= _Product_3 Value'
133
+ production(:_Product_2) do |input|
134
+ operation = input.first[:_Product_3]
135
+ value = input.last[:Value]
136
+ output = "#{operation} #{value}"
137
+ puts "_Product_2: '#{input}' -> '#{output}'"
138
+ output
139
+ end
140
+
141
+ # Rule: '[15.1] _Product_1 ::= _Product_2*'
142
+ production(:_Product_1) do |input|
143
+ output = input
144
+ puts "_Product_1: '#{input}' -> '#{output}'"
145
+ output
146
+ end
147
+
148
+ # Rule: '[15] Product ::= Value _Product_1'
149
+ production(:Product) do |input|
150
+ value = input.first[:Value]
151
+ product_1_results = input.last[:_Product_1]
152
+ output = "#{value} #{product_1_results.join(' ')}"
153
+ puts "Product: '#{input}' -> '#{output}'"
154
+ output
155
+ end
156
+
157
+ # Rule: '[14.3] _Sum_3 ::= "+" | "-"'
158
+ production(:_Sum_3) do |input|
159
+ output = input
160
+ puts "_Sum_3: '#{input}' -> '#{output}'"
161
+ output
162
+ end
163
+
164
+ # Rule: '[14.2] _Sum_2 ::= _Sum_3 Product'
165
+ production(:_Sum_2) do |input|
166
+ operation = input.first[:_Sum_3]
167
+ value = input.last[:Product]
168
+ output = "#{operation} #{value}"
169
+ puts "_Sum_2: '#{input}' -> '#{output}'"
170
+ output
171
+ end
172
+
173
+ # Rule: '[14.1] _Sum_1 ::= _Sum_2*'
174
+ production(:_Sum_1) do |input|
175
+ output = input
176
+ puts "_Sum_1: '#{input}' -> '#{output}'"
177
+ output
178
+ end
179
+
180
+ # Rule: '[14] Sum ::= Product _Sum_1'
181
+ production(:Sum) do |input|
182
+ value = input.first[:Product]
183
+ sum_1_results = input.last[:_Sum_1]
184
+ output = "#{value} #{sum_1_results.join(' ')}"
185
+ puts "Sum: '#{input}' -> '#{output}'"
186
+ output
187
+ end
188
+
189
+ # Rule: '[13] IntExpr ::= Sum'
190
+ production(:IntExpr) do |input|
191
+ output = input
192
+ puts "IntExpr: '#{input}' -> '#{output}'"
193
+ output
194
+ end
195
+
196
+ # Rule: '[12.3] _Comparison_3 ::= CMPOP Sum'
197
+ production(:_Comparison_3) do |input|
198
+ output = input
199
+ puts "_Comparison_3: '#{input}' -> '#{output}'"
200
+ output
201
+ end
202
+
203
+ # Rule: '[12.2] _Comparison_2 ::= _Comparison_3+'
204
+ production(:_Comparison_2) do |input|
205
+ output = input
206
+ puts "_Comparison_2: '#{input}' -> '#{output}'"
207
+ output
208
+ end
209
+
210
+ # Rule: '[12.1] _Comparison_1 ::= Sum _Comparison_2'
211
+ production(:_Comparison_1) do |input|
212
+ output = input
213
+ puts "_Comparison_1: '#{input}' -> '#{output}'"
214
+ output
215
+ end
216
+
217
+ # Rule: '[12] Comparison ::= BOOL | _Comparison_1'
218
+ production(:Comparison) do |input|
219
+ output = input
220
+ puts "Comparison: '#{input}' -> '#{output}'"
221
+ output
222
+ end
223
+
224
+ # Rule: '[11.1] _Negation_1 ::= "!" Comparison'
225
+ production(:_Negation_1) do |input|
226
+ output = input
227
+ puts "_Negation_1: '#{input}' -> '#{output}'"
228
+ output
229
+ end
230
+
231
+ # Rule: '[11] Negation ::= _Negation_1 | Comparison'
232
+ production(:Negation) do |input|
233
+ output = input
234
+ puts "Negation: '#{input}' -> '#{output}'"
235
+ output
236
+ end
237
+
238
+ # Rule: '[10.2] _Konjunction_2 ::= "&&" Negation'
239
+ production(:_Konjunction_2) do |input|
240
+ output = input
241
+ puts "_Konjunction_2: '#{input}' -> '#{output}'"
242
+ output
243
+ end
244
+
245
+ # Rule: '[10.1] _Konjunction_1 ::= _Konjunction_2*'
246
+ production(:_Konjunction_1) do |input|
247
+ output = input
248
+ puts "_Konjunction_1: '#{input}' -> '#{output}'"
249
+ output
250
+ end
251
+
252
+ # Rule: '[10] Konjunction ::= Negation _Konjunction_1'
253
+ production(:Konjunction) do |input|
254
+ output = input
255
+ puts "Konjunction: '#{input}' -> '#{output}'"
256
+ output
257
+ end
258
+
259
+ # Rule: '[9.2] _Disjunction_2 ::= "||" Konjunction'
260
+ production(:_Disjunction_2) do |input|
261
+ output = input
262
+ puts "_Disjunction_2: '#{input}' -> '#{output}'"
263
+ output
264
+ end
265
+
266
+ # Rule: '[9.1] _Disjunction_1 ::= _Disjunction_2*'
267
+ production(:_Disjunction_1) do |input|
268
+ output = input
269
+ puts "_Disjunction_1: '#{input}' -> '#{output}'"
270
+ output
271
+ end
272
+
273
+ # Rule: '[9] Disjunction ::= Konjunction _Disjunction_1'
274
+ production(:Disjunction) do |input|
275
+ output = input
276
+ puts "Disjunction: '#{input}' -> '#{output}'"
277
+ output
278
+ end
279
+
280
+ # Rule: '[8.2] _Implication_2 ::= "->" Disjunction'
281
+ production(:_Implication_2) do |input|
282
+ output = input
283
+ puts "_Implication_2: '#{input}' -> '#{output}'"
284
+ output
285
+ end
286
+
287
+ # Rule: '[8.1] _Implication_1 ::= _Implication_2*'
288
+ production(:_Implication_1) do |input|
289
+ output = input
290
+ puts "_Implication_1: '#{input}' -> '#{output}'"
291
+ output
292
+ end
293
+
294
+ # Rule: '[8] Implication ::= Disjunction _Implication_1'
295
+ production(:Implication) do |input|
296
+ output = input
297
+ puts "Implication: '#{input}' -> '#{output}'"
298
+ output
299
+ end
300
+
301
+ # Rule: '[7.3] _Equivalence_3 ::= "<->" | "<!>"'
302
+ production(:_Equivalence_3) do |input|
303
+ output = input
304
+ puts "_Equivalence_3: '#{input}' -> '#{output}'"
305
+ output
306
+ end
307
+
308
+ # Rule: '[7.2] _Equivalence_2 ::= _Equivalence_3 Implication'
309
+ production(:_Equivalence_2) do |input|
310
+ output = input
311
+ puts "_Equivalence_2: '#{input}' -> '#{output}'"
312
+ output
313
+ end
314
+
315
+ # Rule: '[7.1] _Equivalence_1 ::= _Equivalence_2*'
316
+ production(:_Equivalence_1) do |input|
317
+ output = input
318
+ puts "_Equivalence_1: '#{input}' -> '#{output}'"
319
+ output
320
+ end
321
+
322
+ # Rule: '[7] Equivalence ::= Implication _Equivalence_1'
323
+ production(:Equivalence) do |input|
324
+ output = input
325
+ puts "Equivalence: '#{input}' -> '#{output}'"
326
+ output
327
+ end
328
+
329
+ # Rule: '[6] BoolExpr ::= Equivalence'
330
+ production(:BoolExpr) do |input|
331
+ output = input
332
+ puts "BoolExpr: '#{input}' -> '#{output}'"
333
+ output
334
+ end
335
+
336
+ # Rule: '[5] Expression ::= BoolExpr | IntExpr'
337
+ production(:Expression) do |input|
338
+ output = input
339
+ puts "Expression: '#{input}' -> '#{output}'"
340
+ output
341
+ end
342
+
343
+ # Rule: '[4] Assignment ::= VARIABLE ":=" IntExpr'
344
+ production(:Assignment) do |input|
345
+ output = input
346
+ puts "Assignment: '#{input}' -> '#{output}'"
347
+ output
348
+ end
349
+
350
+ # Rule: '[3] Precon ::= BoolExpr'
351
+ production(:Precon) do |input|
352
+ output = input
353
+ puts "Precon: '#{input}' -> '#{output}'"
354
+ output
355
+ end
356
+
357
+ # Rule: '[2] Guard ::= BoolExpr'
358
+ production(:Guard) do |input|
359
+ output = input
360
+ puts "Guard: '#{input}' -> '#{output}'"
361
+ output
362
+ end
363
+
364
+ # Rule: '[1.2] _Action_2 ::= "|" Assignment'
365
+ production(:_Action_2) do |input|
366
+ output = input
367
+ puts "_Action_2: '#{input}' -> '#{output}'"
368
+ output
369
+ end
370
+
371
+ # Rule: '[1.1] _Action_1 ::= _Action_2*'
372
+ production(:_Action_1) do |input|
373
+ output = input
374
+ puts "_Action_1: '#{input}' -> '#{output}'"
375
+ output
376
+ end
377
+
378
+ # Rule: '[1] Action ::= Assignment _Action_1'
379
+ production(:Action) do |input|
380
+ output = input
381
+ puts "Action: '#{input}' -> '#{output}'"
382
+ output
383
+ end
384
+
385
+
386
+ def initialize(type: :Expression)
387
+ @type = type
388
+ @options = {}
389
+ # @options[:logger] = Logger.new(STDERR)
390
+ # @options[:logger].level = :info
391
+ # @options[:logger].formatter = lambda {|severity, datetime, progname, msg| "#{severity} #{msg}\n"}
392
+
393
+ # Intantiate the grammar
394
+ ebnf_file = File.expand_path("expressions.ebnf", __dir__)
395
+ # Perform PEG-specific transformation to the associated rules, which will be passed directly to the parser.
396
+ @rules = EBNF.parse(File.open(ebnf_file)).make_peg.ast
397
+
398
+ end
399
+
400
+ def parse!(input)
401
+ raise "Empty expression!" if input.nil? || input.empty?
402
+ ast_map = parse(input, @type, @rules, **@options)
403
+ Ast.new(ast_map)
404
+ end
405
+
406
+ # def evaluate!(input, type: :Expression)
407
+ # # TODO: Change this to actually eval (Also in specs)
408
+ # parse(input, type, @rules, **@options)
409
+ # end
410
+
411
+ # def accepts?(input, type: :Expression)
412
+ # begin
413
+ # evaluate!(input, type: type)
414
+ # return true
415
+ # rescue EBNF::PEG::Parser::Error => e
416
+ # return false
417
+ # end
418
+ # end
419
+ end
420
+
421
+ end
422
+ end
@@ -0,0 +1,33 @@
1
+ /*
2
+ This grammar accepts a combination of
3
+ Note that boolean variables are not supported, thus
4
+ this expression will be rejected: 'A && true'
5
+ */
6
+
7
+ [1] Action ::= Assignment ('|' Assignment)*
8
+ [2] Guard ::= BoolExpr
9
+ [3] Precon ::= BoolExpr
10
+
11
+ [4] Assignment ::= VARIABLE ':=' IntExpr
12
+ [5] Expression ::= BoolExpr | IntExpr
13
+
14
+ [6] BoolExpr ::= Equivalence
15
+ [7] Equivalence ::= Implication (('<->' | '<!>') Implication)*
16
+ [8] Implication ::= Disjunction ('->' Disjunction)*
17
+ [9] Disjunction ::= Konjunction ('||' Konjunction)*
18
+ [10] Konjunction ::= Negation ('&&' Negation)*
19
+ [11] Negation ::= '!' Comparison | Comparison
20
+
21
+ [12] Comparison ::= BOOL | Sum (CMPOP Sum)+
22
+
23
+ [13] IntExpr ::= Sum
24
+ [14] Sum ::= Product (('+' | '-') Product)*
25
+ [15] Product ::= Value (('*' | '/') Value)*
26
+ [16] Value ::= NUMBER | VARIABLE | '(' Expression ')'
27
+
28
+ [17] NUMBER ::= '-'?[0-9]+
29
+ [18] BOOL ::= 'true' | 'false' | '(' BoolExpr ')'
30
+ // Note that we do have to exclude 'true' & 'false' because otherwise 'true' & 'false'
31
+ // would be legal Integer expressions as they would be considered variables
32
+ [19] VARIABLE ::= [^('true' | 'false')][a-zA-Z_][a-zA-Z0-9_]* | [a-zA-Z_]
33
+ [20] CMPOP ::= '<=' | '>=' | '<' | '>' | '==' | '!='
@@ -0,0 +1,52 @@
1
+ [1] Action ::= Assignment _Action_1
2
+ [1.1] _Action_1 ::= _Action_2*
3
+ [1.2] _Action_2 ::= "|" Assignment
4
+ [2] Guard ::= BoolExpr
5
+ [3] Precon ::= BoolExpr
6
+ [4] Assignment ::= VARIABLE ":=" IntExpr
7
+ [5] Expression ::= BoolExpr | IntExpr
8
+ [6] BoolExpr ::= Equivalence
9
+ [7] Equivalence ::= Implication _Equivalence_1
10
+ [7.1] _Equivalence_1 ::= _Equivalence_2*
11
+ [7.2] _Equivalence_2 ::= _Equivalence_3 Implication
12
+ [7.3] _Equivalence_3 ::= "<->" | "<!>"
13
+ [8] Implication ::= Disjunction _Implication_1
14
+ [8.1] _Implication_1 ::= _Implication_2*
15
+ [8.2] _Implication_2 ::= "->" Disjunction
16
+ [9] Disjunction ::= Konjunction _Disjunction_1
17
+ [9.1] _Disjunction_1 ::= _Disjunction_2*
18
+ [9.2] _Disjunction_2 ::= "||" Konjunction
19
+ [10] Konjunction ::= Negation _Konjunction_1
20
+ [10.1] _Konjunction_1 ::= _Konjunction_2*
21
+ [10.2] _Konjunction_2 ::= "&&" Negation
22
+ [11] Negation ::= _Negation_1 | Comparison
23
+ [11.1] _Negation_1 ::= "!" Comparison
24
+ [12] Comparison ::= BOOL | _Comparison_1
25
+ [12.1] _Comparison_1 ::= Sum _Comparison_2
26
+ [12.2] _Comparison_2 ::= _Comparison_3+
27
+ [12.3] _Comparison_3 ::= CMPOP Sum
28
+ [13] IntExpr ::= Sum
29
+ [14] Sum ::= Product _Sum_1
30
+ [14.1] _Sum_1 ::= _Sum_2*
31
+ [14.2] _Sum_2 ::= _Sum_3 Product
32
+ [14.3] _Sum_3 ::= "+" | "-"
33
+ [15] Product ::= Value _Product_1
34
+ [15.1] _Product_1 ::= _Product_2*
35
+ [15.2] _Product_2 ::= _Product_3 Value
36
+ [15.3] _Product_3 ::= "*" | "/"
37
+ [16] Value ::= NUMBER | VARIABLE | _Value_1
38
+ [16.1] _Value_1 ::= "(" Expression ")"
39
+ [17] NUMBER ::= _NUMBER_1 _NUMBER_2
40
+ [17.1] _NUMBER_1 ::= "-"?
41
+ [17.2] _NUMBER_2 ::= _NUMBER_3+
42
+ [17.3] _NUMBER_3 ::= [0-9]
43
+ [18] BOOL ::= "true" | "false" | _BOOL_1
44
+ [18.1] _BOOL_1 ::= "(" BoolExpr ")"
45
+ [19] VARIABLE ::= _VARIABLE_1 | _VARIABLE_2
46
+ [19.1] _VARIABLE_1 ::= _VARIABLE_3 _VARIABLE_4 _VARIABLE_5
47
+ [19.3] _VARIABLE_3 ::= [^('true'#x20|#x20'false')]
48
+ [19.4] _VARIABLE_4 ::= [a-zA-Z_]
49
+ [19.5] _VARIABLE_5 ::= _VARIABLE_6*
50
+ [19.6] _VARIABLE_6 ::= [a-zA-Z0-9_]
51
+ [19.2] _VARIABLE_2 ::= [a-zA-Z_]
52
+ [20] CMPOP ::= "<=" | ">=" | "<" | ">" | "==" | "!="
@@ -0,0 +1,26 @@
1
+ module PgVerify
2
+ module EbnfParser
3
+
4
+ class ParserResult
5
+
6
+ attr_accessor :ast
7
+ attr_accessor :error
8
+
9
+ def initialize(ast, error)
10
+ @ast, @error = ast, error
11
+ end
12
+
13
+ def check!()
14
+ return unless error?()
15
+ # TODO: Custom exception
16
+ raise @error
17
+ end
18
+
19
+ def error?()
20
+ return !@error.nil?
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,125 @@
1
+
2
+ module PgVerify
3
+ module Interpret
4
+
5
+ class ComponentContext
6
+
7
+ # Name of this component as a symbol
8
+ attr_accessor :name
9
+
10
+ # The list of states of this component as symbols
11
+ attr_accessor :states_list
12
+
13
+ # The list of transitions of this component
14
+ attr_accessor :transition_list
15
+
16
+ # The list of variables which is component has declared
17
+ # and thus owns
18
+ attr_accessor :owned_variables
19
+
20
+ # Back reference to the parent graph
21
+ attr_accessor :parent_graph
22
+
23
+ # Flag on whether this component is used to represent a fault.
24
+ attr_accessor :represents_fault
25
+
26
+ # The source location of this components definition
27
+ attr_accessor :source_location
28
+
29
+ attr_accessor :init_expressions
30
+
31
+ def initialize(name, parent_graph)
32
+ @name, @parent_graph = name, parent_graph
33
+ @states_list, @transition_list = [], []
34
+ @owned_variables = []
35
+ @init_expressions = []
36
+ @represents_fault = false
37
+ @source_location = parent_graph.parent_script.find_source_location()
38
+ end
39
+
40
+ # DSL method for declaring a variable to be owned by this component
41
+ def var(hash)
42
+ raise InvalidDSL_var.new("Invalid argument '#{hash}'") unless hash.is_a?(Hash)
43
+ name = hash.keys.first
44
+ range = hash[name]
45
+ raise "Variable name must be different to the component that owns it" if name.to_sym == @name
46
+ raise InvalidDSL_var.new("Name '#{name}' is not a symbol") unless name.is_a?(Symbol)
47
+ raise InvalidDSL_var.new("Range '#{range}' is not a range or array") unless range.is_a?(Range) && range.first.is_a?(Integer)
48
+ sloc = @parent_graph.parent_script.find_source_location()
49
+ variable = Model::Variable.new(name, range, @name, sloc)
50
+
51
+ # The "init" argument can be an expression, or a value out of the
52
+ # range of that variable
53
+ if hash.key?(:init)
54
+ init_expr = variable.values().include?(hash[:init]) \
55
+ ? "#{variable.name} == #{hash[:init]}" \
56
+ : hash[:init]
57
+ raise "Neither a string, nor a valid initial value: #{hash[:init]}" unless init_expr.is_a?(String)
58
+ variable.init_expression = Model::ParsedExpression.new(init_expr, Model::ParsedExpression::TYPE_PL)
59
+ end
60
+
61
+ @owned_variables << variable
62
+ return variable
63
+ end
64
+
65
+ # DSL method to define states which this component can have
66
+ def states(*states, init: nil)
67
+ states.each { |state|
68
+ raise InvalidDSL_state.new("State '#{state}' is neither a string or symbol") unless state.is_a?(String) || state.is_a?(Symbol)
69
+ raise InvalidDSL_state.new("State '#{state}' was already declared for component '#{name}'") if @states_list.include?(state)
70
+ raise InvalidDSL_state.new("Initial state '#{init}' is none of #{state}") unless init.nil? || states.include?(init)
71
+ }
72
+ @states_list += states.map(&:to_sym)
73
+ self.init("#{@name} == #{init}") unless init.nil?
74
+ end
75
+
76
+ # DSL method for the definition of one state
77
+ def state(state)
78
+ states(state)
79
+ end
80
+
81
+ # DSL method for the decleration of a transition between states of this component
82
+ def transition(hash, &blk)
83
+ raise InvalidDSL_transition.new("Invalid argument '#{hash}'") unless hash.is_a?(Hash)
84
+ from = hash.keys.first
85
+ to = hash[from]
86
+ [ from, to ].each { |state|
87
+ next if @states_list.include?(state)
88
+ raise NoSuchStateError.new(state, self)
89
+ }
90
+ transition = TransitionContext.new(self, from, to)
91
+ transition.instance_eval(&blk) unless blk.nil?
92
+ @transition_list << transition
93
+ return transition
94
+ end
95
+
96
+ def init(string)
97
+ @init_expressions << string
98
+ end
99
+
100
+ def to_model()
101
+ params = {}
102
+ # Use the name as is
103
+ params[:name] = @name
104
+ # Use states as is
105
+ params[:states] = @states_list
106
+ # Convert the transitions to their model representation
107
+ params[:transitions] = @transition_list.map(&:to_model)
108
+ params[:represents_fault] = @represents_fault
109
+ # Pass the source location
110
+ params[:source_location] = @source_location
111
+ # Pass the init expression
112
+ unless @init_expressions.empty?
113
+ init_expression = @init_expressions.map { |e| "( #{e} )" }.join(" && ")
114
+ init_expression = Model::ParsedExpression.new(init_expression, Model::ParsedExpression::TYPE_PL)
115
+ params[:init_expression] = init_expression
116
+ end
117
+
118
+ # Create a model component using these params
119
+ Model::Component.new(params)
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+ end