The last InteLib from the 0.5.* series, the 0.5.83, included a completely new feature, the InteLibScheme computational model, supported with the appropriate translator and interactive interpreter. The computation model's implementation was based on the notion of SchemeContinuation. The implementation technique has shown it is more efficient in speed, and better fits some of existing tasks. Therefore, a decision was made to reimplement the Lisp part of the library using the same technique (and partially the same code).
During the reworking, the sexpress/ directory got split off into 3 parts, and another directory was added as well to contain the common code for Lisp and Scheme. See the detailed explanation below.
The Lisp part was totally refactored; the very number of files (modules) has changed, and their names changed as well.
The Scheme part got changed as well, primarily because lots of code went to the genlisp/ directory as to be shared with the Lisp part.
Another major change resulted from a discussion at the SeminarMPP where I actually was strongly adviced to do something to the well-known but nevertheless unclear and tricky hack related to the reference counting mechanism. At the seminar's session, people thrown in some ideas on how to avoid the necessity of that hack, but that ideas didn't actually satisfy me. However, in several days another idea appeared, and it was good enough to be implemented. So, there's no damn tricky hack there now.
So, now to the details.
The Lisp part has been reimplemented using the stack-based machine which models the notion of a Continuation well-known for Scheme. The main idea is that the evaluator is never reentered; if, being evaluating a Lisp expression, we have to evaluate another expression first (such as when evaluating a plain function call form, in which case we've got to evaluate all the arguments first), then we push all the necessary steps to a stack of pending actions and then just return, in the hope the caller is smart enough to call us another time.
This works several times faster than the straight-forward implementation. One of the tips is that there's a stack of evaluation results; this stack is implemented as a vector, and parts of that vector are used for pasing parameters to the function implementations. In the previous (straight-forward) implementation we had to allocate such a vector every time we were to call a function.
The sexpress/ directory now contains lesser set of modules. Only the modules that represent S-expressions as data structures left there; instrumental tools such as streams, readrs, common numerical operations etc are now found in the directory named tools/. The glue for GnuReadline? has been moved to the interact/ directory.
There's now one more new directory, named genlisp/, which contains the code useful for both Lisp and Scheme implementations. This code includes the base implementation of Continuation (the IntelibContinuation class), the prototypes for a function and a special form (surprisingly enough, they are the same for both Scheme and Lisp), and the external (global) C++ variables interface (the extvar module).
The implementations of the Lisp and Scheme computation models reside, just like in the past, in the lisp/ and scheme/ directories.
The translators and interpreters are found in the ill/ and ils/ directories.
Changing of the directory layout can affect your code in the part of include files' paths. For example, if your program uses InteLib streams, you might be including the respective header like this:
This will no longer compile. Try the following directive instead:
As the InteLib longtimers definitely know, there was a killing difference between the SReference(SExpression*) and SReference(SExpression&) constructors. The SExpression objects were always created with the counter of references set to 1, and the first form of the constructor was intended for a code like SReference(new SExpression(...)), so it didn't increment the reference counter of the referenced object.
This unclear trick was a source of infinite bugs and errors.
For now, SExpression objects are created with the reference counter set to zero, so it is no problem to increment the counter always when another SReference referencing the object is created.
The form SReference(SExpression&), as no longer actual, has been eliminated.
The negative consequence of all this is that SExpressions now MUST NOT created outside of the dynamic memory. That is, you should NEVER NEVER EVER try to create such objects as automatic (stack) or global varables. Once you create a SReference to such an object and then destroy the SReference, it will try to delete your stack or global variable and will definitely crash your program.
To prevent the user from doing such a stupid mistake, I've made destructors of (hopefully) all the SExpression classes to be protected. Please follow this policy when you create your own types of SExpressions.
The class LEvaluationFrame doesn't exist any longer. In most cases, however, the class LispContinuation can be ised instead, and the functional (applicable) SExpression classes accept a reference to it immediate base class, IntelibContinuation?, instead of the LEvaluationFrame.
The SExpressionTypeId has been renamed into the IntelibTypeId class, as it was a violation of the global naming policy (only the classes derived from SExpression have the word Expression in their names).
For those who already tried the InteLib Scheme: the class SchContinuation? has been renamed to SchemeContinuation.
Instead of the LExpressionForm and LExpressionCFunction, there are now SExpressionForm and SExpressionFunction, found in the include file intelib/genlisp/lispform.hpp.
There are other changes as well, but they are not that visible.