Class: CGenerator::Function

Inherits:
CFragment show all
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.

Defined Under Namespace

Classes: InitAccumulator, ReturnAccumulator

Instance Attribute Summary

Attributes inherited from Accumulator

#name, #parent

Instance Method Summary collapse

Methods inherited from Template

accumulator

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

Returns:

  • (Boolean)


1701
1702
1703
# File 'lib/cgen/cgen.rb', line 1701

def empty?
  block!.to_s =~ /\A\{\s*\}\z/m
end

#prototypeObject



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