mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 11:50:28 +02:00
391 lines
8.7 KiB
JavaScript
391 lines
8.7 KiB
JavaScript
var scheme = {
|
|
obarray : {},
|
|
primitives : {},
|
|
utils : {},
|
|
env : {},
|
|
cache: [],
|
|
builtins: [],
|
|
dynstack : [],
|
|
// TODO: placeholders
|
|
FALSE : false,
|
|
TRUE : true,
|
|
NIL : false,
|
|
EMPTY : [],
|
|
UNSPECIFIED : [],
|
|
// FIXME: wingo says not to leak undefined to users
|
|
UNDEFINED: undefined
|
|
};
|
|
|
|
function not_implemented_yet() {
|
|
throw "not implemented yet";
|
|
};
|
|
|
|
function coerce_bool(obj) {
|
|
return obj ? scheme.TRUE : scheme.FALSE;
|
|
};
|
|
|
|
// Numbers
|
|
scheme.primitives.add = function (x, y) {
|
|
return x + y;
|
|
};
|
|
|
|
scheme.primitives.add1 = function (x) {
|
|
return x + 1;
|
|
};
|
|
|
|
scheme.primitives.sub = function (x, y) {
|
|
return x - y;
|
|
};
|
|
|
|
scheme.primitives.sub1 = function (x) {
|
|
return x - 1;
|
|
};
|
|
|
|
scheme.primitives.mul = function (x, y) {
|
|
return x * y;
|
|
};
|
|
|
|
scheme.primitives.div = function (x, y) {
|
|
return x / y;
|
|
};
|
|
|
|
scheme.primitives["="] = function (x, y) {
|
|
return coerce_bool(x == y);
|
|
};
|
|
|
|
scheme.primitives["<"] = function (x, y) {
|
|
return coerce_bool(x < y);
|
|
};
|
|
|
|
scheme.primitives["<="] = function (x, y) {
|
|
return coerce_bool(x <= y);
|
|
};
|
|
|
|
scheme.primitives[">"] = function (x, y) {
|
|
return coerce_bool(x > y);
|
|
};
|
|
|
|
scheme.primitives[">="] = function (x, y) {
|
|
return coerce_bool(x >= y);
|
|
};
|
|
|
|
scheme.primitives.quo = not_implemented_yet;
|
|
scheme.primitives.rem = not_implemented_yet;
|
|
scheme.primitives.mod = not_implemented_yet;
|
|
|
|
// Boxes
|
|
scheme.Box = function (x) {
|
|
this.x = x;
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["box"] = function(x) {
|
|
return new scheme.Box(x);
|
|
};
|
|
|
|
scheme.primitives["box-ref"] = function (box) {
|
|
return box.x;
|
|
};
|
|
|
|
scheme.primitives["box-set!"] = function (box, val) {
|
|
box.x = val;
|
|
};
|
|
|
|
// Lists
|
|
scheme.Pair = function (car, cdr) {
|
|
this.car = car;
|
|
this.cdr = cdr;
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["pair?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.Pair);
|
|
};
|
|
|
|
scheme.primitives.cons = function (car, cdr) {
|
|
return new scheme.Pair(car,cdr);
|
|
};
|
|
|
|
scheme.primitives.car = function (obj) {
|
|
return obj.car;
|
|
};
|
|
|
|
scheme.primitives.cdr = function (obj) {
|
|
return obj.cdr;
|
|
};
|
|
|
|
scheme.primitives["set-car!"] = function (pair, obj) {
|
|
obj.car = obj;
|
|
};
|
|
|
|
scheme.primitives["set-cdr!"] = function (pair, obj) {
|
|
obj.cdr = obj;
|
|
};
|
|
|
|
scheme.list = function () {
|
|
var l = scheme.EMPTY;
|
|
for (var i = arguments.length - 1; i >= 0; i--){
|
|
l = scheme.primitives.cons(arguments[i],l);
|
|
};
|
|
return l;
|
|
};
|
|
|
|
scheme.primitives["null?"] = function(obj) {
|
|
return coerce_bool(scheme.EMPTY == obj);
|
|
};
|
|
|
|
// Symbols
|
|
scheme.Symbol = function(s) {
|
|
if (scheme.obarray[s]) {
|
|
return scheme.obarray[s];
|
|
} else {
|
|
this.name = s;
|
|
scheme.obarray[s] = this;
|
|
return this;
|
|
};
|
|
};
|
|
|
|
scheme.primitives["symbol?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.Symbol);
|
|
};
|
|
|
|
// Keywords
|
|
scheme.Keyword = function(s) {
|
|
this.name = s;
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["keyword?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.Keyword);
|
|
};
|
|
|
|
scheme.utils.keyword_ref = function(kw, args, start, dflt) {
|
|
var l = args.length;
|
|
|
|
if ((l - start) % 2 == 1) {
|
|
// FIXME: should error
|
|
return undefined;
|
|
}
|
|
// Need to loop in reverse because last matching keyword wins
|
|
for (var i = l - 2; i >= start; i -= 2) {
|
|
if (!(args[i] instanceof scheme.Keyword)) {
|
|
return undefined;
|
|
}
|
|
if (args[i].name === kw.name) {
|
|
return args[i + 1];
|
|
}
|
|
}
|
|
return dflt;
|
|
};
|
|
|
|
// Vectors
|
|
scheme.Vector = function () {
|
|
this.array = Array.prototype.slice.call(arguments);
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["vector-ref"] = function (vec, idx) {
|
|
return vec.array[idx];
|
|
};
|
|
|
|
scheme.primitives["vector-set!"] = function (vec, idx, obj) {
|
|
return vec.array[idx] = obj;
|
|
};
|
|
|
|
scheme.primitives["vector-length"] = function (vec) {
|
|
return vec.array.length;
|
|
};
|
|
|
|
scheme.primitives["vector?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.Vector);
|
|
};
|
|
|
|
scheme.primitives["make-vector/immediate"] = not_implemented_yet;
|
|
scheme.primitives["vector-set!/immediate"] = not_implemented_yet;
|
|
scheme.primitives["vector-ref/immediate"] = not_implemented_yet;
|
|
|
|
// Bytevectors
|
|
|
|
// Booleans
|
|
|
|
scheme.primitives["boolean?"] = not_implemented_yet;
|
|
|
|
// Chars
|
|
scheme.Char = function(c) {
|
|
this.c = c;
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["char?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.Char);
|
|
};
|
|
|
|
// Strings
|
|
scheme.String = function(s) {
|
|
this.s = s;
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["string?"] = function (obj) {
|
|
return coerce_bool(obj instanceof scheme.String);
|
|
};
|
|
|
|
scheme.primitives["string-length"] = function (str) {
|
|
return str.s.length;
|
|
};
|
|
|
|
scheme.primitives["string-ref"] = function (str, idx) {
|
|
return new scheme.Char(str.s[idx]);
|
|
};
|
|
|
|
// Closures
|
|
scheme.Closure = function(f, size) {
|
|
this.fun = f;
|
|
this.freevars = new Array(size);
|
|
return this;
|
|
};
|
|
|
|
scheme.primitives["free-set!"] = function (closure, idx, obj) {
|
|
closure.freevars[idx] = obj;
|
|
};
|
|
|
|
scheme.primitives["free-ref"] = function (closure, idx) {
|
|
return closure.freevars[idx];
|
|
};
|
|
|
|
scheme.primitives["builtin-ref"] = function (idx) {
|
|
return scheme.builtins[idx];
|
|
};
|
|
|
|
// Modules
|
|
scheme.primitives["define!"] = function(sym, obj) {
|
|
scheme.env[sym.name] = new scheme.Box(obj);
|
|
};
|
|
|
|
scheme.primitives["cache-current-module!"] = function (module, scope) {
|
|
scheme.cache[scope] = module;
|
|
};
|
|
|
|
scheme.primitives["cached-toplevel-box"] = function (scope, sym, is_bound) {
|
|
return scheme.cache[scope][sym.name];
|
|
};
|
|
|
|
scheme.primitives["cached-module-box"] = not_implemented_yet;
|
|
|
|
scheme.primitives["current-module"] = function () {
|
|
return scheme.env;
|
|
};
|
|
|
|
scheme.primitives["resolve"] = function (sym, is_bound) {
|
|
return scheme.env[sym.name];
|
|
};
|
|
|
|
// bleh
|
|
scheme.initial_cont = function (x) { return x; };
|
|
scheme.primitives.return = function (x) { return x; };
|
|
scheme.is_true = function (obj) {
|
|
return !(obj === scheme.FALSE || obj === scheme.NIL);
|
|
};
|
|
|
|
// Builtins
|
|
var apply = function(self, k, f, arg) {
|
|
return f.fun(f.freevars, k, arg);
|
|
};
|
|
|
|
var values = function(self, k, arg) {
|
|
|
|
return k(arg);
|
|
};
|
|
|
|
var abort_to_prompt = function(self, k, prompt, arg) {
|
|
|
|
var idx = find_prompt(prompt);
|
|
var spec = scheme.dynstack[idx];
|
|
|
|
var kont = undefined; // actual value doesn't matter
|
|
|
|
if (!scheme.is_true(spec[1])) {
|
|
var f = function (self, k2) {
|
|
var args = Array.prototype.slice.call(arguments, 2);
|
|
return k.apply(k,args);
|
|
};
|
|
kont = new scheme.Closure(f, 0);
|
|
};
|
|
|
|
unwind(idx);
|
|
|
|
var handler = spec[2];
|
|
|
|
return handler(kont, arg);
|
|
};
|
|
|
|
var call_with_values = not_implemented_yet;
|
|
|
|
var callcc = function (self, k, closure) {
|
|
var f = function (self, k2) {
|
|
var args = Array.prototype.slice.call(arguments, 2);
|
|
return k.apply(k,args);
|
|
};
|
|
return closure.fun(closure, k, new scheme.Closure(f, 0));
|
|
};
|
|
scheme.builtins[0] = new scheme.Closure(apply, 0);
|
|
scheme.builtins[1] = new scheme.Closure(values, 0);
|
|
scheme.builtins[2] = new scheme.Closure(abort_to_prompt, 0);
|
|
scheme.builtins[3] = new scheme.Closure(call_with_values, 0);
|
|
scheme.builtins[4] = new scheme.Closure(callcc, 0);
|
|
|
|
// Structs
|
|
scheme.primitives["struct?"] = not_implemented_yet;
|
|
scheme.primitives["struct-set!/immediate"] = not_implemented_yet;
|
|
scheme.primitives["struct-vtable"] = not_implemented_yet;
|
|
scheme.primitives["struct-ref/immediate"] = not_implemented_yet;
|
|
scheme.primitives["struct-ref"] = not_implemented_yet;
|
|
scheme.primitives["struct-set!"] = not_implemented_yet;
|
|
scheme.primitives["allocate-struct/immediate"] = not_implemented_yet;
|
|
|
|
// Equality
|
|
scheme.primitives["eq?"] = function(x, y) {
|
|
return coerce_bool(x === y);
|
|
};
|
|
|
|
scheme.primitives["eqv?"] = function(x, y) {
|
|
return coerce_bool(x === y);
|
|
};
|
|
|
|
scheme.primitives["equal?"] = not_implemented_yet;
|
|
|
|
// Fluids
|
|
scheme.primitives["pop-fluid"] = not_implemented_yet;
|
|
scheme.primitives["push-fluid"] = not_implemented_yet;
|
|
scheme.primitives["fluid-ref"] = not_implemented_yet;
|
|
|
|
// Variables
|
|
scheme.primitives["variable?"] = not_implemented_yet;
|
|
|
|
// Dynamic Wind
|
|
scheme.primitives["wind"] = not_implemented_yet;
|
|
scheme.primitives["unwind"] = not_implemented_yet;
|
|
|
|
// Misc
|
|
scheme.primitives["prompt"] = function(escape_only, tag, handler){
|
|
scheme.dynstack.unshift([tag, escape_only, handler]);
|
|
};
|
|
|
|
var unwind = function (idx) {
|
|
// TODO: call winders
|
|
scheme.dynstack = scheme.dynstack.slice(idx+1);
|
|
};
|
|
|
|
var find_prompt = function(prompt) {
|
|
var eq = scheme.primitives["eq?"];
|
|
function test(x){
|
|
return scheme.is_true(eq(x,prompt)) || scheme.is_true(eq(x,scheme.TRUE));
|
|
};
|
|
for (idx in scheme.dynstack) {
|
|
if (test(scheme.dynstack[idx][0])) {
|
|
return idx;
|
|
};
|
|
};
|
|
// FIXME: should error
|
|
return undefined;
|
|
};
|