adsl 0.0.3 → 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 +4 -4
- data/Gemfile +2 -20
- data/README.md +14 -21
- data/bin/adsl-verify +8 -8
- data/lib/adsl.rb +3 -0
- data/lib/adsl/adsl.rb +3 -0
- data/lib/adsl/ds/data_store_spec.rb +339 -0
- data/lib/adsl/extract/instrumenter.rb +206 -0
- data/lib/adsl/extract/meta.rb +33 -0
- data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
- data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
- data/lib/adsl/extract/rails/action_runner.rb +57 -0
- data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
- data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
- data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
- data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
- data/lib/adsl/extract/rails/other_meta.rb +57 -0
- data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
- data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
- data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
- data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
- data/lib/adsl/extract/sexp_utils.rb +54 -0
- data/lib/adsl/fol/first_order_logic.rb +261 -0
- data/lib/adsl/parser/adsl_parser.racc +159 -0
- data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
- data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
- data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
- data/lib/adsl/parser/ast_nodes.rb +1410 -0
- data/lib/adsl/railtie.rb +67 -0
- data/lib/adsl/spass/bin.rb +230 -0
- data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
- data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
- data/lib/adsl/spass/spass_translator.rb +393 -0
- data/lib/adsl/spass/util.rb +13 -0
- data/lib/adsl/util/csv_hash_formatter.rb +94 -0
- data/lib/adsl/util/general.rb +228 -0
- data/lib/adsl/util/test_helper.rb +71 -0
- data/lib/adsl/verification/formula_generators.rb +231 -0
- data/lib/adsl/verification/instrumentation_filter.rb +50 -0
- data/lib/adsl/verification/invariant.rb +19 -0
- data/lib/adsl/verification/rails_verification.rb +33 -0
- data/lib/adsl/verification/utils.rb +20 -0
- data/lib/adsl/verification/verification_case.rb +13 -0
- data/test/integration/rails/rails_branch_verification_test.rb +112 -0
- data/test/integration/rails/rails_verification_test.rb +253 -0
- data/test/integration/spass/basic_translation_test.rb +563 -0
- data/test/integration/spass/control_flow_translation_test.rb +421 -0
- data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
- data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
- data/test/unit/adsl/extract/meta_test.rb +142 -0
- data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
- data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
- data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
- data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
- data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
- data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
- data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
- data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
- data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
- data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
- data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
- data/test/unit/adsl/parser/class_parser_test.rb +288 -0
- data/test/unit/adsl/parser/general_parser_test.rb +67 -0
- data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
- data/test/unit/adsl/parser/parser_util_test.rb +126 -0
- data/test/unit/adsl/spass/bin_test.rb +65 -0
- data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
- data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
- data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
- data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
- data/test/unit/adsl/util/general_test.rb +303 -0
- data/test/unit/adsl/util/test_helper_test.rb +120 -0
- data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
- data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
- data/test/unit/adsl/verification/utils_test.rb +39 -0
- data/test/unit/adsl/verification/verification_case_test.rb +8 -0
- metadata +229 -29
- data/lib/ds/data_store_spec.rb +0 -292
- data/lib/fol/first_order_logic.rb +0 -260
- data/lib/parser/adsl_ast.rb +0 -779
- data/lib/parser/adsl_parser.racc +0 -151
- data/lib/parser/adsl_parser.tab.rb +0 -976
- data/lib/parser/dsdl_parser.rex.rb +0 -196
- data/lib/parser/dsdl_parser.tab.rb +0 -976
- data/lib/spass/bin.rb +0 -164
- data/lib/spass/spass_ds_extensions.rb +0 -870
- data/lib/spass/spass_translator.rb +0 -388
- data/lib/spass/util.rb +0 -11
- data/lib/util/csv_hash_formatter.rb +0 -47
- data/lib/util/test_helper.rb +0 -33
- data/lib/util/util.rb +0 -114
data/lib/ds/data_store_spec.rb
DELETED
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
require 'util/util'
|
|
2
|
-
|
|
3
|
-
module DS
|
|
4
|
-
class DSNode
|
|
5
|
-
def list_entity_classes_written_to
|
|
6
|
-
recursively_gather :entity_class_writes
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def list_entity_classes_read
|
|
10
|
-
recursively_gather :entity_class_reads
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def replace(what, with)
|
|
14
|
-
to_inspect = [self]
|
|
15
|
-
inspected = Set.new
|
|
16
|
-
replaced = false
|
|
17
|
-
while not to_inspect.empty?
|
|
18
|
-
elem = to_inspect.pop
|
|
19
|
-
if elem.kind_of? Array
|
|
20
|
-
elem.length.times do |i|
|
|
21
|
-
if elem[i] == what
|
|
22
|
-
elem[i] = with
|
|
23
|
-
replaced = true
|
|
24
|
-
else
|
|
25
|
-
to_inspect << elem[i] unless inspected.include? elem[i]
|
|
26
|
-
end
|
|
27
|
-
inspected << elem[i]
|
|
28
|
-
end
|
|
29
|
-
elsif elem.class.methods.include? 'container_for_fields' or elem.class.methods.include? :container_for_fields
|
|
30
|
-
elem.class.container_for_fields.each do |field_name|
|
|
31
|
-
field_val = elem.send field_name
|
|
32
|
-
if field_val == what
|
|
33
|
-
elem.send "#{field_name}=", with
|
|
34
|
-
replaced = true
|
|
35
|
-
elsif field_val.kind_of?(Array) or field_val.class.methods.include?('container_for_fields')
|
|
36
|
-
to_inspect << field_val unless inspected.include? field_val
|
|
37
|
-
end
|
|
38
|
-
inspected << field_val
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
replaced
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
class DSSpec < DSNode
|
|
47
|
-
container_for :classes, :actions, :invariants
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
class DSClass < DSNode
|
|
51
|
-
container_for :name, :parent, :relations, :inverse_relations do
|
|
52
|
-
@relations = [] if @relations.nil?
|
|
53
|
-
@inverse_relations = [] if @inverse_relations.nil?
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def to_s
|
|
57
|
-
@name
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def superclass_of?(other_class)
|
|
61
|
-
until other_class.nil?
|
|
62
|
-
return true if other_class == self
|
|
63
|
-
other_class = other_class.parent
|
|
64
|
-
end
|
|
65
|
-
return false
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
class DSRelation < DSNode
|
|
70
|
-
container_for :cardinality, :from_class, :to_class, :name, :inverse_of
|
|
71
|
-
|
|
72
|
-
def to_s
|
|
73
|
-
"#{from}.#{name}"
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
class DSAction < DSNode
|
|
78
|
-
container_for :name, :args, :cardinalities, :block
|
|
79
|
-
|
|
80
|
-
def statements
|
|
81
|
-
@block.statements
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
class DSBlock < DSNode
|
|
86
|
-
container_for :statements
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
class DSAssignment < DSNode
|
|
90
|
-
container_for :var, :objset
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
class DSCreateObj < DSNode
|
|
94
|
-
container_for :klass
|
|
95
|
-
|
|
96
|
-
def entity_class_writes
|
|
97
|
-
Set[@klass]
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
class DSCreateObjset < DSNode
|
|
102
|
-
container_for :createobj
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
class DSCreateTup < DSNode
|
|
106
|
-
container_for :objset1, :relation, :objset2
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
class DSDeleteObj < DSNode
|
|
110
|
-
container_for :objset
|
|
111
|
-
|
|
112
|
-
def entity_class_writes
|
|
113
|
-
Set[@objset.type]
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
class DSDeleteTup < DSNode
|
|
118
|
-
container_for :objset1, :relation, :objset2
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
class DSEither < DSNode
|
|
122
|
-
container_for :blocks, :lambdas
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
class DSEitherLambdaObjset < DSNode
|
|
126
|
-
container_for :either, :vars
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
class DSForEachCommon < DSNode
|
|
130
|
-
container_for :objset, :block
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
class DSForEach < DSForEachCommon
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
class DSFlatForEach < DSForEachCommon
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
class DSForEachIteratorObjset < DSNode
|
|
140
|
-
container_for :for_each
|
|
141
|
-
|
|
142
|
-
def typecheck_and_resolve(context)
|
|
143
|
-
self
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def type
|
|
147
|
-
@for_each.objset.type
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
class DSForEachPreLambdaObjset < DSNode
|
|
152
|
-
container_for :for_each, :before_var, :inside_var
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
class DSForEachPostLambdaObjset < DSNode
|
|
156
|
-
container_for :for_each, :before_var, :inside_var
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
class DSVariable < DSNode
|
|
160
|
-
container_for :name, :type
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
class DSAllOf < DSNode
|
|
164
|
-
container_for :klass
|
|
165
|
-
|
|
166
|
-
def type
|
|
167
|
-
@klass
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def entity_class_reads
|
|
171
|
-
@klass
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
class DSSubset < DSNode
|
|
176
|
-
container_for :objset
|
|
177
|
-
|
|
178
|
-
def type
|
|
179
|
-
@objset.type
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
class DSOneOf < DSNode
|
|
184
|
-
container_for :objset
|
|
185
|
-
def type
|
|
186
|
-
@objset.type
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
class DSDereference < DSNode
|
|
191
|
-
container_for :objset, :relation
|
|
192
|
-
|
|
193
|
-
def type
|
|
194
|
-
@relation.to_class
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
class DSInvariant < DSNode
|
|
199
|
-
container_for :name, :formula
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
class DSBoolean < DSNode
|
|
203
|
-
container_for :bool_value
|
|
204
|
-
|
|
205
|
-
TRUE = DSBoolean.new :bool_value => true
|
|
206
|
-
FALSE = DSBoolean.new :bool_value => false
|
|
207
|
-
|
|
208
|
-
def type
|
|
209
|
-
:formula
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
class DSForAll < DSNode
|
|
214
|
-
container_for :vars, :objsets, :subformula
|
|
215
|
-
|
|
216
|
-
def type
|
|
217
|
-
:formula
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
class DSExists < DSNode
|
|
222
|
-
container_for :vars, :objsets, :subformula
|
|
223
|
-
|
|
224
|
-
def type
|
|
225
|
-
:formula
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
class DSIn < DSNode
|
|
230
|
-
container_for :objset1, :objset2
|
|
231
|
-
|
|
232
|
-
def type
|
|
233
|
-
:formula
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
class DSEmpty < DSNode
|
|
238
|
-
container_for :objset
|
|
239
|
-
|
|
240
|
-
def type
|
|
241
|
-
:formula
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
class DSNot < DSNode
|
|
246
|
-
container_for :subformula
|
|
247
|
-
|
|
248
|
-
def type
|
|
249
|
-
:formula
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
class DSAnd < DSNode
|
|
254
|
-
container_for :subformulae
|
|
255
|
-
|
|
256
|
-
def type
|
|
257
|
-
:formula
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
class DSOr < DSNode
|
|
262
|
-
container_for :subformulae
|
|
263
|
-
|
|
264
|
-
def type
|
|
265
|
-
:formula
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
class DSImplies < DSNode
|
|
270
|
-
container_for :subformula1, :subformula2
|
|
271
|
-
|
|
272
|
-
def type
|
|
273
|
-
:formula
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
class DSEquiv < DSNode
|
|
278
|
-
container_for :subformulae
|
|
279
|
-
|
|
280
|
-
def type
|
|
281
|
-
:formula
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
class DSEqual < DSNode
|
|
286
|
-
container_for :objsets
|
|
287
|
-
|
|
288
|
-
def type
|
|
289
|
-
:formula
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
end
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
require 'active_support/all'
|
|
2
|
-
require 'util/util'
|
|
3
|
-
|
|
4
|
-
class String
|
|
5
|
-
def resolve_spass
|
|
6
|
-
self
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def split_by_zero_level_comma
|
|
10
|
-
parts = []
|
|
11
|
-
sequence_beginning_index = 0
|
|
12
|
-
index = 0
|
|
13
|
-
paren_level = 0
|
|
14
|
-
while index < length
|
|
15
|
-
if self[index, 1] == '('
|
|
16
|
-
paren_level += 1
|
|
17
|
-
elsif self[index, 1] == ')'
|
|
18
|
-
paren_level -= 1
|
|
19
|
-
raise ArgumentError, 'Unmatching parenthesis' if paren_level < 0
|
|
20
|
-
elsif self[index, 1] == ',' and paren_level == 0
|
|
21
|
-
parts << self[sequence_beginning_index, index - sequence_beginning_index].strip
|
|
22
|
-
sequence_beginning_index = index + 1
|
|
23
|
-
end
|
|
24
|
-
index += 1
|
|
25
|
-
end
|
|
26
|
-
parts << self[sequence_beginning_index, length - sequence_beginning_index].strip
|
|
27
|
-
parts
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class Symbol
|
|
32
|
-
def resolve_spass
|
|
33
|
-
to_s
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
class TrueClass
|
|
38
|
-
def resolve_spass
|
|
39
|
-
"true"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class FalseClass
|
|
44
|
-
def resolve_spass
|
|
45
|
-
"false"
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
module FOL
|
|
50
|
-
class Not
|
|
51
|
-
def initialize(*formulae)
|
|
52
|
-
@formulae = formulae.flatten
|
|
53
|
-
raise ArgumentError, "At least one subformula required" if @formulae.empty?
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def resolve_spass
|
|
57
|
-
children = @formulae.map{ |obj| obj.resolve_spass }
|
|
58
|
-
children.delete_if{ |a| a == 'false' }
|
|
59
|
-
return 'false' if children.include? 'true'
|
|
60
|
-
return And.new(children.map{ |child| child.match('\Anot\((.*)\)\z') ? $1 : "not(#{child})" }).resolve_spass
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class And
|
|
66
|
-
attr_reader :objs
|
|
67
|
-
|
|
68
|
-
def initialize(*objs)
|
|
69
|
-
@objs = objs.flatten
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def resolve_spass
|
|
73
|
-
children = @objs.map{ |child| child.resolve_spass }
|
|
74
|
-
children = children.map{ |child| child.match('\Aand\((.*)\)\z') ? $1.split_by_zero_level_comma : child }.flatten
|
|
75
|
-
children.delete_if{ |a| a == 'true' }
|
|
76
|
-
return 'false' if children.include? 'false'
|
|
77
|
-
return 'true' if children.empty?
|
|
78
|
-
return children.first if children.length == 1
|
|
79
|
-
return "and(#{children.join(', ')})"
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
class Or
|
|
84
|
-
attr_reader :objs
|
|
85
|
-
|
|
86
|
-
def initialize(*objs)
|
|
87
|
-
@objs = objs.flatten
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def resolve_spass
|
|
91
|
-
children = @objs.map{ |child| child.resolve_spass }
|
|
92
|
-
children = children.map{ |child| child.match('\Aor\((.*)\)\z') ? $1.split_by_zero_level_comma : child }.flatten
|
|
93
|
-
children.delete_if{ |a| a == 'false' }
|
|
94
|
-
return 'true' if children.include? 'true'
|
|
95
|
-
return 'false' if children.empty?
|
|
96
|
-
return children.first if children.length == 1
|
|
97
|
-
return "or(#{children.join(', ')})"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
class ForAll
|
|
102
|
-
def initialize(*params)
|
|
103
|
-
params = params.flatten
|
|
104
|
-
raise ArgumentError, "At least a formula required" if params.length < 1
|
|
105
|
-
@args = params.first(params.length - 1)
|
|
106
|
-
@formula = params.last
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def resolve_spass
|
|
110
|
-
args = @args.map{ |obj| obj.resolve_spass }
|
|
111
|
-
formula = @formula.resolve_spass
|
|
112
|
-
return formula if args.empty?
|
|
113
|
-
return 'true' if formula == 'true'
|
|
114
|
-
return 'false' if formula == 'false'
|
|
115
|
-
"forall( [#{args.join(', ')}], #{formula})"
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
class Exists
|
|
120
|
-
def initialize(*params)
|
|
121
|
-
params = params.flatten
|
|
122
|
-
raise ArgumentError, "At least a formula required" if params.length < 1
|
|
123
|
-
@args = params.first(params.length - 1)
|
|
124
|
-
@formula = params.last
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def resolve_spass
|
|
128
|
-
args = @args.map{ |obj| obj.resolve_spass }
|
|
129
|
-
formula = @formula.resolve_spass
|
|
130
|
-
return formula if args.empty?
|
|
131
|
-
return 'true' if formula == 'true'
|
|
132
|
-
return 'false' if formula == 'false'
|
|
133
|
-
"exists( [#{args.join(', ')}], #{formula})"
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
class Equal
|
|
138
|
-
def initialize(*subformulae)
|
|
139
|
-
@subformulae = subformulae.flatten
|
|
140
|
-
raise ArgumentError, "At least two subformulae required" if @subformulae.length < 2
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def resolve_spass
|
|
144
|
-
return @subformulae.first.resolve_spass if @subformulae.length == 1
|
|
145
|
-
combinations = []
|
|
146
|
-
(@subformulae.length-1).times do |index|
|
|
147
|
-
combinations << "equal(#{@subformulae[index].resolve_spass}, #{@subformulae[index+1].resolve_spass})"
|
|
148
|
-
end
|
|
149
|
-
return And.new(combinations).resolve_spass
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
class Equiv
|
|
154
|
-
def initialize(*subformulae)
|
|
155
|
-
@subformulae = subformulae.flatten
|
|
156
|
-
raise ArgumentError, "At least two subformulae required" if @subformulae.length < 2
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def resolve_spass
|
|
160
|
-
subformulae = @subformulae.map{ |sub| sub.resolve_spass }
|
|
161
|
-
return subformulae.first if subformulae.length == 1
|
|
162
|
-
return And.new(subformulae).resolve_spass if subformulae.include? 'true'
|
|
163
|
-
return Not.new(subformulae).resolve_spass if subformulae.include? 'false'
|
|
164
|
-
combinations = []
|
|
165
|
-
(subformulae.length-1).times do |index|
|
|
166
|
-
combinations << "equiv(#{subformulae[index]}, #{subformulae[index+1]})"
|
|
167
|
-
end
|
|
168
|
-
return And.new(combinations).resolve_spass
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
class Implies
|
|
173
|
-
def initialize(from, to)
|
|
174
|
-
@from = from
|
|
175
|
-
@to = to
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def resolve_spass
|
|
179
|
-
from = @from.resolve_spass
|
|
180
|
-
to = @to.resolve_spass
|
|
181
|
-
return to if from == 'true'
|
|
182
|
-
return 'true' if from == 'false'
|
|
183
|
-
return Not.new(from).resolve_spass if to == 'false'
|
|
184
|
-
return 'true' if to == 'true'
|
|
185
|
-
return "implies(#{from}, #{to})"
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
class OneOf
|
|
190
|
-
def initialize(*formulae)
|
|
191
|
-
@formulae = formulae.flatten
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def resolve_spass
|
|
195
|
-
return 'false' if @formulae.empty?
|
|
196
|
-
return @formulae.first.resolve_spass if @formulae.length == 1
|
|
197
|
-
return Equiv.new(Not.new(@formulae.first), @formulae.last).resolve_spass if @formulae.length == 2
|
|
198
|
-
|
|
199
|
-
substatements = []
|
|
200
|
-
@formulae.length.times do |i|
|
|
201
|
-
formulae_without_i = @formulae.first(i) + @formulae.last(@formulae.length - 1 - i)
|
|
202
|
-
substatements << Implies.new(@formulae[i], Not.new(formulae_without_i))
|
|
203
|
-
end
|
|
204
|
-
And.new(Or.new(@formulae), substatements).resolve_spass
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
class IfThenElse
|
|
209
|
-
def initialize(iif, tthen, eelse)
|
|
210
|
-
@iif = iif
|
|
211
|
-
@tthen = tthen
|
|
212
|
-
@eelse = eelse
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def resolve_spass
|
|
216
|
-
And.new(Implies.new(@iif, @tthen), Implies.new(Not.new(@iif), @eelse)).resolve_spass
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
class IfThenElseEq
|
|
221
|
-
def initialize(iif, tthen, eelse)
|
|
222
|
-
@iif = iif
|
|
223
|
-
@tthen = tthen
|
|
224
|
-
@eelse = eelse
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def resolve_spass
|
|
228
|
-
And.new(Equiv.new(@iif, @tthen), Equiv.new(Not.new(@iif), @eelse)).resolve_spass
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
class PairwiseEqual
|
|
233
|
-
def initialize(*list)
|
|
234
|
-
list = list.flatten
|
|
235
|
-
@list1 = list.first((list.length/2.0).ceil)
|
|
236
|
-
@list2 = list.last((list.length/2.0).floor)
|
|
237
|
-
raise ArgumentError, "Lists not of equal length: [#{@list1.join(", ")}], [#{@list2.join(", ")}]" if @list1.length != @list2.length
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def resolve_spass
|
|
241
|
-
equalities = []
|
|
242
|
-
@list1.length.times do |i|
|
|
243
|
-
equalities << Equal.new(@list1[i], @list2[i])
|
|
244
|
-
end
|
|
245
|
-
return And.new(equalities).resolve_spass
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
# define a method for each of the above classes, starting with underscore and underscored* afterwards
|
|
250
|
-
# *see: http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/String/Inflections.html
|
|
251
|
-
self.constants.each do |klass_name|
|
|
252
|
-
instance_eval do
|
|
253
|
-
klass = FOL.const_get klass_name
|
|
254
|
-
send :define_method, "_#{klass_name.to_s.underscore}".to_sym do |*args|
|
|
255
|
-
klass.new(*args).resolve_spass
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|