Class: Idl::ReturnExpressionAst

Inherits:
AstNode
  • Object
show all
Defined in:
lib/idl/ast.rb

Instance Method Summary collapse

Constructor Details

#initialize(input, interval, return_nodes) ⇒ ReturnExpressionAst

Returns a new instance of ReturnExpressionAst.



3983
3984
3985
3986
# File 'lib/idl/ast.rb', line 3983

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

Instance Method Details

#enclosing_functionObject



4059
4060
4061
# File 'lib/idl/ast.rb', line 4059

def enclosing_function
  find_ancestor(FunctionDefAst)
end

#expected_return_type(symtab) ⇒ Type

Returns The expected return type (as defined by the encolsing function).

Returns:

  • (Type)

    The expected return type (as defined by the encolsing function)



4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
# File 'lib/idl/ast.rb', line 4008

def expected_return_type(symtab)
  func_def = find_ancestor(FunctionDefAst)
  if func_def.nil?
    if symtab.get("__expected_return_type").nil?
      internal_error "Forgot to set __expected_return_type in the symbol table"
    end

    symtab.get("__expected_return_type")
  else
    # need to find the type to get the right symbol table
    func_type = @func_type_cache[symtab.cfg_arch]
    return func_type.return_type(EMPTY_ARRAY, self) unless func_type.nil?

    func_type = symtab.get_global(func_def.name)
    internal_error "Couldn't find function type for '#{func_def.name}' #{symtab.keys} " if func_type.nil?

    # to get the return type, we need to find the template values in case this is
    # a templated function definition
    #
    # that information should be up the stack in the symbol table
    if func_type.templated?
      template_values = symtab.find_all(single_scope: true) do |o|
        o.is_a?(Var) && o.template_value_for?(func_def.name)
      end
      unless template_values.size == func_type.template_names.size
        internal_error "Did not find correct number of template arguments (found #{template_values.size}, need #{func_type.template_names.size}) #{symtab.keys_pretty}"
      end
      func_type.return_type(template_values.sort { |a, b| a.template_index <=> b.template_index }.map(&:value), self)
    else
      @func_type_cache[symtab.cfg_arch]= func_type
      func_type.return_type(EMPTY_ARRAY, self)
    end
  end
end

#return_type(symtab) ⇒ Type

Returns The actual return type.

Returns:

  • (Type)

    The actual return type



3998
3999
4000
4001
4002
4003
4004
4005
# File 'lib/idl/ast.rb', line 3998

def return_type(symtab)
  types = return_types(symtab)
  if types.size > 1
    Type.new(:tuple, tuple_types: types)
  else
    types[0]
  end
end

#return_types(symtab) ⇒ Array<Type>

Returns List of actual return types.

Returns:

  • (Array<Type>)

    List of actual return types



3989
3990
3991
3992
3993
3994
3995
# File 'lib/idl/ast.rb', line 3989

def return_types(symtab)
  if 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



4064
4065
4066
4067
4068
4069
4070
# File 'lib/idl/ast.rb', line 4064

def return_value(symtab)
  if 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



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

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



4073
4074
4075
4076
4077
4078
4079
# File 'lib/idl/ast.rb', line 4073

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

#to_idlObject



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

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

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



4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
# File 'lib/idl/ast.rb', line 4044

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

  if 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 convertable to expected return type (#{expected_return_type(symtab)})"
  end
end