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 arugment 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 implmentation.
- #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.
4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 |
# File 'lib/idl/ast.rb', line 4847 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.
4865 4866 4867 |
# File 'lib/idl/ast.rb', line 4865 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
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 |
# File 'lib/idl/ast.rb', line 5067 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.
4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 |
# File 'lib/idl/ast.rb', line 4895 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
4926 4927 4928 |
# File 'lib/idl/ast.rb', line 4926 def arguments_list_str @argument_nodes.map(&:text_value) end |
#body ⇒ Object
5118 5119 5120 5121 5122 |
# File 'lib/idl/ast.rb', line 5118 def body internal_error "Function has no body" if builtin? @body end |
#builtin? ⇒ Boolean
5124 5125 5126 |
# File 'lib/idl/ast.rb', line 5124 def builtin? @body.nil? end |
#description ⇒ String
Returns Asciidoc formatted function description.
4880 4881 4882 |
# File 'lib/idl/ast.rb', line 4880 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
4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 |
# File 'lib/idl/ast.rb', line 4868 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
5000 5001 5002 |
# File 'lib/idl/ast.rb', line 5000 def name @name end |
#num_args ⇒ Integer
Returns The number of arguments to the function.
4890 4891 4892 |
# File 'lib/idl/ast.rb', line 4890 def num_args @argument_nodes.size end |
#return_type(symtab) ⇒ Object
return the return type, which may be a tuple of multiple types
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 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 |
# File 'lib/idl/ast.rb', line 4931 def return_type(symtab) cached = @cached_return_type[symtab.archdef] 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.archdef] = VoidType return VoidType end unless templated? # with no templates, the return type does not change for a given arch_def 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.archdef] = 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
4992 4993 4994 4995 4996 4997 4998 |
# File 'lib/idl/ast.rb', line 4992 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 arugment names, in order.
5081 5082 5083 |
# File 'lib/idl/ast.rb', line 5081 def template_names @targs.map(&:name) end |
#template_types(symtab) ⇒ Array<Type>
Returns Template argument types, in order.
5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 |
# File 'lib/idl/ast.rb', line 5087 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.
4885 4886 4887 |
# File 'lib/idl/ast.rb', line 4885 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
5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 |
# File 'lib/idl/ast.rb', line 5040 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
5108 5109 5110 |
# File 'lib/idl/ast.rb', line 5108 def type_check_args(symtab) @argument_nodes.each { |a| a.type_check(symtab, false) } end |
#type_check_body(symtab) ⇒ Object
5112 5113 5114 5115 5116 |
# File 'lib/idl/ast.rb', line 5112 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 implmentation
5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 |
# File 'lib/idl/ast.rb', line 5023 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
5104 5105 5106 |
# File 'lib/idl/ast.rb', line 5104 def type_check_return(symtab) @return_type_nodes.each { |r| r.type_check(symtab) } end |
#type_check_targs(symtab) ⇒ Object
5099 5100 5101 5102 |
# File 'lib/idl/ast.rb', line 5099 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
5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 |
# File 'lib/idl/ast.rb', line 5005 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 |