Class: Idl::ReturnExpressionAst

Inherits:
AstNode
  • Object
show all
Includes:
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 inherited from AstNode

#always_terminates?, #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, return_nodes) ⇒ ReturnExpressionAst

Returns a new instance of ReturnExpressionAst.



6914
6915
6916
6917
# File 'lib/idlc/ast.rb', line 6914

def initialize(input, interval, return_nodes)
  super(input, interval, return_nodes)
  @func_type_cache = {}
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
# File 'lib/idlc/ast.rb', line 6997

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

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  ReturnExpressionAst.new(
    input, interval,
    yaml.fetch("exprs").map { |r| AstNode.from_h(r, source_mapper) }
  )
end

Instance Method Details

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


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

def const_eval?(symtab) = return_value_nodes.all? { |node| node.const_eval?(symtab) }

#enclosing_functionObject



6960
6961
6962
# File 'lib/idlc/ast.rb', line 6960

def enclosing_function
  find_ancestor(FunctionDefAst)
end

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



35
36
37
# File 'lib/idlc/passes/gen_adoc.rb', line 35

def gen_adoc(indent = 0, indent_spaces: 2)
  "#{' ' * indent}return #{return_value_nodes.map { |r| r.gen_adoc(0, indent_spaces:) }.join(', ')}"
end

#gen_option_adocObject



115
116
117
118
119
# File 'lib/idlc/passes/gen_option_adoc.rb', line 115

def gen_option_adoc
  raise "unexpected" if return_value_nodes.size != 1

  return_value_nodes[0].gen_option_adoc
end

#prune(symtab, forced_type: nil) ⇒ Object



877
878
879
# File 'lib/idlc/passes/prune.rb', line 877

def prune(symtab, forced_type: nil)
  ReturnExpressionAst.new(input, interval, return_value_nodes.map { |n| n.prune(symtab) })
end

#return_type(symtab) ⇒ Object



6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
# File 'lib/idlc/ast.rb', line 6933

def return_type(symtab)
  types = return_types(symtab)
  if types.empty?
    return Type.new(:void)
  elsif types.size > 1
    Type.new(:tuple, tuple_types: types)
  else
    types.fetch(0)
  end
end

#return_types(symtab) ⇒ Object



6921
6922
6923
6924
6925
6926
6927
6928
6929
# File 'lib/idlc/ast.rb', line 6921

def return_types(symtab)
  if return_value_nodes.empty?
    [Type.new(:void)]
  elsif return_value_nodes[0].type(symtab).kind == :tuple
    return_value_nodes[0].type(symtab).tuple_types
  else
    return_value_nodes.map { |v| v.type(symtab) }
  end
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



6965
6966
6967
6968
6969
6970
6971
6972
6973
# File 'lib/idlc/ast.rb', line 6965

def return_value(symtab)
  if return_value_nodes.empty?
    :void
  elsif return_value_nodes.size == 1
    return_value_nodes[0].value(symtab)
  else
    return_value_nodes.map { |v| v.value(symtab) }
  end
end

#return_value_nodesObject



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

def return_value_nodes = @children

#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



6976
6977
6978
6979
6980
6981
6982
6983
6984
# File 'lib/idlc/ast.rb', line 6976

def return_values(symtab)
  if return_value_nodes.empty?
    [:void]
  elsif return_value_nodes.size == 1
    return_value_nodes[0].values(symtab)
  else
    return_value_nodes.map { |v| v.values(symtab) }
  end
end

#to_hObject



6990
6991
6992
6993
6994
# File 'lib/idlc/ast.rb', line 6990

def to_h = {
  "kind" => "return_expr",
  "exprs" => return_value_nodes.map(&:to_h),
  "source" => source_yaml
}

#to_idlObject



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

def to_idl = "return #{return_value_nodes.map(&:to_idl).join(',')}"

#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:



6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
# File 'lib/idlc/ast.rb', line 6945

def type_check(symtab, strict:)
  return_value_nodes.each do |v|
    v.type_check(symtab, strict:)
    type_error "Unknown type for #{v.text_value}" if v.type(symtab).nil?
  end

  if !return_value_nodes.empty? && return_value_nodes[0].type(symtab).kind == :tuple
    type_error("Can't combine tuple types in return") unless return_value_nodes.size == 1
  end

  unless return_type(symtab).convertable_to?(expected_return_type(symtab))
    type_error "Return type (#{return_type(symtab)}) not convertible to expected return type (#{expected_return_type(symtab)})"
  end
end