adsl 0.0.3 → 0.1.0

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