Hans,

> Apparently the string becomes a primitive char* at some point; at  
> least that's
> my guess...

That's right.  A "string" in an s-expression represents the address  
of its primitive contents (just like a string literal in C).  To make  
a String object you can either construct it (as in your example) or  
quote it, like '"this".

Steve Folta hit the nail on the head a few days ago: Jolt is just a  
(dynamic) C compiler with a Lisp-like syntax.   Thinking of it that  
way might help you in your adventures with lambdas, arguments and  
environments.  In C terms, lambdas are

typedef void *(*lambda)(...);

(pretend that you don't need a named arg before '...').  There is no  
explicit collection that contains the arguments; they are constructed  
(and only exist) transiently on the runtime stack (and/or in argument  
registers) for the duration of the call -- just like in C.  The  
'environment's that keep track of local variables are compile-time  
constructs that relate symbolic variable names to code generator  
objects representing the physical location (e.g., an offset into the  
runtime stack frame) where the variable's value will be stored.   
Again, just like a C compiler would use a symbol table to keep track  
of local variable names and implementations.

So there is no 'current environment'.  Variables are stored in stack  
frames, not in structured objects.  By the time code is compiled and  
running, the 'environment' objects are long gone.  There definitely  
ought to be meta information at run time that allows one to get at  
information about the frames in the stack but for now we don't have it.

Right now the relationship between what you are trying to do and Jolt  
is the same as the relationship between Pepsi and the C compiler.   
Pepsi manages to implement (e.g.) blocks with free variables on top  
of C's runtime model, by using the very primitive facilities provided  
by C to build the higher-level facilities intrinsic to languages like  
Lisp and Smalltalk.  The Pepsi compiler would have a far easier job  
if the C compiler made its meta information available to arbitrary  
user-defined functions that are instantiated and run during  
compilation.  Your job should be far easier because Jolt does expose  
its meta information and does let you run arbitrary code during  
compilation.  The beginnings of the necessary hooks are there (syntax  
functions, active variables, environments, etc.) but they are far  
from properly developed.  The situation should improve significantly  
as I move the Pepsi compiler into Jolt, but for now what you are  
trying to do is simply very hard.

One of the things that is planned and would help you immensely is a  
kind of 'apply' but it will be a very different thing from Lisp's  
apply, intended for building low-level calls (setup of arguments in  
stack/registers and a primitive subroutine 'call') dynamically.   
(Much closer to GCC's __builtin_apply* family of functions, if you  
know about those, but dynamic rather than static.)

If anyone is up for a huge adventure in metaprogramming then here are  
a couple of things that are possible with the current (underdeveloped  
and under-documented) Compiler internals:

1. Syntax can be used to create something like a 'let' form (let's  
call it 'free-let') but which stores its variables' values in state  
arrays (much like the Pepsi compiler does for the free variables in  
blocks).  The 'free-let' form could use 'active' to create active  
variables whose getters and setters operate on the slots in their  
state array.  By keeping track of the nesting of state arrays (maybe  
one array per lambda, which can be redefined using 'syntax' as  
required) they can be chained together at runtime to provide access  
to non-local state.  At compile time new active variable declarations  
would be inserted at the head of each nested lambda, with getters and  
setters that follow the appropriate number of chained state array  
indirections before designating the slot storing their value.

2. The Environments in the Compiler just associate variable names  
with objects that respond to 'translateLvalue:' to create the code  
needed to designate the location of the stored value at runtime.   
Free variables can be implemented in Pepsi within the Compiler by  
creating something like a NonLocalVariable type to populate the  
Compiler's Environments and then managing the same heap-allocated  
state arrays as described in (1) above.

Neither of these are projects for the timid.  (I'd be tempted to  
start with (2), just because I'm a wimp. ;-)

The next step (for extra credits) would be to figure out how to call  
the resulting closures (lambdas that have to be initialised with the  
chain of state arrays) as if they were functions; i.e., no difference  
(to the caller) between lambda (without free state) and closures.

Hope that helps rather than confuses.

Cheers,
Ian

_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc

Reply via email to