Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but 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
Brandon Benvie replace the one place where I cheat and parse code, make some conveni…
…ence bindings, clean up and DRY the destructurer
56bbf49
Brandon 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
269 lib/interpretor.js
View
@@ -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))
152 transformers/es6.js
View
@@ -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.