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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +98 -0
- data/README.md +29 -0
- data/Rakefile +62 -0
- data/bin/console +15 -0
- data/bin/pg-verify.rb +18 -0
- data/bin/setup +8 -0
- data/calc.ebnf +21 -0
- data/data/config/pg-verify.yml +66 -0
- data/data/nusmv.sample.smv +179 -0
- data/data/project-template/.gitignore.resource +4 -0
- data/data/project-template/.pg-verify.yml +0 -0
- data/data/project-template/README.md +18 -0
- data/data/project-template/addon/.keep +0 -0
- data/data/project-template/program-graph.rb.resource +103 -0
- data/devpg +5 -0
- data/doc/examples/railroad_crossing.rb +61 -0
- data/doc/examples/train-tree.rb +43 -0
- data/doc/examples/weidezaun.rb +99 -0
- data/doc/examples/weidezaun.txt +29 -0
- data/doc/expose/definition.png +0 -0
- data/doc/expose/diagram.png +0 -0
- data/doc/expose/expose.md +359 -0
- data/doc/expose/validity.png +0 -0
- data/exe/pg-verify +4 -0
- data/integration_tests/ruby_dsl/001_states.rb +10 -0
- data/integration_tests/ruby_dsl/002_transitions.rb +10 -0
- data/integration_tests/ruby_dsl/003_actions.rb +14 -0
- data/integration_tests/ruby_dsl/004_guards.rb +18 -0
- data/integration_tests/ruby_dsl/005_variables.rb +16 -0
- data/integration_tests/ruby_dsl/006_state_variables.rb +26 -0
- data/integration_tests/ruby_dsl/007_variable_initialization.rb +28 -0
- data/integration_tests/ruby_dsl/008_state_initialization.rb +19 -0
- data/integration_tests/ruby_dsl/009_shared_variables.rb +26 -0
- data/integration_tests/ruby_dsl/010_complex_guards.rb +18 -0
- data/integration_tests/ruby_dsl/011_complex_actions.rb +16 -0
- data/integration_tests/ruby_dsl/012_error_components.rb +9 -0
- data/integration_tests/ruby_dsl/013_hazards.rb +25 -0
- data/integration_tests/ruby_dsl/014_tau_transitions.rb +26 -0
- data/integration_tests/ruby_dsl/015_basic_dcca.rb +19 -0
- data/integration_tests/ruby_dsl/016_pressure_tank.rb +146 -0
- data/lib/pg-verify/cli/cli.rb +235 -0
- data/lib/pg-verify/core/cmd_runner.rb +151 -0
- data/lib/pg-verify/core/core.rb +38 -0
- data/lib/pg-verify/core/extensions/array_extensions.rb +11 -0
- data/lib/pg-verify/core/extensions/enumerable_extensions.rb +19 -0
- data/lib/pg-verify/core/extensions/nil_extensions.rb +7 -0
- data/lib/pg-verify/core/extensions/string_extensions.rb +84 -0
- data/lib/pg-verify/core/shell/colorizer.rb +136 -0
- data/lib/pg-verify/core/shell/shell.rb +0 -0
- data/lib/pg-verify/core/util.rb +146 -0
- data/lib/pg-verify/doctor/doctor.rb +180 -0
- data/lib/pg-verify/ebnf_parser/ast.rb +31 -0
- data/lib/pg-verify/ebnf_parser/ebnf_parser.rb +26 -0
- data/lib/pg-verify/ebnf_parser/expression_parser.rb +177 -0
- data/lib/pg-verify/ebnf_parser/expression_parser2.rb +422 -0
- data/lib/pg-verify/ebnf_parser/expressions.ebnf +33 -0
- data/lib/pg-verify/ebnf_parser/expressions.peg +52 -0
- data/lib/pg-verify/ebnf_parser/parser_result.rb +26 -0
- data/lib/pg-verify/interpret/component_context.rb +125 -0
- data/lib/pg-verify/interpret/graph_context.rb +85 -0
- data/lib/pg-verify/interpret/interpret.rb +142 -0
- data/lib/pg-verify/interpret/pg_script.rb +72 -0
- data/lib/pg-verify/interpret/spec/ltl_builder.rb +90 -0
- data/lib/pg-verify/interpret/spec/spec_context.rb +32 -0
- data/lib/pg-verify/interpret/spec/spec_set_context.rb +67 -0
- data/lib/pg-verify/interpret/transition_context.rb +55 -0
- data/lib/pg-verify/model/allocation_set.rb +28 -0
- data/lib/pg-verify/model/assignment.rb +34 -0
- data/lib/pg-verify/model/component.rb +40 -0
- data/lib/pg-verify/model/dcca/hazard.rb +16 -0
- data/lib/pg-verify/model/dcca.rb +67 -0
- data/lib/pg-verify/model/expression.rb +106 -0
- data/lib/pg-verify/model/graph.rb +58 -0
- data/lib/pg-verify/model/model.rb +10 -0
- data/lib/pg-verify/model/parsed_expression.rb +77 -0
- data/lib/pg-verify/model/simulation/trace.rb +43 -0
- data/lib/pg-verify/model/simulation/variable_state.rb +23 -0
- data/lib/pg-verify/model/source_location.rb +45 -0
- data/lib/pg-verify/model/specs/spec.rb +44 -0
- data/lib/pg-verify/model/specs/spec_result.rb +25 -0
- data/lib/pg-verify/model/specs/spec_set.rb +43 -0
- data/lib/pg-verify/model/specs/specification.rb +50 -0
- data/lib/pg-verify/model/transition.rb +41 -0
- data/lib/pg-verify/model/validation/assignment_to_state_variable_validation.rb +26 -0
- data/lib/pg-verify/model/validation/empty_state_set_validation.rb +18 -0
- data/lib/pg-verify/model/validation/errors.rb +119 -0
- data/lib/pg-verify/model/validation/foreign_assignment_validation.rb +30 -0
- data/lib/pg-verify/model/validation/unknown_token_validation.rb +35 -0
- data/lib/pg-verify/model/validation/validation.rb +23 -0
- data/lib/pg-verify/model/variable.rb +47 -0
- data/lib/pg-verify/model/variable_set.rb +84 -0
- data/lib/pg-verify/nusmv/nusmv.rb +23 -0
- data/lib/pg-verify/nusmv/runner.rb +124 -0
- data/lib/pg-verify/puml/puml.rb +23 -0
- data/lib/pg-verify/shell/loading/line_animation.rb +36 -0
- data/lib/pg-verify/shell/loading/loading_animation.rb +80 -0
- data/lib/pg-verify/shell/loading/loading_prompt.rb +43 -0
- data/lib/pg-verify/shell/loading/no_animation.rb +20 -0
- data/lib/pg-verify/shell/shell.rb +30 -0
- data/lib/pg-verify/simulation/simulation.rb +7 -0
- data/lib/pg-verify/simulation/simulator.rb +90 -0
- data/lib/pg-verify/simulation/state.rb +53 -0
- data/lib/pg-verify/transform/hash_transformation.rb +104 -0
- data/lib/pg-verify/transform/nusmv_transformation.rb +261 -0
- data/lib/pg-verify/transform/puml_transformation.rb +89 -0
- data/lib/pg-verify/transform/transform.rb +8 -0
- data/lib/pg-verify/version.rb +5 -0
- data/lib/pg-verify.rb +47 -0
- data/pg-verify.gemspec +38 -0
- data/sig/pg-verify.rbs +4 -0
- 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
|