Class: ADSL::Extract::Rails::ActionBlockBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/adsl/extract/rails/action_block_builder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeActionBlockBuilder

Returns a new instance of ActionBlockBuilder.



12
13
14
15
16
17
18
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 12

def initialize
  @root_paths = []
  @stmt_frames = [[]]
  @branch_choices = []
  @return_values = []
  @has_returned_or_raised = false
end

Instance Attribute Details

#branch_choicesObject

Returns the value of attribute branch_choices.



10
11
12
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 10

def branch_choices
  @branch_choices
end

#root_pathsObject

Returns the value of attribute root_paths.



10
11
12
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 10

def root_paths
  @root_paths
end

#stmt_framesObject

Returns the value of attribute stmt_frames.



10
11
12
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 10

def stmt_frames
  @stmt_frames
end

Instance Method Details

#adsl_astObject



212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 212

def adsl_ast
  blocks = @root_paths.map do |root_path|
    ::ADSL::Parser::ASTBlock.new :statements => root_path
  end

  if blocks.empty?
    ::ADSL::Parser::ASTBlock.new :statements => []
  elsif blocks.length == 1
    blocks.first
  else
    ::ADSL::Parser::ASTBlock.new :statements => [::ADSL::Parser::ASTEither.new(:blocks => blocks)]
  end
end

#all_stmts_so_farObject



185
186
187
188
189
190
191
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 185

def all_stmts_so_far
  stmts = []
  @stmt_frames.each do |frame|
    stmts += frame
  end
  stmts
end

#append_stmt(stmt, options = {}) ⇒ Object Also known as: <<



39
40
41
42
43
44
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 39

def append_stmt(stmt, options = {})
  return stmt if @has_returned_or_raised && !options[:ignore_has_returned]
  return stmt if included_already? @stmt_frames.last, stmt
  @stmt_frames.last << stmt
  stmt
end

#branch_choice(if_id) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 47

def branch_choice(if_id)
  @branch_choices.each do |iter_if_id, choice|
    return choice if iter_if_id == if_id
  end
  @branch_choices << [if_id, true]
  true
end

#common_return_valueObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 144

def common_return_value
  uniq = @return_values.dup
  # avoid include? because it uses :== and metaobjects override the == operator
  if uniq.map(&:nil?).include? true
    uniq.delete_if{ |e| e.nil? }
    uniq << nil
  end

  if uniq.length == 1
    uniq.first
  elsif ct = common_supertype_of_objsets(uniq)
    objsets = uniq.map(&:adsl_ast).map{ |r| r.is_a?(ADSL::Parser::ASTObjsetStmt) ? r.objset : r }
    ct.new(:adsl_ast => ADSL::Parser::ASTOneOfObjset.new(:objsets => objsets))
  elsif ct = common_supertype_of_objset_arrays(uniq)
    highest_length = uniq.map(&:length).max
    combined_objsets = []
    highest_length.times do |index|
      objsets = uniq.map{|u| u[index]}.map(&:adsl_ast).map{ |r| r.is_a?(ADSL::Parser::ASTObjsetStmt) ? r.objset : r }
      combined_objsets << ct[index].new(:objset => ADSL::Parser::ASTOneOfObjset.new(:objsets => objsets))
    end
    combined_objsets
  else
    # append all return values to root paths
    # cause they won't be returned and handled by the caller
    # if an array is returned, assume the 'return 1, 2, 3' syntax

    @return_values.length.times do |index|
      Array.wrap(@return_values[index]).flatten.each do |ret_value|
        stmt = ADSL::Extract::Rails::ActionInstrumenter.extract_stmt_from_expr ret_value
        @root_paths[index] << stmt unless (
          stmt.nil? ||
          !stmt.class.is_statement? ||
          included_already?(@root_paths[index], stmt)
        )
      end
    end
    
    ADSL::Extract::Rails::MetaUnknown.new
  end
end

#common_supertype_of_objset_arrays(values) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 127

def common_supertype_of_objset_arrays(values)
  return false if values.empty?

  values.each do |value|
    return false unless value.is_a? Array
  end
  
  return_value = []
  highest_length = values.map(&:length).max
  highest_length.times do |index|
    ct = compatible_types(values.map{ |v| v[index] })
    return false unless ct
    return_value << ct
  end
  return_value
end

#common_supertype_of_objsets(values) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 96

def common_supertype_of_objsets(values)
  return false if values.empty?
  values.each do |value|
    return false if value.is_a?(MetaUnknown) || !value.respond_to?(:adsl_ast)
  end
  adsl_asts = values.reject{ |v| v.nil? }.map(&:adsl_ast)
  adsl_asts = adsl_asts.map{ |v| v.is_a?(ADSL::Parser::ASTObjsetStmt) ? v.objset : v }
  adsl_asts.each do |adsl_ast|
    return false unless adsl_ast.class.is_objset?
    # side effects should trigger only if the selection is chosen;
    # but the translation does not do this
    return false if adsl_ast.objset_has_side_effects?
  end

  common_supertype = nil
  values.each do |value|
    next if value.nil?
    if common_supertype.nil?
      common_supertype = value.class
    elsif value.class <= common_supertype
      # all is fine
    elsif common_supertype <= value.class
      common_supertype = value.class
    else
      return false
    end
  end

  common_supertype
end

#do_raise(*args) ⇒ Object



202
203
204
205
206
207
208
209
210
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 202

def do_raise(*args)
  unless @has_returned_or_raised
    # appending nothing to root paths
    @root_paths << [::ADSL::Parser::ASTDummyStmt.new(:type => :raise)]
    @return_values << nil
    @has_returned_or_raised = true
  end
  return *args
end

#do_return(return_value = nil) ⇒ Object



193
194
195
196
197
198
199
200
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 193

def do_return(return_value = nil)
  unless @has_returned_or_raised
    @root_paths << all_stmts_so_far
    @return_values << return_value
    @has_returned_or_raised = true
  end
  return_value
end

#explore_all_choicesObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 77

def explore_all_choices
  while true
    begin
      reset
      increment_branch_choice

      return_value = yield
   
      do_return return_value unless @has_returned_or_raised
    rescue Exception => e
      #puts "Exception: #{e}"
      #puts e.backtrace.first 20
      #do_raise unless @has_returned_or_raised
    ensure
      return common_return_value unless has_more_executions?
    end
  end
end

#has_more_executions?Boolean

Returns:

  • (Boolean)


55
56
57
58
59
60
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 55

def has_more_executions?
  @branch_choices.each do |if_id, choice|
    return true if choice == true
  end
  false
end

#in_stmt_frame(*args) ⇒ Object



23
24
25
26
27
28
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 23

def in_stmt_frame(*args)
  push_frame
  yield *args
ensure
  return pop_frame
end

#included_already?(where, what) ⇒ Boolean

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 30

def included_already?(where, what)
  return where.map{ |e| e.equal? what }.include?(true) ||
    (
      where.last.is_a?(ADSL::Parser::ASTObjsetStmt) &&
      what.is_a?(ADSL::Parser::ASTObjsetStmt) &&
      where.last.objset == what.objset
    )
end

#increment_branch_choiceObject



62
63
64
65
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 62

def increment_branch_choice
  @branch_choices.pop while !@branch_choices.empty? && @branch_choices.last[1] == false
  @branch_choices.last[1] = false unless @branch_choices.empty?
end

#pop_frameObject



21
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 21

def pop_frame;  @stmt_frames.pop; end

#push_frameObject



20
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 20

def push_frame; @stmt_frames << []; end

#resetObject



67
68
69
70
71
72
73
74
75
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 67

def reset
  unless has_more_executions?
    @root_paths = []
    @branch_choices = []
    @return_values = []
  end
  @has_returned_or_raised = false
  @stmt_frames = [[]]
end

#root_lvl_adsl_astObject



226
227
228
# File 'lib/adsl/extract/rails/action_block_builder.rb', line 226

def root_lvl_adsl_ast
  ::ADSL::Parser::ASTBlock.new :statements => @stmt_frames.first
end