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,779 +0,0 @@
1
- require 'ds/data_store_spec'
2
- require 'rubygems'
3
- require 'active_support'
4
- require 'util/util'
5
- require 'pp'
6
- require 'set'
7
-
8
- module ADSL
9
-
10
- class ADSLNode
11
- def self.node_type(*fields)
12
- container_for *fields
13
- container_for :lineno
14
- end
15
- end
16
-
17
- class ADSLError < StandardError; end
18
-
19
- class ADSLDummyObjset < ADSLNode
20
- node_type :type
21
-
22
- def typecheck_and_resolve(context)
23
- self
24
- end
25
- end
26
-
27
- class ADSLSpec < ADSLNode
28
- node_type :classes, :actions, :invariants
29
-
30
- def typecheck_and_resolve
31
- context = ADSLTypecheckResolveContext.new
32
-
33
- # make sure class names are unique
34
- @classes.each do |class_node|
35
- if context.classes.include? class_node.name.text
36
- raise ADSLError, "Duplicate class name '#{class_node.name.text}' on line #{class_node.name.lineno} (first definition on line #{context.classes[class_node.name.text][0].name.lineno}"
37
- end
38
- klass = DS::DSClass.new :name => class_node.name.text
39
- context.classes[klass.name] = [class_node, klass]
40
- end
41
-
42
- # make sure the parent classes are declared properly and that the inheritance graph is non-cyclic
43
- parents = Hash.new{}
44
- context.classes.values.select{ |v| v[0].parent_name }.each do |class_node, klass|
45
- parent_node, parent = context.classes[class_node.parent_name.text]
46
- raise ADSLError, "Unknown parent class name #{class_node.parent_name.text} for class #{class_node.name.text} on line #{class_node.parent_name}" if parent.nil?
47
- klass.parent = parent
48
-
49
- parents[klass] = parent
50
- parent_chain = [klass]
51
- while parent != nil do
52
- if parent_chain.include? parent
53
- cyclic_chain = parent_chain.slice(parent_chain.index(parent), parent_chain.length) + [parent]
54
- raise ADSLError, "Cyclic inheritance detected: #{cyclic_chain.map{ |c| c.name }.join ' -> '}"
55
- end
56
- parent_chain << parent
57
- parent = parents[parent]
58
- end
59
- end
60
-
61
- # make sure relations are valid and refer to existing classes
62
- context.classes.values.each do |class_node, klass|
63
- class_node.relations.each do |rel_node|
64
- iter = klass
65
- while iter != nil
66
- if context.relations[iter.name].include? rel_node.name.text
67
- raise ADSLError, "Duplicate relation name '#{class_node.name.text}' under class '#{klass.name}' on line #{rel_node.lineno} (first definition on line #{context.relations[iter.name][rel_node.name.text][0].lineno}"
68
- end
69
- iter = iter.parent
70
- end
71
- rel = DS::DSRelation.new :name => rel_node.name.text, :from_class => klass
72
- context.relations[klass.name][rel.name] = [rel_node, rel]
73
- end
74
- end
75
-
76
- # now that classes and rels are initialized, check them
77
- @classes.each do |class_node|
78
- class_node.typecheck_and_resolve context
79
- end
80
-
81
- @actions.each do |action_node|
82
- action_node.typecheck_and_resolve context
83
- end
84
-
85
- # make sure invariants have unique names; add names to unnamed invariants
86
- names = Set.new
87
- @invariants.each do |invariant_node|
88
- invariant = invariant_node.typecheck_and_resolve context
89
- if invariant.name && names.include?(invariant.name)
90
- raise ADSLError, "Duplicate invariant name #{invariant.name} on line #{invariant_node.lineno}"
91
- end
92
- name = invariant.name || "unnamed_line_#{invariant_node.lineno}"
93
- while names.include? name
94
- name = name.increment_suffix
95
- end
96
- invariant.name = name
97
- context.invariants << invariant
98
- names << name
99
- end
100
-
101
- @invariants.each do |invariant_node|
102
- invariant = invariant_node.typecheck_and_resolve context
103
- end
104
-
105
- DS::DSSpec.new(
106
- :classes => context.classes.map{ |a, b| b[1] },
107
- :actions => context.actions.map{ |a, b| b[1] },
108
- :invariants => context.invariants.dup
109
- )
110
- end
111
- end
112
-
113
- class ADSLClass < ADSLNode
114
- node_type :name, :parent_name, :relations
115
-
116
- def typecheck_and_resolve(context)
117
- klass = context.classes[@name.text][1]
118
- @relations.each do |rel_node|
119
- rel = context.relations[@name.text][rel_node.name.text][1]
120
- klass.relations << rel
121
-
122
- if rel_node.cardinality[0] > rel_node.cardinality[1]
123
- raise ADSLError, "Invalid cardinality of relation #{klass.name}.#{rel_node.name.text} on line #{rel_node.cardinality[2]}: minimum cardinality #{rel_node.cardinality[0]} must not be greater than the maximum cardinality #{rel_node.cardinality[1]}"
124
- end
125
- if rel_node.cardinality[1] == 0
126
- raise ADSLError, "Invalid cardinality of relation #{klass.name}.#{rel_node.name.text} on line #{rel_node.cardinality[2]}: maximum cardinality #{rel_node.cardinality[1]} must be positive"
127
- end
128
- unless context.classes.include? rel_node.to_class_name.text
129
- raise ADSLError, "Unknown class name #{rel_node.to_class_name.text} in relation #{klass.name}.#{rel_node.name.text} on line #{rel_node.to_class_name.lineno}"
130
- end
131
-
132
- rel.to_class = context.classes[rel_node.to_class_name.text][1]
133
- rel.cardinality = rel_node.cardinality
134
- if rel_node.inverse_of_name
135
- target_class = context.classes[rel.to_class.name][1]
136
- inverse_of_node, inverse_of = context.relations[target_class.name][rel_node.inverse_of_name.text]
137
-
138
- while inverse_of_node.nil?
139
- inverse_of_node, inverse_of = context.relations[target_class.name][rel_node.inverse_of_name.text]
140
- target_class = target_class.parent
141
- raise ADSLError, "Unknown relation to which #{rel.from_class.name}.#{rel.name} relation is inverse to: #{rel.to_class.name}.#{rel_node.inverse_of_name.text} on line #{rel_node.inverse_of_name.lineno}" if target_class.nil?
142
- end
143
-
144
- if inverse_of_node.inverse_of_name
145
- raise ADSLError, "Relation #{rel.from_class.name}.#{rel.name} cannot be inverse to an inverse relation #{rel.to_class.name}.#{rel_node.inverse_of_name.text} on line #{rel_node.inverse_of_name.lineno}"
146
- end
147
- rel.inverse_of = inverse_of
148
- end
149
- end
150
- end
151
- end
152
-
153
- class ADSLRelation < ADSLNode
154
- node_type :cardinality, :to_class_name, :name, :inverse_of_name
155
- end
156
-
157
- class ADSLIdent < ADSLNode
158
- node_type :text
159
- end
160
-
161
- class ADSLTypecheckResolveContext
162
- attr_accessor :classes, :relations, :actions, :invariants, :var_stack
163
-
164
- class ADSLStackFrame < ActiveSupport::OrderedHash
165
- attr_accessor :var_write_listeners
166
- attr_accessor :var_read_listeners
167
-
168
- def initialize
169
- super
170
- @var_write_listeners = []
171
- @var_read_listeners = []
172
- end
173
-
174
- def on_var_read(&block)
175
- listeners = @var_read_listeners
176
- listeners.push block
177
- end
178
-
179
- def on_var_write(&block)
180
- listeners = @var_write_listeners
181
- listeners.push block
182
- end
183
-
184
- def fire_write_event(name)
185
- listeners = @var_write_listeners
186
- listeners.each do |listener|
187
- listener.call name
188
- end
189
- end
190
-
191
- def fire_read_event(name)
192
- listeners = @var_read_listeners
193
- listeners.each do |listener|
194
- listener.call name
195
- end
196
- end
197
-
198
- def dup
199
- other = ADSLStackFrame.new
200
- self.each do |key, val|
201
- other[key] = val.dup
202
- end
203
- other.var_write_listeners = @var_write_listeners.dup
204
- other.var_read_listeners = @var_read_listeners.dup
205
- other
206
- end
207
-
208
- def clone
209
- dup
210
- end
211
- end
212
-
213
- def initialize
214
- # name => [astnode, dsobj]
215
- @classes = ActiveSupport::OrderedHash.new
216
- # classname => name => [astnode, dsobj]
217
- @relations = ActiveSupport::OrderedHash.new{ |hash, key| hash[key] = ActiveSupport::OrderedHash.new }
218
- # stack of name => [astnode, dsobj]
219
- @actions = ActiveSupport::OrderedHash.new
220
- @invariants = []
221
- @var_stack = []
222
- end
223
-
224
- def initialize_copy(source)
225
- super
226
- source.classes.each do |name, value|
227
- @classes[name] = value.dup
228
- end
229
- source.relations.each do |class_name, class_entry|
230
- entries = @relations[class_name]
231
- class_entry.each do |name, value|
232
- entries[name] = value.dup
233
- end
234
- end
235
- @actions = source.actions.dup
236
- @invariants = source.invariants.dup
237
- @var_stack = source.var_stack.map{ |frame| frame.dup }
238
- end
239
-
240
- def on_var_write(&block)
241
- @var_stack.last.on_var_write(&block)
242
- end
243
-
244
- def on_var_read(&block)
245
- @var_stack.last.on_var_read(&block)
246
- end
247
-
248
- def in_stack_frame
249
- push_frame
250
- yield
251
- ensure
252
- pop_frame
253
- end
254
-
255
- def push_frame
256
- @var_stack.push ADSLStackFrame.new
257
- end
258
-
259
- def pop_frame
260
- @var_stack.pop
261
- end
262
-
263
- def define_var(var, node)
264
- raise ADSLError, "Defining variables on a stack with no stack frames" if @var_stack.empty?
265
- prev_var_node, prev_var = lookup_var var.name
266
- raise ADSLError, "Duplicate identifier '#{var.name}' on line #{node.lineno}; previous definition on line #{prev_var_node.lineno}" unless prev_var.nil?
267
- @var_stack.last[var.name] = [node, var]
268
- @var_stack.last.fire_write_event var.name
269
- return var
270
- end
271
-
272
- def redefine_var(var, node)
273
- @var_stack.length.times do |frame_index|
274
- frame = @var_stack[frame_index]
275
- next unless frame.include? var.name
276
- old_var = frame[var.name][1]
277
-
278
- raise ADSL::ADSLError, "Unmatched type '#{var.type.name}' for variable '#{var.name}' on line #{node.lineno}" if var.type != old_var.type
279
-
280
- frame[var.name][1] = var
281
-
282
- @var_stack[frame_index..-1].reverse.each do |subframe|
283
- subframe.fire_write_event var.name
284
- end
285
-
286
- return var
287
- end
288
- return define_var var, node
289
- end
290
-
291
- def lookup_var(name, fire_read_event=true)
292
- @var_stack.length.times do |index|
293
- frame = @var_stack[index]
294
- next if frame[name].nil?
295
- var = frame[name]
296
-
297
- if fire_read_event
298
- @var_stack[index..-1].reverse.each do |subframe|
299
- subframe.fire_read_event name
300
- end
301
- end
302
-
303
- # handle events here, none defined atm
304
- return var
305
- end
306
- nil
307
- end
308
-
309
- def self.context_vars_that_differ(*contexts)
310
- vars_per_context = []
311
- contexts.each do |context|
312
- vars_per_context << context.var_stack.inject(ActiveSupport::OrderedHash.new) { |so_far, frame| so_far.merge! frame }
313
- end
314
- all_vars = vars_per_context.map{ |c| c.keys }.flatten.uniq
315
- packed = ActiveSupport::OrderedHash.new
316
- all_vars.each do |v|
317
- packed[v] = vars_per_context.map{ |vpc| vpc[v][1] }
318
- end
319
- packed.delete_if { |v, vars| vars.uniq.length == 1 }
320
- packed
321
- end
322
- end
323
-
324
- class ADSLAction < ADSLNode
325
- node_type :name, :arg_cardinalities, :arg_names, :arg_types, :block
326
-
327
- def typecheck_and_resolve(context)
328
- old_action_node, old_action = context.actions[@name.text]
329
- raise ADSLError, "Duplicate action name #{@name.text} on line #{@name.lineno}; first definition on line #{old_action_node.name.lineno}" unless old_action.nil?
330
- arguments = []
331
- cardinalities = []
332
- block = nil
333
- context.in_stack_frame do
334
- @arg_names.length.times do |i|
335
- cardinality = @arg_cardinalities[i]
336
- if cardinality[0] > cardinality[1]
337
- raise ADSLError, "Invalid cardinality of argument #{@arg_names[i].text} of action #{@name.text} on line #{cardinality[2]}: minimum cardinality #{cardinality[0]} must not be greater than the maximum cardinality #{cardinality[1]}"
338
- end
339
- if cardinality[1] == 0
340
- raise ADSLError, "Invalid cardinality of relation #{@arg_names[i].text} of action #{@name.text} on line #{cardinality[2]}: maximum cardinality #{cardinality[1]} must be positive"
341
- end
342
- cardinality = cardinality.first 2
343
-
344
- klass_node, klass = context.classes[@arg_types[i].text]
345
- raise ADSLError, "Unknown class #{@arg_types[i].text} on line #{@arg_types[i].lineno}" if klass.nil?
346
- var = DS::DSVariable.new :name => @arg_names[i].text, :type => klass
347
- context.define_var var, @arg_types[i]
348
- arguments << var
349
- cardinalities << cardinality
350
- end
351
- block = @block.typecheck_and_resolve context, false
352
- end
353
- action = DS::DSAction.new :name => @name.text, :args => arguments, :cardinalities => cardinalities, :block => block
354
- context.actions[action.name] = [self, action]
355
- return action
356
- end
357
- end
358
-
359
- class ADSLBlock < ADSLNode
360
- node_type :statements
361
-
362
- def typecheck_and_resolve(context, open_subcontext=true)
363
- context.push_frame if open_subcontext
364
- stmts = @statements.map{ |node| node.typecheck_and_resolve context }.flatten
365
- return DS::DSBlock.new :statements => stmts
366
- ensure
367
- context.pop_frame if open_subcontext
368
- end
369
- end
370
-
371
- class ADSLAssignment < ADSLNode
372
- node_type :var_name, :objset
373
-
374
- def typecheck_and_resolve(context)
375
- objset = @objset.typecheck_and_resolve context
376
- @var = DS::DSVariable.new :name => @var_name.text, :type => objset.type
377
- context.redefine_var @var, @var_name
378
- return DS::DSAssignment.new :var => @var, :objset => objset
379
- end
380
- end
381
-
382
- class ADSLCreateObj < ADSLNode
383
- node_type :var_name, :class_name
384
-
385
- def typecheck_and_resolve(context)
386
- klass_node, klass = context.classes[@class_name.text]
387
- raise ADSLError, "Undefined class #{@class_name.text} referred to at line #{@class_name.lineno}" if klass.nil?
388
- create_obj = DS::DSCreateObj.new :klass => klass
389
- if @var_name
390
- var = DS::DSVariable.new :name => @var_name.text, :type => klass
391
- objset = DS::DSCreateObjset.new :createobj => create_obj
392
- assignment = DS::DSAssignment.new :var => var, :objset => objset
393
- context.redefine_var var, @var_name
394
- return [create_obj, assignment]
395
- end
396
- return create_obj
397
- end
398
- end
399
-
400
- class ADSLForEach < ADSLNode
401
- node_type :var_name, :objset, :block
402
-
403
- def typecheck_and_resolve(context)
404
- before_context = context.dup
405
- objset = @objset.typecheck_and_resolve context
406
-
407
- temp_iterator_objset = ADSL::ADSLDummyObjset.new :type => objset.type
408
- assignment = ADSL::ADSLAssignment.new :lineno => @lineno, :var_name => @var_name, :objset => temp_iterator_objset
409
- @block.statements = [assignment, @block.statements].flatten
410
-
411
- vars_written_to = Set[]
412
- vars_read = Set[]
413
- vars_read_before_being_written_to = Set[]
414
- context.on_var_write do |name|
415
- vars_written_to << name
416
- end
417
- context.on_var_read do |name|
418
- var_node, var = context.lookup_var name, false
419
- vars_read_before_being_written_to << name unless
420
- vars_written_to.include?(name) or vars_read_before_being_written_to.include? name
421
- vars_read << name unless vars_read.include? name
422
- end
423
-
424
- context.push_frame
425
- block = @block.typecheck_and_resolve context
426
- context.pop_frame
427
-
428
- vars_read_before_being_written_to.each do |var_name|
429
- vars_read_before_being_written_to.delete var_name unless vars_written_to.include? var_name
430
- end
431
-
432
- flat = true
433
- # flat = false unless vars_read_before_being_written_to.empty?
434
-
435
- if flat
436
- for_each = DS::DSFlatForEach.new :objset => objset, :block => block
437
- else
438
- for_each = DS::DSForEach.new :objset => objset, :block => block
439
- end
440
-
441
- vars_read_before_being_written_to.each do |var_name|
442
- before_var_node, before_var = before_context.lookup_var var_name, false
443
- inside_var_node, inside_var = context.lookup_var var_name, false
444
- lambda_objset = DS::DSForEachPreLambdaObjset.new :for_each => for_each, :before_var => before_var, :inside_var => inside_var
445
- var = DS::DSVariable.new :name => var_name, :type => before_var.type
446
- assignment = DS::DSAssignment.new :var => var, :objset => lambda_objset
447
- block.replace before_var, var
448
- block.statements.unshift assignment
449
- end
450
-
451
- iterator_objset = DS::DSForEachIteratorObjset.new :for_each => for_each
452
- block.replace temp_iterator_objset, iterator_objset
453
- return for_each
454
- end
455
-
456
- def list_creations
457
- @block.list_creations
458
- end
459
- end
460
-
461
- class ADSLEither < ADSLNode
462
- node_type :blocks
463
-
464
- def typecheck_and_resolve(context)
465
- context.push_frame
466
-
467
- contexts = [context]
468
- (@blocks.length-1).times do
469
- contexts << context.dup
470
- end
471
-
472
- blocks = []
473
- @blocks.length.times do |i|
474
- blocks << @blocks[i].typecheck_and_resolve(contexts[i])
475
- end
476
-
477
- contexts.each do |c|
478
- c.pop_frame
479
- end
480
-
481
- either = DS::DSEither.new :blocks => blocks
482
-
483
- lambdas = []
484
-
485
- ADSLTypecheckResolveContext::context_vars_that_differ(*contexts).each do |var_name, vars|
486
- var = DS::DSVariable.new :name => var_name, :type => vars.first.type
487
- objset = DS::DSEitherLambdaObjset.new :either => either, :vars => vars
488
- assignment = DS::DSAssignment.new :var => var, :objset => objset
489
- context.redefine_var var, nil
490
- lambdas << assignment
491
- end
492
-
493
- return [ either, lambdas ]
494
- end
495
-
496
- def list_entity_classes_written_to
497
- @blocks.map{ block.list_entity_classes_written_to }.flatten
498
- end
499
- end
500
-
501
- class ADSLDeleteObj < ADSLNode
502
- node_type :objset
503
-
504
- def typecheck_and_resolve(context)
505
- objset = @objset.typecheck_and_resolve context
506
- return DS::DSDeleteObj.new :objset => objset
507
- end
508
- end
509
-
510
- def self.find_relation(context, from_type, rel_name, lineno, to_type=nil)
511
- iter = from_type
512
- relation_node, relation = context.relations[iter.name][rel_name]
513
- while relation.nil?
514
- iter = iter.parent
515
- raise ADSLError, "Unknown relation #{from_type.name}.#{rel_name} on line #{lineno}" if iter.nil?
516
- relation_node, relation = context.relations[iter.name][rel_name]
517
- end
518
-
519
- unless to_type.nil?
520
- raise ADSLError, "Mismatched right-hand-side type for relation #{from_type.name}.#{rel_name} on line #{lineno}. Expected #{relation.to_class.name} but was #{to_type.name}" unless relation.to_class.superclass_of? to_type
521
- end
522
-
523
- relation
524
- end
525
-
526
- class ADSLCreateTup < ADSLNode
527
- node_type :objset1, :rel_name, :objset2
528
-
529
- def typecheck_and_resolve(context)
530
- objset1 = @objset1.typecheck_and_resolve context
531
- objset2 = @objset2.typecheck_and_resolve context
532
- relation = ADSL::find_relation context, objset1.type, @rel_name.text, @rel_name.lineno, objset2.type
533
- return DS::DSCreateTup.new :objset1 => objset1, :relation => relation, :objset2 => objset2
534
- end
535
- end
536
-
537
- class ADSLDeleteTup < ADSLNode
538
- node_type :objset1, :rel_name, :objset2
539
-
540
- def typecheck_and_resolve(context)
541
- objset1 = @objset1.typecheck_and_resolve context
542
- objset2 = @objset2.typecheck_and_resolve context
543
- relation = ADSL::find_relation context, objset1.type, @rel_name.text, @rel_name.lineno, objset2.type
544
- return DS::DSDeleteTup.new :objset1 => objset1, :relation => relation, :objset2 => objset2
545
- end
546
- end
547
-
548
- class ADSLAllOf < ADSLNode
549
- node_type :class_name
550
-
551
- def typecheck_and_resolve(context)
552
- klass_node, klass = context.classes[@class_name.text]
553
- raise ADSLError, "Unknown class name #{@class_name.text} on line #{@class_name.lineno}" if klass.nil?
554
- return DS::DSAllOf.new :klass => klass
555
- end
556
- end
557
-
558
- class ADSLSubset < ADSLNode
559
- node_type :objset
560
-
561
- def typecheck_and_resolve(context)
562
- objset = @objset.typecheck_and_resolve context
563
- return DS::DSSubset.new :objset => objset
564
- end
565
- end
566
-
567
- class ADSLOneOf < ADSLNode
568
- node_type :objset
569
-
570
- def typecheck_and_resolve(context)
571
- objset = @objset.typecheck_and_resolve context
572
- return DS::DSOneOf.new :objset => objset
573
- end
574
- end
575
-
576
- class ADSLVariable < ADSLNode
577
- node_type :var_name
578
-
579
- def typecheck_and_resolve(context)
580
- var_node, var = context.lookup_var @var_name.text
581
- raise ADSLError, "Undefined variable #{@var_name.text} on line #{@var_name.lineno}" if var.nil?
582
- return var
583
- end
584
- end
585
-
586
- class ADSLDereference < ADSLNode
587
- node_type :objset, :rel_name
588
-
589
- def typecheck_and_resolve(context)
590
- objset = @objset.typecheck_and_resolve context
591
- klass = objset.type
592
- relation = ADSL::find_relation context, objset.type, @rel_name.text, @rel_name.lineno
593
- return DS::DSDereference.new :objset => objset, :relation => relation
594
- end
595
- end
596
-
597
- class ADSLInvariant < ADSLNode
598
- node_type :name, :formula
599
-
600
- def typecheck_and_resolve(context)
601
- formula = @formula.typecheck_and_resolve context
602
- name = @name.nil? ? nil : @name.text
603
- return DS::DSInvariant.new :name => name, :formula => formula
604
- end
605
- end
606
-
607
- class ADSLBoolean < ADSLNode
608
- node_type :bool_value
609
-
610
- def typecheck_and_resolve(context)
611
- return DS::DSBoolean::TRUE if @bool_value
612
- return DS::DSBoolean::FALSE
613
- end
614
- end
615
-
616
- class ADSLForAll < ADSLNode
617
- node_type :vars, :subformula
618
-
619
- def typecheck_and_resolve(context)
620
- context.in_stack_frame do
621
- vars = []
622
- objsets = []
623
- @vars.each do |var_node, objset_node|
624
- objset = objset_node.typecheck_and_resolve context
625
-
626
- var = DS::DSVariable.new :name => var_node.text, :type => objset.type
627
- context.define_var var, var_node
628
-
629
- vars << var
630
- objsets << objset
631
- end
632
- subformula = @subformula.typecheck_and_resolve context
633
- return DS::DSForAll.new :vars => vars, :objsets => objsets, :subformula => subformula
634
- end
635
- end
636
- end
637
-
638
- class ADSLExists < ADSLNode
639
- node_type :vars, :subformula
640
-
641
- def typecheck_and_resolve(context)
642
- context.in_stack_frame do
643
- vars = []
644
- objsets = []
645
- @vars.each do |var_node, objset_node|
646
- objset = objset_node.typecheck_and_resolve context
647
-
648
- var = DS::DSVariable.new :name => var_node.text, :type => objset.type
649
- context.define_var var, var_node
650
-
651
- vars << var
652
- objsets << objset
653
- end
654
- subformula = @subformula.nil? ? nil : @subformula.typecheck_and_resolve(context)
655
- return DS::DSExists.new :vars => vars, :objsets => objsets, :subformula => subformula
656
- end
657
- end
658
- end
659
-
660
- class ADSLNot < ADSLNode
661
- node_type :subformula
662
-
663
- def typecheck_and_resolve(context)
664
- subformula = @subformula.typecheck_and_resolve context
665
- raise "Substatement not a formula on line #{@subformula.lineno}" unless subformula.type == :formula
666
- return subformula.subformula if subformula.is_a? DS::DSNot
667
- return DS::DSNot.new :subformula => subformula
668
- end
669
- end
670
-
671
- class ADSLAnd < ADSLNode
672
- node_type :subformulae
673
-
674
- def typecheck_and_resolve(context)
675
- subformulae = @subformulae.map{ |o| o.typecheck_and_resolve context }
676
- subformulae.each do |subformula|
677
- raise "Substatement not a formula on line #{subformula.lineno}" unless subformula.type == :formula
678
- end
679
- flattened_subformulae = []
680
- subformulae.each do |subformula|
681
- if subformula.is_a? DS::DSAnd
682
- flattened_subformulae += subformula.subformulae
683
- else
684
- flattened_subformulae << subformula
685
- end
686
- end
687
- return DS::DSAnd.new :subformulae => flattened_subformulae
688
- end
689
- end
690
-
691
- class ADSLOr < ADSLNode
692
- node_type :subformulae
693
-
694
- def typecheck_and_resolve(context)
695
- subformulae = @subformulae.map{ |o| o.typecheck_and_resolve context }
696
- subformulae.each do |subformula|
697
- raise "Substatement not a formula on line #{subformula.lineno}" unless subformula.type == :formula
698
- end
699
- flattened_subformulae = []
700
- subformulae.each do |subformula|
701
- if subformula.is_a? DS::DSOr
702
- flattened_subformulae += subformula.subformulae
703
- else
704
- flattened_subformulae << subformula
705
- end
706
- end
707
- return DS::DSOr.new :subformulae => flattened_subformulae
708
- end
709
- end
710
-
711
- class ADSLEquiv < ADSLNode
712
- node_type :subformulae
713
-
714
- def typecheck_and_resolve(context)
715
- subformulae = @subformulae.map{ |o| o.typecheck_and_resolve context }
716
- subformulae.each do |subformula|
717
- raise "Substatement not a formula on line #{subformula.lineno}" unless subformula.type == :formula
718
- end
719
- return DS::DSEquiv.new :subformulae => subformulae
720
- end
721
- end
722
-
723
- class ADSLImplies < ADSLNode
724
- node_type :subformula1, :subformula2
725
-
726
- def typecheck_and_resolve(context)
727
- subformula1 = @subformula1.typecheck_and_resolve context
728
- subformula2 = @subformula2.typecheck_and_resolve context
729
-
730
- [subformula1, subformula2].each do |subformula|
731
- raise "Substatement not a formula on line #{subformula.lineno}" unless subformula.type == :formula
732
- end
733
- return DS::DSImplies.new :subformula1 => subformula1, :subformula2 => subformula2
734
- end
735
- end
736
-
737
- class ADSLEqual < ADSLNode
738
- node_type :objsets
739
-
740
- def typecheck_and_resolve(context)
741
- objsets = @objsets.map{ |o| o.typecheck_and_resolve context }
742
-
743
- types = objsets.map{ |o| o.type }.uniq
744
- while types.length > 1
745
- type1 = types.pop
746
- type2 = types.pop
747
- if type1.superclass_of? type2
748
- types << type2
749
- elsif type2.superclass_of? type1
750
- types << type1
751
- else
752
- raise ADSLError, "Object sets are not of compatible types: #{objsets.map { |o| o.type.name }.join(", ")}"
753
- end
754
- end
755
-
756
- return DS::DSEqual.new :objsets => objsets
757
- end
758
- end
759
-
760
- class ADSLIn < ADSLNode
761
- node_type :objset1, :objset2
762
-
763
- def typecheck_and_resolve(context)
764
- objset1 = @objset1.typecheck_and_resolve context
765
- objset2 = @objset2.typecheck_and_resolve context
766
- raise ADSLError, "Object sets are not of compatible types: #{objset1.type.name}, #{objset2.type.name}" unless objset2.type.superclass_of? objset1.type
767
- return DS::DSIn.new :objset1 => objset1, :objset2 => objset2
768
- end
769
- end
770
-
771
- class ADSLEmpty < ADSLNode
772
- node_type :objset
773
-
774
- def typecheck_and_resolve(context)
775
- objset = @objset.typecheck_and_resolve context
776
- return DS::DSEmpty.new :objset => objset
777
- end
778
- end
779
- end