Provided by: critcl_3.1.17+dfsg-1_all bug

NAME

       critcl-cproc-types - Critcl - cproc Type Reference

SYNOPSIS

       package require Tcl  8.4

       package require critcl  ?3.1.17?

       ::critcl::has-resulttype name

       ::critcl::resulttype name body ?ctype?

       ::critcl::resulttype name = origname

       ::critcl::has-argtype name

       ::critcl::argtype name body ?ctype? ?ctypefun?

       ::critcl::argtype name = origname

       ::critcl::argtypesupport name code ?guard?

       ::critcl::argtyperelease name code

________________________________________________________________________________________________________________

DESCRIPTION

       Welcome  to the C Runtime In Tcl, CriTcl for short, a system to build C extension packages for Tcl on the
       fly, from C code embedded within Tcl scripts, for all who wish to make their code go faster.

       This document is a breakout of the descriptions for the predefined argument- and result-types usable with
       the critcl::cproc command, as detailed in  the  reference  manpage  for  the  critcl  package,  plus  the
       information  on  how  to  extend the predefined set with custom types. The breakout was made to make this
       information easier to find (toplevel document vs. having to search the large main reference).

       Its intended audience are developers wishing to write Tcl packages with embedded C code.

STANDARD ARGUMENT TYPES

       Tcl_Obj*

       object The function takes an argument of type Tcl_Obj*.  No argument checking is  done.   The  Tcl  level
              word is passed to the argument as-is.

       pstring
              The  function  takes an argument of type critcl_pstring containing the original Tcl_Obj* reference
              of the Tcl argument, plus the length of the string and a pointer to the character array.

              typedef struct critcl_pstring {
                  Tcl_Obj* o;
                  char*    s;
                  int      len;
              } critcl_pstring;

       list   The function takes an argument of type critcl_list containing the original Tcl_Obj*  reference  of
              the Tcl argument, plus the length of the Tcl list and a pointer to the array of the list elements.

              typedef struct critcl_list {
                  Tcl_Obj*  o;
                  Tcl_Obj** v;
                  int       c;
              } critcl_list;

              The Tcl argument must be convertible to List, an error is thrown otherwise.

       bytearray

       rawchar*

       rawchar
              The  function takes an argument of type char*.  The Tcl argument must be convertible to ByteArray,
              an error is thrown otherwise.  Note that the  length  of  the  ByteArray  is  not  passed  to  the
              function, making this type not very usable.

       bytes  This is the new and usable ByteArray type.

              The  function takes an argument of type critcl_bytes containing the original Tcl_Obj* reference of
              the Tcl argument, plus the length of the byte array and a pointer to the byte data.

              typedef struct critcl_bytes {
                  Tcl_Obj* o;
                  char*    s;
                  int      len;
              } critcl_list;

              The Tcl argument must be convertible to ByteArray, an error is thrown otherwise.

       char*  The function takes an argument of type char*.  The string representation of the  Tcl  argument  is
              passed in.

       double The function takes an argument of type double.  The Tcl argument must be convertible to Double, an
              error is thrown otherwise.

       float  The  function takes an argument of type float.  The Tcl argument must be convertible to Double, an
              error is thrown otherwise.

       boolean

       bool   The function takes an argument of type int.  The Tcl argument must be convertible to  Boolean,  an
              error is thrown otherwise.

       int    The function takes an argument of type int.  The Tcl argument must be convertible to Int, an error
              is thrown otherwise.

       long   The function takes an argument of type long int.  The Tcl argument must be convertible to Long, an
              error is thrown otherwise.

       wideint
              The  function  takes  an  argument  of  type Tcl_WideInt.  The Tcl argument must be convertible to
              WideInt, an error is thrown otherwise.

       void*

       double*

       float*

       int*   The function takes an argument of the same-named C type.  The Tcl argument must be convertible  to
              ByteArray,  an  error  is thrown otherwise.  The bytes in the ByteArray are then re-interpreted as
              the raw representation of a single C pointer of the given type which is then passed as argument to
              the function.  In other words, this is for Tcl values somehow holding raw C pointers, i.e.  memory
              addresses.

              Attention:  These types are considered DEPRECATED.  It is planned to remove their documentation in
              release 3.2, and their implementation in release 3.3.  Their deprecation can be undone if good use
              cases are shown.

STANDARD RESULT TYPES

       Tcl_Obj*

       object The function returns a value of type Tcl_Obj*.  This value becomes the interpreter result, if  not
              0. The Tcl status is TCL_ERROR when a 0 is returned, and TCL_OK otherwise.

              Note  how it is the responsibility of the function to set the interpreter result to an appropriate
              error message when returning 0.

              Attention: The conversion assumes that the value belonged to  the  function,  with  an  associated
              reference  count,  and  decrements  the  reference  count to indicate the loss of ownership by the
              function. This means that it is an error to return a value whose  reference  count  is  zero.  The
              system will crash at some point after the return due to reuse of the freed memory.

       Tcl_Obj*0

       object0
              The  function returns a value of type Tcl_Obj*.  This value becomes the interpreter result, if not
              0. The Tcl status is TCL_ERROR when a 0 is returned, and TCL_OK otherwise.

              Note how it is the responsibility of the function to set the interpreter result to an  appropriate
              error message when returning 0.

              Attention:  Contrary  to  Tcl_Obj*  above  this  conversion  assumes that the returned value has a
              reference count of 0 and performs no decrement. Returning a value whose reference count is greater
              than zero will likely cause a memory leak.

       char*

       vstring
              The function returns a value of type char*.  This value becomes the interpreter result, wrapped in
              a String.  It is assumed that the string is volatile in some way, with the wrapping  in  a  String
              duplicating it before making it the result, ensuring that we will not access a dangling pointer in
              the future.  The Tcl status is always TCL_OK.

       const char*
              Like type char* above, except that the returned string is const-qualified.

       string

       dstring
              The  function  returns  a  value  of type char*.  Contrary to the previous string types here it is
              assumed that  the  value  is  dynamically  allocated,  via  Tcl_Alloc.   This  value  becomes  the
              interpreter result, as usual, but is not copied.  The Tcl status is always TCL_OK.

       double The  function returns a value of type double.  This value becomes the interpreter result, properly
              wrapped as a Double.  The Tcl status is always TCL_OK.

       float  The function returns a value of type float.  This value becomes the interpreter  result,  properly
              wrapped as a Double.  The Tcl status is always TCL_OK.

       boolean

       bool   The  function  returns  a  value  of  type  int,  interpreted  as boolean.  This value becomes the
              interpreter result, properly wrapped as a Int.  The Tcl status is always TCL_OK.

       int    The function returns a value of type int.  This value becomes  the  interpreter  result,  properly
              wrapped as a Int.  The Tcl status is always TCL_OK.

       long   The  function  returns  a  value  of  type  long  int.  This value becomes the interpreter result,
              properly wrapped as a Long.  The Tcl status is always TCL_OK.

       wideint
              The function returns a value of type Tcl_WideInt.  This  value  becomes  the  interpreter  result,
              properly wrapped as a WideInt.  The Tcl status is always TCL_OK.

       ok     The  function  returns  a  value  of  type  int.   It  is interpreted as the Tcl status code.  The
              interpreter result is left untouched (empty).  For a different outcome the function has to set the
              interpreter result by itself.

       void   The function does not return a value.  The interpreter result is left  untouched  (empty).  For  a
              different  outcome  the  function  has to set the interpreter result by itself.  The Tcl status is
              always TCL_OK.

ADVANCED: ADDING TYPES

       While the critcl::cproc command understands the most common C types (as per  the  previous  2  sections),
       sometimes this is not enough.

       To  get  around  this limitation the commands in this section enable users of critcl to extend the set of
       argument and result types understood by critcl::cproc. In other words, they allow them  to  define  their
       own, custom, types.

       ::critcl::has-resulttype name
              This  command tests if the named result-type is known or not.  It returns a boolean value, true if
              the type is known and false otherwise.

       ::critcl::resulttype name body ?ctype?
              This command defines the result type name, and associates it with the C code doing the  conversion
              (body) from C to Tcl.  The C return type of the associated function, also the C type of the result
              variable, is ctype. This type defaults to name if it is not specified.

              If  name is declared already an error will be thrown.  Attention! The standard result type void is
              special as it has no accompanying result variable. This cannot  be  expressed  by  this  extension
              command.

              The  body's  responsibility  is the conversion of the functions result into a Tcl result and a Tcl
              status. The first has to be set into the interpreter we are in, and the second has to be returned.

              The C code of body is guaranteed to be called last in the wrapper around the actual implementation
              of the cproc in question and has access to the following environment:

              interp A Tcl_Interp* typed C variable referencing the interpreter the  result  has  to  be  stored
                     into.

              rv     The C variable holding the result to convert, of type ctype.

              As examples here are the definitions of two standard result types:

                  resulttype int {
                Tcl_SetObjResult(interp, Tcl_NewIntObj(rv));
                return TCL_OK;
                  }

                  resulttype ok {
                /* interp result must be set by cproc body */
                return rv;
                  } int

       ::critcl::resulttype name = origname
              This  form  of the resulttype command declares name as an alias of result type origname, which has
              to be defined already. If this is not the case an error is thrown.

       ::critcl::has-argtype name
              This command tests if the named argument-type is known or not.  It returns a boolean  value,  true
              if the type is known and false otherwise.

       ::critcl::argtype name body ?ctype? ?ctypefun?
              This  command  defines  the  argument  type  name,  and  associates  it  with the C code doing the
              conversion (body) from Tcl to C The C type of the variable to hold the conversion result is  ctype
              and  the type of the function argument itself is ctypefun.  Both types default to name if they are
              not specified (or the empty string).

              If name is declared already an error will be thrown.

              The body's responsibility is the conversion of a command's Tcl_Obj* argument into a  C  value  for
              the underlying function and its storage in a helper variable.

              The C code of body is guaranteed to be called inside of a separate C code block (thus allowing the
              use of local variables) which has access to the following environment:

              interp A Tcl_Interp* typed C variable referencing the interpreter the code is running in.

              @@     A  placeholder  for the Tcl_Obj*-valued C expression providing the value of the argument to
                     convert.

              @A     A placeholder for the name of the C variable to store the converted argument into.

              As examples here are the definitions of two standard argument types:

                  argtype int {
                if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR;
                  }

                  argtype float {
                double t;
                if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR;
                @A = (float) t;
                  }

       ::critcl::argtype name = origname
              This form of the argtype command declares name as an alias of argument type origname, which has to
              be defined already. If this is not the case an error is thrown.

       ::critcl::argtypesupport name code ?guard?
              This command defines a C code fragment for the already defined argument type name  which  will  be
              inserted  before  all functions using that type. Its purpose is the definition of any supporting C
              types needed by the argument type.  If the type is used by many functions the system ensures  that
              only the first of the multiple insertions of the code fragment is active, and the others disabled.
              The  guard  identifier  is  normally derived from name, but can also be set explicitly, via guard.
              This latter allows different custom types to share a common support structure  without  having  to
              perform their own guarding.

       ::critcl::argtyperelease name code
              This  command  defines  a C code fragment for the already defined argument type name which will be
              inserted whenever the worker  function  of  a  critcl::cproc  returns  to  the  shim.  It  is  the
              responsibility  of  this  fragment  to  unconditionally  release any resources the critcl::argtype
              conversion code allocated.  An example of this are the variadic  types  for  the  support  of  the
              special,  variadic  args  argument  to critcl::cproc's.  They allocate a C array for the collected
              arguments which has to be released when the worker returns. This command defines the  C  code  for
              doing that.

EXAMPLES

       The  examples  shown  here have been drawn from section "Embedding C" in the document about Using CriTcl.
       Please see that document for many more examples.

   A SIMPLE PROCEDURE
       Starting simple, let us assume that the Tcl code in question is something like

                  proc math {x y z} {
                      return [expr {(sin($x)*rand())/$y**log($z)}]
                  }

       with the expression pretending to be something very complex and slow. Converting this to C we get:

                  critcl::cproc math {double x double y double z} double {
                      double up   = rand () * sin (x);
                      double down = pow(y, log (z));
                      return up/down;
                  }

       Notable about this translation:

       [1]    All the arguments got type information added to them, here "double".  Like in C the type  precedes
              the  argument  name.  Other  than  that  it  is pretty much a Tcl dictionary, with keys and values
              swapped.

       [2]    We now also have to declare the type of the result, here "double", again.

       [3]    The reference manpage lists all the legal C types supported as arguments and results.

   CUSTOM TYPES, INTRODUCTION
       When writing bindings to external libraries critcl::cproc is usually the most convenient way  of  writing
       the  lower  layers.  This  is  however  hampered  by  the fact that critcl on its own only supports a few
       standard (arguably the most import) standard types, whereas the functions we wish to bind most  certainly
       will use much more, specific to the library's function.

       The  critcl  commands  argtype,  resulttype  and  their adjuncts are provided to help here, by allowing a
       developer to extend critcl's type system with custom conversions.

       This and the three following sections will demonstrate this, from trivial to complex.

       The most trivial use is to create types which are aliases of existing types, standard  or  other.  As  an
       alias it simply copies and uses the conversion code from the referenced types.

       Our  example is pulled from an incomplete project of mine, a binding to Jeffrey Kegler's libmarpa library
       managing Earley parsers. Several custom types simply reflect the typedef's done by the library,  to  make
       the critcl::cprocs as self-documenting as the underlying library functions themselves.

                  critcl::argtype Marpa_Symbol_ID     = int
                  critcl::argtype Marpa_Rule_ID       = int
                  critcl::argtype Marpa_Rule_Int      = int
                  critcl::argtype Marpa_Rank          = int
                  critcl::argtype Marpa_Earleme       = int
                  critcl::argtype Marpa_Earley_Set_ID = int

                  ...

                  method sym-rank: proc {
                      Marpa_Symbol_ID sym
                      Marpa_Rank      rank
                  } Marpa_Rank {
                      return marpa_g_symbol_rank_set (instance->grammar, sym, rank);
                  }

                  ...

   CUSTOM TYPES, SEMI-TRIVIAL
       A  more  involved  custom argument type would be to map from Tcl strings to some internal representation,
       like an integer code.

       The first example is taken from the tclyaml package, a binding to the libyaml library. In a few places we
       have to map readable names for block styles, scalar styles, etc. to the internal enumeration.

                  critcl::argtype yaml_sequence_style_t {
                      if (!encode_sequence_style (interp, @@, &@A)) return TCL_ERROR;
                  }

                  ...

                  critcl::ccode {
                      static const char* ty_block_style_names [] = {
                          "any", "block", "flow", NULL
                      };

                      static int
                      encode_sequence_style (Tcl_Interp* interp, Tcl_Obj* style,
                                             yaml_sequence_style_t* estyle)
                      {
                          int value;
                          if (Tcl_GetIndexFromObj (interp, style, ty_block_style_names,
                                                   "sequence style", 0, &value) != TCL_OK) {
                              return 0;
                          }
                          *estyle = value;
                          return 1;
                      }
                  }

                  ...

                  method sequence_start proc {
                      pstring anchor
                      pstring tag
                      int implicit
                      yaml_sequence_style_t style
                  } ok {
                      /* Syntax: <instance> seq_start <anchor> <tag> <implicit> <style> */
                      ...
                  }

                  ...

       It should be noted that this code precedes the advent of the supporting generator  package  critcl::emap.
       using the generator the definition of the mapping becomes much simpler:

                  critcl::emap::def yaml_sequence_style_t {
                      any   0
                      block 1
                      flow  2
                  }

       Note  that  the  generator will not only provide the conversions, but also define the argument and result
       types needed for their use by critcl::cproc.  Another example of such a semi-trivial argument type can be
       found in the CRIMP package, which defines a Tcl_ObjType for image values. This not only provides a  basic
       argument  type  for  any  image, but also derived types which check that the image has a specific format.
       Here we see for the first time non-integer arguments, and the  need  to  define  the  C  types  used  for
       variables holding the C level value, and the type of function parameters (Due to C promotion rules we may
       need different types).

                  critcl::argtype image {
                      if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
                          return TCL_ERROR;
                      }
                  } crimp_image* crimp_image*

                  ...

                      set map [list <<type>> $type]
                      critcl::argtype image_$type [string map $map {
                          if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
                              return TCL_ERROR;
                          }
                          if (@A->itype != crimp_imagetype_find ("crimp::image::<<type>>")) {
                              Tcl_SetObjResult (interp,
                                                Tcl_NewStringObj ("expected image type <<type>>",
                                                                  -1));
                              return TCL_ERROR;
                          }
                      }] crimp_image* crimp_image*

                  ...

   CUSTOM TYPES, SUPPORT STRUCTURES
       The  adjunct  command critcl::argtypesupport is for when the conversion needs additional definitions, for
       example a helper structure.

       An example of this can be found among the standard types of critcl itself, the pstring  type.  This  type
       provides  the  C  function with not only the string pointer, but also the string length, and the Tcl_Obj*
       this data came from. As critcl::cproc's calling conventions allow us only one argument for  the  data  of
       the parameter a structure is needed to convey these three pieces of information.

       Thus the argument type is defined as

                  critcl::argtype pstring {
                      @A.s = Tcl_GetStringFromObj(@@, &(@A.len));
                      @A.o = @@;
                  } critcl_pstring critcl_pstring

                  critcl::argtypesupport pstring {
                      typedef struct critcl_pstring {
                          Tcl_Obj* o;
                          char*    s;
                          int      len;
                      } critcl_pstring;
                  }

       In  the  case of such a structure being large we may wish to allocate it on the heap instead of having it
       taking space on the stack. If we do that we need another adjunct  command,  critcl::argtyperelease.  This
       command  specifies  the code required to release dynamically allocated resources when the worker function
       returns, before the shim returns to the caller in Tcl.  To keep things simple our example is synthetic, a
       modification of pstring above, to demonstrate the technique. An actual, but more complex example  is  the
       code to support the variadic args argument of critcl::cproc.

                  critcl::argtype pstring {
                      @A = (critcl_pstring*) ckalloc(sizeof(critcl_pstring));
                      @A->s = Tcl_GetStringFromObj(@@, &(@A->len));
                      @A->o = @@;
                  } critcl_pstring* critcl_pstring*

                  critcl::argtypesupport pstring {
                      typedef struct critcl_pstring {
                          Tcl_Obj* o;
                          char*    s;
                          int      len;
                      } critcl_pstring;
                  }

                  critcl::argtyperelease pstring {
                      ckfree ((char*)) @A);
                  }

       Note,  the above example shows only the most simple case of an allocated argument, with a conversion that
       cannot fail (namely, string retrieval). If the conversion can fail  then  either  allocation  has  to  be
       defered  to  happen  only  on  successful conversion, or the conversion code has to release the allocated
       memory  itself  in  the  failure  path,  because   it   will   never   reach   the   code   defined   via
       critcl::argtyperelease in that case.

   CUSTOM TYPES, RESULTS
       All  of the previous sections dealt with argument conversions, i.e. going from Tcl into C.  Custom result
       types are for the reverse direction, from C to Tcl.  This is usually easier, as most of the  time  errors
       should not be possible. Supporting structures, or allocating them on the heap are not really required and
       therefore not supported.

       The  example  of a result type shown below was pulled from KineTcl. It is a variant of the builtin result
       type Tcl_Obj*, aka object. The builtin conversion assumes that the object returned by the function has  a
       refcount of 1 (or higher), with the function having held the reference, and releases that reference after
       placing  the  value into the interp result. The conversion below on the other hand assumes that the value
       has a refcount of 0 and thus that decrementing it is forbidden, lest it be released much  to  early,  and
       crashing the system.

                  critcl::resulttype KTcl_Obj* {
                      if (rv == NULL) { return TCL_ERROR; }
                      Tcl_SetObjResult(interp, rv);
                      /* No refcount adjustment */
                      return TCL_OK;
                  } Tcl_Obj*

       This type of definition is also found in Marpa and recent hacking hacking on CRIMP introduced it there as
       well.  Which  is  why this definition became a builtin type starting with version 3.1.16, under the names
       Tcl_Obj*0 and object0.

       Going back to errors and their handling, of course, if a function we are wrapping signals  them  in-band,
       then  the conversion of such results has to deal with that. This happens for example in KineTcl, where we
       find

                  critcl::resulttype XnStatus {
                      if (rv != XN_STATUS_OK) {
                          Tcl_AppendResult (interp, xnGetStatusString (rv), NULL);
                          return TCL_ERROR;
                      }
                      return TCL_OK;
                  }

                  critcl::resulttype XnDepthPixel {
                      if (rv == ((XnDepthPixel) -1)) {
                          Tcl_AppendResult (interp,
                                            "Inheritance error: Not a depth generator",
                                            NULL);
                          return TCL_ERROR;
                      }
                      Tcl_SetObjResult (interp, Tcl_NewIntObj (rv));
                      return TCL_OK;
                  }

AUTHORS

       Jean Claude Wippler, Steve Landers, Andreas Kupries

BUGS, IDEAS, FEEDBACK

       This document, and the package it describes, will undoubtedly contain bugs and  other  problems.   Please
       report them at https://github.com/andreas-kupries/critcl/issues.  Ideas for enhancements you may have for
       either  package,  application,  and/or  the documentation are also very welcome and should be reported at
       https://github.com/andreas-kupries/critcl/issues as well.

KEYWORDS

       C code, Embedded C Code, code generator, compile  &  run,  compiler,  dynamic  code  generation,  dynamic
       compilation, generate package, linker, on demand compilation, on-the-fly compilation

CATEGORY

       Glueing/Embedded C code

COPYRIGHT

       Copyright (c) Jean-Claude Wippler
       Copyright (c) Steve Landers
       Copyright (c) 2011-2015 Andreas Kupries

doc                                                  3.1.17                             critcl-cproc-types(3tcl)