[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Visionaries] New DG-Scheme features & some engine talk
From: |
Peter Minten |
Subject: |
[Visionaries] New DG-Scheme features & some engine talk |
Date: |
Fri, 25 Jul 2003 12:52:27 +0200 |
User-agent: |
Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030529 |
Hi folks,
currenlty I'm working on the implementation of DG-Scheme. While doing that I got
some ideas on how to improve the language.
== Macros ==
Macros can be dangerous, they can be helpful too however. It depends on the
situation what they are. That's why I'm introducing set-macro-safe. The
set-macro-safe function takes one argument which is either a number or a symbol
and sets the macro-safe level to that argument. The possible arguments are:
0 'allow-all -- Allow normal macro behaviour for all macros.
1 'explicit-deny -- Allow normal macro behaviour for all macro's except when
explicitely told not to do that.
2 'allow-base -- Allow normal macro behaviour for all macro's in the Base
hiearchy (the baselib). Disallow normal macro behaviour for all other macros
unless explicitely told otherwise.
3 'explicit-allow -- The same as 'allow-base, except that the Base macro's
aren't automatically allowed anymore.
4 'deny-all -- Deny all macro's.
Some primitive macro's are allowed regardless of what the macro-safe level says.
Macro's that can't be called with normal macro behaviour can still be called,
but they only take a single argument (a list) and produce a list that must be
explicitely evaluated (using '(eval list)').
The standard macro level is 0. Note that that's not a safe level for any
production code.
At the first deny command the macro level automatically gets set to 1, if it's
not already at that or a lower level. Thus level 0 can be regarded as level 1,
however it's faster since the macro deny checks are off.
== Argument order ==
In DG-Scheme the argument order of a function can never be trusted. DG-Scheme
functions have the power to make an argument delayed, in which case it's not
evaluated until needed. All other arguments are evaluated left to right.
Delayed evaluating is simple, a backquote (`) is put before the argument. For
example:
(\ (a b `c) ...) ;;c is delayed evaluated
(\ (a `(b (\ (v) (v.in-range? 10 20)))) ;;b is delayed evaluated
== Dynamic binding and enviroment variables ==
Sometimes it's handy to pass arguments to functions without putting them in the
argument list but by defining a variable and having the function read that
variable. In the case (begin (define a 10) (foo)) foo can't read a, and it
shouldn't. For enviroment variables like macro-safe it's another situation
however. That's why I'm introducing enviroment variables.
Enviroment variables are dynamically bound. They can't leave the scope in which
they are defined however (like any other variable). To define an eviroment
variable you need a special function (define-enviroment-variable) aka (defenv).
This function simply behaves like a normal define, except that the variable is
automatically set read-only (you can override, but normally it's what you want).
The variable can then be accessed using env.variable-name, note that 'env' is a
special variable.
Almost all the special variables can be accessed using env too (env.super,
env.owner, etc), they only have names without env in them because they are used
so much that it's reasonable to shorten them. The macro-safe variable is however
only accessible with env.macro-safe (it's a read-write variable btw).
A word of warning is due here, don't define enviroment variables unless you
really need them, it's bad style to depend on them for stuff you should pass in
a parameter list.
== DgsSimple and DgsObject ==
To cut down complexity in the engine I've decided to split the primitive data
types from their object representations. That's like Java splitting int from
Integer (though I'm not going to make the primitive data types available for the
code). The primitive data types are all decendants from DgsSimple and have names
like DgsSimpleString and DgsSimpleInteger. The primitive objects are all
decendants from DgsObject and have names like DgsString and DgsInteger.
Every DgsSimple has a reference to it's corresponding DgsObject and vice versa.
Conversion between the two is implicit.
The key advantage of this approach is that the C# implementation of the
primitive data types is clearly separated from the DGS primitives (intercall
functions of DGS) attached to the data types. The C# implementation is in the
DgsSimple and the DGS primitives are in the DgsObject.
== Stack ==
The DG-Scheme call stack model isn't as straightforward as that of IL due to
call-with-current-continuation (call/cc). Since it's possible to move from a
stack frame to it's parent with the possibility of returning to that stack frame
it's possible to have to stack frames with the same parent. That's why my
stacks can branch.
It turns out this stack model is pretty easy to do since all of the operations
can be clearly defined:
* Creating a new stack frame
If the current stack frame already has a child frame add the new stack frame to
the existing child frame in an array. Else set the child reference to the new
stack frame.
* Exiting a stack frame
If the exit is caused by a call/cc leave the stack frame and simply revert some
bindings and go to parent. Else revert bindings, go to parent and remove frame.
Note that call/cc is not the only way to do a non-local exit. I have the
call-with-return-function (call/rf) and call-with-throw-function (call/tf) too,
but these don't produce continuations.
A stack frame consists of many things, some of which I have yet to figure out.
But I know how the bindings will be stored. A simple before-after image for each
binding will do.
Greetings,
Peter
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Visionaries] New DG-Scheme features & some engine talk,
Peter Minten <=