class AdLint::Cc1::SwitchStatementInterpreter

Public Class Methods

new(owner) click to toggle source
Calls superclass method AdLint::Cc1::SubInterpreter::new
# File lib/adlint/cc1/interp.rb, line 1462
def initialize(owner)
  super(owner, SwitchStatement)
end

Public Instance Methods

visit_switch_statement(node) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1466
def visit_switch_statement(node)
  checkpoint(node.location)

  node.executed = true
  notify_switch_stmt_started(node)

  ctrlexpr = node.expression
  ctrlexpr_var = object_to_variable(interpret(ctrlexpr), ctrlexpr)
  notify_switch_ctrlexpr_evaled(node, ctrlexpr_var)
  notify_variable_value_referred(ctrlexpr, ctrlexpr_var)

  execute_switch_body(ctrlexpr_var, node.statement)
  notify_switch_stmt_ended(node)
end

Private Instance Methods

complete?(block_items) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1628
def complete?(block_items)
  block_items.any? do |block_item|
    case block_item
    when GenericLabeledStatement, CaseLabeledStatement
      block_item = block_item.statement
      redo
    when DefaultLabeledStatement
      true
    else
      false
    end
  end
end
enter_next_clause(labeled_stmt, block_items, idx, branch, branch_opts) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1575
def enter_next_clause(labeled_stmt, block_items, idx, branch, branch_opts)
  prepare_fall_through(branch, branch_opts, labeled_stmt)

  case labeled_stmt
  when DefaultLabeledStatement
    branch_opts.push(COMPLEMENTAL)
  end

  branch_opts.push(FINAL) if final_branch?(block_items, idx)
  branch.add_options(*branch_opts)

  case stmt = labeled_stmt.statement
  when CaseLabeledStatement, DefaultLabeledStatement
    enter_next_clause(stmt, block_items, idx, branch, branch_opts)
  end
end
execute_branch(labeled_stmt, block_items, idx, branch_opts) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1526
def execute_branch(labeled_stmt, block_items, idx, branch_opts)
  ctrlexpr = labeled_stmt.normalized_expression
  ctrlexpr_val = value_of(interpret(ctrlexpr, QUIET))

  case labeled_stmt
  when DefaultLabeledStatement
    branch_opts.push(COMPLEMENTAL)
  end

  case
  when ctrlexpr_val.test_must_be_true.true?
    branch_opts.push(FINAL, COMPLETE)
  when ctrlexpr_val.test_must_be_false.true?
    # NOTE: To end the current branch group of switch-statement if this
    #       case-clause is the final one.
    branched_eval(ctrlexpr, *branch_opts) {}
    return seek_next_branch(block_items, idx)
  end

  branched_eval(ctrlexpr, *branch_opts) do |branch|
    case stmt = labeled_stmt.statement
    when CaseLabeledStatement, DefaultLabeledStatement
      # NOTE: Consecutive label appears!
      enter_next_clause(stmt, block_items, idx, branch, branch_opts)
    end
    interpret(labeled_stmt)
    idx += 1

    while item = block_items[idx]
      case item
      when GenericLabeledStatement
        item.executed = true
        notify_label_defined(item)
        item = item.statement
        redo
      when CaseLabeledStatement, DefaultLabeledStatement
        # NOTE: Fall through!
        enter_next_clause(item, block_items, idx, branch, branch_opts)
      end
      interpret(item)
      idx += 1
    end
    # NOTE: To simulate implicit breaking of the last case-clause.
    BreakEvent.of_break.throw
  end

  branch_opts.include?(FINAL) ? nil : seek_next_branch(block_items, idx)
end
execute_switch_body(var, node) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1482
def execute_switch_body(var, node)
  checkpoint(node.location)

  node.executed = true
  scoped_eval do
    begin
      notify_block_started(node)
      execute_switch_branches(var, node.block_items)
    ensure
      notify_block_ended(node)
    end
  end
end
execute_switch_branches(var, block_items) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1496
def execute_switch_branches(var, block_items)
  if complete?(block_items)
    base_opts = [SMOTHER_BREAK, IMPLICIT_COND, NARROWING, COMPLETE]
  else
    base_opts = [SMOTHER_BREAK, IMPLICIT_COND, NARROWING]
  end

  idx = 0
  while block_item = block_items[idx]
    case block_item
    when GenericLabeledStatement
      block_item.executed = true
      notify_label_defined(block_item)
      block_item = block_item.statement
      redo
    when CaseLabeledStatement, DefaultLabeledStatement
      if final_branch?(block_items, idx)
        opts = base_opts + [FINAL]
      else
        opts = base_opts.dup
      end
      idx = execute_branch(block_item, block_items, idx, opts)
      break unless idx
    else
      interpret(block_item)
      idx += 1
    end
  end
end
final_branch?(block_items, idx) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1612
def final_branch?(block_items, idx)
  idx += 1
  while block_item = block_items[idx]
    case block_item
    when GenericLabeledStatement
      block_item = block_item.statement
      redo
    when CaseLabeledStatement, DefaultLabeledStatement
      return false
    else
      idx += 1
    end
  end
  true
end
prepare_fall_through(branch, branch_opts, labeled_stmt) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1592
def prepare_fall_through(branch, branch_opts, labeled_stmt)
  value_domain_manip = nil

  branch.restart_versioning do
    ctrlexpr = labeled_stmt.normalized_expression
    ctrlexpr_val = value_of(interpret(ctrlexpr, QUIET))

    case
    when ctrlexpr_val.test_must_be_true.true?
      branch_opts.push(FINAL, COMPLETE)
    when ctrlexpr_val.test_must_be_false.true?
      return
    end

    value_domain_manip = branch.ctrlexpr.ensure_true_by_widening(ctrlexpr)
  end

  value_domain_manip.commit!
end
seek_next_branch(block_items, idx) click to toggle source
# File lib/adlint/cc1/interp.rb, line 1642
def seek_next_branch(block_items, idx)
  idx += 1
  while block_item = block_items[idx]
    case block_item
    when GenericLabeledStatement
      notify_label_defined(block_item)
      block_item = block_item.statement
      redo
    when CaseLabeledStatement, DefaultLabeledStatement
      return idx
    else
      idx += 1
    end
  end
  nil
end