Class: Wrapture::FunctionSpec
- Inherits:
-
Object
- Object
- Wrapture::FunctionSpec
- Defined in:
- lib/wrapture/function_spec.rb
Overview
A description of a function to be generated, including details about the underlying implementation.
Instance Attribute Summary collapse
-
#return_type ⇒ Object
readonly
A TypeSpec describing the return type of this function.
Class Method Summary collapse
-
.normalize_return_hash(spec) ⇒ Object
Returns a copy of the return type specification
spec. -
.normalize_spec_hash(spec) ⇒ Object
Normalizes a hash specification of a function.
Instance Method Summary collapse
-
#constructor? ⇒ Boolean
True if the function is a constructor, false otherwise.
-
#declaration(&block) ⇒ Object
Calls the given block once for each line of the declaration of the function, including any documentation.
-
#declaration_includes ⇒ Object
A list of includes needed for the declaration of the function.
-
#definable? ⇒ Boolean
True if this function can be defined.
-
#definition {|"#{return_expression(func_name: qualified_name)} {"| ... } ⇒ Object
Gives the definition of the function in a block, line by line.
-
#definition_includes ⇒ Object
A list of includes needed for the definition of the function.
-
#doc ⇒ Object
A Comment holding the function documentation.
-
#initialize(spec, owner = Scope.new, constructor: false, destructor: false) ⇒ FunctionSpec
constructor
Creates a function spec based on the provided function spec.
-
#name ⇒ Object
The name of the function.
-
#param_list ⇒ Object
A string with the parameter list for this function.
-
#qualified_name ⇒ Object
The name of the function with the class name, if it exists.
-
#resolve_type(type) ⇒ Object
A resolved type, given a TypeSpec
type. -
#resolve_wrapped_param(param_spec) ⇒ Object
Gives an expression for calling a given parameter within this function.
-
#return_expression(func_name: name) ⇒ Object
Calls return_expression on the return type of this function.
-
#signature(func_name: name) ⇒ Object
The signature of the function.
-
#variadic? ⇒ Boolean
True if the function is variadic.
-
#virtual? ⇒ Boolean
True if the function is virtual.
Constructor Details
#initialize(spec, owner = Scope.new, constructor: false, destructor: false) ⇒ FunctionSpec
Creates a function spec based on the provided function spec.
The hash must have the following keys:
- name
-
the name of the function
- params
-
a list of parameter specifications
- wrapped-function
-
a hash describing the function to be wrapped
Each parameter specification must have a ‘name’ key with the name of the parameter and a ‘type’ key with its type. The type key may be ommitted if the name of the parameter is ‘…’ in which case the generated function will be made variadic. It may optionally have an ‘includes’ key with includes that are required (for example to support the type) and/or a ‘doc’ key with documentation of the parameter.
Only one parameter named ‘…’ is allowed in a specification. If more than one is provided, then only the first encountered will be used. This parameter should also be last - if it is not, it will be moved to the end of the parameter list during normalization.
The wrapped-function must have a ‘name’ key with the name of the function, and a ‘params’ key with a list of parameters (each a hash with a ‘name’ and ‘type’ key). Optionally, it may also include an ‘includes’ key with a list of includes that are needed for this function to compile. The wrapped function may be left out entirely, but the function will not be definable if this is the case.
The following keys are optional:
- doc
-
a string containing the documentation for this function
- return
-
a specification of the return value for this function
- static
-
set to true if this is a static function
The return specification may have either a ‘type’ key with the name of the type the function returns, and/or a ‘doc’ key with documentation on the return value itself. If neither of these is needed, then the return specification may simply be omitted.
The ‘type’ key of the return spec may also be set to ‘self-reference’ which will have the function return a reference to the instance it was called on. Of course, this cannot be used from a function that is not a class method.
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/wrapture/function_spec.rb', line 98 def initialize(spec, owner = Scope.new, constructor: false, destructor: false) @owner = owner @spec = FunctionSpec.normalize_spec_hash(spec) @wrapped = if @spec.key?('wrapped-function') WrappedFunctionSpec.new(@spec['wrapped-function']) end @params = ParamSpec.new_list(@spec['params']) @return_type = TypeSpec.new(@spec['return']['type']) @constructor = constructor @destructor = destructor end |
Instance Attribute Details
#return_type ⇒ Object (readonly)
A TypeSpec describing the return type of this function.
112 113 114 |
# File 'lib/wrapture/function_spec.rb', line 112 def return_type @return_type end |
Class Method Details
.normalize_return_hash(spec) ⇒ Object
Returns a copy of the return type specification spec.
26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/wrapture/function_spec.rb', line 26 def self.normalize_return_hash(spec) if spec.nil? { 'type' => 'void', 'includes' => [] } else normalized = Marshal.load(Marshal.dump(spec)) Comment.validate_doc(spec['doc']) if spec.key?('doc') normalized['type'] ||= 'void' normalized['includes'] = Wrapture.normalize_includes(spec['includes']) normalized end end |
.normalize_spec_hash(spec) ⇒ Object
Normalizes a hash specification of a function. Normalization will check for things like invalid keys, duplicate entries in include lists, and will set missing keys to their default values (for example, an empty list if no includes are given).
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/wrapture/function_spec.rb', line 42 def self.normalize_spec_hash(spec) Comment.validate_doc(spec['doc']) if spec.key?('doc') normalized = spec.dup normalized['version'] = Wrapture.spec_version(spec) normalized['virtual'] = Wrapture.normalize_boolean(spec, 'virtual') normalized['params'] = ParamSpec.normalize_param_list(spec['params']) normalized['return'] = normalize_return_hash(spec['return']) overload = Wrapture.normalize_boolean(normalized['return'], 'overloaded') normalized['return']['overloaded'] = overload normalized end |
Instance Method Details
#constructor? ⇒ Boolean
True if the function is a constructor, false otherwise.
115 116 117 |
# File 'lib/wrapture/function_spec.rb', line 115 def constructor? @constructor end |
#declaration(&block) ⇒ Object
Calls the given block once for each line of the declaration of the function, including any documentation.
203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/wrapture/function_spec.rb', line 203 def declaration(&block) doc.format_as_doxygen(max_line_length: 76) { |line| block.call(line) } modifier_prefix = if @spec['static'] 'static ' elsif virtual? 'virtual ' else '' end block.call("#{modifier_prefix}#{return_expression};") end |
#declaration_includes ⇒ Object
A list of includes needed for the declaration of the function.
120 121 122 123 124 125 |
# File 'lib/wrapture/function_spec.rb', line 120 def declaration_includes includes = @spec['return']['includes'].dup @params.each { |param| includes.concat(param.includes) } includes.concat(@return_type.includes) includes.uniq end |
#definable? ⇒ Boolean
True if this function can be defined.
128 129 130 131 132 |
# File 'lib/wrapture/function_spec.rb', line 128 def definable? definable_check rescue UndefinableSpec false end |
#definition {|"#{return_expression(func_name: qualified_name)} {"| ... } ⇒ Object
Gives the definition of the function in a block, line by line.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/wrapture/function_spec.rb', line 218 def definition definable_check yield "#{return_expression(func_name: qualified_name)} {" locals { |declaration| yield " #{declaration}" } yield " va_start( variadic_args, #{@params[-2].name} );" if variadic? if @wrapped.error_check? yield yield " #{wrapped_call_expression};" yield @wrapped.error_check(return_val: return_variable) do |line| yield " #{line}" end else yield " #{wrapped_call_expression};" end yield ' va_end( variadic_args );' if variadic? if @return_type.self? yield ' return *this;' elsif @spec['return']['type'] != 'void' && !returns_call_directly? yield ' return return_val;' end yield '}' end |
#definition_includes ⇒ Object
A list of includes needed for the definition of the function.
135 136 137 138 139 140 141 142 |
# File 'lib/wrapture/function_spec.rb', line 135 def definition_includes includes = @wrapped.includes includes.concat(@spec['return']['includes']) @params.each { |param| includes.concat(param.includes) } includes.concat(@return_type.includes) includes << 'stdarg.h' if variadic? includes.uniq end |
#doc ⇒ Object
A Comment holding the function documentation.
250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/wrapture/function_spec.rb', line 250 def doc comment = String.new comment << @spec['doc'] if @spec.key?('doc') @params .reject { |param| param.doc.empty? } .each { |param| comment << "\n\n" << param.doc.text } if @spec['return'].key?('doc') comment << "\n\n@return " << @spec['return']['doc'] end Comment.new(comment) end |
#name ⇒ Object
The name of the function.
145 146 147 |
# File 'lib/wrapture/function_spec.rb', line 145 def name @spec['name'] end |
#param_list ⇒ Object
A string with the parameter list for this function.
150 151 152 |
# File 'lib/wrapture/function_spec.rb', line 150 def param_list ParamSpec.signature(@params, self) end |
#qualified_name ⇒ Object
The name of the function with the class name, if it exists.
155 156 157 158 159 160 161 |
# File 'lib/wrapture/function_spec.rb', line 155 def qualified_name if @owner.is_a?(ClassSpec) "#{@owner.name}::#{name}" else name end end |
#resolve_type(type) ⇒ Object
A resolved type, given a TypeSpec type. Resolved types will not have any keywords like equivalent-struct, which will be resolved to their effective type.
268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/wrapture/function_spec.rb', line 268 def resolve_type(type) if type.equivalent_struct? TypeSpec.new("struct #{@owner.struct_name}") elsif type.equivalent_pointer? TypeSpec.new("struct #{@owner.struct_name} *") elsif type.self? TypeSpec.new("#{@owner.name}&") else type end end |
#resolve_wrapped_param(param_spec) ⇒ Object
Gives an expression for calling a given parameter within this function. Equivalent structs and pointers are resolved, as well as casts between types if they are known within the scope of this function.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/wrapture/function_spec.rb', line 166 def resolve_wrapped_param(param_spec) used_param = @params.find { |p| p.name == param_spec['value'] } if param_spec['value'] == EQUIVALENT_STRUCT_KEYWORD @owner.this_struct elsif param_spec['value'] == EQUIVALENT_POINTER_KEYWORD @owner.this_struct_pointer elsif param_spec['value'] == '...' 'variadic_args' elsif castable?(param_spec) param_class = @owner.type(used_param.type) param_class.cast(used_param.name, param_spec['type'], used_param.type) else param_spec['value'] end end |
#return_expression(func_name: name) ⇒ Object
Calls return_expression on the return type of this function. func_name is passed to return_expression if provided.
187 188 189 190 191 192 193 |
# File 'lib/wrapture/function_spec.rb', line 187 def return_expression(func_name: name) if @constructor || @destructor signature(func_name: func_name) else resolved_return.return_expression(self, func_name: func_name) end end |
#signature(func_name: name) ⇒ Object
The signature of the function. func_name can be used to override the function name if needed, for example if a class name qualifier is needed.
197 198 199 |
# File 'lib/wrapture/function_spec.rb', line 197 def signature(func_name: name) "#{func_name}( #{param_list} )" end |
#variadic? ⇒ Boolean
True if the function is variadic.
281 282 283 |
# File 'lib/wrapture/function_spec.rb', line 281 def variadic? @params.last&.variadic? end |
#virtual? ⇒ Boolean
True if the function is virtual.
286 287 288 |
# File 'lib/wrapture/function_spec.rb', line 286 def virtual? @spec['virtual'] end |