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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -20
  3. data/README.md +14 -21
  4. data/bin/adsl-verify +8 -8
  5. data/lib/adsl.rb +3 -0
  6. data/lib/adsl/adsl.rb +3 -0
  7. data/lib/adsl/ds/data_store_spec.rb +339 -0
  8. data/lib/adsl/extract/instrumenter.rb +206 -0
  9. data/lib/adsl/extract/meta.rb +33 -0
  10. data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
  11. data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
  12. data/lib/adsl/extract/rails/action_runner.rb +57 -0
  13. data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
  14. data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
  15. data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
  16. data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
  17. data/lib/adsl/extract/rails/other_meta.rb +57 -0
  18. data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
  19. data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
  20. data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
  21. data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
  22. data/lib/adsl/extract/sexp_utils.rb +54 -0
  23. data/lib/adsl/fol/first_order_logic.rb +261 -0
  24. data/lib/adsl/parser/adsl_parser.racc +159 -0
  25. data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
  26. data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
  27. data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
  28. data/lib/adsl/parser/ast_nodes.rb +1410 -0
  29. data/lib/adsl/railtie.rb +67 -0
  30. data/lib/adsl/spass/bin.rb +230 -0
  31. data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
  32. data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
  33. data/lib/adsl/spass/spass_translator.rb +393 -0
  34. data/lib/adsl/spass/util.rb +13 -0
  35. data/lib/adsl/util/csv_hash_formatter.rb +94 -0
  36. data/lib/adsl/util/general.rb +228 -0
  37. data/lib/adsl/util/test_helper.rb +71 -0
  38. data/lib/adsl/verification/formula_generators.rb +231 -0
  39. data/lib/adsl/verification/instrumentation_filter.rb +50 -0
  40. data/lib/adsl/verification/invariant.rb +19 -0
  41. data/lib/adsl/verification/rails_verification.rb +33 -0
  42. data/lib/adsl/verification/utils.rb +20 -0
  43. data/lib/adsl/verification/verification_case.rb +13 -0
  44. data/test/integration/rails/rails_branch_verification_test.rb +112 -0
  45. data/test/integration/rails/rails_verification_test.rb +253 -0
  46. data/test/integration/spass/basic_translation_test.rb +563 -0
  47. data/test/integration/spass/control_flow_translation_test.rb +421 -0
  48. data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
  49. data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
  50. data/test/unit/adsl/extract/meta_test.rb +142 -0
  51. data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
  52. data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
  53. data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
  54. data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
  55. data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
  56. data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
  57. data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
  58. data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
  59. data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
  60. data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
  61. data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
  62. data/test/unit/adsl/parser/class_parser_test.rb +288 -0
  63. data/test/unit/adsl/parser/general_parser_test.rb +67 -0
  64. data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
  65. data/test/unit/adsl/parser/parser_util_test.rb +126 -0
  66. data/test/unit/adsl/spass/bin_test.rb +65 -0
  67. data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
  68. data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
  69. data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
  70. data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
  71. data/test/unit/adsl/util/general_test.rb +303 -0
  72. data/test/unit/adsl/util/test_helper_test.rb +120 -0
  73. data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
  74. data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
  75. data/test/unit/adsl/verification/utils_test.rb +39 -0
  76. data/test/unit/adsl/verification/verification_case_test.rb +8 -0
  77. metadata +229 -29
  78. data/lib/ds/data_store_spec.rb +0 -292
  79. data/lib/fol/first_order_logic.rb +0 -260
  80. data/lib/parser/adsl_ast.rb +0 -779
  81. data/lib/parser/adsl_parser.racc +0 -151
  82. data/lib/parser/adsl_parser.tab.rb +0 -976
  83. data/lib/parser/dsdl_parser.rex.rb +0 -196
  84. data/lib/parser/dsdl_parser.tab.rb +0 -976
  85. data/lib/spass/bin.rb +0 -164
  86. data/lib/spass/spass_ds_extensions.rb +0 -870
  87. data/lib/spass/spass_translator.rb +0 -388
  88. data/lib/spass/util.rb +0 -11
  89. data/lib/util/csv_hash_formatter.rb +0 -47
  90. data/lib/util/test_helper.rb +0 -33
  91. data/lib/util/util.rb +0 -114
@@ -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
-