New update : now supports floating point numbers. They can be added, subtracted, multiplied, compared with is, isnt, <, >, <=, >=.
There are a few things incompatible with canonical arc regarding the status of flonums ending with .0. They are regarded as integers by arc (but are still written, e.g., 1.0). In arc2c, any literal written x.0 is translated into x and any generated flonum ending by .0 is considered a flonum. That will probably be fixed soon, but I think it is an almost bug in arc (I guess this will be changed in future versions of arc), so, we'll see.
As an aside: maybe it's better to make the primitives really, really primitive?
Basically we define separate %n+ for adding two fixnums, %f+ for adding two flonums, %fn+ for adding a flonum and a fixnum (in that order) and, %nf+ for adding a fixnum and a flonum (in that order).
As for macros: Hmm. You see... Look, up in the sky! Is it a bird? A plane? Superman? Nothing? Oh, what were we talking about again? ^^ LOL
Okay now serious: currently I'm blocked with creating a "protected" eval for macros. Programmer's block. The bit blocking me is the destructuring thing. Erk.
I think you're right for primitives. I asked pg the same question a few time ago, he answered he didn't know yet. Anyway, for an optimizing compiler, we will need these (as in : "hmmm, n can only hold a fixnum, let's translate this heavy '+ in a lightweight '%n+ !")
Now, macros. I tried to think about it yesterday, and I don't really understand why you need this protected mode. I mean, macros have to be defined (globally) before they are called and treated as such. Since you can already identify all the globals (and since a macro is a global thing annotated by 'mac), it should be easy to
- make a list of all the symbols holding a macro at a given moment in the code
- explore all the sexprs to see if one of those symbols is the first element of any sublist
If I understand well, we have to interpret the code as we compile it (as a macro's body is executed when a function is defined/compiled, not when executed) ? To me, macros were something translating a piece of code into another one, period. But that's not always the case as your example shows. If someone writes
(mac foo
(prn "blah"))
(def bar (n)
(foo) (* n 2))
That means we have to display "blah" on compile time, right ? Hmm, that's much harder than I thought... It really means implementing an arc interpreter in arc (the way the official one is written in mzscheme), with for example prepending all the interpreted names with _ to distinguish them from the compiler's names...
Ok, I think I'm starting to realy get it ; or am I still missing an even trickier issue ?
That is about it. ^^ However my current implementation uses tables as environments for the function. Keys in the table are symbols for the variable names in that environment. A "parent" string key accesses the environment's parent.
The global environment is shadowed by a table; when this table is accessed, if a table entry does not exist, we look it up in the real environment using 'eval (!!) and retain a copy. This allows the macro to use stuff like 'map.
However there is still a leak here: if the real global-level environment has a function that modifies a global, it will modify a different global variable from the one that is visible to the macro. This shouldn't happen anyway: we should really avoid using globals in utility functions ^^.
Okay, now that I've actually gotten to see it - I think you forgot to push codegen.arc, since the current version on git don't actually generate code that calls DBL2OBJ.
Edit: Also, it might be useful to organize the primitives as "functions", like what I did with cons_fun().
So:
#define CONS() {obj d = POP(); TOS() = cons_fun(TOS(), d);}
This should allow us to express some primitive calls directly:
Let's call the cons_fun(FIX2OBJ(1) ...) call cons_fun1, and the other as cons_fun2. cons_fun2 is called first (because it's more inner). The value is then pushed into the C stack. Then cons_fun1 is called. However, what if GC is triggered at exactly cons_fun1? Then the cons cell returned by cons_fun2 is on the C stack, not the Arc stack; the C stack is not scanned by the GC! This means we actually lose memory areas.
Probably means I have to modify the way constants are stored.
Hmmm, good point. The stack, GLOBALS and QUOTE_CONSTANTS are all explored when GC is triggered. Maybe the solution would be to add a temporary storage (that should be taken into consideration by GC too) before putting things in the constants, or something like that ?
> Maybe the solution would be to add a temporary storage (that should be taken into consideration by GC too) before putting things in the constants, or something like that ?
Okay, converted init_constants() to use the Arc stack instead of the C stack. Fear the pointer arithmetic foo-ness when using a processor with special PUSH and POP instructions (which are arguably dying out, because RISC processors handle stacks using explicit pointer ariths).