Hacking on Iguana
=================

This document should help developers to find their way through Iguana's
architecture and source code: readers should not consider this document to 
be an exhaustive description. 


Design Principles
-----------------

(This aphorisms comes from the Python website, www.python.org, but they fits
PERFECTLY Iguana).

Each software project has it's own culture and style, it's own approach
to solving problems. Iguana tries to keep things simple and orthogonal
and to assist the user as much as possible. Follows some funny aphorisms:

  o  beautiful is better than ugly
  o  explicit is better than implicit
  o  simple is better than complex
  o  complex is better than complicated
  o  flat is better than nested
  o  special cases aren't special enough to break the rules
  o  errors should never pass silently
  o  unless explicitly silenced
  o  if the implementation is hard to explain, it's a bad idea
  o  if the implementation is easy to explain, it may be a good idea

don't take these aphorisms too seriously -- tattooing them on your
body is probably a bad idea, for example -- but it's instructive to
contemplate them: some parallels can be drawn to the guiding
principles of extreme programming, most notably the emphasis on ``do
the simplest thing that can possibly work''.

Another principle is ``correctness and clarity before speed''. Most of
the code in the Iguana interpreter and standard modules is written in
a very straight-forward style. I am not interested in making the interpreter
run faster at the expense of unreadable or hard-to-follow tricky code.

By all means, keep it is simple, straight-forward, and extensible.


Version Numbering
=================

Versions are denoted using a standard triplet of integers: MAJOR.MINOR.TEENY. 
The basic intent is that MAJOR versions are incompatible, large-scale upgrades 
of the API. MINOR versions retain source and binary compatibility with older 
minor versions, and changes in the TEENY level are perfectly compatible, 
forwards and backwards.

It is important to note that Iguana has not reached 1.0.0 version and is not
subject to the guidelines described in the previous section. Before a 1.0 
release (version 0.x.y), the API can and will be changing freely, without 
regard to the restrictions detailed above.


Release Strategy
----------------

This section details how we will build the code to meet the above requirements 
and guidelines.

  TEENY versions 
      To retain perfect source and binary compatibility, a teeny release can 
      only change function implementations or add new functions. Effectively, 
      these releases are pure bug fix releases. Add new syntax is correct.
      Ig_API_VERSION should not be changed.
 
  MINOR versions
      Minor releases can introduce new functions, new symbolic and enumerated 
      constants, and deprecate existing functions. Add new syntax is correct as
      well as deprecated function should be removed. 

  MAJOR versions
      Any kind of change can be made during a major version release. Particular
      types of changes that might occur:
         o  remove or change constants
         o  remove or rename API functions
         o  fold together macro-ized function replacements
         o  change syntax


Build Number
------------

Iguana has a "build number" scheme that isn't hard to explain:

Iguana 0.0.0-alpha0 (#6, Apr 7 2002, 02:40:55)
                      ^
                      the build number here is "6".

Each developer tree generates its own "build numbers", starting from 0, and
increasing by 1 each time a build is done in that tree. These numbers are
never checked in, or coordinated in any other way: it's just handy for a
developer to distinguish among their own personal builds.


Tools
=====

The Iguana developers needs some stuff that the end users don't:

  o  GNU autoconf 
  o  GNU bison (version 1.875 is required)
  o  GNU flex (version 2.5.4 is required)
  o  GNU make 3.80 or greater  
  o  GNU libtool 1.4.3 or greater
  o  other tools, including makedepend, indent, ctags, etags, etc.

Once you have this stuff, you can start working from your own machine. 
A known working combination for several platforms is GNU autoconf 2.57, 
GNU libtool 1.4.3 and GNU make 3.80. 


Makefile targets
----------------

Follow a list of useful Makefile targets for Iguana developers:

  config                  Rebuild configure and config.h.in
  recheck                 Rerun the configure script
  clean                   Deletes all object files
  clobber                 Deletes executables and libraries
  distclean               Deletes all files produced in the build
  parserclean             Deletes all files produced by bison and flex
  dep                     Build/Rebuild Makefile dependencies
  tags                    Create a tag file for vi
  TAGS                    Create a tag file for Emacs
  indent                  Call GNU indent for all source files (.c only)

                                                                              
Special Builds
--------------

This section describes some special Iguana build types enabled via
compile-time preprocessor defines.

If you want or need to change the optimization/debugging options for
the C compiler, assign to the OPT variable on the top-level make
command; e.g. `make OPT=-g' will build a debugging version of Iguana
on most platforms.  The default is OPT="-DIg_DEBUG -g2"; a value for
OPT in the environment when the configure script is run overrides
this default (likewise for CC; and the initial value for LIBS is used
as the base set of libraries to link with).

If you want C profiling turned on, the easiest way is to run configure
with the CC environment variable to the necessary compiler
invocation.  For example, on Linux, this works for profiling using
gprof(1):

    % make OPT=-pg

Other special Iguana build types enabled via compile-time preprocessor defines
are:

Ig_DEBUG
  this is what is generally meant by "a debug build" of the interpreter and 
  of the library.
  Ig_DEBUG implies Ig_WITH_ASSERT. 

Ig_WITH_ASSERT
  enable the Ig_ASSERT and Ig_ASSERT_NOT_REACHED macros.

Ig_WITH_PARSER_DEBUG
  turns on parser debug mode. Iguana will print a bunch of internal
  state messages during executing scripts. Not useful very often, but
  very useful when needed.


Debugging Iguana
----------------

See Misc/gdbinit for some useful GNU gdb hooks. It was tested only with 
GNU gdb 5.3. 

Try also `iguana -v' or even `iguana -v -v'.


Notes for Volunteers
====================

- Make sure you are allowed to release code under the GPL. It may be
  necessary to get a written disclaimer from your employer to confirm
  it. You don't need to assign copyright to us, but you need to check
  that you are allowed to release GPL software -- otherwise the work
  will be wasted.

- Tell to Davide Angelocola <davide.angelocola@tiscali.it> what you plan 
  to do, just to make sure nobody else starts on it.

- Code goes into Iguana when it is well-tested and has documentation.


Making patches 
--------------

The diff command with the -ruN options compares two file subtrees and creates 
a patch file that lists the differences between the subtrees. We'll show on a
specific example how to interpret the patch file produced by diff.

SCENARIO: we are interested in checking the differences between the 0.1.0 and 
the 0.1.1 file subtrees. First we must issue a:

    % make distclean

command in both directories to remove all non-text files. Now we are
ready to issue the following command:

    % diff -ruN Iguana-0.1.0 Iguana-0.1.1 > patch-0.1.1

COMMAND EXECUTION: since the -r recursive option is set, diff examines all
directories and files in the two Iguana subtrees. The -N option specifies 
that if a file is present in a directory, it must be considered as present, 
although empty, in the corresponding directory. The -u option specifies that 
the unified output format is used. 


Documenting Iguana
------------------

Iguana must be well documented. A feature that isn't documented is a
useless feature. A patch for a new feature must include the a comprehensive
and understandable documentation and using examples is recommended. Document
your modules and method with the Ig_DOC() macro.  


Object oriented programming in C
================================

Overview
--------

Most Iguana C API functions have one or more arguments as well as a
return value of a pointer to IgObject. This type is a pointer to an opaque
data type representing an arbitrary object. Since all Iguana object types are 
treated the same way by the Iguana language in most situations (e.g., 
assignments, transforming, and argument passing), it is only fitting that 
they should be represented by a single C type. Almost all Iguana objects live 
on the heap: you never declare an automatic or static variable of type 
IgObject, only pointer variables of type IgObject* can be declared. The sole 
exception are the type objects, since these must never be deallocated, and
boolean object (True and False), and the None object.

All Iguana objects (even Iguana modules) have a type and a reference count. 
An object's type determines what kind of object it is (e.g., an integer, a 
tuple, a method; For each of the well-known types there is a macro to check 
whether an object is of that type; for instance, "IgFloat_TYPE(a)" is true 
if, and only if, the object pointed to by a is an Iguana float.

Reference Counting
------------------

It counts how many different places there are that have a reference to an 
object. Such a place could be another object, or a global (or static) C 
variable, or a local variable in some C function. When an object's reference 
count becomes zero, the object is deallocated. If it contains references to
other objects, their reference count is decremented. Those other objects may 
be deallocated in turn, if this decrement makes their reference count become 
zero, and so on.

Reference counts are always manipulated explicitly. The normal way is
to use the macro Ig_INCREF() to increment an object's reference count
by one, and Ig_DECREF() to decrement it by one. The Ig_DECREF() macro is 
a little more complex than the Ig_INCREF one, since it must check whether the 
reference count becomes zero and then cause the object's deallocator to be 
called. The deallocator is a function pointer contained in the object's type 
structure and is responsible for the correct deallocation of the object. 
Eventually type-specific deallocator takes care of decrementing the reference 
counts for other objects contained in the object if this is a compound object 
type, such as an array, as well as performing any additional finalization
that's needed. There's no chance that the reference count can overflow; at 
least as many bits are used to hold the reference count as there are distinct 
memory locations in virtual memory (assuming sizeof(long) >= sizeof(char*)). 
Thus, the reference count increment is a simple operation.


Deep Focus
----------

Iguana uses a lot of design principles normally found in object oriented
designs. As Iguana is written in C, a few basic principles shall be explained
here on how Iguana is object oriented anyway.

Classes are struts containing function pointers and data members. Classes in 
Iguana are called types. 

The base class is the Object. Objects are structures allocated on the heap, 
never statically or on the stack. All Iguana types can be casted into a
pointer to Object and back. Here is an example of an Iguana object:

	struct _IgIntObject
	{
	        IgObject_HEAD;
        	long ob_ival;
	};
 
The IgObject_HEAD macro declares the initial segment of every Iguana object, 
whereas ob_ival is the object data member.    

Here is an example: 

	struct _IgNumberMethods
	{
	        coercion nm_coerce;
	        binaryfunc nm_add;
        	binaryfunc nm_sub;
	        binaryfunc nm_mul;
        	binaryfunc nm_true_div;
	        binaryfunc nm_floor_div;
	        binaryfunc nm_mod;
	        binaryfunc nm_pow;
	        unaryfunc nm_neg;
	        unaryfunc nm_pos;
	        unaryfunc nm_abs;
	        inquiryfunc nm_nonzero;
	};

This methods are grouped in "protocol". Actually there are two protocols: 
Number (the example) and Sequence. Each method is implemented as a static 
method (to prevent namespace pollution).

Each type (class) has the following attributes:
  - name (for user convenience)
  - docstring 
  - size
  - standard method (print, del, cmp, repr)
  - protocols (number and/or sequence */

Follow a type struct: 

	struct _IgTypeObject
	{
        	IgObject_HEAD;
	        char *tp_name;
	        char *tp_doc;
	        unsigned int tp_size;

	        /* Methods to implement standard operations */
		newfunc tp_new;
	       	delfunc tp_del;
	        printfunc tp_print;
	        reprfunc tp_repr;
	        cmpfunc tp_cmp;

	        /* Protocols */
	        IgNumberMethods *tp_as_number;
	        IgSequenceMethods *tp_as_sequence;
	};	

You should note that also the type struct contains the IgObject_HEAD: this means
that also the type object is an object itself. 

To be continued...


Coding suggestions
==================

These are the rules to use when making changes to the Iguana source code  
that any programmer, adding or changing code in Iguana, should follow.


Style Guide
-----------

This list is not complete (and may never be). Look in the source code
for more examples.

  o  It is more important to be correct than to be fast (see "Design 
     Principles" section in this document).

  o  It is more important to keep the code maintainable and readable than to 
     be fast. If you have a great idea about optimizing the code, make sure 
     it is implemented cleanly. I can assure you that *often* there is a 
     clean and maintainable way to do it.
 
  o  Cleaning code in Iguana is more important than trying to break it.
     By all means, code cleanups are always welcome :-)

  o  Minimize the use of global variables. Always prototype global functions 
     in the appropriate header file. Functions should always be declared 
     as static unless they are intended to be global.
                                                                                
  o  If you use a system specific feature, don't add #ifdef __CRAY__ or 
     something like that. Rather write a check for that feature for 
     configure.ac and use a meaningful macro name in the `config.h'.

  o  Don't use C++-style comments (i.e., // comments).

  o  One statement per line:

     WRONG: if (cond) a = 1;

     RIGHT: if (cond)
              a = 1;

     WRONG: while (cond);

     RIGHT: while (cond)
              ;

  o  No space between a function name and the bracket:

     WRONG: func (arg);
     RIGHT: func(arg);

  o  Do use a space after if, while, switch, etc.

     WRONG: if(cond)         for(;;)
     RIGHT: if (cond)        for (;;)

  o  Use a space after a comma and semicolon:

     WRONG: func(arg1,arg2);        for (i = 0;i < 2;++i)
     RIGHT: func(arg1, arg2);       for (i = 0; i < 2; ++i)

  o  Use a space before and after '=', '+', '/', etc.

     WRONG: var=a*5;
     RIGHT: var = a * 5;

  o  In general: use empty lines to group lines of code together. Put a 
     comment just above the group of lines. This makes it more easy to 
     quickly see what is being done:
 
     RIGHT: /* Avoid to importing __main__ and __builtin__ */
            if (!strcmp(name, "__main__") || !strcmp(name, "__builtin__"))
                  return 0;

            /* Checking if the module was already imported. */
            m = IgImport_GetModule(name);

            if (m != NULL) {
                  if (Ig_VerboseMode) {
                       path = IgString_VALUE(IgModule_FILENAME(m));
                       fprintf(stdout, "# module '%s' was already imported "
                                       "from '%s'\n", name, path);
                  }

                  return 0;
            }
  
  o  Use Misc/indent.pro. For an explanation about it's use refer to the
     GNU indent manpage. Or just type `make indent' in the top-level
     directory of your copy of the Iguana sources.


How to coding for portability
-----------------------------

Some efforts have been made to make Iguana development portable. Have a look
to the system.h file. Some functions that are common to use, have a special 
Iguana version (their names start always with IgSys_). Always consider using 
the Iguana version, because they were introduced with a reason:
 
  o  (Iguana/mymalloc.c) IgSys_malloc(), IgSys_realloc() and IgSys_free() can 
     be used instead of classic C malloc(), realloc() and free() functions.
     These functions test the return value, and if the allocation failed, 
     the interpreter call Ig_Suicide(). 
 
  o  (Iguana/mysnprintf.c) Replacements for snprintf() and vsnprintf() 
     functions which are not available on all platforms. Where the functions 
     are available natively, these are just wrappers. 

  o  (Iguana/mysignal.c) IgSys_setsignal() and IgSys_getsignal() are wrappers
     around sigaction() or signal(). These function provides a common and
     portable way to set/get a signal handler. 

  o  (Iguana/myrandom.c) provide wrappers around random(), lrand48() and 
     rand(). 

  o  (Include/system.h) This file contains all the portability hacks that you
     can found in this Iguana implementation. Please use it when you are 
     writing a something that is not portable.


How to coding for speed without break portability
-------------------------------------------------

These few rules comes from my old writing "Coding for speed" (available only
in Italian). You should notice that this rules never break the C portability.

  o  Don't use recursion. Recursion can be very elegant and neat, but creates
     many more function calls which can become a large overhead.

  o  Avoid the square root function (sqrt) in loops because is very CPU 
     intensive.

  o  Floating point multiplication is often faster that division - use v * 0.5
     instead of v / 2.
 
  o  Addition is quicker than multiplication - use v + v + v instead of 
     v * 3.

  o  Use word-size variables if you can, as the compiler can work with these
     better (instead of char, short, etc...).

  o  This code may speedup strings comparisons:
        if (name[0] == 'N' && strcmp(name, "None") == 0)
                                                                                
  o  Use the "register" declaration whenever you can, e.g.

          register float val;
          register double dval;	
          register int ival;

     this is only a hint to the compiler: modern compilers are quite good at
     register allocation, and may ignore this altogheter, but it allows to
     allocate registers more aggressively, if you let it know which variables
     are suitable. However you cannot take the address of a register, so 
     &ival (above) would fail.

Happy hacking :-)
