whalesong/js-assembler/runtime-src/baselib-modules.js
2012-02-27 18:34:44 -05:00

151 lines
4.7 KiB
JavaScript

/*jslint sub: true, vars: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
/*global plt*/
// Modules
(function (baselib, plt) {
'use strict';
var exports = {};
baselib.modules = exports;
var Namespace = function(modrec) {
this.modrec = modrec;
// string -> integer
// Returns the position within the prefix that we should be looking.
this.mapping = {};
this.prefix = void(0);
this.extra = {};
};
Namespace.prototype.get = function(name) {
if (this.mapping.hasOwnProperty(name)) {
return this.prefix[this.mapping[name]];
}
if (this.extra.hasOwnProperty(name)) {
return this.extra[name];
}
return void(0);
};
Namespace.prototype.refreshPrefixMapping = function() {
var prefix = this.modrec.prefix;
var name;
var i;
for (i = 0; i < prefix.length; i++) {
name = prefix.names[i];
this.mapping[name] = i;
if (this.extra.hasOwnProperty(name)) {
prefix[i] = this.extra[name];
delete this.extra[name];
}
}
this.prefix = prefix;
};
Namespace.prototype.hasKey = function(name) {
return this.mapping.hasOwnProperty(name);
};
Namespace.prototype.set = function(name, value) {
if (this.mapping.hasOwnProperty(name)) {
this.prefix[this.mapping[name]] = value;
return;
};
if (this.extra.hasOwnProperty(name)) {
this.extra[name] = value;
return;
}
this.extra[name] = value;
return;
};
var ModuleRecord = function (name, label) {
this.name = name;
this.label = label;
this.isInvoked = false;
this.prefix = false;
this.namespace = new Namespace(this);
// JavaScript-implemented code will assign privateExports
// with all of the exported identifiers.
this.privateExports = {};
};
// Returns the offset into the prefix in which the value will be stored.
ModuleRecord.prototype.getPrefixOffset = function(externalName) {
var i;
for (i = 0; i < this.prefix.names.length; i++) {
if (this.prefix.names[i] === externalName) {
return i;
}
}
return void(0);
};
// Returns access to the names defined in the module.
ModuleRecord.prototype.getNamespace = function () {
return this.namespace;
};
ModuleRecord.prototype.finalizeModuleInvokation = function () {
this.namespace.refreshPrefixMapping();
};
// External invokation of a module.
ModuleRecord.prototype.invoke = function (MACHINE, succ, fail) {
this._invoke(false, MACHINE, succ, fail);
};
// Internal invokation of a module.
ModuleRecord.prototype.internalInvoke = function (MACHINE, succ, fail) {
this._invoke(true, MACHINE, succ, fail);
};
// Private: general invokation of a module
ModuleRecord.prototype._invoke = function (isInternal, MACHINE, succ, fail) {
var that = this;
MACHINE = MACHINE || plt.runtime.currentMachine;
succ = succ || function () {};
fail = fail || function () {};
var oldErrorHandler = MACHINE.params['currentErrorHandler'];
var afterGoodInvoke = function (MACHINE) {
MACHINE.params['currentErrorHandler'] = oldErrorHandler;
if (isInternal) { succ(); }
else {
throw new plt.runtime.HaltError(succ)
}
};
if (this.isInvoked) {
succ();
} else {
if (isInternal) {
MACHINE.params['currentErrorHandler'] = function (MACHINE, anError) {
MACHINE.params['currentErrorHandler'] = oldErrorHandler;
fail(MACHINE, anError);
};
MACHINE.c.push(new plt.baselib.frames.CallFrame(afterGoodInvoke, null));
throw that.label;
} else {
MACHINE.exclusiveLock.acquire(
void(0),
function(release) {
MACHINE.params['currentErrorHandler'] = function (MACHINE, anError) {
MACHINE.params['currentErrorHandler'] = oldErrorHandler;
fail(MACHINE, anError);
};
MACHINE.c.push(new plt.baselib.frames.CallFrame(afterGoodInvoke, null));
MACHINE._trampoline(that.label, false, release);
});
}
}
};
exports.ModuleRecord = ModuleRecord;
}(this.plt.baselib, this.plt));