Skip to content

Commit

Permalink
Allow the runtime to be imported as modules
Browse files Browse the repository at this point in the history
When using `--modules=commonjs --import-runtime` or
`--modules=parse --import-runtime` the generated code will output
require/import statements that import the runtime function as a module.
This means that if you are compiling to commonjs or es6 modules you
can get a minimal runtime and no external runtime file is needed.

Fixes #1628
  • Loading branch information
arv committed Apr 23, 2016
1 parent f8a52b6 commit 0520814
Show file tree
Hide file tree
Showing 22 changed files with 313 additions and 99 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,9 @@ updateSemver: # unless the package.json has been manually edited.
git diff --quiet -- package.json && node build/incrementSemver.js

dist/commonjs: bin/traceur.js
./traceur --dir src/ dist/commonjs/ --modules=commonjs
./traceur --dir src/ dist/commonjs/ --modules=commonjs --import-runtime

prepublish: bin/traceur.js bin/traceur-runtime.js
prepublish: bin/traceur.js bin/traceur-runtime.js dist/commonjs/

WIKI_OUT = \
test/wiki/CompilingOffline/out/greeter.js
Expand Down
2 changes: 2 additions & 0 deletions src/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const optionsV01 = enumerableOnlyObject({
freeVariableChecker: false,
generatorComprehension: false,
generators: true,
importRuntime: false,
inputSourceMap: false,
jsx: false,
lowResolutionSourceMap: false,
Expand Down Expand Up @@ -151,6 +152,7 @@ addFeatureOption('exponentiation', EXPERIMENTAL);
addFeatureOption('exportFromExtended', EXPERIMENTAL);
addFeatureOption('forOn', EXPERIMENTAL);
addFeatureOption('generatorComprehension', EXPERIMENTAL);
addFeatureOption('importRuntime', EXPERIMENTAL);
addFeatureOption('jsx', EXPERIMENTAL);
addFeatureOption('memberVariables', EXPERIMENTAL);
addFeatureOption('require', EXPERIMENTAL);
Expand Down
13 changes: 9 additions & 4 deletions src/codegeneration/AsyncGeneratorTransformPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
FunctionDeclaration,
FunctionExpression
} from '../syntax/trees/ParseTrees.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
createBindingIdentifier,
createIdentifierExpression as id,
Expand All @@ -29,7 +30,8 @@ import {
parseStatement
} from './PlaceholderParser.js';

export class AsyncGeneratorTransformPass extends TempVarTransformer {
export class AsyncGeneratorTransformPass extends
ImportRuntimeTrait(TempVarTransformer) {
// TODO: This class is modelled after GeneratorTransformPass. When the spec
// for async generators will have stabilized, it may be an option to merge
// this class into GeneratorTransformPass. However, note: This transformer
Expand All @@ -50,9 +52,10 @@ export class AsyncGeneratorTransformPass extends TempVarTransformer {
return super.transformFunctionDeclaration(tree);

let nameIdExpression = id(tree.name.identifierToken);

let initAsyncGeneratorFunction =
this.getRuntimeExpression('initAsyncGeneratorFunction');
let setupPrototypeExpression = parseExpression
`$traceurRuntime.initAsyncGeneratorFunction(${nameIdExpression})`;
`${initAsyncGeneratorFunction}(${nameIdExpression})`;

// Function declarations in blocks do not hoist. In that case we add the
// variable declaration after the function declaration.
Expand Down Expand Up @@ -89,8 +92,10 @@ export class AsyncGeneratorTransformPass extends TempVarTransformer {

let functionExpression =
this.transformFunction_(tree, FunctionExpression, id(name));
let initAsyncGeneratorFunction =
this.getRuntimeExpression('initAsyncGeneratorFunction');
return parseExpression
`$traceurRuntime.initAsyncGeneratorFunction(${functionExpression })`;
`${initAsyncGeneratorFunction}(${functionExpression })`;
}

transformFunction_(tree, constructor, nameExpression) {
Expand Down
7 changes: 5 additions & 2 deletions src/codegeneration/AsyncGeneratorTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
createVariableStatement
} from './ParseTreeFactory.js';
import {parseStatement} from './PlaceholderParser.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {
AwaitExpression,
Expand All @@ -37,7 +38,7 @@ import {ARGUMENTS} from '../syntax/PredefinedName.js';
import {VAR} from '../syntax/TokenType.js';

export class AsyncGeneratorTransformer extends
SkipFunctionsTransformerTrait(TempVarTransformer) {
SkipFunctionsTransformerTrait(ImportRuntimeTrait(TempVarTransformer)) {
constructor(identifierGenerator, reporter, options) {
super(identifierGenerator, reporter, options);
this.variableDeclarations_ = [];
Expand Down Expand Up @@ -78,8 +79,10 @@ export class AsyncGeneratorTransformer extends
createVariableDeclarationList(VAR, this.variableDeclarations_)));
}
let body = createBlock(tree.statements);
let createAsyncGeneratorInstance =
this.getRuntimeExpression('createAsyncGeneratorInstance');
statements.push(parseStatement `
return $traceurRuntime.createAsyncGeneratorInstance(
return ${createAsyncGeneratorInstance}(
async function (${this.ctx_}) {
${body}
}, ${name});`);
Expand Down
10 changes: 6 additions & 4 deletions src/codegeneration/AsyncToGeneratorTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
Method,
YieldExpression
} from '../syntax/trees/ParseTrees.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {ParenTrait} from './ParenTrait.js';
import {parseStatement} from './PlaceholderParser.js';
import {TempVarTransformer} from './TempVarTransformer.js';
Expand All @@ -30,7 +31,7 @@ import {
} from './ParseTreeFactory.js';

export class AsyncToGeneratorTransformer extends
ParenTrait(TempVarTransformer) {
ImportRuntimeTrait(ParenTrait(TempVarTransformer)) {
constructor(identifierGenerator, reporter, options) {
super(identifierGenerator, reporter, options);
this.inAsyncFunction_ = false;
Expand Down Expand Up @@ -63,7 +64,8 @@ export class AsyncToGeneratorTransformer extends
const inAsyncFunction = this.inAsyncFunction_;
this.inAsyncFunction_ = true;
body = this.transformFunctionBody(body);
body = wrapBodyInSpawn(body);
const spawn = this.getRuntimeExpression('spawn');
body = wrapBodyInSpawn(body, spawn);
this.inAsyncFunction_ = inAsyncFunction;
return body;
}
Expand Down Expand Up @@ -91,13 +93,13 @@ export class AsyncToGeneratorTransformer extends
}
}

function wrapBodyInSpawn(body) {
function wrapBodyInSpawn(body, spawn) {
const visitor = new FindArguments();
visitor.visitAny(body);
const argExpr = visitor.found ?
createIdentifierExpression(ARGUMENTS) :
createNullLiteral();
const statement = parseStatement
`return $traceurRuntime.spawn(this, ${argExpr}, function*() { ${body} });`
`return ${spawn}(this, ${argExpr}, function*() { ${body} });`
return new FunctionBody(body.location, [statement])
}
36 changes: 18 additions & 18 deletions src/codegeneration/ClassTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
} from '../syntax/TokenType.js';
import {MakeStrictTransformer} from './MakeStrictTransformer.js';
import {ParenTrait} from './ParenTrait.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
createBindingIdentifier,
createIdentifierExpression as id,
Expand Down Expand Up @@ -88,16 +89,6 @@ import {
//
// The super property and super calls are transformed in the SuperTransformer.

function classCall(func, object, staticObject, superClass) {
if (superClass) {
return parseExpression
`($traceurRuntime.createClass)(${func}, ${object}, ${staticObject},
${superClass})`;
}
return parseExpression
`($traceurRuntime.createClass)(${func}, ${object}, ${staticObject})`;
}

function methodNameFromTree(tree) {
// COMPUTED_PROPERTY_NAME such as [Symbol.iterator]
if (tree.type === COMPUTED_PROPERTY_NAME) {
Expand Down Expand Up @@ -147,7 +138,7 @@ function removeStaticModifier(tree) {
}
}

export default function isConstructor(tree) {
function isConstructor(tree) {
if (tree.type !== METHOD || tree.isStatic ||
tree.functionKind !== null) {
return false;
Expand All @@ -157,7 +148,8 @@ export default function isConstructor(tree) {
name.literalToken.value === CONSTRUCTOR;
}

export class ClassTransformer extends ParenTrait(TempVarTransformer) {
export class ClassTransformer extends
ImportRuntimeTrait(ParenTrait(TempVarTransformer)) {
/**
* @param {UniqueIdentifierGenerator} identifierGenerator
* @param {ErrorReporter} reporter
Expand Down Expand Up @@ -234,6 +226,7 @@ export class ClassTransformer extends ParenTrait(TempVarTransformer) {
constructor.body);

let expression;
let createClass = this.getRuntimeExpression('createClass');
if (tree.name) {
let functionStatement;
let name = tree.name.identifierToken;
Expand All @@ -249,18 +242,23 @@ export class ClassTransformer extends ParenTrait(TempVarTransformer) {
if (superClass) {
expression = parseExpression `function($__super) {
${functionStatement};
return ($traceurRuntime.createClass)(${nameId}, ${protoObject},
${staticObject}, $__super);
return (${createClass})(${nameId}, ${protoObject},
${staticObject}, $__super);
}(${superClass})`;
} else {
expression = parseExpression `function() {
${functionStatement};
return ($traceurRuntime.createClass)(${nameId}, ${protoObject},
${staticObject});
return (${createClass})(${nameId}, ${protoObject}, ${staticObject});
}()`;
}
} else {
expression = classCall(func, protoObject, staticObject, superClass);
if (superClass) {
expression = parseExpression
`(${createClass})(${func}, ${protoObject}, ${staticObject}, ${superClass})`;
} else {
expression = parseExpression
`(${createClass})(${func}, ${protoObject}, ${staticObject})`;
}
}

return this.makeStrict_(expression);
Expand Down Expand Up @@ -290,10 +288,12 @@ export class ClassTransformer extends ParenTrait(TempVarTransformer) {
}

getDefaultConstructor_(tree) {
// TODO(arv): Move this to SuperTransformer.
if (tree.superClass) {
let name = id(tree.name.identifierToken);
let superConstructor = this.getRuntimeExpression('superConstructor');
return parsePropertyDefinition `constructor() {
$traceurRuntime.superConstructor(${name}).apply(this, arguments)
${superConstructor}(${name}).apply(this, arguments)
}`;
}
return parsePropertyDefinition `constructor() {}`;
Expand Down
7 changes: 5 additions & 2 deletions src/codegeneration/DestructuringTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
VariableDeclarationList,
VariableStatement,
} from '../syntax/trees/ParseTrees.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {
EQUAL,
Expand Down Expand Up @@ -164,7 +165,8 @@ class VariableDeclarationDesugaring extends Desugaring {
*
* @see <a href="http://wiki.ecmascript.org/doku.php?id=harmony:destructuring#assignments">harmony:destructuring</a>
*/
export class DestructuringTransformer extends TempVarTransformer {
export class DestructuringTransformer extends
ImportRuntimeTrait(TempVarTransformer) {
/**
* @param {UniqueIdentifierGenerator} identifierGenerator
*/
Expand Down Expand Up @@ -563,9 +565,10 @@ export class DestructuringTransformer extends TempVarTransformer {
continue;
} else if (lvalue.isSpreadPatternElement()) {
// Rest of the array, for example [x, ...y] = [1, 2, 3]
let iteratorToArray = this.getRuntimeExpression('iteratorToArray');
desugaring.assign(
lvalue.lvalue,
parseExpression `$traceurRuntime.iteratorToArray(${iterId})`);
parseExpression `${iteratorToArray}(${iterId})`);
} else {
if (lvalue.initializer) {
initializerFound = true;
Expand Down
3 changes: 2 additions & 1 deletion src/codegeneration/ForOnTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
FOR_ON_STATEMENT,
LABELLED_STATEMENT
} from '../syntax/trees/ParseTreeType.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {InnerForOnTransformer} from './InnerForOnTransformer.js';

Expand Down Expand Up @@ -60,7 +61,7 @@ import {InnerForOnTransformer} from './InnerForOnTransformer.js';
/**
* Desugars for-on statement.
*/
export class ForOnTransformer extends TempVarTransformer {
export class ForOnTransformer extends ImportRuntimeTrait(TempVarTransformer) {
/**
* @param {ForOnStatement} original
* @return {ParseTree}
Expand Down
30 changes: 20 additions & 10 deletions src/codegeneration/GeneratorTransformPass.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
parseStatement
} from './PlaceholderParser.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {FindInFunctionScope} from './FindInFunctionScope.js';
import {
AnonBlock,
Expand Down Expand Up @@ -48,7 +49,8 @@ function needsTransform(tree, transformOptions) {
* This pass just finds function bodies with yields in them and passes them
* off to the GeneratorTransformer for the heavy lifting.
*/
export class GeneratorTransformPass extends TempVarTransformer {
export class GeneratorTransformPass extends
ImportRuntimeTrait(TempVarTransformer) {
/**
* @param {UniqueIdentifierGenerator} identifierGenerator
* @param {ErrorReporter} reporter
Expand All @@ -75,9 +77,9 @@ export class GeneratorTransformPass extends TempVarTransformer {

transformGeneratorDeclaration_(tree) {
let nameIdExpression = id(tree.name.identifierToken);

let initGeneratorFunction = this.getRuntimeExpression('initGeneratorFunction');
let setupPrototypeExpression = parseExpression
`$traceurRuntime.initGeneratorFunction(${nameIdExpression})`;
`${initGeneratorFunction}(${nameIdExpression})`;

// Function declarations in blocks do not hoist. In that case we add the
// variable declaration after the function declaration.
Expand Down Expand Up @@ -124,8 +126,9 @@ export class GeneratorTransformPass extends TempVarTransformer {

let functionExpression =
this.transformFunction_(tree, FunctionExpression, id(name));
return parseExpression
`$traceurRuntime.initGeneratorFunction(${functionExpression })`;
let initGeneratorFunction =
this.getRuntimeExpression('initGeneratorFunction');
return parseExpression `${initGeneratorFunction}(${functionExpression })`;
}

transformFunction_(tree, constructor, nameExpression) {
Expand All @@ -141,13 +144,20 @@ export class GeneratorTransformPass extends TempVarTransformer {
}

if (this.tranformOptions_.generators && tree.isGenerator()) {
body = GeneratorTransformer.transformGeneratorBody(
this.identifierGenerator, this.reporter, this.options, body,
nameExpression);
let transformer = new GeneratorTransformer(this.identifierGenerator,
this.reporter, this.options);
body = transformer.transformGeneratorBody(body, nameExpression);
transformer.requiredNames.forEach((n) => {
this.addImportedName(n);
});

} else if (this.tranformOptions_.asyncFunctions && tree.isAsyncFunction()) {
body = AsyncTransformer.transformAsyncBody(
this.identifierGenerator, this.reporter, this.options, body);
let transformer = new AsyncTransformer(this.identifierGenerator,
this.reporter, this.options);
body = transformer.transformAsyncBody(body, nameExpression);
transformer.requiredNames.forEach((n) => {
this.addImportedName(n);
});
}

// The generator has been transformed away.
Expand Down
Loading

0 comments on commit 0520814

Please sign in to comment.