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.



6929
6930
6931
6932
# File 'lib/idlc/ast.rb', line 6929

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

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
# File 'lib/idlc/ast.rb', line 7012

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)


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

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

#enclosing_functionObject



6975
6976
6977
# File 'lib/idlc/ast.rb', line 6975

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



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

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



6936
6937
6938
6939
6940
6941
6942
6943
6944
# File 'lib/idlc/ast.rb', line 6936

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



6980
6981
6982
6983
6984
6985
6986
6987
6988
# File 'lib/idlc/ast.rb', line 6980

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



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

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



6991
6992
6993
6994
6995
6996
6997
6998
6999
# File 'lib/idlc/ast.rb', line 6991

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



7005
7006
7007
7008
7009
# File 'lib/idlc/ast.rb', line 7005

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

#to_idlObject



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

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:



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

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