2003-08-19 15:19:38 -04:00
|
|
|
/* Environments, define, set!, etc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kernel.h"
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Set_Name (Object, Object);
|
|
|
|
void Memoize_Frame (Object);
|
|
|
|
void Memoize_Frames (Object, Object);
|
|
|
|
void Forget_Frame (Object);
|
|
|
|
|
2003-08-19 15:25:35 -04:00
|
|
|
#define Env_To_List(env, list) SET((list), T_Pair, (ptrdiff_t)POINTER(env))
|
|
|
|
#define List_To_Env(list, env) SET((env), T_Environment, (ptrdiff_t)POINTER(list))
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
Object The_Environment, Global_Environment;
|
|
|
|
|
|
|
|
Object General_Define();
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Init_Env () {
|
2003-08-19 15:19:38 -04:00
|
|
|
List_To_Env (Cons (Null, Null), Global_Environment);
|
|
|
|
The_Environment = Global_Environment;
|
|
|
|
Global_GC_Link (Global_Environment);
|
|
|
|
Global_GC_Link (The_Environment);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Environment_To_List (Object env) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object e;
|
|
|
|
|
|
|
|
Check_Type (env, T_Environment);
|
|
|
|
Env_To_List (env, e);
|
|
|
|
return Copy_List (e);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Environmentp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return TYPE(x) == T_Environment ? True : False;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Push_Frame (Object frame) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object e;
|
|
|
|
|
|
|
|
Memoize_Frame (frame);
|
|
|
|
Env_To_List (The_Environment, e);
|
|
|
|
List_To_Env (Cons (frame, e), The_Environment);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Pop_Frame () {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object e;
|
2003-08-19 15:24:23 -04:00
|
|
|
|
2003-08-19 15:19:38 -04:00
|
|
|
Env_To_List (The_Environment, e);
|
|
|
|
List_To_Env (Cdr (e), The_Environment);
|
|
|
|
Forget_Frame (Car (e));
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Switch_Environment (Object to) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object old, new, n;
|
|
|
|
|
|
|
|
if (EQ(The_Environment,to))
|
|
|
|
return;
|
|
|
|
Env_To_List (The_Environment, old);
|
|
|
|
Env_To_List (to, new);
|
|
|
|
for ( ; !Nullp (old); old = Cdr (old)) {
|
|
|
|
for (n = new; !Nullp (n) && !EQ(n,old);
|
|
|
|
n = Cdr (n))
|
|
|
|
;
|
|
|
|
if (EQ(n,old))
|
|
|
|
break;
|
|
|
|
Forget_Frame (Car (old));
|
|
|
|
}
|
|
|
|
Memoize_Frames (new, n);
|
|
|
|
The_Environment = to;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Memoize_Frames (Object this, Object last) {
|
2003-08-19 15:19:38 -04:00
|
|
|
if (Nullp (this) || EQ(this,last))
|
|
|
|
return;
|
|
|
|
Memoize_Frames (Cdr (this), last);
|
|
|
|
Memoize_Frame (Car (this));
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Memoize_Frame (Object frame) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object binding;
|
|
|
|
|
|
|
|
for (; !Nullp (frame); frame = Cdr (frame)) {
|
|
|
|
binding = Car (frame);
|
|
|
|
SYMBOL(Car (binding))->value = Cdr (binding);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Forget_Frame (Object frame) {
|
2003-08-19 15:19:38 -04:00
|
|
|
for (; !Nullp (frame); frame = Cdr (frame))
|
|
|
|
SYMBOL(Car (Car (frame)))->value = Unbound;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Add_Binding (Object frame, Object sym, Object val) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object b;
|
|
|
|
GC_Node;
|
|
|
|
|
|
|
|
GC_Link (frame);
|
|
|
|
b = Cons (sym, val);
|
|
|
|
GC_Unlink;
|
|
|
|
return Cons (b, frame);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Lookup_Symbol (Object sym, int err) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object p, f, b;
|
|
|
|
|
|
|
|
Env_To_List (The_Environment, p);
|
|
|
|
for (; !Nullp (p); p = Cdr (p)) {
|
|
|
|
for (f = Car (p); !Nullp (f); f = Cdr (f)) { /* Inlined Assq() */
|
|
|
|
b = Car (f);
|
|
|
|
if (EQ(Car (b), sym))
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (err)
|
|
|
|
Primitive_Error ("unbound variable: ~s", sym);
|
|
|
|
return Null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object P_The_Environment () { return The_Environment; }
|
|
|
|
|
|
|
|
Object P_Global_Environment () { return Global_Environment; }
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Define_Procedure (Object form, Object body, Object sym) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object ret;
|
|
|
|
GC_Node3;
|
|
|
|
|
|
|
|
GC_Link3 (form, body, sym);
|
|
|
|
body = Cons (Cdr (form), body);
|
|
|
|
body = Cons (sym, body);
|
|
|
|
body = Cons (body, Null);
|
|
|
|
body = Cons (Car (form), body);
|
|
|
|
ret = General_Define (body, sym);
|
|
|
|
GC_Unlink;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Define (Object argl, Object sym) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object val, var, frame, binding;
|
|
|
|
GC_Node3;
|
|
|
|
TC_Prolog;
|
|
|
|
|
|
|
|
var = Car (argl);
|
|
|
|
val = Cdr (argl);
|
|
|
|
if (TYPE(var) == T_Symbol) {
|
|
|
|
frame = Null;
|
|
|
|
GC_Link3 (var, val, frame);
|
|
|
|
if (Nullp (val)) {
|
|
|
|
val = Void;
|
|
|
|
} else {
|
|
|
|
TC_Disable;
|
|
|
|
val = Eval (Car (val));
|
|
|
|
TC_Enable;
|
|
|
|
}
|
|
|
|
Set_Name (var, val);
|
|
|
|
frame = Car (The_Environment);
|
|
|
|
binding = Assq (var, frame);
|
|
|
|
if (EQ(binding, False)) {
|
|
|
|
frame = Add_Binding (frame, var, val);
|
|
|
|
Car (The_Environment) = frame;
|
|
|
|
} else
|
|
|
|
Cdr (binding) = val;
|
|
|
|
SYMBOL(var)->value = val;
|
|
|
|
GC_Unlink;
|
|
|
|
return var;
|
|
|
|
} else if (TYPE(var) == T_Pair) {
|
|
|
|
if (Nullp (val))
|
|
|
|
Primitive_Error ("no sub-forms in compound: ~s", var);
|
|
|
|
return Define_Procedure (var, val, sym);
|
|
|
|
} else Wrong_Type_Combination (var, "symbol or pair");
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Define (Object argl) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Define (argl, Sym_Lambda);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Define_Macro (Object argl) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Define (argl, Sym_Macro);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Set (Object argl) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object val, var, binding, old;
|
|
|
|
GC_Node3;
|
|
|
|
TC_Prolog;
|
|
|
|
|
|
|
|
var = Car (argl);
|
|
|
|
val = Car (Cdr (argl));
|
|
|
|
Check_Type (var, T_Symbol);
|
|
|
|
binding = Lookup_Symbol (var, 1);
|
|
|
|
old = Cdr (binding);
|
|
|
|
GC_Link3 (var, binding, old);
|
|
|
|
TC_Disable;
|
|
|
|
val = Eval (val);
|
|
|
|
TC_Enable;
|
|
|
|
Set_Name (var, val);
|
|
|
|
Cdr (binding) = val;
|
|
|
|
SYMBOL(var)->value = val;
|
|
|
|
GC_Unlink;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Set_Name (Object var, Object val) {
|
|
|
|
register int t;
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
t = TYPE(val);
|
|
|
|
if (t == T_Compound) {
|
|
|
|
if (Nullp (COMPOUND(val)->name))
|
|
|
|
COMPOUND(val)->name = var;
|
|
|
|
} else if (t == T_Macro) {
|
|
|
|
if (Nullp (MACRO(val)->name))
|
|
|
|
MACRO(val)->name = var;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Boundp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Type (x, T_Symbol);
|
|
|
|
return Nullp (Lookup_Symbol (x, 0)) ? False : True;
|
|
|
|
}
|