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
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require 'active_record'
|
|
3
|
+
require 'adsl/parser/ast_nodes'
|
|
4
|
+
require 'adsl/extract/instrumenter'
|
|
5
|
+
require 'adsl/extract/sexp_utils'
|
|
6
|
+
require 'adsl/extract/rails/other_meta'
|
|
7
|
+
require 'adsl/extract/rails/action_block_builder'
|
|
8
|
+
require 'adsl/extract/rails/active_record_metaclass_generator'
|
|
9
|
+
|
|
10
|
+
module Kernel
|
|
11
|
+
def ins_stmt(expr = nil, options = {})
|
|
12
|
+
if expr.is_a? Array
|
|
13
|
+
expr.each do |subexpr|
|
|
14
|
+
ins_stmt subexpr, options
|
|
15
|
+
end
|
|
16
|
+
else
|
|
17
|
+
stmt = ::ADSL::Extract::Rails::ActionInstrumenter.extract_stmt_from_expr expr
|
|
18
|
+
if stmt.is_a? ::ADSL::Parser::ASTNode and stmt.class.is_statement?
|
|
19
|
+
::ADSL::Extract::Instrumenter.get_instance.abb.append_stmt stmt, options
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
expr
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ins_mark_render_statement()
|
|
26
|
+
::ADSL::Parser::ASTDummyStmt.new :type => :render
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ins_multi_assignment(outer_binding, names, values, operator = '=')
|
|
30
|
+
values_to_be_returned = []
|
|
31
|
+
names.length.times do |index|
|
|
32
|
+
name = names[index]
|
|
33
|
+
value = values[index]
|
|
34
|
+
|
|
35
|
+
adsl_ast_name = if /^@@[^@]+$/ =~ name.to_s
|
|
36
|
+
"atat__#{ name.to_s[2..-1] }"
|
|
37
|
+
elsif /^@[^@]+$/ =~ name.to_s
|
|
38
|
+
"at__#{ name.to_s[1..-1] }"
|
|
39
|
+
elsif /^\$.*$/ =~ name.to_s
|
|
40
|
+
"global__#{ name.to_s[1..-1] }"
|
|
41
|
+
else
|
|
42
|
+
name.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if value.respond_to?(:adsl_ast) && value.adsl_ast.class.is_objset?
|
|
46
|
+
assignment = ::ADSL::Parser::ASTAssignment.new(
|
|
47
|
+
:var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name),
|
|
48
|
+
:objset => value.adsl_ast
|
|
49
|
+
)
|
|
50
|
+
if operator == '||='
|
|
51
|
+
old_value = outer_binding.eval name rescue nil
|
|
52
|
+
if old_value.respond_to?(:adsl_ast) &&
|
|
53
|
+
old_value.adsl_ast.class.is_objset?
|
|
54
|
+
assignment = [
|
|
55
|
+
::ADSL::Parser::ASTDeclareVar.new(:var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name.dup)),
|
|
56
|
+
::ADSL::Parser::ASTEither.new(:blocks => [
|
|
57
|
+
::ADSL::Parser::ASTBlock.new(:statements => []),
|
|
58
|
+
::ADSL::Parser::ASTBlock.new(:statements => [assignment])
|
|
59
|
+
])
|
|
60
|
+
]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
ins_stmt assignment
|
|
64
|
+
|
|
65
|
+
variable = value.nil? ? nil : value.class.new(
|
|
66
|
+
:adsl_ast => ::ADSL::Parser::ASTVariable.new(:var_name => ::ADSL::Parser::ASTIdent.new(:text => adsl_ast_name)
|
|
67
|
+
))
|
|
68
|
+
outer_binding.eval "#{name} #{operator} ObjectSpace._id2ref(#{variable.object_id})"
|
|
69
|
+
|
|
70
|
+
values_to_be_returned << variable
|
|
71
|
+
else
|
|
72
|
+
outer_binding.eval "#{name} #{operator} ObjectSpace._id2ref(#{value.object_id})"
|
|
73
|
+
values_to_be_returned << value
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
names.length == 1 ? values_to_be_returned.first : values_to_be_returned
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def ins_do_return(*return_values)
|
|
80
|
+
::ADSL::Extract::Instrumenter.get_instance.abb.do_return *return_values
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def ins_do_raise(*args)
|
|
84
|
+
::ADSL::Extract::Instrumenter.get_instance.abb.do_raise *args
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def ins_branch_choice(condition, branch_id)
|
|
88
|
+
ins_stmt condition
|
|
89
|
+
::ADSL::Extract::Instrumenter.get_instance.abb.branch_choice branch_id
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def ins_explore_all(method_name, &block)
|
|
93
|
+
instrumenter = ::ADSL::Extract::Instrumenter.get_instance
|
|
94
|
+
|
|
95
|
+
return_value = instrumenter.abb.explore_all_choices &block
|
|
96
|
+
|
|
97
|
+
block_adsl_ast = instrumenter.abb.adsl_ast
|
|
98
|
+
|
|
99
|
+
instrumenter.prev_abb << block_adsl_ast
|
|
100
|
+
|
|
101
|
+
# are we at the root level? if so, wrap everything around in an action/callback
|
|
102
|
+
if instrumenter.stack_depth == 2
|
|
103
|
+
Array.wrap(return_value).each do |final_return|
|
|
104
|
+
adsl_ast = ::ADSL::Extract::Rails::ActionInstrumenter.extract_stmt_from_expr final_return
|
|
105
|
+
block_adsl_ast.statements << adsl_ast if !adsl_ast.nil? and adsl_ast.class.is_statement?
|
|
106
|
+
end
|
|
107
|
+
instrumenter.prev_abb << ::ADSL::Parser::ASTDummyStmt.new(:type => method_name)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
return_value
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def ins_push_frame
|
|
114
|
+
instrumenter = ::ADSL::Extract::Instrumenter.get_instance
|
|
115
|
+
instrumenter.abb.push_frame
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def ins_pop_frame
|
|
119
|
+
instrumenter = ::ADSL::Extract::Instrumenter.get_instance
|
|
120
|
+
instrumenter.abb.pop_frame
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def ins_if(condition, arg1, arg2)
|
|
124
|
+
ins_stmt condition
|
|
125
|
+
push_frame_expr1, frame1_ret_value, frame1_stmts = arg1
|
|
126
|
+
push_frame_expr2, frame2_ret_value, frame2_stmts = arg2
|
|
127
|
+
if frame1_stmts.length <= 1 && frame2_stmts.length <= 1 &&
|
|
128
|
+
frame1_ret_value.respond_to?(:adsl_ast) && frame1_ret_value.adsl_ast.class.is_objset? &&
|
|
129
|
+
frame2_ret_value.respond_to?(:adsl_ast) && frame2_ret_value.adsl_ast.class.is_objset? &&
|
|
130
|
+
!frame1_ret_value.adsl_ast.objset_has_side_effects? && !frame2_ret_value.adsl_ast.objset_has_side_effects?
|
|
131
|
+
|
|
132
|
+
return nil if frame1_ret_value.nil? && frame2_ret_value.nil?
|
|
133
|
+
|
|
134
|
+
result_type = if frame1_ret_value.nil?
|
|
135
|
+
frame2_ret_value.class
|
|
136
|
+
elsif frame2_ret_value.nil?
|
|
137
|
+
frame1_ret_value.class
|
|
138
|
+
elsif frame1_ret_value.class <= frame2_ret_value.class
|
|
139
|
+
frame2_ret_value.class
|
|
140
|
+
elsif frame2_ret_value.class <= frame1_ret_value.class
|
|
141
|
+
frame1_ret_value.class
|
|
142
|
+
else
|
|
143
|
+
# objset types are incompatible
|
|
144
|
+
# but MRI cannot parse return statements inside an if that's being assigned
|
|
145
|
+
nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
if result_type.nil?
|
|
149
|
+
block1 = ::ADSL::Parser::ASTBlock.new :statements => frame1_stmts
|
|
150
|
+
block2 = ::ADSL::Parser::ASTBlock.new :statements => frame2_stmts
|
|
151
|
+
return ::ADSL::Parser::ASTEither.new :blocks => [block1, block2]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
result_type.new(:adsl_ast => ::ADSL::Parser::ASTOneOfObjset.new(
|
|
155
|
+
:objsets => [frame1_ret_value.adsl_ast, frame2_ret_value.adsl_ast]
|
|
156
|
+
))
|
|
157
|
+
else
|
|
158
|
+
block1 = ::ADSL::Parser::ASTBlock.new :statements => frame1_stmts
|
|
159
|
+
block2 = ::ADSL::Parser::ASTBlock.new :statements => frame2_stmts
|
|
160
|
+
::ADSL::Parser::ASTEither.new :blocks => [block1, block2]
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
module ADSL
|
|
166
|
+
module Extract
|
|
167
|
+
module Rails
|
|
168
|
+
|
|
169
|
+
class ActionInstrumenter < ::ADSL::Extract::Instrumenter
|
|
170
|
+
def self.extract_stmt_from_expr(expr, method_name=nil)
|
|
171
|
+
adsl_ast = expr
|
|
172
|
+
adsl_ast = expr.adsl_ast if adsl_ast.respond_to? :adsl_ast
|
|
173
|
+
return nil unless adsl_ast.is_a? ::ADSL::Parser::ASTNode
|
|
174
|
+
return adsl_ast if adsl_ast.class.is_statement?
|
|
175
|
+
return ::ADSL::Parser::ASTObjsetStmt.new :objset => adsl_ast if adsl_ast.class.is_objset?
|
|
176
|
+
nil
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
attr_accessor :action_block
|
|
180
|
+
|
|
181
|
+
def abb
|
|
182
|
+
method_locals[:abb]
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def prev_abb
|
|
186
|
+
previous_locals[:abb]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def create_locals
|
|
190
|
+
{ :abb => ActionBlockBuilder.new }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def make_returns_explicit(sexp, last_stmt_index = -1)
|
|
194
|
+
last_stmt = sexp[last_stmt_index]
|
|
195
|
+
case last_stmt.sexp_type
|
|
196
|
+
when :block
|
|
197
|
+
make_returns_explicit last_stmt, -1
|
|
198
|
+
when :if
|
|
199
|
+
if last_stmt[2].nil?
|
|
200
|
+
last_stmt[2] = s(:return)
|
|
201
|
+
else
|
|
202
|
+
make_returns_explicit last_stmt, 2
|
|
203
|
+
end
|
|
204
|
+
if last_stmt[3].nil?
|
|
205
|
+
last_stmt[3] = s(:return)
|
|
206
|
+
else
|
|
207
|
+
make_returns_explicit last_stmt, 3
|
|
208
|
+
end
|
|
209
|
+
when :ensure
|
|
210
|
+
make_returns_explicit last_stmt, 1
|
|
211
|
+
when :rescue
|
|
212
|
+
make_returns_explicit last_stmt, 1
|
|
213
|
+
else
|
|
214
|
+
sexp[last_stmt_index] = s(:return, last_stmt) unless last_stmt.sexp_type == :return
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def initialize(ar_class_names, instrument_domain = Dir.pwd)
|
|
219
|
+
super instrument_domain
|
|
220
|
+
|
|
221
|
+
@branch_index = 0
|
|
222
|
+
|
|
223
|
+
# remove respond_to and render
|
|
224
|
+
render_stmts = [:respond_to, :render, :redirect_to, :respond_with]
|
|
225
|
+
replace :call do |sexp|
|
|
226
|
+
next sexp unless sexp.length >= 3 and sexp[1].nil? and render_stmts.include?(sexp[2])
|
|
227
|
+
s(:call, nil, :ins_mark_render_statement)
|
|
228
|
+
end
|
|
229
|
+
replace :iter do |sexp|
|
|
230
|
+
next sexp unless sexp[1].length >= 3 and sexp[1][0] == :call and sexp[1][1].nil? and render_stmts.include?(sexp[1][2])
|
|
231
|
+
s(:call, nil, :ins_mark_render_statement)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# surround the entire method with a call to abb.explore_all_choices
|
|
235
|
+
replace :defn, :defs do |sexp|
|
|
236
|
+
header_elem_count = sexp.sexp_type == :defn ? 3 : 4
|
|
237
|
+
stmts = sexp.pop(sexp.length - header_elem_count)
|
|
238
|
+
|
|
239
|
+
single_stmt = stmts.length > 1 ? s(:block, *stmts) : stmts.first
|
|
240
|
+
|
|
241
|
+
explore_all = s(:iter,
|
|
242
|
+
s(:call, nil, :ins_explore_all, s(:lit, sexp[header_elem_count - 2])),
|
|
243
|
+
s(:args),
|
|
244
|
+
single_stmt)
|
|
245
|
+
|
|
246
|
+
sexp.push explore_all
|
|
247
|
+
sexp
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# replace raise with ins_do_raise
|
|
251
|
+
replace :call do |sexp|
|
|
252
|
+
next sexp unless sexp[2] == :raise
|
|
253
|
+
s(:call, nil, :ins_do_raise)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# replace returns with ins_do_return
|
|
257
|
+
replace :return do |sexp|
|
|
258
|
+
s(:call, nil, :ins_do_return, *sexp.sexp_body)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# instrument assignments
|
|
262
|
+
replace :lasgn, :iasgn, :cvasgn, :cvdecl, :gasgn, :masgn, :op_asgn_or, :unless_in => [:args, :op_asgn_or] do |sexp|
|
|
263
|
+
next sexp if sexp.length <= 2
|
|
264
|
+
|
|
265
|
+
variables_and_prefixes = if sexp.sexp_type == :masgn
|
|
266
|
+
sexp[1].sexp_body.map{ |asgn_type, var| [asgn_type.to_s[0..-5], var] }
|
|
267
|
+
elsif sexp.sexp_type == :op_asgn_or
|
|
268
|
+
[]
|
|
269
|
+
else
|
|
270
|
+
[[sexp[0].to_s[0..-5], sexp[1]]]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
prepare_assignments = variables_and_prefixes.map{ |prefix, var|
|
|
274
|
+
s(:op_asgn_or, s("#{prefix}var".to_sym, var), s("#{prefix}asgn".to_sym, var, s(:nil)))
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
var_names = if sexp.sexp_type == :masgn
|
|
278
|
+
sexp[1].sexp_body.map{ |var| s(:str, var[1].to_s) }.to_a
|
|
279
|
+
elsif sexp.sexp_type == :op_asgn_or
|
|
280
|
+
[s(:str, sexp[1][1].to_s)]
|
|
281
|
+
else
|
|
282
|
+
[s(:str, sexp[1].to_s)]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
values = if sexp.sexp_type == :masgn
|
|
286
|
+
sexp[2]
|
|
287
|
+
elsif sexp.sexp_type == :op_asgn_or
|
|
288
|
+
s(:array, sexp[2][2])
|
|
289
|
+
else
|
|
290
|
+
s(:array, sexp[2])
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
operator = sexp.sexp_type == :op_asgn_or ? s(:str, '||=') : s(:str, '=')
|
|
294
|
+
|
|
295
|
+
s(:block,
|
|
296
|
+
*prepare_assignments,
|
|
297
|
+
s(:call, nil, :ins_multi_assignment, s(:call, nil, :binding), s(:array, *var_names), values, operator)
|
|
298
|
+
)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# prepend ins_stmt to every non-return or non-if statement
|
|
302
|
+
replace :defn, :defs, :block, :iter do |sexp|
|
|
303
|
+
first_stmt_index = case sexp.sexp_type
|
|
304
|
+
when :defn; 3
|
|
305
|
+
when :defs; 4
|
|
306
|
+
when :iter; 3
|
|
307
|
+
when :block; 1
|
|
308
|
+
end
|
|
309
|
+
(first_stmt_index..sexp.length-1).each do |index|
|
|
310
|
+
unless [:if, :return].include?(sexp[index].sexp_type) ||
|
|
311
|
+
(sexp[index][1].nil? && [:ins_push_frame, :ins_pop_frame].include?(sexp[index][2]))
|
|
312
|
+
sexp[index] = s(:call, nil, :ins_stmt, sexp[index])
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
sexp
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# instrument branches
|
|
319
|
+
replace :if do |sexp|
|
|
320
|
+
if sexp.may_return_or_raise?
|
|
321
|
+
sexp[1] = s(:call, nil, :ins_branch_choice, sexp[1], s(:lit, @branch_index += 1))
|
|
322
|
+
sexp[2] = s(:block, sexp[2]) unless sexp[2].nil? or sexp[2].sexp_type == :block
|
|
323
|
+
sexp[3] = s(:block, sexp[3]) unless sexp[3].nil? or sexp[3].sexp_type == :block
|
|
324
|
+
sexp
|
|
325
|
+
else
|
|
326
|
+
block1_sexp = sexp[2] || s(:nil)
|
|
327
|
+
block1 = block1_sexp.sexp_type == :block ? block1_sexp : s(:block, block1_sexp)
|
|
328
|
+
block2_sexp = sexp[3] || s(:nil)
|
|
329
|
+
block2 = block2_sexp.sexp_type == :block ? block2_sexp : s(:block, block2_sexp)
|
|
330
|
+
s(:call, nil, :ins_if,
|
|
331
|
+
sexp[1],
|
|
332
|
+
s(:array,
|
|
333
|
+
s(:call, nil, :ins_push_frame),
|
|
334
|
+
s(:splat, s(:rescue,
|
|
335
|
+
s(:array, block1, s(:call, nil, :ins_pop_frame)),
|
|
336
|
+
s(:resbody,
|
|
337
|
+
s(:array, s(:const, :Exception)),
|
|
338
|
+
s(:array, s(:nil), s(:call, nil, :ins_pop_frame))
|
|
339
|
+
)
|
|
340
|
+
))
|
|
341
|
+
),
|
|
342
|
+
s(:array,
|
|
343
|
+
s(:call, nil, :ins_push_frame),
|
|
344
|
+
s(:splat, s(:rescue,
|
|
345
|
+
s(:array, block2, s(:call, nil, :ins_pop_frame)),
|
|
346
|
+
s(:resbody,
|
|
347
|
+
s(:array, s(:const, :Exception)),
|
|
348
|
+
s(:array, s(:nil), s(:call, nil, :ins_pop_frame))
|
|
349
|
+
)
|
|
350
|
+
))
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# change rescue into a branch statement
|
|
357
|
+
replace :rescue do |sexp|
|
|
358
|
+
resbody = sexp.sexp_body.select{ |a| a.sexp_type == :resbody }.first
|
|
359
|
+
exception_type_array = s(:array, *resbody[1].sexp_body)
|
|
360
|
+
res_block = resbody[2..-1]
|
|
361
|
+
res_block = res_block.length > 1 ? s(:block, *res_block) : res_block.first
|
|
362
|
+
s(:if, s(:nil), res_block, sexp[1])
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# change attrasgn into a normal call
|
|
366
|
+
replace :attrasgn do |sexp|
|
|
367
|
+
s(:call, *sexp.sexp_body)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# make the implicit return explicit
|
|
371
|
+
replace :defn, :defs do |sexp|
|
|
372
|
+
make_returns_explicit sexp
|
|
373
|
+
sexp
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# replace calls to collection_action, member_action or page_action with a def
|
|
377
|
+
# these represent code sugar for defining actions with the activeadmin gem
|
|
378
|
+
replace :iter do |sexp|
|
|
379
|
+
next sexp unless (
|
|
380
|
+
sexp[1].sexp_type == :call &&
|
|
381
|
+
sexp[1][1] == nil &&
|
|
382
|
+
[:collection_action, :member_action, :page_action].include?(sexp[1][2])
|
|
383
|
+
)
|
|
384
|
+
s(:defn, sexp[1][3][1], sexp[2], sexp[3])
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def should_instrument?(object, method_name)
|
|
389
|
+
return false unless super
|
|
390
|
+
|
|
391
|
+
klass = object.is_a?(Class) ? object : object.class
|
|
392
|
+
method = object.method method_name
|
|
393
|
+
|
|
394
|
+
klass.name.match(/^ADSL::.*$/).nil? && !(method.source_location[0] =~ /.*lib\/adsl\/.*/)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'adsl/parser/ast_nodes'
|
|
2
|
+
|
|
3
|
+
module ADSL
|
|
4
|
+
module Extract
|
|
5
|
+
module Rails
|
|
6
|
+
class ActionRunner
|
|
7
|
+
include ::ADSL::Parser
|
|
8
|
+
|
|
9
|
+
attr_reader :controller, :action
|
|
10
|
+
|
|
11
|
+
def initialize(controller, action)
|
|
12
|
+
@controller = controller
|
|
13
|
+
@action = action
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def callbacks
|
|
17
|
+
@controller._process_action_callbacks
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def root_paths_to_stmts(root_paths)
|
|
21
|
+
return root_paths.first.statements if root_paths.length == 1
|
|
22
|
+
[ASTEither.new(:blocks => root_paths)]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def run_action
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
action_root_paths = action_adsl_ast.blocks.map{ |block| [block, false] }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run_before_filter(higher_root_paths)
|
|
32
|
+
filter_root_paths =
|
|
33
|
+
|
|
34
|
+
filter_root_paths.each do |block, chain_halted|
|
|
35
|
+
block += root_paths_to_stmts(higher_root_paths) unless chain_halted
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
filter_root_paths
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def run_after_filter(higher_root_paths)
|
|
42
|
+
filter_root_paths =
|
|
43
|
+
|
|
44
|
+
higher_root_paths.each do |block, chain_halted|
|
|
45
|
+
block += root_paths_to_stmts(filter_root_paths) unless chain_halted
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
higher_root_paths
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def run_around_filter
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|