Logo Search packages:      
Sourcecode: falconpl version File versions  Download package

core_ext.cpp

/*
   FALCON - The Falcon Programming Language.
   FILE: core_func.cpp

   Falcon module manager
   -------------------------------------------------------------------
   Author: Giancarlo Niccolai
   Begin: 2004-08-01

   -------------------------------------------------------------------
   (C) Copyright 2004: the FALCON developers (see list in AUTHORS file)

   See LICENSE file for licensing details.
*/


#include <falcon/module.h>
#include <falcon/runtime.h>
#include <falcon/item.h>
#include <falcon/types.h>
#include <falcon/stream.h>
#include <falcon/core_ext.h>
#include <falcon/error.h>
#include <falcon/vm.h>
#include <falcon/format.h>
#include "vmsema.h"

#include <falcon/string.h>
#include <falcon/carray.h>
#include <falcon/cdict.h>
#include <falcon/cobject.h>
#include <falcon/cclass.h>
#include <falcon/pagedict.h>
#include <falcon/memory.h>
#include <falcon/error.h>
#include <falcon/sys.h>
#include <falcon/attribute.h>
#include <falcon/sequence.h>
#include <falcon/membuf.h>

#include <falcon/messages.h>
#include <falcon/engstrings.h>
#include <falcon/fbom.h>

/*#
   @file core_ext.cpp The core module main file

   The core module is generated by this file.

   @beginfile core_ext.cpp
*/

/*#
   @module core The Core Module
   @brief Main VM support module

   The core module interacts with the virtual machine, to the point that, at times,
   the virtual machine itself refers to it. In example, while the exceptions can be of
   any types, the exceptions internally generated by the machine are instance of the
   Error class, which is part of the core module.

   However, the core module is not automatically linked in the VM. Every embedding
   application must create an instance of the core module, and then link it to the
   VM it uses; this allow to override also the functions that are in this module to,
   in example, trace their calls or change their behavior.

   Scripts lanuced from the falcon command line tools are granted to have access to the
   core and RTL module contents as they are described in this manual.

   @beginmodule core
*/

/*#
   @group general_purpose General purpose
   @brief Generic functions and items meant to support basic script functionalities
*/


/*#
   @funset attrib_model Attribute model support
   @brief Functions supporting attributes.

   Attributes define dynamic boolean characteristics that instances may have at a certain moment.
   An attributed can be given or removed from a certain object, or automatically given to new
   instances through class declaration has statement. The VM keeps track of instances having attributes,
   so it is possible to iterate on, or send a message to, all the objects having a certain attribute.
   In this section, the functions that allow to access this functionalities are explained.

   Attribute can be treated as collections in for/in loops and iterators can be extracted from
   them with the first() BOM method and with the Iterator class constructor.
*/

/*#
   @funset functional_support Functional programming support
   @brief ETA functions and functional constructs.

   Falcon provides some special functional programming constructs that are known
   to the VM to have special significance. The vast majority of them starts a
   “functional evaluation” chain on their parameters before their value is evaluated.
   A functional evaluation is a recursive evaluation (reduction) of list structures into
   atoms. At the moment, the only list structure that can be evaluated this way is the array.
   Evaluating a parameter in functional context means that the given parameter will be
   recursively scanned for callable arrays or symbols that can be reduced to atoms. A callable
   array is reduced by calling the function and substituting it with its return value.
   When all the contents of the list are reduced, the higher level is evaluated.

   Consider this example:
   @code
   function func0( p0, p1 ): ...
   function func1( p0 ): ...

   list = [func0, [func1, param1], param2]
   @endcode

   Calling @b list as a callable array, func0 will be called with the array [func1, param1] as
   the first parameter, and param2 as the second parameter. On the other hand, evaluating
   the above list in a functional context, first func1 will be called with param1, then
   func0 will be called with the return value of the previous evaluation as the first parameter,
   and with param2 as the second parameter.

   The functions in this section are considered “special constructs” as the VM knows them and
   treats them specially. Their definition overrides the definition of a functional evaluation,
   so that when the VM finds a special construct in its evaluation process, it ceases using the
   default evaluation algorithm and passes evaluation control to the construct.

   In example, the iff construct selects one of its branches to be evaluated only if the first
   parameter evaluates to true:
   @code
   list = [iff, someValueIsTrue, [func0, [func1, param1]], [func1, param2] ]
   @endcode

   If this list had to be evaluated in a functional context, then before iff had a chance to
   decide what to do, the two arrays [func0, ...] and [func1,...] would have been evaluated.
   As iff is a special construct, the VM doesn't evaluate its parameters and lets iff perform
   its operations as it prefer. In the case o iff, it first evaluates the first parameter,
   then evaluates in functional context the second on the third parameter, 
   leaving unevaluated the other one.

   Not all constructs evaluates everything it is passed to them in a functional context. Some of
   them are meant exactly to treat even a callable array (or anything else that should be reduced)
   as-is, stopping the evaluation process as the VM meets them. The description of each construct
   explains its working principles, and whether if its parameters are  evaluated or not.

   Please, notice that “callable” doesn't necessarily mean “evaluable”. To evaluate in functional
   context a callable symbol without parameter, it must be transformed into a single-element array.
   In example:
   @code
   function func0(): ...

   result = [iff, shouldEval, [func0], func0]
   @endcode

   This places in result the value returned by func0 if shouldEval is true, while it returns exactly
   the function object func0 as-is if shouldEval is false.
   
   A more formal definition of the funcional programming support  in Falcon is provided in the
   Survival Guide.
*/

/*#
   @funset type_mangling Type mangling
   @brief Functions managing item conversions and type detection.
*/

/*#
   @group coroutine_support Coroutine support
   @brief Functions that support quasi-parallel routine execution.

   The functions in this group allow to interact with the coroutine support that
   is provided by the Virtual Machine. Most of them translate directly into requests
   to the Virtual Machine.
*/

/*#
   @funset varparams_support Variable parameters support
   @brief Functions giving informations on variable parameters.

   Falcon supports variable parameter calling; a function or method may
   access the items that have been used in the parameter call by counting
   them and accessing them one by one.

   Parameter passed by reference may be modified with the appropriate function.

   This functions may be used whether the calling function provides a list of
   formal parameters or not. The first formal parameter will be treated as the
   variable parameter number zero, and the parameter count may be the same as,
   more than or less than the number of formal parameters.
   So, part of the parameters may be accessible via parameter names,
   and the others may be accessed with the functions in this group.
*/

/*#
   @funset gc_control Garbage collecting control
   @brief Support for script-based garbage collection strategies.

   The standard collector strategy (be it set up by the Falcon interpreter or
   by embedding applications) is adequate for average scripts.

   However, some script meant to start from command line and dealing with time
   critical data may find the action of the garbage collector too intrusive. In example
   the GC may occuur at the wrong time. Other times, calculation intensive programs
   may generate a lot of data that they know in advance can be never garbaged
   during some period. In those case, having GC to scan periodically the
   allocated memory for released blocks is evidently a useless waste of time.

   Finally, some complex scripts may even provide their own collection strategy,
   based on memory pattern usage that they know in advance. Starting the collection
   loop at time intervals, provided the memory allocation has grown at a certain rate,
   or hasn't grown for a certain time, may be a fitting strategy for some scripts.

   A sensible usage of the garbage collection feature may boost performance of
   calculation and memory intensive scripts by order of degrees, and may be
   essential in time critical applications where some part of the process has to
   be performed as fast as possible.

   Consider that some of the functions listed in this section may not be always available.
   Some embedding application may decide to turn some or all of them off for security
   reasons, as a malevolent script may crash an application very fast by turning
   off automatic GC check-and-reclaim feature and then creating a great amount
   of garbage. Also, the loop maximum execution time control is not present by
   default in Falcon command line, as the time-deterministic version of the
   garbage collector is sensibly slower, and it would be useless to the
   vast majority of the scripts.
*/

namespace Falcon {

00228 namespace core {

/****************************************
   VM Interface.
****************************************/
/*#
   @funset vminfo Virtual Machine Informations
   @brief Generic informations on the Virtual Machine.

   This functions are meant to provide minimal informations about the
   virtual machine and its configuration. In example, they provide
   the VM version number and target architectures.
*/

/*#
   @function vmVersionInfo
   @ingroup vminfo
   @inset vminfo
   @brief Returns an array containing VM version informations.
   @return Major, minor and revision numbers of the running virtual machine in a 3 elements array.
*/
FALCON_FUNC  vmVersionInfo( ::Falcon::VMachine *vm )
{
   CoreArray *ca = new CoreArray( vm, 3 );
   ca->append( (int64) ((FALCON_VERSION_NUM >> 16)) );
   ca->append( (int64) ((FALCON_VERSION_NUM >> 8) & 0xFF) );
   ca->append( (int64) ((FALCON_VERSION_NUM ) & 0xFF) );
   vm->retval( ca );
}

/*#
   @function vmModuleVersionInfo
   @ingroup vminfo
   @inset vminfo
   @brief Returns an array containing current module version informations.
   @return Major, minor and revision numbers of the curerntly being executed module,
      in a 3 elements array.
*/
FALCON_FUNC  vmModuleVersionInfo( ::Falcon::VMachine *vm )
{
   CoreArray *ca = new CoreArray( vm, 3 );
   int major=0, minor=0, revision=0;

   // we don't want our current (core) module version info...
   StackFrame *thisFrame = (StackFrame *) &vm->stackItem( vm->stackBase() - VM_FRAME_SPACE );
   if( thisFrame->m_stack_base != 0 )
   {
      StackFrame *prevFrame = (StackFrame *) &vm->stackItem( thisFrame->m_stack_base - VM_FRAME_SPACE );
      if ( prevFrame->m_module != 0 )
      {
         prevFrame->m_module->getModuleVersion( major, minor, revision );
      }
   }

   ca->append( (int64) major );
   ca->append( (int64) minor );
   ca->append( (int64) revision );
   vm->retval( ca );
}

/*#
   @function vmVersionName
   @ingroup vminfo
   @inset vminfo
   @brief Returns the nickname for this VM version.
   @return A string containing the symbolic name of this VM version.
*/
FALCON_FUNC  vmVersionName( ::Falcon::VMachine *vm )
{
   String *str = new GarbageString( vm, FALCON_VERSION " (" FALCON_VERSION_NAME ")" );
   vm->retval( str );
}

/*#
   @function vmSystemType
   @ingroup vminfo
   @inset vminfo
   @brief Returns a descriptive name of the overall system architecture.
   @return A string containing a small descriptiuon of the system architecture.

   Currently, it can be "WIN" on the various MS-Windows flavours and POSIX on
   Linux, BSD, Solaris, Mac-OSX and other *nix based systems.
*/
FALCON_FUNC  vmSystemType( ::Falcon::VMachine *vm )
{
   String *str = new GarbageString( vm, Sys::SystemData::getSystemType() );
   vm->retval( str );
}


/****************************************
   Generic item handling
****************************************/

/*#
   @function len
   @inset type_mangling
   @brief Retreives the lenght of a collection
   @param item an item of any kind
   @return the count of items in the sequence, or 0.

   The returned value represent the "size" of the item passed as a parameter.
   The number is consistent with the object type: in case of a string, it
   represents the count of characters, in case of arrays or dictionaries it
   represents the number of elements, in all the other cases the returned
   value is 0.
*/

FALCON_FUNC  len ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 ) {
      vm->retval( 0 );
      return;
   }

   Item *elem = vm->param(0);
   switch( elem->type() ) {
      case FLC_ITEM_STRING:
         vm->retval( (int64) elem->asString()->length() );
      break;

      case FLC_ITEM_ARRAY:
         vm->retval( (int64) elem->asArray()->length() );
      break;

      case FLC_ITEM_MEMBUF:
         vm->retval( (int64) elem->asMemBuf()->length() );
      break;

      case FLC_ITEM_DICT:
         vm->retval( (int64) elem->asDict()->length() );
      break;

      case FLC_ITEM_ATTRIBUTE:
         vm->retval( (int64) elem->asAttribute()->size() );
      break;

      case FLC_ITEM_RANGE:
         vm->retval( 3 );
      break;

      default:
         vm->retval( 0 );
   }
}


/****************************************
   Error management
****************************************/
/*#
   @group errors The Falcon Error System.
   @brief Falcon classes reflecting internal errors.

   This is the list of classes used by falcon core module to report the scripts (or
   embedding applications) about runtime errors.
*/

/*#
   @class Error
   @brief Internal VM and runtime error reflection class.
   @ingroup errors
   @ingroup general_purpose

   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.

   The Error class is used by the virtual machine and by the Falcon Feathers
   functions to communicate to the scripts, and eventually to the embedding
   application, about error conditions. It is also available to extension modules,
   and to the script themselves, that can create error instances that can be
   cached internally or returned to the embedder.

   A complete error code is formed by two letters indicating the error origin,
   and a numeric code specifying the correct error name. By convention, one and
   only one error description may be associated with one error code. The error
   @i message is free to be used to carry more specific informations about the error
   conditions.

   Use the comment parameter when the error message is generic, and/or the error
   may be reported because of various reasons, or to give an hint about how to
   avoid the error.

   Error codes below 5000 are reserved to Falcon engine and officially recognized
   modules. Extension modules should issue errors above 5001, unless raising well
   known error codes that are encoded and described directly by the Falcon Engine
   (i.e. a very common error code is 901 - invalid parameters when a user makes a
   mistake in calling a script function).

   All the elements in the error class are automatically initialized by the
   constructor, except for the code, the message and the description. As some error
   are created by binary modules, which are not executed by the VM, the
   informations about the line and the program counter that generated the error may
   not always be available.

   The toString() method returns a string representation of the error, which
   includes all the available informations (except for system error description).
   In this version, access to the TraceBack class has been removed from scripts.

   @prop description Textual description for the error code of this error.

   @prop message Arbitrary text used to better explain and define the error
                 conditions. Consider this as a "free text".

   @prop systemError If the error was caused by a failure during an OS operation,
                     this this property contains the error code indicating the cause of the failure.
                     Otherwise, it will be 0.


   @prop module Name of the module where the error has been generated.
   @prop symbol Symbol name (function or method) where the error has been raised.
   @prop line Line at which the error happened. If not applicable
             (i.e. because the error is not generated by a Falcon script) is 0.

   @prop pc Program counter of the instruction that raised the error.
            If not applicable (i.e. if the VM wasn't running when the error has been raised)
            the number will be 0.

   @prop subErrors Array of sub-errors.
                  Some error generating facilities may delay error
                  reporting to complete some operations, and then report all the
                  errors at once, encapsulated in a top-level failure signaling error.
                  It's the case of the reflexive compiler, which, in case of
                  errors during compilation of source code, would record all the
                  errors and store them in a generic "syntax error" exception.
                  This property stores a vector of the single sub-errors that have
                  caused operation failure.
*/

// Separate "code" property to test for @property command

/*#
   @init Error
   @brief Initializes the error.

   In case the error code is a well known code (i.e. one of the codes
   known by the engine), the description of the error will be automatically provided.

   To provide an error message without setting the code description, use directly the
   @a Error.message property after having created the object.
*/

00471 FALCON_FUNC  Error_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();

   // subclasses may have already given a value to the userdata.
   Falcon::Error *err;
   if( einst->getUserData() == 0 )
   {
      err = new GenericError;
   }
   else {
      err = reinterpret_cast<ErrorCarrier *>(einst->getUserData())->error();
   }

   // declare that the script has created it
   err->origin( e_orig_script );
   vm->fillErrorContext( err );

   // filling properties
   Item *param = vm->param( 0 );
   if ( param != 0 && param->type() != FLC_ITEM_NIL  )
      err->errorCode( (int) param->forceInteger() );

   param = vm->param( 1 );
   if ( param != 0 && param->isString() )
      err->errorDescription( *param->asString() );

   param = vm->param( 2 );
   if ( param != 0 && param->isString() )
      err->extraDescription( *param->asString() );

   einst->setUserData( new ErrorCarrier( err ) );

   vm->retval( einst );
}

/*#
   @method toString Error
   @brief Creates a textual representation of the error.

   This method uses the standard Falcon error representation to render
   the error codes, descriptions and stack traces into a string. Suberrors
   are also considered.

   To get only a descriptive string of the error without its stack trace,
   use the @a Error.heading method.
*/
00518 FALCON_FUNC  Error_toString ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   Falcon::ErrorCarrier *car = (Falcon::ErrorCarrier *) einst->getUserData();
   Falcon::Error *err = car->error();

   if ( err != 0 )
   {
      String *cs = new GarbageString( vm );
      err->toString( *cs );
      vm->retval( cs );
   }
   else
      vm->retnil();
}

/*#
   @method heading Error
   @brief Creates a short textual representation of the error.

   This method will only render the essential informations of the error,
   without printing the stack trace and without checking for other
   sub errors in the @a Error.subErrors array.

   @see Error.toString
*/
FALCON_FUNC  Error_heading ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   Falcon::ErrorCarrier *car = (Falcon::ErrorCarrier *) einst->getUserData();
   Falcon::Error *err = car->error();

   if ( err != 0 )
   {
      String *cs = new GarbageString( vm );
      err->heading( *cs );
      vm->retval( cs );
   }
   else
      vm->retnil();
}

/*#
   @method getSysErrDesc Error
   @brief returns system specific error description.
   @return System specific error description or nil if not available.

   If the error was generated by the underlying system (that is, if
   systemError > 0) returns a system and locale dependent error
   description. The description is obtained by querying the relevant
   OS error description API/SDK.

*/
FALCON_FUNC  Error_getSysErrDesc ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   Falcon::ErrorCarrier *car = (Falcon::ErrorCarrier *) einst->getUserData();
   Falcon::Error *err = car->error();

   if ( err != 0 )
   {
      String temp;
      ::Falcon::Sys::_describeError( err->systemError(), temp );
      vm->retval( temp );
   }
   else
      vm->retnil();
}


/*#
   @class SyntaxError
   @brief Syntax error descriptor.

   @ingroup errors
   @ingroup general_purpose

   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.

   @from Error code, description, extra

   This errors are generated by the compiler or the assembler when a compilation fails.
   Usually, scripts won't receive this unless they are using the compiler to compile
   themselves modules on the fly.
*/
FALCON_FUNC  SyntaxError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::SyntaxError ) );

   Error_init( vm );
}

/*#
   @class CodeError
   @brief VM and internal coded related error descriptor.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This hard errors are usually generated by the VM when it finds some corruption of the code,
   or some illegal istruction parameter. Scripts can hardly receive it, if not as a notification
   of something bad happened to another controlled script.

*/
FALCON_FUNC  CodeError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::CodeError ) );

   Error_init( vm );
}

/*#
   @class IoError
   @brief Error on I/O operations.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is raised when an I/O operation fails on the underlying
   system stream. It may also be generated by functions accessing streams
   at high abstraction level, as the functions used to serialize items
   or to read XML files.
*/
FALCON_FUNC  IoError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::IoError ) );

   Error_init( vm );
}

/*#
   @class TypeError
   @brief Type mismatch in a typed operation.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is generated when some operations requiring items of a
   certain type fail because of type mismatch.
*/

FALCON_FUNC  TypeError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::TypeError ) );

   Error_init( vm );
}

/*#
   @class AccessError
   @brief Error accessing an indexed item.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is generated when an array was accessed beyond its size,
   or a key was not found in a dictionary, or a requested property was
   not found in an object.

   In addition, core, RTL and extension functions may raise this error when the
   semantic is appropriate (i.e. when providing them unexisting property
   names, or when requesting to access an unexisting range in an array).
*/
FALCON_FUNC  AccessError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::AccessError ) );

   Error_init( vm );
}

/*#
   @class MathError
   @brief Mathematical calculation error.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This class is generated when a mathematical operation caused an error;
   it may be a domain error, as trying to extract the square root of a negative number,
   an overflow error or a division by zero. The error code will detail what kind of
   math error has happened.
*/
FALCON_FUNC  MathError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::MathError ) );

   Error_init( vm );
}

/*#
   @class ParamError
   @brief Incongruent paremeter error.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is generated when a function is called with insufficient parameters,
   or with parameters of the wrong types; this error may also be raised if the function
   determines the parameters not to be valid for other reasons (i.e. if the function
   requires not just a string as a parameter, but also a string of a minimum length).

   This error usually indicates a problem in the script code. Normally, it is to be
   considered a runtime error that has to be resolved by fixing an incorrect script,
   which should pass correct parameter to the functions it calls.
*/
FALCON_FUNC  ParamError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::ParamError ) );

   Error_init( vm );
}

/*#
   @class ParseError
   @brief Generic input parsing error.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is generated when a parsing operation fails. It is used by RTL and
   extension modules when an input that should respect a given format is malformed.
   In example, the core module throws this error when the command line parser is
   told to search for a named parameter, but the command line parameters have been
   exhausted.

   It is also used by the mxml module to report problems while parsing XML files.

   Finally, this error is available for script to describe an error status due to
   invalid inputs.
*/
FALCON_FUNC  ParseError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::ParseError ) );

   Error_init( vm );
}

/*#
   @class CloneError
   @brief Item cannot be cloned.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   Items containing external data, provided by extension modules or
   embedding application, must respect a "clone" protocol that allows
   to share, or duplicate, the inner data between different Falcon
   instances of the cloned item.

   If the inner core of Falcon item coming from a non-falcon source
   does not respect this protocol, the item cannot be cloned.

   When this error is raised, it is usually because the script
   tried to explicitly duplicate a "very special object" (in example,
   as an external resource handle created by a module).
*/
FALCON_FUNC  CloneError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::CloneError ) );

   Error_init( vm );
}

/*#
   @class InterruptedError
   @brief Wait operation interrupted.
   @ingroup errors
   @ingroup general_purpose
   @optparam code A numeric error code.
   @optparam description A textual description of the error code.
   @optparam extra A descriptive message explaining the error conditions.
   @from Error code, description, extra

   This error is raised when a wait interrupt request has been received
   by the VM during a blocking wait.

   @see interrupt_protocol
*/
FALCON_FUNC  IntrruptedError_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   if( einst->getUserData() == 0 )
      einst->setUserData( new Falcon::ErrorCarrier( new Falcon::InterruptedError ) );

   Error_init( vm );
}


/*#
   @function int
   @brief Converts the given parameter to integer.
   @inset type_mangling
   @param item The item to be converted
   @return An integer value.
   @raise ParseError in case the given string cannot be converted to an integer.
   @raise MathError if a given floating point value is too large to be converted to an integer.

   Integer values are just copied. Floating point values are converted to long integer;
   in case they are too big to be prepresented a RangeError is raised.
   Strings are converted from base 10. If the string cannot be converted,
   or if the value is anything else, a MathError instance is raised.
*/
FALCON_FUNC  val_int ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 ) {
      vm->retnil();
      return;
   }

   Item *to_int = vm->param(0);

   switch( to_int->type() ) {
      case FLC_ITEM_INT:
          vm->retval( to_int->asInteger() );
      break;

      case FLC_ITEM_NUM:
      {
         numeric num = to_int->asNumeric();
         if ( num > 9.223372036854775808e18 || num < -9.223372036854775808e18 )
         {
            vm->raiseRTError( new MathError( ErrorParam( e_domain, __LINE__ ) ) );
            return;
         }
         vm->retval( (int64)num );
      }
      break;

      case FLC_ITEM_STRING:
      {
         String *cs = to_int->asString();
         if ( cs->size() == 0 )
            vm->retval(0);
         else {
            int32 pos = cs->size() -1;
            if ( pos > 18 ) {
               vm->raiseRTError( new ParseError( ErrorParam( e_numparse_long, __LINE__ ) ) );
               return;
            }
            uint32 chr =  cs->getCharAt( pos );
            uint64 val = 0;
            uint64 base = 1;
            while( pos > 0 ) {
               if ( chr < '0' || chr > '9' ) {
                  vm->raiseRTError( new ParseError( ErrorParam( e_numparse, __LINE__ ) ) );
                  return;
               }
               val += ( chr -'0') * base;
               pos--;
               chr =  cs->getCharAt( pos );
               base *= 10;
            }
            if ( chr == '-' )
               vm->retval( -(int64)val );
            else {
               if ( chr < '0' || chr > '9' ) {
                  vm->raiseRTError( new ParseError( ErrorParam( e_numparse, __LINE__ ) ) );
                  return;
               }

               vm->retval( (int64)(val + ( chr -'0' ) * base ) );
            }
         }
      }
      break;

      default:
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).extra( "(N|S)" ) ) );
   }
}

/*#
   @function numeric
   @brief Converts the given parameter to numeric.
   @inset type_mangling
   @param item The item to be converted
   @return A numeric value.
   @raise ParseError in case the given string cannot be converted to an integer.
   @raise MathError if a given floating point value is too large to be converted to an integer.

   Floating point values are just copied. Integer values are converted to floating point;
   in case of very large integers, precision may be lost.
   Strings are converted from base 10. If the string cannot be converted,
   or if the value is anything else, a MathError instance is raised.
*/
FALCON_FUNC  val_numeric ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 ) {
      vm->retnil();
      return;
   }

   Item *to_numeric = vm->param(0);

   switch( to_numeric->type() ) {
      case FLC_ITEM_NUM:
          vm->retval( to_numeric->asNumeric() );
      break;

      case FLC_ITEM_INT:
      {
         int64 num = to_numeric->asInteger();
         if ( num > 9.223372036854775808e18 || num < -9.223372036854775808e18 )
         {
            vm->raiseRTError( new MathError( ErrorParam( e_domain, __LINE__ ) ) );
            return;
         }
         vm->retval( (numeric)num );
      }
      break;

      case FLC_ITEM_STRING:
      {
         String *cs = to_numeric->asString();
         if ( cs->size() == 0 )
            vm->retval(0);
         else {
            int32 pos = cs->size() -1;
            if ( pos > 18 ) {
               vm->raiseRTError( new MathError( ErrorParam( e_numparse_long, __LINE__ ) ) );
               return;
            }
            uint32 chr =  cs->getCharAt( pos );
            numeric val = 0;
            uint32 base = 1;
            while( pos > 0 ) {
               if ( chr == '.' ) {
                  numeric decbase = 1 / (numeric) base;
                  val *= decbase;

                  pos--;
                  chr = cs->getCharAt( pos );
                  base = 1;
                  continue;
               }
               else if ( chr < '0' || chr > '9' ) {
                  vm->raiseRTError( new MathError( ErrorParam( e_numparse, __LINE__ ) ) );
                  return;
               }
               val += ( chr -'0' ) * base;
               pos--;
               chr =  cs->getCharAt( pos );
               base *= 10;
            }

            if ( chr == '-' )
               vm->retval( -(numeric)val );
            else {
               if ( chr < '0' || chr > '9' ) {
                  vm->raiseRTError( new MathError( ErrorParam( e_numparse, __LINE__ ) ) );
                  return;
               }

               vm->retval( (numeric)(val + ( chr -'0' ) * base ) );
            }
         }
      }
      break;

      default:
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params, __LINE__ ).extra( "(N|S)" ) ) );
   }
}

/*#
   @function typeOf
   @inset type_mangling
   @param item An item of any kind.
   @brief Returns an integer indicating the type of an item.
   @return A constant indicating the type of the item.

   The typeId returned is an integer; the Falcon compiler is fed with a set of
   compile time constants that can be used to determine the type of an item.
   Those constants are always available at Falcon sources.

 the item is a user-defined opaque type


   The value returned may be one of the following:
   - @b NilType - the item is NIL
   - @b BooleanType - the item is true or false
   - @b IntegerType - the item is an integer
   - @b NumericType - the item is a floating point number
   - @b RangeType - the item is a range (a pair of two integers)
   - @b FunctionType - the item is a function
   - @b StringType - the item is a string
   - @b MemBufType - the item is a Memory Buffer Table
   - @b ArrayType - the item is an array
   - @b DictionaryType - the item is a dictionary
   - @b ObjectType - the item is an object
   - @b ClassType - the item is a class
   - @b MethodType - the item is a method
   - @b ClassMethodType - the item is a method inside a class
*/
FALCON_FUNC  typeOf ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 )
      vm->retnil();
   else
      vm->retval( vm->param( 0 )->type() );
}

/*#
   @function isCallable
   @brief Determines if an item is callable.
   @inset type_mangling
   @param item The item to be converted
   @return true if the item is callable, false otheriwse.

   If the function returns true, then the call operator can be applied.
   If it returns false, the item is not a callable one, and trying to call
   it would cause an error.
*/

FALCON_FUNC  isCallable ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 )
      vm->retval( 0 );
   else
      vm->retval( vm->param( 0 )->isCallable() ? 1 : 0 );
}

/*#
   @function getProperty
   @brief Returns the value of a property in an object.
   @param obj the source object
   @param propName A string representing the name of a property or a method inside the object.
   @return the property
   @raise AccessError if the property can't be found.

   An item representing the property is returned. The returned value is
   actually a copy of the property; assigning a new value to it won't have any
   effect on the original object.

   If the property is a method, a callable method item is returned.
   If the property is not found, an error of class RangeError is raised.
*/
FALCON_FUNC  getProperty( ::Falcon::VMachine *vm )
{
   Item *obj_x = vm->param(0);
   Item *prop_x = vm->param(1);

   if ( obj_x == 0 || ! obj_x->isObject() || prop_x == 0 || ! prop_x->isString() ) {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "(0,S)" ) ) );
   }
   else if ( ! obj_x->asObject()->getProperty( *prop_x->asString(), vm->regA() ) )
   {
      vm->raiseRTError( new AccessError( ErrorParam( e_prop_acc ) ) );
   }

   if ( vm->regA().isCallable() )
   {
      vm->regA().methodize( obj_x->asObject() );
   }
}

/*#
   @function setProperty
   @param obj The source object.
   @param propName A string representing the name of a property or a method inside the object.
   @param value The property new value.
   @raise AccessError If the property can't be found.

   Alters the value of the property in the given object. If the required property is not present,
   an AccessError is raised.

*/
FALCON_FUNC  setProperty( ::Falcon::VMachine *vm )
{
   Item *obj_x = vm->param(0);
   Item *prop_x = vm->param(1);
   Item *new_item = vm->param(2);

   if ( obj_x == 0 || ! obj_x->isObject() || prop_x == 0 || ! prop_x->isString() || new_item == 0) {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( getMessage( msg::core_002 ) ) ) );
   }
   else if ( ! obj_x->asObject()->setProperty( *prop_x->asString(), *new_item ) )
   {
      vm->raiseRTError( new AccessError( ErrorParam( e_prop_acc ) ) );
   }
}

/*#
   @function exit
   @ingroup general_purpose
   @param value an item representing VM exit code.
   @brief Requires immediate termination of the program.

   The VM execution will be interrupted, with normal state, and the item will be
   passed in the A register of the VM, where embedding application expects to receive
   the exit value. Semantic of the exit value will vary depending on the embedding
   application. The Falcon command line tools (and so, stand alone scripts) will pass
   this return value to the system if it is an integer, else they will terminate
   passing 0 to the system.

   This function terminates the VM also when there are more coroutines running.

*/

FALCON_FUNC  hexit ( ::Falcon::VMachine *vm )
{
   Item *ret = vm->param(0);

   vm->requestQuit();
   if ( ret != 0 )
      vm->retval( *ret );
}


/*#
   @function chr
   @brief Returns a string containing a single character that corresponds to the given number.
   @inset type_mangling
   @param number Numeric code of the desired character
   @return a single-char string.

   This function returns a single character string whose only character is the UNICODE
   equivalent for the given number. The number must be a valid UNICODE character,
   so it must be in range 0-0xFFFFFFFF.
*/

FALCON_FUNC  chr ( ::Falcon::VMachine *vm )
{
   uint32 val;
   Item *elem = vm->param(0);
   if ( elem == 0 ) return;
   if ( elem->type() == FLC_ITEM_INT )
      val = (uint32) elem->asInteger();
   else if ( elem->type() == FLC_ITEM_NUM )
      val = (uint32) elem->asNumeric();
   else {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "(N)" ) ) );
      return;
   }

   String *ret = new GarbageString( vm );
   ret->append( val );
   vm->retval( ret );
}

/*#
   @function ord
   @brief Returns the numeric UNICODE ID of a given character.
   @inset type_mangling
   @param string The character for which the ID is requested.
   @return the UNICODE value of the first element in the string.

   The first character in string is taken, and it's numeric ID is returned.

   @see chr
*/
FALCON_FUNC  ord ( ::Falcon::VMachine *vm )
{
   Item *elem = vm->param(0);
   if ( elem == 0 || ! elem->isString() || elem->asString()->size() == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params).extra( "(N)" ) ) );
      return;
   }

   vm->retval( (int64) elem->asString()->getCharAt(0) );
}

/*#
   @function toString
   @brief Returns a string representation of the item.
   @param item The item to be converted to string.
   @optparam numprec Number of significative decimals for numeric items.
   @return the string representation of the item.

   This function is useful to convert an unknown value in a string. The item may be any kind of Falcon
   item; the following rules apply:
      - Nil items are represented as “<NIL>”
      - Integers are converted in base 10.
      - Floating point values are converted in base 10 with a default precision of 6;
        numprec may be specified to change the default precision.
      - Array and dictionaries are represented as “Array of 'n' elements” or “Dictionary of 'n' elements”.
      - Strings are copied.
      - Objects are represented as “Object 'name of class'”, but if a toString() method is provided by the object,
        that one is called instead.
      - Classes and other kind of opaque items are rendered with their names.

   This function is not meant to provide complex applications with pretty-print facilities, but just to provide
   simple scripts with a simple and consistent output facility.
*/

FALCON_FUNC  hToString ( ::Falcon::VMachine *vm )
{
   Item *elem = vm->param(0);
   Item *format = vm->param(1);

   Fbom::toString( vm, elem, format );
}

/*#
   @function paramCount
   @return The parameter count.
   @inset varparams_support
   @brief Returns number of parameter that have been passed to the current function or method.

   The return value is the minimum value between the formal parameters declared
   for the current function and the number of actual parameters the caller passed.
   Formal parameters which are declared in the function header, but for which the
   caller didn't provide actual parameters, are filled with nil.
*/

FALCON_FUNC  paramCount ( ::Falcon::VMachine *vm )
{
   // temporarily save the call environment.
   if ( vm->stackBase() == 0 ) {
      vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
   }
   else {
      StackFrame *thisFrame = (StackFrame *) &vm->stackItem( vm->stackBase() - VM_FRAME_SPACE );
      if( thisFrame->m_stack_base == 0 ) {
         vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
         return;
      }

      StackFrame *prevFrame = (StackFrame *) &vm->stackItem( thisFrame->m_stack_base - VM_FRAME_SPACE );
      vm->retval( prevFrame->m_param_count );
   }
}

/*#
   @function parameter
   @brief Gets the Nth parameter
   @inset varparams_support
   @param pnum The ordinal number of the paremeter, zero based
   @return The nth paramter (zero based) or NIL if the parameter is not given.
   @raise AccessError if @b pnum is out of range.

   This function returns the required parameter, being the first one passed to
   the function indicated as 0, the second as 1 and so on. Both formally declared
   parameters and optional parameters can be accessed this way.

   If the given parameter number cannot be accessed, a AccessError is raised.

   @note This function used to be called "paramNumber", and has been renamed in
      version 0.8.10. The function is still aliased throught the old function name
      for compatibility reason, but its usage is deprecated. Use @b parameter instead.
*/

FALCON_FUNC  _parameter ( ::Falcon::VMachine *vm )
{
   Item *number = vm->param(0);
   if ( number == 0 || ! number->isOrdinal() ) {
      vm->raiseRTError( new ParamError( ErrorParam( e_param_outside ).extra( "(N)" ) ) );
      return;
   }

   if ( vm->stackBase() == 0 )
   {
      vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
   }
   else {
      int32 val = (int32) number->forceInteger();

      StackFrame *thisFrame = (StackFrame *) vm->currentStack().at( vm->stackBase() - VM_FRAME_SPACE );
      uint32 oldbase = thisFrame->m_stack_base;
      if( oldbase == 0 ) {
         vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
         return;
      }

      // ...but we want the parameter count of our caller.
      StackFrame *prevFrame = (StackFrame *) vm->currentStack().at( oldbase - VM_FRAME_SPACE );
      // ...while the parameters are below our frame's base.

      if( val >= 0 && val < prevFrame->m_param_count )
      {
         val = oldbase - prevFrame->m_param_count - VM_FRAME_SPACE + val;
         vm->retval( *vm->stackItem( val ).dereference() );
      }
      else {
         vm->retnil();
      }
   }
}

/*#
   @function paramIsRef
   @inset varparams_support
   @brief Checks whether the nth parameter has been passed by reference or not.
   @param number The paramter that must be checked (zero based)
   @return true if the parameter has been passed by reference, false otherwise.
   @raise AccessError if @b number is out of range.

   Both assigning a value to a certain parameter and using the paramSet()
   function will change locally the value of the parameter, b
   ut this value won't be reflected in the actual parameter that was used to
   call the function, unless the parameter was explicitly passed by reference.
   In some contexts, it may be useful to know if this is the case.

   If the given parameter number cannot be accessed, a AccessError is raised.
*/

FALCON_FUNC  paramIsRef ( ::Falcon::VMachine *vm )
{
   Item *number = vm->param(0);
   if ( number == 0 || ! number->isOrdinal() ) {
      vm->raiseRTError( new ParamError( ErrorParam( e_param_outside ).extra( "(N)" ) ) );
      return;
   }

   if ( vm->stackBase() == 0 )
   {
      vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
   }
   else
   {
      int32 val = (int32) number->forceInteger();

      StackFrame *thisFrame = (StackFrame *) &vm->stackItem( vm->stackBase() - VM_FRAME_SPACE );
      uint32 oldbase = thisFrame->m_stack_base;
      if( oldbase == 0 ) {
         vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
         return;
      }

      StackFrame *prevFrame = (StackFrame *) &vm->stackItem( oldbase - VM_FRAME_SPACE );

      if( val >= 0 && val < prevFrame->m_param_count )
      {
         val = oldbase - prevFrame->m_param_count - VM_FRAME_SPACE + val;
         vm->retval( vm->stackItem( val ).isReference() ? (int64) 1 : (int64) 0 );
      }
      else {
         vm->retval( (int64) 0 );
      }
   }
}

/*#
   @function paramSet
   @inset varparams_support
   @brief Changes the nth paramter if it has been passed by reference.
   @param number the paramter to be changed (zero based)
   @param value the new value for the parameter
   @raise AccessError if @number is out of range.

   The function is equivalent to assigning the value directly to the required
   parameter; of course, in this way also optional parameter may be accessed.
   If the required parameter was passed by reference, also the original value
   in the caller is changed.

   If the given parameter number cannot be accessed, an AccessError is raised.
*/
FALCON_FUNC  paramSet ( ::Falcon::VMachine *vm )
{

   Item *number = vm->param(0);
   Item *value = vm->param(1);
   if ( number == 0 || ! number->isOrdinal() || value == 0) {
      vm->raiseRTError( new ParamError( ErrorParam( e_param_outside ).extra( "( N, ? )" ) ) );
      return;
   }

   if ( vm->stackBase() == 0 )
   {
      vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
   }
   else
   {
      int32 val = (int32) number->forceInteger();

      StackFrame *thisFrame = (StackFrame *) &vm->stackItem( vm->stackBase() - VM_FRAME_SPACE );
      uint32 oldbase = thisFrame->m_stack_base;
      if( oldbase == 0 ) {
         vm->raiseRTError( new GenericError( ErrorParam( e_param_outside ) ) );
         return;
      }

      StackFrame *prevFrame = (StackFrame *) &vm->stackItem( oldbase - VM_FRAME_SPACE );

      if( val >= 0 && val < prevFrame->m_param_count )
      {
         val = oldbase - prevFrame->m_param_count - VM_FRAME_SPACE + val;
         vm->stackItem( val ).dereference()->copy( *value );
      }
   }
}

static bool internal_eq( ::Falcon::VMachine *vm, const Item &first, const Item &second )
{
   if( first == second || vm->compareItems( first, second ) == 0 )
   {
      return true;
   }

   if( first.isArray() && second.isArray() )
   {
      CoreArray *arr1 = first.asArray();
      CoreArray *arr2 = second.asArray();

      if ( arr1->length() != arr2->length() )
         return false;

      for ( uint32 p = 0; p < arr1->length(); p++ )
      {
         if ( ! internal_eq( vm, arr1->at(p), arr2->at(p) ) )
            return false;
      }

      return true;
   }

   if( first.isDict() && second.isDict() )
   {
      CoreDict *d1 = first.asDict();
      CoreDict *d2 = second.asDict();

      if ( d1->length() != d2->length() )
         return false;

      DictIterator *di1 = d1->first();
      DictIterator *di2 = d2->first();
      while( di1->isValid() )
      {
         if ( ! internal_eq( vm, di1->getCurrentKey(), di2->getCurrentKey() ) ||
              ! internal_eq( vm, di1->getCurrent(), di2->getCurrent() ) )
         {
            delete d1;
            delete d2;
            return false;
         }
      }

      delete d1;
      delete d2;
      return true;
   }

   return false;
}


FALCON_FUNC  eq( ::Falcon::VMachine *vm )
{
   Item *first = vm->param(0);
   Item *second = vm->param(1);
   if ( first == 0 || second == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params).extra( "X,X" ) ) );
      return;
   }

   vm->retval( internal_eq( vm, *first, *second ) ? 1:0);
}

/*@begingroup coro_sup Coroutine support
   The functions in this group allows to interact with the coroutine support that is
   provided by the Virtual Machine. Most of them translate in requests to the virtual
   machine.
*/

/*#
   @function yield
   @ingroup coroutine_support
   @brief gives up the rest of the coroutine time slice.

   This signals the VM that the current coroutine is temporarily done, and that another
   coroutine may be executed. If no other coroutines can be executed, current coroutine
   is resumed immediately (actually, it is never swapped out).
*/
FALCON_FUNC  yield ( ::Falcon::VMachine *vm )
{
   vm->yieldRequest( 0.0 );
}

/*#
   @function yieldOut
   @brief Terminates current coroutine.
   @ingroup coroutine_support
   @param retval a return value for the coroutine.

   The current coroutine is terminated. If this is the last coroutine,
   the VM exits. Calling this function has the same effect of the END
   virtual machine PCODE.

   In multithreading context, exiting from the last coroutine causes
   a clean termination of the current thread.

   @see exit
*/
FALCON_FUNC  yieldOut ( ::Falcon::VMachine *vm )
{
   Item *ret = vm->param(0);
   vm->yieldRequest( -1.0 );
   if ( ret != 0 )
      vm->retval( *ret );
   else
      vm->retnil();
}


/*#
   @function sleep
   @brief Put the current coroutine at sleep for some time.
   @param time Time, in seconds and fractions, that the coroutine wishes to sleep.
   @return an item posted by the embedding application.
   @ingroup coroutine_support
   @raise InterruptedError in case of asynchronous interruption.

   This function declares that the current coroutines is not willing to proceed at
   least for the given time. The VM will swap out the coroutine until the time has
   elapsed, and will make it eligible to run again after the given time lapse.

   The parameter may be a floating point number if a pause shorter than a second is
   required.

   The @b sleep() function can be called also when the VM has not started any coroutine;
   this will make it to be idle for the required time.

   In embedding applications, the Virtual Machine can be instructed to detect needed idle
   time and return to the calling application instead of performing a system request to
   sleep. In this way, embedding applications can use the idle time of the virtual machine
   to perform background operations. Single threaded applications may continue their execution
   and schedule continuation of the Virtual Machine at a later time, and multi-threaded
   applications can perform background message processing.

   This function complies with the interrupt protocol. The Virtual Machine may be
   asynchronously interrupted from the outside (i.e. from another thread). In this case,
   @b sleep will immediately raise an @a InterruptedError instance. The script may just
   ignore this exception and let the VM to terminate immediately, or it may honor the
   request after a cleanup it provides in a @b catch block, or it may simply ignore the
   request and continue the execution by discarding the error through an appropriate
   @b catch block.

   @see interrupt_protocol
*/

FALCON_FUNC  _f_sleep ( ::Falcon::VMachine *vm )
{
   Item *amount = vm->param(0);
   numeric pause;
   if( amount == 0 )
      pause = 0.0;
   else {
      pause = amount->forceNumeric();
      if ( pause < 0.0 )
         pause = 0.0;
   }

   vm->yieldRequest( pause );
}

/*#
   @function beginCritical
   @brief Signals the VM that this coroutine must not be interrupted.
   @ingroup coroutine_support

   After this call the VM will abstain from swapping this coroutine out
   of the execution context. The coroutine can then alter a set of data that
   must be prepare and readied for other coroutines, and then call @a endCritical
   or @a yield to pass the control back to the other coroutines.

   This function is not recursive. Successive calls to @b beginCritical are not
   counted, and have actually no effect. The first call to @a yield will swap
   out the coroutine, and the first call to @a endCritical will signal the
   availability of the routine to be swapped out, no matter how many
   times @a beginCritical has been called.
*/

FALCON_FUNC  beginCritical ( ::Falcon::VMachine *vm )
{
   vm->allowYield( false );
}

/*#
   @function endCritical
   @brief Signals the VM that this coroutine can be interrupted.
   @ingroup coroutine_support

   After this call, the coroutine may be swapped. This will happen
   only if/when the timeslice for this coroutine is over.

   This function is not recursive. Successive calls to @a beginCritical
   are not counted, and have actually no effect.
   The first call to @a yield will swap out the coroutine, and the first
   call to @a endCritical will signal the availability of the routine to be
   swapped out, no matter how many times @a beginCritical has been called.
*/

FALCON_FUNC  endCritical ( ::Falcon::VMachine *vm )
{
   vm->allowYield( true );
}

/*#
   @class Semaphore
   @brief Simple coroutine synchronization device.
   @ingroup coroutine_support
   @optparam initValue Initial value for the semaphore; if not given, 0 will be assumed.

   The semaphore is a simple synchronization object that is used by coroutines to
   communicate each others about relevant changes in the status of the application.

   Decrements the value of the semaphore, and eventually waits for the value to be > 0.
   When a @a Semaphore.wait method is called on a semaphore, two things may happen:
   if the value of the semaphore is greater than zero, the value is decremented and the
   coroutine can proceed. If it's zero, the coroutine is swapped out until the
   semaphore gets greater than zero again. When this happens, the coroutine
   decrements the value of the semaphore and proceeds. If a timeout parameter is given,
   in case the semaphore wasn't posted before the given timeout the function will return
   false.

   The order by which coroutines are resumed is the same by which they asked
   to wait on a semaphore. In this sense, @a Semaphore.wait method is implemented as a fair
   wait routine.

   The @a Semaphore.post method will raise the count of the semaphore by the given parameter
   (1 is the default if the parameter is not given). However, the calling coroutine
   won't necessarily be swapped out until a @a yield is called.
*/

/*#
   @init Semaphore
   @brief Initializes the semaphore.

   By default, the semaphore is initialized to zero; this means that the
   first wait will block the waiting coroutine, unless a @a Semaphore.post
   is issued first.
*/
FALCON_FUNC  Semaphore_init ( ::Falcon::VMachine *vm )
{
   Item *qty = vm->param(0);
   int32 value = 0;
   if ( qty != 0 ) {
      if ( qty->type() == FLC_ITEM_INT )
         value = (int32) qty->asInteger();
      else if ( qty->type() == FLC_ITEM_NUM )
         value = (int32) qty->asNumeric();
      else {
         vm->raiseRTError( new ParamError( ErrorParam( e_param_outside ).extra( "( N )" ) ) );
         return;
      }
   }

   VMSemaphore *sem = new VMSemaphore( value );
   vm->self().asObject()->setUserData( sem );
}

/*#
   @method post Semaphore
   @brief Increments the count of the semaphore.
   @optparam count The amount by which the semaphore will be incremented (1 by default).

   This method will increment the count of the semaphore by 1 or by a specified amount,
   allowing the same number of waiting coroutines to proceed.

   However, the calling coroutine won't necessarily be swapped out until a @a yield is called.
*/
FALCON_FUNC  Semaphore_post ( ::Falcon::VMachine *vm )
{
   VMSemaphore *semaphore = static_cast< VMSemaphore *>(vm->self().asObject()->getUserData());
   Item *qty = vm->param(0);
   int32 value = 1;
   if ( qty != 0 ) {
      if ( qty->type() == FLC_ITEM_INT )
         value = (int32)qty->asInteger();
      else if ( qty->type() == FLC_ITEM_NUM )
         value = (int32) qty->asNumeric();
      else {
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "( N )" ) ) );
         return;
      }
      if (value <= 0)
         value = 1;
   }

   semaphore->post( vm, value );
}

/*#
   @method wait Semaphore
   @brief Waits on a semaphore.
   @optparam timeout Optional maximum wait in seconds.

   Decrements the value of the semaphore, and eventually waits for the value to be greater
   than zero.
*/
FALCON_FUNC  Semaphore_wait ( ::Falcon::VMachine *vm )
{
   VMSemaphore *semaphore = static_cast< VMSemaphore *>(vm->self().asObject()->getUserData());
   Item *i_wc = vm->param( 0 );
   if ( i_wc == 0 )
      semaphore->wait( vm );
   else {
      if ( ! i_wc->isOrdinal() )
        {
           vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "( N )" ) ) );
         return;
        }
        semaphore->wait( vm, i_wc->forceNumeric() );
   }

}

/*#
   @function suspend
   @brief Temporarily suspends the execution of the Virtual Machine.
   @optparam timeout Optional maximum wait in seconds.
   @return an item posted by the embedding application.
   @ingroup coroutine_support

   This function is meant to provide a very simple means of communication
   with the embedding application. Other means are provided as well; they all
   require less work on the script side, but more integration work on the embedding
   application side. So, this communcation mean may be interesting for very simple
   embedding applications, or in the early stage of the integration process.

   This function hasn't any utility for stand-alone applications, and should not
   be used by them, except than for testing.

   After this call, the VM exits immediately and the control is given back to the
   embedder. The embedder can check for the VM to have exited because of a suspend
   call, and in this case, it may call the VM method Falcon::VMachine::resume()
   to make the script to proceed from the point it was suspended.

   The resume method of the virtual machine may accept an item that is then passed
   to the suspended script as the return value of the suspend call. In this way,
   the script may receive a callback notification of events happening in the main
   application, and manage them. This is an example:

   @code
   lastEvent = “none”

   while lastEvent != “quit”

      lastEvent = suspend()

      switch lastEvent
         case “this”
            doThis()
         case “that”
            doThat()
      end
   end
   @endcode

   The kind of item that is returned by suspend() call is a convention between the
   script and the embedding application, and may be a complex item as well as an
   instance of an embedder specific class.

   While in suspended state, the VM may be also destroyed, or the calling module may
   be unlinked from it, or the execution may be restarted instead of resumed.
*/

FALCON_FUNC vmSuspend( ::Falcon::VMachine *vm )
{
   vm->requestSuspend();
}

/****************************************
   The Format class.
****************************************/
/*#
   @class Format
   @brief Controls the rendering of items into strings.
   @ingroup general_purpose
   @optparam fmtspec If provided, must be a valid format specifier
      which is immediately parsed. In case of invalid format,
      a ParseError is raised.

   Format class is meant to provide an efficient way to format variables into
   strings that can then be sent to output streams. Internally, the format class
   is used in string expansion (the '@' operator), but while string expansion causes
   a string parsing to be initiated and an internal temporary Format object to be
   instantiated each time an expansion is performed, using a prebuilt Format object
   allows to optimize repeated formatting operations. Also, Format class instances may
   be used as other objects properties, applied directly to strings being written on streams,
   modified after being created and are generally more flexible than the string expansion.

   The format specifier is a string that may contain various elements indicating how the target
   variable should be rendered as a string.

   @subsection Format specification

      @b Size: The minimum field length; it can be just expressed by a number.
      if the formatted output is wide as or wider than the allocated size, the output
      will not be truncated, and the resulting string may be just too wide to be displayed
      where it was intended to be. The size can be mandatory by adding '*' after it.
      In this case, the format() method will return false (and eventually raise an error)
      if the conversion caused the output to be wider than allowed.

      @b Padding: the padding character is appended after the formatted size, or it is put in
      front of it if alignment is to the right. To define padding character, use 'p' followed
      by the character. In example, p0 to fill the field with zeros. Of course, the character
      may be any Unicode character (the format string accepts standard Falcon character escapes).
      In the special case of p0, front sign indicators are placed at the beginning of the field;
      in example "4p0+" will produce "+001" "-002" and so on, while "4px+" will produce "xx+1", "xx-2" etc.

      @b Numeric @b base: the way an integer should be rendered. It may be:
         - Decimal: as it's the default translation, no command is needed; a 'N' character may
           be added to the format to specify that we are actually expecting a number.
         - Hexadecimal: Command may be 'x' (lowercase hex), 'X' (uppercase Hex), 'c'
           (0x prefixed lowercase hex) or 'C' (0x prefixed uppercase hex). Binary: 'b' to
           convert to binary, and 'B' to convert to binary and add a "b" after the number.

         - Octal: 'o' to display an octal number, or '0' to display an octal with "0" prefix.
         - Scientific: 'e' to display a number in scientific notation W.D+/-eM. Format of numbers in
           scientific notation is fixed, so thousand separator and decimal digit separator cannot be set,
           but decimals cipher setting will still work.

      @b Decimals: a dot '.' followed by a number indicates the number of decimal to be displayed. If no
          decimal is specified, floating point numbers will be displayed with all significant digits digits,
          while if it's set to zero, decimal numbers will be rounded.

      @b Decimal @b separator: a 'd' followed by any non-cipher character will be interpreted as decimal
      separator setting. In example, to use central European standard for decimal nubmers and limit the
      output to 3 decimals, write ".3d,", or "d,.3". The default value is '.'.

      @b (Thousands) @b Grouping: actually it's the integer part group separator, as it will be displayed
      also for hexadecimal, octal and binary conversions. It is set using 'g' followed by the separator
      character, it defaults to ','. Normally, it is not displayed; to activate it set also the integer
      grouping digit count; normally is 3, but it's 4 in Japanaese and Chinese locales, while it may be
      useful to set it to 2 or 4 for hexadecimal, 3 for octal and 4 or 8 for binary. In example 'g4-'
      would group digits 4 by 4, grouping them with a "-". Zero would disable grouping.

      @b Grouping @b Character: If willing to change only the grouping character and not the default
      grouping count, use 'G'.

      @b Alignment: by default the field is aligned to the left; to align the field to
         the right use 'r'.
      @b Negative @b display @b format: By default, a '-' sign is appended in front of the number if it's
         negative. If the '+' character is added to the format, then in case the number is positive, '+'
         will be appended in front. '--' will postpend a '-' if the number is negative, while '++'
         will postpend either '+' or '-' depending on the sign of the number. To display a parenthesis around
         negative numbers, use '[', or use ']' to display a parenthesis for negative numbers and use the padding
         character in front and after positive numbers. Using parenthesis will prevent using '+', '++' or '--'
         formats. Format '-^' will add a - in front of padding space if the number is negative, while '+^'
         will add plus or minus depending on number sign. In example, "5+" would render -12 as "  -12", while "5+^"
          will render as "-  12". If alignment is to the right, the sign will be added at the other side of the
          padding: "5+^r" would render -12 as "12  -". If size is not mandatory, parenthesis will be wrapped
          around the formatted field, while if size is mandatory they will be wrapped around the whole field,
          included padding. In example "5[r" on -4 would render
          as "  (4)", while "5*[r" would render as "(  4)".

      @b Nil @b format: How to represent a nil. It may be one of the following:
         - 'nn': nil is not represented (mute).
         - 'nN': nil is represented by "N"
         - 'nl': nil is rendered with "nil"
         - 'nL': nil is rendered with "Nil". This is also the default.
         - 'nu': nil is rendered with "Null"
         - 'nU': nil is rendered with "NULL"
         - 'no': nil is rendered with "None"
         - 'nA': nil is rendered with "NA"

      @b Action @b on @b error: Normally, if trying to format something different from
      what is expected, the method format() will simply return false. In example, to format
      a string in a number, a string using the date formatter, a number in a simple
      pad-and-size formatter etc. To change this behavior, use '/' followed by one of
      the following:
         - 'n': act as the wrong item was nil (and uses the defined nil formatter).
         - '0': act as if the given item was 0, the empty string or an invalid date,
                or anyhow the neuter item of the expected type.
         - 'r': raise a type error.

      A 'c' letter may be added after the '/' and before the specifier to try a
      basic conversion into the expected type before triggering the requested effect.
      In example, if the formatted item is an object and the conversion type is string
      (that is, no numeric related options are set), this will cause the toString()
      method of the target object to be called, or if not available, the toString()
      function to be applied on the target object. In example “6/cr” tries to convert the
      item to a 6 character long string, and if it fails (i.e. because toString() method
      returns nil) an TypeError is raised.

      @b Object @b specific @b format: Objects may accept an object specific formatting as
      parameter of the standard toString() method. A pipe separator '|' will cause all the
      following format to be passed unparsed to the toString() method of objects eventually
      being formatted. If the object does not provides a toString() method, or if it's not
      an object at all, an error will be raised. The object is the sole responsible for
      parsing and applying its specific format.

      @note Ranges will be represented as [n1:n2:n3] or [n1:] if they are open. Size, alignment and padding
      will work on the whole range, while numeric formatting will be applied to each end of the range.

      Example: the format specifier "8*Xs-g2" means to format variables in a field
      of 8 characters, size mandatory (i.e. truncated if wider), Hexadecimal uppercase, grouped 2 by 2
      with '-' characters. A result may be "0A-F1-DA".

      Another example: "12.3'0r+/r" means to format a number in 12 ciphers, of which 3 are
      fixed decimals, 0 padded, right aligned; a '+' is always added in front of positive
      numbers. In case the formatted item is not a number, a type error is raised.

      Format class instances may be applied on several variables; in example, a currency value
      oriented numeric format may be applied on all the currency values of a program, and changing
      the default format would just be a matter of changing just one format object.
*/


/*#
   @method parse Format
   @brief Initializes the Format instance with an optional value.
   @param fmtspec Format specifier
   @raise ParseError if the format specifier is not correct.

   Sets or changes the format specifier for this Format instance.
   If the format string is not correct, a ParseError is raised.
*/
FALCON_FUNC  Format_parse ( ::Falcon::VMachine *vm )
{

   CoreObject *einst = vm->self().asObject();
   Format *fmt = (Format *) einst->getUserData();

   Item *param = vm->param( 0 );
   if ( param != 0 )
   {
      if( ! param->isString() )
      {
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "[S]" ) ) );
      }
      else  {
         fmt->parse( *param->asString() );
         if( ! fmt->isValid() )
         {
            vm->raiseRTError( new ParseError( ErrorParam( e_param_fmt_code ) ) );
         }
      }
   }
}

/*#
   @init Format
   @brief Initializes the Format instance with an optional value.

   If an initialization format is provided, the @a Format.parse method is called.
   Otherwise, it is necessary to call it at least once before performing a formatting.
*/
FALCON_FUNC  Format_init ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();

   Format *fmt = new Format;
   einst->setUserData( fmt );

   Format_parse( vm );
}

/*#
   @method format Format
   @param item The item to be formatted
   @optparam dest A string where to store the formatted data.
   @return A formatted string
   @raise ParamError if a format specifier has not been set yet.
   @raise TypeError if the format specifier can't be applied the item because of
         incompatible type.

   Formats the variable as per the given format descriptor. If the class has been
   instantiated without format, and the parse() method has not been called yet,
   a ParamError is raised. If the type of the variable is incompatible with the
   format descriptor, the method returns nil; a particular format specifier allows
   to throw a TypeError in this case.

   On success, the method returns a string containing a valid formatted representation
   of the variable.

   It is possible to provide a pre-allocated string where to store the formatted
   result to improve performace and spare memory.
*/
FALCON_FUNC  Format_format ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   Format *fmt = (Format *) einst->getUserData();

   Item *param = vm->param( 0 );
   Item *dest = vm->param( 1 );
   if( param == 0 || ( dest != 0 && ! dest->isString() ) )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "X,[S]" ) ) );
   }
   else
   {
      String *tgt;

      if( dest != 0 )
      {
         tgt = dest->asString();
      }
      else {
         tgt = new GarbageString( vm );
      }

      if( ! fmt->format( vm, *param, *tgt ) )
         vm->retnil();
      else
         vm->retval( tgt );
   }
}


/*#
   @method toString Format
   @return The format specifier.

   Returns a string representation of the format instance.
*/

FALCON_FUNC  Format_toString ( ::Falcon::VMachine *vm )
{
   CoreObject *einst = vm->self().asObject();
   Format *fmt = (Format *) einst->getUserData();
   vm->retval( new GarbageString( vm,fmt->originalFormat()) );
}


/*#
   @function gcEnable
   @inset gc_control
   @brief Turns automatic GC feature on or off.
   @param mode true to turn automatic GC on, false to turn it off.

   Virtual machines and some heavy garbage generating functions call
   periodically a function that checks for the level of allocated
   memory to have reached a critical point. When there is too much allocated
   memory of uncertain status, a garbage collecting loop is started.

   By setting gcEnable to off, this automatic control is skipped, and allocated
   memory can grow up to physical process limits (or VM memory limit
   constraints, if provided). Setting this value to true will cause VM to
   perform memory control checks again with the usual strategy.

   In case the script is sure to have generated a wide amount of garbage, it
   is advisable to call explicitly gcPerform() before turning automatic GC on,
   as the “natural” collection loop may start at any later moment, also after
   several VM loops.
*/

FALCON_FUNC  gcEnable( ::Falcon::VMachine *vm )
{
   if( vm->param(0) == 0 )
      vm->retval( vm->memPool()->autoCleanMode() ? 1 : 0 );
   else
      vm->memPool()->autoCleanMode( vm->param(0)->isTrue() );
}

/*#
   @function gcSetThreshold
   @inset gc_control
   @brief Turns automatic GC feature on or off.
   @optparam scanTh Amount of memory (in Kb) that triggers garbage scan.
   @optparam collectTh Amount of memory (in Kb) that triggers garbage collection.

   This function sets the garbage collection threshold levels that start automatic
   GC loop. They are both optional; if nil is provided in place of one of them,
   that value is ignored (and stays at it was before).

   The scanTh parameter determines when the automatic check the VM performs triggers
   a collection loop. When the allocated memory is below the scanTh level,
   nothing happens; when it is above, a collection loop is started.

   When the VM determines how much memory is garbage, it checks that value against
   the collectTh level. A reclaim loop is started only if the detected free memory
   is more than collectTh bytes.

   While scanTh value is not used if @a gcEnable is turned to off, collectTh
   level will still determine if the claim loop is worth to be taken also in case
   of explicit @a gcPerform calls from scripts.

   The GC level does not take into consideration the real amount of memory that the
   objects are using, but the memory they report to the VM when they are created or
   modified.

   After a GC is performed, the threshold levels are automatically adjusted so that GC
   collection checks and reclaims are not performed too often. The adjustment may
   change on a per VM basis; the default is to set the scanTh to the double of the
   memory that was found actually used, without changing the collectTh.

   Default scanTh is very strict (1MB in this version); this level has the advantage
   to scale up fast in case of huge scripts while still being big enough to let the
   vast majority of control/embedded scripts to run without GC hindrance for their
   whole life.
*/

FALCON_FUNC  gcSetThreshold( ::Falcon::VMachine *vm )
{
   Item *p0 = vm->param( 0 );
   Item *p1 = vm->param( 1 );
   bool done = false;

   if( p0 != 0 && p0->isOrdinal() ) {
      done = true;
      vm->memPool()->thresholdMemory( (uint32) p0->forceInteger() );
   }

   if( p1 != 0 && p1->isOrdinal() ) {
      done = true;
      vm->memPool()->reclaimLevel( (uint32) p1->forceInteger() );
   }

   if ( ! done )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "( [N], [N] )" ) ) );
   }
}

/*#
   @function gcSetTimeout
   @inset gc_control
   @brief Turns automatic GC feature on or off.
   @param msTimeout Amount of memory (in Kb) that triggers garbage scan.

   This function sets the maximum time a collection loop may take, expressed
   in milliseconds. A timeout of 0 means "infinite".

   This functionality is turned off by default. It must be explicitly activated
   by requesting it at the Falcon command line interpreter, or in case of
   embedding applications, it must be explicitly provided to the VM that
   is hosting the script.

   This is for two reasons: mainly, checking for time constraints is itself
   a time consuming operation, especially when compared to the atomic operations
   that a GC loop usually performs. Secondly, a script using this feature
   may crash the host application very soon once environmental condition changes.

   Considering the fact that without a complete GC loop used memory will never
   decrease, it's easy to see that a strict time constraint may prevent a full
   GC loop to ever take place. Even if the time is wide enough under normal
   circumstances (i.e. 100ms), if the script is to run ONCE on a heavy used
   CPU it may end up to be unable to perform the GC loop in the specified
   time, causing the next loops to be penalized, and possibly to never
   be able again to complete the collection under the given constraints.

   If a script and the hosting program are willing to use this feature, the
   time constraints must be used only when it is really needed; they must
   be periodically turned off (by setting the timeout to 0) or possibly not used at all.

   Of course, this is valid only for the time-constraint aware default GC provided by
   the Falcon API. Embedders are free to implement progressive GCs that may
   actually perform partial scanning in given time constraints. The "three-colors"
   garbage collector is a classical example. As all the GC strategies providing
   this feature are intrinsically less efficient than a monolithic all-or-nothing
   approach, and as they turn to be useful only in a very small category of
   applications (usually not delegated to scripting languages), Falcon does not
   provide any of them (for now).

   However, as the embedders may find this hook useful, it is provided here in
   the core module, where it interfaces directly with a property on the base
   class handling memory and garbage: MemPool.
*/

FALCON_FUNC  gcSetTimeout( ::Falcon::VMachine *vm )
{
   Item *p0 = vm->param( 0 );
   bool done = false;

   if( p0 != 0 && p0->isOrdinal() ) {
      vm->memPool()->setTimeout( (uint32) p0->forceInteger() );
   }
   else
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "( N )" ) ) );
   }
}

/*#
   @function gcPerform
   @inset gc_control
   @brief Requests immediate check of garbage.
   @optparam bForce If true, force collection of unused memory.
   @return true if the gc has been actually performed, false otherwise.

   Performs immediately a garbage collection loop. All the items the script
   is managing are checked, and the memory they occupy is stored for
   later reference; the findings of the perform loop may be retrieved
   by the gcGetParams function. If the memory that is found unreferenced
   is below the memory reclaim threshold level, the function returns immediately false.
   Otherwise, a reclaim loop is performed and some memory gets cleared,
   and the function returns true.

   If @b bForce is set to true, all the unused memory is immediately reclaimed,
   without taking into consideration the reclaim threshold.

   See @a gcSetThreshold function for a in-depth of thresholds and memory
   constraints.
*/

FALCON_FUNC  gcPerform( ::Falcon::VMachine *vm )
{
   bool bRec;

   if ( vm->param( 0 ) != 0 )
   {
      bRec = vm->param( 0 )->isTrue();
   }
   else {
      bRec = false;
   }

   vm->retval( vm->memPool()->performGC( bRec ) ? 1 : 0 );
}

/*#
   @function gcGetParams
   @inset gc_control
   @brief Requests immediate check of garbage.
   @optparam amem Amount of allocated memory.
   @optparam aitm Amount of allocated items.
   @optparam lmem Amount of alive memory.
   @optparam litm Amount of alive items.
   @optparam sth Currently set scan threshold.
   @optparam cth Currently set collect threshold.
   @optparam to Currently set collection timeout.

   This function retreives several statistical data and settings from the
   virtual machine memory manager. To retreive a parameter, pass a variable
   by reference, and pass nil in place of uninteresting parameters; in example,
   if wishing to recover the amount of alive memory and items:
   @code
   aliveItems = 0
   aliveMemory = 0
   gcGetParams( nil, nil, $aliveMemory, $aliveItems )
   @endcode

   Extra unneeded informations may just be ignored.

   The value of the alive memory and items is reliable only after (actually, soon after)
   a gcPerform() call. The data is also stored by automatic GC loops invoked
   by the VM, but the scripts have no mean to know when they are performed.
   It is reasonable to suppose that the information is still not available if
   the values returned are both 0.

   Both alive and allocated item count refers to those items that are actually stored
   in the memory manager. In fact, not every falcon item being available to the program
   will require garbage collection; only complex and deep items are accounted
   (mainly objects, strings, arrays and dictionaries).

   The informations returned by this function may be used by scripts both for
   debugging purpose and to build their own collection strategy.
*/

FALCON_FUNC  gcGetParams( ::Falcon::VMachine *vm )
{
   Item *i_mpAllocMem = vm->param( 0 );
   Item *i_mpAllocItems = vm->param( 1 );
   Item *i_mpAliveMem = vm->param( 2 );
   Item *i_mpAliveItems = vm->param( 3 );
   Item *i_mpThreshold = vm->param( 4 );
   Item *i_mpRecLev = vm->param( 5 );
   Item *i_mpTimeout = vm->param( 6 );

   if( i_mpAllocMem != 0 )
      i_mpAllocMem->setInteger( vm->memPool()->allocatedMem() );
   if( i_mpAllocItems != 0 )
      i_mpAllocItems->setInteger( vm->memPool()->allocatedItems() );
   if( i_mpAliveMem != 0 )
      i_mpAliveMem->setInteger( vm->memPool()->aliveMem() );
   if( i_mpAliveItems != 0 )
      i_mpAliveItems->setInteger( vm->memPool()->aliveItems() );
   if( i_mpThreshold != 0 )
      i_mpThreshold->setInteger( vm->memPool()->thresholdMemory() );
   if( i_mpRecLev != 0 )
      i_mpRecLev->setInteger( vm->memPool()->reclaimLevel() );
   if( i_mpTimeout != 0 )
      i_mpTimeout->setInteger( vm->memPool()->getTimeout() );
}

/****************************************
   The iterator class
****************************************/
/*#
   @class Iterator
   @brief Indirect pointer to sequences.
   @ingroup general_purpose
   @param collection The collection on which to iterate.
   @optparam position Indicator for start position.

   An iterator is an object meant to point to a certain position in a collection
   (array, dictionary, string, or eventually user defined types), and to access
   iteratively the elements in that collection.

   Iterators may be used to alter a collection by removing the item they are pointing
   to, or by changing its value. They can be stored to be used at a later moment, or
   they can be passed as parameters. Most notably, they hide the nature of the underlying
   collection, so that they can be used as an abstraction layer to access underlying data,
   one item at a time.

   Altering the collection may cause an iterator to become invalid; only performing write
   operations through an iterator it is possible to guarantee that it will stay valid
   after the modify. A test for iterator validity is performed on each operation, and in
   case the iterator is not found valid anymore, an error is raised.

   Iterators supports equality tests and provide an equal() method. Two iterators pointing
   to the same element in the same collection are considered equal; so it is possible to
   iterate through all the items between a start and an end.
*/

/*#
   @init Iterator
   @brief Initialize the iterator

   The iterator is normally created at the begin of the sequence.
   If items in the collection can be directly accessed
      (i.e. if the collection is an array or a string), the @b position
      parameter can be any valid index.

   Otherwise, @b position can be 0 (the default) or -1. If it's -1,
   an iterator pointing to the last element of the collection will be returned.
*/

FALCON_FUNC  Iterator_init( ::Falcon::VMachine *vm )
{
   Item *collection = vm->param(0);
   Item *pos = vm->param(1);

   if( collection == 0 || ( pos != 0 && ! pos->isOrdinal() ) )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "X,[N]" ) ) );
      return;
   }

   CoreObject *self = vm->self().asObject();
   int32 p = pos == 0 ? 0: (int32) pos->forceInteger();

   switch( collection->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item tgt;
         String *orig = collection->asString();
         vm->referenceItem( tgt, *collection );
         self->setProperty( "_origin", tgt );

         if( orig->checkPosBound( p ) )
         {
            self->setProperty( "_pos", (int64) p );
         }
         else {
            vm->raiseRTError( new AccessError( ErrorParam( e_inv_params ) ) );
            return;
         }
      }
      break;

      case FLC_ITEM_MEMBUF:
      {
         Item tgt;
         MemBuf *orig = collection->asMemBuf();
         vm->referenceItem( tgt, *collection );
         self->setProperty( "_origin", tgt );
         int64 len = (int64) orig->length();
         if( p >= 0 && p < len )
         {
            self->setProperty( "_pos", (int64) p );
         }
         else if ( p < 0 && p >= -len )
         {
            self->setProperty( "_pos", (int64) len - p );
         }
         else {
            vm->raiseRTError( new AccessError( ErrorParam( e_inv_params ) ) );
            return;
         }
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         CoreArray *orig = collection->asArray();
         self->setProperty( "_origin", *collection );
         if( orig->checkPosBound( p ) )
         {
            self->setProperty( "_pos", (int64) p );
         }
         else {
            vm->raiseRTError( new AccessError( ErrorParam( e_inv_params ) ) );
            return;
         }
      }
      break;

      case FLC_ITEM_DICT:
      {
         CoreDict *orig = collection->asDict();
         self->setProperty( "_origin", *collection );
         DictIterator *iter;
         if( p == 0 )
            iter = orig->first();
         else if( p == -1 )
            iter = orig->last();
         else {
            vm->raiseRTError( new AccessError( ErrorParam( e_inv_params ) ) );
            return;
         }

         self->setUserData( iter );
      }
      break;

      case FLC_ITEM_ATTRIBUTE:
      {
         Attribute *orig = collection->asAttribute();
         self->setProperty( "_origin", *collection );
         if( p != 0 )
         {
            vm->raiseRTError( new AccessError( ErrorParam( e_inv_params ) ) );
            return;
         }

         AttribIterator *iter = orig->getIterator();
         self->setUserData( iter );
      }
      break;

      case FLC_ITEM_OBJECT:
      {
         // Objects can have iterators if they have sequence extensions.
         CoreObject *obj = collection->asObject();
         UserData *ud = obj->getUserData();
         if ( ud != 0 && ud->isSequence() )
         {
            Sequence *seq = static_cast<Sequence *>( ud );
            self->setProperty( "_origin", *collection );
            CoreIterator *iter = seq->getIterator( p != 0 );
            self->setUserData( iter );
            return;
         }
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ) ) );
      }
      break;

      default:
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ) ) );
   }
}


/*#
   @method hasCurrent Iterator
   @brief Check if the iterator is valid and can be used to
          access the underlying collection.
   @return true if the iterator is valid and can be used to
          access a current item.
*/

FALCON_FUNC  Iterator_hasCurrent( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item * pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && ( p < porigin->asString()->length() ) );
      }
      break;

      case FLC_ITEM_MEMBUF:
      {
         Item * pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && ( p < porigin->asMemBuf()->length() ) );
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item * pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && ( p < porigin->asArray()->length() ) );
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         vm->retval( (int64) ( iter != 0 && iter->isValid() ? 1: 0 ) );
      }
   }
}

/*#
   @method hasNext Iterator
   @brief Check if the iterator is valid and a @a Iterator.next operation would
          still leave it valid.
   @return true if there is an item past to the current one.
*/

FALCON_FUNC  Iterator_hasNext( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item *pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && (p + 1 < porigin->asString()->length() ) );
      }
      break;

      case FLC_ITEM_MEMBUF:
      {
         Item *pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && (p + 1 < porigin->asMemBuf()->length() ) );
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item *pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         vm->retval( p >= 0 && (p + 1 < porigin->asArray()->length() ) );
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         vm->retval( (int64) ( iter != 0 && iter->hasNext() ? 1: 0 ) );
      }
   }
}

/*#
   @method hasPrev Iterator
   @brief Check if the iterator is valid and a @a Iterator.prev operation would
          still leave it valid.
   @return true if there is an item before to the current one.
*/
FALCON_FUNC  Iterator_hasPrev( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      case FLC_ITEM_MEMBUF:
      case FLC_ITEM_ARRAY:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         vm->retval( pos.forceInteger() >= 0 );
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         vm->retval( (int64) ( iter != 0 && iter->hasPrev() ? 1: 0 ) );
      }
   }
}

/*#
   @method next Iterator
   @brief Advance the iterator.
   @return true if the iterator is still valid after next() has been completed.

   Moves the iterator to the next item in the collection.
   If the iterator is not valid anymore, or if the current element was the last
   in the collection, the method returns false.
   If the iterator has successfully moved, it returns true.
*/
FALCON_FUNC  Iterator_next( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item * pos = self->getProperty( "_pos" );
         uint32 p = (uint32) pos->forceInteger();
         if ( p < porigin->asString()->length() )
         {
            p++;
            vm->retval( p != porigin->asString()->length() );
            pos->setInteger( p );
         }
         else
            vm->retval( false );
      }
      break;

      case FLC_ITEM_MEMBUF:
      {
         Item * pos = self->getProperty( "_pos" );
         uint32 p = (uint32) pos->forceInteger();
         if ( p < porigin->asMemBuf()->length() )
         {
            p++;
            vm->retval( p != porigin->asMemBuf()->length() );
            pos->setInteger( p );
         }
         else
            vm->retval( false );
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item * pos = self->getProperty( "_pos" );
         uint32 p = (uint32) pos->forceInteger();
         if ( p < porigin->asArray()->length() )
         {
            p++;
            vm->retval( p != porigin->asArray()->length() );
            pos->setInteger( p );
         }
         else
            vm->retval( false );
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         vm->retval( (int64) ( iter != 0 && iter->next() ? 1: 0 ) );
      }
   }
}


/*#
   @method prev Iterator
   @brief Move the iterator back.
   @return true if the iterator is still valid after prev() has been completed.

   Moves the iterator to the previous item in the collection.
   If the iterator is not valid anymore, or if the current element was the
   first in the collection, the method returns false. If the iterator has
   successfully moved, it returns true.
*/
FALCON_FUNC  Iterator_prev( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      case FLC_ITEM_MEMBUF:
      case FLC_ITEM_ARRAY:
      {
         Item *pos = self->getProperty( "_pos" );
         int64 p = pos->forceInteger();
         if ( p >= 0 )
         {
            pos->setInteger( p - 1 );
            vm->retval( p != 0 );
         }
         else
            vm->retval( false );
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         vm->retval( (int64) ( iter != 0 && iter->prev() ? 1: 0 ) );
      }
   }
}

/*#
   @method value Iterator
   @brief Retreives the current item in the collection.
   @optparam subst New value for the current item.
   @return The current item.
   @raise AccessError if the iterator is not valid.

   If the iterator is valid, the method returns the value of
   the item being currently pointed by the iterator.

   If a parameter @b subst is given, the current value in the sequence
   is changed to @b substs.
*/
FALCON_FUNC  Iterator_value( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();
   Item *subst = vm->param( 0 );

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item pos;
         self->getProperty( "_pos", pos );

         if ( pos.forceInteger() < 0 )
            break;

         uint32 p = (uint32) pos.forceInteger();
         if( p < porigin->asString()->length() )
         {
            GarbageString *str = new GarbageString( vm,
               porigin->asString()->subString( p, p + 1 ) );
            vm->retval( str );

            // change value
            if( subst != 0 )
            {
               switch( subst->type() )
               {
                  case FLC_ITEM_STRING:
                     porigin->asString()->change( p, p + 1, *subst->asString() );
                  break;

                  case FLC_ITEM_NUM:
                     porigin->asString()->setCharAt( p, (uint32) subst->asNumeric() );
                  break;

                  case FLC_ITEM_INT:
                     porigin->asString()->setCharAt( p, (uint32) subst->asInteger() );
                  break;

                  default:
                     vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "S/N" ) ) );
               }
            }
            return;
         }
      }
      break;

      case FLC_ITEM_MEMBUF:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         if ( pos.forceInteger() < 0 )
            break;
         uint32 p = (uint32) pos.forceInteger();
         if( p < porigin->asMemBuf()->length() )
         {
            vm->retval( (int64) porigin->asMemBuf()->get( p ) );
            // change value
            if( subst != 0 )
            {
               if ( subst->isOrdinal() )
                  porigin->asMemBuf()->set( p, (uint32) subst->forceInteger() );
               else
                  break; // only numbers allowed
            }
            return;
         }
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         if ( pos.forceInteger() < 0 )
            break;
         uint32 p = (uint32) pos.forceInteger();
         if( p < porigin->asArray()->length() )
         {
            vm->retval( porigin->asArray()->at( p ) );
            // change value
            if( subst != 0 )
            {
               porigin->asArray()->at( p ) = *subst;
            }
            return;
         }
      }
      break;

      default:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         if( iter->isValid() )
         {
            vm->retval( iter->getCurrent() );
            // change value
            if( subst != 0 )
            {
               iter->getCurrent() = *subst;
            }

            return;
         }
      }
   }

   vm->raiseRTError( new AccessError( ErrorParam( e_arracc ).extra( "Iterator.value" ) ) );
}

/*#
   @method key Iterator
   @brief Retreives the current key in the collection.
   @return The current key.
   @raise AccessError if the iterator is not valid, or if the collection has not keys.

   If this iterator is valid and is pointing to a collection that provides key
   ordering (i.e. a dictionary),  it returns the current key; otherwise,
   it raises an AccessError.
*/

FALCON_FUNC  Iterator_key( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   if( origin.isDict() )
   {
      DictIterator *iter = (DictIterator *) self->getUserData();
      if( iter->isValid() )
      {
         vm->retval( iter->getCurrentKey() );
         return;
      }
   }

   vm->raiseRTError( new AccessError( ErrorParam( e_arracc ).extra( "missing key" ) ) );
}


/*#
   @method equal Iterator
   @param item The item to which this iterator must be compared.
   @brief Check if this iterator is equal to the provided item.
   @return True if the item matches this iterator.

   This method overrides the FBOM equal method, and overloads
   the equality check of the VM.
*/

FALCON_FUNC  Iterator_equal( ::Falcon::VMachine *vm )
{
   Item *i_other = vm->param(0);

   if( i_other == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "O" ) ) );
      return;
   }

   if( i_other->isObject() )
   {
      CoreObject *other = i_other->asObject();

      if( other->derivedFrom( "Iterator" ) )
      {
         CoreObject *self = vm->self().asObject();

         Item origin, other_origin;
         self->getProperty( "_origin", origin );
         other->getProperty( "_origin", other_origin );
         if( origin.dereference()->equal( *other_origin.dereference() ) )
         {
            switch( origin.type() )
            {
               case FLC_ITEM_STRING:
               case FLC_ITEM_MEMBUF:
               case FLC_ITEM_REFERENCE:
               case FLC_ITEM_ARRAY:
               {
                  Item pos1, pos2;
                  self->getProperty( "_pos", pos1 );
                  other->getProperty( "_pos", pos2 );
                  if( pos1 == pos2 )
                  {
                     vm->retval( (int64) 1 );
                     return;
                  }
               }
               break;

               default:
               {
                  CoreIterator *iter = (CoreIterator *) self->getUserData();
                  CoreIterator *other_iter = (CoreIterator *) other->getUserData();
                  if( iter->equal( *other_iter ) )
                  {
                     vm->retval( (int64) 1 );
                     return;
                  }
               }
               break;

            }
         }
      }
   }

   vm->retval( (int64) 0 );
}

/*#
   @method clone Iterator
   @brief Returns an instance of this iterator pointing to the same item.
   @return A new copy of this iterator.

   Creates an iterator equivalent to this one. In this way, it is possible
   to record a previous position and use it later. Using a normal assignment
   wouldn't work, as the assignand would just be given the same iterator, and
   its value would change accordingly with the other image of the iterator.

*/

FALCON_FUNC  Iterator_clone( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   CoreIterator *iter = (CoreIterator *) self->getUserData();
   UserData *iclone;

   // create an instance
   Item *i_cls = vm->findWKI( "Iterator" );
   fassert( i_cls != 0 );
   CoreObject *other = i_cls->asClass()->createInstance();

   // copy low level iterator, if we have one
   if ( iter != 0 ) {
      iclone = iter->clone();
      if ( iclone == 0 )
      {
         // uncloneable iterator
         vm->raiseError( new CloneError( ErrorParam( e_uncloneable, __LINE__ ).origin( e_orig_runtime ) ) );
         return;
      }
   }
   else {
      iclone = 0;
   }

   other->setUserData( iclone );

   // then copy properties
   Item prop;
   self->getProperty( "_origin", prop );
   other->setProperty( "_origin", prop );
   self->getProperty( "_pos", prop );
   other->setProperty( "_pos", prop );

   // we can return the object
   vm->retval( other );
}

/*#
   @method erase Iterator
   @brief Erase current item in the underlying sequence.
   @raise AccessError if the iterator is invalid.

   If the iterator is valid, this method removes current item. The iterator
   is moved to the very next item in the collection, and this may invalidate
   it if the removed element was the last one. To remove element while performing
   a scanning from the last element to the first one, remember to call the prev()
   method after every remove(); in forward scans, a successful remove() implies
   that the caller must not call next() to continue the scan.
*/
FALCON_FUNC  Iterator_erase( ::Falcon::VMachine *vm )
{
   // notice: attribute cannot be removed through iterator.

   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         uint32 p = (uint32) pos.forceInteger();
         String *str = porigin->asString();

         if ( p < str->length() )
         {
            str->remove( p, 1 );
            return;
         }
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         uint32 p = (uint32) pos.forceInteger();
         CoreArray *array = porigin->asArray();

         if ( p < array->length() )
         {
            array->remove( p );
            return;
         }
      }
      break;

      default:
      {
         CoreIterator *iter = (DictIterator *) self->getUserData();
         CoreDict *dict = porigin->asDict();

         if( iter->isValid() )
         {
            iter->erase();
            return;
         }
      }
   }

   vm->raiseRTError( new AccessError( ErrorParam( e_arracc ).extra( "Iterator.erase" ) ) );
}

/*#
   @method find Iterator
   @param key the key to be searched.
   @brief Moves this iterator on the searched item.
   @return true if the key was found, false otheriwse.
   @raise AccessError if the iterator is invalid or if the sequence doesn't provide keys.

   This method searches for an key in the underlying sequence, provided it offers search
   keys support. This is the case of the various dictionaries.

   This search is optimizied so that the subtree below the current position of the iterator
   is searched first. If the iterator is pointing to an item that matches the required
   key, this method returns immediately.

   After a succesful search, the iterator is moved to the position of the searched item.

   After a failed search, the iterator is moved to the smallest item in the sequence
   greater than the desired key; it's the best position for an insertion of the searched
   key.

   In example, to traverse all the items in a dictionary starting with 'C',
   the following code can be used:

   @code
   dict = [ "Alpha" => 1, "Beta" => 2, "Charlie" => 3, "Columbus" => 4, "Delta" => 5 ]
   iter = Iterator( dict )

   iter.find( "C" )  // we don't care if it succeeds
   while iter.hasCurrent() and iter.key()[0] == "C"
      > iter.key(), " => ", iter.value()
      iter.next()
   end
   @endcode

   Also, a failed search gives anyhow a useful hint position for a subsequent
   insertion, which may avoid performing the search again.
*/
FALCON_FUNC  Iterator_find( ::Falcon::VMachine *vm )
{
   Item *i_key = vm->param(0);

   if( i_key == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "X" ) ) );
      return;
   }

   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   if ( porigin->isDict() )
   {
      DictIterator *iter = (DictIterator *) self->getUserData();
      CoreDict *dict = porigin->asDict();

      if( iter->isOwner( dict ) )
      {
         vm->retval( dict->find( *i_key, *iter ) );
         return;
      }
   }

   vm->raiseRTError( new AccessError( ErrorParam( e_arracc ).extra( "Iterator.find" ) ) );
}

/*#
   @method insert Iterator
   @param key Item to be inserted (or key, if the underlying sequence is keyed).
   @optparam value A value associated with the key.
   @brief Insert an item, or a pair of key values, in an underlying sequence.
   @raise AccessError if the iterator is invalid.

   Inserts an item at current position. In case the underlying sequence is an
   ordered sequence of key-value pairs, a correct position for insertion is first
   searched, and then the iterator is moved to the position of the inserted key.

   In this second case, if the iterator already points to a valid position for
   insertion of the given key, the search step is skipped.

   @see Iterator.find
*/

FALCON_FUNC  Iterator_insert( ::Falcon::VMachine *vm )
{
   Item *i_key = vm->param(0);
   Item *i_value = vm->param(1);

   if( i_key == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "X" ) ) );
      return;
   }

   CoreObject *self = vm->self().asObject();
   Item origin, *porigin;
   self->getProperty( "_origin", origin );
   porigin = origin.dereference();

   switch( porigin->type() )
   {
      case FLC_ITEM_STRING:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         uint32 p = (uint32) pos.forceInteger();
         String *str = porigin->asString();

         if ( ! i_key->isString() )
         {
            vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "S" ) ) );
            return;
         }

         if ( p < str->length() )
         {
            str->insert( p, 0, *i_key->asString() );
            return;
         }
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         Item pos;
         self->getProperty( "_pos", pos );
         uint32 p = (uint32) pos.forceInteger();
         CoreArray *array = porigin->asArray();

         if ( p < array->length() )
         {
            array->insert( *i_key, p );
            return;
         }
      }
      break;

      case FLC_ITEM_DICT:
      {
         if ( i_value == 0 )
         {
            vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "X,X" ) ) );
            return;
         }

         DictIterator *iter = (DictIterator *) self->getUserData();
         CoreDict *dict = porigin->asDict();

         if( iter->isOwner( dict ) && iter->isValid() )
         {
            dict->smartInsert( *iter, *i_key, *i_value );
            return;
         }
      }
      break;

      case FLC_ITEM_OBJECT:
      {
         CoreIterator *iter = (CoreIterator *) self->getUserData();
         if ( iter->insert( *i_key ) )
            return;
      }
      break;
   }

   vm->raiseRTError( new AccessError( ErrorParam( e_arracc ).extra( "Iterator.insert" ) ) );
}


/*#
   @method getOrigin Iterator
   @brief Returns the underlying sequence.
   @return The sequence being pointed by this iterator.
*/
FALCON_FUNC  Iterator_getOrigin( ::Falcon::VMachine *vm )
{
   CoreObject *self = vm->self().asObject();
   self->getProperty( "_origin", vm->regA() );
}

//===================================================
// Page dict
//===================================================

/*#
   @function PageDict
   @ingroup general_purpose
   @brief Creates a paged dictionary (which is internally represented as a B-Tree).
   @param pageSize size of pages expressed in maximum items.
   @return A new dictionary.

   The function returns a Falcon dictionary that can be handled exactly as a normal
   dictionary. The difference is only in the internal management of memory allocation
   and tree balance. Default Falcon dictionaries (the ones created with the “[=>]”
   operator) are internally represented as paired linear vectors of ordered entries.
   They are extremely efficient to store a relatively small set of data, whose size,
   and possibly key order, is known in advance. As this is exactly the condition under
   which source level dictionary are created, this way to store dictionary is the
   default in Falcon. The drawback is that if the data grows beyond a critical mass
   linear dictionary may become sluggishly slow and hang down the whole VM processing.

   This function, which is actually a class factory function (this is the reason why
   its name begins in uppercase), returns an empty Falcon dictionary that is internally
   organized as a B-Tree structure. At a marginal cost in term of memory with respect
   to the mere storage of falcon items, which is used as spare and growth area, this
   structure offer high performances on medium to large amount of data to be ordered
   and searched. Empirical tests in Falcon language showed that this structure can
   scale up easily to several millions items.

   In general, if a Falcon dictionary is meant to store large data, above five to ten
   thousands elements, or if the size of stored data is not known in advance, using
   this structure instead of the default Falcon dictionaries is highly advisable.
*/
FALCON_FUNC  PageDict( ::Falcon::VMachine *vm )
{
   Item *i_pageSize = vm->param(0);

   if( i_pageSize != 0 && ! i_pageSize->isOrdinal() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "[N]" ) ) );
      return;
   }

   uint32 pageSize = (uint32)( i_pageSize == 0 ? 33 : (uint32)i_pageSize->forceInteger() );
   CoreDict *cd = new ::Falcon::PageDict( vm, pageSize );
   vm->retval( cd );
}

//===================================================
// Memory Buffer
//===================================================

FALCON_FUNC Make_MemBuf( ::Falcon::VMachine *vm )
{
   Item *i_size = vm->param(0);
   Item *i_wordSize = vm->param(1);

   if( ( i_size == 0 || ! i_size->isOrdinal() ) ||
       ( i_wordSize != 0 && ! i_wordSize->isOrdinal() )
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).extra( "N,[N]" ) ) );
      return;
   }

   int64 wordSize = i_wordSize == 0 ? 1: i_wordSize->forceInteger();
   int64 size = i_size->forceInteger();
   if ( wordSize < 1 || wordSize > 4 || size <= 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_param_range ) ) );
      return;
   }

   MemBuf *mb = 0;
   switch( wordSize )
   {
      case 1: mb = new MemBuf_1( vm, (uint32) size ); break;
      case 2: mb = new MemBuf_2( vm, (uint32) size * 2); break;
      case 3: mb = new MemBuf_3( vm, (uint32) size * 3); break;
      case 4: mb = new MemBuf_4( vm, (uint32) size * 4); break;
   }
   fassert( mb != 0 );
   vm->retval( mb );
}

//============================================
// Fucntional extensions

static bool core_any_next( ::Falcon::VMachine *vm )
{
   // was the elaboration succesful?
   if ( vm->regA().isTrue() )
   {
      vm->retval( (int64) 1 );
      return false;
   }

   // repeat checks.
   CoreArray *arr = vm->param(0)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();
   while( count < arr->length() )
   {
      Item *itm = &arr->at(count);
      *vm->local(0) = (int64) count+1;
      if ( vm->functionalEval( *itm  ) )
      {
         return true;
      }
      else if ( vm->regA().isTrue() ) {
         vm->retval( (int64) 1 );
         return false;
      }
      count++;
   }

   vm->retval( (int64) 0 );
   return false;
}


/*#
   @function any
   @inset functional_support
   @brief Returns true if any of the items in a given collection evaluate to true.
   @param sequence A sequence of arbitrary items.
   @return true at least one item in the collection is true, false otherwise.

   Items in @b sequence are evaluated in functional context for truth value. This means that,
   if they are sigmas, they get sigma-reduced and their return value is evaluated,
   otheriwise they are evaluated directly.

   Truth value is determined using the standard Falcon truth
   check (nil is false, numerics are true if not zero, strings and collections are true if not
   empty, object and classes are always true).
   
   The check is short circuited. This means that elements are evaluated until 
   an element considered to be true (or sigma-reduced to a true value) is found.

   If the collection is empty, this function returns false.
*/
FALCON_FUNC  core_any ( ::Falcon::VMachine *vm )
{
   Item *i_param = vm->param(0);
   if( i_param == 0 || !i_param->isArray() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "A" ) ) );
      return;
   }

   CoreArray *arr = i_param->asArray();
   uint32 count = arr->length();
   vm->returnHandler( core_any_next );
   vm->addLocals(1);

   for( uint32 i = 0; i < count; i ++ )
   {
      Item *itm = &arr->at(i);
      *vm->local(0) = (int64) i+1;
      if ( vm->functionalEval( *itm  ) )
      {
         return;
      }
      else if ( vm->regA().isTrue() ) {
         vm->returnHandler( 0 );
         vm->retval( (int64) 1 );
         return;
      }
   }

   vm->returnHandler( 0 );
   vm->retval( (int64) 0 );
}


static bool core_all_next( ::Falcon::VMachine *vm )
{
   // was the elaboration succesful?
   if ( ! vm->regA().isTrue() )
   {
      vm->retval( (int64) 0 );
      return false;
   }

   // repeat checks.
   CoreArray *arr = vm->param(0)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();
   while( count < arr->length() )
   {
      Item *itm = &arr->at(count);

      *vm->local(0) = (int64) count+1;
      if ( vm->functionalEval( *itm  ) )
      {
         return true;
      }
      else if ( ! vm->regA().isTrue() ) {
         vm->retval( (int64) 0 );
         return false;
      }
      count++;
   }

   vm->retval( (int64) 1 );
   return false;
}

/*#
   @function all
   @inset functional_support
   @brief Returns true if all the items in a given collection evaluate to true.
   @param sequence A sequence of arbitrary items.
   @return true if all the items are true, false otherwise

   Items in @b sequence are evaluated in functional context for truth value. This means that,
   if they are sigmas, they get sigma-reduced and their return value is evaluated,
   otheriwise they are evaluated directly.

   Truth value is determined using the standard Falcon truth
   check (nil is false, numerics are true if not zero, strings and collections are true if not
   empty, object and classes are always true).

   The check is short circuited. This means that the processing of parameters 
   is interrupted as an element is evaluated into false.
   
   If the collection is empty, this function returns false.
*/

FALCON_FUNC  core_all ( ::Falcon::VMachine *vm )
{
   Item *i_param = vm->param(0);
   if( i_param == 0 || !i_param->isArray() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "A" ) ) );
      return;
   }

   CoreArray *arr = i_param->asArray();
   uint32 count = arr->length();
   if ( count == 0 )
   {
      vm->retval( (int64) 0 );
      return;
   }

   vm->returnHandler( core_all_next );
   vm->addLocals(1);

   for( uint32 i = 0; i < count; i ++ )
   {
      Item *itm = &arr->at(i);
      *vm->local(0) = (int64) i+1;

      if ( vm->functionalEval( *itm  ) )
      {
         return;
      }
      else if ( ! vm->regA().isTrue() ) {
         vm->returnHandler( 0 );
         vm->retval( (int64) 0 );
         return;
      }
   }

   vm->returnHandler( 0 );
   vm->retval( (int64) 1 );
}


static bool core_anyp_next( ::Falcon::VMachine *vm )
{
   // was the elaboration succesful?
   if ( vm->regA().isTrue() )
   {
      vm->retval( (int64) 1 );
      return false;
   }

   // repeat checks.
   int32 count = (uint32) vm->local(0)->asInteger();
   while( count < vm->paramCount() )
   {
      Item *itm = vm->param( count );
      *vm->local(0) = (int64) count+1;

      if ( vm->functionalEval( *itm  ) )
      {
         return true;
      }
      else if ( vm->regA().isTrue() ) {
         vm->retval( (int64) 1 );
         return false;
      }
      count++;
   }

   vm->retval( (int64) 0 );
   return false;
}

/*#
   @function anyp
   @inset functional_support
   @brief Returns true if any one of the parameters evaluate to true.
   @param ... A list of arbitrary items.
   @return true at least one parameter is true, false otherwise.
   
   This function works like @a any, but the sequence may be specified directly
   in the parameters rather being given in a separate array. This make easier to write
   anyp in callable arrays. In example, one may write
   @code
      [anyp, 1, k, n ...]
   @endcode
   while using any one should write
   @code
      [any, [1, k, n ...]]
   @endcode   
   
   Parameters are evaluated in functional context. This means that,
   if they are sigmas, they get sigma-reduced and their return value is evaluated,
   otheriwise they are evaluated directly.

   Truth value is determined using the standard Falcon truth
   check (nil is false, numerics are true if not zero, strings and collections are true if not
   empty, object and classes are always true).

   If called without parameters, this function returns false.
*/
FALCON_FUNC  core_anyp ( ::Falcon::VMachine *vm )
{
   uint32 count = vm->paramCount();
   vm->returnHandler( core_anyp_next );
   vm->addLocals(1);

   for( uint32 i = 0; i < count; i ++ )
   {
      Item *itm = vm->param(i);
      *vm->local(0) = (int64) i+1;

      if ( vm->functionalEval( *itm  ) )
      {
         return;
      }
      else if ( vm->regA().isTrue() ) {
         vm->returnHandler( 0 );
         vm->retval( (int64) 1 );
         return;
      }
   }

   vm->returnHandler( 0 );
   vm->retval( (int64) 0 );
}


static bool core_allp_next( ::Falcon::VMachine *vm )
{
   // was the elaboration succesful?
   if ( ! vm->regA().isTrue() )
   {
      vm->retval( (int64) 0 );
      return false;
   }

   // repeat checks.
   int32 count = (uint32) vm->local(0)->asInteger();
   while( count < vm->paramCount() )
   {
      Item *itm = vm->param(count);

      *vm->local(0) = (int64) count+1;
      if ( vm->functionalEval( *itm  ) )
      {
         return true;
      }
      else if ( ! vm->regA().isTrue() ) {
         vm->retval( (int64) 0 );
         return false;
      }
      count++;
   }

   vm->retval( 1 );
   return false;
}

/*#
   @function allp
   @inset functional_support
   @brief Returns true if all the parameters evaluate to true.
   @param ... An arbitrary list of items.
   @return true if all the items are true, false otherwise

   This function works like @a all, but the collection may be specified directly
   in the parameters rather being given in a separate array. This make easier to
   write allp in callable arrays. In example, one may write
   @code
      [allp, 1, k, n ...]
   @endcode
   while using all one should write
   @code
      [all, [1, k, n ...]]
   @endcode
   
   Parameters are evaluated in functional context. This means that,
   if they are sigmas, they get sigma-reduced and their return value is evaluated,
   otheriwise they are evaluated directly.

   Truth value is determined using the standard Falcon truth
   check (nil is false, numerics are true if not zero, strings and collections are true if not
   empty, object and classes are always true).
   
   If called without parameters, this function returns false.
*/
FALCON_FUNC  core_allp ( ::Falcon::VMachine *vm )
{
   uint32 count = vm->paramCount();
   vm->returnHandler( core_allp_next );
   vm->addLocals(1);

   if ( count == 0 )
   {
      vm->retval(0);
      return;
   }

   for( uint32 i = 0; i < count; i ++ )
   {
      Item *itm = vm->param(i);
      *vm->local(0) = (int64) i+1;
      if ( vm->functionalEval( *itm  ) )
      {
         return;
      }
      else if ( ! vm->regA().isTrue() ) {
         vm->returnHandler( 0 );
         vm->retval( (int64) 0 );
         return;
      }
   }

   vm->returnHandler( 0 );
   vm->retval( 1 );
}


/*#
   @function eval
   @inset functional_support
   @brief Evaluates a sequence in functional context.
   @param sequence A sequence to be evaluated.
   @return The sigma-reduction (evaluation) result.

   The parameter is evaluated in functional context; this means that if the parameter
   is a sequence starting with a callable item, that item gets called with the rest of the
   sequence passed as parameters, and the result it returns is considered the
   "evaluation result". This is performed recursively, inner-to-outer, on every element
   of the sequence before the call to the first element is actually performed.

   The description of the functional evaluation algorithm is included in the heading
   of this section.
*/

FALCON_FUNC  core_eval ( ::Falcon::VMachine *vm )
{
   Item *i_param = vm->param(0);
   if( i_param == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X" ) ) );
      return;
   }

   vm->functionalEval( *i_param );
}


FALCON_FUNC  core_min ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 )
   {
      vm->retnil();
      return;
   }

   Item *elem = vm->param( 0 );
   for ( int32 i = 1; i < vm->paramCount(); i++)
   {
      if ( vm->compareItems( *vm->param(i), *elem ) < 0 )
      {
         elem = vm->param(i);
      }

      if (vm->hadEvent())
         return;
   }

   vm->retval( *elem );
}

FALCON_FUNC  core_max ( ::Falcon::VMachine *vm )
{
   if ( vm->paramCount() == 0 )
   {
      vm->retnil();
      return;
   }

   Item *elem = vm->param( 0 );
   int32 count = vm->paramCount();
   for ( int32 i = 1; i < count; i++)
   {
      if ( vm->compareItems( *vm->param(i), *elem ) > 0 )
      {
         elem = vm->param(i);
      }

      if (vm->hadEvent())
         return;
   }

   vm->retval( *elem );
}

/*#
   @function map
   @inset functional_support
   @brief Creates a new vector of items transforming each item in the original array through the mapping function.
   @param mfunc A function or sigma used to map the array.
   @param sequence A sequence of arbitrary items.
   @return The parameter unevaluated.

   mfunc is called iteratively for every item in the collection; its return value is added to the
   mapped array. In this way it is possible to apply an uniform transformation to all the item
   in a collection.

   If mfunc returns an out of band nil item, map skips the given position in the target array,
   actually acting also as a filter function.

   In example:
   @code
      function mapper( item )
         if item < 0: return oob(nil)  // discard negative items
         return item ** 0.5            // perform square root
      end

   inspect( map( mapper, [ 100, 4, -12, 9 ]) )    // returns [10, 2, 3]
   @endcode

   @see oob
*/

static bool core_map_next( ::Falcon::VMachine *vm )
{
   // callable in first item
   CoreArray *origin = vm->param(1)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();
   CoreArray *mapped = vm->local(1)->asArray();

   if ( ! vm->regA().isOob() )
      mapped->append( vm->regA() );

   if ( count < origin->length() )
   {
      *vm->local(0) = (int64) count + 1;
      vm->pushParameter( origin->at(count) );
      vm->callFrame( *vm->param(0), 1 );
      return true;
   }

   vm->retval( mapped );
   return false;
}

FALCON_FUNC  core_map ( ::Falcon::VMachine *vm )
{
   Item *callable = vm->param(0);
   Item *i_origin = vm->param(1);
   if( callable == 0 || !callable->isCallable() ||
       i_origin == 0 || !i_origin->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "C,A" ) ) );
      return;
   }

   CoreArray *origin = i_origin->asArray();
   CoreArray *mapped = new CoreArray( vm, origin->length() );
   if ( origin->length() > 0 )
   {
      vm->returnHandler( core_map_next );
      vm->addLocals( 2 );
      *vm->local(0) = (int64)1;
      *vm->local(1) = mapped;

      vm->pushParameter( origin->at(0) );
      // do not use pre-fetched pointer
      vm->callFrame( *vm->param(0), 1 );
      return;
   }

   vm->retval( mapped );
}

static bool core_dolist_next ( ::Falcon::VMachine *vm )
{
   CoreArray *origin = vm->param(1)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();

   // done -- let A stay as is.
   if ( count >= origin->length() )
      return false;

   //if we called
   if ( vm->local(1)->asInteger() == 1 )
   {
      // not true? -- exit
      if ( ! vm->regA().isTrue() )
      {
         return false;
      }

      // prepare for next loop
      *vm->local(1) = (int64)0;
      if ( vm->functionalEval( origin->at(count) ) )
      {
         return true;
      }
   }

   *vm->local(0) = (int64) count + 1;
   *vm->local(1) = (int64) 1;
   vm->pushParameter( vm->regA() );
   vm->callFrame( *vm->param(0), 1 );
   return true;
}

/*#
   @function dolist
   @inset functional_support
   @brief Repeats an operation on a list of parameters.
   @param processor A callable item that will receive data coming from the sequence.
   @param sequence A list of items that will be fed in the processor one at a time.
   @optparam ... Optional parameters to be passed to the first callable item.
   @return The return value of the last callable item.

   Every item in @b sequence is passed as parameter to the processor, which must be a callable
   item. Items are also functionally evaluated, one by one, but the parameter @b sequence is not
   functionally evaluated as a whole; to do that, use the explicit evaluation:
   @code
      dolist( processor, eval(array) )
   @endcode
   This method is equivalent to @a xmap, but it has the advantage that it doesn't create an array
   of evaluated results. So, when it is not necessary to transform a sequence in another through a
   mapping function, but just to run repeatedly over a collection, this function is to be preferred.
*/
FALCON_FUNC  core_dolist ( ::Falcon::VMachine *vm )
{
   Item *callable = vm->param(0);
   Item *i_origin = vm->param(1);
   if( callable == 0 || !callable->isCallable() ||
       i_origin == 0 || !i_origin->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "C,A" ) ) );
      return;
   }

   CoreArray *origin = i_origin->asArray();
   if ( origin->length() != 0 )
   {
      vm->returnHandler( core_dolist_next );
      vm->addLocals( 2 );
      // count
      *vm->local(0) = (int64) 0;

      //exiting from an eval or from a call frame? -- 0 eval
      *vm->local(1) = (int64) 0;

      if ( vm->functionalEval( origin->at(0) ) )
      {
         return;
      }

      // count
      *vm->local(0) = (int64) 1;

      //exiting from an eval or from a call frame? -- 1 callframe
      *vm->local(1) = (int64) 1;
      vm->pushParameter( vm->regA() );
      vm->callFrame( *vm->param(0), 1 );
   }
}


static bool core_times_next ( ::Falcon::VMachine *vm )
{
   // we may mangle with the parameters -- be careful.
   Item var = *vm->param(1);
   CoreArray *sequence = vm->param(2)->asArray();
   Item &range = *vm->local(0); // temporary reference, we won't hold for long.
   int32 start = range.asRangeStart();
   uint32 currentItemID = (uint32) vm->local(1)->asInteger();

   // Continue or items terminated?
   if( currentItemID == sequence->length() ||
      ( vm->regA().isOob() && vm->regA().isInteger() && vm->regA().asInteger() == 1 )
      )
   {
      currentItemID = 0;
      // here it is safe to change the reference
      start += range.asRangeStep();
      if ( vm->isParamByRef( 1 ) )
         vm->param(1)->setInteger( start );

      // we won't need the range past this point.
      range.setRange( start, range.asRangeEnd(), range.asRangeStep(), false );
   }

   // Break or loop terminated?
   if( ( range.asRangeStep() > 0 && start >= range.asRangeEnd()) ||
       ( range.asRangeStep() < 0 && start < range.asRangeEnd()) ||
      ( vm->regA().isOob() && vm->regA().isInteger() && vm->regA().asInteger() == 0 )
      )
   {
      vm->regA().setInteger( (int64) range.asRangeStart() );
      return false;
   }

   // get the current item.
   Item &current = sequence->at( currentItemID );

   // prepare the next current item ID
   vm->local(1)->setInteger( currentItemID + 1 );

   // Is the current item callable? -- if not, raise an error
   if ( ! current.isCallable() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "uncallable" ) ) );
      return false;   // don't call me anymore
   }

   // how should we call the item?
   if ( ! vm->isParamByRef( 1 ) )
   {
      // we must alter its parameters.
      if ( current.isArray() )
      {
         CoreArray *curArray = current.asArray();
         // append? -- explode the call (callFrame would do it anyhow)
         int64 varID = var.forceInteger();
         if ( varID <= 0 )
         {
            for ( uint32 i = 1; i < curArray->length(); i++ )
            {
               vm->pushParameter( curArray->at(i) );
            }
            vm->pushParameter( (int64) start);
            // queue the call ( + 1 parameter - 1 because first item is callable)
            vm->callFrame( curArray->at(0), curArray->length() );
         }
         // otherwise, mangle the item ID
         else {
            // for now, let's ignore too short arrays.
            if ( curArray->length() > (uint32) varID )
            {
               curArray->at( (uint32) varID ) = (int64) start;
            }
            // just perform the call as-is.
            vm->callFrame( curArray, 0 );
         }
      }
      // if it's not an array, just push the parameter and call
      else {
         vm->pushParameter( (int64) start);
         vm->callFrame( current, 1 );
      }
   }
   else {
      // we need just to call the item.
      vm->callFrame( current, 0 );
   }

   // prepare the next current item ID
   vm->local(1)->setInteger( currentItemID + 1 );

   return true;
}

/*#
   @function times
   @inset functional_support
   @brief Repeats a sequence a determined number of times.
   @param count Count of times to be repeated or non-open range.
   @param var A reference to a variable that will receive the current count, nil or a number.
   @param sequence A list of callable items that can be called one at a time.
   @return Last index processed.

   This function is very similar to a functional for/in loop. It repeats a sequence
   of callable items in the @b sequence parameter a determined number of
   times, eventually filling a variable with the current loop index, or mangling the
   parameters of the given callable items so that they receive the index as a parameter.

   @note The paramters of @b times are not functionally evaluated.

   The loop index count will be given values from 0 to the required index-1 if @b count is numeric,
   or it will act as the for/in loop if @b count is a range.

   The way the current index loop is sent to the items depends on the type of @b var.
   If it's nil, then the count is only kept internally; Sigma functions in @b sequence may not need it, or
   they may use an internal counter. In example:
   @code
      function printTimes()
         static: i = 0
         > "Called ", ++i, " times."
      end

      times( 10, nil, [ printTimes ] )
   @endcode

   If @b val is a reference to a variable, then that variable is
   updated to the current loop value. The Sigmas in @b sequence may receive it as a parameter
   passed by reference or may accesses it from the outer (global) scope. In example:
   @code
      // module scope
      sent = nil

      function printSent()
         global sent
         > "Called ", sent, " times."
      end

      function printParam( var )
         > "Parameter is... ", var
      end

      times( 10, $sent, [ printSent, [printParam, $sent] ] )
   @endcode

   In the above example, printSent "fishes" the global value of @b sent, while printParam
   uses a reference to it in its parameters and sees its paramter list changed at each call.

   Finally, @b var may be a number. If the number is zero or less, the loop variable is just
   appended to the parameters in the call. The following example prints a list of pair numbers
   between 2 and 10:

   @code
      times( [2:11:2],     // range 2 to 10+1, with step 2
         0,                // instruct times to add the loop index to the calls
         .[ .[ printl "Index is now..." ] ]      // the calls (just 1).
         )
   @endcode

   If it's a positive number, then the nth element of the Sigmas in the list will be
   changed. In this last case, the items in @b sequence need not just to be callable; they
   must be Sigmas (lists starting with a callable item) having at least enough items for
   the @b var ID to be meaningful. The next example alters the parameter element #2 in the
   Sigmas array it calls:

   @code
      times( [2:11:2], 2,
         .[ .[ printl "Index is now... "
                 nil
                 " ..." ] ]
         )
   @endcode

   Notice the "nil" at position 2 in the Sigma call of printl. It may actually be any item, as it will be
   changed each time before the sigma is called.

   In this case, if the callable items in @b sequence are not sigmas, or if they are to short for the
   @b var ID to be useful, they get called without the addition of the loop index parameter.

   @note The original sigmas are not restored after @b times is executed in this modality. This means that the
   arrays in @b sequence will be altered, and they will hold the last number set by @b times before exit.

   Exactly like @a floop, the flow of calls in @b times can be altered by the functions in sequence returning
   an out-of-band 0 or 1. If any function in the sequence returns an out-of-band 0, @b times terminates and
   return immediately (performing an operation similar to "break"). If a function returns an out-of-band 1,
   the rest of the items in @b sequence are ignored, and the loop is restarted with the index updated; this
   is equivalent to a functional "continue". In example:

   @code
   times( 10, 0,
      .[ (function(x); if x < 5: return oob(1); end)   // skip numbers less than 5
         printl // print the others
       ]
    )
   @endcode

   The @b times function return the last generated value for the index. A natural termination of @b times
   can be detected thanks to the fact that the index is equal to the upper bound of the range, while
   an anticipated termination causes @b times to return a different index. In example, if @b count is
   10, the generated index (possibly received by the items in @b sequence) will range from 0 to 9 included,
   and if the function terminates correctly, it will return 10. If a function in @b sequence returns an
   out-of-band 0, causing a premature termination of the loop, the value returned by times will be the loop
   index at which the out-of-band 0 was returned.

   @note Ranges [m:n] where m > n (down-ranges) terminate at n included; in that case, a succesful
   completion of @b times return one-past n.
*/
FALCON_FUNC  core_times ( ::Falcon::VMachine *vm )
{
   Item *i_count = vm->param(0);
   Item *i_var = vm->param(1);
   Item *i_sequence = vm->param(2);

   if( i_count == 0 || ! ( i_count->isRange() || i_count->isOrdinal() ) ||
       i_var == 0 || ! ( vm->isParamByRef( 1 ) || i_var->isNil() || i_var->isOrdinal() ) ||
       i_sequence == 0 || ! i_sequence->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "N|R, $|Nil|N, A" ) ) );
      return;
   }

   CoreArray *origin = i_sequence->asArray();
   int32 start, end, step;
   if( i_count->isRange() )
   {
      if ( i_count->asRangeIsOpen() )
      {
         vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
            extra( "open range" ) ) );
         return;
      }

      start = i_count->asRangeStart();
      end = i_count->asRangeEnd();
      step = i_count->asRangeStep();
      if ( step == 0 ) step = start > end ? -1 : 1;
   }
   else {
      start = 0;
      end = (int32) i_count->forceInteger();
      step = end < 0 ? -1 : 1;
   }

   CoreArray *sequence = i_sequence->asArray();

   // check ranges and steps.
   if ( start == end ||
        ( start < end && ( step < 0 || start + step > end ) ) ||
        ( start > end && ( step > 0 || start + step < end ) ) ||
        sequence->length() == 0
    )
   {
      // no loop to be done.
      vm->retval( (int64) start );
      return;
   }

   // ok, we must do at least a loop
   vm->returnHandler( core_times_next );

   // 1: shifting range
   // 2: position in the sequence calls.
   vm->addLocals( 2 );
   // count
   vm->local(0)->setRange( start, end, step, false);
   *vm->local(1) = (int64) 0;

   // prevent dirty A to mess our break/continue system.
   vm->regA().setNil();

   // eventually, set the initial count
   if ( vm->isParamByRef( 1 ) )
   {
      *i_var = (int64) start;
   }

   // ready; now the VM will call core_times_next
}

static bool core_xmap_next( ::Falcon::VMachine *vm )
{
   // in vm->param(0) there is "callable".
   CoreArray *origin = vm->param(1)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();
   CoreArray *mapped = vm->local(1)->asArray();


   if ( count < origin->length() )
   {
      if ( vm->local(2)->asInteger() == 1 )
      {
         if ( ! vm->regA().isOob() )
            mapped->append( vm->regA() );

         // prepare for next loop
         *vm->local(0) = (int64) count + 1;
         *vm->local(2) = (int64) 0;
         if ( vm->functionalEval( origin->at(count) ) )
         {
            return true;
         }
      }

      *vm->local(2) = (int64) 1;
      vm->pushParameter( vm->regA() );
      vm->callFrame( *vm->param(0), 1 );
      return true;
   }
   else {
      if ( ! vm->regA().isOob() )
            mapped->append( vm->regA() );
   }

   vm->retval( mapped );
   return false;
}

/*#
   @function xmap
   @inset functional_support
   @brief Creates a new vector of items transforming each item in the original array through the mapping function, applying also filtering on undesired items.
   @param mfunc A function or sigma used to map the array.
   @param sequence A sequence to be mapped.
   @return The mapped sequence.

   @b mfunc is called iteratively for every item in the collection;  its return value is added to
   the mapped array. Moreover, each item in the collection is functionally evaluated before
   being passed to mfunc.

   The filter function may return an out of band nil item to signal that the current item should
   not be added to the final collection.

    In example:
   @code
      
      mapper = lambda item => (item < 0 ? oob(nil) : item ** 0.5)
      add = lambda a, b => a+b         // a lambda that will be evaluated

      inspect( xmap( mapper, [ [add, 99, 1], 4, -12, 9 ]) )    // returns [10, 2, 3]
   @endcode

   @see oob
   @see dolist
*/

FALCON_FUNC  core_xmap ( ::Falcon::VMachine *vm )
{
   Item *callable = vm->param(0);
   Item *i_origin = vm->param(1);
   if( callable == 0 || !callable->isCallable() ||
       i_origin == 0 || !i_origin->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "C,A" ) ) );
      return;
   }

   CoreArray *origin = i_origin->asArray();
   CoreArray *mapped = new CoreArray( vm, origin->length() );
   if ( origin->length() > 0 )
   {
      vm->returnHandler( core_xmap_next );
      vm->addLocals( 3 );
      *vm->local(0) = (int64)1;
      *vm->local(1) = mapped;
      *vm->local(2) = (int64) 0;

      if ( vm->functionalEval( origin->at(0) ) )
      {
         return;
      }

      *vm->local(2) = (int64) 1;
      vm->pushParameter( vm->regA() );
      vm->callFrame( *vm->param(0), 1 );
      return;
   }

   vm->retval( mapped );
}

static bool core_filter_next ( ::Falcon::VMachine *vm )
{
   CoreArray *origin = vm->param(1)->asArray();
   CoreArray *mapped = vm->local(0)->asArray();
   uint32 count = (uint32) vm->local(1)->asInteger();

   if ( vm->regA().isTrue() )
      mapped->append( origin->at(count -1) );

   if( count == origin->length()  )
   {
      vm->retval( mapped );
      return false;
   }

   *vm->local(1) = (int64) count+1;
   vm->pushParameter( origin->at(count) );
   vm->callFrame( *vm->param(0), 1 );
   return true;
}


/*#
   @function filter
   @inset functional_support
   @brief Filters sequence using a filter function.
   @param ffunc A callable item used to filter the array.
   @param sequence A sequence of arbitrary items.
   @return The filtered sequence.

   ffunc is called iteratively for every item in the collection, which is passed as a parameter to it.
   If the call returns true, the item is added to the returned array; if it returns false,
   the item is not added.

   Items in the collection are treated literally (not evaluated).
*/

FALCON_FUNC  core_filter ( ::Falcon::VMachine *vm )
{
   Item *callable = vm->param(0);
   Item *i_origin = vm->param(1);
   if( callable == 0 || !callable->isCallable() ||
      i_origin == 0 || !i_origin->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "C,A" ) ) );
      return;
   }

   CoreArray *origin = i_origin->asArray();
   CoreArray *mapped = new CoreArray( vm, origin->length() / 2 );
   if( origin->length() > 0 )
   {
      vm->returnHandler( core_filter_next );
      vm->addLocals(2);
      *vm->local(0) = mapped;
      *vm->local(1) = (int64) 1;
      vm->pushParameter( origin->at(0) );
      vm->callFrame( *vm->param(0), 1 );
      return;
   }

   vm->retval( mapped );
}


static bool core_reduce_next ( ::Falcon::VMachine *vm )
{
   // Callable in param 0
   CoreArray *origin = vm->param(1)->asArray();

   // if we had enough calls, return (the return value of the last call frame is
   // already what we want to return).
   uint32 count = (uint32) vm->local(0)->asInteger();
   if( count >= origin->length() )
      return false;

   // increment count for next call
   vm->local(0)->setInteger( count + 1 );

   // call next item
   vm->pushParameter( vm->regA() ); // last returned value
   vm->pushParameter( origin->at(count) ); // next element
   vm->callFrame( *vm->param(0), 2 );
   return true;
}

/*#
   @function reduce
   @inset functional_support
   @brief Uses the values in a given sequence and iteratively calls a reductor function to extract a single result.
   @param reductor A function or Sigma to reduce the array.
   @param sequence A sequence of arbitrary items.
   @optparam initial_value Optional startup value for the reduction.
   @return The reduced result.

   The reductor is a function receiving two values as parameters. The first value is the
   previous value returned by the reductor, while the second one is an item iteratively
   taken from the origin array. If a startup value is given, the first time the reductor
   is called that value is provided as its first parameter, otherwise the first two items
   from the array are used in the first call. If the collection is empty, the initial_value
   is returned instead, and if is not given, nil is returned. If a startup value is not given
   and the collection contains only one element, that element is returned.

   Some examples:
   @code
   > reduce( lambda a,b=> a+b, [1,2,3,4])       // sums 1 + 2 + 3 + 4 = 10
   > reduce( lambda a,b=> a+b, [1,2,3,4], -1 )  // sums -1 + 1 + 2 + 3 + 4 = 9
   > reduce( lambda a,b=> a+b, [1] )            // never calls lambda, returns 1
   > reduce( lambda a,b=> a+b, [], 0 )          // never calls lambda, returns 0
   > reduce( lambda a,b=> a+b, [] )             // never calls lambda, returns Nil
   @endcode

   Items in the collection are treated literally (not evaluated).
*/
FALCON_FUNC  core_reduce ( ::Falcon::VMachine *vm )
{
   Item *callable = vm->param(0);
   Item *i_origin = vm->param(1);
   Item *init = vm->param(2);
   if( callable == 0 || !callable->isCallable()||
      i_origin == 0 || !i_origin->isArray()
      )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "C,A,[X]" ) ) );
      return;
   }

   CoreArray *origin = i_origin->asArray();
   vm->addLocals(1);
   // local 0: array position

   if ( init != 0 )
   {
      if( origin->length() == 0 )
      {
         vm->retval( *init );
         return;
      }

      vm->returnHandler( core_reduce_next );
      vm->pushParameter( *init );
      vm->pushParameter( origin->at(0) );
      *vm->local(0) = (int64) 1;

      //WARNING: never use pre-cached item pointers after stack changes.
      vm->callFrame( *vm->param(0), 2 );
      return;
   }

   // if init == 0; if there is only one element in the array, return it.
   if ( origin->length() == 0 )
      vm->retnil();
   else if ( origin->length() == 1 )
      vm->retval( origin->at(0) );
   else
   {
      vm->returnHandler( core_reduce_next );
      *vm->local(0) = (int64) 2; // we'll start from 2

      // the first call is between the first and the second elements in the array.
      vm->pushParameter( origin->at(0) );
      vm->pushParameter( origin->at(1) );

      //WARNING: never use pre-cached item pointers after stack changes.
      vm->callFrame( *vm->param(0), 2 );
   }
}


static bool core_iff_next( ::Falcon::VMachine *vm )
{
   // anyhow, we don't want to be called anymore
   vm->returnHandler( 0 );

   if ( vm->regA().isTrue() )
   {
      if ( vm->functionalEval( *vm->param(1) ) )
         return true;
   }
   else
   {
      Item *i_ifFalse = vm->param(2);
      if ( i_ifFalse != 0 )
      {
         if ( vm->functionalEval( *i_ifFalse ) )
            return true;
      }
      else
         vm->retnil();
   }

   return false;
}


/*#
   @function iff
   @inset functional_support
   @brief Performs a functional if; if the first parameter evaluates to true, the second parameter is evaluated and then returned, else the third one is evaluated and returned.
   @param cfr A condition or a callable item.
   @param whenTrue Value to be called and/or returned in case cfr evaluates to true.
   @optparam whenFalse Value to be called and/or returned in case cfr evaluates to false.
   @return The evaluation result of one of the two branches (or nil).

   Basically, this function is meant to return the second parameter or the third (or nil if not given),
   depending on the value of the first parameter; however, every item is evaluated in a functional
   context. This means that cfr may be a callable item, in which case its return value will be evaluated
   for truthfulness, and also the other parameters may. In example:
   @code
      > iff( 0, "was true", "was false" )           // will print “was false”
      iff( [lambda a=>a*2, 1] , [printl, "ok!"] )   // will print “ok!” and return nil
   @endcode

   In the last example, we are not interested in the return value (printl returns nil), but in executing
   that item only in case the first item is true. The first item is a callable item too, so iff will first
   execute the given lambda, finding a result of 2 (true), and then will decide which element to pick, and
   eventually execute. Notice that:
   @code
      iff( 1 , printl( "ok!" ), printl( "no" ) )
   @endcode
   
   This would have forced Falcon to execute the two printl calls before entering the iff function;
   still, iff would have returned printl return values (which is nil in both cases).
*/
FALCON_FUNC  core_iff ( ::Falcon::VMachine *vm )
{
   Item *i_cond = vm->param(0);
   Item *i_ifTrue = vm->param(1);
   Item *i_ifFalse = vm->param(2);

   if( i_cond == 0 || i_ifTrue == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X,X,[X]" ) ) );
      return;
   }

   // we can use pre-fetched values as we have stack unchanged on
   // paths where we use item pointers.

   vm->returnHandler( core_iff_next );
   if ( vm->functionalEval( *i_cond ) )
   {
      return;
   }
   vm->returnHandler( 0 );

   if ( vm->regA().isTrue() )
   {
      vm->functionalEval( *i_ifTrue );
   }
   else {
      if ( i_ifFalse != 0 )
         vm->functionalEval( *i_ifFalse );
      else
         vm->retnil();
   }
}


static bool core_choice_next( ::Falcon::VMachine *vm )
{
   if ( vm->regA().isTrue() )
   {
      vm->retval( *vm->param(1) );
   }
   else {
      Item *i_ifFalse = vm->param(2);
      if ( i_ifFalse != 0 )
         vm->retval( *i_ifFalse );
      else
         vm->retnil();
   }

   return false;
}

/*#
   @function choice
   @inset functional_support
   @brief Selects one of two alternatives depending on the evaluation of the first parameter.
   @param selector The item to be evaluated.
   @param whenTrue The item to return if selector evaluates to true.
   @optparam whenFalse The item to be returned if selector evaluates to false
   @optparam ... Optional parameters to be passed to the first callable item.
   @return The return value of the last callable item.

   The selector parameter is evaluated in functional context. If it's a true atom or if it's a
   callable array which returns a true value, the ifTrue parameter is returned as-is, else the
   ifFalse parameter is returned. If the ifFalse parameter is not given and the selector evaluates
   to false, nil is returned.

   The choice function is equivalent to iff where each branch is passed through the @a lit function:
   @code
      choice( selector, a, b ) == iff( selector, [lit, a], [lit, b] )
   @endcode
   In case a literal value is needed, choice is more efficient than using iff and applying lit on
   the parameters.
*/
FALCON_FUNC  core_choice ( ::Falcon::VMachine *vm )
{
   Item *i_cond = vm->param(0);
   Item *i_ifTrue = vm->param(1);
   Item *i_ifFalse = vm->param(2);

   if( i_cond == 0 || i_ifTrue == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X,X,[X]" ) ) );
      return;
   }

   vm->returnHandler( core_choice_next );
   if ( vm->functionalEval( *i_cond ) )
   {
      return;
   }
   vm->returnHandler( 0 );

   if ( vm->regA().isTrue() )
   {
      vm->retval( *i_ifTrue );
   }
   else {
      if ( i_ifFalse != 0 )
         vm->retval( *i_ifFalse );
      else
         vm->retnil();
   }
}

/*#
   @function lit
   @inset functional_support
   @brief Return its parameter as-is
   @param item A condition or a callable item.
   @return The parameter unevaluated.

   This function is meant to interrupt functional evaluation of lists. It has
   the same meaning of the single quote literal ' operator of the LISP language.

   In example, the following code will return either a callable instance of printl,
   which prints a “prompt” before the parameter, or a callable instance of inspect:
   @code
      iff( a > 0, [lit, [printl, "val: "] ], inspect)( param )
   @endcode
   as inspect is a callable token, but not an evaluable one, it is already returned literally;
   however, [printl, “val:”] would be considered an evaluable item. To take its literal
   value and prevent evaluation in functional context, the lit construct must be used.
*/

FALCON_FUNC  core_lit ( ::Falcon::VMachine *vm )
{
   Item *i_cond = vm->param(0);

   if( i_cond == 0 )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X" ) ) );
      return;
   }

   vm->regA() = *i_cond;
   // result already in A.
}


static bool core_cascade_next ( ::Falcon::VMachine *vm )
{
   // Param 0: callables array
   // local 0: counter (position)
   // local 1: last accepted result
   CoreArray *callables = vm->param(0)->asArray();
   uint32 count = (uint32) vm->local(0)->asInteger();

   // Done?
   if ( count >= callables->length() )
   {
      // if the last result is not accepted, return last accepted
      if ( vm->regA().isOob() )
      {
         // reset OOB, that may be set on first unaccepted parameter.
         vm->local(1)->resetOob();
         vm->retval( *vm->local(1) );
      }
      // else, just keep
      return false;
   }

   uint32 pc;

   // still some loop to do
   // accept result?
   if ( vm->regA().isOob() )
   {
      // not accepted.

      // has at least one parameter been accepted?
      if ( vm->local(1)->isOob() )
      {
         // no? -- replay initial params
         pc = vm->paramCount();
         for ( uint32 pi = 1; pi < pc; pi++ )
         {
            vm->pushParameter( *vm->param(pi) );
         }
         pc--;  //first param is our callable
      }
      else {
         // yes? -- reuse last accepted parameter
         pc = 1;
         vm->pushParameter( *vm->local(1) );
      }
   }
   else {
      *vm->local(1) = vm->regA();
      pc = 1;
      vm->pushParameter( vm->regA() );
   }

   // prepare next call
   vm->local(0)->setInteger( count + 1 );

   // perform call
   if ( ! vm->callFrame( callables->at(count), pc ) )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_non_callable ) ) );
      return false;
   }

   return true;
}

/*#
   @function cascade
   @inset functional_support
   @brief Concatenate a set of callable items so to form a single execution unit.
   @param callList Sequence of callable items.
   @optparam ... Optional parameters to be passed to the first callable item.
   @return The return value of the last callable item.

   This function executes a set of callable items passing the parameters it receives
   beyond the first one to the first  item in the list; from there on, the return value
   of the previous call is fed as the sole parameter of the next call. In other words,
   @code
      cascade( [F1, F2, ..., FN], p1, p2, ..., pn )
   @endcode
   is equivalent to
   @code
      FN( ... F2( F1( p1, p2, ..., pn ) ) ... )
   @endcode

   A function may declare itself “uninterested” to insert its value in the cascade
   by returning an out-of-band item. In that case, the return value is ignored and the same parameter
   it received is passed on to the next calls and eventually returned.

   Notice that the call list is not evaluated in functional context; it is just a list
   of callable items. To evaluate the list, or part of it, in functional context, use
   the eval() function.

   A simple example usage is the following:
   @code
      function square( a )
         return a * a
      end

      function sqrt( a )
         return a ** 0.5
      end

      cascade_abs = [cascade, [square, sqrt] ]
      > cascade_abs( 2 )      // 2
      > cascade_abs( -4 )     // 4
   @endcode

   Thanks to the possibility to prevent insertion of the return value in the function call sequence,
   it is possible to program “interceptors” that will catch the progress of the sequence without
   interfering:

   @code
      function showprog( v )
         > "Result currently ", v
        return oob(nil)
      end

      // define sqrt and square as before...
      cascade_abs = [cascade, [square, showprog, sqrt, showprog] ]
      > "First process: ", cascade_abs( 2 )
      > "Second process: ", cascade_abs( -4 )
   @endcode

   If the first function of the list declines processing by returning an oob item, the initial parameters
   are all passed to the second function, and so on till the last call.

   In example:

   @code
      function whichparams( a, b )
         > "Called with ", a, " and ", b
         return oob(nil)
      end

      csq = [cascade, [ whichparams, lambda a,b=> a*b] ]
      > csq( 3, 4 )
   @endcode

   Here, the first function in the list intercepts the parameters but, as it doesn't
   accepts them, they are both passed to the second in the list.
   
   @see oob
*/
FALCON_FUNC  core_cascade ( ::Falcon::VMachine *vm )
{
   Item *i_callables = vm->param(0);

   if( i_callables == 0 || !i_callables->isArray() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "A,..." ) ) );
      return;
   }

   // for the first callable...
   CoreArray *callables = i_callables->asArray();
   if( callables->length() == 0 )
   {
      vm->retnil();
      return;
   }

   // we have at least one callable.
   // Prepare the local space
   // 0: array counter
   // 1: saved previous value
   // saved previous value is initialized to oob until
   // someone accepts the first parameters.
   vm->addLocals(2);
   vm->local(0)->setInteger( 1 );  // we'll start from 1
   vm->local(1)->setOob();

   // echo the parameters to the first call
   uint32 pcount = vm->paramCount();
   for ( uint32 pi = 1; pi < pcount; pi++ )
   {
      vm->pushParameter( *vm->param(pi) );
   }
   pcount--;

   // install the handler
   vm->returnHandler( core_cascade_next );

   // perform the real call
   if ( ! vm->callFrame( callables->at(0), pcount ) )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_non_callable ) ) );
   }
}


static bool core_floop_next ( ::Falcon::VMachine *vm )
{
   // Param 0: callables array
   CoreArray *callables = vm->param(0)->asArray();
   // local 0: counter (position)
   uint32 count = (uint32) vm->local(0)->asInteger();

   // next item.
   ++count;

   // still some loop to do
   if ( vm->regA().isInteger() && vm->regA().isOob() )
   {
      if ( vm->regA().asInteger() == 0 )
      {
         // we're done.
         vm->returnHandler( 0 ); // ensure we're not called after first loop
         vm->retnil();
         return false;
      }
      else if ( vm->regA().asInteger() == 1 )
      {
         // continue
         count = 0;
      }
   }

   if ( count >= callables->length() )
   {
      count = 0;
   }

   // save the count
   *vm->local(0) = (int64) count;
   // find a callable in the array
   if ( ! vm->callFrame( (*callables)[count], 0 ) )
   {
      // set the item as A and recall ourself for evaluation
      vm->regA() = (*callables)[count];
      vm->recallFrame();
      return true;
   }

   // else, just return true
   return true;
}

/*#
   @function floop
   @inset functional_support
   @brief Repeats indefinitely a list of operations.
   @param sequence A sequence of callable items that gets called one after another.

   Every item in @b sequence gets executed, one after another. When the last element is executed,
   the first one is called again, looping indefinitely.
   Any function in the sequence may interrupt the loop by returning an out-of-band 0;
   if a function returns an out of band 1, all the remaining items in the list are ignored
   and the loop starts again from the first item.

   Items in the array are not functionally evaluated.
*/

FALCON_FUNC  core_floop ( ::Falcon::VMachine *vm )
{
   Item *i_callables = vm->param(0);

   if( i_callables == 0 || !i_callables->isArray() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "A" ) ) );
      return;
   }

   // for the first callable...
   CoreArray *callables = i_callables->asArray();
   if( callables->length() == 0 )
   {
      return;
   }

   // we have at least one callable.
   // Prepare the local space
   // 0: array counter
   vm->addLocals(1);
   vm->local(0)->setInteger( callables->length() );  // we'll start from 0 from the first loop

   // install the handler
   vm->returnHandler( core_floop_next );

   // call it directly
   vm->regA().setNil(); // zero to avoid false signals to next handler
   vm->callFrameNow( core_floop_next );
}

/*#
   @function firstOf
   @inset functional_support
   @brief Returns the first non-false of its parameters.
   @param ... Any number of arbitrary parameters.
   @return The first non-false item.

   This function scans the paraters one at a time. Sigma evaluation is stopped,
   or in other words, every parameters is considered as-is, as if @a lit was used on each of them.
   The function returns the first parameter being non-false in a standard Falcon truth check.
   Nonzero numeric values, non empty strings, arrays and dictionaries and any object is considered true.

   If none of the parameters is true, of is none of the parameter is given, the function returns nil
   (which is considered  false).
*/
FALCON_FUNC  core_firstof ( ::Falcon::VMachine *vm )
{
   int count = 0;
   Item *i_elem = vm->param(0);
   while( i_elem != 0 )
   {
      if ( i_elem->isTrue() )
      {
         vm->retval( *i_elem );
         return;
      }
      i_elem = vm->param( ++count );
   }

   vm->retnil();
}

/*#
   @funset oob_support Out of band items support
   @brief Handle out of band items.

   Out-of-band items are normal items which can be tested for the out-of-band quality
   through the @a isoob function to perform special tasks. Some core and RTL functions can
   check for the item being out-of-band to take special decisions about the item, or to
   modify their behavior. In example, the @a map function drops the item (acting like @a filter ),
   if it is out-of-band.

   This feature is available also to scripts; functions accepting any kind of items from
   callbacks they are using to generate data may wish to receive special instructions
   through out of band data. In the next example, a data producer returns a set of items
   one at a time, and notifies the caller to switch to another producer via an out-of-band
   notification.

   @code
   function firstSeries()
      static: vals = [1, 2, 3, 4 ]
      if vals: return arrayHead( vals )
      // notify the next function
      return oob( secondSeries )
   end

   function secondSeries()
      static: vals = [ "a", nil, "b", 4 ]
      if vals: return arrayHead( vals )
      // notify we're done with an nil OOB
      return oob()
   end

   function consumer( producer )
      loop item = producer()
         if isoob( item )
            // An OOB means we have something special. If it's nil, we're done...
            if item == nil: return
            // else it's the notification of a new producer
            producer = item
         else
            // if it's not an OOB, then we must process it
            > "Received item: ", item
         end
      end
   end

   consumer( firstSeries )
   @endcode

   Marking an item as out-of-band allows the creation of @i monads in functional evaluations.
   More automatism will be introduced in future, but scripters can have monads by assigning the
   oob status to complex objects and perform out-of-band processing on them.
*/

/*#
   @function oob
   @brief Generates an out-of-band item.
   @ingroup general_purpose
   @inset oob_support
   @optparam item The item to be declared out of band.
   @return An oob version of the item, or an oob @b nil if no item is given.

   This function returns an out-of-band nil item, or if a parameter is given,
   an out-of-band version of that item.
*/
FALCON_FUNC  core_oob( ::Falcon::VMachine *vm )
{
   Item *obbed = vm->param(0);
   if ( ! obbed )
   {
      vm->regA().setNil();
   }
   else {
      vm->regA() = *obbed;
   }

   vm->regA().setOob();
}


/*#
   @function deoob
   @brief Turns an out-of-band item in a normal item.
   @ingroup general_purpose
   @inset oob_support
   @param item The out of band item to be turned into a normal item.
   @return An the non-out-of-band version version of the item.

   The function returns a flat copy of the item without the out-of-band status set.
   If the item was initially not OOB, then deoob() does nothing.
   See @a oob for a deeper explanation of OOB items.
*/
FALCON_FUNC  core_deoob( ::Falcon::VMachine *vm )
{
   Item *obbed = vm->param(0);
   if ( ! obbed )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X" ) ) );
      return;
   }

   vm->regA() = *obbed;
   vm->regA().resetOob();
}

/*#
   @function isoob
   @brief Checks for the out-of-band status of an item.
   @ingroup general_purpose
   @inset oob_support
   @param item The item to be checked.
   @return True if the item is out of band, false otherwise.

   This function can be used to check if a certain item is an out of band item.
*/
FALCON_FUNC  core_isoob( ::Falcon::VMachine *vm )
{
   Item *obbed = vm->param(0);
   if ( ! obbed )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "X" ) ) );
      return;
   }

   vm->retval( (int64) (obbed->isOob() ? 1 : 0 ) );
}

// =================================================
// Attribute support
//


/*#
   @function having
   @inset attrib_model
   @brief Returns an array containing all the items having a certain attribute.
   @param attrib The attribute that will be inspected
   @return An array with all the items currently having that attribute.

   If the attribute isn't currently given to any item, this function will return an
   empty array. Notice that it is not strictly necessary to call having function
   just to iterate over the items i.e. in a for/in loop, as attributes
   can be directly iterated:

   @code
   attributes: opened
   //....
   for item in opened
      > "Item ", item.name, " has opened"
   end
   @endcode

   Also, attributes support iterators; an Iterator instance can be built passing an attribute
   as the parameter of the constructor, and first() BOM method can be called on an
   attribute to create an iterator which can be used to inspect all the objects having
   a certain attribute.

   However, having function is still useful when a snapshot of the items currently having
   a certain attribute is needed. In example, it is possible to save in a variable the array,
   change the status of some objects by removing the attribute from them and finally re-giving
   the attribute.
*/
FALCON_FUNC  having( ::Falcon::VMachine *vm )
{
   Item *itm = vm->param( 0 );
   if ( ! itm->isAttribute() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "a" ) ) );
      return;
   }

   Attribute *attrib = itm->asAttribute();
   AttribObjectHandler *head = attrib->head();
   CoreArray *arr = new CoreArray( vm );
   while( head != 0 )
   {
      arr->append( head->object() );
      head = head->next();
   }

   vm->retval( arr );
}

/*#
   @function giveTo
   @inset attrib_model
   @brief Gives a certain attribute to a certain object.
   @param attrib The attribute to be given
   @param obj The object that will receive the attribute

   This function is equivalent to the @b give statement, and is provided to allow
   functional processing of attributes. In example:

   @code
   attributes: opened
   dolist( [giveTo, opened], [obj1, obj2, obj3] )
   @endcode

   If the target object had already the attribute, nothing is done.
   If the first parameter is not an attribute or the second parameter is not an
   object, a ParamError is rasied.
   
   @see dolist
*/
FALCON_FUNC  giveTo( ::Falcon::VMachine *vm )
{
   Item *i_attrib = vm->param( 0 );
   Item *i_obj = vm->param( 1 );

   if ( i_attrib == 0 || ! i_attrib->isAttribute() ||
        i_obj == 0 || ! i_obj->isObject() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "a,X" ) ) );
      return;
   }

   vm->retval( (int64) (i_attrib->asAttribute()->giveTo( i_obj->asObject() ) ? 1 : 0) );
}


/*#
   @function removeFrom
   @inset attrib_model
   @brief Removes a certain attribute from a certain object.
   @param attrib The attribute to be removed
   @param obj The object from which the attribute must be removed

   This function is equivalent to the give statement using to remove
   an attribute, and is provided to allow functional processing of
   attributes. In example:

   @code
   attributes: opened
   dolist( [removeFrom, opened], [obj1, obj2, obj3] )
   @endcode

   If the target object didn't have the attribute, nothing is done.
   If the first parameter is not an attribute or the second parameter
   is not an object, a ParamError is rasied.
*/

FALCON_FUNC  removeFrom( ::Falcon::VMachine *vm )
{
   Item *i_attrib = vm->param( 0 );
   Item *i_obj = vm->param( 1 );

   if ( i_attrib == 0 || ! i_attrib->isAttribute() ||
        i_obj == 0 || ! i_obj->isObject() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "a,X" ) ) );
      return;
   }

   vm->retval( (int64) (i_attrib->asAttribute()->removeFrom( i_obj->asObject() ) ? 1 : 0) );
}

/*#
   @function removeFromAll
   @inset attrib_model
   @brief Removes a certain attribute from all the objects currently having it.
   @param attrib The attribute to be removed

   After this function is called, the target attribute will not be
   found in any object anymore.
*/

FALCON_FUNC  removeFromAll( ::Falcon::VMachine *vm )
{
   Item *i_attrib = vm->param( 0 );

   if ( i_attrib == 0 || ! i_attrib->isAttribute() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "a" ) ) );
      return;
   }

   i_attrib->asAttribute()->removeFromAll();
}


static bool broadcast_next_attrib_next( ::Falcon::VMachine *vm )
{
   // break the chain if last call returned true or an OOB item
   if ( vm->regA().isOob() || vm->regA().isTrue() )
   {
      return false;
   }

   AttribObjectHandler *ho= (AttribObjectHandler *) vm->local(0)->asUserPointer();
   while ( ho != 0 )
   {
      CoreObject *obj = ho->object();
      // we want a copy anyhow...
      Item callable;
      obj->getProperty( vm->param(0)->asAttribute()->name(), callable );
      if ( callable.isCallable() )
      {
         // prepare our next frame
         vm->local(0)->setUserPointer( ho->next() );

         // great, we found an object willing to be called
         // prepare the stack;
         uint32 pc = vm->paramCount();
         for( uint32 i = 1; i < pc; i ++ )
         {
            vm->pushParameter( *vm->param( i ) );
         }
         callable.methodize( obj );
         vm->callFrame( callable, pc - 1 );
         return true;
      }
      ho = ho->next();
   }

   // we're done, return false
   return false;
}

FALCON_FUNC broadcast_next_attrib( ::Falcon::VMachine *vm )
{
   Attribute *attrib = vm->param(0)->asAttribute();

   // prevent making the frame (and calling) if empty
   if ( attrib->empty() )
      return;

   // signal we'll be using an attribute
   vm->addLocals( 1 );
   vm->local(0)->setUserPointer( attrib->head() );
   // fake a return true
   vm->retval( false );
   vm->returnHandler( broadcast_next_attrib_next );
}

static bool broadcast_next_array( ::Falcon::VMachine *vm )
{
   // break chain if last call returned true
   if ( vm->regA().isOob() || vm->regA().isTrue() )
   {
      return false;
   }

   // select next item in the array.
   Item *callback = 0;
   uint32 pos = (uint32) vm->local(0)->asInteger();
   CoreArray *aarr = vm->param(0)->asArray();

   // time to scan for a new attribute
   if ( pos >= aarr->length() )
   {
      // we're done
      vm->retnil();
      return false;
   }

   // is it REALLY an attribute?
   const Item &attrib = aarr->at(pos);
   if ( ! attrib.isAttribute() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_param_type ).extra( "not an attribute" ) ) );
      return false;
   }

   // save next pos
   vm->local(0)->setInteger( pos + 1 );

   // select next item in the array
   vm->pushParameter( attrib );

   // and append our parameters
   uint32 pc = vm->paramCount();
   for( uint32 i = 1; i < pc; i++)
   {
      vm->pushParameter( *vm->param(i) );
   }

   // we pre-cached our frame initializer (broadcast_next_attrib)
   vm->callFrame( *vm->local(1), pc );
   return true;

}

/*#
   @function broadcast
   @inset attrib_model
   @param signaling An attribute or an array of attributes to be broadcast.
   @param ... Zero or more data to be broadcaset.
   @return Value returned by a message handler or nil.
   @brief Send a message to every object having an attribute.

   This function iterates over all the items having a certain attribute; if those objects provide a method
   named exactly as the attribute, then that method is called. A method can declare that it has “consumed”
   the message (i.e. done what is expected to be done) by returning true. In this case, the call chain is
   interrupted and broadcast returns. A method not wishing to prevent other methods to receive the incoming
   message must return false. Returning true means “yes, I have handled this message,
   no further processing is needed”.

   It is also possible to have the caller of broadcast to receive a return value created by the handler;
   If the handler returns an out of band item (using @a oob) propagation of the message is stopped and
   the value is returned directly to the caller of the @b broadcast function.

   The order in which the objects receive the message is random; there isn't any priority across a single
   attribute message. For this reason, the second form of broadcast function is provided. To implement
   priority processing, it is possible to broadcast a sequence of attributes. In that case, all the
   objects having the first attribute will receive the message, and will have a chance to stop
   further processing, before any item having the second attribute is called and so on.

   The broadcast function can receive other parameters; in that case the remaining parameters are passed
   as-is to the handlers.

   Items having a certain attribute and receiving a broadcast over it need not to implement an handler.
   If they don't provide a method having the same name of the broadcast attribute, they are simply
   skipped. The same happens if they provide a property which is not callable; setting an handler to
   a non-callable item is a valid operation to disable temporarily message processing.

   An item may be called more than once in a single chained broadcast call if it has more than one of
   the attributes being broadcast and if it provides methods to handle the messages.

   It is possible to receive more than one broadcast in the same handler using the “same handler idiom”:
   setting a property to a method of the same item in the init block or in the property initialization.
   In example:

   @code
      attributes: attr_one, attr_two

      object handler
         attr_two = attr_one
         function attr_one( param )
            // do something
            return false
         end
         has attr_one, attr_two
      end
   @endcode
*/

FALCON_FUNC  broadcast( ::Falcon::VMachine *vm )
{
   uint32 pcount = vm->paramCount();
   Item *i_attrib = vm->param( 0 );
   if ( ! i_attrib->isAttribute() && ! i_attrib->isArray() )
   {
      vm->raiseRTError( new ParamError( ErrorParam( e_inv_params ).
         extra( "a|A,..." ) ) );
      return;
   }

   if ( i_attrib->isAttribute() )
   {
      Attribute *attrib = i_attrib->asAttribute();
      // nothing to broadcast?
      if ( attrib->empty() )
         return;

      // signal we'll be using an attribute
      vm->addLocals( 1 );
      vm->local(0)->setUserPointer( attrib->head() );
      vm->returnHandler( broadcast_next_attrib_next );
   }
   else
   {
      // prevent overdoing for nothing
      if ( i_attrib->asArray()->length() == 0 )
         return;

      // add space for the tracer
      vm->addLocals( 2 );
      vm->local(0)->setInteger( 0 );
      // pre-cache our service function
      Item *bcast_func = vm->findWKI( "%broadcast_next_attrib" );
      fassert( bcast_func != 0 );
      *vm->local(1) = *bcast_func;

      // set A to true to force first execution
      vm->returnHandler( broadcast_next_array );
   }

   // force vm to start first loop
   vm->retval( false );
}


} // end of core namespace


/****************************************
   Module initializer
****************************************/

Module * core_module_init()
{
   Module *core = new Module();
   core->name( "falcon.core" );

   /*#
      @entity args
      @brief Script arguments
      @ingroup general_purpose

      A global variable holding an array that contains the strings passed as argument for
      the script. Embedders may change the convention, and pass any Falcon item as
      arguments; however, falcon command line and the other standard tools pass only
      an array of strings.
   */
   core->addGlobal( "args", true );

   /*#
      @entity scriptName
      @brief Logical module name of current module
      @ingroup general_purpose

      It's a global variable that is usually filled with the script name. It's the logical
      script name that the VM has assigned to this module, mainly used for debugging.
   */
   core->addGlobal( "scriptName", true );

   /*#
      @entity scriptPath
      @brief Complete path used to load the script
      @ingroup general_purpose

      It's a global variable that is usually filled with the location from which the script
      has been loaded. It's semantic may vary among embedding applications, but it should
      usually receive the complete path to the main script, in Falcon file convention
      (forward slashes to separate directories), or the complete URI where applicable.
   */
   core->addGlobal( "scriptPath", true );

   // we leave EQ undocumented for now.
   core->addExtFunc( "eq", Falcon::core::eq );
   core->addExtFunc( "len", Falcon::core::len );
   core->addExtFunc( "chr", Falcon::core::chr );
   core->addExtFunc( "ord", Falcon::core::ord );
   core->addExtFunc( "toString", Falcon::core::hToString );
   core->addExtFunc( "isCallable", Falcon::core::isCallable );
   core->addExtFunc( "getProperty", Falcon::core::getProperty );
   core->addExtFunc( "setProperty", Falcon::core::setProperty );

   core->addExtFunc( "yield", Falcon::core::yield );
   core->addExtFunc( "yieldOut", Falcon::core::yieldOut );
   core->addExtFunc( "sleep", Falcon::core::_f_sleep );
   core->addExtFunc( "beginCritical", Falcon::core::beginCritical );
   core->addExtFunc( "endCritical", Falcon::core::endCritical );
   core->addExtFunc( "suspend", Falcon::core::vmSuspend );

   core->addExtFunc( "int", Falcon::core::val_int );
   core->addExtFunc( "numeric", Falcon::core::val_numeric );
   core->addExtFunc( "typeOf", Falcon::core::typeOf );
   core->addExtFunc( "exit", Falcon::core::hexit );

   core->addExtFunc( "paramCount", Falcon::core::paramCount );
   core->addExtFunc( "paramNumber", Falcon::core::_parameter );
   core->addExtFunc( "parameter", Falcon::core::_parameter );
   core->addExtFunc( "paramIsRef", Falcon::core::paramIsRef );
   core->addExtFunc( "paramSet", Falcon::core::paramSet );
   core->addExtFunc( "PageDict", Falcon::core::PageDict );
   core->addExtFunc( "MemBuf", Falcon::core::Make_MemBuf );

   // ===================================
   // Attribute support
   //
   core->addExtFunc( "having", Falcon::core::having );
   core->addExtFunc( "giveTo", Falcon::core::giveTo );
   core->addExtFunc( "removeFrom", Falcon::core::removeFrom );
   core->addExtFunc( "removeFromAll", Falcon::core::removeFromAll );
   core->addExtFunc( "broadcast", Falcon::core::broadcast );
   core->addExtFunc( "%broadcast_next_attrib", Falcon::core::broadcast_next_attrib )->setWKS(true);

   // Creating the TraceStep class:
   // ... first the constructor
   /*Symbol *ts_init = core->addExtFunc( "TraceStep._init", Falcon::core::TraceStep_init );

   //... then the class
   Symbol *ts_class = core->addClass( "TraceStep", ts_init );

   // then add var props; flc_CLSYM_VAR is 0 and is linked correctly by the VM.
   core->addClassProperty( ts_class, "module" );
   core->addClassProperty( ts_class, "symbol" );
   core->addClassProperty( ts_class, "pc" );
   core->addClassProperty( ts_class, "line" );
   // ... finally add a method, using the symbol that this module returns.
   core->addClassMethod( ts_class, "toString",
      core->addExtFunc( "TraceStep.toString", Falcon::core::TraceStep_toString ) );*/

   // Creating the Error class class:
   Symbol *error_init = core->addExtFunc( "Error._init", Falcon::core::Error_init );
   Symbol *error_class = core->addClass( "Error", error_init );
   error_class->setWKS( true );

   core->addClassMethod( error_class, "toString",
         core->addExtFunc( "Error.toString", Falcon::core::Error_toString ) );
   core->addClassMethod( error_class, "heading", Falcon::core::Error_heading );

   // separated property description to test for separate @property faldoc command
   /*#
      @property code Error
      @brief Error code associated with this error.
   */

   core->addClassProperty( error_class, "code" );
   core->addClassProperty( error_class, "description" );
   core->addClassProperty( error_class, "message" );
   core->addClassProperty( error_class, "systemError" );

   /*#
       @property origin Error
       @brief String identifying the origin of the error.

      This code allows to determine  what element of the Falcon engine has raised the error
      (or eventually, if this error has been raised by a script or a loaded module).

      The error origin is a string; when an error gets displayed through a standard
      rendering function (as the Error.toString() method), it is indicated by two
      letters in front of the error code for better readability. The origin code may
      be one of the following:

      - @b compiler - (represented in Error.toString() as CO)
      - @b assembler - (AS)
      - @b loader -  that is, the module loader (LD)
      - @b vm - the virtual machine (when not running a script, short VM)
      - @b script - (that is, a VM running a script, short SS)
      - @b runtime - (core or runtime modules, RT)
      - @b module - an extension module (MD).
      -
   */

   core->addClassProperty( error_class, "origin" );
   core->addClassProperty( error_class, "module" );
   core->addClassProperty( error_class, "symbol" );
   core->addClassProperty( error_class, "line" );
   core->addClassProperty( error_class, "pc" );
   core->addClassProperty( error_class, "subErrors" );
   core->addClassMethod( error_class, "getSysErrorDesc", Falcon::core::Error_getSysErrDesc );

   // Other derived error classes.
   Falcon::Symbol *synerr_cls = core->addClass( "SyntaxError", Falcon::core::SyntaxError_init );
   synerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   synerr_cls->setWKS( true );

   Falcon::Symbol *codeerr_cls = core->addClass( "CodeError", Falcon::core::CodeError_init );
   codeerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   codeerr_cls->setWKS( true );

   Falcon::Symbol *rangeerr_cls = core->addClass( "AccessError", Falcon::core::AccessError_init );
   rangeerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   rangeerr_cls->setWKS( true );

   Falcon::Symbol *matherr_cls = core->addClass( "MathError", Falcon::core::MathError_init );
   matherr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   matherr_cls->setWKS( true );

   Falcon::Symbol *ioerr_cls = core->addClass( "IoError", Falcon::core::IoError_init );
   ioerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   ioerr_cls->setWKS( true );

   Falcon::Symbol *typeerr_cls = core->addClass( "TypeError", Falcon::core::TypeError_init );
   typeerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   typeerr_cls->setWKS( true );

   Falcon::Symbol *paramerr_cls = core->addClass( "ParamError", Falcon::core::ParamError_init );
   paramerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   paramerr_cls->setWKS( true );

   Falcon::Symbol *parsererr_cls = core->addClass( "ParseError", Falcon::core::ParseError_init );
   parsererr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   parsererr_cls->setWKS( true );

   Falcon::Symbol *cloneerr_cls = core->addClass( "CloneError", Falcon::core::CloneError_init );
   cloneerr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   cloneerr_cls->setWKS( true );

   Falcon::Symbol *interr_cls = core->addClass( "InterruptedError", Falcon::core::IntrruptedError_init );
   interr_cls->getClassDef()->addInheritance(  new Falcon::InheritDef( error_class ) );
   interr_cls->setWKS( true );
   //=========================================

   // Creating the semaphore class
   Symbol *semaphore_init = core->addExtFunc( "Semaphore._init", Falcon::core::Semaphore_init );
   Symbol *semaphore_class = core->addClass( "Semaphore", semaphore_init );

   core->addClassMethod( semaphore_class, "post",
            core->addExtFunc( "Semaphore.post", Falcon::core::Semaphore_post ) );
   core->addClassMethod( semaphore_class, "wait",
            core->addExtFunc( "Semaphore.wait", Falcon::core::Semaphore_wait ) );

   // GC support
   core->addExtFunc( "gcEnable", Falcon::core::gcEnable );
   core->addExtFunc( "gcSetThreshold", Falcon::core::gcSetThreshold );
   core->addExtFunc( "gcPerform", Falcon::core::gcPerform );
   core->addExtFunc( "gcSetTimeout", Falcon::core::gcSetTimeout );
   core->addExtFunc( "gcGetParams", Falcon::core::gcGetParams );

   // VM support
   core->addExtFunc( "vmVersionInfo", Falcon::core::vmVersionInfo );
   core->addExtFunc( "vmVersionName", Falcon::core::vmVersionName );
   core->addExtFunc( "vmSystemType", Falcon::core::vmSystemType );
   core->addExtFunc( "vmModuleVersionInfo", Falcon::core::vmModuleVersionInfo );

   // Format
   Symbol *format_class = core->addClass( "Format", Falcon::core::Format_init );
   core->addClassMethod( format_class, "format", Falcon::core::Format_format );
   core->addClassMethod( format_class, "parse", Falcon::core::Format_parse );
   core->addClassMethod( format_class, "toString", Falcon::core::Format_toString );
   core->addClassProperty( format_class,"size" );
   core->addClassProperty( format_class, "decimals" );
   core->addClassProperty( format_class, "paddingChr" );
   core->addClassProperty( format_class, "groupingChr" );
   core->addClassProperty( format_class, "decimalChr" );
   core->addClassProperty( format_class, "grouiping" );
   core->addClassProperty( format_class, "fixedSize" );
   core->addClassProperty( format_class, "rightAlign" );
   core->addClassProperty( format_class, "originalFormat" );
   core->addClassProperty( format_class, "misAct" );
   core->addClassProperty( format_class, "convType" );
   core->addClassProperty( format_class, "nilFormat" );
   core->addClassProperty( format_class, "negFormat" );
   core->addClassProperty( format_class, "numFormat" );

   // Iterators
   Symbol *iterator_class = core->addClass( "Iterator", Falcon::core::Iterator_init );
   iterator_class->setWKS( true );
   core->addClassMethod( iterator_class, "hasCurrent", Falcon::core::Iterator_hasCurrent );
   core->addClassMethod( iterator_class, "hasNext", Falcon::core::Iterator_hasNext );
   core->addClassMethod( iterator_class, "hasPrev", Falcon::core::Iterator_hasPrev );
   core->addClassMethod( iterator_class, "next", Falcon::core::Iterator_next );
   core->addClassMethod( iterator_class, "prev", Falcon::core::Iterator_prev );
   core->addClassMethod( iterator_class, "value", Falcon::core::Iterator_value );
   core->addClassMethod( iterator_class, "key", Falcon::core::Iterator_key );
   core->addClassMethod( iterator_class, "erase", Falcon::core::Iterator_erase );
   core->addClassMethod( iterator_class, "equal", Falcon::core::Iterator_equal );
   core->addClassMethod( iterator_class, "clone", Falcon::core::Iterator_clone );
   core->addClassMethod( iterator_class, "find", Falcon::core::Iterator_find );
   core->addClassMethod( iterator_class, "insert", Falcon::core::Iterator_insert );
   core->addClassMethod( iterator_class, "getOrigin", Falcon::core::Iterator_getOrigin );
   core->addClassProperty( iterator_class, "_origin" );
   core->addClassProperty( iterator_class, "_pos" );

   // ================================================
   // Functional extensions
   //

   //ETA functions
   core->addExtFunc( "all", Falcon::core::core_all )->setEta( true );
   core->addExtFunc( "any", Falcon::core::core_any )->setEta( true );
   core->addExtFunc( "allp", Falcon::core::core_allp )->setEta( true );
   core->addExtFunc( "anyp", Falcon::core::core_anyp )->setEta( true );
   core->addExtFunc( "eval", Falcon::core::core_eval )->setEta( true );
   core->addExtFunc( "choice", Falcon::core::core_choice )->setEta( true );
   core->addExtFunc( "xmap", Falcon::core::core_xmap )->setEta( true );
   core->addExtFunc( "iff", Falcon::core::core_iff )->setEta( true );
   core->addExtFunc( "lit", Falcon::core::core_lit )->setEta( true );
   core->addExtFunc( "cascade", Falcon::core::core_cascade )->setEta( true );
   core->addExtFunc( "dolist", Falcon::core::core_dolist )->setEta( true );
   core->addExtFunc( "floop", Falcon::core::core_floop )->setEta( true );
   core->addExtFunc( "firstOf", Falcon::core::core_firstof )->setEta( true );
   core->addExtFunc( "times", Falcon::core::core_times )->setEta( true );

   // other functions
   core->addExtFunc( "min", Falcon::core::core_min );
   core->addExtFunc( "max", Falcon::core::core_max );
   core->addExtFunc( "map", Falcon::core::core_map );
   core->addExtFunc( "filter", Falcon::core::core_filter );
   core->addExtFunc( "reduce", Falcon::core::core_reduce );

   core->addExtFunc( "oob", Falcon::core::core_oob );
   core->addExtFunc( "deoob", Falcon::core::core_deoob );
   core->addExtFunc( "isoob", Falcon::core::core_isoob );

   return core;
}

}

/* end of core_func.cpp */

Generated by  Doxygen 1.6.0   Back to index