Class: Idl::IfAst

Inherits:
AstNode show all
Includes:
Executable, Returns
Defined in:
lib/idl/ast.rb

Instance Method Summary collapse

Constructor Details

#initialize(input, interval, if_cond, if_body, elseifs, final_else_body) ⇒ IfAst

Returns a new instance of IfAst.



5494
5495
5496
5497
5498
5499
5500
# File 'lib/idl/ast.rb', line 5494

def initialize(input, interval, if_cond, if_body, elseifs, final_else_body)
  children_nodes = [if_cond, if_body]
  children_nodes += elseifs
  children_nodes << final_else_body

  super(input, interval, children_nodes)
end

Instance Method Details

#elseifsObject



5491
# File 'lib/idl/ast.rb', line 5491

def elseifs = @children[2..-2]

#execute_unknown(symtab) ⇒ Object

nothing to do for a function call



5699
5700
5701
5702
# File 'lib/idl/ast.rb', line 5699

def execute_unknown(symtab)
  if_body.execute_unknown(symtab)
  execute_unknown_after_if(symtab)
end

#final_else_bodyObject



5492
# File 'lib/idl/ast.rb', line 5492

def final_else_body = @children.last

#if_bodyObject



5490
# File 'lib/idl/ast.rb', line 5490

def if_body = @children[1]

#if_condObject



5489
# File 'lib/idl/ast.rb', line 5489

def if_cond = @children[0]

#return_value(symtab) ⇒ Integer, ... Also known as: execute

Evaluate the compile-time return value of this node, or, if the node does not return (e.g., because it is an IfAst but there is no return on the taken path), execute the node and update the symtab

Parameters:

  • symtab (SymbolTable)

    The symbol table for the context

Returns:

  • (Integer)

    The return value, if it is integral

  • (Boolean)

    The return value, if it is boolean

  • (nil)

    if the return value is not compile-time-known

Raises:

  • ValueError if, during evaluation, a node without a compile-time value is found



5554
5555
5556
5557
5558
5559
5560
# File 'lib/idl/ast.rb', line 5554

def return_value(symtab)

  body = taken_body(symtab)
  return nil if body.nil?

  body.return_value(symtab)
end

#return_values(symtab) ⇒ Array<Integer,Bool>

Returns a list of all possible return values, if known. Otherwise, raises a ValueError

Parameters:

Returns:

  • (Array<Integer,Bool>)

    List of all possible return values

Raises:

  • ValueError if it is not possible to determine all return values at compile time



5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
# File 'lib/idl/ast.rb', line 5596

def return_values(symtab)
  value_result = value_try do
    if_cond_value = if_cond.value(symtab)
    if if_cond_value
      # if is taken, so the only possible return values are those in the if body
      return if_body.return_values(symtab)
    else
      # if cond not taken; check else ifs and possibly final else
      return return_values_after_if(symtab)
    end
  end
  value_else(value_result) do
    # if condition not known; both paths are possible
    (if_body.return_values(symtab) + return_values_after_if(symtab)).uniq
  end
end

#taken_body(symtab) ⇒ Boolean

Returns true if the taken path is knowable at compile-time.

Returns:

  • (Boolean)

    true if the taken path is knowable at compile-time

Raises:

  • ValueError if the take path is not known at compile time



5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
# File 'lib/idl/ast.rb', line 5541

def taken_body(symtab)
  return if_body if if_cond.value(symtab)

  unless elseifs.empty?
    elseifs.each do |eif|
      return eif.body if eif.cond.value(symtab)
    end
  end

  final_else_body.stmts.empty? ? nil : final_else_body
end

#to_idlString

Return valid IDL representation of the node (and its subtree)

Returns:

  • (String)

    IDL code for the node



5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
# File 'lib/idl/ast.rb', line 5705

def to_idl
  result = "if (#{if_cond.to_idl}) { "
  result << if_body.to_idl
  result << "} "
  elseifs.each do |eif|
    result << eif.to_idl
  end
  unless final_else_body.stmts.empty?
    result << " else { "
    result << final_else_body.to_idl
    result << "} "
  end
  result
end

#type_check(symtab) ⇒ void

This method returns an undefined value.

type check this node and all children

Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError

Parameters:

Raises:



5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
# File 'lib/idl/ast.rb', line 5503

def type_check(symtab)
  level = symtab.levels
  if_cond.type_check(symtab)


  unless if_cond.type(symtab).convertable_to?(:boolean)
    if if_cond.type(symtab).kind == :bits
      type_error "'#{if_cond.text_value}' is not boolean. Maybe you meant 'if ((#{if_cond.text_value}) != 0)'?"
    else
      type_error "'#{if_cond.text_value}' is not boolean"
    end
  end

  if_cond_value = nil
  value_try do
    if_cond_value = if_cond.value(symtab)
  end

  # short-circuit the if body if we can
  if_body.type_check(symtab) unless if_cond_value == false

  internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels

  unless (if_cond_value == true) || elseifs.empty?
    elseifs.each do |eif|
      eif.type_check(symtab)
    end
  end

  internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels

  final_else_body.type_check(symtab) unless if_cond_value == true

  internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels
end