diff --git a/Makefile b/Makefile
index bec0b24da..6d8b3d514 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/src/Options.js b/src/Options.js
index 4c3746567..2cf038742 100644
--- a/src/Options.js
+++ b/src/Options.js
@@ -43,6 +43,7 @@ export const optionsV01 = enumerableOnlyObject({
freeVariableChecker: false,
generatorComprehension: false,
generators: true,
+ importRuntime: false,
inputSourceMap: false,
jsx: false,
lowResolutionSourceMap: false,
@@ -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);
diff --git a/src/codegeneration/AsyncGeneratorTransformPass.js b/src/codegeneration/AsyncGeneratorTransformPass.js
index 4b9129787..854e97f2b 100644
--- a/src/codegeneration/AsyncGeneratorTransformPass.js
+++ b/src/codegeneration/AsyncGeneratorTransformPass.js
@@ -19,6 +19,7 @@ import {
FunctionDeclaration,
FunctionExpression
} from '../syntax/trees/ParseTrees.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
createBindingIdentifier,
createIdentifierExpression as id,
@@ -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
@@ -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.
@@ -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) {
diff --git a/src/codegeneration/AsyncGeneratorTransformer.js b/src/codegeneration/AsyncGeneratorTransformer.js
index 3f5127e21..9ea7dfa9d 100644
--- a/src/codegeneration/AsyncGeneratorTransformer.js
+++ b/src/codegeneration/AsyncGeneratorTransformer.js
@@ -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,
@@ -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_ = [];
@@ -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});`);
diff --git a/src/codegeneration/AsyncToGeneratorTransformer.js b/src/codegeneration/AsyncToGeneratorTransformer.js
index b268e3730..d737c667b 100644
--- a/src/codegeneration/AsyncToGeneratorTransformer.js
+++ b/src/codegeneration/AsyncToGeneratorTransformer.js
@@ -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';
@@ -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;
@@ -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;
}
@@ -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])
}
diff --git a/src/codegeneration/ClassTransformer.js b/src/codegeneration/ClassTransformer.js
index 9325d5a21..3308d211f 100644
--- a/src/codegeneration/ClassTransformer.js
+++ b/src/codegeneration/ClassTransformer.js
@@ -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,
@@ -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) {
@@ -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;
@@ -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
@@ -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;
@@ -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);
@@ -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() {}`;
diff --git a/src/codegeneration/DestructuringTransformer.js b/src/codegeneration/DestructuringTransformer.js
index 4ec9d37bf..2fb508a2c 100644
--- a/src/codegeneration/DestructuringTransformer.js
+++ b/src/codegeneration/DestructuringTransformer.js
@@ -44,6 +44,7 @@ import {
VariableDeclarationList,
VariableStatement,
} from '../syntax/trees/ParseTrees.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {
EQUAL,
@@ -164,7 +165,8 @@ class VariableDeclarationDesugaring extends Desugaring {
*
* @see harmony:destructuring
*/
-export class DestructuringTransformer extends TempVarTransformer {
+export class DestructuringTransformer extends
+ ImportRuntimeTrait(TempVarTransformer) {
/**
* @param {UniqueIdentifierGenerator} identifierGenerator
*/
@@ -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;
diff --git a/src/codegeneration/ForOnTransformer.js b/src/codegeneration/ForOnTransformer.js
index e25cb5c68..354e70156 100644
--- a/src/codegeneration/ForOnTransformer.js
+++ b/src/codegeneration/ForOnTransformer.js
@@ -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';
@@ -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}
diff --git a/src/codegeneration/GeneratorTransformPass.js b/src/codegeneration/GeneratorTransformPass.js
index 4a21030e1..83e2d6917 100644
--- a/src/codegeneration/GeneratorTransformPass.js
+++ b/src/codegeneration/GeneratorTransformPass.js
@@ -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,
@@ -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
@@ -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.
@@ -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) {
@@ -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.
diff --git a/src/codegeneration/ImportRuntimeTrait.js b/src/codegeneration/ImportRuntimeTrait.js
new file mode 100644
index 000000000..0bc17841f
--- /dev/null
+++ b/src/codegeneration/ImportRuntimeTrait.js
@@ -0,0 +1,134 @@
+// Copyright 2015 Traceur Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {CONST, VAR} from '../syntax/TokenType.js';
+import {
+ ImportDeclaration,
+ ImportedBinding,
+ ImportSpecifier,
+ ImportSpecifierSet,
+ Module,
+ ModuleSpecifier,
+ Script,
+} from '../syntax/trees/ParseTrees.js';
+import {StringSet} from '../util/StringSet.js';
+import {
+ createBindingIdentifier,
+ createIdentifierToken,
+ createIdentifierExpression,
+ createMemberExpression,
+ createStringLiteral,
+ createStringLiteralToken,
+ createVariableStatement,
+} from './ParseTreeFactory.js';
+import {parseExpression} from './PlaceholderParser.js';
+import {prependStatements} from './PrependStatements.js';
+
+function toTempName(name) {
+ return `$__${name}`;
+}
+
+function getDeclarationType(options) {
+ return options.parseOptions.blockBinding &&
+ !options.transformOptions.blockBinding ? CONST : VAR;
+}
+
+export default function ImportRuntimeTrait(ParseTreeTransformerClass) {
+ return class extends ParseTreeTransformerClass {
+ constructor(...args) {
+ super(...args);
+ this.importedNames = new StringSet();
+ this._existingImports = new StringSet();
+ }
+
+ getRuntimeExpression(name) {
+ if (this.options.importRuntime) {
+ this.addImportedName(name);
+ return createIdentifierExpression(toTempName(name));
+ }
+ return createMemberExpression('$traceurRuntime', name);
+ }
+
+ get requiredNames() {
+ return this.importedNames;
+ }
+
+ addImportedName(name) {
+ this.importedNames.add(name);
+ }
+
+ transformScript(tree) {
+ let transformed = super.transformScript(tree);
+ if (tree === transformed) {
+ return tree;
+ }
+
+ if (!this.options.importRuntime) {
+ return transformed;
+ }
+
+ let scriptItemList = this.addRuntimeImports(transformed.scriptItemList);
+ return new Script(tree.location, scriptItemList, tree.moduleName);
+ }
+
+ transformModule(tree) {
+ let transformed = super.transformModule(tree);
+ if (tree === transformed) {
+ return tree;
+ }
+
+ if (!this.options.importRuntime) {
+ return transformed;
+ }
+
+ let scriptItemList = this.addRuntimeImports(transformed.scriptItemList);
+ return new Module(tree.location, scriptItemList, tree.moduleName);
+ }
+
+ transformImportedBinding(tree) {
+ // Add seen imports so that we do not add them twice.
+ this._existingImports.add(tree.binding.getStringValue());
+ return super.transformImportedBinding(tree);
+ }
+
+ _getModuleSpecifier(name) {
+ let base = 'traceur/dist/commonjs';
+ if (this.options.modules === 'parse') {
+ base = 'traceur/src';
+ }
+ const moduleId = createStringLiteralToken(
+ `${base}/runtime/modules/${name}.js`);
+ return new ModuleSpecifier(null, moduleId);
+ }
+
+ getRuntimeImports() {
+ return this.importedNames.valuesAsArray().filter(
+ name => !this._existingImports.has(toTempName(name))).map(name => {
+ // import {default as $__name} from '.../name.js'
+ const def = createIdentifierToken('default');
+ const binding = new ImportedBinding(null,
+ createBindingIdentifier(toTempName(name)));
+ const specifier = new ImportSpecifier(null, binding, def);
+ return new ImportDeclaration(null,
+ new ImportSpecifierSet(null, [specifier]),
+ this._getModuleSpecifier(name));
+ });
+ }
+
+ addRuntimeImports(scriptItemList) {
+ let runtimeImports = this.getRuntimeImports();
+ return prependStatements(scriptItemList, ...runtimeImports);
+ }
+ }
+}
diff --git a/src/codegeneration/InnerForOnTransformer.js b/src/codegeneration/InnerForOnTransformer.js
index d22af5ff6..14835a5d2 100644
--- a/src/codegeneration/InnerForOnTransformer.js
+++ b/src/codegeneration/InnerForOnTransformer.js
@@ -53,7 +53,7 @@ export class InnerForOnTransformer extends
// FnExtractAbruptCompletions. The common code should really be refactored
// into an abstract base class.
- constructor(tempIdGenerator, labelSet) {
+ constructor(tempIdGenerator, labelSet, options) {
super();
this.idGenerator_ = tempIdGenerator;
this.inLoop_ = 0;
@@ -68,6 +68,7 @@ export class InnerForOnTransformer extends
this.labelSet_.forEach((tree) => {
this.parentLabels_.add(tree.name.value);
});
+ this.options = options;
}
transform(tree) {
@@ -107,11 +108,12 @@ export class InnerForOnTransformer extends
return ${this.result_}.v;`));
let switchStatement = createSwitchStatement(this.result_, caseClauses);
+ let observeForEach = this.idGenerator_.getRuntimeExpression('observeForEach');
let statement = parseStatement `
do {
${createVariableStatement(
createVariableDeclarationList(VAR, this.variableDeclarations_))}
- await $traceurRuntime.observeForEach(
+ await ${observeForEach}(
${tree.observable}[Symbol.observer].bind(${tree.observable}),
async function (${value}) {
var ${this.observer_} = this;
diff --git a/src/codegeneration/JsxTransformer.js b/src/codegeneration/JsxTransformer.js
index 776bcf02e..f32e75730 100644
--- a/src/codegeneration/JsxTransformer.js
+++ b/src/codegeneration/JsxTransformer.js
@@ -42,6 +42,7 @@ import {
} from './ParseTreeFactory.js';
import {parseExpression} from './PlaceholderParser.js';
import {spreadProperties} from './SpreadPropertiesTransformer.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
/**
* Desugars JSX expressions.
@@ -63,10 +64,10 @@ import {spreadProperties} from './SpreadPropertiesTransformer.js';
*
* myFunc('p', null)
*/
-export class JsxTransformer extends ParseTreeTransformer {
+export class JsxTransformer extends ImportRuntimeTrait(ParseTreeTransformer) {
constructor(idGen, reporter, options) {
super();
- this.options_ = options;
+ this.options = options;
this.jsxFunction_ = null;
}
@@ -75,7 +76,7 @@ export class JsxTransformer extends ParseTreeTransformer {
// --jsx -> React.createElement(tagName, opts, ...children)
// --jsx=a.b.c -> a.b.c(tagName, opts, ...children)
if (!this.jsxFunction_) {
- let jsx = this.options_.jsx;
+ let jsx = this.options.jsx;
if (typeof jsx === 'string') {
this.jsxFunction_ = parseExpression([jsx]);
} else {
@@ -99,19 +100,15 @@ export class JsxTransformer extends ParseTreeTransformer {
return createNullLiteral();
}
if (tree.attributes.some(a => a.type === JSX_SPREAD_ATTRIBUTE)) {
- return this.createSpreadAttributeExpression_(attrs);
+ //
+ // =>
+ // React.createElement('a',
+ // $traceurRuntime.spreadProperties({b: 'b', c: 'c'}, d, g))
+ return spreadProperties(attrs, this);
}
return createObjectLiteral(attrs);
}
- createSpreadAttributeExpression_(attrs) {
- //
- // =>
- // React.createElement('a',
- // $traceurRuntime.spreadProperties({b: 'b', c: 'c'}, d, g))
- return spreadProperties(attrs);
- }
-
transformJsxElementName(tree) {
if (tree.names.length === 1) {
let {value} = tree.names[0];
diff --git a/src/codegeneration/ModuleTransformer.js b/src/codegeneration/ModuleTransformer.js
index 58d2f2d9b..a4723c795 100644
--- a/src/codegeneration/ModuleTransformer.js
+++ b/src/codegeneration/ModuleTransformer.js
@@ -24,6 +24,7 @@ import {
} from '../syntax/trees/ParseTrees.js';
import {DestructuringTransformer} from './DestructuringTransformer.js';
import {DirectExportVisitor} from './module/DirectExportVisitor.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {ImportSimplifyingTransformer} from './ImportSimplifyingTransformer.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {
@@ -59,6 +60,7 @@ import {
parseStatement,
parseStatements
} from './PlaceholderParser.js';
+import {prependStatements} from './PrependStatements.js';
function removeUseStrictDirectives(tree) {
let result = tree.scriptItemList.filter(tree => !tree.isUseStrictDirective());
@@ -71,7 +73,7 @@ class DestructImportVarStatement extends DestructuringTransformer {
}
}
-export class ModuleTransformer extends TempVarTransformer {
+export class ModuleTransformer extends ImportRuntimeTrait(TempVarTransformer) {
/**
* @param {UniqueIdentifierGenerator} identifierGenerator
*/
@@ -116,8 +118,9 @@ export class ModuleTransformer extends TempVarTransformer {
this.pushTempScope();
let statements = this.transformList(tree.scriptItemList);
-
statements = this.appendExportStatement(statements);
+ const runtimeImports = this.transformList(this.getRuntimeImports());
+ statements = prependStatements(statements, ...runtimeImports);
this.popTempScope();
@@ -224,7 +227,8 @@ export class ModuleTransformer extends TempVarTransformer {
this.getTempVarNameForModuleSpecifier(moduleSpecifier));
});
let args = createArgumentList([exportObject, ...starIdents]);
- return parseExpression `$traceurRuntime.exportStar(${args})`;
+ const runtime = this.getRuntimeExpression('exportStar');
+ return parseExpression `${runtime}(${args})`;
}
return exportObject;
}
diff --git a/src/codegeneration/ProperTailCallTransformer.js b/src/codegeneration/ProperTailCallTransformer.js
index f2524bf1f..44f0fb5cf 100644
--- a/src/codegeneration/ProperTailCallTransformer.js
+++ b/src/codegeneration/ProperTailCallTransformer.js
@@ -29,6 +29,7 @@ import {
FunctionDeclaration,
FunctionExpression,
} from '../syntax/trees/ParseTrees.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
//
// Example:
@@ -49,13 +50,15 @@ import {
// }, this, arguments);
// })
-export class ProperTailCallTransformer extends TempVarTransformer {
+export class ProperTailCallTransformer extends
+ ImportRuntimeTrait(TempVarTransformer) {
// TODO(mnieper): This transformer currently expects that classes and template
// literals have already been desugared. Otherwise they are not guaranteed
// to have proper tail calls.
constructor(identifierGenerator, reporter, options) {
super(identifierGenerator, reporter, options);
this.inBlock_ = false;
+ this.options = options;
}
transformFunctionDeclaration(tree) {
@@ -67,8 +70,11 @@ export class ProperTailCallTransformer extends TempVarTransformer {
let nameIdExpression = id(tree.name.identifierToken);
+ const initTailRecursiveFunction =
+ this.getRuntimeExpression('initTailRecursiveFunction');
+
let setupFlagExpression = parseExpression
- `$traceurRuntime.initTailRecursiveFunction(${nameIdExpression})`;
+ `${initTailRecursiveFunction}(${nameIdExpression})`;
let funcDecl = this.transformFunction_(tree, FunctionDeclaration);
if (funcDecl === tree) {
@@ -105,8 +111,10 @@ export class ProperTailCallTransformer extends TempVarTransformer {
return tree;
}
- return parseExpression `
- $traceurRuntime.initTailRecursiveFunction(${functionExpression})`;
+ const initTailRecursiveFunction =
+ this.getRuntimeExpression('initTailRecursiveFunction');
+ return parseExpression `${
+ initTailRecursiveFunction}(${functionExpression})`;
}
transformFunction_(tree, constructor) {
@@ -116,8 +124,9 @@ export class ProperTailCallTransformer extends TempVarTransformer {
}
let func = id(this.getTempIdentifier());
let innerFunction = createFunctionExpression(tree.parameterList, body);
+ const call = this.getRuntimeExpression('call');
let outerBody = createFunctionBody(parseStatements `
- return $traceurRuntime.call(${innerFunction}, this, arguments);`);
+ return ${call}(${innerFunction}, this, arguments);`);
return new constructor(tree.location, tree.name, tree.functionKind,
tree.parameterList, tree.typeAnnotation, tree.annotations, outerBody);
}
diff --git a/src/codegeneration/RewriteTailExpressionsTransformer.js b/src/codegeneration/RewriteTailExpressionsTransformer.js
index a159cd114..fc7fb7ea5 100644
--- a/src/codegeneration/RewriteTailExpressionsTransformer.js
+++ b/src/codegeneration/RewriteTailExpressionsTransformer.js
@@ -43,7 +43,7 @@ import {
OR
} from '../syntax/TokenType.js';
-function createCall(tree, operand, thisArg) {
+function createCall(tree, operand, thisArg, importRuntimeTransformer) {
let argList = tree.args; // can be null
let argArray = argList ? argList.args : [];
argArray = argArray.map(arg => {
@@ -52,8 +52,10 @@ function createCall(tree, operand, thisArg) {
}
return arg;
});
+ const continuation =
+ importRuntimeTransformer.getRuntimeExpression('continuation');
return new CallExpression(tree.location,
- createMemberExpression('$traceurRuntime', 'continuation'),
+ continuation,
new ArgumentList(argList ? argList.location : null, [operand, thisArg,
createArrayLiteral(argArray)]));
}
@@ -86,7 +88,8 @@ export class RewriteTailExpressionsTransformer extends ParseTreeTransformer {
}
switch (operand.type) {
case IDENTIFIER_EXPRESSION:
- return createCall(tree, operand, createNullLiteral());
+ return createCall(tree, operand, createNullLiteral(),
+ this.bodyTransformer_);
case MEMBER_EXPRESSION:
case MEMBER_LOOKUP_EXPRESSION:
return this.transformMemberExpressionCall_(tree, operand)
@@ -115,9 +118,9 @@ export class RewriteTailExpressionsTransformer extends ParseTreeTransformer {
}
if (assignment) {
return createParenExpression(createCommaExpression([assignment,
- createCall(tree, operand, thisArg)]));
+ createCall(tree, operand, thisArg, this.bodyTransformer_)]));
} else {
- return createCall(tree, operand, thisArg);
+ return createCall(tree, operand, thisArg, this.bodyTransformer_);
}
}
@@ -144,8 +147,8 @@ export class RewriteTailExpressionsTransformer extends ParseTreeTransformer {
}
transformNewExpression(tree) {
- return createCall(tree, createMemberExpression('$traceurRuntime', 'construct'),
- tree.operand);
+ const construct = this.bodyTransformer_.getRuntimeExpression('construct');
+ return createCall(tree, construct, tree.operand, this.bodyTransformer_);
}
transformArrayLiteral(tree) {return tree;}
diff --git a/src/codegeneration/SpreadPropertiesTransformer.js b/src/codegeneration/SpreadPropertiesTransformer.js
index 02a599f8f..d6acbb7f5 100644
--- a/src/codegeneration/SpreadPropertiesTransformer.js
+++ b/src/codegeneration/SpreadPropertiesTransformer.js
@@ -15,6 +15,7 @@
import {SPREAD_EXPRESSION} from '../syntax/trees/ParseTreeType.js';
import {createObjectLiteral, createArgumentList} from './ParseTreeFactory.js';
import {parseExpression} from './PlaceholderParser.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {ParseTreeTransformer} from './ParseTreeTransformer.js';
function hasSpread(trees) {
@@ -30,18 +31,24 @@ function hasSpread(trees) {
* =>
* $spreadProperties({a}, b, {c}, d)
*/
-export class SpreadPropertiesTransformer extends ParseTreeTransformer {
+export class SpreadPropertiesTransformer extends
+ ImportRuntimeTrait(ParseTreeTransformer) {
+ constructor(identifierGenerator, reporter, options) {
+ super(identifierGenerator, reporter, options);
+ this.options = options;
+ }
+
transformObjectLiteral(tree) {
if (!hasSpread(tree.propertyNameAndValues)) {
return super.transformObjectLiteral(tree);
}
const properties = this.transformList(tree.propertyNameAndValues);
- return spreadProperties(properties);
+ return spreadProperties(properties, this);
}
}
-export function spreadProperties(properties) {
+export function spreadProperties(properties, self) {
// Accummulate consecutive properties into a single js property.
let args = [];
let accummulatedProps = null;
@@ -63,6 +70,6 @@ export function spreadProperties(properties) {
if (accummulatedProps) {
args.push(createObjectLiteral(accummulatedProps));
}
- return parseExpression `$traceurRuntime.spreadProperties(${
- createArgumentList(args)})`;
+ const runtime = self.getRuntimeExpression('spreadProperties');
+ return parseExpression `${runtime}(${createArgumentList(args)})`;
}
diff --git a/src/codegeneration/SpreadTransformer.js b/src/codegeneration/SpreadTransformer.js
index 6b5d3cb2e..3f07abbde 100644
--- a/src/codegeneration/SpreadTransformer.js
+++ b/src/codegeneration/SpreadTransformer.js
@@ -23,7 +23,9 @@ import {
MEMBER_LOOKUP_EXPRESSION,
SPREAD_EXPRESSION
} from '../syntax/trees/ParseTreeType.js';
+import {Script} from '../syntax/trees/ParseTrees.js';
import {TempVarTransformer} from './TempVarTransformer.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
createArgumentList,
createArrayLiteral,
@@ -39,8 +41,10 @@ import {
createVoid0
} from './ParseTreeFactory.js';
import {
- parseExpression
+ parseExpression,
+ parseStatement,
} from './PlaceholderParser.js';
+import {prependStatements} from './PrependStatements.js';
function hasSpreadMember(trees) {
return trees.some((tree) => tree && tree.type === SPREAD_EXPRESSION);
@@ -52,7 +56,7 @@ function hasSpreadMember(trees) {
*
* @see harmony:spread
*/
-export class SpreadTransformer extends TempVarTransformer {
+export class SpreadTransformer extends ImportRuntimeTrait(TempVarTransformer) {
/**
* Creates an expression that results in an array where all the elements are
* spread.
@@ -91,8 +95,8 @@ export class SpreadTransformer extends TempVarTransformer {
if (lastArray)
args.push(createArrayLiteral(lastArray));
- return parseExpression
- `$traceurRuntime.spread(${createArgumentList(args)})`;
+ const spread = this.getRuntimeExpression('spread');
+ return parseExpression `${spread}(${createArgumentList(args)})`;
}
desugarCallSpread_(tree) {
diff --git a/src/codegeneration/SuperTransformer.js b/src/codegeneration/SuperTransformer.js
index 51a1269e9..04fb8cd18 100644
--- a/src/codegeneration/SuperTransformer.js
+++ b/src/codegeneration/SuperTransformer.js
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {TempVarTransformer} from './TempVarTransformer.js';
import {
ArgumentList,
@@ -138,7 +139,7 @@ class PrototypeState extends State {
* }
* }
*/
-export class SuperTransformer extends TempVarTransformer {
+export class SuperTransformer extends ImportRuntimeTrait(TempVarTransformer) {
constructor(identifierGenerator, reporter, options) {
super(identifierGenerator, reporter, options);
// Pushing onto this stack is done in pairs. For classes we push one state
@@ -308,7 +309,8 @@ export class SuperTransformer extends TempVarTransformer {
transformMemberShared_(name) {
let {home} = this.peekState();
- return parseExpression `$traceurRuntime.superGet(this, ${home}, ${name})`;
+ let superGet = this.getRuntimeExpression('superGet');
+ return parseExpression `${superGet}(this, ${home}, ${name})`;
}
/**
@@ -337,7 +339,8 @@ export class SuperTransformer extends TempVarTransformer {
createThisExpression(), ...args.args
]);
let {home} = this.stateStack_[this.stateStack_.length - 2];
- operand = parseExpression `$traceurRuntime.superConstructor(${home})`;
+ let superConstructor = this.getRuntimeExpression('superConstructor');
+ operand = parseExpression `${superConstructor}(${home})`;
} else if (hasSuperMemberExpression(tree.operand)) {
// super.x(args)
operand = this.transformAny(tree.operand);
@@ -367,8 +370,9 @@ export class SuperTransformer extends TempVarTransformer {
let right = this.transformAny(tree.right);
let {home} = this.peekState();
+ let superSet = this.getRuntimeExpression('superSet');
return parseExpression
- `$traceurRuntime.superSet(this, ${home}, ${name}, ${right})`;
+ `${superSet}(this, ${home}, ${name}, ${right})`;
}
return super.transformBinaryExpression(tree);
diff --git a/src/codegeneration/SymbolTransformer.js b/src/codegeneration/SymbolTransformer.js
index f9e3971f3..4a5fdd2ff 100644
--- a/src/codegeneration/SymbolTransformer.js
+++ b/src/codegeneration/SymbolTransformer.js
@@ -22,6 +22,7 @@ import {
UNARY_EXPRESSION,
} from '../syntax/trees/ParseTreeType.js';
import {ParseTreeTransformer} from './ParseTreeTransformer.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
EQUAL_EQUAL,
EQUAL_EQUAL_EQUAL,
@@ -63,7 +64,20 @@ function isSafeTypeofString(tree) {
* This transformer transforms typeof expressions to return 'symbol' when
* symbols have been shimmed.
*/
-export class SymbolTransformer extends ParseTreeTransformer {
+export class SymbolTransformer extends
+ ImportRuntimeTrait(ParseTreeTransformer) {
+ /**
+ * @param {UniqueIdentifierGenerator} identifierGenerator
+ * @param {ErrorReporter} reporter
+ * @param {Options} options
+ */
+ constructor(identifierGenerator, reporter, options) {
+ super();
+ this.identifierGenerator = identifierGenerator;
+ this.reporter = reporter;
+ this.options = options;
+ }
+
/**
* Helper for the case where we only want to transform the operand of
* the typeof expression.
@@ -114,6 +128,7 @@ export class SymbolTransformer extends ParseTreeTransformer {
}
getRuntimeTypeof(operand) {
- return parseExpression `$traceurRuntime.typeof(${operand})`;
+ let typeOf = this.getRuntimeExpression('typeof');
+ return parseExpression `${typeOf}(${operand})`;
}
}
diff --git a/src/codegeneration/TemplateLiteralTransformer.js b/src/codegeneration/TemplateLiteralTransformer.js
index ecdac1218..52c9568d8 100644
--- a/src/codegeneration/TemplateLiteralTransformer.js
+++ b/src/codegeneration/TemplateLiteralTransformer.js
@@ -26,6 +26,7 @@ import {
import {LiteralToken} from '../syntax/LiteralToken.js';
import {ParenTrait} from './ParenTrait.js';
import {ParseTreeTransformer} from './ParseTreeTransformer.js';
+import ImportRuntimeTrait from './ImportRuntimeTrait.js';
import {
PERCENT,
PLUS,
@@ -63,7 +64,7 @@ function createStringLiteralExpression(loc, str) {
* @param {Array} elements
* @return {ParseTree}
*/
-function createGetTemplateObject(elements) {
+function createGetTemplateObject(elements, getTemplateObject) {
let cooked = [];
let raw = [];
let same = true;
@@ -93,7 +94,7 @@ function createGetTemplateObject(elements) {
}
return createCallExpression(
- createMemberExpression('$traceurRuntime', 'getTemplateObject'),
+ getTemplateObject,
createArgumentList(args));
}
@@ -203,7 +204,13 @@ function toCookedString(s) {
}
export class TemplateLiteralTransformer extends
- ParenTrait(ParseTreeTransformer) {
+ ImportRuntimeTrait(ParenTrait(ParseTreeTransformer)) {
+
+ constructor(identifierGenerator, reporter, options) {
+ super();
+ this.options = options;
+ }
+
transformTemplateLiteralExpression(tree) {
if (!tree.operand) {
return this.createDefaultTemplateLiteral(tree);
@@ -211,8 +218,8 @@ export class TemplateLiteralTransformer extends
let operand = this.transformAny(tree.operand);
let elements = tree.elements;
-
- let args = [createGetTemplateObject(tree.elements)];
+ let getTemplateObject = this.getRuntimeExpression('getTemplateObject');
+ let args = [createGetTemplateObject(tree.elements, getTemplateObject)];
for (let i = 1; i < elements.length; i += 2) {
args.push(this.transformAny(elements[i]));
}
diff --git a/src/codegeneration/generator/AsyncTransformer.js b/src/codegeneration/generator/AsyncTransformer.js
index 2cffab1c7..ee26b9055 100644
--- a/src/codegeneration/generator/AsyncTransformer.js
+++ b/src/codegeneration/generator/AsyncTransformer.js
@@ -20,6 +20,7 @@ import {
import {CPSTransformer} from './CPSTransformer.js';
import {EndState} from './EndState.js';
import {FallThroughState} from './FallThroughState.js';
+import ImportRuntimeTrait from '../ImportRuntimeTrait.js';
import {
AWAIT_EXPRESSION,
BINARY_EXPRESSION,
@@ -67,7 +68,7 @@ function scopeContainsAwait(tree) {
* return $traceurRuntime.asyncWrap(machineFunction);
* }
*/
-export class AsyncTransformer extends CPSTransformer {
+export class AsyncTransformer extends ImportRuntimeTrait(CPSTransformer) {
expressionNeedsStateMachine(tree) {
if (tree === null)
@@ -213,8 +214,8 @@ export class AsyncTransformer extends CPSTransformer {
* @return {FunctionBody}
*/
transformAsyncBody(tree) {
- let runtimeFunction = parseExpression `$traceurRuntime.asyncWrap`;
- return this.transformCpsFunctionBody(tree, runtimeFunction);
+ let asyncWrap = this.getRuntimeExpression('asyncWrap');
+ return this.transformCpsFunctionBody(tree, asyncWrap);
}
/**
diff --git a/src/codegeneration/generator/GeneratorTransformer.js b/src/codegeneration/generator/GeneratorTransformer.js
index 1e3b4b777..905559d7b 100644
--- a/src/codegeneration/generator/GeneratorTransformer.js
+++ b/src/codegeneration/generator/GeneratorTransformer.js
@@ -23,6 +23,7 @@ import {
} from '../../syntax/trees/ParseTrees.js'
import {FindInFunctionScope} from '../FindInFunctionScope.js'
import {ReturnState} from './ReturnState.js';
+import ImportRuntimeTrait from '../ImportRuntimeTrait.js';
import {YieldState} from './YieldState.js';
import {
createIdentifierExpression as id,
@@ -69,7 +70,7 @@ function scopeContainsYield(tree) {
* return $traceurRuntime.createGeneratorInstance(machineFunction);
* }
*/
-export class GeneratorTransformer extends CPSTransformer {
+export class GeneratorTransformer extends ImportRuntimeTrait(CPSTransformer) {
constructor(identifierGenerator, reporter, options) {
super(identifierGenerator, reporter, options);
@@ -295,9 +296,9 @@ export class GeneratorTransformer extends CPSTransformer {
* @return {FunctionBody}
*/
transformGeneratorBody(tree, name) {
- let runtimeFunction =
- parseExpression `$traceurRuntime.createGeneratorInstance`;
- return this.transformCpsFunctionBody(tree, runtimeFunction, name);
+ let createGeneratorInstance =
+ this.getRuntimeExpression('createGeneratorInstance');
+ return this.transformCpsFunctionBody(tree, createGeneratorInstance, name);
}
/**