// runtime.js: the main runtime library for whalesong.
//

if(this['plt'] === undefined) { this['plt'] = {}; }


// All of the values here are namespaced under "plt.runtime".
(function(scope) {
    var runtime = {};
    scope['runtime'] = runtime;



    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    // We try to isolate the effect of external modules: all the identifiers we
    // pull from external modules should be listed here, and should otherwise not
    // show up outside this section!
    var isNumber = plt.baselib.numbers.isNumber;
    var isNatural = plt.baselib.numbers.isNatural;
    var isReal = plt.baselib.numbers.isReal;
    var isPair = plt.baselib.lists.isPair;
    var isList = plt.baselib.lists.isList;
    var isVector = plt.baselib.vectors.isVector;
    var isString = plt.baselib.strings.isString;
    var isSymbol = plt.baselib.symbols.isSymbol;
    var isNonNegativeReal = plt.baselib.numbers.isNonNegativeReal;
    var equals = plt.baselib.equality.equals;

    var NULL = plt.baselib.lists.EMPTY;
    var VOID = plt.baselib.constants.VOID_VALUE;
    var EOF = plt.baselib.constants.EOF_VALUE;

    var NEGATIVE_ZERO = plt.baselib.numbers.negative_zero;
    var INF = plt.baselib.numbers.inf;
    var NEGATIVE_INF = plt.baselib.numbers.negative_inf;
    var NAN = plt.baselib.numbers.nan;

    var makeFloat = plt.baselib.numbers.makeFloat;
    var makeRational = plt.baselib.numbers.makeRational;
    var makeBignum = plt.baselib.numbers.makeBignum;
    var makeComplex = plt.baselib.numbers.makeComplex;

    var makeSymbol = plt.baselib.symbols.makeSymbol;

    var makeBox = plt.baselib.boxes.makeBox;
    var isBox = plt.baselib.boxes.isBox;

    var makeVector = plt.baselib.vectors.makeVector;
    var makeList = plt.baselib.lists.makeList;
    var makePair = plt.baselib.lists.makePair;


    var Closure = plt.baselib.functions.Closure;
    var finalizeClosureCall = plt.baselib.functions.finalizeClosureCall;
    var makePrimitiveProcedure = plt.baselib.functions.makePrimitiveProcedure;


    // Other helpers
    var withArguments = plt.baselib.withArguments;
    var heir = plt.baselib.heir;
    var makeClassPredicate = plt.baselib.makeClassPredicate;
    var toDomNode = plt.baselib.format.toDomNode;
    var toWrittenString = plt.baselib.format.toWrittenString;
    var toDisplayedString = plt.baselib.format.toDisplayedString;



    // Frame structures.
    var Frame = plt.baselib.frames.Frame;
    var CallFrame = plt.baselib.frames.CallFrame;
    var PromptFrame = plt.baselib.frames.PromptFrame;

    // Module structure
    var ModuleRecord = plt.baselib.modules.ModuleRecord;



    // Ports
    var OutputPort = plt.baselib.ports.OutputPort;
    var isOutputPort = plt.baselib.ports.isOutputPort;
    var StandardOutputPort = plt.baselib.ports.StandardOutputPort;
    var StandardErrorPort = plt.baselib.ports.StandardErrorPort;
    var OutputStringPort = plt.baselib.ports.OutputStringPort;
    var isOutputStringPort = plt.baselib.ports.isOutputStringPort;




    // Exceptions and error handling.
    var raise = plt.baselib.exceptions.raise;
    var raiseUnboundToplevelError = plt.baselib.exceptions.raiseUnboundToplevelError;
    var raiseArgumentTypeError = plt.baselib.exceptions.raiseArgumentTypeError;
    var raiseContextExpectedValuesError = plt.baselib.exceptions.raiseContextExpectedValuesError;
    var raiseArityMismatchError = plt.baselib.exceptions.raiseArityMismatchError;
    var raiseOperatorApplicationError = plt.baselib.exceptions.raiseOperatorApplicationError;
    var raiseOperatorIsNotPrimitiveProcedure = plt.baselib.exceptions.raiseOperatorIsNotPrimitiveProcedure;
    var raiseOperatorIsNotClosure = plt.baselib.exceptions.raiseOperatorIsNotClosure;
    var raiseUnimplementedPrimitiveError = plt.baselib.exceptions.raiseUnimplementedPrimitiveError;




    

    var testArgument = plt.baselib.check.testArgument;
    var testArity = plt.baselib.check.testArity;
    var makeCheckArgumentType = plt.baselib.check.makeCheckArgumentType;

    var checkOutputPort = plt.baselib.check.checkOutputPort;
    var checkString = plt.baselib.check.checkString;
    var checkSymbol = plt.baselib.check.checkSymbol;
    var checkProcedure = plt.baselib.check.checkProcedure;
    var checkNumber = plt.baselib.check.checkNumber;
    var checkReal = plt.baselib.check.checkReal;
    var checkNonNegativeReal = plt.baselib.check.checkNonNegativeReal;
    var checkNatural = plt.baselib.check.checkNatural;
    var checkInteger = plt.baselib.check.checkInteger;
    var checkRational = plt.baselib.check.checkRational;
    var checkPair = plt.baselib.check.checkPair;
    var checkList = plt.baselib.check.checkList;
    var checkVector = plt.baselib.check.checkVector;
    var checkBox = plt.baselib.check.checkBox;
    var checkMutableBox = plt.baselib.check.checkMutableBox;
    var checkInspector = plt.baselib.check.checkInspector;



    //////////////////////////////////////////////////////////////////////]
    // The MACHINE


    // This value will be dynamically determined.
    // See findStackLimit later in this file.
    var STACK_LIMIT_ESTIMATE = 100;


    var Machine = function() {
	this.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;
	this.val = undefined;
	this.proc = undefined;
	this.argcount = undefined;
	this.env = [];
	this.control = [];     // Arrayof (U Frame CallFrame PromptFrame)
	this.running = false;
	this.modules = {};     // String -> ModuleRecord
        this.mainModules = []; // Arrayof String
	this.params = {

	    // currentDisplayer: DomNode -> Void
	    // currentDisplayer is responsible for displaying to the browser.
	    'currentDisplayer': function(MACHINE, domNode) {
		$(domNode).appendTo(document.body);
	    },
	    
	    // currentErrorDisplayer: DomNode -> Void
	    // currentErrorDisplayer is responsible for displaying errors to the browser.
	    'currentErrorDisplayer': function(MACHINE, domNode) {
                $(domNode).appendTo(document.body);
	    },

            'currentInspector': plt.baselib.inspectors.DEFAULT_INSPECTOR,
	    
	    'currentOutputPort': new StandardOutputPort(),
	    'currentErrorPort': new StandardErrorPort(),
	    'currentSuccessHandler': function(MACHINE) {},
	    'currentErrorHandler': function(MACHINE, exn) {
                MACHINE.params.currentErrorDisplayer(
                    MACHINE,
                    toDomNode(exn));
            },
	    
	    'currentNamespace': {},
	    
	    // These parameters control how often
	    // control yields back to the browser
	    // for response.  The implementation is a
	    // simple PID controller.
	    //
	    // To tune this, adjust desiredYieldsPerSecond.
	    // Do no touch numBouncesBeforeYield or
	    // maxNumBouncesBeforeYield, because those
	    // are adjusted automatically by the
	    // recomputeMaxNumBouncesBeforeYield
	    // procedure.
	    'desiredYieldsPerSecond': 5,
	    'numBouncesBeforeYield': 2000,   // self-adjusting
	    'maxNumBouncesBeforeYield': 2000, // self-adjusting

	    'currentPrint': defaultCurrentPrint


	};
	this.primitives = Primitives;
    };




    // Approximately find the stack limit.
    // This function assumes, on average, five variables or
    // temporaries per stack frame.
    // This will never report a number greater than MAXIMUM_CAP.
    var findStackLimit = function(after) {
	var MAXIMUM_CAP = 100000;
	var n = 1;
	var limitDiscovered = false;
	setTimeout(
	    function() {
		if(! limitDiscovered) {
		    limitDiscovered = true;
		    after(n);
		}
	    },
	    0);
	var loop1 = function(x, y, z, w, k) {
	    // Ensure termination, just in case JavaScript ever
	    // does eliminate stack limits.
	    if (n >= MAXIMUM_CAP) { return; }
	    n++;
	    return 1 + loop2(y, z, w, k, x);
	};
	var loop2 = function(x, y, z, w, k) {
	    n++;
	    return 1 + loop1(y, z, w, k, x);
	};
	try {
	    var dontCare = 1 + loop1(2, "seven", [1], {number: 8}, 2);
	} catch (e) {
	    // ignore exceptions.
	}
	if (! limitDiscovered) { 
	    limitDiscovered = true;
	    after(n);
	}
    };


    // Schedule a stack limit estimation.  If it fails, no harm, no
    // foul (hopefully!)
    setTimeout(function() {
	findStackLimit(function(v) {
	    // Trying to be a little conservative.
	    STACK_LIMIT_ESTIMATE = Math.floor(v / 10);
	});
    },
	       0);


    // captureControl implements the continuation-capturing part of
    // call/cc.  It grabs the control frames up to (but not including) the
    // prompt tagged by the given tag.
    var captureControl = function(MACHINE, skip, tag) {
	var i;
	for (i = MACHINE.control.length - 1 - skip; i >= 0; i--) {
	    if (MACHINE.control[i].tag === tag) {
		return MACHINE.control.slice(i + 1,
					     MACHINE.control.length - skip);
	    }
	} 
	raise(MACHINE, new Error("captureControl: unable to find tag " + tag));
    };



    // restoreControl clears the control stack (up to, but not including the
    // prompt tagged by tag), and then appends the rest of the control frames.
    // At the moment, the rest of the control frames is assumed to be in the 
    // top of the environment.
    var restoreControl = function(MACHINE, tag) {
	var i;
	for (i = MACHINE.control.length - 1; i >= 0; i--) {
	    if (MACHINE.control[i].tag === tag) {
		MACHINE.control = 
		    MACHINE.control.slice(0, i+1).concat(
			MACHINE.env[MACHINE.env.length - 1]);
		return;
	    }
	}
	raise(MACHINE, new Error("restoreControl: unable to find tag " + tag));     

    };


    // Splices the list argument in the environment.  Adjusts MACHINE.argcount
    // appropriately.
    var spliceListIntoStack = function(MACHINE, depth) {
	var lst = MACHINE.env[MACHINE.env.length - 1 - depth];
	var vals = [];
	while(lst !== NULL) {
	    vals.push(lst.first);
	    lst = lst.rest;
	}
	vals.reverse();
	MACHINE.env.splice.apply(MACHINE.env,
				 [MACHINE.env.length - 1 - depth, 1].concat(vals));
	MACHINE.argcount = MACHINE.argcount + vals.length - 1;
    };


    // Unsplices a list from the MACHINE stack.
    var unspliceRestFromStack = function(MACHINE, depth, length) {
	var lst = NULL;
	var i;
	for (i = 0; i < length; i++) {
	    lst = makePair(MACHINE.env[MACHINE.env.length - depth - length + i], 
                           lst);
	}
	MACHINE.env.splice(MACHINE.env.length - depth - length,
			   length, 
			   lst);
	MACHINE.argcount = MACHINE.argcount - length + 1;
    };



    // recomputeGas: state number -> number
    var recomputeMaxNumBouncesBeforeYield = function(MACHINE, observedDelay) {
	// We'd like to see a delay of DESIRED_DELAY_BETWEEN_BOUNCES so
	// that we get MACHINE.params.desiredYieldsPerSecond bounces per
	// second.
	var DESIRED_DELAY_BETWEEN_BOUNCES = 
	    (1000 / MACHINE.params.desiredYieldsPerSecond);
	var ALPHA = 256;
	var delta = (ALPHA * ((DESIRED_DELAY_BETWEEN_BOUNCES -
			       observedDelay) / 
			      DESIRED_DELAY_BETWEEN_BOUNCES));
	MACHINE.params.maxNumBouncesBeforeYield = 
            Math.max(MACHINE.params.maxNumBouncesBeforeYield + delta,
                     1);
    };


    var HaltError = function(onHalt) {
        // onHalt: MACHINE -> void
        this.onHalt = onHalt || function(MACHINE) {};
    };


    var Pause = function(onPause) {
        // onPause: MACHINE -> void
        this.onPause = onPause || function(MACHINE) {};
    };

    var PAUSE = function(onPause) {
        throw(new Pause(onPause));
    };
    



    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    // The toplevel trampoline.
    //
    //
    // trampoline: MACHINE (MACHINE -> void) -> void
    //
    // All evaluation in Racketland happens in the context of this
    // trampoline.
    //
    var trampoline = function(MACHINE, initialJump) {
	var thunk = initialJump;
	var startTime = (new Date()).valueOf();
	MACHINE.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;
	MACHINE.params.numBouncesBeforeYield = 
	    MACHINE.params.maxNumBouncesBeforeYield;
	MACHINE.running = true;

	while(true) {
            try {
		thunk(MACHINE);
		break;
            } catch (e) {
                // There are a few kinds of things that can get thrown
                // during racket evaluation:
                //
                // functions: this gets thrown if the Racket code
                // realizes that the number of bounces has grown too
                // large.  The thrown function represents a restarter
                // function.  The running flag remains true.
                //
                // Pause: causes the machine evaluation to pause, with
                // the expectation that it will restart momentarily.
                // The running flag on the machine will remain true.
                //
                // HaltError: causes evaluation to immediately halt.
                // We schedule the onHalt function of the HaltError to
                // call afterwards.  The running flag on the machine
                // is set to false.
                //
                // Everything else: otherwise, we send the exception value
                // to the current error handler and exit.
                // The running flag is set to false.
		if (typeof(e) === 'function') {
                    thunk = e;
                    MACHINE.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;

		    if (MACHINE.params.numBouncesBeforeYield-- < 0) {
			recomputeMaxNumBouncesBeforeYield(
			    MACHINE,
			    (new Date()).valueOf() - startTime);
			setTimeout(
			    function() { trampoline(MACHINE, thunk); },
			    0);
			return;
		    } else {
                        continue;
                    }
		} else if (e instanceof Pause) {
                    var restart = function(thunk) {
		        setTimeout(
			    function() { trampoline(MACHINE, thunk); },
			    0);
                    };
                    e.onPause(restart);
                    return;
                } else if (e instanceof HaltError) {
		    MACHINE.running = false;
                    e.onHalt(MACHINE);
                    return;
                } else {
		    // General error condition: just exit out
		    // of the trampoline and call the current error handler.
		    MACHINE.running = false;
                    MACHINE.params.currentErrorHandler(MACHINE, e);
	            return;
		}
            }
	}
	MACHINE.running = false;
        setTimeout(
            function() { MACHINE.params.currentSuccessHandler(MACHINE); },
            0);
	return;
    };



    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////







    var defaultCurrentPrint = new Closure(
	function(MACHINE) {
            if(--MACHINE.callsBeforeTrampoline < 0) { 
                throw arguments.callee; 
            }
	    var elt = MACHINE.env[MACHINE.env.length - 1];
	    var outputPort = 
		MACHINE.params.currentOutputPort;
	    if (elt !== VOID) {
		outputPort.writeDomNode(MACHINE, toDomNode(elt, 'print'));
		outputPort.writeDomNode(MACHINE, toDomNode("\n", 'display'));
	    }
            return finalizeClosureCall(MACHINE, VOID);
	},
	1,
	[],
	"printer");





    var VariableReference = function(prefix, pos) {
        this.prefix = prefix;
        this.pos = pos;
    };



    // A continuation prompt tag labels a prompt frame.
    var ContinuationPromptTag = function(name) {
	this.name = name;
    };



    // There is a single, distinguished default continuation prompt tag
    // that's used to wrap around toplevel prompts.
    var DEFAULT_CONTINUATION_PROMPT_TAG = 
	new ContinuationPromptTag("default-continuation-prompt-tag");







    

    // Primitives are the set of primitive values.  Not all primitives
    // are coded here; several of them (including call/cc) are injected by
    // the bootstrapping code in compiler/boostrapped-primitives.rkt
    var Primitives = {};

    var installPrimitiveProcedure = function(name, arity, f) {
        Primitives[name] = f;
        Primitives[name].arity = arity;
        Primitives[name].displayName = name;
    };

    var installPrimitiveClosure = function(name, arity, f) {
        Primitives[name] = 
            new Closure(f, arity, [], name);
    };


    var installPrimitiveConstant = function(name, v) {
        Primitives[name] = v;
    };



    installPrimitiveConstant('pi', plt.baselib.numbers.pi);
    installPrimitiveConstant('e', plt.baselib.numbers.e);
    installPrimitiveConstant('null', NULL);


    installPrimitiveProcedure(
        'display', makeList(1, 2),
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    var outputPort = MACHINE.params.currentOutputPort;
	    if (MACHINE.argcount === 2) {
	        outputPort = checkOutputPort(MACHINE, 'display', 1);
	    }
	    outputPort.writeDomNode(MACHINE, toDomNode(firstArg, 'display'));
            return VOID;
        });

    installPrimitiveProcedure(
        'newline', makeList(0, 1),
        function(MACHINE) {
	    var outputPort = MACHINE.params.currentOutputPort;
	    if (MACHINE.argcount === 1) { 
	        outputPort = checkOutputPort(MACHINE, 'newline', 1);
	    }
	    outputPort.writeDomNode(MACHINE, toDomNode("\n", 'display'));
            return VOID;
        });

    installPrimitiveProcedure(
        'displayln',
        makeList(1, 2),
        function(MACHINE){
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    var outputPort = MACHINE.params.currentOutputPort;
	    if (MACHINE.argcount === 2) {
                outputPort = checkOutputPort(MACHINE, 'displayln', 1);
	    }
	    outputPort.writeDomNode(MACHINE, toDomNode(firstArg, 'display'));
	    outputPort.writeDomNode(MACHINE, toDomNode("\n", 'display'));
            return VOID;
        });



    installPrimitiveProcedure(
        'format',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
            var args = [], i, formatString;
            formatString = checkString(MACHINE, 'format', 0).toString();
            for(i = 1; i < MACHINE.argcount; i++) {
                args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
            }
            return plt.baselib.format.format(formatString, args, 'format');
        });


    installPrimitiveProcedure(
        'printf',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
            var args = [], i, formatString, result, outputPort;
            formatString = checkString(MACHINE, 'printf', 0).toString();
            for(i = 1; i < MACHINE.argcount; i++) {
                args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
            }
            result = plt.baselib.format.format(formatString, args, 'format');
            outputPort = MACHINE.params.currentOutputPort;            
	    outputPort.writeDomNode(MACHINE, toDomNode(result, 'display'));
            return VOID;
        });


    installPrimitiveProcedure(
        'fprintf',
        plt.baselib.arity.makeArityAtLeast(2),
        function(MACHINE) {
            var args = [], i, formatString, outputPort, result;
            outputPort = checkOutputPort(MACHINE, 'fprintf', 0);
            formatString = checkString(MACHINE, 'fprintf', 1).toString();
            for(i = 2; i < MACHINE.argcount; i++) {
                args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
            }
            result = plt.baselib.format.format(formatString, args, 'format');
	    outputPort.writeDomNode(MACHINE, toDomNode(result, 'display'));
            return VOID;
        });






    installPrimitiveProcedure(
        'current-print',
        makeList(0, 1),
        function(MACHINE) {
            if (MACHINE.argcount === 1) {
                MACHINE.params['currentPrint'] =                 
                    checkProcedure(MACHINE, 'current-print', 0);
                return VOID;
            } else {
	        return MACHINE.params['currentPrint'];
            }
        });


    installPrimitiveProcedure(
        'current-output-port',
        makeList(0, 1),
        function(MACHINE) {
            if (MACHINE.argcount === 1) {
                MACHINE.params['currentOutputPort'] = 
                    checkOutputPort(MACHINE, 'current-output-port', 0);
                return VOID;
            } else {
	        return MACHINE.params['currentOutputPort'];
            }
        });





    installPrimitiveProcedure(
        '=',
        plt.baselib.arity.makeArityAtLeast(2),
        function(MACHINE) {
	    var firstArg = checkNumber(MACHINE, '=', 0), secondArg;
	    for (var i = 1; i < MACHINE.argcount; i++) {
                var secondArg = checkNumber(MACHINE, '=', i);
	        if (! (plt.baselib.numbers.equals(firstArg, secondArg))) {
		    return false; 
	        }
	    }
	    return true;
        });


    
    installPrimitiveProcedure(
        '=~',
        3,
        function(MACHINE) {
	    var x = checkReal(MACHINE, '=~', 0);
	    var y = checkReal(MACHINE, '=~', 1);
	    var range = checkNonNegativeReal(MACHINE, '=~', 2);
            return plt.baselib.numbers.lessThanOrEqual(
                plt.baselib.numbers.abs(plt.baselib.numbers.subtract(x, y)), 
                range);
        });



    var makeChainingBinop = function(predicate, name) {
        return function(MACHINE) {
	    var firstArg = checkNumber(MACHINE, name, 0), secondArg;
	    for (var i = 1; i < MACHINE.argcount; i++) {
	        secondArg = checkNumber(MACHINE, name, i);
	        if (! (predicate(firstArg, secondArg))) {
		    return false; 
	        }
                firstArg = secondArg;
	    }
	    return true;
        };
    };

    installPrimitiveProcedure(
        '<',
        plt.baselib.arity.makeArityAtLeast(2),
        makeChainingBinop(plt.baselib.numbers.lessThan, '<'));


    installPrimitiveProcedure(
        '>',
        plt.baselib.arity.makeArityAtLeast(2),
        makeChainingBinop(plt.baselib.numbers.greaterThan, '>'));


    installPrimitiveProcedure(
        '<=',
        plt.baselib.arity.makeArityAtLeast(2),
        makeChainingBinop(plt.baselib.numbers.lessThanOrEqual, '<='));


    installPrimitiveProcedure(
        '>=',
        plt.baselib.arity.makeArityAtLeast(2),
        makeChainingBinop(plt.baselib.numbers.greaterThanOrEqual, '>='));
    

    installPrimitiveProcedure(
        '+',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    var result = 0;
	    var i = 0;
	    for (i = 0; i < MACHINE.argcount; i++) {
	        result = plt.baselib.numbers.add(
                    result, 
                    checkNumber(MACHINE, '+', i));
	    };
	    return result;
        });
    

    installPrimitiveProcedure(
        '*',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    var result = 1;
	    var i = 0;
	    for (i=0; i < MACHINE.argcount; i++) {
	        result = plt.baselib.numbers.multiply(
                    result, 
                    checkNumber(MACHINE, '*', i));
	    }
	    return result;
        });

    installPrimitiveProcedure(
        '-',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
	    if (MACHINE.argcount === 1) { 
	        return plt.baselib.numbers.subtract(
                    0, 
                    checkNumber(MACHINE, '-', 0));
	    }
	    var result = checkNumber(MACHINE, '-', 0);
	    for (var i = 1; i < MACHINE.argcount; i++) {
	        result = plt.baselib.numbers.subtract(
                    result, 
                    checkNumber(MACHINE, '-', i));
	    }
	    return result;
        });
    
    installPrimitiveProcedure(
        '/',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
	    var result = checkNumber(MACHINE, '/', 0);
	    for (var i = 1; i < MACHINE.argcount; i++) {
	        result = plt.baselib.numbers.divide(
                    result,
                    checkNumber(MACHINE, '/', i));
	    }
	    return result;
        });
    

    installPrimitiveProcedure(
        'add1',
        1,
        function(MACHINE) {
	    var firstArg = checkNumber(MACHINE, 'add1', 0);
	    return plt.baselib.numbers.add(firstArg, 1);
        });


    installPrimitiveProcedure(
        'sub1',
        1,
        function(MACHINE) {
	    var firstArg = checkNumber(MACHINE, 'sub1', 0);
	    return plt.baselib.numbers.subtract(firstArg, 1);
        });


    installPrimitiveProcedure(
        'zero?',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return plt.baselib.numbers.equals(firstArg, 0);
        });


    installPrimitiveProcedure(
        'cons',
        2,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
	    return makePair(firstArg, secondArg);
        });


    installPrimitiveProcedure(
        'list',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    var result = NULL;
	    for (var i = 0; i < MACHINE.argcount; i++) {
	        result = makePair(MACHINE.env[MACHINE.env.length - (MACHINE.argcount - i)],
		                  result);
	    }
	    return result;
        });

    installPrimitiveProcedure(
        'car',
        1,
        function(MACHINE) {
	    var firstArg = checkPair(MACHINE, 'car', 0);
	    return firstArg.first;
        });

    installPrimitiveProcedure(
        'cdr',
        1,
        function(MACHINE) {
	    var firstArg = checkPair(MACHINE, 'cdr', 0);
	    return firstArg.rest;
        });

    installPrimitiveProcedure(
        'pair?',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return isPair(firstArg);
        });

    installPrimitiveProcedure(
        'set-car!',
        2,
        function(MACHINE) {
	    var firstArg = checkPair(MACHINE, 'set-car!', 0);
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
	    firstArg.first = secondArg;
            return VOID;
        });


    installPrimitiveProcedure(
        'set-cdr!',
        2,
        function(MACHINE) {
	    var firstArg = checkPair(MACHINE, 'set-car!', 0);
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
	    firstArg.rest = secondArg;
            return VOID;
        });

    
    installPrimitiveProcedure(
        'not',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return (firstArg === false);
        });


    installPrimitiveProcedure(
        'null?',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return firstArg === NULL;
        });


    installPrimitiveProcedure(
        'vector',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    var i;
	    var result = [];
	    for (i = 0; i < MACHINE.argcount; i++) {
	        result.push(MACHINE.env[MACHINE.env.length-1-i]);
	    }
	    var newVector = makeVector.apply(null, result);
            return newVector;
        });


    installPrimitiveProcedure(
        'vector->list',
        1,
        function(MACHINE) {
	    var elts = checkVector(MACHINE, 'vector->list', 0).elts;
	    var i;
	    var result = NULL;
	    for (i = 0; i < elts.length; i++) {
	        result = makePair(elts[elts.length - 1 - i], result);
	    }
	    return result;
        });

    
    installPrimitiveProcedure(
        'list->vector',
        1,
        function(MACHINE) {
	    var firstArg = checkList(MACHINE, 'list->vector', 0);
	    var result = [];
	    while (firstArg !== NULL) {
	        result.push(firstArg.first);
	        firstArg = firstArg.rest;
	    }
            return makeVector.apply(null, result);
        });


    installPrimitiveProcedure(
        'vector-ref',
        2,
        function(MACHINE) {
	    var elts = checkVector(MACHINE, 'vector-ref', 0).elts;
	    var index = MACHINE.env[MACHINE.env.length-2];
	    return elts[index];
        });


    installPrimitiveProcedure(
        'vector-set!',
        3,
        function(MACHINE) {
	    var elts = checkVector(MACHINE, 'vector-set!', 0).elts;
            // FIXME: check out-of-bounds vector
	    var index = plt.baselib.numbers.toFixnum(
                checkNatural(MACHINE, 'vector-set!', 1));
	    var val = MACHINE.env[MACHINE.env.length - 1 - 2];
	    elts[index] = val;
	    return VOID;
        });


    installPrimitiveProcedure(
        'vector-length',
        1,
        function(MACHINE) {
	    return checkVector(MACHINE, 'vector-length', 0).elts.length;
        });


    installPrimitiveProcedure(
        'make-vector',
        makeList(1, 2),
        function(MACHINE) {
	    var value = 0;
	    var length = plt.baselib.numbers.toFixnum(
                checkNatural(MACHINE, 'make-vector', 0));
	    if (MACHINE.argcount == 2) {
	        value = MACHINE.env[MACHINE.env.length - 2];
	    }
	    var arr = [];
	    for(var i = 0; i < length; i++) {
	        arr[i] = value;
	    }
            return makeVector.apply(null, arr);
        });
    


    installPrimitiveProcedure(
        'symbol?',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return isSymbol(firstArg);
        });

    installPrimitiveProcedure(
        'symbol->string',
        1,
        function(MACHINE) {
	    var firstArg = checkSymbol(MACHINE, 'symbol->string', 0);
	    return firstArg.toString();
        });

    installPrimitiveProcedure(
        'string-append',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    var buffer = [];
	    var i;
	    for (i = 0; i < MACHINE.argcount; i++) {
	        buffer.push(checkString(MACHINE, 'string-append', i).toString());
	    }
	    return buffer.join('');
        });

    installPrimitiveProcedure(
        'string-length',
        1,
        function(MACHINE) {
	    var firstArg = checkString(MACHINE, 'string-length', 0).toString();
	    return firstArg.length;
        });
    
    installPrimitiveProcedure(
        'box',
        1,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    return makeBox(firstArg);
        });

    installPrimitiveProcedure(
        'unbox',
        1,
        function(MACHINE) {
	    var firstArg = checkBox(MACHINE, 'unbox', 0);
            return firstArg.ref();
        });

    installPrimitiveProcedure(
        'set-box!',
        2,
        function(MACHINE) {
	    var firstArg = checkMutableBox(MACHINE, 'set-box!', 0);
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
            firstArg.set(secondArg);
	    return VOID;
        });

    installPrimitiveProcedure(
        'void',
        plt.baselib.arity.makeArityAtLeast(0),
        function(MACHINE) {
	    return VOID;
        });

    installPrimitiveProcedure(
        'eq?',
        2,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
	    return firstArg === secondArg;
        });

    installPrimitiveProcedure(
        'equal?',
        2,
        function(MACHINE) {
	    var firstArg = MACHINE.env[MACHINE.env.length-1];
	    var secondArg = MACHINE.env[MACHINE.env.length-2];
	    return equals(firstArg, secondArg);
        });



    installPrimitiveProcedure(
        'member',
        2,
        function(MACHINE) {
	    var x = MACHINE.env[MACHINE.env.length-1];
	    var lst = MACHINE.env[MACHINE.env.length-2];
	    var originalLst = lst;
	    while (true) {
	        if (lst === NULL) {
		    return false;
	        }
	        if (! isPair(lst)) {
		    raiseArgumentTypeError(MACHINE,
                                           'member',
                                           'list',
                                           1,
                                           MACHINE.env[MACHINE.env.length - 1 - 1]);
	        }
	        if (equals(x, (lst.first))) {
		    return lst;
	        }
	        lst = lst.rest;
	    }	
        });
    


    installPrimitiveProcedure(
        'reverse',
        1,
        function(MACHINE) {
	    var rev = NULL;
	    var lst = MACHINE.env[MACHINE.env.length-1];
	    while(lst !== NULL) {
	        testArgument(MACHINE,
			     'pair', isPair, lst, 0, 'reverse');
	        rev = makePair(lst.first, rev);
	        lst = lst.rest;
	    }
	    return rev;
        });




    installPrimitiveProcedure(
        'abs',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.abs(
                checkNumber(MACHINE, 'abs', 0));
        });

    installPrimitiveProcedure(
        'acos',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.acos(
                checkNumber(MACHINE, 'acos', 0));
        });


    installPrimitiveProcedure(
        'asin',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.asin(
                checkNumber(MACHINE, 'asin', 0));
        });

    installPrimitiveProcedure(
        'sin',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.sin(
                checkNumber(MACHINE, 'sin', 0));
        });



    installPrimitiveProcedure(
        'sinh',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.sinh(
                checkNumber(MACHINE, 'sinh', 0));
        });


    installPrimitiveProcedure(
        'tan',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.tan(
                checkNumber(MACHINE, 'tan', 0));
        });

    

    installPrimitiveProcedure(
        'atan',
        makeList(1, 2),
        function(MACHINE) {
            if (MACHINE.argcount === 1) {
		return plt.baselib.numbers.atan(
                    checkNumber(MACHINE, 'atan', 0));
            } else {
                testArgument(MACHINE,
                             'number',
                             isNumber,
                             MACHINE.env[MACHINE.env.length - 1],
                             0,
                             'atan');
                testArgument(MACHINE,
                             'number',
                             isNumber,
                             MACHINE.env[MACHINE.env.length - 2],
                             1,
                             'atan');
                return plt.baselib.numbers.makeFloat(
		    Math.atan2(
                        plt.baselib.numbers.toFixnum(checkNumber(MACHINE, 'atan', 0)),
                        plt.baselib.numbers.toFixnum(checkNumber(MACHINE, 'atan', 1))));
            }
        });


    installPrimitiveProcedure(
        'angle',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.angle(
                checkNumber(MACHINE, 'angle', 0));
        });

    installPrimitiveProcedure(
        'magnitude',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.magnitude(
                checkNumber(MACHINE, 'magnitude', 0));
        });

    installPrimitiveProcedure(
        'conjugate',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.conjugate(
                checkNumber(MACHINE, 'conjugate', 0));
        });




    installPrimitiveProcedure(
        'cos',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.cos(
                checkNumber(MACHINE, 'cos', 0));
        });


    installPrimitiveProcedure(
        'cosh',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.cosh(
                checkNumber(MACHINE, 'cosh', 0));
        });

    installPrimitiveProcedure(
        'gcd',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
            var args = [], i, x;
            for (i = 0; i < MACHINE.argcount; i++) {
                args.push(checkNumber(MACHINE, 'gcd', i));
            }
            x = args.shift();
	    return plt.baselib.numbers.gcd(x, args);
        });

    installPrimitiveProcedure(
        'lcm',
        plt.baselib.arity.makeArityAtLeast(1),
        function(MACHINE) {
            var args = [], i, x;
            for (i = 0; i < MACHINE.argcount; i++) {
                args.push(checkNumber(MACHINE, 'lcm', i));
            }
            x = args.shift();
	    return plt.baselib.numbers.lcm(x, args);
        });




    installPrimitiveProcedure(
        'exp',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.exp(
                checkNumber(MACHINE, 'exp', 0));
        });


    installPrimitiveProcedure(
        'expt',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.expt(
                checkNumber(MACHINE, 'expt', 0),
                checkNumber(MACHINE, 'expt', 1));
        });


    installPrimitiveProcedure(
        'exact?',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.isExact(
                checkNumber(MACHINE, 'exact?', 0));
        });


    installPrimitiveProcedure(
        'integer?',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.isInteger(MACHINE.env[MACHINE.env.length - 1]);
        });



    installPrimitiveProcedure(
        'imag-part',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.imaginaryPart(
                checkNumber(MACHINE, 'imag-part', 0));
        });


    installPrimitiveProcedure(
        'real-part',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.realPart(
                checkNumber(MACHINE, 'real-part', 0));
        });


    installPrimitiveProcedure(
        'make-polar',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.makeComplexPolar(
                checkReal(MACHINE, 'make-polar', 0),
                checkReal(MACHINE, 'make-polar', 1));
        });


    installPrimitiveProcedure(
        'make-rectangular',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.makeComplex(
                checkReal(MACHINE, 'make-rectangular', 0),
                checkReal(MACHINE, 'make-rectangular', 1));
        });

    installPrimitiveProcedure(
        'modulo',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.modulo(
                checkInteger(MACHINE, 'modulo', 0),
                checkInteger(MACHINE, 'modulo', 1));
        });


    installPrimitiveProcedure(
        'remainder',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.remainder(
                checkInteger(MACHINE, 'remainder', 0),
                checkInteger(MACHINE, 'remainder', 1));
        });


    installPrimitiveProcedure(
        'quotient',
        2,
        function(MACHINE) {
            return plt.baselib.numbers.quotient(
                checkInteger(MACHINE, 'quotient', 0),
                checkInteger(MACHINE, 'quotient', 1));
        });



    installPrimitiveProcedure(
        'floor',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.floor(
                checkReal(MACHINE, 'floor', 0));
        });
    

    installPrimitiveProcedure(
        'ceiling',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.ceiling(
                checkReal(MACHINE, 'ceiling', 0));
        });
   

    installPrimitiveProcedure(
        'round',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.round(
                checkReal(MACHINE, 'round', 0));
        });
    

    installPrimitiveProcedure(
        'truncate',
        1,
        function(MACHINE) {
            var n = checkReal(MACHINE, 'truncate', 0);
	    if (plt.baselib.numbers.lessThan(n, 0)) {
		return plt.baselib.numbers.ceiling(n);
	    } else {
		return plt.baselib.numbers.floor(n);
	    }
        });
    

    installPrimitiveProcedure(
        'numerator',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.numerator(
                checkRational(MACHINE, 'numerator', 0));
        });


    installPrimitiveProcedure(
        'denominator',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.denominator(
                checkRational(MACHINE, 'denominator', 0));
        });


    installPrimitiveProcedure(
        'log',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.log(
                checkNumber(MACHINE, 'log', 0));
        });


    installPrimitiveProcedure(
        'sqr',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.sqr(
                checkNumber(MACHINE, 'sqr', 0));
        });




    installPrimitiveProcedure(
        'sqrt',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.sqrt(
                checkNumber(MACHINE, 'sqrt', 0));
        });



    installPrimitiveProcedure(
        'integer-sqrt',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.integerSqrt(
                checkInteger(MACHINE, 'integer-sqrt', 0));
        });



    installPrimitiveProcedure(
        'sgn',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.sign(
                checkInteger(MACHINE, 'sgn', 0));
        });


    installPrimitiveProcedure(
        'number->string',
        1,
        function(MACHINE) {
            return checkNumber(MACHINE, 'number->string', 0).toString();
        });


    installPrimitiveProcedure(
	'string->symbol',
	1,
	function(MACHINE) {
	    return makeSymbol(checkString(MACHINE, 'string->symbol', 0).toString());
	});


    installPrimitiveProcedure(
        'string->number',
        1,
        function(MACHINE) {
            return plt.baselib.numbers.fromString(
                checkString(MACHINE, 'string->number', 0).toString());
        });

    

    installPrimitiveClosure(
        'make-struct-type',
        makeList(4, 5, 6, 7, 8, 9, 10, 11),
        function(MACHINE) {
            withArguments(
                MACHINE,
                4,
                [false, 
	         NULL,
	         false,
	         false,
	         NULL,
	         false,
	         false],
                function(name, 
                         superType,
	                 initFieldCount,
	                 autoFieldCount,
	                 autoV,
	                 props,	 // FIXME: currently ignored
	                 inspector,  // FIXME: currently ignored
	                 procSpec,	 // FIXME: currently ignored
	                 immutables, // FIXME: currently ignored
	                 guard,      // FIXME: currently ignored
                         constructorName
                        ) {

                    // FIXME: typechecks.

                    var structType = plt.baselib.structs.makeStructureType(
                        name,
                        superType,
                        initFieldCount,
                        autoFieldCount,
                        autoV,
                        //props,
                        //inspector,
                        //procSpec,
                        //immutables,
                        guard);

                    var constructorValue = 
                        makePrimitiveProcedure(
                            constructorName,
                            plt.baselib.numbers.toFixnum(initFieldCount),
                            function(MACHINE) {
                                var args = [];
                                for(var i = 0; i < initFieldCount; i++) {
                                    args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
                                }
                                return structType.constructor.apply(null, args);
                            });

                    var predicateValue = 
                        makePrimitiveProcedure(
                            String(name) + "?",
                            1,
                            function(MACHINE) {
                                return structType.predicate(MACHINE.env[MACHINE.env.length - 1]);
                            });

                    var accessorValue = 
                        makePrimitiveProcedure(
                            String(name) + "-accessor",
                            2,
                            function(MACHINE) {
                                // FIXME: typechecks
                                return structType.accessor(
                                    MACHINE.env[MACHINE.env.length - 1],
                                    plt.baselib.numbers.toFixnum(MACHINE.env[MACHINE.env.length - 2]));
                            });
                    accessorValue.structType = structType;

                    var mutatorValue = 
                        makePrimitiveProcedure(
                            String(name) + "-mutator",
                            3,
                            function(MACHINE) {
                                // FIXME: typechecks
                                return structType.mutator(
                                    MACHINE.env[MACHINE.env.length - 1],
                                    plt.baselib.numbers.toFixnum(MACHINE.env[MACHINE.env.length - 2]),
                                    MACHINE.env[MACHINE.env.length - 3]);
                            });
                    mutatorValue.structType = structType;


                    finalizeClosureCall(MACHINE,
                                        structType,
                                        constructorValue,
                                        predicateValue,
                                        accessorValue,
                                        mutatorValue);
                });
        });
        

     installPrimitiveProcedure(
         'current-inspector',
         makeList(0, 1),
         function(MACHINE) {
            if (MACHINE.argcount === 1) {
                MACHINE.params['currentInspector'] = 
                    checkInspector(MACHINE, 'current-inspector', 0);
                return VOID;
            } else {
	        return MACHINE.params['currentInspector'];
            }
         }
     ); 


    installPrimitiveProcedure(
        'make-struct-field-accessor',
        makeList(2, 3),
        function(MACHINE){
            // FIXME: typechecks
            // We must guarantee that the ref argument is good.
            var structType = MACHINE.env[MACHINE.env.length - 1].structType;
            var index = MACHINE.env[MACHINE.env.length - 2];
            var name;
            if (MACHINE.argcount === 3) {
                name = String(MACHINE.env[MACHINE.env.length - 3]);
            } else {
                name = 'field' + index;
            }
            return makePrimitiveProcedure(
                name,
                1,
                function(MACHINE) {
                    return structType.accessor(
                        MACHINE.env[MACHINE.env.length - 1],
                        plt.baselib.numbers.toFixnum(index));
                });
            
        });


    installPrimitiveProcedure(
        'make-struct-field-mutator',
        makeList(2, 3),
        function(MACHINE){
            // FIXME: typechecks
            // We must guarantee that the set! argument is good.
            var structType = MACHINE.env[MACHINE.env.length - 1].structType;
            var index = MACHINE.env[MACHINE.env.length - 2];
            var name;
            if (MACHINE.argcount === 3) {
                name = String(MACHINE.env[MACHINE.env.length - 3]);
            } else {
                name = 'field' + index;
            }
            return makePrimitiveProcedure(
                name,
                2,
                function(MACHINE) {
                    return structType.mutator(
                        MACHINE.env[MACHINE.env.length - 1],
                        plt.baselib.numbers.toFixnum(index),
                        MACHINE.env[MACHINE.env.length - 2]);
                });            
        });






    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////






    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////

    // Implementation of the ready function.  This will fire off when
    // setReadyTrue is called.

    (function(scope) {
        scope.ready = function(f) {
            if (runtimeIsReady) {
                notifyWaiter(f);
            } else {
                readyWaiters.push(f);
            }
        };

        scope.setReadyTrue = function() {
            runtimeIsReady = true;
            while(runtimeIsReady && readyWaiters.length > 0) {
                notifyWaiter(readyWaiters.shift());
            }
        };

        scope.setReadyFalse = function() {
            runtimeIsReady = false;
        };


        var runtimeIsReady = false;
        var readyWaiters = [];
        var notifyWaiter = function(w) {
            w();
        };
    })(this);


    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////

    // Executes all programs that have been labeled as a main module
    var invokeMains = function(machine, succ, fail) {
        runtime.ready(function() {
            setReadyFalse();
            machine = machine || runtime.currentMachine;
            succ = succ || function() {};
            fail = fail || function() {};
            var mainModules = machine.mainModules.slice();
            var loop = function() {
                if (mainModules.length > 0) {
                    var nextModule = mainModules.shift();
                    nextModule.invoke(machine, loop, fail);
                } else {
                    setReadyTrue();
                    succ();
                }
            };
            setTimeout(loop, 0);
        });
    };

    // Looks up a name in any of the machine's main modules.
    var lookupInMains = function(name, machine) {
        machine = machine || runtime.currentMachine;
        for (var i = 0; i < machine.mainModules.length; i++) {
            var ns = machine.mainModules[i].getNamespace();
            if(ns.hasOwnProperty(name)) {
                return ns[name];
            }
        }
    };



    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////


    // Exports
    var exports = runtime;
    exports['currentMachine'] = new Machine();
    exports['invokeMains'] = invokeMains;
    exports['lookupInMains'] = lookupInMains;


    // installing new primitives
    exports['installPrimitiveProcedure'] = installPrimitiveProcedure;
    exports['installPrimitiveClosure'] = installPrimitiveClosure;
    exports['makePrimitiveProcedure'] = makePrimitiveProcedure;
    exports['Primitives'] = Primitives;
    
    exports['ready'] = ready;
    // Private: the runtime library will set this flag to true when
    // the library has finished loading.
    exports['setReadyTrue'] = setReadyTrue;
    exports['setReadyFalse'] = setReadyFalse;

    exports['Machine'] = Machine;
    exports['Frame'] = Frame;
    exports['CallFrame'] = CallFrame;
    exports['PromptFrame'] = PromptFrame;
    exports['Closure'] = Closure;
    exports['ModuleRecord'] = ModuleRecord;
    exports['VariableReference'] = VariableReference;
    exports['ContinuationPromptTag'] = ContinuationPromptTag;
    exports['DEFAULT_CONTINUATION_PROMPT_TAG'] = 
	DEFAULT_CONTINUATION_PROMPT_TAG;
    exports['NULL'] = NULL;
    exports['VOID'] = VOID;

    exports['NEGATIVE_ZERO'] = NEGATIVE_ZERO;
    exports['INF'] = INF;
    exports['NEGATIVE_INF'] = NEGATIVE_INF;
    exports['NAN'] = NAN;





    exports['testArgument'] = testArgument;
    exports['testArity'] = testArity;
    exports['makeCheckArgumentType'] = makeCheckArgumentType;


    exports['raise'] = raise;
    exports['raiseUnboundToplevelError'] = raiseUnboundToplevelError;
    exports['raiseArgumentTypeError'] = raiseArgumentTypeError;
    exports['raiseContextExpectedValuesError'] = raiseContextExpectedValuesError;
    exports['raiseArityMismatchError'] = raiseArityMismatchError;
    exports['raiseOperatorApplicationError'] = raiseOperatorApplicationError;
    exports['raiseOperatorIsNotPrimitiveProcedure'] = raiseOperatorIsNotPrimitiveProcedure;
    exports['raiseOperatorIsNotClosure'] = raiseOperatorIsNotClosure;
    exports['raiseUnimplementedPrimitiveError'] = raiseUnimplementedPrimitiveError;


    exports['captureControl'] = captureControl;
    exports['restoreControl'] = restoreControl;

    exports['trampoline'] = trampoline;
    exports['spliceListIntoStack'] = spliceListIntoStack;
    exports['unspliceRestFromStack'] = unspliceRestFromStack;


    exports['finalizeClosureCall'] = finalizeClosureCall;


    //////////////////////////////////////////////////////////////////////


    // Type constructors

    // numbers
    exports['makeList'] = makeList;
    exports['makePair'] = makePair;
    exports['makeVector'] = makeVector;
    exports['makeBox'] = makeBox;
    exports['makeFloat'] = makeFloat;
    exports['makeRational'] = makeRational;
    exports['makeBignum'] = makeBignum;
    exports['makeComplex'] = makeComplex;
    exports['makeSymbol'] = makeSymbol;


    // Type predicates
    exports['isPair'] = isPair;
    exports['isList'] = isList;
    exports['isVector'] = isVector;
    exports['isOutputPort'] = isOutputPort;
    exports['isOutputStringPort'] = isOutputStringPort;
    exports['isBox'] = isBox;
    exports['isString'] = isString;
    exports['isSymbol'] = isSymbol;
    exports['isNumber'] = isNumber;
    exports['isNatural'] = isNatural;
    exports['isReal'] = isReal;
    exports['equals'] = equals;

    exports['toDomNode'] = toDomNode;
    exports['toWrittenString'] = toWrittenString;
    exports['toDisplayedString'] = toDisplayedString;

    exports['ArityAtLeast'] = plt.baselib.arity.ArityAtLeast;
    exports['makeArityAtLeast'] = plt.baselib.arity.makeArityAtLeast;
    exports['isArityMatching'] = plt.baselib.arity.isArityMatching;

    exports['heir'] = heir;
    exports['makeClassPredicate'] = makeClassPredicate;

    exports['PAUSE'] = PAUSE;
    exports['HaltError'] = HaltError;



    exports['makeStructureType'] = plt.baselib.structs.makeStructureType;
    exports['Struct'] = plt.baselib.structs.Struct;
    exports['StructType'] = plt.baselib.structs.StructType;


})(this['plt']);