UNPKG

neutrinoscript

Version:
541 lines (455 loc) 12.7 kB
(function (exports) { // Extend as needed. var lang = exports.lang = { Node: { }, Program: { extends: 'Node', fields: ['@body'] }, Statement: { extends: 'Node' }, EmptyStatement: { extends: 'Statement' }, BlockStatement: { extends: 'Statement', fields: ['@body'] }, ExpressionStatement: { extends: 'Statement', fields: ['@expression'] }, IfStatement: { extends: 'Statement', fields: ['@test', '@consequent', '@alternate'] }, LabeledStatement: { extends: 'Statement', fields: ['@label', '@body'] }, BreakStatement: { extends: 'Statement', fields: ['@label'] }, ContinueStatement: { extends: 'Statement', fields: ['@label'] }, WithStatement: { extends: 'Statement', fields: ['@object', '@body'] }, SwitchStatement: { extends: 'Statement', fields: ['@discriminant', '@cases', 'lexical'], }, ReturnStatement: { extends: 'Statement', fields: ['@argument'] }, ThrowStatement: { extends: 'Statement', fields: ['@argument'] }, TryStatement: { extends: 'Statement', fields: ['@block', '@handlers', '@finalizer'] }, WhileStatement: { extends: 'Statement', fields: ['@test', '@body'] }, DoWhileStatement: { extends: 'Statement', fields: ['@body', '@test'] }, ForStatement: { extends: 'Statement', fields: ['@init', '@test', '@update', '@body'] }, ForInStatement: { extends: 'Statement', fields: ['@left', '@right', '@body', 'each'] }, LetStatement: { extends: 'Statement', fields: ['@head', '@body'] }, DebuggerStatement: { extends: 'Statement' }, Declaration: { extends: 'Statement' }, FunctionDeclaration: { extends: 'Declaration', fields: ['@id', '@params', '@body', '@decltype', 'generator', 'expression', '@modifiers'] }, VariableDeclaration: { extends: 'Declaration', fields: ['kind', '@declarations'] }, VariableDeclarator: { extends: 'Node', fields: ['@id', '@init', '@decltype', '@arguments'] }, Expression: { extends: 'Pattern' }, ThisExpression: { extends: 'Expression' }, ArrayExpression: { extends: 'Expression', fields: ['@elements'] }, ObjectExpression: { extends: 'Expression', fields: ['@properties'] }, Property: { extends: 'Node', fields: ['@key', '@value', 'kind'], }, FunctionExpression: { extends: 'Expression', fields: ['@id', '@params', '@body', '@decltype', 'generator', 'expression'] }, SequenceExpression: { extends: 'Expression', fields: ['@expressions'] }, UnaryExpression: { extends: 'Expression', fields: ['operator', '@argument', 'prefix'] }, BinaryExpression: { extends: 'Expression', fields: ['operator', '@left', '@right'] }, AssignmentExpression: { extends: 'Expression', fields: ['@left', 'operator', '@right'] }, UpdateExpression: { extends: 'Expression', fields: ['operator', '@argument', 'prefix'] }, LogicalExpression: { extends: 'Expression', fields: ['operator', '@left', '@right'] }, ConditionalExpression: { extends: 'Expression', fields: ['@test', '@consequent', '@alternate'] }, NewExpression: { extends: 'Expression', fields: ['@callee', '@arguments'] }, CallExpression: { extends: 'Expression', fields: ['@callee', '@arguments'] }, MemberExpression: { extends: 'Expression', fields: ['@object', '@property', 'computed', 'kind'] }, YieldExpression: { extends: 'Expression', fields: ['@argument'] }, ComprehensionExpression: { extends: 'Expression', fields: ['@blocks', '@filter'] }, GeneratorExpression: { extends: 'Expression', fields: ['@blocks', '@filter'] }, LetExpression: { extends: 'Expression', fields: ['@head', '@body'] }, Pattern: { extends: 'Node' }, ObjectPattern: { extends: 'Pattern', fields: ['@properties'] }, ArrayPattern: { extends: 'Pattern', fields: ['@elements'] }, SwitchCase: { extends: 'Node', fields: ['@test', '@consequent'] }, CatchClause: { extends: 'Node', fields: ['@param', '@guard', '@body'] }, Identifier: { extends: 'Expression', fields: ['name', 'kind'] }, Literal: { extends: 'Expression', fields: ['value'] }, Type: { extends: 'Node' }, PointerType: { extends: 'Type', fields: ['@base'] }, ArrayType: { extends: 'PointerType', fields: ['length'] }, StructType: { extends: 'Type', fields: ['@id', '@members', 'isUnion'] }, MemberDeclarator: { extends: 'Node', fields: ['modifiers', '@declarator'] }, ArrowType: { extends: 'Type', fields: ['@params', '@return'] }, TypeIdentifier: { extends: 'Type', fields: ['name'] }, TypeAliasDirective: { extends: 'Node', fields: ['@original', '@alias'] }, CastExpression: { extends: 'Expression', fields: ['@as', '@argument'] } }; function allFields(spec) { // Make the location a special last field. var fields = ['leadingComments', 'loc']; while (spec) { if (spec.fields) { fields = spec.fields.concat(fields); } spec = spec.extends ? lang[spec.extends] : null; } return fields; } exports.allFields = allFields; function prefixUnderscore(s) { return '_' + s; } function ensureConstructor(name, spec) { if (!exports[name]) { // Make a new constructor if it doesn't exist yet. var fields = allFields(spec); var children = []; var body = ['this.type = "' + name + '";']; for (var i = 0, j = fields.length; i < j; i++) { var fname = fields[i]; if (fname.charAt(0) === '@') { fields[i] = fname = fname.substr(1); children.push(fname); } body.push('this.' + fname + ' = _' + fname + ';'); } // Prefix parameter names with underscores so keywords work. var node = new Function(fields.map(prefixUnderscore), body.join('\n')); // Hook up the prototypes. if (spec.extends) { var pnode = ensureConstructor(spec.extends, lang[spec.extends]); node.prototype = Object.create(pnode.prototype); } Object.defineProperty(node.prototype, '_children', { value: children, writable: true, configurable: true, enumerable: false }); exports[name] = node; } return exports[name]; } // Build constructors out of the language spec. for (var name in lang) { ensureConstructor(name, lang[name]); } // Make a walk function (map and replace) named |name|. By default it // walks the ASexports bottom-up. If different behavior is needed for different // nodes, override the walk function explicitly on those nodes. // // Returning null means "delete this null". Any other falsey values means // identity. exports.makePass = function makePass(name, prop) { return function (o) { var trans, arr; var child, children = this._children; for (var i = 0, j = children.length; i < j; i++) { if (!(child = this[children[i]])) { continue; } if (child instanceof Array) { arr = this[children[i]] = []; for (var k = 0, l = child.length; k < l; k++) { if (!child[k]) { arr.push(child[k]); } else if (typeof child[k][name] === 'function') { trans = child[k][name](o); if (trans !== null) { arr.push(trans); } } } } else if (typeof child[name] === 'function') { trans = child[name](o); if (trans === null) { this[children[i]] = undefined; } else { this[children[i]] = trans; } } } if (typeof this[prop] === 'function') { if (o.logger && typeof this.loc !== 'undefined') { o.logger.push(this); trans = this[prop](o); o.logger.pop(); } else { trans = this[prop](o); } if (trans === null) { return null; } return trans ? trans : this; } return this; }; }; exports.makePass = function makePass(name, prop, backward) { return function (o) { var trans, arr; var child, children = this._children; var i, k; for (var x = 0, j = children.length; x < j; x++) { i = backward ? children.length - 1 - x : x; if (!(child = this[children[i]])) { continue; } if (child instanceof Array) { arr = this[children[i]] = []; var y; for (var y = 0, l = child.length; y < l; y++) { k = backward ? child.length - 1 - y : y; if (!child[k]) { if (backward) { arr.unshift(child[k]); } else { arr.push(child[k]); } } else if (typeof child[k][name] === 'function') { trans = child[k][name](o); if (trans !== null) { if (backward) { arr.unshift(trans); } else { arr.push(trans); } } } } } else if (typeof child[name] === 'function') { trans = child[name](o); if (trans === null) { this[children[i]] = undefined; } else { this[children[i]] = trans; } } } if (typeof this[prop] === 'function') { if (o.logger && typeof this.loc !== 'undefined') { o.logger.push(this); trans = this[prop](o); o.logger.pop(); } else { trans = this[prop](o); } if (trans === null) { return null; } return trans ? trans : this; } return this; }; }; exports.lift = function lift(raw) { if (!raw) { return raw; } if (raw instanceof Array) { return raw.map(function (r) { return r ? lift(r) : r; }); } var type = raw.type; var Node = exports[type]; if (!Node) { throw new Error('unknown node type `' + type + '\''); } var node = new Node(); node.loc = raw.loc; var fields = allFields(lang[type]); for (var i = 0, j = fields.length; i < j; i++) { var field; if (fields[i].charAt(0) === '@') { field = fields[i].substr(1); if (raw[field]) { node[field] = lift(raw[field]); } } else { field = fields[i]; node[field] = raw[field]; } } return node; }; exports.flatten = function flatten(node) { if (!node) { return node; } if (node instanceof Array) { return node.map(function (n) { return flatten(n); }); } var type = node.type; var raw = { type: type }; var fields = allFields(lang[type]); for (var i = 0, j = fields.length; i < j; i++) { var field; if (fields[i].charAt(0) === '@') { field = fields[i].substr(1); if (node[field]) { raw[field] = flatten(node[field]); } else { raw[field] = null; } } else { field = fields[i]; raw[field] = node[field]; } } return raw; }; })(typeof exports === 'undefined' ? (estransform = {}) : exports);