Comparing version 0.0.3 to 0.0.4
@@ -67,3 +67,5 @@ var fs = require('fs'), | ||
Builder.prototype.writeFile = function writeFile(name){ | ||
write(name, this.combine()); | ||
var src = this.combine(); | ||
write(name+'.js', src); | ||
write(name+'.min.js', minify(src)); | ||
} | ||
@@ -93,16 +95,69 @@ | ||
builder.addDirectory('../builtins', function(name, source){ | ||
if (name === 'index') { | ||
return ''; | ||
} else { | ||
if (name[0] === '@') { | ||
return 'exports.modules["'+name+'"] = '+escapeJS(source) + ';'; | ||
} else { | ||
return 'exports.builtins.'+name+' = '+escapeJS(source) + ';'; | ||
} | ||
} | ||
builder.addDirectory('../modules', function(name, source){ | ||
return name === 'index' ? '' : 'exports.modules["'+name+'"] = '+escapeJS(source) + ';'; | ||
}); | ||
builder.addFiles('./footer.js'); | ||
builder.writeFile('../continuum-combined.js'); | ||
var esprima, esmangle, escodegen, passes, post; | ||
function minify(src){ | ||
esprima = esprima || require('esprima'); | ||
escodegen = escodegen || require('escodegen'); | ||
esmangle = esmangle || require('esmangle'); | ||
passes = passes || [ | ||
esmangle.require('lib/pass/transform-dynamic-to-static-property-access'), | ||
esmangle.require('lib/pass/reordering-function-declarations'), | ||
esmangle.require('lib/pass/remove-unused-label'), | ||
esmangle.require('lib/pass/remove-empty-statement'), | ||
esmangle.require('lib/pass/remove-wasted-blocks'), | ||
esmangle.require('lib/pass/transform-to-compound-assignment'), | ||
esmangle.require('lib/pass/transform-to-sequence-expression'), | ||
esmangle.require('lib/pass/transform-branch-to-expression'), | ||
esmangle.require('lib/pass/reduce-sequence-expression'), | ||
esmangle.require('lib/pass/reduce-branch-jump'), | ||
esmangle.require('lib/pass/reduce-multiple-if-statements'), | ||
esmangle.require('lib/pass/dead-code-elimination') | ||
]; | ||
post = post || [ | ||
esmangle.require('lib/post/transform-static-to-dynamic-property-access'), | ||
esmangle.require('lib/post/rewrite-boolean'), | ||
esmangle.require('lib/post/rewrite-conditional-expression') | ||
]; | ||
function passer(node, pass){ return pass(node) } | ||
var a = { loc: true }, | ||
b = { destructive: true }, | ||
c = { | ||
comment: false, | ||
allowUnparenthesizedNew: true, | ||
format: { | ||
indent: { | ||
style: ' ', | ||
base: 0, | ||
adjustMultilineComment: false | ||
}, | ||
json: false, | ||
renumber: true, | ||
hexadecimal: true, | ||
quotes: 'single', | ||
escapeless: false, | ||
compact: true, | ||
parentheses: true, | ||
semicolons: true, | ||
safeConcatenation: true | ||
} | ||
}, | ||
parse = esprima.parse, | ||
mangle = esmangle.mangle, | ||
optimize = esmangle.optimize, | ||
generate = escodegen.generate; | ||
return generate(mangle(post.reduce(passer, optimize(parse(src, a), passes, b)), b), c); | ||
} | ||
builder.writeFile('../continuum'); |
@@ -1,13 +0,20 @@ | ||
return (function(Realm){ | ||
function continuum(listener){ | ||
return new Realm(listener); | ||
} | ||
var continuum = { | ||
createBytecode : exports.runtime.createBytecode, | ||
createNativeFunction: exports.runtime.createNativeFunction, | ||
createRealm : exports.runtime.createRealm, | ||
createRenderer : exports.debug.createRenderer, | ||
introspect : exports.debug.introspect | ||
}; | ||
continuum.debug = exports.debug; | ||
continuum.utility = exports.utility; | ||
continuum.constants = exports.constants; | ||
continuum.Realm = Realm; | ||
exports.utility.define(continuum, { | ||
Assembler : exports.assembler.Assembler, | ||
Realm : exports.runtime.Realm, | ||
Renderer : exports.debug.Renderer, | ||
Script : exports.runtime.Script, | ||
ScriptFile: exports.runtime.ScriptFile, | ||
constants : exports.constants, | ||
utility : exports.utility | ||
}); | ||
return continuum; | ||
})(exports.runtime.Realm); | ||
@@ -22,3 +29,3 @@ }).apply(this, function(){ | ||
return [exports, require]; | ||
return [this, exports, require]; | ||
}()); |
@@ -1,1 +0,1 @@ | ||
continuum = (function(exports, require, module){ | ||
continuum = (function(global, exports, require, module){ |
@@ -1,2 +0,2 @@ | ||
(function(global, Realm, constants, utility, debug){ | ||
(function(global, continuum, constants, utility){ | ||
var inherit = utility.inherit, | ||
@@ -6,2 +6,3 @@ create = utility.create, | ||
define = utility.define, | ||
each = utility.each, | ||
isObject = utility.isObject; | ||
@@ -44,2 +45,10 @@ | ||
function forward(o, from, to){ | ||
Object.defineProperty(o, to, { | ||
configurable: true, | ||
get: function(){ return this[from] }, | ||
set: function(v){ this[from] = v } | ||
}); | ||
return o; | ||
} | ||
@@ -49,4 +58,3 @@ try { | ||
var Event = global.Event; | ||
} | ||
catch (e) { | ||
} catch (e) { | ||
var Event = (function(E){ | ||
@@ -62,15 +70,13 @@ function EventInit(type, o){ | ||
EventInit.prototype = assign(create(null), { bubbles: true, cancelable: true, type: '' }); | ||
EventInit.prototype = assign(create(null), eventOptions); | ||
EventInit.prototype.type = ''; | ||
if ('createEvent' in document) { | ||
var Event = (function(){ | ||
function Event(type, dict){ | ||
dict = new EventInit(type, dict); | ||
var evt = document.createEvent('Event'); | ||
evt.initEvent(dict.type, dict.bubbles, dict.cancelable); | ||
return evt; | ||
} | ||
return Event; | ||
})(); | ||
var Event = function Event(type, dict){ | ||
dict = new EventInit(type, dict); | ||
var evt = document.createEvent('Event'); | ||
evt.initEvent(dict.type, dict.bubbles, dict.cancelable); | ||
return evt; | ||
}; | ||
} else { | ||
@@ -87,2 +93,12 @@ var Event = (function(){ | ||
} | ||
function preventDefault(){ | ||
this.returnValue = false; | ||
} | ||
define(E.prototype, preventDefault); | ||
forward(E.prototype, 'screenX', 'pageX'); | ||
forward(E.prototype, 'screenY', 'pageY'); | ||
return Event; | ||
@@ -101,20 +117,23 @@ })(); | ||
function Component(tag){ | ||
if (typeof tag === 'string') { | ||
this.element = _(tag); | ||
} else { | ||
this.element = tag; | ||
var Component = (function(){ | ||
var textContent = 'textContent' in document.body ? 'textContent' : 'innerText'; | ||
function Component(tag){ | ||
if (typeof tag === 'string') { | ||
this.element = _(tag); | ||
} else { | ||
this.element = tag; | ||
} | ||
if (this.element.classList) { | ||
this.classes = this.element.classList; | ||
} | ||
this.styles = this.element.style; | ||
this.element.component = this; | ||
} | ||
if (this.element.classList) { | ||
this.classes = this.element.classList; | ||
} | ||
this.styles = this.element.style; | ||
this.element.component = this; | ||
} | ||
define(Component.prototype, { | ||
ns: 'ƒ' | ||
}); | ||
define(Component.prototype, { | ||
ns: 'ƒ' | ||
}); | ||
void function(){ | ||
define(Component.prototype, [ | ||
@@ -152,3 +171,11 @@ function append(subject){ | ||
} | ||
this.element.removeChild(subject); | ||
if (subject && subject.parentNode) { | ||
if (subject.parentNode === this.element) { | ||
this.element.removeChild(subject); | ||
} | ||
} else if (subject === this.element.parentNode) { | ||
subject.removeChild(this.element); | ||
} else { | ||
console.dir(subject); | ||
} | ||
} | ||
@@ -216,3 +243,4 @@ }, | ||
function getMetric(name){ | ||
return parseFloat(this.getComputed(name)); | ||
var v = this.getComputed(name); | ||
return v === 'auto' ? 0 : parseFloat(v); | ||
}, | ||
@@ -273,8 +301,15 @@ function getComputed(name){ | ||
} | ||
}, | ||
function text(value){ | ||
if (value === undefined) { | ||
return this.element[textContent]; | ||
} else { | ||
this.element[textContent] = value; | ||
return this; | ||
} | ||
} | ||
]); | ||
}(); | ||
if (document.body.classList) { | ||
void function(){ | ||
if (document.body.classList) { | ||
define(Component.prototype, [ | ||
@@ -298,49 +333,49 @@ function addClass(name, noNS){ | ||
]); | ||
}(); | ||
} else { | ||
void function(cache){ | ||
function matcher(n){ | ||
if (!(n in cache)) { | ||
cache[n] = new RegExp('(.*)(?:^'+n+'\\s|\\s'+n+'$|\\s'+n+'\\s)(.*)'); | ||
} | ||
return cache[n]; | ||
} | ||
} else { | ||
void function(){ | ||
var cache = create(null); | ||
define(Component.prototype, [ | ||
function addClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
var className = this.element.className; | ||
if (!matcher(name).test(className)) { | ||
this.element.className = className + ' ' + name; | ||
function matcher(n){ | ||
if (!(n in cache)) { | ||
cache[n] = new RegExp('(.*)(?:^'+n+'\\s|\\s'+n+'$|\\s'+n+'\\s)(.*)'); | ||
} | ||
return this; | ||
}, | ||
function removeClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
var p = this.element.className.match(matcher(name)); | ||
if (p) { | ||
this.element.className = p[1] ? p[2] ? p[1]+' '+p[2] : p[1] : p[2]; | ||
} | ||
return this; | ||
}, | ||
function toggleClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
if (this.hasClass(name)) { | ||
this.removeClass(name); | ||
} else { | ||
this.addClass(name); | ||
} | ||
return this; | ||
}, | ||
function hasClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
return matcher(name).test(this.element.className); | ||
return cache[n]; | ||
} | ||
]); | ||
}(create(null)); | ||
} | ||
define(Component.prototype, [ | ||
function addClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
var className = this.element.className; | ||
if (!matcher(name).test(className)) { | ||
this.element.className = className + ' ' + name; | ||
} | ||
return this; | ||
}, | ||
function removeClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
var p = this.element.className.match(matcher(name)); | ||
if (p) { | ||
this.element.className = p[1] ? p[2] ? p[1]+' '+p[2] : p[1] : p[2]; | ||
} | ||
return this; | ||
}, | ||
function toggleClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
if (this.hasClass(name)) { | ||
this.removeClass(name); | ||
} else { | ||
this.addClass(name); | ||
} | ||
return this; | ||
}, | ||
function hasClass(name, noNS){ | ||
if (!noNS) name = this.ns+name; | ||
return matcher(name).test(this.element.className); | ||
} | ||
]); | ||
}(); | ||
} | ||
if ('dispatchEvent' in document.body) { | ||
void function(){ | ||
if ('dispatchEvent' in document.body) { | ||
define(Component.prototype, [ | ||
@@ -372,2 +407,3 @@ function on(event, listener, receiver){ | ||
receiver = receiver || this; | ||
function bound(e){ | ||
@@ -377,2 +413,3 @@ this.removeEventListener(event, bound, false); | ||
} | ||
this.element.addEventListener(event, bound, false); | ||
@@ -396,114 +433,89 @@ return this; | ||
]); | ||
}(); | ||
} else { | ||
void function(){ | ||
var realEvents = create(null); | ||
utility.iterate([ | ||
'activate', 'afterupdate', 'beforeactivate', 'beforecopy', 'beforecut', 'beforedeactivate', 'beforeeditfocus', | ||
'beforepaste', 'beforeupdate', 'blur', 'cellchange', 'click', 'contextmenu', 'controlselect', 'copy', | ||
'dataavailable', 'datasetchanged', 'datasetcomplete', 'dblclick', 'deactivate', 'drag', 'dragend', 'dragenter', | ||
'dragleave', 'dragover', 'dragstart', 'drop', 'errorupdate', 'filterchange', 'focus', 'focusin', 'focusout', | ||
'help', 'keydown', 'keyup', 'losecapture', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', | ||
'mouseup', 'mousewheel', 'move', 'moveend', 'movestart', 'paste', 'propertychange', 'readystatechange', 'resize', | ||
'resizeend', 'resizestart', 'rowenter', 'rowexit', 'rowsdelete', 'rowsinserted', 'scroll', 'selectstart' | ||
], function(name){ realEvents[name] = true }); | ||
} else { | ||
void function(){ | ||
var realEvents = create(null); | ||
each([ | ||
'activate', 'afterupdate', 'beforeactivate', 'beforecopy', 'beforecut', 'beforedeactivate', | ||
'beforeeditfocus', 'beforepaste', 'beforeupdate', 'blur', 'cellchange', 'click', 'contextmenu', | ||
'controlselect', 'copy', 'dataavailable', 'datasetchanged', 'datasetcomplete', 'dblclick', | ||
'deactivate', 'drag', 'dragend', 'dragenter', 'dragleave', 'dragover', 'dragstart', 'drop', | ||
'errorupdate', 'filterchange', 'focus', 'focusin', 'focusout', 'help', 'keydown', 'keyup', | ||
'losecapture', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseup', | ||
'mousewheel', 'move', 'moveend', 'movestart', 'paste', 'propertychange', 'readystatechange', | ||
'resize', 'resizeend', 'resizestart', 'rowenter', 'rowexit', 'rowsdelete', 'rowsinserted', | ||
'scroll', 'selectstart' | ||
], function(name){ realEvents[name] = true }); | ||
define(Component.prototype, [ | ||
function on(event, listener, receiver){ | ||
if (typeof listener !== 'function') { | ||
for (var k in listener) { | ||
this.on(k, listener[k], receiver) | ||
define(Component.prototype, [ | ||
function on(event, listener, receiver){ | ||
if (typeof listener !== 'function') { | ||
for (var k in listener) { | ||
this.on(k, listener[k], receiver) | ||
} | ||
return this; | ||
} | ||
return this; | ||
} | ||
receiver || (receiver = this); | ||
receiver || (receiver = this); | ||
var real = event in realEvents; | ||
var real = event in realEvents; | ||
if (real) { | ||
var bound = function(e){ return listener.call(receiver, e) }; | ||
} else { | ||
var bound = function(e){ | ||
e = e.srcElement.customEvent; | ||
if (e && !e.expired && e.type === event) { | ||
if (real) { | ||
var bound = function(e){ | ||
return listener.call(receiver, e); | ||
} | ||
}; | ||
} | ||
}; | ||
} else { | ||
var bound = function(e){ | ||
e = e.srcElement.customEvent; | ||
if (e && !e.expired && e.type === event) { | ||
return listener.call(receiver, e); | ||
} | ||
}; | ||
} | ||
define(listener, bound); | ||
if (real) { | ||
define(listener, 'bound', bound); | ||
event = real ? event : 'propertychange'; | ||
this.element.attachEvent('on'+event, bound); | ||
} else { | ||
this.element.attachEvent('onpropertychange', bound); | ||
} | ||
return this; | ||
}, | ||
function off(event, listener){ | ||
event = event in realEvents ? event : 'propertychange'; | ||
this.element.detachEvent('on'+event, listener.bound); | ||
delete listener.bound; | ||
return this; | ||
}, | ||
function once(event, listener, receiver){ | ||
function one(e){ | ||
this.off(event, one); | ||
return listener.call(receiver, e); | ||
} | ||
this.on(event, one, this); | ||
return this; | ||
}, | ||
function emit(event, data){ | ||
if (typeof event === 'string') { | ||
var opts = data && data.bubbles === false ? noBubbleEventOptions : eventOptions; | ||
event = new Event(event, opts); | ||
} | ||
return this; | ||
}, | ||
function off(event, listener){ | ||
event = event in realEvents ? event : 'propertychange'; | ||
this.element.detachEvent('on'+event, listener.bound); | ||
delete listener.bound; | ||
return this; | ||
}, | ||
function once(event, listener, receiver){ | ||
function one(e){ | ||
this.off(event, one); | ||
return listener.call(receiver, e); | ||
} | ||
this.on(event, one, this); | ||
return this; | ||
}, | ||
function emit(event, data){ | ||
if (typeof event === 'string') { | ||
var opts = data && data.bubbles === false ? noBubbleEventOptions : eventOptions; | ||
event = new Event(event, opts); | ||
} | ||
if (data) { | ||
for (var k in data) { | ||
event[k] = data[k]; | ||
if (data) { | ||
for (var k in data) { | ||
event[k] = data[k]; | ||
} | ||
} | ||
} | ||
if (event in realEvents) { | ||
return this.element.fireEvent(event); | ||
} else { | ||
this.element.customEvent = event; | ||
event.expired = true; | ||
return event.returnValue === undefined ? true : event.returnValue; | ||
if (event in realEvents) { | ||
return this.element.fireEvent(event); | ||
} else { | ||
this.element.customEvent = event; | ||
event.expired = true; | ||
return event.returnValue === undefined ? true : event.returnValue; | ||
} | ||
} | ||
} | ||
]); | ||
}(); | ||
} | ||
]); | ||
}(); | ||
} | ||
return Component; | ||
})(); | ||
if ('textContent' in document.body) { | ||
void function(){ | ||
define(Component.prototype, [ | ||
function text(value){ | ||
if (value === undefined) { | ||
return this.element.textContent; | ||
} else { | ||
this.element.textContent = value; | ||
return this; | ||
} | ||
} | ||
]); | ||
}(); | ||
} else { | ||
void function(){ | ||
define(Component.prototype, [ | ||
function text(value){ | ||
if (value === undefined) { | ||
return this.element.innerText; | ||
} else { | ||
this.element.innerText = value; | ||
return this; | ||
} | ||
} | ||
]); | ||
}(); | ||
} | ||
@@ -596,3 +608,3 @@ | ||
container.style({ | ||
paddingRight: parseFloat(container.getComputed('paddingRight')) + scrollbarWidth, | ||
paddingRight: container.getMetric('paddingRight') + scrollbarWidth, | ||
overflowY: 'auto' | ||
@@ -627,15 +639,14 @@ }); | ||
this.down.on('mousedown', function(e){ | ||
e.preventDefault(); | ||
self.repeat(.005, 15); | ||
this.addClass('scrolling'); | ||
e.preventDefault(); | ||
}); | ||
this.up.on('mousedown', function(e){ | ||
e.preventDefault(); | ||
self.repeat(-.005, 15); | ||
this.addClass('scrolling'); | ||
e.preventDefault(); | ||
}); | ||
this.track.on('mousedown', function(e){ | ||
e.preventDefault(); | ||
var compare = e.pageY > self.thumb.bottom() ? 1 : e.pageY < self.thumb.top() ? -1 : 0; | ||
@@ -646,2 +657,3 @@ if (compare) { | ||
} | ||
e.preventDefault(); | ||
}); | ||
@@ -661,2 +673,3 @@ | ||
self.repeating = true; | ||
body.once('mouseup', function(){ | ||
@@ -668,2 +681,3 @@ if (self.repeating) { | ||
}); | ||
body.once('click', function(){ | ||
@@ -675,3 +689,4 @@ if (self.repeating) { | ||
}); | ||
setTimeout(function repeat(){ | ||
function loop(){ | ||
if (self.repeating) { | ||
@@ -681,3 +696,3 @@ var percent = max(min(self.percent() + amount, 1), 0); | ||
if (percent !== 1 && percent !== 0) { | ||
setTimeout(repeat, speed); | ||
setTimeout(loop, speed); | ||
} else if (self.repeating) { | ||
@@ -688,3 +703,5 @@ self.repeating = false; | ||
} | ||
}, 100); | ||
} | ||
setTimeout(loop, 100); | ||
}, | ||
@@ -847,3 +864,2 @@ function scrollHeight(){ | ||
body.append(this.element); | ||
var computed = getComputedStyle(this.element); | ||
this.size = 1; | ||
@@ -958,4 +974,3 @@ update(); | ||
function grab(e){ | ||
e.preventDefault(); | ||
document.body.appendChild(this.element); | ||
body.append(this); | ||
this.x = e.pageX; | ||
@@ -970,2 +985,3 @@ this.y = e.pageY; | ||
}); | ||
e.preventDefault(); | ||
}, | ||
@@ -977,3 +993,3 @@ function drag(e){ | ||
if (this.element.parentNode) { | ||
document.body.removeChild(this.element); | ||
body.remove(this); | ||
this.emit('drop', this.calculate(e)); | ||
@@ -1163,14 +1179,14 @@ } | ||
keyboard.on('Enter', 'activate', function(e){ | ||
self.entry(); | ||
e.preventDefault(); | ||
self.entry(); | ||
}); | ||
keyboard.on('Up', 'activate', function(e){ | ||
self.previous(); | ||
e.preventDefault(); | ||
self.previous(); | ||
}); | ||
keyboard.on('Down', 'activate', function(e){ | ||
self.next(); | ||
e.preventDefault(); | ||
self.next(); | ||
}); | ||
@@ -1416,7 +1432,7 @@ | ||
function disable(){ | ||
this.codemirror.readonly(true); | ||
this.codemirror.setOption('readOnly', true); | ||
this.disabled = true; | ||
}, | ||
function enable(){ | ||
this.codemirror.readonly(false); | ||
this.codemirror.setOption('readOnly', false); | ||
this.disabled = false; | ||
@@ -1614,11 +1630,12 @@ } | ||
var Proto = (function(){ | ||
function Proto(mirror){ | ||
function createSpecialProperty(label, classname, callback){ | ||
var SpecialProperty = function(mirror){ | ||
Component.call(this, 'li'); | ||
this.mirror = mirror; | ||
this.addClass('property'); | ||
this.key = new Key('[[proto]]'); | ||
this.key.addClass('Proto'); | ||
this.key = new Key(label); | ||
this.key.addClass(classname); | ||
this.append(this.key); | ||
this.prop = mirror.getPrototype(); | ||
this.prop = callback(mirror); | ||
this.property = renderer.render(this.prop); | ||
@@ -1630,7 +1647,7 @@ this.append(this.property); | ||
inherit(Proto, Property, [ | ||
inherit(SpecialProperty, Property, [ | ||
function refresh(){ | ||
var proto = this.mirror.getPrototype(); | ||
if (this.prop !== proto) { | ||
this.prop = proto; | ||
var prop = callback(this.mirror); | ||
if (this.prop !== prop) { | ||
this.prop = prop; | ||
this.element.removeChild(this.element.lastElementChild); | ||
@@ -1642,5 +1659,9 @@ this.append(renderer.render(this.property)); | ||
return Proto; | ||
})(); | ||
return SpecialProperty; | ||
} | ||
var Scope = createSpecialProperty('[[scope]]', 'FunctionScope', function(mirror){ return mirror.getScope() }); | ||
var Proto = createSpecialProperty('[[proto]]', 'Proto', function(mirror){ return mirror.getPrototype() }); | ||
var Env = createSpecialProperty('[[env]]', 'Env', function(mirror){ return mirror.getEnvironment() }); | ||
var Outer = createSpecialProperty('[[outer]]', 'Outer', function(mirror){ return mirror.getPrototype() }); | ||
@@ -1771,3 +1792,3 @@ var PreviewProperty = (function(){ | ||
this.append(_('div')); | ||
this.append(tree); | ||
this.tree = this.append(tree); | ||
} | ||
@@ -1779,2 +1800,11 @@ } | ||
this.result.refresh(); | ||
}, | ||
function expand(){ | ||
this.result.expand(); | ||
}, | ||
function contract(){ | ||
this.result.contract(); | ||
}, | ||
function toggle(){ | ||
this.result.toggle(); | ||
} | ||
@@ -1965,2 +1995,6 @@ ]); | ||
return this; | ||
}, | ||
function initTree(){ | ||
Branch.prototype.initTree.call(this); | ||
this.tree.append(new Scope(this.mirror)); | ||
} | ||
@@ -1973,2 +2007,49 @@ ]); | ||
var GlobalBranch = (function(){ | ||
function GlobalBranch(mirror){ | ||
Branch.call(this, mirror); | ||
} | ||
creator(GlobalBranch); | ||
inherit(GlobalBranch, Branch, [ | ||
function initTree(){ | ||
Branch.prototype.initTree.call(this); | ||
if (this.mirror.subject.env.outer) { | ||
this.tree.append(new Env(this.mirror)); | ||
} | ||
} | ||
]); | ||
return GlobalBranch; | ||
})(); | ||
var ScopeBranch = (function(){ | ||
function ScopeBranch(mirror){ | ||
Branch.call(this, mirror); | ||
} | ||
creator(ScopeBranch); | ||
inherit(ScopeBranch, Branch, [ | ||
function initTree(){ | ||
if (!this.tree.initialized) { | ||
this.tree.initialized = true; | ||
this.keys = this.mirror.list(true); | ||
utility.iterate(this.keys, function(key){ | ||
this.tree.append(new Property(this.mirror, key)); | ||
}, this); | ||
if (this.mirror.subject.outer) { | ||
this.tree.append(new Outer(this.mirror)); | ||
} | ||
} | ||
return this; | ||
} | ||
]); | ||
return ScopeBranch; | ||
})(); | ||
var ThrownBranch = (function(){ | ||
@@ -2077,3 +2158,3 @@ function ThrownBranch(mirror){ | ||
var renderer = new debug.Renderer({ | ||
var renderer = continuum.createRenderer({ | ||
Unknown: Branch.create, | ||
@@ -2086,3 +2167,3 @@ BooleanValue: Leaf.create, | ||
Accessor: Leaf.create, | ||
Global: Branch.create, | ||
Global: GlobalBranch.create, | ||
Thrown: ThrownBranch.create, | ||
@@ -2098,5 +2179,7 @@ Arguments: Branch.create, | ||
Math: Branch.create, | ||
Module: Branch.create, | ||
Object: Branch.create, | ||
Number: Branch.create, | ||
RegExp: Branch.create, | ||
Scope: ScopeBranch.create, | ||
Set: Branch.create, | ||
@@ -2107,3 +2190,3 @@ String: Branch.create, | ||
var previewRenderer = new debug.Renderer({ | ||
var previewRenderer = continuum.createRenderer({ | ||
Unknown: Preview.create, | ||
@@ -2127,5 +2210,7 @@ BooleanValue: Leaf.create, | ||
Math: Preview.create, | ||
Module: Preview.create, | ||
Object: Preview.create, | ||
Number: Preview.create, | ||
RegExp: Preview.create, | ||
Scope: Preview.create, | ||
Set: Preview.create, | ||
@@ -2145,3 +2230,2 @@ String: Preview.create, | ||
void function(){ | ||
//var input = new InputBox({ hint: 'Enter code to run...', autofocus: true }), | ||
var stdout = new Console, | ||
@@ -2204,9 +2288,14 @@ inspector = new Tree, | ||
function createRealm(){ | ||
realm = (function(){ | ||
var realm = continuum.createRealm(); | ||
function run(code){ | ||
var result = renderer.render(realm.evaluate(code)); | ||
inspector.append(new Result(result)); | ||
realm.evaluateAsync(code, inspect); | ||
} | ||
function inspect(o){ | ||
var tree = inspector.append(new Result(renderer.render(o))); | ||
inspector.element.scrollTop = inspector.element.scrollHeight; | ||
inspector.refresh(); | ||
return result; | ||
return tree; | ||
} | ||
@@ -2218,13 +2307,2 @@ | ||
realm = new Realm; | ||
realm.on('throw', function(err){ | ||
console.log(err); | ||
inspector.append(new Result(renderer.render(err))); | ||
inspector.element.scrollTop = inspector.element.scrollHeight; | ||
inspector.refresh(); | ||
}); | ||
run('this'); | ||
realm.on('write', function(args){ | ||
@@ -2266,9 +2344,11 @@ stdout.write.apply(stdout, args); | ||
}, 100); | ||
} | ||
setTimeout(createRealm, 1); | ||
var item = inspect(realm.evaluate('this')); | ||
setTimeout(function(){ item.expand() }, 50); | ||
return realm; | ||
})(); | ||
}(); | ||
})(this, continuum.Realm, continuum.constants, continuum.utility, continuum.debug); | ||
delete continuum | ||
})(this, continuum, continuum.constants, continuum.utility); |
@@ -5,3 +5,3 @@ var assembler = (function(exports){ | ||
var visit = utility.visit, | ||
var walk = utility.walk, | ||
collector = utility.collector, | ||
@@ -17,2 +17,8 @@ Stack = utility.Stack, | ||
isObject = utility.isObject, | ||
iterate = utility.iterate, | ||
each = utility.each, | ||
repeat = utility.repeat, | ||
map = utility.map, | ||
fold = utility.fold, | ||
generate = utility.generate, | ||
quotes = utility.quotes; | ||
@@ -24,2 +30,3 @@ | ||
ENTRY = constants.ENTRY.hash, | ||
SCOPE = constants.SCOPE.hash, | ||
AST = constants.AST, | ||
@@ -29,15 +36,23 @@ FUNCTYPE = constants.FUNCTYPE.hash; | ||
var hasOwn = {}.hasOwnProperty, | ||
push = [].push; | ||
push = [].push, | ||
proto = Math.random().toString(36).slice(2), | ||
context, | ||
opcodes = 0; | ||
var context; | ||
var opcodes = 0; | ||
function OpCode(params, name){ | ||
this.id = opcodes++; | ||
this.params = params; | ||
this.name = name; | ||
function StandardOpCode(params, name){ | ||
var opcode = this; | ||
var func = this.creator(); | ||
this.id = func.id = opcodes++; | ||
this.params = func.params = params; | ||
this.name = func.opname = name; | ||
return func; | ||
} | ||
define(OpCode.prototype, [ | ||
define(StandardOpCode.prototype, [ | ||
function creator(){ | ||
var opcode = this; | ||
return function(){ | ||
return context.code.createDirective(opcode, arguments); | ||
}; | ||
}, | ||
function inspect(){ | ||
@@ -58,156 +73,197 @@ return this.name; | ||
function InternedOpCode(params, name){ | ||
return StandardOpCode.call(this, params, name); | ||
} | ||
var ARRAY = new OpCode(0, 'ARRAY'), | ||
ARG = new OpCode(0, 'ARG'), | ||
ARGS = new OpCode(0, 'ARGS'), | ||
ARRAY_DONE = new OpCode(0, 'ARRAY_DONE'), | ||
BINARY = new OpCode(1, 'BINARY'), | ||
BLOCK = new OpCode(1, 'BLOCK'), | ||
CALL = new OpCode(0, 'CALL'), | ||
CASE = new OpCode(1, 'CASE'), | ||
CLASS_DECL = new OpCode(1, 'CLASS_DECL'), | ||
CLASS_EXPR = new OpCode(1, 'CLASS_EXPR'), | ||
COMPLETE = new OpCode(0, 'COMPLETE'), | ||
CONST = new OpCode(1, 'CONST'), | ||
CONSTRUCT = new OpCode(0, 'CONSTRUCT'), | ||
DEBUGGER = new OpCode(0, 'DEBUGGER'), | ||
DEFAULT = new OpCode(1, 'DEFAULT'), | ||
DUP = new OpCode(0, 'DUP'), | ||
ELEMENT = new OpCode(0, 'ELEMENT'), | ||
ENUM = new OpCode(0, 'ENUM'), | ||
FUNCTION = new OpCode(2, 'FUNCTION'), | ||
GET = new OpCode(0, 'GET'), | ||
IFEQ = new OpCode(2, 'IFEQ'), | ||
IFNE = new OpCode(2, 'IFNE'), | ||
INDEX = new OpCode(2, 'INDEX'), | ||
ITERATE = new OpCode(0, 'ITERATE'), | ||
JUMP = new OpCode(1, 'JUMP'), | ||
LET = new OpCode(1, 'LET'), | ||
LITERAL = new OpCode(1, 'LITERAL'), | ||
LOG = new OpCode(0, 'LOG'), | ||
MEMBER = new OpCode(1, 'MEMBER'), | ||
METHOD = new OpCode(3, 'METHOD'), | ||
NATIVE_CALL = new OpCode(0, 'NATIVE_CALL'), | ||
NATIVE_REF = new OpCode(1, 'NATIVE_REF'), | ||
OBJECT = new OpCode(0, 'OBJECT'), | ||
POP = new OpCode(0, 'POP'), | ||
POPN = new OpCode(1, 'POPN'), | ||
PROPERTY = new OpCode(1, 'PROPERTY'), | ||
PUT = new OpCode(0, 'PUT'), | ||
REF = new OpCode(1, 'REF'), | ||
REGEXP = new OpCode(1, 'REGEXP'), | ||
RETURN = new OpCode(0, 'RETURN'), | ||
ROTATE = new OpCode(1, 'ROTATE'), | ||
RUN = new OpCode(0, 'RUN'), | ||
SAVE = new OpCode(0, 'SAVE'), | ||
SPREAD = new OpCode(1, 'SPREAD'), | ||
SPREAD_ARG = new OpCode(0, 'SPREAD_ARG'), | ||
STRING = new OpCode(1, 'STRING'), | ||
SUPER_CALL = new OpCode(0, 'SUPER_CALL'), | ||
SUPER_ELEMENT = new OpCode(0, 'SUPER_ELEMENT'), | ||
SUPER_MEMBER = new OpCode(1, 'SUPER_MEMBER'), | ||
THIS = new OpCode(0, 'THIS'), | ||
THROW = new OpCode(0, 'THROW'), | ||
UNARY = new OpCode(1, 'UNARY'), | ||
UNDEFINED = new OpCode(0, 'UNDEFINED'), | ||
UPDATE = new OpCode(1, 'UPDATE'), | ||
UPSCOPE = new OpCode(0, 'UPSCOPE'), | ||
VAR = new OpCode(1, 'VAR'), | ||
WITH = new OpCode(0, 'WITH'); | ||
inherit(InternedOpCode, StandardOpCode, [ | ||
function creator(){ | ||
var opcode = this; | ||
return function(arg){ | ||
//return context.code.createDirective(opcode, [context.intern(arg)]); | ||
return context.code.createDirective(opcode, [arg]); | ||
}; | ||
} | ||
]); | ||
function Operation(op, a, b, c, d){ | ||
this.op = op; | ||
this.loc = currentNode.loc; | ||
this.range = currentNode.range; | ||
for (var i=0; i < op.params; i++) { | ||
this[i] = arguments[i + 1]; | ||
} | ||
} | ||
var ARRAY = new StandardOpCode(0, 'ARRAY'), | ||
ARG = new StandardOpCode(0, 'ARG'), | ||
ARGS = new StandardOpCode(0, 'ARGS'), | ||
ARRAY_DONE = new StandardOpCode(0, 'ARRAY_DONE'), | ||
BINARY = new StandardOpCode(1, 'BINARY'), | ||
BLOCK = new StandardOpCode(1, 'BLOCK'), | ||
CALL = new StandardOpCode(0, 'CALL'), | ||
CASE = new StandardOpCode(1, 'CASE'), | ||
CLASS_DECL = new StandardOpCode(1, 'CLASS_DECL'), | ||
CLASS_EXPR = new StandardOpCode(1, 'CLASS_EXPR'), | ||
COMPLETE = new StandardOpCode(0, 'COMPLETE'), | ||
CONST = new StandardOpCode(1, 'CONST'), | ||
CONSTRUCT = new StandardOpCode(0, 'CONSTRUCT'), | ||
DEBUGGER = new StandardOpCode(0, 'DEBUGGER'), | ||
DEFAULT = new StandardOpCode(1, 'DEFAULT'), | ||
DEFINE = new StandardOpCode(1, 'DEFINE'), | ||
DUP = new StandardOpCode(0, 'DUP'), | ||
ELEMENT = new StandardOpCode(0, 'ELEMENT'), | ||
ENUM = new StandardOpCode(0, 'ENUM'), | ||
EXTENSIBLE = new StandardOpCode(1, 'EXTENSIBLE'), | ||
FLIP = new StandardOpCode(1, 'FLIP'), | ||
FUNCTION = new StandardOpCode(2, 'FUNCTION'), | ||
GET = new StandardOpCode(0, 'GET'), | ||
IFEQ = new StandardOpCode(2, 'IFEQ'), | ||
IFNE = new StandardOpCode(2, 'IFNE'), | ||
INC = new StandardOpCode(0, 'INC'), | ||
INDEX = new StandardOpCode(2, 'INDEX'), | ||
ITERATE = new StandardOpCode(0, 'ITERATE'), | ||
JUMP = new StandardOpCode(1, 'JUMP'), | ||
LET = new StandardOpCode(1, 'LET'), | ||
LITERAL = new StandardOpCode(1, 'LITERAL'), | ||
LOG = new StandardOpCode(0, 'LOG'), | ||
MEMBER = new InternedOpCode(1, 'MEMBER'), | ||
METHOD = new StandardOpCode(3, 'METHOD'), | ||
NATIVE_CALL = new StandardOpCode(0, 'NATIVE_CALL'), | ||
NATIVE_REF = new InternedOpCode(1, 'NATIVE_REF'), | ||
OBJECT = new StandardOpCode(0, 'OBJECT'), | ||
POP = new StandardOpCode(0, 'POP'), | ||
POPN = new StandardOpCode(1, 'POPN'), | ||
PROPERTY = new InternedOpCode(1, 'PROPERTY'), | ||
PUT = new StandardOpCode(0, 'PUT'), | ||
REF = new InternedOpCode(1, 'REF'), | ||
REGEXP = new StandardOpCode(1, 'REGEXP'), | ||
RETURN = new StandardOpCode(0, 'RETURN'), | ||
ROTATE = new StandardOpCode(1, 'ROTATE'), | ||
RUN = new StandardOpCode(0, 'RUN'), | ||
SAVE = new StandardOpCode(0, 'SAVE'), | ||
SPREAD = new StandardOpCode(1, 'SPREAD'), | ||
SPREAD_ARG = new StandardOpCode(0, 'SPREAD_ARG'), | ||
STRING = new InternedOpCode(1, 'STRING'), | ||
SUPER_CALL = new StandardOpCode(0, 'SUPER_CALL'), | ||
SUPER_ELEMENT = new StandardOpCode(0, 'SUPER_ELEMENT'), | ||
SUPER_MEMBER = new StandardOpCode(1, 'SUPER_MEMBER'), | ||
TEMPLATE = new StandardOpCode(1, 'TEMPLATE'), | ||
THIS = new StandardOpCode(0, 'THIS'), | ||
THROW = new StandardOpCode(0, 'THROW'), | ||
UNARY = new StandardOpCode(1, 'UNARY'), | ||
UNDEFINED = new StandardOpCode(0, 'UNDEFINED'), | ||
UPDATE = new StandardOpCode(1, 'UPDATE'), | ||
UPSCOPE = new StandardOpCode(0, 'UPSCOPE'), | ||
VAR = new StandardOpCode(1, 'VAR'), | ||
WITH = new StandardOpCode(0, 'WITH'), | ||
YIELD = new StandardOpCode(1, 'YIELD'); | ||
define(Operation.prototype, [ | ||
function inspect(){ | ||
var out = []; | ||
for (var i=0; i < this.op.params; i++) { | ||
out.push(util.inspect(this[i])); | ||
var Code = (function(){ | ||
var Directive = (function(){ | ||
function Directive(op, args){ | ||
this.op = op; | ||
this.loc = currentNode.loc; | ||
this.range = currentNode.range; | ||
for (var i=0; i < op.params; i++) { | ||
this[i] = args[i]; | ||
} | ||
} | ||
return util.inspect(this.op)+'('+out.join(', ')+')'; | ||
} | ||
]); | ||
define(Directive.prototype, [ | ||
function inspect(){ | ||
var out = []; | ||
for (var i=0; i < this.op.params; i++) { | ||
out.push(util.inspect(this[i])); | ||
} | ||
return util.inspect(this.op)+'('+out.join(', ')+')'; | ||
} | ||
]); | ||
return Directive; | ||
})(); | ||
function Params(params, node, rest){ | ||
this.length = 0; | ||
if (params) { | ||
// for (var i=0; i < params.length; i++) { | ||
// if (params[i].type === 'Identifier') { | ||
// push.call(this, intern(params[i].name)) | ||
// } else { | ||
// push.call(this, params[i]); | ||
// } | ||
// } | ||
push.apply(this, params) | ||
} | ||
this.Rest = rest; | ||
this.BoundNames = BoundNames(node);//.map(intern); | ||
var args = collectExpectedArguments(this); | ||
this.ExpectedArgumentCount = args.length; | ||
this.ArgNames = []; | ||
for (var i=0; i < args.length; i++) { | ||
if (args[i].type === 'Identifier') { | ||
this.ArgNames.push(intern(args[i].name)); | ||
} else { | ||
var Params = (function(){ | ||
function Params(params, node, rest){ | ||
this.length = 0; | ||
if (params) { | ||
push.apply(this, params) | ||
this.BoundNames = BoundNames(params); | ||
} else { | ||
this.BoundNames = []; | ||
} | ||
this.Rest = rest; | ||
this.ExpectedArgumentCount = this.BoundNames.length; | ||
if (rest) this.BoundNames.push(rest.name); | ||
} | ||
define(Params, [ | ||
function add(items){ | ||
} | ||
]); | ||
return Params; | ||
})(); | ||
function Code(node, source, type, scope, strict){ | ||
function Instruction(opcode, args){ | ||
Directive.call(this, opcode, args); | ||
} | ||
} | ||
} | ||
inherit(Instruction, Directive, { | ||
code: this | ||
}); | ||
function Code(node, source, type, global, strict){ | ||
function Instruction(args){ | ||
Operation.apply(this, args); | ||
} | ||
var body = node; | ||
inherit(Instruction, Operation, { | ||
code: this | ||
}); | ||
if (node.type === 'Program') { | ||
this.topLevel = true; | ||
this.imports = getImports(node); | ||
} else { | ||
this.topLevel = false; | ||
body = body.body; | ||
if (node.type === 'ModuleDeclaration') { | ||
this.imports = getImports(body); | ||
body = body.body; | ||
} | ||
} | ||
this.topLevel = node.type === 'Program'; | ||
var body = this.topLevel ? node : node.body; | ||
this.path = []; | ||
define(this, { | ||
body: body, | ||
source: source, | ||
range: node.range, | ||
loc: node.loc, | ||
children: [], | ||
LexicalDeclarations: LexicalDeclarations(body), | ||
createOperation: function(args){ | ||
var op = new Instruction(args); | ||
this.ops.push(op); | ||
return op; | ||
define(this, { | ||
body: body, | ||
source: source == null ? context.code.source : source, | ||
range: node.range, | ||
loc: node.loc, | ||
children: [], | ||
LexicalDeclarations: LexicalDeclarations(body), | ||
createDirective: function(opcode, args){ | ||
var op = new Instruction(opcode, args); | ||
this.ops.push(op); | ||
return op; | ||
} | ||
}); | ||
if (node.id) { | ||
this.name = node.id.name; | ||
} | ||
}); | ||
if (!this.topLevel && node.id) { | ||
this.name = node.id.name; | ||
if (node.generator) { | ||
this.generator = true; | ||
} | ||
this.transfers = []; | ||
this.ScopeType = scope; | ||
this.Type = type || FUNCTYPE.NORMAL; | ||
this.VarDeclaredNames = []; | ||
this.NeedsSuperBinding = ReferencesSuper(this.body); | ||
this.Strict = strict || (context.code && context.code.strict) || isStrict(this.body); | ||
if (scope === SCOPE.MODULE) { | ||
this.ExportedNames = getExports(this.body); | ||
} | ||
this.params = new Params(node.params, node, node.rest); | ||
this.ops = []; | ||
} | ||
this.global = global; | ||
this.transfers = []; | ||
this.Type = type || FUNCTYPE.NORMAL; | ||
this.VarDeclaredNames = []; | ||
this.NeedsSuperBinding = ReferencesSuper(this.body); | ||
this.Strict = strict || isStrict(this.body); | ||
this.params = new Params(node.params, node, node.rest); | ||
this.ops = []; | ||
} | ||
void function(){ | ||
var proto = Math.random().toString(36).slice(2); | ||
define(Code.prototype, [ | ||
function inherit(code){ | ||
function derive(code){ | ||
if (code) { | ||
@@ -228,5 +284,7 @@ this.strings = code.strings; | ||
]); | ||
}(); | ||
return Code; | ||
})(); | ||
function ClassDefinition(node){ | ||
@@ -238,3 +296,3 @@ this.name = node.id ? node.id.name : null; | ||
for (var i=0, method; method = node.body.body[i]; i++) { | ||
var code = new Code(method.value, context.source, FUNCTYPE.METHOD, false, context.code.strict); | ||
var code = new Code(method.value, context.source, FUNCTYPE.METHOD, SCOPE.CLASS, context.code.Strict); | ||
if (this.name) { | ||
@@ -264,3 +322,3 @@ code.name = this.name + '#' + method.key.name; | ||
recurse(node.superClass); | ||
record(GET); | ||
GET(); | ||
this.superClass = node.superClass.name; | ||
@@ -270,10 +328,9 @@ } | ||
var Unwinder = (function(){ | ||
function Unwinder(type, begin, end){ | ||
this.type = type; | ||
this.begin = begin; | ||
this.end = end; | ||
} | ||
function Unwinder(type, begin, end){ | ||
this.type = type; | ||
this.begin = begin; | ||
this.end = end; | ||
} | ||
void function(){ | ||
define(Unwinder.prototype, [ | ||
@@ -284,13 +341,13 @@ function toJSON(){ | ||
]); | ||
}(); | ||
return Unwinder; | ||
})(); | ||
var ControlTransfer = (function(){ | ||
function ControlTransfer(labels){ | ||
this.labels = labels; | ||
this.breaks = []; | ||
this.continues = []; | ||
} | ||
function ControlTransfer(labels){ | ||
this.labels = labels; | ||
this.breaks = []; | ||
this.continues = []; | ||
} | ||
void function(){ | ||
define(ControlTransfer.prototype, { | ||
@@ -300,3 +357,3 @@ labels: null, | ||
continues: null | ||
}) | ||
}); | ||
@@ -306,5 +363,3 @@ define(ControlTransfer.prototype, [ | ||
if (ip !== undefined) { | ||
for (var i=0, item; item = this.breaks[i]; i++) { | ||
item[0] = ip; | ||
} | ||
each(this.continues, function(item){ item[0] = ip }); | ||
} | ||
@@ -314,159 +369,77 @@ }, | ||
if (ip !== undefined) { | ||
for (var i=0, item; item = this.continues[i]; i++) { | ||
item[0] = ip; | ||
} | ||
each(this.breaks, function(item){ item[0] = ip }); | ||
} | ||
} | ||
]); | ||
}(); | ||
return ControlTransfer; | ||
})(); | ||
function isSuperReference(node) { | ||
return !!node && node.type === 'Identifier' && node.name === 'super'; | ||
} | ||
function AssemblerOptions(o){ | ||
o = Object(o); | ||
for (var k in this) | ||
this[k] = k in o ? o[k] : this[k]; | ||
function isUseStrictDirective(node){ | ||
return node.type === 'ExpressionSatatement' | ||
&& node.expression.type === 'Literal' | ||
&& node.expression.value === 'use strict'; | ||
} | ||
AssemblerOptions.prototype = { | ||
eval: false, | ||
normal: true, | ||
natives: false, | ||
filename: null | ||
}; | ||
function isPattern(node){ | ||
return !!node && node.type === 'ObjectPattern' || node.type === 'ArrayPattern'; | ||
} | ||
function isLexicalDeclaration(node){ | ||
return !!node && node.type === 'VariableDeclaration' && node.kind !== 'var'; | ||
} | ||
function isFunction(node){ | ||
return node.type === 'FunctionDeclaration' | ||
|| node.type === 'FunctionExpression' | ||
|| node.type === 'ArrowFunctionExpression'; | ||
} | ||
function Assembler(options){ | ||
this.options = new AssemblerOptions(options); | ||
define(this, { | ||
strings: [], | ||
hash: create(null) | ||
}); | ||
function isDeclaration(node){ | ||
return node.type === 'FunctionDeclaration' | ||
|| node.type === 'ClassDeclaration' | ||
|| node.type === 'VariableDeclaration'; | ||
} | ||
define(Assembler.prototype, { | ||
source: null, | ||
node: null, | ||
code: null, | ||
pending: null, | ||
levels: null, | ||
jumps: null, | ||
labels: null, | ||
}); | ||
void function(){ | ||
define(Assembler.prototype, [ | ||
function assemble(node, source){ | ||
context = this; | ||
this.pending = new Stack; | ||
this.levels = new Stack; | ||
this.jumps = new Stack; | ||
this.labels = null; | ||
this.source = source; | ||
if (this.options.normal) | ||
node = node.body[0].expression; | ||
var type = this.options.eval ? 'eval' : this.options.normal ? 'function' : 'global'; | ||
var code = new Code(node, source, type, !this.options.scoped); | ||
define(code, { | ||
strings: this.strings, | ||
hash: this.hash | ||
}); | ||
code.topLevel = true; | ||
if (this.options.natives) { | ||
code.natives = true; | ||
reinterpretNatives(node); | ||
function isStrict(node){ | ||
if (isFunction(node)) { | ||
node = node.body.body; | ||
} else if (node.type === 'Program') { | ||
node = node.body; | ||
} | ||
if (node instanceof Array) { | ||
for (var i=0, element; element = node[i]; i++) { | ||
if (isUseStrictDirective(element)) { | ||
return true; | ||
} else if (element.type !== 'EmptyStatement' && element.type !== 'FunctionDeclaration') { | ||
return false; | ||
} | ||
annotateParent(node); | ||
this.queue(code); | ||
while (this.pending.length) { | ||
var lastCode = this.code; | ||
this.code = this.pending.pop(); | ||
this.code.filename = this.filename; | ||
if (lastCode) { | ||
this.code.inherit(lastCode); | ||
} | ||
recurse(this.code.body); | ||
if (this.code.eval || this.code.global){ | ||
record(COMPLETE); | ||
} else { | ||
if (this.code.Type === FUNCTYPE.ARROW && this.code.body.type !== 'BlockStatement') { | ||
record(GET); | ||
} else { | ||
record(UNDEFINED); | ||
} | ||
record(RETURN); | ||
} | ||
} | ||
return code; | ||
}, | ||
function queue(code){ | ||
if (this.code) { | ||
this.code.children.push(code); | ||
} | ||
this.pending.push(code); | ||
}, | ||
function intern(name){ | ||
return name; | ||
if (name === '__proto__') { | ||
if (!this.hash[proto]) { | ||
var index = this.hash[proto] = this.strings.length; | ||
this.strings[index] = '__proto__'; | ||
} | ||
name = proto; | ||
} | ||
if (name in this.hash) { | ||
return this.hash[name]; | ||
} else { | ||
var index = this.hash[name] = this.strings.length; | ||
this.strings[index] = name; | ||
return index; | ||
} | ||
}, | ||
]); | ||
}(); | ||
function annotateParent(node, parent){ | ||
visit(node, function(node){ | ||
if (isObject(node) && parent) { | ||
define(node, 'parent', parent); | ||
} | ||
return visit.RECURSE; | ||
}); | ||
} | ||
return false; | ||
} | ||
function reinterpretNatives(node){ | ||
visit(node, function(node){ | ||
if (node.type === 'Identifier' && /^\$__/.test(node.name)) { | ||
node.type = 'NativeIdentifier'; | ||
node.name = node.name.slice(3); | ||
} else { | ||
return visit.RECURSE; | ||
} | ||
}); | ||
} | ||
var boundNamesCollector = collector({ | ||
ObjectPattern : visit.RECURSE, | ||
ArrayPattern : visit.RECURSE, | ||
VariableDeclaration: visit.RECURSE, | ||
VariableDeclarator : ['id', 'name'], | ||
BlockStatement : visit.RECURSE, | ||
Property : visit.RECURSE, | ||
ObjectPattern : 'properties', | ||
ArrayPattern : 'elements', | ||
VariableDeclaration: 'declarations', | ||
BlockStatement : walk.RECURSE, | ||
Program : walk.RECURSE, | ||
ForStatement : walk.RECURSE, | ||
Property : 'value', | ||
ExportDeclaration : 'declaration', | ||
ExportSpecifierSet : 'specifiers', | ||
ImportDeclaration : 'specifiers', | ||
Identifier : ['name'], | ||
FunctionDeclaration: ['id', 'name'], | ||
ClassDeclaration : ['id', 'name'] | ||
ImportSpecifier : 'id', | ||
VariableDeclarator : 'id', | ||
ModuleDeclaration : 'id', | ||
FunctionDeclaration: 'id', | ||
ClassDeclaration : 'id' | ||
}); | ||
@@ -476,10 +449,6 @@ | ||
function BoundNames(node){ | ||
var names = boundNamesCollector(node); | ||
if (node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') { | ||
return names.slice(1); | ||
} else if (node.type === 'FunctionExpression') { | ||
return node.id ? names.slice(1) : names; | ||
} else { | ||
return names; | ||
if (isFunction(node) || node.type === 'ClassDeclaration') { | ||
//node = node.body; | ||
} | ||
return boundNamesCollector(node); | ||
} | ||
@@ -491,3 +460,5 @@ | ||
FunctionDeclaration: lexical(false), | ||
SwitchCase: visit.RECURSE, | ||
ExportDeclaration: walk.RECURSE, | ||
SwitchCase: walk.RECURSE, | ||
Program: walk.RECURSE, | ||
VariableDeclaration: lexical(function(node){ | ||
@@ -511,9 +482,114 @@ return node.kind === 'const'; | ||
function isSuperReference(node) { | ||
return !!node && node.type === 'Identifier' && node.name === 'super'; | ||
} | ||
var getExports = (function(){ | ||
var collectExportDecls = collector({ | ||
Program : 'body', | ||
BlockStatement : 'body', | ||
ExportDeclaration: true | ||
}); | ||
var getExportedDecls = collector({ | ||
ClassDeclaration : true, | ||
ExportDeclaration : walk.RECURSE, | ||
ExportSpecifier : true, | ||
ExportSpecifierSet : walk.RECURSE, | ||
FunctionDeclaration: true, | ||
ModuleDeclaration : true, | ||
VariableDeclaration: walk.RECURSE, | ||
VariableDeclarator : true | ||
}); | ||
var getExportedNames = collector({ | ||
ArrayPattern : 'elements', | ||
ObjectPattern : 'properties', | ||
Property : 'value', | ||
ClassDeclaration : 'id', | ||
ExportSpecifier : 'id', | ||
FunctionDeclaration: 'id', | ||
ModuleDeclaration : 'id', | ||
VariableDeclarator : 'id', | ||
Glob : true, | ||
Identifier : ['name'], | ||
}); | ||
return function getExports(node){ | ||
return getExportedNames(getExportedDecls(collectExportDecls(node))); | ||
}; | ||
})(); | ||
var getImports = (function(){ | ||
var collectImportDecls = collector({ | ||
Program : 'body', | ||
BlockStatement : 'body', | ||
ImportDeclaration: true, | ||
ModuleDeclaration: true | ||
}); | ||
function Import(origin, name, specifiers){ | ||
this.origin = origin; | ||
this.name = name; | ||
this.specifiers = specifiers; | ||
} | ||
var handlers = { | ||
Glob: function(){ | ||
return ['*', '*']; | ||
}, | ||
Path: function(node){ | ||
return map(node.body, function(subpath){ | ||
return handlers[subpath.type](subpath); | ||
}); | ||
}, | ||
ImportSpecifier: function(node){ | ||
var name = handlers[node.id.type](node.id); | ||
var from = node.from === null ? name : handlers[node.from.type](node.from); | ||
return [name, from]; | ||
}, | ||
Identifier: function(node){ | ||
return node.name; | ||
}, | ||
Literal: function(node){ | ||
return node.value; | ||
} | ||
}; | ||
return function getImports(node){ | ||
var decls = collectImportDecls(node), | ||
imported = []; | ||
each(decls, function(decl, i){ | ||
if (decl.body) { | ||
var origin = name = decl.id.name; | ||
var specifiers = decl; | ||
} else { | ||
var origin = handlers[decl.from.type](decl.from); | ||
if (decl.type === 'ModuleDeclaration') { | ||
var name = decl.id.name; | ||
} else { | ||
var specifiers = create(null); | ||
each(decl.specifiers, function(specifier){ | ||
var result = handlers[specifier.type](specifier); | ||
result = typeof result === 'string' ? [result, result] : result; | ||
if (!(result[1] instanceof Array)) { | ||
result[1] = [result[1]]; | ||
} | ||
specifiers[result[0]] = result[1]; | ||
}); | ||
} | ||
} | ||
imported.push(new Import(origin, name, specifiers)); | ||
}); | ||
return imported; | ||
}; | ||
})(); | ||
function ReferencesSuper(node){ | ||
var found = false; | ||
visit(node, function(node){ | ||
walk(node, function(node){ | ||
switch (node.type) { | ||
@@ -523,16 +599,18 @@ case 'MemberExpression': | ||
found = true; | ||
return visit.BREAK; | ||
return walk.BREAK; | ||
} | ||
return walk.RECURSE; | ||
case 'CallExpression': | ||
if (isSuperReference(node.callee)) { | ||
found = true; | ||
return visit.BREAK; | ||
return walk.BREAK; | ||
} | ||
break; | ||
return walk.RECURSE; | ||
case 'FunctionExpression': | ||
case 'FunctionDeclaration': | ||
case 'ArrowFunctionExpression': | ||
return visit.CONTINUE; | ||
return walk.CONTINUE; | ||
default: | ||
return walk.RECURSE; | ||
} | ||
return visit.RECURSE; | ||
}); | ||
@@ -542,55 +620,16 @@ return found; | ||
function isUseStrictDirective(node){ | ||
return node.type === 'ExpressionSatatement' | ||
&& node.expression.type === 'Literal' | ||
&& node.expression.value === 'use strict'; | ||
} | ||
function isFunction(node){ | ||
return node.type === 'FunctionDeclaration' | ||
|| node.type === 'FunctionExpression' | ||
|| node.type === 'ArrowFunctionExpression'; | ||
} | ||
function isStrict(node){ | ||
if (isFunction(node)) { | ||
node = node.body.body; | ||
} else if (node.type === 'Program') { | ||
node = node.body; | ||
} | ||
if (node instanceof Array) { | ||
for (var i=0, element; element = node[i]; i++) { | ||
if (element) { | ||
if (isUseStrictDirective(element)) { | ||
return true; | ||
} else if (element.type !== 'EmptyStatement' && element.type !== 'FunctionDeclaration') { | ||
return false; | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
function isPattern(node){ | ||
return !!node && node.type === 'ObjectPattern' || node.type === 'ArrayPattern'; | ||
} | ||
var collectExpectedArguments = collector({ | ||
Identifier: true, | ||
ObjectPattern: true, | ||
ArrayPattern: true, | ||
}); | ||
var currentNode; | ||
function recurse(node){ | ||
if (node) { | ||
var lastNode = currentNode; | ||
currentNode = node; | ||
handlers[node.type](node); | ||
if (lastNode) { | ||
currentNode = lastNode; | ||
if (node.type) { | ||
var lastNode = currentNode; | ||
currentNode = node; | ||
handlers[node.type](node); | ||
if (lastNode) { | ||
currentNode = lastNode; | ||
} | ||
} else if (node.length) { | ||
each(node, recurse); | ||
} | ||
@@ -600,2 +639,3 @@ } | ||
function intern(str){ | ||
@@ -605,7 +645,2 @@ return str;//context.intern(string); | ||
function record(){ | ||
return context.code.createOperation(arguments); | ||
} | ||
function current(){ | ||
@@ -624,7 +659,25 @@ return context.code.ops.length; | ||
function adjust(op){ | ||
return op[0] = context.code.ops.length; | ||
if (op) { | ||
return op[0] = context.code.ops.length; | ||
} | ||
} | ||
function macro(){ | ||
var opcodes = arguments; | ||
MACRO.params = opcodes.length; | ||
return MACRO; | ||
function MACRO(){ | ||
var offset = 0, | ||
args = arguments; | ||
each(opcodes, function(opcode){ | ||
opcode.apply(null, generate(opcode.params, function(){ | ||
return args[offset++] | ||
})); | ||
}); | ||
} | ||
} | ||
function block(callback){ | ||
if (context.labels){ | ||
var entry = new ControlTransfer(context.labels); | ||
@@ -636,5 +689,2 @@ context.jumps.push(entry); | ||
context.jumps.pop(); | ||
} else { | ||
callback(); | ||
} | ||
} | ||
@@ -661,14 +711,14 @@ | ||
function move(node){ | ||
function move(node, set, pos){ | ||
if (node.label) { | ||
var entry = context.jumps.first(function(transfer){ | ||
var transfer = context.jumps.first(function(transfer){ | ||
return node.label.name in transfer.labels; | ||
}); | ||
} else { | ||
var entry = context.jumps.first(function(transfer){ | ||
var transfer = context.jumps.first(function(transfer){ | ||
return transfer && transfer.continues; | ||
}); | ||
} | ||
return entry; | ||
transfer && transfer[set].push(pos); | ||
} | ||
@@ -687,11 +737,9 @@ | ||
var key = left.type === 'ArrayPattern' ? 'elements' : 'properties', | ||
lefts = left[key], | ||
rights = right[key], | ||
binding, value; | ||
rights = right[key]; | ||
for (var i=0; i < lefts.length; i++) { | ||
binding = elementAt[key](left, i); | ||
each(left[key], function(item, i){ | ||
var binding = elementAt[key](left, i); | ||
if (isPattern(binding)){ | ||
value = rights && rights[i] ? elementAt[key](right, i) : binding; | ||
var value = rights && rights[i] ? elementAt[key](right, i) : binding; | ||
destructure(binding, value); | ||
@@ -702,3 +750,3 @@ } else { | ||
recurse(right); | ||
record(SPREAD, i); | ||
SPREAD(i); | ||
} else { | ||
@@ -708,28 +756,32 @@ recurse(binding); | ||
if (left.type === 'ArrayPattern') { | ||
record(LITERAL, i); | ||
record(ELEMENT, i); | ||
LITERAL(i); | ||
ELEMENT(i); | ||
} else { | ||
record(MEMBER, binding.name) | ||
MEMBER(binding.name) | ||
} | ||
} | ||
record(PUT); | ||
PUT(); | ||
} | ||
} | ||
}); | ||
} | ||
function args(node){ | ||
record(ARGS); | ||
for (var i=0, item; item = node[i]; i++) { | ||
ARGS(); | ||
each(node, function(item, i){ | ||
if (item && item.type === 'SpreadElement') { | ||
recurse(item.argument); | ||
record(GET); | ||
record(SPREAD_ARG); | ||
GET(); | ||
SPREAD_ARG(); | ||
} else { | ||
recurse(item); | ||
record(GET); | ||
record(ARG); | ||
GET(); | ||
ARG(); | ||
} | ||
} | ||
}); | ||
} | ||
function isGlobalOrEval(){ | ||
return context.code.ScopeType === SCOPE.EVAL || context.code.ScopeType === SCOPE.GLOBAL; | ||
} | ||
@@ -744,13 +796,13 @@ | ||
recurse(node.right); | ||
record(GET); | ||
record(PUT); | ||
GET(); | ||
PUT(); | ||
} | ||
} else { | ||
recurse(node.left); | ||
record(DUP); | ||
record(GET); | ||
DUP(); | ||
GET(); | ||
recurse(node.right); | ||
record(GET); | ||
record(BINARY, BINARYOPS[node.operator.slice(0, -1)]); | ||
record(PUT); | ||
GET(); | ||
BINARY(BINARYOPS[node.operator.slice(0, -1)]); | ||
PUT(); | ||
} | ||
@@ -760,4 +812,4 @@ } | ||
function ArrayExpression(node){ | ||
record(ARRAY); | ||
for (var i=0, item; i < node.elements.length; i++) { | ||
ARRAY(); | ||
each(node.elements, function(item, i){ | ||
var empty = false, | ||
@@ -776,5 +828,6 @@ spread = false, | ||
record(INDEX, empty, spread); | ||
} | ||
record(ARRAY_DONE); | ||
GET(); | ||
INDEX(empty, spread); | ||
}); | ||
ARRAY_DONE(); | ||
} | ||
@@ -785,5 +838,5 @@ | ||
function ArrowFunctionExpression(node){ | ||
var code = new Code(node, context.code.source, FUNCTYPE.ARROW, false, context.code.strict); | ||
var code = new Code(node, null, FUNCTYPE.ARROW, SCOPE.FUNCTION); | ||
context.queue(code); | ||
record(FUNCTION, null, code); | ||
FUNCTION(null, code); | ||
} | ||
@@ -793,13 +846,10 @@ | ||
recurse(node.left); | ||
record(GET); | ||
GET(); | ||
recurse(node.right); | ||
record(GET); | ||
record(BINARY, BINARYOPS[node.operator]); | ||
GET(); | ||
BINARY(BINARYOPS[node.operator]); | ||
} | ||
function BreakStatement(node){ | ||
var entry = move(node); | ||
if (entry) { | ||
entry.breaks.push(record(JUMP, 0)); | ||
} | ||
move(node, 'breaks', JUMP(0)); | ||
} | ||
@@ -810,9 +860,5 @@ | ||
lexical(function(){ | ||
record(BLOCK, { LexicalDeclarations: LexicalDeclarations(node.body) }); | ||
for (var i=0, item; item = node.body[i]; i++) { | ||
recurse(item); | ||
} | ||
record(UPSCOPE); | ||
BLOCK({ LexicalDeclarations: LexicalDeclarations(node.body) }); | ||
each(node.body, recurse); | ||
UPSCOPE(); | ||
}); | ||
@@ -824,13 +870,13 @@ }); | ||
if (isSuperReference(node.callee)) { | ||
if (context.code.Type === 'global' || context.code.Type === 'eval' && context.code.global) { | ||
if (context.code.ScopeType !== SCOPE.FUNCTION) { | ||
throwError('illegal_super'); | ||
} | ||
record(SUPER_CALL); | ||
SUPER_CALL(); | ||
} else { | ||
recurse(node.callee); | ||
} | ||
record(DUP); | ||
record(GET); | ||
DUP(); | ||
GET(); | ||
args(node.arguments); | ||
record(node.callee.type === 'NativeIdentifier' ? NATIVE_CALL : CALL); | ||
node.callee.type === 'NativieIdentifier' ? NATIVE_CALL(): CALL(); | ||
} | ||
@@ -852,10 +898,7 @@ | ||
}); | ||
record(BLOCK, { LexicalDeclarations: decls }); | ||
BLOCK({ LexicalDeclarations: decls }); | ||
recurse(node.param); | ||
record(PUT); | ||
for (var i=0, item; item = node.body.body[i]; i++) { | ||
recurse(item); | ||
} | ||
record(UPSCOPE); | ||
PUT(); | ||
each(node.body.body, recurse); | ||
UPSCOPE(); | ||
}); | ||
@@ -867,7 +910,7 @@ } | ||
function ClassDeclaration(node){ | ||
record(CLASS_DECL, new ClassDefinition(node)); | ||
CLASS_DECL(new ClassDefinition(node)); | ||
} | ||
function ClassExpression(node){ | ||
record(CLASS_EXPR, new ClassDefinition(node)); | ||
CLASS_EXPR(new ClassDefinition(node)); | ||
} | ||
@@ -879,18 +922,15 @@ | ||
recurse(node.test); | ||
record(GET); | ||
var test = record(IFEQ, 0, false); | ||
GET(); | ||
var test = IFEQ(0, false); | ||
recurse(node.consequent) | ||
record(GET); | ||
var alt = record(JUMP, 0); | ||
GET(); | ||
var alt = JUMP(0); | ||
adjust(test); | ||
recurse(node.alternate); | ||
record(GET); | ||
adjust(alt) | ||
GET(); | ||
adjust(alt); | ||
} | ||
function ContinueStatement(node){ | ||
var entry = move(node); | ||
if (entry) { | ||
entry.continues.push(record(JUMP, 0)); | ||
} | ||
move(node, 'continues', JUMP(0)); | ||
} | ||
@@ -904,4 +944,4 @@ | ||
recurse(node.test); | ||
record(GET); | ||
record(IFEQ, start, true); | ||
GET(); | ||
IFEQ(start, true); | ||
return cond; | ||
@@ -912,18 +952,23 @@ }); | ||
function DebuggerStatement(node){ | ||
record(DEBUGGER); | ||
DEBUGGER(); | ||
} | ||
function EmptyStatement(node){} | ||
function ExportSpecifier(node){} | ||
function ExportSpecifierSet(node){} | ||
function ExportDeclaration(node){} | ||
function ExportSpecifierSet(node){ | ||
} | ||
function ExportDeclaration(node){ | ||
if (node.declaration) { | ||
recurse(node.declaration); | ||
} | ||
} | ||
function ExpressionStatement(node){ | ||
recurse(node.expression); | ||
record(GET); | ||
if (context.code.eval || context.code.global) { | ||
record(SAVE) | ||
} else { | ||
record(POP); | ||
} | ||
GET(); | ||
isGlobalOrEval() ? SAVE() : POP(); | ||
} | ||
@@ -933,27 +978,26 @@ | ||
control(function(){ | ||
var update; | ||
lexical(function(){ | ||
var scope = record(BLOCK, { LexicalDeclarations: [] }); | ||
var init = node.init; | ||
if (init){ | ||
if (init.type === 'VariableDeclaration') { | ||
var isLexical = isLexicalDeclaration(init); | ||
if (isLexical) { | ||
var scope = BLOCK({ LexicalDeclarations: [] }); | ||
recurse(init); | ||
if (init.kind === 'let' || init.kind === 'const') { | ||
var decl = init.declarations[init.declarations.length - 1].id; | ||
scope[0].LexicalDeclarations = BoundNames(decl); | ||
var lexicalDecl = { | ||
type: 'VariableDeclaration', | ||
kind: init.kind, | ||
declarations: [{ | ||
type: 'VariableDeclarator', | ||
id: decl, | ||
init: null | ||
}], | ||
}; | ||
lexicalDecl.BoundNames = BoundNames(lexicalDecl); | ||
recurse(decl); | ||
} | ||
var decl = init.declarations[init.declarations.length - 1].id; | ||
scope[0].LexicalDeclarations = BoundNames(decl); | ||
var lexicalDecl = { | ||
type: 'VariableDeclaration', | ||
kind: init.kind, | ||
declarations: [{ | ||
type: 'VariableDeclarator', | ||
id: decl, | ||
init: null | ||
}], | ||
}; | ||
lexicalDecl.BoundNames = BoundNames(lexicalDecl); | ||
recurse(decl); | ||
} else { | ||
record(GET); | ||
record(POP); | ||
recurse(init); | ||
GET(); | ||
POP(); | ||
} | ||
@@ -966,7 +1010,7 @@ } | ||
recurse(node.test); | ||
record(GET); | ||
var op = record(IFEQ, 0, false); | ||
GET(); | ||
var op = IFEQ(0, false); | ||
} | ||
update = current(); | ||
var update = current(); | ||
@@ -978,13 +1022,9 @@ if (node.body.body && decl) { | ||
lexicals.push(lexicalDecl); | ||
record(GET); | ||
record(BLOCK, { LexicalDeclarations: lexicals }); | ||
GET(); | ||
BLOCK({ LexicalDeclarations: lexicals }); | ||
recurse(decl); | ||
record(ROTATE, 1); | ||
record(PUT); | ||
for (var i=0, item; item = node.body.body[i]; i++) { | ||
recurse(item); | ||
} | ||
record(UPSCOPE); | ||
ROTATE(1); | ||
PUT(); | ||
each(node.body.body, recurse); | ||
UPSCOPE(); | ||
}); | ||
@@ -998,11 +1038,11 @@ }); | ||
recurse(node.update); | ||
record(GET); | ||
record(POP); | ||
GET(); | ||
POP(); | ||
} | ||
record(JUMP, test); | ||
JUMP(test); | ||
adjust(op); | ||
record(UPSCOPE); | ||
isLexical && UPSCOPE(); | ||
return update; | ||
}); | ||
return update; | ||
}); | ||
@@ -1019,3 +1059,3 @@ } | ||
function iteration(node, kind){ | ||
function iteration(node, KIND){ | ||
control(function(){ | ||
@@ -1025,22 +1065,22 @@ var update; | ||
recurse(node.right); | ||
record(GET); | ||
record(kind); | ||
record(GET); | ||
record(DUP); | ||
record(MEMBER, 'next'); | ||
record(GET); | ||
GET(); | ||
KIND(); | ||
GET(); | ||
DUP(); | ||
MEMBER('next'); | ||
GET(); | ||
update = current(); | ||
record(DUP); | ||
record(DUP); | ||
record(ARGS); | ||
record(CALL); | ||
record(DUP); | ||
var compare = record(IFEQ, 0, false); | ||
DUP(); | ||
DUP(); | ||
ARGS(); | ||
CALL(); | ||
DUP(); | ||
var compare = IFEQ(0, false); | ||
if (node.left.type === 'VariableDeclaration' && node.left.kind !== 'var') { | ||
block(function(){ | ||
lexical(function(){ | ||
record(BLOCK, { LexicalDeclarations: LexicalDeclarations(node.left) }); | ||
BLOCK({ LexicalDeclarations: LexicalDeclarations(node.left) }); | ||
recurse(node.left); | ||
recurse(node.body); | ||
record(UPSCOPE); | ||
UPSCOPE(); | ||
}); | ||
@@ -1052,3 +1092,3 @@ }); | ||
} | ||
record(JUMP, update); | ||
JUMP(update); | ||
adjust(compare); | ||
@@ -1061,3 +1101,3 @@ }); | ||
function FunctionDeclaration(node){ | ||
node.Code = new Code(node, context.code.source, FUNCTYPE.NORMAL, false, context.code.strict); | ||
node.Code = new Code(node, null, FUNCTYPE.NORMAL, SCOPE.FUNCTION); | ||
context.queue(node.Code); | ||
@@ -1067,3 +1107,3 @@ } | ||
function FunctionExpression(node, methodName){ | ||
var code = new Code(node, context.code.source, FUNCTYPE.NORMAL, false, context.code.strict); | ||
var code = new Code(node, null, FUNCTYPE.NORMAL, SCOPE.FUNCTION); | ||
if (methodName) { | ||
@@ -1073,3 +1113,3 @@ code.name = methodName; | ||
context.queue(code); | ||
record(FUNCTION, intern(node.id ? node.id.name : ''), code); | ||
FUNCTION(intern(node.id ? node.id.name : ''), code); | ||
} | ||
@@ -1080,3 +1120,3 @@ | ||
function Identifier(node){ | ||
record(REF, intern(node.name)); | ||
REF(node.name); | ||
} | ||
@@ -1086,8 +1126,8 @@ | ||
recurse(node.test); | ||
record(GET); | ||
var test = record(IFEQ, 0, false); | ||
GET(); | ||
var test = IFEQ(0, false); | ||
recurse(node.consequent); | ||
if (node.alternate) { | ||
var alt = record(JUMP, 0); | ||
var alt = JUMP(0); | ||
adjust(test); | ||
@@ -1101,13 +1141,23 @@ recurse(node.alternate); | ||
function ImportDeclaration(node){} | ||
function ImportDeclaration(node){ | ||
// recurse(node.from); | ||
// IMPORT(); | ||
// each(node.specifiers, function(specifier){ | ||
// recurse(specifier); | ||
// GET(); | ||
// PUT(); | ||
// }); | ||
} | ||
function ImportSpecifier(spec){} | ||
function ImportSpecifier(node){ | ||
} | ||
function Literal(node){ | ||
if (node.value instanceof RegExp) { | ||
record(REGEXP, node.value); | ||
REGEXP(node.value); | ||
} else if (typeof node.value === 'string') { | ||
record(STRING, intern(node.value)); | ||
STRING(node.value); | ||
} else { | ||
record(LITERAL, node.value); | ||
LITERAL(node.value); | ||
} | ||
@@ -1129,6 +1179,6 @@ } | ||
recurse(node.left); | ||
record(GET); | ||
var op = record(IFNE, 0, node.operator === '||'); | ||
GET(); | ||
var op = IFNE(0, node.operator === '||'); | ||
recurse(node.right); | ||
record(GET); | ||
GET(); | ||
adjust(op); | ||
@@ -1140,3 +1190,3 @@ } | ||
if (isSuper){ | ||
if (context.code.Type === 'global' || context.code.Type === 'eval' && context.code.global) { | ||
if (context.code.ScopeType !== SCOPE.FUNCTION) { | ||
throwError('illegal_super_reference'); | ||
@@ -1146,3 +1196,3 @@ } | ||
recurse(node.object); | ||
record(GET); | ||
GET(); | ||
} | ||
@@ -1152,14 +1202,21 @@ | ||
recurse(node.property); | ||
record(GET); | ||
record(isSuper ? SUPER_ELEMENT : ELEMENT); | ||
GET(); | ||
isSuper ? SUPER_ELEMENT() : ELEMENT(); | ||
} else { | ||
record(isSuper ? SUPER_MEMBER : MEMBER, intern(node.property.name)); | ||
isSuper ? SUPER_MEMBER() : MEMBER(node.property.name); | ||
} | ||
} | ||
function MethodDefinition(node){} | ||
function ModuleDeclaration(node){} | ||
function ModuleDeclaration(node){ | ||
if (node.body) { | ||
node.Code = new Code(node, null, FUNCTYPE.NORMAL, SCOPE.MODULE); | ||
node.Code.path = context.code.path.concat(node.id.name); | ||
context.queue(node.Code); | ||
} | ||
} | ||
function NativeIdentifier(node){ | ||
record(NATIVE_REF, intern(node.name)); | ||
NATIVE_REF(node.name); | ||
} | ||
@@ -1169,12 +1226,10 @@ | ||
recurse(node.callee); | ||
record(GET); | ||
GET(); | ||
args(node.arguments); | ||
record(CONSTRUCT); | ||
CONSTRUCT(); | ||
} | ||
function ObjectExpression(node){ | ||
record(OBJECT); | ||
for (var i=0, item; item = node.properties[i]; i++) { | ||
recurse(item); | ||
} | ||
OBJECT(); | ||
each(node.properties, recurse); | ||
} | ||
@@ -1184,8 +1239,8 @@ | ||
function Path(){} | ||
function Path(node){ | ||
} | ||
function Program(node){ | ||
for (var i=0, item; item = node.body[i]; i++) { | ||
recurse(item); | ||
} | ||
each(node.body, recurse); | ||
} | ||
@@ -1201,8 +1256,8 @@ | ||
} | ||
record(GET); | ||
record(PROPERTY, intern(key)); | ||
GET(); | ||
PROPERTY(key); | ||
} else { | ||
var code = new Code(node.value, context.source, FUNCTYPE.NORMAL, false, context.code.strict); | ||
var code = new Code(node.value, context.source, FUNCTYPE.NORMAL, SCOPE.FUNCTION, context.code.Strict); | ||
context.queue(code); | ||
record(METHOD, node.kind, code, intern(node.key.name)); | ||
METHOD(node.kind, code, intern(node.key.name)); | ||
} | ||
@@ -1214,8 +1269,8 @@ } | ||
recurse(node.argument); | ||
record(GET); | ||
GET(); | ||
} else { | ||
record(UNDEFINED); | ||
UNDEFINED(); | ||
} | ||
record(RETURN); | ||
RETURN(); | ||
} | ||
@@ -1226,7 +1281,7 @@ | ||
recurse(item) | ||
record(GET); | ||
record(POP); | ||
GET(); | ||
POP(); | ||
} | ||
recurse(item); | ||
record(GET); | ||
GET(); | ||
} | ||
@@ -1237,14 +1292,14 @@ | ||
recurse(node.discriminant); | ||
record(GET); | ||
GET(); | ||
lexical(function(){ | ||
record(BLOCK, { LexicalDeclarations: LexicalDeclarations(node.cases) }); | ||
BLOCK({ LexicalDeclarations: LexicalDeclarations(node.cases) }); | ||
if (node.cases){ | ||
var cases = []; | ||
for (var i=0, item; item = node.cases[i]; i++) { | ||
each(node.cases, function(item, i){ | ||
if (item.test){ | ||
recurse(item.test); | ||
record(GET); | ||
cases.push(record(CASE, 0)); | ||
GET(); | ||
cases.push(CASE(0)); | ||
} else { | ||
@@ -1254,17 +1309,15 @@ var defaultFound = i; | ||
} | ||
} | ||
}); | ||
if (defaultFound != null){ | ||
record(DEFAULT, cases[defaultFound]); | ||
DEFAULT(cases[defaultFound]); | ||
} else { | ||
record(POP); | ||
var last = record(JUMP, 0); | ||
POP(); | ||
var last = JUMP(0); | ||
} | ||
for (var i=0, item; item = node.cases[i]; i++) { | ||
each(node.cases, function(item, i){ | ||
adjust(cases[i]) | ||
for (var j=0, consequent; consequent = item.consequent[j]; j++) { | ||
recurse(consequent); | ||
} | ||
} | ||
each(item.consequent, recurse); | ||
}); | ||
@@ -1275,6 +1328,6 @@ if (last) { | ||
} else { | ||
record(POP); | ||
POP(); | ||
} | ||
record(UPSCOPE); | ||
UPSCOPE(); | ||
}); | ||
@@ -1284,10 +1337,42 @@ }); | ||
function TemplateElement(node){} | ||
function TemplateLiteral(node){} | ||
function TemplateLiteral(node, tagged){ | ||
each(node.quasis, function(element, i){ | ||
STRING(element.value.raw); | ||
if (!element.tail) { | ||
recurse(node.expressions[i]); | ||
GET(); | ||
BINARY(BINARYOPS['string+']); | ||
} | ||
if (i) { | ||
BINARY(BINARYOPS['string+']); | ||
} | ||
}); | ||
} | ||
function TaggedTemplateExpression(node){} | ||
function TaggedTemplateExpression(node){ | ||
var template = []; | ||
each(node.quasi.quasis, function(element){ | ||
template.push(element.value); | ||
}); | ||
UNDEFINED(); | ||
recurse(node.tag); | ||
GET(); | ||
ARGS(); | ||
TEMPLATE(template); | ||
GET(); | ||
ARG(); | ||
each(node.quasi.expressions, function(node){ | ||
recurse(node); | ||
GET(); | ||
ARG(); | ||
}); | ||
CALL(); | ||
} | ||
function ThisExpression(node){ | ||
record(THIS); | ||
THIS(); | ||
} | ||
@@ -1297,4 +1382,4 @@ | ||
recurse(node.argument); | ||
record(GET); | ||
record(THROW); | ||
GET(); | ||
THROW(); | ||
} | ||
@@ -1307,3 +1392,3 @@ | ||
var tryer = record(JUMP, 0), | ||
var tryer = JUMP(0), | ||
handlers = []; | ||
@@ -1314,3 +1399,3 @@ | ||
if (i < node.handlers.length - 1) { | ||
handlers.push(record(JUMP, 0)); | ||
handlers.push(JUMP(0)); | ||
} | ||
@@ -1331,3 +1416,3 @@ } | ||
recurse(node.argument); | ||
record(UNARY, UNARYOPS[node.operator]); | ||
UNARY(UNARYOPS[node.operator]); | ||
} | ||
@@ -1337,7 +1422,7 @@ | ||
recurse(node.argument); | ||
record(UPDATE, !!node.prefix | ((node.operator === '++') << 1)); | ||
UPDATE(!!node.prefix | ((node.operator === '++') << 1)); | ||
} | ||
function VariableDeclaration(node){ | ||
var op = { | ||
var DECLARE = { | ||
'var': VAR, | ||
@@ -1348,20 +1433,14 @@ 'const': CONST, | ||
for (var i=0, item; item = node.declarations[i]; i++) { | ||
each(node.declarations, function(item){ | ||
if (item.init) { | ||
recurse(item.init); | ||
record(GET); | ||
} else if (item.kind === 'let') { | ||
record(UNDEFINED); | ||
GET(); | ||
} | ||
//if (item.id.type === 'Identifier') { | ||
// record(op, intern(item.id.name)); | ||
//} else { | ||
record(op, item.id); | ||
//} | ||
DECLARE(item.id); | ||
if (node.kind === 'var') { | ||
context.code.VarDeclaredNames.push(intern(item.id.name)); | ||
push.apply(context.code.VarDeclaredNames, BoundNames(item.id)); | ||
} | ||
} | ||
}); | ||
} | ||
@@ -1375,6 +1454,6 @@ | ||
recurse(node.test); | ||
record(GET); | ||
var op = record(IFEQ, 0, false) | ||
GET(); | ||
var op = IFEQ(0, false) | ||
recurse(node.body); | ||
record(JUMP, start); | ||
JUMP(start); | ||
adjust(op); | ||
@@ -1388,10 +1467,19 @@ return start; | ||
lexical(function(){ | ||
record(WITH); | ||
WITH(); | ||
recurse(node.body); | ||
record(UPSCOPE); | ||
UPSCOPE(); | ||
}); | ||
} | ||
function YieldExpression(node){} | ||
function YieldExpression(node){ | ||
if (node.argument){ | ||
recurse(node.argument); | ||
GET(); | ||
} else { | ||
UNDEFINED(); | ||
} | ||
YIELD(node.delegate); | ||
} | ||
var handlers = {}; | ||
@@ -1416,10 +1504,142 @@ | ||
function assemble(options){ | ||
var assembler = new Assembler(assign({ normal: false }, options)); | ||
var Assembler = exports.Assembler = (function(){ | ||
function annotateParent(node, parent){ | ||
walk(node, function(node){ | ||
if (isObject(node) && parent) { | ||
define(node, 'parent', parent); | ||
} | ||
return walk.RECURSE; | ||
}); | ||
} | ||
function reinterpretNatives(node){ | ||
walk(node, function(node){ | ||
if (node.type === 'Identifier' && /^\$__/.test(node.name)) { | ||
node.type = 'NativeIdentifier'; | ||
node.name = node.name.slice(3); | ||
} else { | ||
return walk.RECURSE; | ||
} | ||
}); | ||
} | ||
function AssemblerOptions(o){ | ||
o = Object(o); | ||
for (var k in this) | ||
this[k] = k in o ? o[k] : this[k]; | ||
} | ||
AssemblerOptions.prototype = { | ||
scope: SCOPE.GLOBAL, | ||
natives: false, | ||
filename: null | ||
}; | ||
function Assembler(options){ | ||
this.options = new AssemblerOptions(options); | ||
define(this, { | ||
strings: [], | ||
hash: create(null) | ||
}); | ||
} | ||
define(Assembler.prototype, { | ||
source: null, | ||
node: null, | ||
code: null, | ||
pending: null, | ||
jumps: null, | ||
labels: null, | ||
}); | ||
define(Assembler.prototype, [ | ||
function assemble(node, source){ | ||
context = this; | ||
this.pending = new Stack; | ||
this.jumps = new Stack; | ||
this.labels = null; | ||
this.source = source; | ||
if (this.options.scope === SCOPE.FUNCTION) { | ||
node = node.body[0].expression; | ||
} | ||
var code = new Code(node, source, FUNCTYPE.NORMAL, this.options.scope); | ||
define(code, { | ||
strings: this.strings, | ||
hash: this.hash | ||
}); | ||
code.topLevel = true; | ||
if (this.options.natives) { | ||
code.natives = true; | ||
reinterpretNatives(node); | ||
} | ||
annotateParent(node); | ||
this.queue(code); | ||
while (this.pending.length) { | ||
var lastCode = this.code; | ||
this.code = this.pending.pop(); | ||
this.code.filename = this.filename; | ||
if (lastCode) { | ||
this.code.derive(lastCode); | ||
} | ||
recurse(this.code.body); | ||
if (this.code.ScopeType === SCOPE.GLOBAL || this.code.ScopeType === SCOPE.EVAL){ | ||
COMPLETE(); | ||
} else { | ||
if (this.code.Type === FUNCTYPE.ARROW && this.code.body.type !== 'BlockStatement') { | ||
GET(); | ||
} else { | ||
UNDEFINED(); | ||
} | ||
RETURN(); | ||
} | ||
} | ||
return code; | ||
}, | ||
function queue(code){ | ||
if (this.code) { | ||
this.code.children.push(code); | ||
} | ||
this.pending.push(code); | ||
}, | ||
function intern(name){ | ||
return name; | ||
if (name === '__proto__') { | ||
if (!this.hash[proto]) { | ||
var index = this.hash[proto] = this.strings.length; | ||
this.strings[index] = '__proto__'; | ||
} | ||
name = proto; | ||
} | ||
if (name in this.hash) { | ||
return this.hash[name]; | ||
} else { | ||
var index = this.hash[name] = this.strings.length; | ||
this.strings[index] = name; | ||
return index; | ||
} | ||
}, | ||
]); | ||
return Assembler; | ||
})(); | ||
exports.assemble = function assemble(options){ | ||
var assembler = new Assembler(options); | ||
return assembler.assemble(options.ast, options.source); | ||
} | ||
}; | ||
exports.assemble = assemble; | ||
return exports; | ||
})(typeof module !== 'undefined' ? module.exports : {}); | ||
@@ -54,2 +54,3 @@ var constants = (function(exports){ | ||
exports.BRANDS = { | ||
BooleanWrapper : new NativeBrand('Boolean'), | ||
GlobalObject : new NativeBrand('global'), | ||
@@ -59,4 +60,8 @@ NativeArguments : new NativeBrand('Arguments'), | ||
NativeDate : new NativeBrand('Date'), | ||
NativeError : new NativeBrand('Error'), | ||
NativeFunction : new NativeBrand('Function'), | ||
NativeJSON : new NativeBrand('JSON'), | ||
NativeMap : new NativeBrand('Map'), | ||
NativeMath : new NativeBrand('Math'), | ||
NativeModule : new NativeBrand('Module'), | ||
NativeObject : new NativeBrand('Object'), | ||
@@ -67,9 +72,5 @@ NativePrivateName : new NativeBrand('PrivateName'), | ||
NativeWeakMap : new NativeBrand('WeakMap'), | ||
BooleanWrapper : new NativeBrand('Boolean'), | ||
NumberWrapper : new NativeBrand('Number'), | ||
StringWrapper : new NativeBrand('String'), | ||
NativeError : new NativeBrand('Error'), | ||
NativeMath : new NativeBrand('Math'), | ||
NativeJSON : new NativeBrand('JSON'), | ||
StopIteration : new NativeBrand('StopIteration') | ||
StopIteration : new NativeBrand('StopIteration'), | ||
StringWrapper : new NativeBrand('String') | ||
}; | ||
@@ -79,6 +80,7 @@ | ||
exports.BINARYOPS = new Constants(['instanceof', 'in', 'is', 'isnt', '==', '!=', '===', '!==', '<', '>', | ||
'<=', '>=', '*', '/','%', '+', '-', '<<', '>>', '>>>', '|', '&', '^']); | ||
'<=', '>=', '*', '/','%', '+', '-', '<<', '>>', '>>>', '|', '&', '^', 'string+']); | ||
exports.UNARYOPS = new Constants(['delete', 'void', 'typeof', '+', '-', '~', '!']); | ||
exports.ENTRY = new Constants(['ENV', 'FINALLY', 'TRYCATCH', 'FOROF' ]); | ||
exports.FUNCTYPE = new Constants(['NORMAL', 'METHOD', 'ARROW' ]); | ||
exports.SCOPE = new Constants(['EVAL', 'FUNCTION', 'GLOBAL', 'MODULE' ]); | ||
@@ -85,0 +87,0 @@ exports.SYMBOLS = { |
@@ -7,2 +7,3 @@ var debug = (function(exports){ | ||
create = utility.create, | ||
each = utility.each, | ||
define = utility.define; | ||
@@ -43,2 +44,5 @@ | ||
}, | ||
getValue: function(){ | ||
return _Undefined; | ||
}, | ||
kind: 'Unknown', | ||
@@ -52,10 +56,10 @@ label: always(''), | ||
getterAttrs: alwaysCall(create, [null]), | ||
isExtensible: always(null), | ||
isEnumerable: always(null), | ||
isConfigurable: always(null), | ||
isPropExtensible: always(null), | ||
isPropEnumerable: always(null), | ||
isPropConfigurable: always(null), | ||
getOwnDescriptor: always(null), | ||
getDescriptor: always(null), | ||
getProperty: always(null), | ||
isAccessor: always(null), | ||
isWritable: always(null), | ||
isPropAccessor: always(null), | ||
isPropWritable: always(null), | ||
propAttributes: always(null) | ||
@@ -111,3 +115,7 @@ }); | ||
this.subject = accessor.Get.Call(holder, key); | ||
this.introspected = introspect(this.subject); | ||
if (this.subject.__introspected) { | ||
this.introspected = this.subject.__introspected; | ||
} else { | ||
this.introspected = introspect(this.subject); | ||
} | ||
this.kind = this.introspected.kind; | ||
@@ -118,7 +126,26 @@ this.type = this.introspected.type; | ||
inherit(MirrorAccessor, Mirror, { | ||
label: function(){ | ||
return this.introspected.label(); | ||
}, | ||
}); | ||
void function(){ | ||
inherit(MirrorAccessor, Mirror, { | ||
accessor: true | ||
}, [ | ||
function label(){ | ||
return this.introspected.label(); | ||
}, | ||
function getName(){ | ||
return this.subject.properties.get('name'); | ||
}, | ||
function getParams(){ | ||
var params = this.subject.FormalParameters; | ||
if (params && params.ArgNames) { | ||
var names = params.ArgNames.slice(); | ||
if (params.Rest) { | ||
names.rest = true; | ||
} | ||
return names; | ||
} else { | ||
return []; | ||
} | ||
} | ||
]); | ||
}(); | ||
@@ -139,2 +166,3 @@ var proto = Math.random().toString(36).slice(2); | ||
type: 'object', | ||
parentLabel: '[[proto]]', | ||
attrs: null, | ||
@@ -437,6 +465,10 @@ props: null | ||
function MirrorThrown(subject){ | ||
MirrorError.call(this, subject); | ||
if (utility.isObject(subject)) { | ||
MirrorError.call(this, subject); | ||
} else { | ||
return introspect(subject); | ||
} | ||
} | ||
void function(){ | ||
void function(){ | ||
inherit(MirrorThrown, MirrorError, { | ||
@@ -453,3 +485,3 @@ kind: 'Thrown' | ||
var file = this.getValue('filename') || '', | ||
type = this.getValue('type') || ''; | ||
type = this.getValue('kind') || ''; | ||
@@ -482,4 +514,4 @@ return file && type ? type + ' ' + file : type + file; | ||
var params = this.subject.FormalParameters; | ||
if (params && params.ArgNames) { | ||
var names = params.ArgNames.slice(); | ||
if (params && params.BoundNames) { | ||
var names = params.BoundNames.slice(); | ||
if (params.Rest) { | ||
@@ -511,2 +543,5 @@ names.rest = true; | ||
} | ||
}, | ||
function getScope(){ | ||
return introspect(this.subject.Scope); | ||
} | ||
@@ -516,3 +551,2 @@ ]); | ||
function MirrorGlobal(subject){ | ||
@@ -522,5 +556,11 @@ MirrorObject.call(this, subject); | ||
inherit(MirrorGlobal, MirrorObject, { | ||
kind: 'Global' | ||
}, []); | ||
void function(){ | ||
inherit(MirrorGlobal, MirrorObject, { | ||
kind: 'Global' | ||
}, [ | ||
function getEnvironment(){ | ||
return introspect(this.subject.env); | ||
} | ||
]); | ||
}(); | ||
@@ -553,2 +593,34 @@ | ||
function MirrorModule(subject){ | ||
MirrorObject.call(this, subject); | ||
} | ||
void function(){ | ||
inherit(MirrorModule, MirrorObject, { | ||
kind: 'Module' | ||
}, [ | ||
function get(key){ | ||
if (this.isPropAccessor(key)) { | ||
if (!this.accessors[key]) { | ||
var prop = this.getProperty(key), | ||
accessor = prop[1] || prop[3]; | ||
realm().enterMutationContext(); | ||
this.accessors[key] = introspect(accessor.Get.Call(this.subject, [])); | ||
realm().exitMutationContext(); | ||
} | ||
return this.accessors[key]; | ||
} else { | ||
var prop = this.props.getProperty(key); | ||
if (prop) { | ||
return introspect(prop[1]); | ||
} else { | ||
return this.getPrototype().get(key); | ||
} | ||
} | ||
}, | ||
]); | ||
}(); | ||
function MirrorNumber(subject){ | ||
@@ -757,2 +829,148 @@ MirrorObject.call(this, subject); | ||
var MirrorScope = (function(){ | ||
function MirrorScope(subject){ | ||
if (subject.type === 'Global Env') { | ||
return new MirrorGlobalScope(subject); | ||
} | ||
subject.__introspected = this; | ||
this.subject = subject; | ||
} | ||
inherit(MirrorScope, Mirror, { | ||
kind: 'Scope', | ||
type: 'scope', | ||
parentLabel: '[[outer]]', | ||
isExtensible: always(true), | ||
isPropEnumerable: always(true), | ||
isPropAccessor: always(false) | ||
}, [ | ||
function isPropAccessor(key){ | ||
return this.getPrototype().isPropAccessor(key) || false; | ||
}, | ||
function getPrototype(){ | ||
return introspect(this.subject.outer); | ||
}, | ||
function getValue(key){ | ||
return this.subject.GetBindingValue(key); | ||
}, | ||
function get(key){ | ||
return introspect(this.subject.GetBindingValue(key)); | ||
}, | ||
function getOwn(key){ | ||
if (this.hasOwn(key)) { | ||
return introspect(this.subject.GetBindingValue(key)); | ||
} | ||
}, | ||
function label(){ | ||
return this.subject.type; | ||
}, | ||
function hasOwn(key){ | ||
return this.subject.HasBinding(key); | ||
}, | ||
function has(key){ | ||
return this.subject.HasBinding(key) || this.getPrototype().has(key); | ||
}, | ||
function inheritedAttrs(){ | ||
return this.ownAttrs(this.getPrototype().inheritedAttrs()); | ||
}, | ||
function ownAttrs(props){ | ||
props || (props = create(null)); | ||
each(this.subject.EnumerateBindings(), function(key){ | ||
key = key === '__proto__' ? proto : key; | ||
props[key] = key | ||
}); | ||
return props; | ||
}, | ||
function list(hidden, own){ | ||
own = true; | ||
var props = own ? this.ownAttrs() : this.inheritedAttrs(), | ||
keys = []; | ||
for (var k in props) { | ||
keys.push(k === proto ? '__proto__' : k); | ||
} | ||
return keys.sort(); | ||
}, | ||
function isPropConfigurable(key){ | ||
return !(this.subject.deletables && key in this.subject.deletables); | ||
}, | ||
function isPropWritable(key){ | ||
return !(this.subject.consts && key in this.subject.consts); | ||
}, | ||
function getOwnDescriptor(key){ | ||
if (this.hasOwn(key)) { | ||
return { configurable: this.isPropConfigurable(key), | ||
enumerable: true, | ||
writable: this.isPropWritable(key), | ||
value: this.get(key) }; | ||
} | ||
}, | ||
function getDescriptor(key){ | ||
return this.getOwnDescriptor(key) || this.getPrototype().getDescriptor(key); | ||
}, | ||
function getProperty(key){ | ||
return [this.subject.GetBindingValue(key), value, this.propAttributes(key)]; | ||
}, | ||
function propAttributes(key){ | ||
return 1 | (this.isPropConfigurable(key) << 1) | (this.isPropWritable(key) << 2); | ||
}, | ||
]); | ||
return MirrorScope; | ||
})(); | ||
var MirrorGlobalScope = (function(){ | ||
function MirrorGlobalScope(subject){ | ||
subject.__introspected = this; | ||
this.subject = subject; | ||
this.global = introspect(subject.bindings); | ||
} | ||
inherit(MirrorGlobalScope, MirrorScope, { | ||
}, [ | ||
function isExtensible(){ | ||
return this.global.isExtensible(); | ||
}, | ||
function isPropEnumerable(key){ | ||
return this.global.isPropEnumerable(key); | ||
}, | ||
function isPropConfigurable(key){ | ||
return this.global.isPropConfigurable(key); | ||
}, | ||
function isPropWritable(key){ | ||
return this.global.isPropWritable(key); | ||
}, | ||
function isPropAccessor(key){ | ||
return this.global.isPropAccessor(key); | ||
}, | ||
function propAttributes(key){ | ||
return this.global.propAttributes(key); | ||
}, | ||
function getProperty(key){ | ||
return this.global.getProperty(key); | ||
}, | ||
function getDescriptor(key){ | ||
return this.global.getDescriptor(key); | ||
}, | ||
function getOwnDescriptor(key){ | ||
return this.global.getOwnDescriptor(key); | ||
}, | ||
function inheritedAttrs(){ | ||
return this.global.inheritedAttrs(); | ||
}, | ||
function ownAttrs(props){ | ||
return this.global.ownAttrs(props); | ||
}, | ||
function list(hidden, own){ | ||
return this.global.list(hidden, own); | ||
} | ||
]); | ||
return MirrorGlobalScope; | ||
})(); | ||
var brands = { | ||
@@ -769,3 +987,3 @@ Arguments: MirrorArguments, | ||
Math : MirrorMath, | ||
Map : MirrorMap, | ||
Module : MirrorModule, | ||
Number : MirrorNumber, | ||
@@ -830,25 +1048,21 @@ RegExp : MirrorRegExp, | ||
return _Null; | ||
} | ||
if (subject instanceof Mirror) { | ||
} else if (subject instanceof Mirror) { | ||
return subject; | ||
} | ||
if (subject.__introspected) { | ||
} else if (subject.__introspected) { | ||
return subject.__introspected; | ||
} | ||
if (subject.Completion) { | ||
} else if (subject.Environment) { | ||
return new MirrorScope(subject); | ||
} else if (subject.Completion) { | ||
return new MirrorThrown(subject.value); | ||
} else if (subject.NativeBrand) { | ||
if (!subject.isProxy) { | ||
var Ctor = subject.NativeBrand.name in brands | ||
? brands[subject.NativeBrand.name] | ||
: 'Call' in subject | ||
? MirrorFunction | ||
: MirrorObject; | ||
return new Ctor(subject); | ||
if (subject.isProxy) { | ||
return new MirrorProxy(subject); | ||
} else if ('Call' in subject) { | ||
return new MirrorFunction(subject); | ||
} else if (subject.NativeBrand.name in brands) { | ||
return new brands[subject.NativeBrand.name](subject); | ||
} else { | ||
return new MirrorProxy(subject); | ||
return new MirrorObject(subject); | ||
} | ||
} else { | ||
console.log(subject); | ||
return _Undefined | ||
@@ -871,3 +1085,3 @@ } | ||
var label = function(mirror){ | ||
var alwaysLabel = function(mirror){ | ||
return mirror.label(); | ||
@@ -877,4 +1091,4 @@ }; | ||
Renderer.prototype = { | ||
Unknown: label, | ||
BooleanValue: label, | ||
Unknown: alwaysLabel, | ||
BooleanValue: alwaysLabel, | ||
StringValue: function(mirror){ | ||
@@ -887,26 +1101,28 @@ return utility.quotes(mirror.subject); | ||
}, | ||
UndefinedValue: label, | ||
NullValue: label, | ||
UndefinedValue: alwaysLabel, | ||
NullValue: alwaysLabel, | ||
Thrown: function(mirror){ | ||
return mirror.getError(); | ||
}, | ||
Accessor: label, | ||
Arguments: label, | ||
Array: label, | ||
Boolean: label, | ||
Date: label, | ||
Accessor: alwaysLabel, | ||
Arguments: alwaysLabel, | ||
Array: alwaysLabel, | ||
Boolean: alwaysLabel, | ||
Date: alwaysLabel, | ||
Error: function(mirror){ | ||
return mirror.getValue('name') + ': ' + mirror.getValue('message'); | ||
}, | ||
Function: label, | ||
Global: label, | ||
JSON: label, | ||
Map: label, | ||
Math: label, | ||
Object: label, | ||
Number: label, | ||
RegExp: label, | ||
Set: label, | ||
String: label, | ||
WeakMap: label | ||
Function: alwaysLabel, | ||
Global: alwaysLabel, | ||
JSON: alwaysLabel, | ||
Map: alwaysLabel, | ||
Math: alwaysLabel, | ||
Module: alwaysLabel, | ||
Object: alwaysLabel, | ||
Number: alwaysLabel, | ||
RegExp: alwaysLabel, | ||
Scope: alwaysLabel, | ||
Set: alwaysLabel, | ||
String: alwaysLabel, | ||
WeakMap: alwaysLabel | ||
}; | ||
@@ -913,0 +1129,0 @@ |
@@ -81,3 +81,3 @@ var errors = (function(errors, messages, exports){ | ||
} | ||
error = errors[type]; | ||
var error = errors[type]; | ||
return exports.createError(error.name, type, error.apply(null, args)); | ||
@@ -119,2 +119,3 @@ } | ||
undefined_to_object : ["Cannot convert undefined to object"], | ||
object_not_coercible : ["$0", " cannot convert ", "$1", " to an object"], | ||
reduce_no_initial : ["Reduce of empty array with no initial value"], | ||
@@ -164,3 +165,6 @@ callback_must_be_callable : ["$0", " requires a function callback"], | ||
double_initialization : ["Initializating an already initialized ", "$0"], | ||
construct_arrow_function : ["Arrow functions cannot be constructed"] | ||
construct_arrow_function : ["Arrow functions cannot be constructed"], | ||
generator_executing : ["'", "$0", "' called on executing generator"], | ||
generator_closed : ["'", "$0", "' called on closed generator"], | ||
generator_send_newborn : ["Sent value into newborn generator"] | ||
}, | ||
@@ -167,0 +171,0 @@ ReferenceError: { |
@@ -218,3 +218,3 @@ var operators = (function(exports){ | ||
return argument >>> 0;; | ||
return argument >> 0;; | ||
} | ||
@@ -457,2 +457,4 @@ exports.ToInteger = ToInteger; | ||
function ADD(lval, rval) { | ||
@@ -491,2 +493,9 @@ lval = ToPrimitive(lval); | ||
function STRING_ADD(lval, rval){ | ||
return convertAdd(lval, rval, STRING, ToString); | ||
} | ||
exports.STRING_ADD = STRING_ADD; | ||
var SHL, SHR, SAR; | ||
@@ -802,24 +811,25 @@ void function(makeShifter){ | ||
case 'instanceof': return INSTANCE_OF(lval, rval); | ||
case 'in': return IN(lval, rval); | ||
case 'is': return IS(lval, rval); | ||
case 'isnt': return NOT(IS(lval, rval)); | ||
case '==': return EQUAL(lval, rval); | ||
case '!=': return NOT(EQUAL(lval, rval)); | ||
case '===': return STRICT_EQUAL(lval, rval); | ||
case '!==': return NOT(STRICT_EQUAL(lval, rval)); | ||
case '<': return LT(lval, rval); | ||
case '>': return GT(lval, rval); | ||
case '<=': return LTE(lval, rval); | ||
case '>=': return GTE(lval, rval); | ||
case '*': return MUL(lval, rval); | ||
case '/': return DIV(lval, rval); | ||
case '%': return MOD(lval, rval); | ||
case '+': return ADD(lval, rval); | ||
case '-': return SUB(lval, rval); | ||
case '<<': return SHL(lval, rval); | ||
case '>>': return SHR(lval, rval); | ||
case '>>>': return SAR(lval, rval); | ||
case '|': return BIT_OR(lval, rval); | ||
case '&': return BIT_AND(lval, rval); | ||
case '^': return BIT_XOR(lval, rval); | ||
case 'in': return IN(lval, rval); | ||
case 'is': return IS(lval, rval); | ||
case 'isnt': return NOT(IS(lval, rval)); | ||
case '==': return EQUAL(lval, rval); | ||
case '!=': return NOT(EQUAL(lval, rval)); | ||
case '===': return STRICT_EQUAL(lval, rval); | ||
case '!==': return NOT(STRICT_EQUAL(lval, rval)); | ||
case '<': return LT(lval, rval); | ||
case '>': return GT(lval, rval); | ||
case '<=': return LTE(lval, rval); | ||
case '>=': return GTE(lval, rval); | ||
case '*': return MUL(lval, rval); | ||
case '/': return DIV(lval, rval); | ||
case '%': return MOD(lval, rval); | ||
case '+': return ADD(lval, rval); | ||
case 'string+': return STRING_ADD(lval, rval); | ||
case '-': return SUB(lval, rval); | ||
case '<<': return SHL(lval, rval); | ||
case '>>': return SHR(lval, rval); | ||
case '>>>': return SAR(lval, rval); | ||
case '|': return BIT_OR(lval, rval); | ||
case '&': return BIT_AND(lval, rval); | ||
case '^': return BIT_XOR(lval, rval); | ||
} | ||
@@ -826,0 +836,0 @@ } |
@@ -7,3 +7,3 @@ var thunk = (function(exports){ | ||
var operators = require('./operators'), | ||
var operators = require('./operators'), | ||
STRICT_EQUAL = operators.STRICT_EQUAL, | ||
@@ -32,7 +32,35 @@ ToObject = operators.ToObject, | ||
function Desc(v){ this.Value = v } | ||
Desc.prototype.Configurable = true; | ||
Desc.prototype.Enumerable = true; | ||
Desc.prototype.Writable = true; | ||
function Desc(v){ | ||
this.Value = v; | ||
} | ||
Desc.prototype = { | ||
Configurable: true, | ||
Enumerable: true, | ||
Writable: true | ||
}; | ||
var D = (function(d, i){ | ||
while (i--) { | ||
d[i] = new Function('return function '+ | ||
((i & 1) ? 'E' : '_') + | ||
((i & 2) ? 'C' : '_') + | ||
((i & 4) ? 'W' : '_') + | ||
'(v){ this.Value = v }')(); | ||
d[i].prototype = { | ||
Enumerable : (i & 1) > 0, | ||
Configurable: (i & 2) > 0, | ||
Writable : (i & 4) > 0 | ||
}; | ||
} | ||
return d; | ||
})([], 8); | ||
function DefineProperty(obj, key, val) { | ||
@@ -46,2 +74,3 @@ if (val && val.Completion) { | ||
} | ||
return obj.DefineOwnProperty(key, new Desc(val), false); | ||
@@ -67,8 +96,8 @@ } | ||
var opcodes = [ARRAY, ARG, ARGS, ARRAY_DONE, BINARY, BLOCK, CALL, CASE, | ||
CLASS_DECL, CLASS_EXPR, COMPLETE, CONST, CONSTRUCT, DEBUGGER, DEFAULT, | ||
DUP, ELEMENT, ENUM, FUNCTION, GET, IFEQ, IFNE, INDEX, ITERATE, JUMP, LET, | ||
CLASS_DECL, CLASS_EXPR, COMPLETE, CONST, CONSTRUCT, DEBUGGER, DEFAULT, DEFINE, | ||
DUP, ELEMENT, ENUM, EXTENSIBLE, FLIP, FUNCTION, GET, IFEQ, IFNE, INC, INDEX, ITERATE, JUMP, LET, | ||
LITERAL, LOG, MEMBER, METHOD, NATIVE_CALL, NATIVE_REF, OBJECT, POP, | ||
POPN, PROPERTY, PUT, REF, REGEXP, RETURN, ROTATE, RUN, SAVE, SPREAD, | ||
SPREAD_ARG, STRING, SUPER_CALL, SUPER_ELEMENT, SUPER_MEMBER, THIS, | ||
THROW, UNARY, UNDEFINED, UPDATE, UPSCOPE, VAR, WITH]; | ||
SPREAD_ARG, STRING, SUPER_CALL, SUPER_ELEMENT, SUPER_MEMBER, TEMPLATE, | ||
THIS, THROW, UNARY, UNDEFINED, UPDATE, UPSCOPE, VAR, WITH, YIELD]; | ||
@@ -80,3 +109,3 @@ var thunk = this, | ||
function ƒ(){ | ||
function unwind(){ | ||
for (var i = 0, entry; entry = code.transfers[i]; i++) { | ||
@@ -124,2 +153,3 @@ if (entry.begin < ip && ip <= entry.end) { | ||
} | ||
completion = error; | ||
@@ -129,2 +159,4 @@ return false; | ||
function ARGS(){ | ||
@@ -136,4 +168,4 @@ stack[sp++] = []; | ||
function ARG(){ | ||
a = stack[--sp]; | ||
stack[sp - 1].push(a); | ||
var arg = stack[--sp]; | ||
stack[sp - 1].push(arg); | ||
return cmds[++ip]; | ||
@@ -149,4 +181,4 @@ } | ||
function ARRAY_DONE(){ | ||
a = stack[--sp]; | ||
stack[sp - 1].Put('length', a); | ||
var len = stack[--sp]; | ||
stack[sp - 1].Put('length', len); | ||
return cmds[++ip]; | ||
@@ -156,14 +188,16 @@ } | ||
function BINARY(){ | ||
a = stack[--sp]; | ||
b = stack[--sp]; | ||
c = BinaryOp(BINARYOPS[ops[ip][0]], b, a); | ||
if (c && c.Completion) { | ||
if (c.Abrupt) { | ||
error = c; | ||
return ƒ; | ||
var right = stack[--sp], | ||
left = stack[--sp], | ||
result = BinaryOp(BINARYOPS[ops[ip][0]], GetValue(left), GetValue(right)); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
c = c.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = c; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -178,15 +212,17 @@ } | ||
function CALL(){ | ||
a = stack[--sp]; | ||
b = stack[--sp]; | ||
c = stack[--sp]; | ||
d = context.EvaluateCall(c, b, a); | ||
if (d && d.Completion) { | ||
if (d.Abrupt) { | ||
error = d; | ||
return ƒ; | ||
var args = stack[--sp], | ||
receiver = stack[--sp], | ||
func = stack[--sp], | ||
result = context.callFunction(func, receiver, args); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
d = d.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = d; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -196,12 +232,14 @@ } | ||
function CASE(){ | ||
a = STRICT_EQUAL(stack[--sp], stack[sp - 1]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = STRICT_EQUAL(stack[--sp], stack[sp - 1]); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
if (a) { | ||
if (result) { | ||
sp--; | ||
@@ -211,22 +249,26 @@ ip = ops[ip][0]; | ||
} | ||
return cmds[++ip]; | ||
} | ||
function CLASS_DECL(){ | ||
a = ops[ip][0]; | ||
b = a.superClass ? stack[--sp] : undefined; | ||
c = context.pushClass(a, b); | ||
if (c && c.Completion) { | ||
if (c.Abrupt) { | ||
error = c; | ||
return ƒ; | ||
var def = ops[ip][0], | ||
sup = def.superClass ? stack[--sp] : undefined, | ||
ctor = context.pushClass(def, sup); | ||
if (ctor && ctor.Completion) { | ||
if (ctor.Abrupt) { | ||
error = ctor; | ||
return unwind; | ||
} else { | ||
c = c.value; | ||
ctor = ctor.value; | ||
} | ||
} | ||
d = context.initializeBindings(a.pattern, c, true); | ||
if (d && d.Abrupt) { | ||
error = d; | ||
return ƒ; | ||
var result = context.initializeBindings(def.pattern, ctor, true); | ||
if (result && result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} | ||
return cmds[++ip]; | ||
@@ -236,14 +278,16 @@ } | ||
function CLASS_EXPR(){ | ||
a = ops[ip][0]; | ||
b = a.superClass ? stack[--sp] : undefined; | ||
c = context.pushClass(a, b); | ||
if (c && c.Completion) { | ||
if (c.Abrupt) { | ||
error = c; | ||
return ƒ; | ||
var def = ops[ip][0], | ||
sup = def.superClass ? stack[--sp] : undefined, | ||
ctor = context.pushClass(def, sup); | ||
if (ctor && ctor.Completion) { | ||
if (ctor.Abrupt) { | ||
error = ctor; | ||
return unwind; | ||
} else { | ||
c = c.value; | ||
ctor = ctor.value; | ||
} | ||
} | ||
stack[sp++] = c; | ||
stack[sp++] = ctor; | ||
return cmds[++ip]; | ||
@@ -262,14 +306,15 @@ } | ||
function CONSTRUCT(){ | ||
a = stack[--sp]; | ||
b = stack[--sp]; | ||
c = context.EvaluateConstruct(b, a); | ||
if (c && c.Completion) { | ||
if (c.Abrupt) { | ||
error = c; | ||
return ƒ; | ||
var args = stack[--sp], | ||
func = stack[--sp], | ||
result = context.constructFunction(func, args); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
c = c.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = c; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -291,5 +336,24 @@ } | ||
function DEFINE(){ | ||
var attrs = ops[ip][0], | ||
val = stack[--sp], | ||
key = stack[sp - 1], | ||
obj = stack[sp - 2], | ||
result = obj.DefineOwnProperty(key, new D[attrs](val)); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
} | ||
function DUP(){ | ||
a = stack[sp - 1]; | ||
stack[sp++] = a; | ||
stack[sp] = stack[sp++ - 1]; | ||
return cmds[++ip]; | ||
@@ -299,12 +363,16 @@ } | ||
function ELEMENT(){ | ||
a = context.Element(stack[--sp], stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var obj = stack[--sp], | ||
key = stack[--sp], | ||
result = context.getPropertyReference(obj, key); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -318,2 +386,7 @@ } | ||
function EXTENSIBLE(){ | ||
stack[sp - 1].SetExtensible(!!ops[ip][0]); | ||
return cmds[++ip]; | ||
} | ||
function FUNCTION(){ | ||
@@ -324,13 +397,33 @@ stack[sp++] = context.createFunction(ops[ip][0], ops[ip][1]); | ||
function FLIP(){ | ||
var buffer = [], | ||
index = 0, | ||
count = ops[ip][0]; | ||
while (index < count) { | ||
buffer[index] = stack[sp - index++]; | ||
} | ||
index = 0; | ||
while (index < count) { | ||
stack[sp - index] = buffer[count - ++index]; | ||
} | ||
return cmds[++ip]; | ||
} | ||
function GET(){ | ||
a = GetValue(stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = GetValue(stack[--sp]); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -357,2 +450,7 @@ } | ||
function INC(){ | ||
stack[sp - 1]++; | ||
return cmds[++ip]; | ||
} | ||
function INDEX(){ | ||
@@ -362,25 +460,31 @@ if (ops[ip][0]) { | ||
} else { | ||
a = GetValue(stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var val = GetValue(stack[--sp]); | ||
if (val && val.Completion) { | ||
if (val.Abrupt) { | ||
error = val; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
val = val.value; | ||
} | ||
} | ||
b = stack[--sp]; | ||
c = stack[sp - 1]; | ||
var index = stack[--sp], | ||
array = stack[sp - 1]; | ||
if (ops[ip][1]) { | ||
d = context.SpreadInitialization(c, b, a) | ||
if (d && d.Abrupt) { | ||
error = d; | ||
return ƒ; | ||
var status = context.spreadArray(array, index, val); | ||
if (status && status.Abrupt) { | ||
error = status; | ||
return unwind; | ||
} | ||
stack[sp++] = d; | ||
stack[sp++] = status; | ||
} else { | ||
c.DefineOwnProperty(b, new Desc(a)); | ||
stack[sp++] = b + 1; | ||
array.DefineOwnProperty(index, new Desc(val)); | ||
stack[sp++] = index + 1; | ||
} | ||
} | ||
return cmds[++ip]; | ||
@@ -419,12 +523,16 @@ } | ||
function MEMBER(){ | ||
a = context.Element(code.lookup(ops[ip][0]), stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var obj = stack[--sp], | ||
key = code.lookup(ops[ip][0]), | ||
result = context.getPropertyReference(key, obj); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -434,6 +542,11 @@ } | ||
function METHOD(){ | ||
a = context.defineMethod(ops[ip][0], stack[sp - 1], code.lookup(ops[ip][2]), ops[ip][1]); | ||
if (a && a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var kind = ops[ip][0], | ||
obj = stack[sp - 1], | ||
key = code.lookup(ops[ip][2]), | ||
code = ops[ip][1], | ||
status = context.defineMethod(kind, obj, key, code); | ||
if (status && status.Abrupt) { | ||
error = status; | ||
return unwind; | ||
} | ||
@@ -450,5 +563,5 @@ return cmds[++ip]; | ||
error = 'invalid native reference'; | ||
return ƒ; | ||
return unwind; | ||
} | ||
stack[sp++] = context.realm.natives.reference(code.lookup(ops[ip][0]), false); | ||
stack[sp++] = context.Realm.natives.reference(code.lookup(ops[ip][0]), false); | ||
return cmds[++ip]; | ||
@@ -458,7 +571,10 @@ } | ||
function PROPERTY(){ | ||
a = stack[--sp]; | ||
b = DefineProperty(stack[sp - 1], code.lookup(ops[ip][0]), a); | ||
if (b && b.Abrupt) { | ||
error = b; | ||
return ƒ; | ||
var val = stack[--sp], | ||
obj = stack[sp - 1], | ||
key = code.lookup(ops[ip][0]), | ||
status = DefineProperty(obj, key, val); | ||
if (status && status.Abrupt) { | ||
error = status; | ||
return unwind; | ||
} | ||
@@ -484,13 +600,15 @@ return cmds[++ip]; | ||
function PUT(){ | ||
a = stack[--sp]; | ||
b = PutValue(stack[--sp], a); | ||
if (b && b.Abrupt) { | ||
error = b; | ||
return ƒ; | ||
var val = stack[--sp], | ||
ref = stack[--sp], | ||
status = PutValue(ref, val); | ||
if (status && status.Abrupt) { | ||
error = status; | ||
return unwind; | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = val; | ||
return cmds[++ip]; | ||
} | ||
function REGEXP(){ | ||
@@ -502,3 +620,4 @@ stack[sp++] = context.createRegExp(ops[ip][0]); | ||
function REF(){ | ||
stack[sp++] = context.IdentifierResolution(code.lookup(ops[ip][0])); | ||
var ident = code.lookup(ops[ip][0]); | ||
stack[sp++] = context.getReference(ident); | ||
return cmds[++ip]; | ||
@@ -510,2 +629,8 @@ } | ||
ip++; | ||
if (code.generator) { | ||
context.currentGenerator.ExecutionContext = context; | ||
context.currentGenerator.State = 'closed'; | ||
error = new AbruptCompletion('throw', context.Realm.intrinsics.StopIteration); | ||
unwind(); | ||
} | ||
return false; | ||
@@ -515,11 +640,17 @@ } | ||
function ROTATE(){ | ||
a = []; | ||
b = stack[--sp]; | ||
for (c = 0; c < ops[ip][0]; c++) { | ||
a[c] = stack[--sp]; | ||
var buffer = [], | ||
item = stack[--sp], | ||
index = 0, | ||
count = ops[ip][0]; | ||
while (index < count) { | ||
buffer[index++] = stack[--sp]; | ||
} | ||
a[c++] = b; | ||
while (c--) { | ||
stack[sp++] = a[c]; | ||
buffer[index++] = item; | ||
while (index--) { | ||
stack[sp++] = buffer[index]; | ||
} | ||
return cmds[++ip]; | ||
@@ -538,12 +669,16 @@ } | ||
function SPREAD(){ | ||
a = context.SpreadDestructuring(stack[--sp], ops[ip][0]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var obj = stack[--sp], | ||
index = ops[ip][0], | ||
result = context.destructureSpread(obj, index); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -553,8 +688,11 @@ } | ||
function SPREAD_ARG(){ | ||
a = stack[--sp]; | ||
b = context.SpreadArguments(stack[sp - 1], a); | ||
if (b && b.Abrupt) { | ||
error = b; | ||
return ƒ; | ||
var spread = stack[--sp], | ||
args = stack[sp - 1], | ||
status = context.spreadArguments(args, spread); | ||
if (status && status.Abrupt) { | ||
error = status; | ||
return unwind; | ||
} | ||
return cmds[++ip]; | ||
@@ -569,12 +707,14 @@ } | ||
function SUPER_CALL(){ | ||
a = context.SuperReference(false); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = context.getSuperReference(false); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -584,12 +724,14 @@ } | ||
function SUPER_ELEMENT(){ | ||
a = context.SuperReference(stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = context.getSuperReference(stack[--sp]); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -599,26 +741,36 @@ } | ||
function SUPER_MEMBER(){ | ||
a = context.SuperReference(code.lookup(ops[ip][0])); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = context.getSuperReference(code.lookup(ops[ip][0])); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
} | ||
function TEMPLATE(){ | ||
stack[sp++] = context.getTemplateCallSite(ops[ip][0]); | ||
console.log(stack, sp); | ||
return cmds[++ip]; | ||
} | ||
function THIS(){ | ||
a = context.ThisResolution(); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = context.getThis(); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -629,16 +781,18 @@ } | ||
error = new AbruptCompletion('throw', stack[--sp]); | ||
return ƒ; | ||
return unwind; | ||
} | ||
function UNARY(){ | ||
a = UnaryOp(UNARYOPS[ops[ip][0]], stack[--sp]); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = UnaryOp(UNARYOPS[ops[ip][0]], stack[--sp]); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -652,18 +806,18 @@ } | ||
var updaters = [POST_DEC, PRE_DEC, POST_INC, PRE_INC]; | ||
function UPDATE(){ | ||
switch (ops[ip][0]) { | ||
case 0: a = POST_DEC(stack[--sp]); break; | ||
case 1: a = PRE_DEC(stack[--sp]); break; | ||
case 2: a = POST_INC(stack[--sp]); break; | ||
case 3: a = PRE_INC(stack[--sp]); break; | ||
} | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var update = updaters[ops[ip][0]], | ||
result = update(stack[--sp]); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
stack[sp++] = a; | ||
stack[sp++] = result; | ||
return cmds[++ip]; | ||
@@ -683,15 +837,27 @@ } | ||
function WITH(){ | ||
a = ToObject(GetValue(stack[--sp])); | ||
if (a && a.Completion) { | ||
if (a.Abrupt) { | ||
error = a; | ||
return ƒ; | ||
var result = ToObject(GetValue(stack[--sp])); | ||
if (result && result.Completion) { | ||
if (result.Abrupt) { | ||
error = result; | ||
return unwind; | ||
} else { | ||
a = a.value; | ||
result = result.value; | ||
} | ||
} | ||
context.pushWith(a); | ||
context.pushWith(result); | ||
return cmds[++ip]; | ||
} | ||
function YIELD(){ | ||
var generator = context.currentGenerator; | ||
generator.ExecutionContext = context; | ||
generator.State = 'suspended'; | ||
context.pop(); | ||
cleanup = yieldCleanup; | ||
yielded = stack[--sp]; | ||
ip++; | ||
return false; | ||
} | ||
@@ -703,13 +869,56 @@ function trace(unwound){ | ||
function normalPrepare(){ | ||
stack = []; | ||
function normalPrepare(newContext){ | ||
thunkStack.push({ | ||
ip: ip, | ||
sp: sp, | ||
stack: stack, | ||
error: error, | ||
prepare: prepare, | ||
execute: execute, | ||
cleanup: cleanup, | ||
history: history, | ||
completion: completion, | ||
stacktrace: stacktrace, | ||
context: context, | ||
log: log, | ||
ctx: ctx, | ||
yielded: yielded | ||
}); | ||
ip = 0; | ||
sp = 0; | ||
stacktrace = completion = error = a = b = c = d = undefined; | ||
stack = []; | ||
error = completion = stacktrace = yielded = undefined; | ||
log = log || cmds.log; | ||
context = newContext; | ||
history = []; | ||
execute = context.Realm.quiet ? normalExecute : instrumentedExecute; | ||
} | ||
function normalCleanup(){ | ||
var result = GetValue(completion); | ||
if (thunkStack.length) { | ||
var v = thunkStack.pop(); | ||
ip = v.ip; | ||
sp = v.sp; | ||
stack = v.stack; | ||
error = v.error; | ||
prepare = v.prepare; | ||
execute = v.execute; | ||
cleanup = v.cleanup; | ||
history = v.history; | ||
completion = v.completion; | ||
stacktrace = v.stacktrace; | ||
context = v.context; | ||
log = v.log; | ||
ctx = v.ctx; | ||
yielded = v.yielded; | ||
} | ||
return result; | ||
} | ||
function normalExecute(){ | ||
var f = cmds[ip]; | ||
var f = cmds[ip], | ||
ips = 0; | ||
if (log) { | ||
var ips = 0; | ||
history = []; | ||
@@ -725,21 +934,11 @@ while (f) { | ||
function normalCleanup(){ | ||
var result = completion; | ||
prepare(); | ||
return result; | ||
} | ||
function instrumentedExecute(){ | ||
var f = cmds[ip], | ||
realm = context.realm; | ||
ips = 0; | ||
ips = 0, | ||
realm = context.Realm; | ||
history = []; | ||
while (f) { | ||
if (f) { | ||
history[ips++] = [ip, ops[ip]]; | ||
realm.emit('op', [ops[ip], stack[sp - 1]]); | ||
f = f(); | ||
} | ||
history[ips++] = [ip, ops[ip]]; | ||
realm.emit('op', [ops[ip], stack[sp - 1]]); | ||
f = f(); | ||
} | ||
@@ -754,3 +953,2 @@ } | ||
ctx = undefined; | ||
context.realm.activate(); | ||
} | ||
@@ -768,20 +966,31 @@ | ||
function yieldPrepare(ctx){ | ||
prepare = normalPrepare; | ||
context = ctx; | ||
} | ||
function yieldCleanup(){ | ||
prepare = yieldPrepare; | ||
cleanup = normalCleanup; | ||
return yielded; | ||
} | ||
function run(ctx){ | ||
context = ctx; | ||
if (context.realm.quiet) { | ||
execute = normalExecute; | ||
} else { | ||
execute = instrumentedExecute; | ||
} | ||
var prevLog = log; | ||
log = log || cmds.log; | ||
prepare(); | ||
prepare(ctx); | ||
execute(); | ||
if (log && !prevLog) log = false; | ||
return cleanup(); | ||
} | ||
function send(ctx, value){ | ||
if (stack) { | ||
stack[sp++] = value; | ||
} | ||
return run(ctx); | ||
} | ||
var completion, stack, ip, sp, error, a, b, c, d, ctx, context, stacktrace, history; | ||
var completion, yielded, stack, ip, sp, error, ctx, context, stacktrace, history; | ||
var executing = false, thunkStack = []; | ||
var prepare = normalPrepare, | ||
@@ -792,2 +1001,3 @@ execute = normalExecute, | ||
this.run = run; | ||
this.send = send; | ||
this.code = code; | ||
@@ -794,0 +1004,0 @@ Emitter.call(this); |
@@ -9,16 +9,37 @@ var utility = (function(exports){ | ||
var KEYS = 'keys', | ||
VALUES = 'values', | ||
ITEMS = 'items', | ||
ATTRS = 'attributes'; | ||
var hasDunderProto = { __proto__: [] } instanceof Array, | ||
isES5 = !(!Object.getOwnPropertyNames || 'prototype' in Object.getOwnPropertyNames); | ||
var toBrand = {}.toString, | ||
slice = [].slice, | ||
_slice = [].slice, | ||
hasOwn = {}.hasOwnProperty, | ||
toSource = Function.toString; | ||
var hasDunderProto = { __proto__: [] } instanceof Array; | ||
var hidden = { | ||
configurable: true, | ||
enumerable: false, | ||
writable: true, | ||
value: undefined | ||
}; | ||
var proto = uid(); | ||
function getBrandOf(o){ | ||
return toBrand.call(o).slice(8, -1); | ||
if (o === null) { | ||
return 'Null'; | ||
} else if (o === undefined) { | ||
return 'Undefined'; | ||
} else { | ||
return toBrand.call(o).slice(8, -1); | ||
} | ||
} | ||
function ensureObject(name, o){ | ||
if (!o || typeof o !== 'object') { | ||
if (o === null || typeof o !== 'object') { | ||
throw new TypeError(name + ' called with non-object ' + getBrandOf(o)); | ||
@@ -28,28 +49,72 @@ } | ||
function uid(){ | ||
return Math.random().toString(36).slice(2); | ||
} | ||
function fname(func){ | ||
if (typeof func !== 'function') { | ||
return ''; | ||
} else if ('name' in func) { | ||
return func.name; | ||
} | ||
exports.uid = uid; | ||
return toSource.call(func).match(/^\n?function\s?(\w*)?_?\(/)[1]; | ||
function toArray(o){ | ||
var len = o.length; | ||
if (!len) return []; | ||
if (len === 1) return [o[0]]; | ||
if (len === 2) return [o[0], o[1]]; | ||
if (len === 3) return [o[0], o[1], o[2]]; | ||
if (len > 9) return _slice.call(o); | ||
if (len === 4) return [o[0], o[1], o[2], o[3]]; | ||
if (len === 5) return [o[0], o[1], o[2], o[3], o[4]]; | ||
if (len === 6) return [o[0], o[1], o[2], o[3], o[4], o[5]]; | ||
if (len === 7) return [o[0], o[1], o[2], o[3], o[4], o[5], o[6]]; | ||
if (len === 8) return [o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]]; | ||
if (len === 9) return [o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7], o[8]]; | ||
} | ||
exports.fname = fname; | ||
exports.toArray = toArray; | ||
function slice(o, start, end){ | ||
if (!o.length) { | ||
return []; | ||
} else if (!end && !start) { | ||
return toArray(o); | ||
} else { | ||
return _slice.call(o, start, end); | ||
} | ||
} | ||
exports.slice = slice; | ||
var fname = exports.fname = (function(){ | ||
if (Function.name === 'Function') { | ||
return function fname(f){ | ||
if (typeof f !== FUNCTION) { | ||
throw new TypeError('Tried to get the name of a non-function'); | ||
} | ||
return f.name; | ||
}; | ||
} | ||
return function fname(f){ | ||
if (typeof f !== FUNCTION) { | ||
throw new TypeError('Tried to get the name of a non-function'); | ||
} | ||
if (!hasOwn.call(f, 'name')) { | ||
hidden.value = toSource.call(f).match(/^\n?function\s?(\w*)?_?\(/)[1]; | ||
defineProperty(f, 'name', hidden); | ||
} | ||
return f.name; | ||
}; | ||
})(); | ||
function isObject(v){ | ||
return typeof v === OBJECT ? v !== null : typeof v === FUNCTION; | ||
var type = typeof v; | ||
return type === OBJECT ? v !== null : type === FUNCTION; | ||
} | ||
exports.isObject = isObject; | ||
exports.nextTick = typeof process !== UNDEFINED | ||
? process.nextTick | ||
: function(f){ setTimeout(f, 1) }; | ||
? process.nextTick | ||
: function nextTick(f){ setTimeout(f, 1) }; | ||
exports.numbers = (function(cache){ | ||
function numbers(start, end){ | ||
return function numbers(start, end){ | ||
if (!isFinite(end)) { | ||
@@ -67,13 +132,14 @@ end = start; | ||
return cache.slice(start, end); | ||
} | ||
return numbers; | ||
}; | ||
})([]); | ||
if (Object.create && !Object.create(null).toString) { | ||
if (isES5) { | ||
var create = exports.create = Object.create; | ||
} else { | ||
var Empty = function(){}; | ||
var create = exports.create = (function(F, empty){ | ||
var Null = function(){}; | ||
var hiddens = ['constructor', 'hasOwnProperty', 'propertyIsEnumerable', | ||
'isPrototypeOf', 'toLocaleString', 'toString', 'valueOf']; | ||
var create = exports.create = (function(F){ | ||
var iframe = document.createElement('iframe'); | ||
@@ -83,18 +149,12 @@ iframe.style.display = 'none'; | ||
iframe.src = 'javascript:'; | ||
empty = iframe.contentWindow.Object.prototype; | ||
Null.prototype = iframe.contentWindow.Object.prototype; | ||
document.body.removeChild(iframe); | ||
var keys = ['constructor', 'hasOwnProperty', 'propertyIsEnumerable', | ||
'isPrototypeOf', 'toLocaleString', 'toString', 'valueOf']; | ||
while (hiddens.length) { | ||
delete Null.prototype[hiddens.pop()]; | ||
} | ||
for (var i=0; i < keys.length; i++) | ||
delete empty[keys[i]]; | ||
Empty.prototype = empty; | ||
keys = null; | ||
function create(object){ | ||
return function create(object){ | ||
if (object === null) { | ||
return new Empty; | ||
return new Null; | ||
} else { | ||
@@ -106,94 +166,138 @@ F.prototype = object; | ||
} | ||
} | ||
return create; | ||
}; | ||
})(function(){}); | ||
} | ||
var ownKeys = exports.keys = (function(){ | ||
if (isES5) return Object.keys; | ||
return function keys(o){ | ||
var out = [], i=0; | ||
for (var k in o) { | ||
if (hasOwn.call(o, k)) { | ||
out[i++] = k; | ||
} | ||
} | ||
return out; | ||
}; | ||
})(); | ||
function enumerate(o){ | ||
var keys = [], i = 0; | ||
for (keys[i++] in o); | ||
return keys; | ||
} | ||
var getPrototypeOf = exports.getPrototypeOf = (function(){ | ||
if (isES5) { | ||
return Object.getPrototypeOf; | ||
} else if (hasDunderProto) { | ||
return function getPrototypeOf(o){ | ||
ensureObject('getPrototypeOf', o); | ||
return o.__proto__; | ||
}; | ||
} else { | ||
return function getPrototypeOf(o){ | ||
ensureObject('getPrototypeOf', o); | ||
exports.enumerate = enumerate; | ||
var ctor = o.constructor; | ||
if (typeof ctor === FUNCTION) { | ||
var proto = ctor.prototype; | ||
if (o !== proto) { | ||
return proto; | ||
} else if (!ctor._super) { | ||
delete o.constructor; | ||
ctor._super = o.constructor; | ||
o.constructor = ctor; | ||
} | ||
return ctor._super.prototype; | ||
} else if (o instanceof Null) { | ||
return null; | ||
} else if (o instanceof Object) { | ||
return Object.prototype; | ||
} | ||
}; | ||
} | ||
})(); | ||
if (Object.keys) { | ||
var ownKeys = exports.keys = Object.keys; | ||
} else { | ||
var ownKeys = exports.keys = (function(hasOwn){ | ||
function keys(o){ | ||
var out = [], i=0; | ||
for (var k in o) | ||
if (hasOwn.call(o, k)) | ||
out[i++] = k; | ||
return out; | ||
} | ||
return keys; | ||
})({}.hasOwnProperty); | ||
} | ||
var defineProperty = exports.defineProperty = (function(){ | ||
if (isES5) return Object.defineProperty; | ||
return function defineProperty(o, k, desc){ | ||
o[k] = desc.value; | ||
return o; | ||
}; | ||
})(); | ||
if (Object.getPrototypeOf) { | ||
var getPrototypeOf = Object.getPrototypeOf; | ||
} else if (hasDunderProto) { | ||
var getPrototypeOf = (function(){ | ||
function getPrototypeOf(o){ | ||
ensureObject('getPrototypeOf', o); | ||
return o.__proto__; | ||
var describeProperty = exports.describeProperty = (function(){ | ||
if (isES5) return Object.getOwnPropertyDescriptor; | ||
return function getOwnPropertyDescriptor(o, k){ | ||
ensureObject('getOwnPropertyDescriptor', o); | ||
if (hasOwn.call(o, k)) { | ||
return { value: o[k] }; | ||
} | ||
return getPrototypeOf; | ||
})(); | ||
} else { | ||
var getPrototypeOf = (function(){ | ||
function getPrototypeOf(o){ | ||
ensureObject('getPrototypeOf', o); | ||
if (typeof o.constructor === 'function') { | ||
return o.constructor.prototype; | ||
} | ||
} | ||
return getPrototypeOf; | ||
})(); | ||
} | ||
}; | ||
})(); | ||
exports.getPrototypeOf = getPrototypeOf | ||
var ownProperties = exports.ownProperties = isES5 ? Object.getOwnPropertyNames : ownKeys; | ||
var _call, _apply, _bind; | ||
if (Object.getOwnPropertyNames) { | ||
var defineProperty = Object.defineProperty; | ||
if (typeof Function.prototype.bind === FUNCTION && !('prototype' in Function.prototype.bind)) { | ||
_bind = Function.prototype.bind; | ||
_call = Function.prototype.call; | ||
_apply = Function.prototype.apply; | ||
} else { | ||
var defineProperty = (function(){ | ||
function defineProperty(o, k, desc){ | ||
o[k] = desc.value; | ||
return o; | ||
} | ||
return defineProperty; | ||
})(); | ||
} | ||
void function(){ | ||
function bind(receiver){ | ||
if (typeof this !== 'function') { | ||
throw new TypeError("Function.prototype.bind called on non-callable"); | ||
} | ||
exports.defineProperty = defineProperty; | ||
var args = toArray(arguments), | ||
params = '', | ||
F = this; | ||
for (var i=1; i < args.length; i++) { | ||
if (i > 1) params += ','; | ||
params += '$['+i+']'; | ||
} | ||
if (Object.getOwnPropertyNames) { | ||
var describeProperty = Object.getOwnPropertyDescriptor; | ||
} else { | ||
var describeProperty = (function(){ | ||
function getOwnPropertyDescriptor(o, k){ | ||
ensureObject('getOwnPropertyDescriptor', o); | ||
return { value: o[k] }; | ||
var bound = function(){ | ||
if (this instanceof bound) { | ||
var p = params; | ||
for (var i=0; i < arguments.length; i++) { | ||
p += ',_['+i+']'; | ||
} | ||
return new Function('F,$,_', 'return new F('+p+')')(F, args, arguments); | ||
} else { | ||
var a = toArray(args); | ||
for (var i=0; i < arguments.length; i++) { | ||
a[a.length] = arguments[i]; | ||
} | ||
return _call.apply(F, a); | ||
} | ||
}; | ||
return bound; | ||
} | ||
return getOwnPropertyDescriptor; | ||
})(); | ||
var iframe = document.createElement('iframe'); | ||
iframe.style.display = 'none'; | ||
document.body.appendChild(iframe); | ||
iframe.src = 'javascript:'; | ||
_call = iframe.contentWindow.Function.prototype.call; | ||
_apply = _call.apply; | ||
_bind = bind; | ||
document.body.removeChild(iframe); | ||
}(); | ||
} | ||
exports.describeProperty = describeProperty; | ||
var bindbind = exports.bindbind = _bind.bind(_bind), | ||
callbind = exports.callbind = bindbind(_call), | ||
applybind = exports.applybind = bindbind(_apply), | ||
bindapply = exports.bindapply = applybind(_bind), | ||
bind = exports.bind = callbind(_bind), | ||
call = exports.call = callbind(_call), | ||
apply = exports.apply = callbind(_apply); | ||
if (Object.getOwnPropertyNames) { | ||
var getProperties = Object.getOwnPropertyNames; | ||
} else { | ||
var getProperties = ownKeys; | ||
function applyNew(Ctor, args){ | ||
return new (bindapply(Ctor, [null].concat(args))); | ||
} | ||
exports.applyNew = applyNew; | ||
@@ -204,13 +308,37 @@ | ||
} | ||
exports.copy = copy; | ||
function clone(o, hidden){ | ||
function recurse(from, to, key){ | ||
try { | ||
var val = from[key]; | ||
if (!isObject(val)) { | ||
return to[key] = val; | ||
} | ||
if (from[key] === val) { | ||
if (hasOwn.call(from[key], tag)) { | ||
return to[key] = from[key][tag]; | ||
} | ||
to[key] = enqueue(from[key]); | ||
} | ||
} catch (e) {} | ||
} | ||
function enqueue(o){ | ||
var out = o instanceof Array ? [] : create(getPrototypeOf(o)); | ||
tagged.push(o); | ||
var keys = list(o); | ||
for (var i=0; i < keys.length; i++) { | ||
queue.push([o, out, keys[i]]); | ||
} | ||
o[tag] = out; | ||
return out; | ||
} | ||
var queue = new Queue, | ||
tag = uid(), | ||
tagged = [], | ||
list = hidden ? getProperties : ownKeys; | ||
list = hidden ? ownProperties : ownKeys, | ||
out = enqueue(o); | ||
var out = enqueue(o); | ||
while (queue.length) { | ||
@@ -225,71 +353,126 @@ recurse.apply(this, queue.shift()); | ||
return out; | ||
} | ||
exports.clone = clone; | ||
function recurse(from, to, key){ | ||
if (!isObject(from[key])) { | ||
return to[key] = from[key]; | ||
function enumerate(o){ | ||
var out = [], i = 0; | ||
for (out[i++] in o); | ||
return out; | ||
} | ||
exports.enumerate = enumerate; | ||
var StopIteration = exports.StopIteration = global.StopIteration || create(null); | ||
function iterate(o, callback, context){ | ||
if (o == null) return; | ||
var type = typeof o; | ||
context = context || o; | ||
if (type === 'number' || type === 'boolean') { | ||
callback.call(context, o, 0, o); | ||
} else { | ||
o = Object(o); | ||
var iterator = o.iterator || o.__iterator__; | ||
if (typeof iterator === 'function') { | ||
var iter = iterator.call(o); | ||
if (iter && typeof iter.next === 'function') { | ||
var i=0; | ||
try { | ||
while (1) callback.call(context, iter.next(), i++, o); | ||
} catch (e) { | ||
if (e === StopIteration) return; | ||
throw e; | ||
} | ||
} | ||
} | ||
if (hasOwn.call(from[key], tag)) { | ||
return to[key] = from[key][tag]; | ||
if (type !== 'function' && o.length) { | ||
for (var i=0; i < o.length; i++) { | ||
callback.call(context, o[i], i, o); | ||
} | ||
} else { | ||
var keys = ownKeys(o); | ||
for (var i=0; i < keys.length; i++) { | ||
callback.call(context, o[keys[i]], keys[i], o); | ||
} | ||
} | ||
to[key] = enqueue(from[key]); | ||
} | ||
} | ||
exports.iterate = iterate; | ||
function enqueue(o){ | ||
var out = o instanceof Array ? [] : create(getPrototypeOf(o)); | ||
tagged.push(o); | ||
var keys = list(o); | ||
for (var i=0; i < keys.length; i++) { | ||
queue.push([o, out, keys[i]]); | ||
} | ||
o[tag] = out; | ||
return out; | ||
function each(o, callback){ | ||
for (var i=0; i < o.length; i++) { | ||
callback(o[i], i, o); | ||
} | ||
} | ||
exports.each = each; | ||
exports.clone = clone; | ||
function map(o, callback){ | ||
var out = new Array(o.length); | ||
for (var i=0; i < o.length; i++) { | ||
out[i] = callback(o[i]); | ||
} | ||
return out; | ||
} | ||
exports.map = map; | ||
function fold(o, initial, callback){ | ||
if (callback) { | ||
var val = initial, i = 0; | ||
} else { | ||
if (typeof initial === STRING) { | ||
callback = fold[initial]; | ||
} else { | ||
callback = initial; | ||
} | ||
function iterate(o, callback, context){ | ||
if (!o) return; | ||
var type = typeof o; | ||
context = context || this; | ||
if (type === 'number' || type === 'boolean') { | ||
return void callback.call(context, o, 0, o); | ||
var val = o[0], i = 1; | ||
} | ||
o = Object(o); | ||
if (type !== 'function' && o.length) { | ||
for (var i=0; i < o.length; i++) { | ||
callback.call(context, o[i], i, o); | ||
for (; i < o.length; i++) { | ||
val = callback(val, o[i], i, o); | ||
} | ||
return val; | ||
} | ||
exports.fold = fold; | ||
fold['+'] = function(a, b){ return a + b }; | ||
fold['*'] = function(a, b){ return a - b }; | ||
fold['-'] = function(a, b){ return a * b }; | ||
fold['/'] = function(a, b){ return a / b }; | ||
function repeat(n, args, callback){ | ||
if (typeof args === FUNCTION) { | ||
callback = args; | ||
for (var i=0; i < n; i++) { | ||
callback(); | ||
} | ||
} else { | ||
var keys = ownKeys(o); | ||
for (var i=0; i < keys.length; i++) { | ||
callback.call(context, o[keys[i]], keys[i], o); | ||
for (var i=0; i < n; i++) { | ||
callback.apply(this, args); | ||
} | ||
} | ||
} | ||
exports.repeat = repeat; | ||
exports.iterate = iterate; | ||
function Hidden(value){ | ||
this.value = value; | ||
function generate(n, callback){ | ||
var out = new Array(n); | ||
for (var i=0; i < n; i++) { | ||
out[i] = callback(i, n, out); | ||
} | ||
return out; | ||
} | ||
exports.generate = generate; | ||
Hidden.prototype = { | ||
configurable: true, | ||
enumerable: false, | ||
writable: true, | ||
value: undefined | ||
}; | ||
function define(o, p, v){ | ||
switch (typeof p) { | ||
case FUNCTION: | ||
v = p; | ||
p = fname(v); | ||
case STRING: | ||
defineProperty(o, p, new Hidden(v)); | ||
hidden.value = v; | ||
defineProperty(o, p, hidden); | ||
break; | ||
case FUNCTION: | ||
defineProperty(o, fname(p), new Hidden(p)); | ||
break; | ||
case OBJECT: | ||
@@ -306,3 +489,4 @@ if (p instanceof Array) { | ||
if (name) { | ||
defineProperty(o, name, new Hidden(f)); | ||
hidden.value = f; | ||
defineProperty(o, name, hidden); | ||
} | ||
@@ -314,7 +498,6 @@ } | ||
for (var i=0; i < keys.length; i++) { | ||
var k = keys[i]; | ||
var desc = describeProperty(p, k); | ||
var desc = describeProperty(p, keys[i]); | ||
if (desc) { | ||
desc.enumerable = 'get' in desc; | ||
defineProperty(o, k, desc); | ||
defineProperty(o, keys[i], desc); | ||
} | ||
@@ -325,18 +508,16 @@ } | ||
hidden.value = undefined; | ||
return o; | ||
} | ||
exports.define = define; | ||
function assign(o, p, v){ | ||
switch (typeof p) { | ||
case FUNCTION: | ||
o[fname(p)] = p; | ||
break; | ||
case STRING: | ||
o[p] = v; | ||
break; | ||
case FUNCTION: | ||
o[fname(p)] = p; | ||
break; | ||
case OBJECT: | ||
@@ -367,3 +548,2 @@ if (p instanceof Array) { | ||
} | ||
exports.assign = assign; | ||
@@ -384,3 +564,2 @@ | ||
} | ||
exports.inherit = inherit; | ||
@@ -403,8 +582,5 @@ | ||
} | ||
exports.partial = partial; | ||
function quotes(s) { | ||
@@ -430,3 +606,2 @@ s = (''+s).replace(/\\/g, '\\\\').replace(/\n/g, '\\n'); | ||
} | ||
exports.quotes = quotes; | ||
@@ -448,11 +623,16 @@ | ||
} | ||
exports.unique = unique; | ||
var MAX_INTEGER = 9007199254740992; | ||
function toInteger(v){ | ||
return (v / 1 || 0) | 0; | ||
if (v === Infinity) { | ||
return MAX_INTEGER; | ||
} else if (v === -Infinity) { | ||
return -MAX_INTEGER; | ||
} else { | ||
return v - 0 >> 0; | ||
} | ||
} | ||
exports.toInteger = toInteger; | ||
@@ -464,3 +644,2 @@ | ||
} | ||
exports.isNaN = isNaN; | ||
@@ -471,7 +650,6 @@ | ||
return typeof value === 'number' | ||
&& value === value | ||
&& value < Infinity | ||
&& value > -Infinity; | ||
&& value === value | ||
&& value < Infinity | ||
&& value > -Infinity; | ||
} | ||
exports.isFinite = isFinite; | ||
@@ -481,25 +659,12 @@ | ||
function isInteger(value) { | ||
return typeof value === 'number' | ||
&& value === value | ||
&& value > -9007199254740992 | ||
&& value < 9007199254740992 | ||
&& value | 0 === value; | ||
return typeof value === NUMBER | ||
&& value === value | ||
&& value > -MAX_INTEGER | ||
&& value < MAX_INTEGER | ||
&& value >> 0 === value; | ||
} | ||
exports.isInteger = isInteger; | ||
function uid(){ | ||
return Math.random().toString(36).slice(2) | ||
} | ||
exports.uid = uid; | ||
var BREAK = visit.BREAK = new Number(1), | ||
CONTINUE = visit.CONTINUE = new Number(2), | ||
RECURSE = visit.RECURSE = new Number(3); | ||
function visit(root, callback){ | ||
var queue = new Queue([root]), | ||
function walk(root, callback){ | ||
var queue = new Queue([[root]]), | ||
branded = [], | ||
@@ -527,5 +692,5 @@ tag = uid(); | ||
var result = callback(item, node); | ||
if (result === visit.RECURSE) { | ||
if (result === walk.RECURSE) { | ||
queue.push(item); | ||
} else if (result === visit.BREAK) { | ||
} else if (result === walk.BREAK) { | ||
return queue.empty(); | ||
@@ -537,10 +702,11 @@ } | ||
} | ||
exports.walk = walk; | ||
exports.visit = visit; | ||
var BREAK = walk.BREAK = new Number(1), | ||
CONTINUE = walk.CONTINUE = new Number(2), | ||
RECURSE = walk.RECURSE = new Number(3); | ||
exports.collector = (function(){ | ||
function path(){ | ||
var parts = [].slice.call(arguments); | ||
var parts = toArray(arguments); | ||
@@ -580,3 +746,3 @@ for (var i=0; i < parts.length; i++) { | ||
handlers[k] = path(o[k]); | ||
} else if (typeof o[k] === 'function') { | ||
} else if (typeof o[k] === FUNCTION) { | ||
handlers[k] = o[k]; | ||
@@ -591,5 +757,9 @@ } else { | ||
function visitor(node, parent){ | ||
function walker(node, parent){ | ||
if (!node) return CONTINUE; | ||
if (node instanceof Array) { | ||
return RECURSE; | ||
} | ||
var handler = handlers[node.type]; | ||
@@ -601,3 +771,7 @@ | ||
return handler; | ||
} else if (typeof handler === 'function') { | ||
} else if (typeof handler === STRING) { | ||
if (node[handler]) { | ||
walk(node[handler], walker); | ||
} | ||
} else if (typeof handler === FUNCTION) { | ||
var item = handler(node); | ||
@@ -607,5 +781,3 @@ if (item !== undefined) { | ||
} | ||
} else if (node instanceof Array) { | ||
return RECURSE; | ||
} | ||
} else | ||
@@ -615,3 +787,3 @@ return CONTINUE; | ||
visit(node, visitor); | ||
walk(node, walker); | ||
@@ -625,16 +797,5 @@ return items; | ||
if (Function.prototype.bind) { | ||
var applybind = Function.prototype.apply.bind(Function.prototype.bind); | ||
exports.applyNew = function(Ctor, args){ | ||
return new (applybind(Ctor, [null].concat(args))); | ||
}; | ||
} else { | ||
exports.applyNew = function(Ctor, args){ | ||
var params = ''; | ||
for (var i=0; i < args.length; i++) { | ||
params += ',$'+i; | ||
} | ||
return new Function('F'+params, 'return new F('+params.slice(1)+')').apply(null, args); | ||
}; | ||
} | ||
function Hash(){} | ||
Hash.prototype = create(null); | ||
exports.Hash = Hash; | ||
@@ -646,61 +807,82 @@ exports.Emitter = (function(){ | ||
function on(events, handler){ | ||
iterate(events.split(/\s+/), function(event){ | ||
if (!(event in this)) { | ||
this[event] = []; | ||
define(Emitter.prototype, [ | ||
function on(events, handler){ | ||
iterate(events.split(/\s+/), function(event){ | ||
if (!(event in this)) { | ||
this[event] = []; | ||
} | ||
this[event].push(handler); | ||
}, this._events); | ||
}, | ||
function off(events, handler){ | ||
iterate(events.split(/\s+/), function(event){ | ||
if (event in this) { | ||
var index = '__index' in handler ? handler.__index : this[event].indexOf(handler); | ||
if (~index) { | ||
this[event].splice(index, 1); | ||
} | ||
} | ||
}, this._events); | ||
}, | ||
function once(events, handler){ | ||
function one(val){ | ||
this.off(events, one); | ||
handler.call(this, val); | ||
} | ||
this[event].push(handler); | ||
}, this._events); | ||
} | ||
this.on(events, one); | ||
}, | ||
function emit(event, val){ | ||
var handlers = this._events['*']; | ||
function off(events, handler){ | ||
iterate(events.split(/\s+/), function(event){ | ||
if (event in this) { | ||
var index = '__index' in handler ? handler.__index : this[event].indexOf(handler); | ||
if (~index) { | ||
this[event].splice(index, 1); | ||
if (handlers) {; | ||
for (var i=0; i < handlers.length; i++) { | ||
handlers[i].call(this, event, val); | ||
} | ||
} | ||
}, this._events); | ||
} | ||
function once(events, handler){ | ||
function one(val){ | ||
this.off(events, one); | ||
handler.call(this, val); | ||
} | ||
this.on(events, one); | ||
} | ||
function emit(event, val){ | ||
var handlers = this._events['*']; | ||
if (handlers) {; | ||
for (var i=0; i < handlers.length; i++) { | ||
handlers[i].call(this, event, val); | ||
handlers = this._events[event]; | ||
if (handlers) { | ||
for (var i=0; i < handlers.length; i++) { | ||
handlers[i].call(this, val); | ||
} | ||
} | ||
} | ||
]); | ||
handlers = this._events[event]; | ||
if (handlers) { | ||
for (var i=0; i < handlers.length; i++) { | ||
handlers[i].call(this, val); | ||
} | ||
} | ||
} | ||
define(Emitter.prototype, [on, off, once, emit]); | ||
return Emitter; | ||
})(); | ||
var PropertyList = exports.PropertyList = (function(){ | ||
var PropertyListIterator = (function(){ | ||
var types = { | ||
keys: 0, | ||
values: 1, | ||
attributes: 2 | ||
}; | ||
function PropertyListIterator(list, type){ | ||
this.list = list; | ||
this.type = type ? types[type] : ITEMS; | ||
this.index = 0; | ||
} | ||
function Hash(){} | ||
Hash.prototype = create(null); | ||
exports.Hash = Hash; | ||
define(PropertyListIterator.prototype, [ | ||
function next(){ | ||
var props = this.list.props, property; | ||
while (!property) { | ||
if (this.index >= props.length) { | ||
throw StopIteration; | ||
} | ||
property = props[this.index++]; | ||
} | ||
return this.type === ITEMS ? property : property[this.type]; | ||
}, | ||
function __iterator__(){ | ||
return this; | ||
} | ||
]); | ||
return PropertyListIterator; | ||
})(); | ||
var proto = Math.random().toString(36).slice(2); | ||
var PropertyList = exports.PropertyList = (function(){ | ||
function PropertyList(){ | ||
@@ -713,219 +895,236 @@ this.hash = new Hash; | ||
function get(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index][1]; | ||
} | ||
} | ||
define(PropertyList.prototype, [ | ||
function get(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index][1]; | ||
} | ||
}, | ||
function getAttribute(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index][2]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
function getProperty(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index]; | ||
} else { | ||
return null; | ||
} | ||
}, | ||
function set(key, value, attr){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name], | ||
prop; | ||
function getAttribute(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index][2]; | ||
} else { | ||
return null; | ||
} | ||
} | ||
if (index === undefined) { | ||
index = this.hash[name] = this.props.length; | ||
prop = this.props[index] = [key, value, 0]; | ||
this.length++; | ||
} else { | ||
prop = this.props[index]; | ||
prop[1] = value; | ||
} | ||
function getProperty(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
return this.props[index]; | ||
} else { | ||
return null; | ||
} | ||
} | ||
function set(key, value, attr){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name], | ||
prop; | ||
if (index === undefined) { | ||
index = this.hash[name] = this.props.length; | ||
prop = this.props[index] = [key, value, 0]; | ||
this.length++; | ||
} else { | ||
prop = this.props[index]; | ||
prop[1] = value; | ||
} | ||
if (attr !== undefined) { | ||
prop[2] = attr; | ||
} | ||
return true; | ||
} | ||
function setAttribute(key, attr){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
this.props[index][2] = attr; | ||
if (attr !== undefined) { | ||
prop[2] = attr; | ||
} | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
}, | ||
function setAttribute(key, attr){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
this.props[index][2] = attr; | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}, | ||
function setProperty(prop){ | ||
var key = prop[0], | ||
name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index === undefined) { | ||
index = this.hash[name] = this.props.length; | ||
this.length++; | ||
} | ||
this.props[index] = prop; | ||
}, | ||
function remove(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
this.hash[name] = undefined; | ||
this.props[index] = undefined; | ||
this.holes++; | ||
this.length--; | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}, | ||
function has(key){ | ||
var name = key === '__proto__' ? proto : key; | ||
return this.hash[name] !== undefined; | ||
}, | ||
function hasAttribute(key, mask){ | ||
var name = key === '__proto__' ? proto : key, | ||
attr = this.getAttribute(name); | ||
if (attr !== null) { | ||
return (attr & mask) > 0; | ||
} | ||
}, | ||
function compact(){ | ||
var props = this.props, | ||
len = props.length, | ||
index = 0, | ||
prop; | ||
function setProperty(prop){ | ||
var key = prop[0], | ||
name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index === undefined) { | ||
index = this.hash[name] = this.props.length; | ||
this.length++; | ||
} | ||
this.props[index] = prop; | ||
} | ||
this.hash = new Hash; | ||
this.props = []; | ||
this.holes = 0; | ||
function remove(key){ | ||
var name = key === '__proto__' ? proto : key, | ||
index = this.hash[name]; | ||
if (index !== undefined) { | ||
this.hash[name] = undefined; | ||
this.props[index] = undefined; | ||
this.holes++; | ||
this.length--; | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
function has(key){ | ||
var name = key === '__proto__' ? proto : key; | ||
return this.hash[name] !== undefined; | ||
} | ||
function hasAttribute(key, mask){ | ||
var name = key === '__proto__' ? proto : key, | ||
attr = this.getAttribute(name); | ||
if (attr !== null) { | ||
return (attr & mask) > 0; | ||
} | ||
} | ||
function compact(){ | ||
var props = this.props, | ||
len = props.length, | ||
index = 0, | ||
prop; | ||
this.hash = new Hash; | ||
this.props = []; | ||
this.holes = 0; | ||
for (var i=0; i < len; i++) { | ||
if (prop = props[i]) { | ||
var name = prop[0] === '__proto__' ? proto : prop[0]; | ||
this.props[index] = prop; | ||
this.hash[name] = index++; | ||
for (var i=0; i < len; i++) { | ||
if (prop = props[i]) { | ||
var name = prop[0] === '__proto__' ? proto : prop[0]; | ||
this.props[index] = prop; | ||
this.hash[name] = index++; | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
function forEach(callback, context){ | ||
var len = this.props.length, | ||
index = 0, | ||
prop; | ||
function forEach(callback, context){ | ||
var len = this.props.length, | ||
index = 0, | ||
prop; | ||
context = context || this; | ||
context = context || this; | ||
for (var i=0; i < len; i++) { | ||
if (prop = this.props[i]) { | ||
callback.call(context, prop, index++, this); | ||
for (var i=0; i < len; i++) { | ||
if (prop = this.props[i]) { | ||
callback.call(context, prop, index++, this); | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
function map(callback, context){ | ||
var out = [], | ||
len = this.props.length, | ||
index = 0, | ||
prop; | ||
function map(callback, context){ | ||
var out = [], | ||
len = this.props.length, | ||
index = 0, | ||
prop; | ||
context = context || this; | ||
context = context || this; | ||
for (var i=0; i < len; i++) { | ||
if (prop = this.props[i]) { | ||
out[index] = callback.call(context, prop, index++, this); | ||
for (var i=0; i < len; i++) { | ||
if (prop = this.props[i]) { | ||
out[index] = callback.call(context, prop, index++, this); | ||
} | ||
} | ||
} | ||
return out; | ||
} | ||
return out; | ||
}, | ||
function translate(callback, context){ | ||
var out = new PropertyList; | ||
function translate(callback, context){ | ||
var out = new PropertyList; | ||
out.length = this.length; | ||
context = context || this; | ||
out.length = this.length; | ||
context = context || this; | ||
this.forEach(function(prop, index){ | ||
prop = callback.call(context, prop, index, this); | ||
var name = prop[0] === '__proto__' ? proto : prop[0]; | ||
out.props[index] = prop; | ||
out.hash[name] = index; | ||
}); | ||
return out; | ||
} | ||
function filter(callback, context){ | ||
var out = new PropertyList, | ||
index = 0; | ||
context = context || this; | ||
this.forEach(function(prop, i){ | ||
if (callback.call(context, prop, i, this)) { | ||
this.forEach(function(prop, index){ | ||
prop = callback.call(context, prop, index, this); | ||
var name = prop[0] === '__proto__' ? proto : prop[0]; | ||
out.props[index] = prop; | ||
out.hash[name] = index++; | ||
} | ||
}); | ||
out.hash[name] = index; | ||
}); | ||
return out; | ||
} | ||
return out; | ||
}, | ||
function filter(callback, context){ | ||
var out = new PropertyList, | ||
index = 0; | ||
function clone(deep){ | ||
return this.translate(function(prop, i){ | ||
return deep ? prop.slice() : prop; | ||
}); | ||
} | ||
context = context || this; | ||
function keys(){ | ||
return this.map(function(prop){ | ||
return prop[0]; | ||
}); | ||
} | ||
this.forEach(function(prop, i){ | ||
if (callback.call(context, prop, i, this)) { | ||
var name = prop[0] === '__proto__' ? proto : prop[0]; | ||
out.props[index] = prop; | ||
out.hash[name] = index++; | ||
} | ||
}); | ||
function values(){ | ||
return this.map(function(prop){ | ||
return prop[1]; | ||
}); | ||
} | ||
return out; | ||
}, | ||
function clone(deep){ | ||
return this.translate(function(prop, i){ | ||
return deep ? prop.slice() : prop; | ||
}); | ||
}, | ||
function keys(){ | ||
return this.map(function(prop){ | ||
return prop[0]; | ||
}); | ||
}, | ||
function values(){ | ||
return this.map(function(prop){ | ||
return prop[1]; | ||
}); | ||
}, | ||
function items(){ | ||
return this.map(function(prop){ | ||
return prop.slice(); | ||
}); | ||
}, | ||
function merge(list){ | ||
list.forEach(this.setProperty, this); | ||
}, | ||
function __iterator__(type){ | ||
return new PropertyListIterator(this, type); | ||
}, | ||
function inspect(){ | ||
var out = create(null); | ||
function Token(value){ | ||
this.value = value; | ||
} | ||
Token.prototype.inspect = function(){ | ||
return this.value; | ||
}; | ||
this.forEach(function(property){ | ||
var attrs = (property[2] & 0x01 ? 'E' : '_') + | ||
(property[2] & 0x02 ? 'C' : '_') + | ||
(property[2] & 0x04 ? 'W' : | ||
property[2] & 0x08 ? 'A' : '_'); | ||
out[property[0]] = new Token(attrs + ' ' + (isObject(property[1]) ? property[1].NativeBrand : property[1])); | ||
}); | ||
return require('util').inspect(out); | ||
} | ||
]); | ||
function items(){ | ||
return this.map(function(prop){ | ||
return prop.slice(); | ||
}); | ||
} | ||
function merge(list){ | ||
list.forEach(this.setProperty, this); | ||
} | ||
define(PropertyList.prototype, [ | ||
get, getAttribute, getProperty, set, setAttribute, setProperty, remove, has, hasAttribute, | ||
compact, forEach, map, translate, filter, clone, keys, values, items, merge | ||
]); | ||
return PropertyList; | ||
})(); | ||
/* | ||
this.forEach(function(property){ | ||
if (property[2] & 0x08) { | ||
Object.defineProperty(out, property[0], { | ||
enumerable: (property[2] & 0x01) > 0, | ||
configurable: (property[2] & 0x02) > 0, | ||
get: property[1].Get ? function(){} : undefined, | ||
set: property[1].Set ? function(){} : undefined | ||
}); | ||
} else { | ||
Object.defineProperty(out, property[0], { | ||
enumerable: (property[2] & 0x01) > 0, | ||
configurable: (property[2] & 0x02) > 0, | ||
writable: (property[2] & 0x04) > 0, | ||
value: isObject(property[1]) ? property[1].properties : property[1] | ||
}); | ||
} | ||
}); | ||
*/ | ||
exports.Stack = (function(){ | ||
@@ -938,45 +1137,42 @@ function Stack(){ | ||
function push(item){ | ||
this.items.push(item); | ||
this.length++; | ||
this.top = item; | ||
return this; | ||
} | ||
define(Stack.prototype, [ | ||
function push(item){ | ||
this.items.push(item); | ||
this.length++; | ||
this.top = item; | ||
return this; | ||
}, | ||
function pop(){ | ||
this.length--; | ||
this.top = this.items[this.length - 1]; | ||
return this.items.pop(); | ||
}, | ||
function empty(){ | ||
this.length = 0; | ||
this.items = []; | ||
this.top = undefined; | ||
}, | ||
function first(callback, context){ | ||
var i = this.length; | ||
context || (context = this); | ||
while (i--) | ||
if (callback.call(context, this[i], i, this)) | ||
return this[i]; | ||
}, | ||
function filter(callback, context){ | ||
var i = this.length, | ||
out = new Stack; | ||
function pop(){ | ||
this.length--; | ||
this.top = this.items[this.length - 1]; | ||
return this.items.pop(); | ||
} | ||
context || (context = this); | ||
function empty(){ | ||
this.length = 0; | ||
this.items = []; | ||
this.top = undefined; | ||
} | ||
for (var i=0; i < this.length; i++) { | ||
if (callback.call(context, this[i], i, this)) { | ||
out.push(this[i]); | ||
} | ||
} | ||
function first(callback, context){ | ||
var i = this.length; | ||
context || (context = this); | ||
while (i--) | ||
if (callback.call(context, this[i], i, this)) | ||
return this[i]; | ||
} | ||
function filter(callback, context){ | ||
var i = this.length, | ||
out = new Stack; | ||
context || (context = this); | ||
for (var i=0; i < this.length; i++) { | ||
if (callback.call(context, this[i], i, this)) { | ||
out.push(this[i]); | ||
} | ||
return out; | ||
} | ||
]); | ||
return out; | ||
} | ||
define(Stack.prototype, [push, pop, empty, first, filter]); | ||
return Stack; | ||
@@ -1006,37 +1202,34 @@ })(); | ||
function push(item){ | ||
this.items.push(item); | ||
this.length++; | ||
return this; | ||
} | ||
function shift(){ | ||
if (this.length) { | ||
var item = this.items[this.index]; | ||
this.items[this.index++] = null; | ||
this.length--; | ||
if (this.index === 500) { | ||
this.items = this.items.slice(this.index); | ||
this.index = 0; | ||
define(Queue.prototype, [ | ||
function push(item){ | ||
this.items.push(item); | ||
this.length++; | ||
return this; | ||
}, | ||
function shift(){ | ||
if (this.length) { | ||
var item = this.items[this.index]; | ||
this.items[this.index++] = null; | ||
this.length--; | ||
if (this.index === 500) { | ||
this.items = this.items.slice(this.index); | ||
this.index = 0; | ||
} | ||
return item; | ||
} | ||
return item; | ||
}, | ||
function empty(){ | ||
this.length = 0; | ||
this.index = 0; | ||
this.items = []; | ||
return this; | ||
}, | ||
function front(){ | ||
return this.items[this.index]; | ||
} | ||
} | ||
]); | ||
function empty(){ | ||
this.length = 0; | ||
this.index = 0; | ||
this.items = []; | ||
return this; | ||
} | ||
function front(){ | ||
return this.items[this.index]; | ||
} | ||
define(Queue.prototype, [push, empty, front, shift]); | ||
return Queue; | ||
})(); | ||
exports.Feeder = (function(){ | ||
@@ -1047,6 +1240,4 @@ function Feeder(callback, context, pace){ | ||
this.active = false; | ||
this.feeder = feeder; | ||
this.pace = pace || 5; | ||
function feeder(){ | ||
this.feeder = function feeder(){ | ||
var count = Math.min(self.pace, self.queue.length); | ||
@@ -1063,56 +1254,30 @@ | ||
} | ||
} | ||
}; | ||
} | ||
function push(item){ | ||
this.queue.push(item); | ||
if (!this.active) { | ||
this.active = true; | ||
setTimeout(this.feeder, 15); | ||
define(Feeder.prototype, [ | ||
function push(item){ | ||
this.queue.push(item); | ||
if (!this.active) { | ||
this.active = true; | ||
setTimeout(this.feeder, 15); | ||
} | ||
return this; | ||
}, | ||
function pause(){ | ||
this.active = false; | ||
} | ||
return this; | ||
} | ||
]); | ||
function pause(){ | ||
this.active = false; | ||
} | ||
define(Feeder.prototype, [push, pause]); | ||
return Feeder; | ||
})(); | ||
function inspect(o){ | ||
o = require('util').inspect(o, null, 10); | ||
o = require('util').inspect(o, null, 4); | ||
console.log(o); | ||
return o; | ||
} | ||
exports.inspect = inspect; | ||
function decompile(ast, options){ | ||
return escodegen.generate(ast, options || decompile.options); | ||
} | ||
exports.decompile = decompile; | ||
decompile.options = { | ||
comment: false, | ||
allowUnparenthesizedNew: true, | ||
format: { | ||
indent: { | ||
style: ' ', | ||
base: 0, | ||
}, | ||
json : false, | ||
renumber : false, | ||
hexadecimal: true, | ||
quotes : 'single', | ||
escapeless : true, | ||
compact : false, | ||
parentheses: true, | ||
semicolons : true | ||
} | ||
}; | ||
return exports; | ||
})(typeof module !== 'undefined' ? module.exports : {}); |
@@ -153,24 +153,30 @@ var file = require('fs'), | ||
function reset(){ | ||
context = continuum(); | ||
context.evaluate(extras, true); | ||
context.on('reset', function(){ | ||
callback(color('fuchsia', 'resetting')); | ||
reset(); | ||
disableUntilTick(); | ||
continuum(function(realm){ | ||
context = realm; | ||
context.evaluate(extras, true); | ||
context.on('reset', function(){ | ||
callback(color('fuchsia', 'resetting')); | ||
reset(); | ||
disableUntilTick(); | ||
}); | ||
context.on('pause', function(){ | ||
callback(color('fuchsia', 'paused')); | ||
disableUntilTick(); | ||
}); | ||
context.on('resume', function(){ | ||
callback(color('fuchsia', 'resumed')); | ||
disableUntilTick(); | ||
}); | ||
context.on('write', function(args){ | ||
var text = args[0]; | ||
if (args[1] in colors) { | ||
text = color(args[1], args[0]); | ||
} | ||
callback('console: '+text); | ||
}); | ||
}); | ||
context.on('pause', function(){ | ||
callback(color('fuchsia', 'paused')); | ||
disableUntilTick(); | ||
}); | ||
context.on('resume', function(){ | ||
callback(color('fuchsia', 'resumed')); | ||
disableUntilTick(); | ||
}); | ||
context.on('write', function(args){ | ||
var text = args[0]; | ||
if (args[1] in colors) { | ||
text = color(args[1], args[0]); | ||
} | ||
callback('console: '+text); | ||
}); | ||
} | ||
@@ -218,4 +224,5 @@ | ||
real: 'continuum', | ||
password: 'jscont', | ||
channels: ['#continuum', '##javascript', '#node.js', '#appjs'] | ||
}]); | ||
} |
{ | ||
"name": "continuum", | ||
"author": "Brandon Benvie <http://bbenvie.com>", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"description": "A JavaScript (ES6) bytecode virtual machine written in JavaScript", | ||
"main": "continuum.js", | ||
"main": "index.js", | ||
"dependencies": { }, | ||
@@ -8,0 +8,0 @@ "repository": { |
106
README.md
@@ -7,10 +7,2 @@ # Continuum - A JavaScript Virtual Machine Built in JavaScript | ||
# Usage | ||
Documentation coming soon. | ||
For now use the debugger interface at http://benvie.github.com/continuum. | ||
![screenshot](https://raw.github.com/Benvie/continuum/gh-pages/docs/screenshot.png) | ||
# Compatibility | ||
@@ -30,2 +22,35 @@ Continuum probably works in every modern engine, but has not been tested. | ||
![screenshot](https://raw.github.com/Benvie/continuum/gh-pages/docs/screenshot.png) | ||
# Installation | ||
In the browser, use the combined continuum.js or continuum.min.js. In node | ||
npm install continuum | ||
# Quickstart Usage Overview | ||
In the browser, a function named `continuum` is added to the window. In Node.js, the `continuum` function is returned by `require('continuum')`. | ||
Usage of continuum is quite simple and can basically be treated like using `eval` or node's `vm.runInContext`. Supply the code, get the result. In ES6 language, a "realm" is basically the container for a context. A realm has a 'global' property which is its global object, and a number of properties that specific to each realm isntance, such as the list of "intrinsics" or builtins like Array, Function, Object, etc. | ||
```javascript | ||
var realm = continuum.createRealm(); | ||
var $array = realm.evaluate('[5, 10, 15, 20]'); | ||
// you can use the ES internal functions to directly interact with objects | ||
console.log($array.Get(0)) // 5 | ||
console.log($array.Get('map')) // $Function object | ||
// these two lines have the same result | ||
var $Function = realm.evaluate('Function'); | ||
var $Function = realm.global.Get('Function'); | ||
// if your code uses the module system then it must be run asynchronously | ||
realm.evaluateAsync('module F = "@Function"', function(result){ | ||
// statements and declarations have no return value so result is undefined in this case, however... | ||
console.log(realm.evaluate('F')) // $Module with Function, call, apply, and bind (functional versions) | ||
}) | ||
``` | ||
# ES6 Implementation Status | ||
@@ -35,7 +60,4 @@ | ||
* destructuring assignment | ||
* destructuring arguments | ||
* spread array initializer | ||
* spread arguments | ||
* spread destructuring | ||
* destructuring assignment and arguments | ||
* spread in arguments and array initializers | ||
* rest parameters | ||
@@ -48,15 +70,13 @@ * classes and super | ||
* new String functions | ||
* concise object literal method syntax | ||
* concise methods in object literals | ||
* mutable and deletable __proto__ | ||
* Map | ||
* Set | ||
* WeakMap (garbage collection semantics not fully realized) | ||
* Map, Set, and WeakMap (garbage collection semantics not fully realized) | ||
* Iterators and for...of | ||
* `is` and `isnt` operators (not in es6 but supported anyway) | ||
* Templates | ||
* Module system with imports and exports | ||
* builtin '@std' modules `module std = '@std'` or `import call from '@Function'` | ||
* Generators (kind of broken at the moment though) | ||
### Partially Implemented | ||
* Proxy and Reflect | ||
* Templates | ||
* Generators | ||
@@ -66,3 +86,2 @@ ### Soon | ||
* Private Names | ||
* Partial implementation of Modules | ||
* Default parameters | ||
@@ -72,7 +91,48 @@ * Tail call optimization | ||
### Further out | ||
* Proper implementation of Modules | ||
* Binary data api | ||
# API Overview | ||
Core API: | ||
* __createRealm([callback])__: creates a new realm (context + global object). Optional debug callback for massive information | ||
* __createBytecode(code|filename)__: Creates bytecode from the given source and returns it unexecuted (this will be serializable to disk soon). | ||
* __createRenderer(handlers)__: For debug rendering, like the debugger UI. | ||
* __createNativeFunction(func)__: Wraps a regular function as a function object that can be used inside the virtual | ||
* __introspect($object)__: return a debug Mirror object that wraps any type of VM object, primitive, or scope object. This provides an easy to use and normalized interface for querying information about objects. | ||
Extras: | ||
* __utility__: substantial amount of useful functionality used in continuum and generally useful in any JS | ||
* __constants__: all of the large amount of constants and symbols used by the VM | ||
Additionally exported is the class objects `Assembler`, `Realm`, `Renderer`, and `Script`. | ||
### Realm ### | ||
A Realm is the main thing you interact with. Each realm has a global object with a unique set of builtin globals. A realm is roughly equivelent to an iframe or a node vm context. | ||
* __realm.evaluate(code)__: Executes code in the virtual machine and returns the completion value, if any. "code" can be a string or an already compiled Script object. Every time code is executed, the script object is added to realm.scripts, so you can reuse a script if desired. | ||
* __realm.evaluateAsync(code, callback)__: Primarily for when executing code that uses the module system, which must be run asynchronously if importing remote resources. | ||
Realms are also event emitters and emit events as hooks to implement some APIs, such as the console, as well as vm signals like uncaught exceptions, or debugger pauses. | ||
__VM Events__ | ||
These are emitted by the VM to indicate changes to the state of execution and provide access to information about related objects. | ||
* __realm.on('complete', function(result){})__: emitted whenever a script completes execution. The result value is the same value that's returned from realm.evaluate. | ||
* __realm.on('executing', function(thunk){})__: emitted whenever execution begins or resume. The thunk is the object which executes the bytecode. | ||
* __realm.on('throw', function(exception){})__: throw is emitted on uncaught exception. The thrown object (usually an $Error) will be passed to the callback. | ||
* __realm.on('pause', function(resume){})__: pause is emitter when a `debugger` statement is encountered. A function which will resume execution is passed to the callback, and is also available as `realm.resume`. | ||
* __realm.on('resume', function(){})__: emitted when the resume function provided from the __pause__ event is called and execution begins again. | ||
* __realm.on('op', function(op){})__: emitted every time an opcode is executed. Be very careful when listening to this event. A small to medium sized chunk of code can emit hundreds of thousands or millions of ops in a very short amount of time. | ||
__API Events__ | ||
These are emitted by functions from inside the VM to simulate things like input/output and require some implementation on your part to do anything useful. | ||
* __realm.on('write', function(text, color){})__: emitted by __stdout.write__, which is used by __console.log__ and friends. | ||
* __realm.on('clear', function(){})__: emitted by __stdout.clear__ to provide a way to clear whatever it is you're providing as stdout | ||
* __realm.on('backspace', function(number){})__: emitted by __stdout.backspace__ to provide a way to delete a specific amount of characters from the end. | ||
# TODO | ||
* Hook up module system to environment | ||
* Much work on optimizations | ||
@@ -79,0 +139,0 @@ * Serializable state for saving applications while they run |
@@ -6,3 +6,8 @@ var fs = require('fs'), | ||
exists = fs.existsSync, | ||
print = console.log; | ||
print = console.log, | ||
define = continuum.utility.define, | ||
iterate = continuum.utility.iterate, | ||
map = continuum.utility.map, | ||
Queue = continuum.utility.Queue, | ||
createNativeFunction = continuum.createNativeFunction; | ||
@@ -23,2 +28,6 @@ var _push = [].push; | ||
function write(name, value){ | ||
fs.writeFileSync(name, value); | ||
} | ||
function percent(n, t){ | ||
@@ -36,44 +45,26 @@ return ((100 * n) / t).toFixed(2); | ||
function Queue(){ | ||
this.items = []; | ||
this.length = 0; | ||
this.index = 0; | ||
function formatPath(name){ | ||
return name.split(/\/|\\/).slice(3).join('/'); | ||
} | ||
Queue.prototype = { | ||
constructor: Queue, | ||
push: function push(items){ | ||
if (!(items instanceof Array)) | ||
items = [items]; | ||
function stringify(o){ | ||
return require('util').inspect(o); | ||
} | ||
_push.apply(this.items, items); | ||
this.length += items.length; | ||
return this; | ||
}, | ||
shift: function shift(){ | ||
if (this.length) { | ||
var item = this.items[this.index]; | ||
this.items[this.index++] = null; | ||
this.length--; | ||
if (this.index === 500) { | ||
this.items = this.items.slice(this.index); | ||
this.index = 0; | ||
function toObject(o){ | ||
if (o && o.Enumerate) { | ||
var out = {}; | ||
var keys = o.Enumerate(false, true); | ||
for (var i=0; i < keys.length; i++) { | ||
var item = out[keys[i]] = o.Get(keys[i]); | ||
if (item && item.Enumerate) { | ||
out[keys[i]] = toObject(item); | ||
} | ||
return item; | ||
} | ||
}, | ||
empty: function empty(){ | ||
this.length = 0; | ||
this.index = 0; | ||
this.items = []; | ||
return this; | ||
}, | ||
front: function front(){ | ||
return this.items[this.index]; | ||
return out; | ||
} | ||
}; | ||
return o; | ||
} | ||
var parseTestRecord = (function(){ | ||
var TestCase = (function(){ | ||
var head = /(?:(?:\s*\/\/.*)?\s*\n)*/, | ||
@@ -100,4 +91,5 @@ comment = /\/\*\*?((?:\s|\S)*?)\*\/\s*\n/, | ||
if (!match) | ||
if (!match) { | ||
throw new Error('unrecognized: '+name); | ||
} | ||
@@ -113,9 +105,11 @@ obj.test = match[3]; | ||
if (!match) | ||
if (!match) { | ||
throw new Error('Malformed "@" attribute: '+name); | ||
} | ||
match = match[0]; | ||
if (match in obj) | ||
if (match in obj) { | ||
throw new Error('duplicate: '+match); | ||
} | ||
@@ -127,187 +121,260 @@ obj[match] = stripStars(text.slice(match.length)); | ||
return parseTestRecord; | ||
function TestCase(filename, strict){ | ||
this.abspath = filename; | ||
this.name = path.basename(filename).slice(0, -3); | ||
parseTestRecord(this, read(filename), this.name); | ||
} | ||
define(TestCase.prototype, [ | ||
function isNegative(){ | ||
return 'negative' in this.record; | ||
}, | ||
function isOnlyStrict(){ | ||
return 'onlyStrict' in this.record; | ||
}, | ||
function isNonStrict(){ | ||
return 'noStrict' in this.record; | ||
}, | ||
function getSource(){ | ||
var source = 'var strict_mode = '; | ||
if (this.strict || this.onlyStrict) { | ||
source = '"use strict";\n'+source+'true;\n'; | ||
} else { | ||
source += 'false;\n'; | ||
} | ||
return source + this.test + '\n'; | ||
} | ||
]); | ||
return TestCase; | ||
})(); | ||
function TestRunner(suite, before, after) { | ||
var self = this; | ||
function TestCase(filename, strict){ | ||
this.abspath = filename; | ||
this.name = path.basename(filename).slice(0, -3); | ||
parseTestRecord(this, read(filename), this.name); | ||
} | ||
this.cache = create(null); | ||
this.suite = suite; | ||
TestCase.prototype = { | ||
isNegative: function isNegative(){ | ||
return 'negative' in this.record; | ||
}, | ||
isOnlyStrict: function isOnlyStrict(){ | ||
return 'onlyStrict' in this.record; | ||
}, | ||
isNonStrict: function isNonStrict(){ | ||
return 'noStrict' in this.record; | ||
}, | ||
getSource: function getSource(){ | ||
var source = 'var strict_mode = '; | ||
if (this.strict || this.onlyStrict) { | ||
source = '"use strict";\n'+source+'true;\n'; | ||
} else { | ||
source += 'false;\n'; | ||
define(this, { | ||
executeBefore: before || '', | ||
executeAfter: after || '' | ||
}); | ||
this.testFinished = function testFinished(){ | ||
var current = self.current, | ||
result = current.Get('result'), | ||
error = current.Get('error'); | ||
if (result === undefined) { | ||
current.Put('result', 'fail'); | ||
current.Put('error', 'Failed to load test case (probable parse error).'); | ||
current.Put('description', 'Failed to load test case!'); | ||
} else if (error !== undefined) { | ||
var msg = error.ConstructorName === 'Test262Error' ? '' : error.Get('name') + ": "; | ||
msg += error.Get('message'); | ||
current.Put('error', msg); | ||
} else if (error === undefined && result === 'fail') { | ||
current.Put('error', 'Test case returned non-true value.'); | ||
} | ||
return source + this.test + '\n'; | ||
} | ||
}; | ||
self.callback(toObject(current)); | ||
}; | ||
function Options(o){ | ||
if (o) | ||
for (var k in this) | ||
if (k in o) | ||
this[k] = o[k]; | ||
this.testRun = function testRun(id, path, description, code, result, error){ | ||
var current = self.current; | ||
current.Put('id', id); | ||
current.Put('path', path); | ||
current.Put('description', description); | ||
current.Put('result', result); | ||
current.Put('error', error); | ||
current.Put('code', code); | ||
}; | ||
} | ||
Options.prototype = { | ||
root: __dirname, | ||
strictOnly: false, | ||
nonStrictOnly: false, | ||
unmarkedDefault: false | ||
}; | ||
define(TestRunner.prototype, [ | ||
function run(test, callback){ | ||
var self = this; | ||
this.callback = callback; | ||
continuum(function(realm){ | ||
var src = test.getSource(), | ||
current = self.current = realm.evaluate('({})'); | ||
realm.on('throw', function(e){ | ||
self.current = e.value; | ||
self.testFinished(); | ||
}); | ||
function TestSuite(options){ | ||
options = new Options(options); | ||
var root = resolve(options.root, 'test262', 'test'); | ||
this.tests = resolve(root, 'suite'); | ||
this.libs = resolve(root, 'harness'); | ||
this.strictOnly = options.strictOnly; | ||
this.nonStrictOnly = options.nonStrictOnly; | ||
this.unmarkedDefault = options.unmarkedDefault; | ||
this.queue = new Queue; | ||
this.results = {}; | ||
iterate(test, function(val, key){ | ||
if (key !== 'test') { | ||
current.Put(key, val); | ||
} | ||
}); | ||
if (!exists(this.tests)) { | ||
throw new Error('No test repository found'); | ||
current.Put('code', src); | ||
realm.evaluate(self.executeBefore); | ||
realm.global.Put('testRun', createNativeFunction(self.testRun)); | ||
realm.global.Put('testFinished', createNativeFunction(self.testFinished)); | ||
realm.global.Put('testDescrip', current); | ||
realm.evaluate(src); | ||
realm.evaluate(self.executeAfter); | ||
}); | ||
} | ||
]); | ||
if (!exists(this.libs)) { | ||
throw new Error('No test library found'); | ||
var TestSuite = (function(){ | ||
function TestSuiteOptions(o){ | ||
if (o) { | ||
o = Object(o); | ||
for (var k in this) { | ||
if (k in o) { | ||
this[k] = o[k]; | ||
} | ||
} | ||
} | ||
} | ||
var includes = ['cth.js', 'sta.js', 'testBuiltInObject.js'].map(function(name){ | ||
return read(resolve(this.libs, name)); | ||
}, this).join('\n\n'); | ||
TestSuiteOptions.prototype = { | ||
root: __dirname, | ||
strictOnly: false, | ||
nonStrictOnly: false, | ||
unmarkedDefault: false | ||
}; | ||
Object.defineProperty(this, 'includes', { | ||
get: function(){ return includes } | ||
}); | ||
} | ||
function TestSuite(options){ | ||
options = new TestSuiteOptions(options); | ||
var root = resolve(options.root, 'test262', 'test'); | ||
this.tests = resolve(root, 'suite'); | ||
this.libs = resolve(root, 'harness'); | ||
this.strictOnly = options.strictOnly; | ||
this.nonStrictOnly = options.nonStrictOnly; | ||
this.unmarkedDefault = options.unmarkedDefault; | ||
this.queue = new Queue; | ||
this.results = {}; | ||
TestSuite.prototype.summary = function summary(progress) { | ||
print() | ||
print("=== Summary ==="); | ||
print(" - Ran %d tests", progress.count); | ||
if (progress.failed === 0) { | ||
print(" - All tests succeeded"); | ||
} else { | ||
print(" - Passed %d tests (%d)", progress.succeeded, percent(progress.succeeded, progress.count)); | ||
print(" - Failed %d tests (%d)", progress.failed, percent(progress.failed, progress.count)); | ||
} | ||
}; | ||
if (!exists(this.tests)) { | ||
throw new Error('No test repository found'); | ||
} | ||
if (!exists(this.libs)) { | ||
throw new Error('No test library found'); | ||
} | ||
TestSuite.prototype.enqueue = function enqueue(path){ | ||
if (this.queue.length >= this.max) return this; | ||
if (isDirectory(path)) { | ||
dir(path).forEach(this.enqueue, this); | ||
} else { | ||
this.queue.push(path); | ||
} | ||
return this; | ||
} | ||
var before = map(['cth.js', 'sta.js', 'testBuiltInObject.js'], function(name){ | ||
return read(resolve(this.libs, name)); | ||
}, this).join('\n\n'); | ||
TestSuite.prototype.chapter = function chapter(chapter){ | ||
chapter = chapter.toString().split('.'); | ||
var path = resolve(this.tests, 'ch' + ('00'+ (chapter[0] | 0)).slice(-2)); | ||
if (chapter[1]) { | ||
path = resolve(path, chapter[0] + '.' + chapter[1]); | ||
var after = read(resolve(this.libs, 'gs.js')); | ||
this.runner = new TestRunner(this, before, after); | ||
Object.defineProperty(this, 'includes', { | ||
get: function(){ return includes } | ||
}); | ||
} | ||
if (chapter[2]) { | ||
path = resolve(path, chapter[0] + '.' + chapter[1] + '.' + chapter[2]); | ||
} | ||
if (exists(path)) { | ||
this.enqueue(path); | ||
} | ||
return this; | ||
}; | ||
TestSuite.prototype.next = function next(){ | ||
var item = this.queue.shift(); | ||
if (item) { | ||
var test = new TestCase(item, this.strict); | ||
test.paths = test.path.split('/'); | ||
define(TestSuite.prototype, [ | ||
function summary(progress) { | ||
print(); | ||
print("=== Summary ==="); | ||
print(" - Ran %d tests", progress.count); | ||
if (progress.failed === 0) { | ||
print(" - All tests succeeded"); | ||
} else { | ||
print(" - Passed %d tests (%d)", progress.succeeded, percent(progress.succeeded, progress.count)); | ||
print(" - Failed %d tests (%d)", progress.failed, percent(progress.failed, progress.count)); | ||
} | ||
}, | ||
function enqueue(path){ | ||
if (this.queue.length >= this.max) return this; | ||
if (isDirectory(path)) { | ||
dir(path).forEach(this.enqueue, this); | ||
} else { | ||
this.queue.push(path); | ||
} | ||
return this; | ||
}, | ||
function chapter(chapter){ | ||
chapter = chapter.toString().split('.'); | ||
var path = resolve(this.tests, 'ch' + ('00'+ (chapter[0] | 0)).slice(-2)); | ||
if (chapter[1]) { | ||
path = resolve(path, chapter[0] + '.' + chapter[1]); | ||
} | ||
if (chapter[2]) { | ||
path = resolve(path, chapter[0] + '.' + chapter[1] + '.' + chapter[2]); | ||
} | ||
if (exists(path)) { | ||
this.enqueue(path); | ||
} | ||
return this; | ||
}, | ||
function next(done){ | ||
var item = this.queue.shift(); | ||
if (item) { | ||
var test = new TestCase(item, this.strict); | ||
test.paths.reduce(function(r, s, i, a){ | ||
if (!(s in r)) { | ||
if (i === a.length - 1) { | ||
r[s] = test; | ||
} else { | ||
r[s] = {}; | ||
test.paths = test.path.split('/'); | ||
test.paths.reduce(function(r, s, i, a){ | ||
if (!(s in r)) { | ||
if (i === a.length - 1) { | ||
r[s] = test; | ||
} else { | ||
r[s] = {}; | ||
} | ||
} | ||
return r[s]; | ||
}, this.results); | ||
var self = this; | ||
this.runner.run(test, function(result){ | ||
done.call(self, test); | ||
}); | ||
} | ||
}, | ||
function run(count, done){ | ||
var record = __dirname+'/tested.json'; | ||
var tested = fs.existsSync(record) ? require(record) : {}; | ||
if (typeof count === 'function') { | ||
done = count; | ||
count = 40; | ||
} | ||
if (count-- && this.queue.length) { | ||
var name = formatPath(path.relative(__dirname, this.queue.front())); | ||
if (name in tested) { | ||
this.queue.shift(); | ||
return this.run(++count, done); | ||
} | ||
} | ||
return r[s]; | ||
}, this.results); | ||
tested[name] = true; | ||
var context = continuum(); | ||
test.global = context.global; | ||
context.on('throw', function(e){ | ||
print(e.Get('message')) | ||
}); | ||
context.evaluate(this.includes); | ||
context.global.properties.forEach(function(prop){ | ||
prop[2] &= ~1; | ||
}); | ||
var src = test.getSource(); | ||
test.result = context.evaluate(src); | ||
return test; | ||
} | ||
} | ||
this.next(function(test){ | ||
var name = test.paths.slice(-1); | ||
delete test.abspath; | ||
delete test.path; | ||
delete test.paths; | ||
if (test.result === undefined) { | ||
test.result = 'PASS'; | ||
} | ||
function formatPath(name){ | ||
return name.split(/\/|\\/).slice(3).join('/'); | ||
} | ||
TestSuite.prototype.run = function run(count){ | ||
var test; | ||
var record = __dirname+'/tested.json'; | ||
var tested = fs.existsSync(record) ? require(record) : {}; | ||
count = count || 40; | ||
while (count-- && this.queue.length) { | ||
var name = formatPath(path.relative(__dirname, this.queue.front())); | ||
if (name in tested) { | ||
this.queue.shift(); | ||
count++; | ||
continue; | ||
write(__dirname + '/results/'+name+'.js', stringify(test)); | ||
test.global = null; | ||
this.run(count, done); | ||
}); | ||
} else { | ||
done('done') | ||
} | ||
} | ||
tested[name] = true; | ||
test = this.next(); | ||
var name = test.paths.slice(-1); | ||
delete test.abspath; | ||
delete test.path; | ||
delete test.paths; | ||
if (test.result === undefined) { | ||
test.result = 'PASS'; | ||
} | ||
fs.writeFileSync(__dirname + '/results/'+name+'.js', require('util').inspect(test)); | ||
test.global = null; | ||
} | ||
]); | ||
fs.writeFileSync(record, JSON.stringify(tested, null, ' ')); | ||
return 'done'; | ||
} | ||
return TestSuite; | ||
})(); | ||
var x = new TestSuite; | ||
x.chapter('12.3'); | ||
print(x.run()); | ||
x.chapter('8.2'); | ||
x.run(function(result){ | ||
print(x); | ||
}); | ||
// print(x.includes); | ||
//print(realm.global); |
@@ -39,5 +39,9 @@ #!/usr/bin/env node | ||
files.forEach(function (filename) { | ||
if (!~filename.indexOf('\n') && fs.existsSync(filename)) { | ||
var content = fs.readFileSync(filename, 'utf-8'); | ||
console.log(JSON.stringify(esprima.parse(content), null, 4)); | ||
} else { | ||
var content = filename.replace(/\\n/g, '\n'); | ||
} | ||
console.log(JSON.stringify(esprima.parse(content), null, 2)); | ||
}); | ||
/* vim: set sw=4 ts=4 et tw=80 : */ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
7238342
342
158864
137
4
64
19