Class: Idl::IfBodyAst

Inherits:
AstNode show all
Includes:
Executable, Returns
Defined in:
lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/gen_option_adoc.rb

Constant Summary

Constants inherited from AstNode

AstNode::Bits1Type, AstNode::Bits32Type, AstNode::Bits64Type, AstNode::BoolType, AstNode::ConstBoolType, AstNode::PossiblyUnknownBits1Type, AstNode::PossiblyUnknownBits32Type, AstNode::PossiblyUnknownBits64Type, AstNode::ReachableFunctionCacheType, AstNode::StringType, AstNode::VoidType

Instance Attribute Summary

Attributes inherited from AstNode

#children, #input, #interval, #parent

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Returns

#expected_return_type

Methods included from Executable

#executable?

Methods inherited from AstNode

#declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_dst_registers, #find_referenced_csrs, #find_src_registers, #freeze_tree, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #nullify_assignments, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested

Constructor Details

#initialize(input, interval, body_stmts) ⇒ IfBodyAst

Returns a new instance of IfBodyAst.



8809
8810
8811
8812
8813
8814
8815
# File 'lib/idlc/ast.rb', line 8809

def initialize(input, interval, body_stmts)
  if body_stmts.empty?
    super("", 0...0, EMPTY_ARRAY)
  else
    super(input, interval, body_stmts)
  end
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
# File 'lib/idlc/ast.rb', line 8925

def self.from_h(yaml, source_mapper)
  raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "if_body"

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  IfBodyAst.new(
    input, interval,
    yaml.fetch("stmts").map { |s| AstNode.from_h(s, source_mapper) }
  )
end

Instance Method Details

#always_terminates?Boolean

Returns:

  • (Boolean)


492
493
494
# File 'lib/idlc/passes/prune.rb', line 492

def always_terminates?
  !stmts.empty? && stmts.last.always_terminates?
end

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


8801
8802
8803
# File 'lib/idlc/ast.rb', line 8801

def const_eval?(symtab)
  stmts.all? { |stmt| stmt.const_eval?(symtab) }
end

#execute(symtab) ⇒ void

This method returns an undefined value.

“execute” the statement by updating the variables in the symbol table

Parameters:

  • symtab (SymbolTable)

    The symbol table for the context

Raises:

  • ValueError if some part of the statement cannot be executed at compile time



8886
8887
8888
8889
8890
8891
8892
8893
8894
8895
8896
8897
8898
8899
8900
8901
8902
8903
8904
8905
8906
8907
8908
8909
# File 'lib/idlc/ast.rb', line 8886

def execute(symtab)
  err = T.let(nil, T.nilable(Symbol))
  stmts.each do |s|
    value_result = value_try do
      if s.is_a?(Returns)
        value_result2 = value_try do
          v = s.return_value(symtab)
          break unless v.nil? # nil means this is a conditional return and the condition is false
        end
        value_else(value_result2) do
          # not known, keep going
          err = :value_error
        end
      else
        s.execute(symtab)
      end
    end
    value_else(value_result) do
      # keep going so that we invalidate everything
      err = :value_error
    end
  end
  throw err unless err.nil?
end

#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object



40
41
42
43
44
45
46
# File 'lib/idlc/passes/gen_adoc.rb', line 40

def gen_adoc(indent = 0, indent_spaces: 2)
  adoc = []
  children.each do |e|
    adoc << e.gen_adoc(indent, indent_spaces:)
  end
  adoc.join("\n")
end

#gen_option_adocObject



71
72
73
# File 'lib/idlc/passes/gen_option_adoc.rb', line 71

def gen_option_adoc
  stmts.map(&:gen_option_adoc).join("\n")
end

#prune(symtab, restore: true, forced_type: nil) ⇒ Object



496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/idlc/passes/prune.rb', line 496

def prune(symtab, restore: true, forced_type: nil)
  pruned_stmts = []
  symtab.push(nil)
  snapshot = symtab.snapshot_values if restore
  stmts.each do |s|
    pruned_stmts << s.prune(symtab)

    break if pruned_stmts.last.always_terminates?
  end
  if restore
    symtab.restore_values(snapshot)
  end
  symtab.pop
  IfBodyAst.new(input, interval, pruned_stmts)
end

#return_type(symtab) ⇒ Object



8831
8832
8833
8834
# File 'lib/idlc/ast.rb', line 8831

def return_type(symtab)
  # the return type is determined by the function
  t = expected_return_type(symtab)
end

#return_value(symtab) ⇒ Integer, ...

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



8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
# File 'lib/idlc/ast.rb', line 8837

def return_value(symtab)
  symtab.push(self)
  begin
    stmts.each do |s|
      if s.is_a?(Returns)
        v = s.return_value(symtab)
        unless v.nil?
          return v
        end
      else
        s.execute(symtab)
      end
    end
  ensure
    symtab.pop
  end

  nil
end

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

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

Parameters:

  • symtab (SymbolTable)

    The symbol table for the context

Returns:

  • (Array<Integer>)

    The possible return values. Will be an empty array if there are no return values

  • (Array<Boolean>)

    The possible return values. Will be an empty array if there are no return values

Raises:

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



8858
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869
8870
8871
8872
8873
8874
8875
8876
8877
8878
8879
8880
8881
8882
8883
# File 'lib/idlc/ast.rb', line 8858

def return_values(symtab)
  values = T.let([], T::Array[ValueRbType])
  symtab.push(self)
  begin
    value_try do
      stmts.each do |s|
        if s.is_a?(Returns)
          value_result = value_try do
            v = s.return_value(symtab)

            return values.push(v).uniq unless v.nil?
          end
          value_else(value_result) do
            values += s.return_values(symtab)
          end
        else
          s.execute(symtab)
        end
      end
    end
  ensure
    symtab.pop
  end

  values.uniq
end

#stmtsObject



8806
# File 'lib/idlc/ast.rb', line 8806

def stmts = T.cast(@children, T::Array[StatementAst])

#to_hObject



8918
8919
8920
8921
8922
# File 'lib/idlc/ast.rb', line 8918

def to_h = {
  "kind" => "if_body",
  "stmts" => stmts.map(&:to_h),
  "source" => source_yaml
}

#to_idlObject



8913
8914
8915
# File 'lib/idlc/ast.rb', line 8913

def to_idl
  stmts.map(&:to_idl).join("")
end

#type_check(symtab, strict:) ⇒ 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:



8818
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
# File 'lib/idlc/ast.rb', line 8818

def type_check(symtab, strict:)
  symtab.push(self)

  begin
    stmts.each do |s|
      s.type_check(symtab, strict:)
    end
  ensure
    symtab.pop
  end
end