class ADSL::Extract::Rails::ActionBlockBuilder

Attributes

branch_choices[RW]
root_paths[RW]
stmt_frames[RW]

Public Class Methods

new() click to toggle source
# 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

Public Instance Methods

<<(stmt, options = {})
Alias for: append_stmt
adsl_ast() click to toggle source
# 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_far() click to toggle source
# 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 = {}) click to toggle source
# 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
Also aliased as: <<
branch_choice(if_id) click to toggle source
# 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_value() click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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_choices() { || ... } click to toggle source
# 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?() click to toggle source
# 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) { |*args| ... } click to toggle source
# 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) click to toggle source
# 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_choice() click to toggle source
# 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_frame() click to toggle source
# File lib/adsl/extract/rails/action_block_builder.rb, line 21
def pop_frame;  @stmt_frames.pop; end
push_frame() click to toggle source
# File lib/adsl/extract/rails/action_block_builder.rb, line 20
def push_frame; @stmt_frames << []; end
reset() click to toggle source
# 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_ast() click to toggle source
# 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