Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: Benvie/js-astify
base: 3379982e5a
...
head fork: Benvie/js-astify
compare: 7f78aaec0b
  • 2 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Oct 05, 2012
@Benvie replace the one place where I cheat and parse code, make some conveni…
…ence bindings, clean up and DRY the destructurer
56bbf49
@Benvie change all the builtins to use CPS, implement "interpret" and "refere…
…nce" basic versions, implement a number of the ASTNode executors, and holy hell it actuall executes code
7f78aae
Showing with 284 additions and 137 deletions.
  1. +193 −76 lib/interpretor.js
  2. +91 −61 transformers/es6.js
View
269 lib/interpretor.js
@@ -3,7 +3,8 @@ var descriptor = require('./descriptor'),
define = require('./utility').define,
hasOwn = {}.hasOwnProperty,
create = Object.create,
- defineProperty = Object.defineProperty;
+ defineProperty = Object.defineProperty,
+ defineProperties = Object.defineProperties;
@@ -48,7 +49,8 @@ define(Reference.prototype, [
var functions = new WeakMap,
- primitiveWrappers = new WeakMap;
+ primitiveWrappers = new WeakMap,
+ argumentObjects = new WeakMap;
// #############
@@ -137,52 +139,52 @@ var builtins = (function(builtins){
return builtins[def.name] = new BuiltinType(def);
}
- function makeCollection(name, Ctor){
+ function makeCollection(Ctor){
var collections = new WeakMap,
- prototype = name + 'Prototype',
+ prototype = Ctor.name + 'Prototype',
Builtin;
return Builtin = register({
- name: name,
- call: function(context, args){
+ name: Ctor.name,
+ call: function(context, args, complete){
if (args.receiver == null)
- return Builtin.construct(context, args);
+ return complete(Builtin.construct(context, args));
var target = ToObject(context, args.receiver);
if (collections.has(target))
- throw new TypeError('Object is already a Set');
+ return context.error('type', 'Object is already a Set');
collections.set(target, new Ctor);
- return target;
+ complete(target);
},
- construct: function(context, args){
+ construct: function(context, args, complete){
var self = create(context.global[prototype]);
collections.set(self, new Ctor);
- return self;
+ complete(self);
}
});
}
- function makePrimitive(name, coerce){
+ function makePrimitive(Ctor){
var primitives = new WeakMap,
- prototype = name + 'Prototype';
+ prototype = Ctor.name + 'Prototype';
return register({
- name: name,
- call: function(context, args){
- return coerce(args[0]);
+ name: Ctor.name,
+ call: function(context, args, complete){
+ complete(Ctor(args[0]));
},
- construct: function(context, args){
+ construct: function(context, args, complete){
var self = create(context.global[prototype]);
- primitives.set(self, coerce(args[0]));
- return self;
+ primitives.set(self, Ctor(args[0]));
+ complete(self);
}
});
}
BuiltinArray = register({
name: 'Array',
- construct: function(context, args){
+ construct: function(context, args, complete){
var self = create(context.global.ArrayPrototype);
if (args.length === 1 && typeof args[0] === 'number') {
var len = args[0];
@@ -191,39 +193,45 @@ var builtins = (function(builtins){
self[i] = args[i];
var len = args.length;
}
- return defineProperty(self, 'length', descriptor('length', args.length));
+ defineProperty(self, 'length', descriptor('length', args.length));
+ complete(self);
}
});
- BuiltinBoolean = makePrimitive('Boolean', Boolean);
+ BuiltinBoolean = makePrimitive(Boolean);
BuiltinFunction = register({
name: 'Function',
- construct: function(context, args){}
+ construct: function(context, args, complete){
+ var body = args.pop();
+ var src = 'function anonymous('+args+') {\n'+body+'\n}';
+ var self = new Thunk('anonymous', args.length, parse(src), null, Thunk.NORMAL).instantiate(context);
+ complete(self);
+ }
});
- BuiltinMap = makeCollection('Map', Map);
+ BuiltinMap = makeCollection(Map);
- BuiltinNumber = makePrimitive('String', String);
+ BuiltinNumber = makePrimitive(String);
BuiltinObject = register({
name: 'Object',
- call: function(context, args){
- return ToObject(context, args[0]);
+ call: function(context, args, complete){
+ complete(ToObject(context, args[0]));
},
- construct: function(context, args){
- return create(context.global.ObjectPrototype);
+ construct: function(context, args, complete){
+ complete(create(context.global.ObjectPrototype));
}
});
BuiltinRegExp = register({
name: 'RegExp',
- construct: function(context, args){}
+ construct: function(context, args, complete){}
});
- BuiltinSet = makeCollection('Set', Set);
+ BuiltinSet = makeCollection(Set);
- BuiltinWeakMap = makeCollection('WeakMap', WeakMap);
+ BuiltinWeakMap = makeCollection(WeakMap);
return builtins;
}({}));
@@ -282,6 +290,19 @@ define(Scope.prototype, [
},
function create(Type, args){
return builtins[Type].construct(this, args ? args : []);
+ },
+ function makeArguments(args){
+ var obj = create(this.global.ObjectPrototype);
+ argumentObjects.set(obj, true);
+
+ if (args) {
+ for (var i=0; i < args.length; i++)
+ obj[i] = args[i];
+ }
+
+ return defineProperty(obj, 'length', {
+ value: i
+ });
}
]);
@@ -307,7 +328,9 @@ function GlobalScope(){
});
}
+
this.record = record;
+ this.receiver = this.record;
}
inherit(GlobalScope, Scope);
@@ -360,29 +383,40 @@ inherit(BlockScope, Scope, [
},
]);
-var glob = new GlobalScope();
-var block = glob.child(FunctionScope).child(BlockScope);
-block.declare('let', 'Function', 'whetver')
-block.declare('var', 'Function', 'x')
-console.log(block);
+
+
+function interpret(node, context, complete){
+ console.log('interpreting ' + node.type);
+ interpretors[node.type](node, context, complete);
+}
+
+function reference(node, context, complete){
+ if (node.type === 'MemberExpression') {
+ interpret(node.object, context, function(object){
+ interpret(node.property, context, function(property){
+ complete(new Reference(object, property));
+ });
+ });
+ } else if (node.type === 'Identifier') {
+ complete(context.reference(node.name));
+ }
+}
var interpretors = {
ArrayExpression: function(node, context, complete){
- var count = node.elements.length,
- array = BuiltinArray.construct(context, [count]);
-
- if (!count)
- return complete(array);
+ var count = node.elements.length;
- function each(i, value){
- array[i] = value;
- if (!--count)
- complete(array);
- }
+ BuiltinArray.construct(context, [count], function(array){
+ if (!count) return complete(array);
- for (var i=0; i < node.elements; i++)
- interpret(node.elements[i], context, each.bind(null, i));
+ for (var i=0; i < count; i++) {
+ interpret(node.elements[i], context, function(value){
+ array[i] = value;
+ if (i === count - 1) complete(array);
+ });
+ }
+ });
},
ArrayPattern: function(node, context){},
ArrowFunctionExpression: function(node, context){},
@@ -437,9 +471,39 @@ var interpretors = {
});
});
},
- BlockStatement: function(node, context){},
- BreakStatement: function(node, context){},
- CallExpression: function(node, context){},
+ BlockStatement: function(node, context, complete){
+ var body = node.body,
+ count = body.length,
+ statement;
+
+ context = context.child(BlockScope);
+
+ for (var i=0; statement = body[i]; i++) {
+ interpret(statement, context, function(result){
+ if (i === count - 1)
+ complete(result);
+ });
+ }
+ },
+ BreakStatement: function(node, context, complete){
+
+ },
+ CallExpression: function(node, context, complete){
+ var argv = node.arguments,
+ argc = argv.length,
+ args = [],
+ arg;
+
+ for (var i=0; arg = argv[i]; i++) {
+ interpret(arg, context, function(result){
+ args.push(result);
+ });
+ }
+
+ interpret(node.callee, context, function(result){
+ functions.get(result).call(context, context.createArguments(args), complete);
+ });
+ },
CatchClause: function(node, context){},
ClassBody: function(node, context){},
ClassDeclaration: function(node, context){},
@@ -449,18 +513,27 @@ var interpretors = {
ContinueStatement: function(node, context){},
DebuggerStatement: function(node, context){},
DoWhileStatement: function(node, context){},
- EmptyStatement: function(node, context){},
+ EmptyStatement: function(node, context, complete){
+ complete();
+ },
ExportDeclaration: function(node, context){},
ExportSpecifier: function(node, context){},
ExportSpecifierSet: function(node, context){},
- ExpressionStatement: function(node, context){},
+ ExpressionStatement: function(node, context, complete){
+ if (node.expression.type === 'Identifier')
+ complete(context.get(node.expression.name));
+ else
+ interpret(node.expression, context, complete);
+ },
ForInStatement: function(node, context){},
ForOfStatement: function(node, context){},
ForStatement: function(node, context){},
FunctionDeclaration: function(node, context){},
FunctionExpression: function(node, context){},
Glob: function(node, context){},
- Identifier: function(node, context){},
+ Identifier: function(node, context, complete){
+ complete(node.name);
+ },
IfStatement: function(node, context){},
ImmediatelyInvokedFunctionExpression: function(node, context){},
ImportDeclaration: function(node, context){},
@@ -470,43 +543,76 @@ var interpretors = {
complete(node.value);
},
LogicalExpression: function(node, context){},
- MemberExpression: function(node, context){},
+ MemberExpression: function(node, context, complete){
+ interpret(node.object, context, function(object){
+ interpret(node.property, context, function(property){
+ complete(object[property]);
+ });
+ });
+ },
MethodDefinition: function(node, context){},
ModuleDeclaration: function(node, context){},
- NewExpression: function(node, context){},
+ NewExpression: function(node, context, complete){
+ var argv = node.arguments,
+ argc = argv.length,
+ args = [],
+ arg;
+
+ for (var i=0; arg = argv[i]; i++) {
+ interpret(arg, context, function(result){
+ args.push(result);
+ });
+ }
+
+ reference(node.callee, context, function(result){
+ functions.get(result.get()).construct(context, context.makeArguments(args), complete);
+ });
+ },
ObjectExpression: function(node, context, complete){
var properties = {},
- count = node.properties.length,
- object = BuiltinObject.construct(context);
+ property,
+ count = node.properties.length;
- if (!count)
- return complete(object);
- function each(property, value){
- if (properties[property.key])
- properties[property.key][property.type] = value;
- else
- properties[property.key] = descriptor(property.type, value);
+ BuiltinObject.construct(context, null, function(object){
+ if (!count)
+ return complete(object);
- if (!--count)
- complete(defineProperties(object, properties));
- }
- node.properties.forEach(function(property){
- properties[property.key] = null;
- interpret(property.value, context, each.bind(null, property));
+
+ for (var i=0; property = node.properties[i]; i++) {
+ interpret(property.key, context, function(key){
+ interpret(property.value, context, function(value){
+ if (properties[key])
+ properties[key][property.kind] = value;
+ else
+ properties[key] = descriptor(property.kind, value);
+
+ if (!--count)
+ complete(defineProperties(object, properties));
+ });
+ });
+ }
});
},
ObjectPattern: function(node, context){},
Path: function(node, context){},
Program: function(node, context, complete){
+ var body = node.body,
+ statement;
+
context = context || new GlobalScope;
- for (var i=0; i < node.body.length; i++) {
+ for (var i=0; statement = body[i]; i++) {
+ interpret(statement, context, function(value){
+ if (i === body.length - 1)
+ complete(value);
+ });
}
+ console.log(context);
},
Property: function(node, context, complete){
-
+ interpret(node.value, context, complete);
},
ReturnStatement: function(node, context){},
SequenceExpression: function(node, context){},
@@ -515,8 +621,8 @@ var interpretors = {
TaggedTemplateExpression: function(node, context){},
TemplateElement: function(node, context){},
TemplateLiteral: function(node, context){},
- ThisExpression: function(node, context){
- return context.receiver;
+ ThisExpression: function(node, context, complete){
+ complete(context.receiver);
},
ThrowStatement: function(node, context){},
TryStatement: function(node, context){},
@@ -528,3 +634,14 @@ var interpretors = {
WithStatement: function(node, context){},
YieldExpression: function(node, context){},
};
+
+// var glob = new GlobalScope();
+// var block = glob.child(FunctionScope).child(BlockScope);
+// block.declare('let', 'Function', 'whetver')
+// block.declare('var', 'Function', 'x')
+// console.log(block);
+
+
+var AST = require('./AST');
+var ast = new AST(0, 0, 'y = ({ x: [[[1], [new Set], [], 4]] }); y').toJSON();
+console.log(interpret(ast, null, console.log))
View
152 transformers/es6.js
@@ -1,13 +1,13 @@
var ASTNode = require('astify').ASTNode,
$ = ASTNode.createNode,
converters = {},
+ define = require('../lib/utility').define,
freeze = $('Object').get('freeze'),
defaultQuasi = ASTNode.parse(function(r){
for (var i=0, o=''; r[i]; o += r[i].raw + (++i === r.length ? '' : arguments[i]));
return o;
});
-
module.exports = function(ast){
for (var k in converters) {
ast.find(k).forEach(function(item){
@@ -18,15 +18,39 @@ module.exports = function(ast){
return ast;
}
-var define = $('Object').get('defineProperty'),
+function typeOF(name, type){
+ return $('#binary', '===', $('#unary', 'typeof', $(name)), $('#literal', type));
+}
+
+function ternary(check, either, or){
+ return $('#conditional', check, either, or);
+}
+
+function object(){
+ return $('#object');
+}
+
+function get(path){
+ if (typeof path === 'string')
+ path = path.split('.');
+ var base = typeof path[0] === 'string' ? $(path[0]) : path[0];
+ for (var i=1; i < path.length; i++)
+ base = base.get(path[i]);
+ return base;
+}
+
+
+var defineProperty = get('Object.defineProperty'),
constructor = $('#literal', 'constructor'),
- hidden = $('#object', { enumerable: false });
+ hidden = $('#object', { enumerable: false }),
+ arraySlice = get('Array.prototype.slice.call');
+
+
function addConverter(type, callback){
converters[type] = callback;
}
-var arraySlice = $('Array').get('prototype').get('slice').get('call');
addConverter('function[rest!=null]', function(node){
@@ -44,7 +68,7 @@ addConverter('class', function(node){
var superclass = node.superClass && node.superClass.clone();
node.find('member[object=super]').forEach(function(superCall){
var call = superCall.parent;
- call.callee = superclass.get('prototype').get(superCall.property);
+ call.callee = get(superclass, 'prototype', superCall.property);
call.call();
});
node.find('call[callee=super]').forEach(function(superCall){
@@ -69,7 +93,7 @@ addConverter('class', function(node){
});
closure.append(node.id.set('prototype', prototype));
- closure.append(define.call([ctor.id.get('prototype'), constructor, hidden]));
+ closure.append(defineProperty.call([ctor.id.get('prototype'), constructor, hidden]));
closure.append(ret);
if (node.matches('class')) {
@@ -97,7 +121,7 @@ addConverter('arrow', function(node){
addConverter('module', function(node){
node.find('export').forEach(converters.export);
var closure = $('#functionexpr', null, ['global', 'exports'], node.body.clone());
- var args = [$('#this'), $('#this'), ASTNode.parse('typeof exports === "undefined" ? {} : exports')];
+ var args = [$('#this'), $('#this'), ternary(typeOF('exports', 'undefined'), object(), $('exports'))];
closure.returns('exports');
var decl = freeze.call(closure.get('call').call(args)).declaration(node.id);
node.replaceWith(decl);
@@ -150,66 +174,72 @@ function destructure(node, parent, value){
handler.run(node);
}
-Destructurer.prototype = new process.EventEmitter;
-
-Destructurer.prototype.run = function run(node){
- this.iife.addArgument(this.root, this.value);
- this.handle(node, []);
- this.container.insertAfter(this.closure, this.parent);
- if (this.decl !== this.parent && this.decl.declarations.length)
- this.container.insertAfter(this.decl, this.parent);
- if (!this.parent.matches('var') || this.parent.declarations.length === 0)
- this.container.remove(this.parent);
-}
-
-Destructurer.prototype.handle = function handle(node, path){
- if (node.matches('arraypattern')) {
- node.elements.forEach(function(subnode, index){
- this.handle(subnode, path.concat(index));
- }, this);
- if (node.parent.matches('decl'))
- node.parent.parent.remove(node.parent);
- } else if (node.matches('objectpattern')) {
- node.properties.forEach(function(prop){
- this.handle(prop.value, path.concat(prop.key.name));
- }, this);
- if (node.parent.matches('decl'))
- node.parent.parent.remove(node.parent);
- } else {
- var resolved = this.resolve(path);
- if (node.matches('ident')) {
- this.decl.append($('#decl', node.clone()));
- }
- else if (node.matches('member'))
- node = this.checkForThis(node)
- this.iife.append(node.set(resolved));
+var interpretPattern = {
+ ArrayPattern: function(node, index, array){
+ this.handle(node, array.path.concat(index));
+ },
+ ObjectPattern: function(prop, index, array){
+ this.handle(prop.value, array.path.concat(prop.key.name));
}
};
-Destructurer.prototype.checkForThis = function checkForThis(node){
- var obj = node;
- while (obj.parent && obj.parent.matches('member'))
- obj = obj.parent;
- if (obj.object.matches('this')) {
- this.usesThis();
- node = node.clone();
- node.object.replaceWith($('$this'));
- }
- return node;
-}
-Destructurer.prototype.usesThis = function usesThis(){
- this.iife.addArgument($('$this'), $('#this'));
- this.usesThis = function(){}
-};
+define(Destructurer.prototype, [
+ function run(node){
+ this.iife.addArgument(this.root, this.value);
+ this.handle(node, []);
+ this.container.insertAfter(this.closure, this.parent);
-Destructurer.prototype.resolve = function resolve(path){
- var root = this.root;
- for (var i=0; i < path.length; i++)
- root = root.get(path[i]);
- return root;
-}
+ if (this.decl !== this.parent && this.decl.declarations.length)
+ this.container.insertAfter(this.decl, this.parent);
+
+ if (!this.parent.matches('var') || this.parent.declarations.length === 0)
+ this.container.remove(this.parent);
+ },
+ function handle(node, path){
+ if (node.matches('pattern')) {
+ var components = node.elements || node.properties;
+ components.path = path;
+ components.forEach(interpretPattern[node.type], this);
+
+ if (node.parent.matches('decl'))
+ node.parent.parent.remove(node.parent);
+
+ } else {
+ var resolved = this.resolve(path);
+
+ if (node.matches('ident'))
+ this.decl.append($('#decl', node.clone()));
+ else if (node.matches('member'))
+ node = this.checkForThis(node)
+
+ this.iife.append(node.set(resolved));
+ }
+ },
+ function checkForThis(node){
+ var obj = node;
+ while (obj.parent && obj.parent.matches('member'))
+ obj = obj.parent;
+
+ if (obj.object.matches('this')) {
+ this.usesThis();
+ node = node.clone();
+ node.object.replaceWith($('$this'));
+ }
+ return node;
+ },
+ function usesThis(){
+ this.iife.addArgument($('$this'), $('#this'));
+ this.usesThis = function(){}
+ },
+ function resolve(path){
+ var root = this.root;
+ for (var i=0; i < path.length; i++)
+ root = root.get(path[i]);
+ return root;
+ }
+]);
function patterns(node){

No commit comments for this range

Something went wrong with that request. Please try again.