pg-verify 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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