Class: CGenerator::Function
- Inherits:
-
CFragment
- Object
- Accumulator
- Template
- CFragment
- CGenerator::Function
- Defined in:
- lib/cgen/cgen.rb
Overview
The Function class manages all kinds of functions and methods.
Function Prototype
scope :static
scope :extern
arguments 'int x', 'double y', 'VALUE obj', ...
return_type 'void'
These accumulators affect the prototype of the function, which will be placed in the declaration section of either the .h or the .c file, depending on the scope setting. The default scope is static. The default return type is ‘void’.
For the Method subclasses of Function, argument and return types can be omitted, in which case they default to ‘VALUE’.
Function Body
declare :x => "static double x", ...
init "x = 0", ...
setup 'x' => "x += 1", ...
body 'y = sin(x); printf("%d\n", y)', ...
These four accumulators determine the contents of the function between the opening and closing braces. The #init code is executed once when the function first runs; it’s useful for initializing static data. The #setup code runs each time the function is called, as does the #body. Distinguishing #setup from #body is useful for two reasons: first, #setup is guaranteed to execute before #body, and, second, one can avoid setting up the same variable twice, because of the key.
returns "2*x"
Specifies the string used in the final return statement of the function. Subsequent uses of this method clobber the previous value. Alternately, one can simply insert a “return” manually in the body.
Method Classes
Method
ModuleFunction
GlobalFunction
SingletonMethod
These subclasses of the Function template are designed for coding Ruby-callable methods in C. The necessary registration (rb_define_method
, etc.) is handled automatically. Defaults are different from Function: ‘VALUE self’ is automatically an argument, and argument and return types are assumed to be ‘VALUE’ and can be omitted by the caller. The return value is nil
by default.
Method Arguments
There are three ways to declare arguments, corresponding to the three ways provided by the Ruby interpreter’s C API.
arguments :arg1, :arg2, ...
The default way of specifying arguments. Allows a fixed number of VALUE arguments.
c_array_args argc_name = 'argc', argv_name = 'argv', &block
rb_array_args args_name = 'args'
Specifies that arguments are to be collected and passed in a C or Ruby array, instead of individually (which is the default). In each case, the array of actual arguments will be bound to a C parameter with the name specified. See the Ruby API documentation for details.
If a block is given to Method#c_array_args, it will be used to specify a call to the API function rb_scan_args
and to declare the associated variables. For example:
c_array_args('argc', 'argv') {
required :arg0, :arg1
optional :arg2, :arg3, :arg4
rest :rest
block :block
}
declares all the listed symbols as variables of type VALUE
in function scope, and arranges for the following to be called in the #setup clause (i.e., before the #body):
rb_scan_args(argc, argv, "23*&", &arg0, &arg1, &arg2,
&arg3, &arg4, &rest, &block);
The 'argc', 'argv'
are the default values and are usually omitted.
The lines in the block can occur in any order, and any line can be omitted. However, only one line of each kind should be used. In addition, each optional argument can be associated with a fragment of C code that will be executed to assign it a default value, if needed. For example, one can add the following lines to the above block:
default :arg3 => "INT2NUM(7)",
:arg4 => "INT2NUM(NUM2INT(arg2) + NUM2INT(arg3))"
Otherwise, optional arguments are assigned nil.
In this case, if arg4
is not provided by argv
, then it is initialized using the code given. If, in addition, arg3
is not provided, then it too is initialized. These initializations happen in the #setup clause of the Function template and are executed in the same order as the arguments are given in the optional
line.
Finally, argument types can be checked automatically:
typecheck :arg2 => Numeric, :arg3 => Numeric
The value passed to the function must either be nil
or match the type. Note that type checking happens before default assignment, so that default calculation code can assume types are correct. No typechecking code is generated if the type is Object.
Direct Known Subclasses
Defined Under Namespace
Classes: InitAccumulator, ReturnAccumulator
Instance Attribute Summary
Attributes inherited from Accumulator
Instance Method Summary collapse
- #arguments(*args) ⇒ Object
- #empty? ⇒ Boolean
-
#initialize(name, parent) ⇒ Function
constructor
A new instance of Function.
- #prototype ⇒ Object
- #return_type(*args) ⇒ Object
- #scope(s) ⇒ Object
Methods inherited from Template
Methods inherited from Accumulator
#accept?, #add, #add_one, #add_one_really, #inspect, #inspect_one, #output, #output_one, #separator, #to_s
Constructor Details
#initialize(name, parent) ⇒ Function
Returns a new instance of Function.
1691 1692 1693 1694 1695 1696 1697 1698 1699 |
# File 'lib/cgen/cgen.rb', line 1691 def initialize name, parent super scope :static return_type 'void' add prototype, block(declare!, init!, setup!, body!, returns!) end |
Instance Method Details
#arguments(*args) ⇒ Object
1763 1764 1765 |
# File 'lib/cgen/cgen.rb', line 1763 def arguments(*args) prototype.arguments(*args) end |
#empty? ⇒ Boolean
1701 1702 1703 |
# File 'lib/cgen/cgen.rb', line 1701 def empty? block!.to_s =~ /\A\{\s*\}\z/m end |
#prototype ⇒ Object
1705 1706 1707 |
# File 'lib/cgen/cgen.rb', line 1705 def prototype @prototype ||= Prototype.new(name, self) end |
#return_type(*args) ⇒ Object
1759 1760 1761 |
# File 'lib/cgen/cgen.rb', line 1759 def return_type(*args) prototype.return_type(*args) end |
#scope(s) ⇒ Object
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 |
# File 'lib/cgen/cgen.rb', line 1709 def scope s scope_str = s.to_s unless defined?(@scope) and scope_str == @scope @scope = scope_str case scope_str when "static" prototype.scope "static " ## this is kludgy declare_static @name => prototype declare_extern @name => nil when "extern" prototype.scope "" ## would be too much work to do "extern " declare_extern @name => prototype declare_static @name => nil end end end |