Class: Idl::FunctionDefAst
- Includes:
- Declaration
- Defined in:
- lib/idl/ast.rb
Instance Attribute Summary collapse
-
#reachable_functions_cache ⇒ Object
readonly
Returns the value of attribute reachable_functions_cache.
Instance Method Summary collapse
-
#add_symbol(symtab) ⇒ Object
Add symbol(s) at the outermost scope of the symbol table.
-
#arguments(symtab) ⇒ Array<Array(Type,String)>
Containing the argument types and names, in order.
-
#arguments_list_str ⇒ Object
returns an array of arguments, as a string function (or template instance) does not need to be resolved.
- #body ⇒ Object
- #builtin? ⇒ Boolean
-
#description ⇒ String
Asciidoc formatted function description.
-
#freeze_tree(global_symtab) ⇒ Object
freeze the entire tree from further modification This is also an opportunity to pre-calculate anything that only needs global symbols.
-
#initialize(input, interval, name, targs, return_types, arguments, desc, body) ⇒ FunctionDefAst
constructor
A new instance of FunctionDefAst.
- #name ⇒ Object
-
#num_args ⇒ Integer
The number of arguments to the function.
-
#return_type(symtab) ⇒ Object
return the return type, which may be a tuple of multiple types.
-
#return_type_list_str ⇒ Array<String>
function (or template instance) does not need to be resolved.
-
#template_names ⇒ Array<String>
Template argument names, in order.
-
#template_types(symtab) ⇒ Array<Type>
Template argument types, in order.
-
#templated? ⇒ Boolean
Whether or not the function is templated.
-
#type_check(symtab) ⇒ void
type check this node and all children.
- #type_check_args(symtab) ⇒ Object
- #type_check_body(symtab) ⇒ Object
-
#type_check_from_call(symtab) ⇒ Object
we do lazy type checking of the function body so that we never check uncalled functions, which avoids dealing with mentions of CSRs that may not exist in a given implementation.
- #type_check_return(symtab) ⇒ Object
- #type_check_targs(symtab) ⇒ Object
- #type_check_template_instance(symtab) ⇒ Object
Constructor Details
#initialize(input, interval, name, targs, return_types, arguments, desc, body) ⇒ FunctionDefAst
Returns a new instance of FunctionDefAst.
4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 |
# File 'lib/idl/ast.rb', line 4882 def initialize(input, interval, name, targs, return_types, arguments, desc, body) if body.nil? super(input, interval, targs + return_types + arguments) else super(input, interval, targs + return_types + arguments + [body]) end @name = name @targs = targs @return_type_nodes = return_types @argument_nodes = arguments @desc = desc @body = body @cached_return_type = {} @reachable_functions_cache ||= {} end |
Instance Attribute Details
#reachable_functions_cache ⇒ Object (readonly)
Returns the value of attribute reachable_functions_cache.
4900 4901 4902 |
# File 'lib/idl/ast.rb', line 4900 def reachable_functions_cache @reachable_functions_cache end |
Instance Method Details
#add_symbol(symtab) ⇒ Object
Add symbol(s) at the outermost scope of the symbol table
5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 |
# File 'lib/idl/ast.rb', line 5102 def add_symbol(symtab) internal_error "Functions should be declared at global scope" unless symtab.levels == 1 # now add the function in global scope def_type = FunctionType.new( name, self, symtab ) symtab.add!(name, def_type) end |
#arguments(symtab) ⇒ Array<Array(Type,String)>
Returns containing the argument types and names, in order.
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 |
# File 'lib/idl/ast.rb', line 4930 def arguments(symtab) return @arglist unless @arglist.nil? if templated? template_names.each do |tname| internal_error "Template values missing in symtab" unless symtab.get(tname) end end return EMPTY_ARRAY if @argument_nodes.empty? arglist = [] @argument_nodes.each do |a| atype = a.type(symtab) type_error "No type for #{a.text_value}" if atype.nil? atype = atype.ref_type if atype.kind == :enum arglist << [atype, a.name] end arglist.freeze unless templated? @arglist = arglist end arglist end |
#arguments_list_str ⇒ Object
returns an array of arguments, as a string function (or template instance) does not need to be resolved
4961 4962 4963 |
# File 'lib/idl/ast.rb', line 4961 def arguments_list_str @argument_nodes.map(&:text_value) end |
#body ⇒ Object
5153 5154 5155 5156 5157 |
# File 'lib/idl/ast.rb', line 5153 def body internal_error "Function has no body" if builtin? @body end |
#builtin? ⇒ Boolean
5159 5160 5161 |
# File 'lib/idl/ast.rb', line 5159 def builtin? @body.nil? end |
#description ⇒ String
Returns Asciidoc formatted function description.
4915 4916 4917 |
# File 'lib/idl/ast.rb', line 4915 def description unindent(@desc) end |
#freeze_tree(global_symtab) ⇒ Object
freeze the entire tree from further modification This is also an opportunity to pre-calculate anything that only needs global symbols
4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 |
# File 'lib/idl/ast.rb', line 4903 def freeze_tree(global_symtab) return if frozen? unless templated? arguments(global_symtab) end @children.each { |child| child.freeze_tree(global_symtab) } freeze end |
#name ⇒ Object
5035 5036 5037 |
# File 'lib/idl/ast.rb', line 5035 def name @name end |
#num_args ⇒ Integer
Returns The number of arguments to the function.
4925 4926 4927 |
# File 'lib/idl/ast.rb', line 4925 def num_args @argument_nodes.size end |
#return_type(symtab) ⇒ Object
return the return type, which may be a tuple of multiple types
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 |
# File 'lib/idl/ast.rb', line 4966 def return_type(symtab) cached = @cached_return_type[symtab.cfg_arch] return cached unless cached.nil? unless symtab.levels == 2 internal_error "Function bodies should be at global + 1 scope (at global + #{symtab.levels - 1})" end if @return_type_nodes.empty? @cached_return_type[symtab.cfg_arch] = VoidType return VoidType end unless templated? # with no templates, the return type does not change for a given cfg_arch rtype = if @return_type_nodes.size == 1 rtype = @return_type_nodes[0].type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype else tuple_types = @return_type_nodes.map do |r| rtype = r.type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype end Type.new(:tuple, tuple_types:) end raise "??????" if rtype.nil? return @cached_return_type[symtab.cfg_arch] = rtype end if templated? template_names.each do |tname| internal_error "Template values missing" unless symtab.get(tname) end end if @return_type_nodes.size == 1 rtype = @return_type_nodes[0].type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype else tuple_types = @return_type_nodes.map do |r| rtype = r.type(symtab) rtype = rtype.ref_type if rtype.kind == :enum rtype end Type.new(:tuple, tuple_types:) end end |
#return_type_list_str ⇒ Array<String>
function (or template instance) does not need to be resolved
5027 5028 5029 5030 5031 5032 5033 |
# File 'lib/idl/ast.rb', line 5027 def return_type_list_str if @return_type_nodes.empty? ["void"] else @return_type_nodes.map(&:text_value) end end |
#template_names ⇒ Array<String>
Returns Template argument names, in order.
5116 5117 5118 |
# File 'lib/idl/ast.rb', line 5116 def template_names @targs.map(&:name) end |
#template_types(symtab) ⇒ Array<Type>
Returns Template argument types, in order.
5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 |
# File 'lib/idl/ast.rb', line 5122 def template_types(symtab) return EMPTY_ARRAY unless templated? ttypes = [] @targs.each do |a| ttype = a.type(symtab) ttype = ttype.ref_type if ttype.kind == :enum ttypes << ttype.clone.make_const end ttypes end |
#templated? ⇒ Boolean
Returns whether or not the function is templated.
4920 4921 4922 |
# File 'lib/idl/ast.rb', line 4920 def templated? !@targs.empty? 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
5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 |
# File 'lib/idl/ast.rb', line 5075 def type_check(symtab) internal_error "Functions must be declared at global scope (at #{symtab.levels})" unless symtab.levels == 1 type_check_targs(symtab) symtab = symtab.deep_clone symtab.push(self) template_names.each_with_index do |tname, index| symtab.add(tname, Var.new(tname, template_types(symtab)[index])) end type_check_return(symtab) arguments(symtab).each do |arg_type, arg_name| symtab.add(arg_name, Var.new(arg_name, arg_type)) end type_check_args(symtab) # template functions are checked as they are called unless templated? type_check_body(symtab) end symtab.pop end |
#type_check_args(symtab) ⇒ Object
5143 5144 5145 |
# File 'lib/idl/ast.rb', line 5143 def type_check_args(symtab) @argument_nodes.each { |a| a.type_check(symtab, false) } end |
#type_check_body(symtab) ⇒ Object
5147 5148 5149 5150 5151 |
# File 'lib/idl/ast.rb', line 5147 def type_check_body(symtab) return if @body.nil? @body.type_check(symtab) end |
#type_check_from_call(symtab) ⇒ Object
we do lazy type checking of the function body so that we never check uncalled functions, which avoids dealing with mentions of CSRs that may not exist in a given implementation
5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 |
# File 'lib/idl/ast.rb', line 5058 def type_check_from_call(symtab) internal_error "Function definitions should be at global + 1 scope" unless symtab.levels == 2 type_check_return(symtab) type_check_args(symtab) # @argument_nodes.each do |a| # value_result = value_try do # symtab.add(a.name, Var.new(a.name, a.type(symtab), a.value(symtab))) # end # value_else(value_result) do # symtab.add(a.name, Var.new(a.name, a.type(symtab))) # end # end type_check_body(symtab) end |
#type_check_return(symtab) ⇒ Object
5139 5140 5141 |
# File 'lib/idl/ast.rb', line 5139 def type_check_return(symtab) @return_type_nodes.each { |r| r.type_check(symtab) } end |
#type_check_targs(symtab) ⇒ Object
5134 5135 5136 5137 |
# File 'lib/idl/ast.rb', line 5134 def type_check_targs(symtab) @targs.each { |t| type_error "Template arguments must be uppercase" unless t.text_value[0] == t.text_value[0].upcase } @targs.each { |t| type_error "Template types must be integral" unless t.type(symtab).integral? } end |
#type_check_template_instance(symtab) ⇒ Object
5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 |
# File 'lib/idl/ast.rb', line 5040 def type_check_template_instance(symtab) internal_error "Function definitions should be at global + 1 scope" unless symtab.levels == 2 internal_error "Not a template function" unless templated? template_names.each do |tname| internal_error "Template values missing" unless symtab.get(tname) end type_check_return(symtab) type_check_args(symtab) @argument_nodes.each { |a| symtab.add(a.name, Var.new(a.name, a.type(symtab))) } type_check_body(symtab) end |