cleanup(build): remove traceur-based Dart transpiler

This commit is contained in:
Alex Eagle 2015-04-28 11:14:18 -07:00
parent 3d62546314
commit 4c1e978536
20 changed files with 2 additions and 1710 deletions

View File

@ -1,55 +0,0 @@
import {describe, it, expect} from 'angular2/test_lib';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {IterableList} from './fixtures/facade';
export function main() {
// TODO(tbosch): For ... of is not supported by our Dart transpiler right now.
// Vojta had a traceur branch that reverted https://github.com/google/traceur-compiler/commit/2d12b2f9cea86e4f234c90dcc188b4c7a2881359
// to make it work, but we should first implement this in a proper way before we start using it!
// describe('for..of', function() {
// it('should iterate iterable', function() {
// var values = ['a', 'b', 'c'];
// var result = ListWrapper.create();
// for (var value of new IterableList(values)) {
// ListWrapper.push(result, value);
// }
// expect(result).toEqual(values);
// });
// it('should iterate iterable without var declaration list', function() {
// var values = ['a', 'b', 'c'];
// var result = ListWrapper.create();
// var value;
// for (value of new IterableList(values)) {
// ListWrapper.push(result, value);
// }
// expect(value).toEqual('c');
// expect(result).toEqual(values);
// });
// it('should iterate maps', function() {
// var values = [['a', 1], ['b', 2], ['c', 3]];
// var result = ListWrapper.create();
// var map = MapWrapper.createFromPairs(values);
// for (var [key, value] of MapWrapper.iterable(map)) {
// ListWrapper.push(result, [key, value]);
// }
// expect(result).toEqual(values);
// });
// it('should iterate maps without var declaration list', function() {
// var values = [['a', 1], ['b', 2], ['c', 3]];
// var result = ListWrapper.create();
// var map = MapWrapper.createFromPairs(values);
// var key, value;
// for ([key, value] of MapWrapper.iterable(map)) {
// ListWrapper.push(result, [key, value]);
// }
// expect(key).toEqual('c');
// expect(value).toEqual(3);
// expect(result).toEqual(values);
// });
// });
}

View File

@ -1,46 +0,0 @@
import {describe, it, expect, IS_DARTIUM} from 'angular2/test_lib';
import {Foo, Bar} from './foo';
// TODO: Does not work, as dart does not support renaming imports
// import {Foo as F} from './fixtures/foo';
import * as fooModule from './foo';
import * as exportModule from './export';
import {Type} from 'angular2/src/facade/lang';
import {Baz} from './reexport';
export function main() {
describe('imports', function() {
it('should re-export imported vars', function() {
expect(Baz).toBe('BAZ');
});
it('should work', function() {
expect(Foo).toBe('FOO');
expect(Bar).toBe('BAR');
// TODO: Does not work
// assert(F == 'FOO');
expect(fooModule.Foo).toBe('FOO');
expect(fooModule.Bar).toBe('BAR');
expect(exportModule.Foo).toBe('FOO');
expect(exportModule.Bar).toBe('BAR');
expect(exportModule.Bar1).toBe('BAR1');
expect(exportModule.Bar2).toBe('BAR2');
// Make sure Bar3 is not re-exported.
expect(function() {
exportModule.Bar3();
}).toThrowError(IS_DARTIUM ?
// Dart
"No top-level method 'exportModule.Bar3' declared.":
// JavaScript
new RegExp('.*is not a function')
);
expect(Type).toBeTruthy();
});
});
}

View File

@ -71,10 +71,7 @@ export function main() {
expect(function() { expect(function() {
wf.name = true; wf.name = true;
}).toThrowError(IS_DARTIUM ? }).toThrowError(
// Dart
"type 'bool' is not a subtype of type 'String' of 'value'" :
// JavaScript
// TODO(vojta): Better error, it's not first argument, it's setting a field. // TODO(vojta): Better error, it's not first argument, it's setting a field.
'Invalid arguments given!\n' + 'Invalid arguments given!\n' +
' - 1st argument has to be an instance of string, got true' ' - 1st argument has to be an instance of string, got true'
@ -86,10 +83,7 @@ export function main() {
it('should fail when setting wrong type value', function() { it('should fail when setting wrong type value', function() {
expect(function() { expect(function() {
WithFields.id = true; WithFields.id = true;
}).toThrowError(IS_DARTIUM ? }).toThrowError(
// Dart
"type 'bool' is not a subtype of type 'num' of 'id'" :
// JavaScript
// TODO(vojta): Better error, it's not first argument, it's setting a field. // TODO(vojta): Better error, it's not first argument, it's setting a field.
'Invalid arguments given!\n' + 'Invalid arguments given!\n' +
' - 1st argument has to be an instance of number, got true' ' - 1st argument has to be an instance of number, got true'

View File

@ -1,26 +0,0 @@
import {FunctionExpression} from 'traceur/src/syntax/trees/ParseTrees';
import {ParseTreeTransformer} from 'traceur/src/codegeneration/ParseTreeTransformer';
import {FUNCTION_BODY} from 'traceur/src/syntax/trees/ParseTreeType';
import alphaRenameThisAndArguments from 'traceur/src/codegeneration/alphaRenameThisAndArguments';
import {
createFunctionBody,
createReturnStatement
} from 'traceur/src/codegeneration/ParseTreeFactory';
/**
* Transforms an arrow function expression into a function declaration by adding a function
* body and return statement if needed.
*/
export class ArrowFunctionTransformer extends ParseTreeTransformer {
transformArrowFunctionExpression(tree) {
var body = this.transformAny(tree.body);
var parameterList = this.transformAny(tree.parameterList);
if (body.type !== FUNCTION_BODY) {
body = createFunctionBody([createReturnStatement(body)]);
}
return new FunctionExpression(tree.location, null, tree.functionKind, parameterList, null, [],
body);
}
}

View File

@ -1,245 +0,0 @@
import {ParseTreeTransformer} from './ParseTreeTransformer';
import {
BINARY_EXPRESSION,
CALL_EXPRESSION,
IDENTIFIER_EXPRESSION,
MEMBER_EXPRESSION,
PROPERTY_METHOD_ASSIGNMENT,
SUPER_EXPRESSION,
THIS_EXPRESSION
} from 'traceur/src/syntax/trees/ParseTreeType';
import {EQUAL} from 'traceur/src/syntax/TokenType';
import {CONSTRUCTOR} from 'traceur/src/syntax/PredefinedName';
import {propName} from 'traceur/src/staticsemantics/PropName';
import {
BinaryExpression,
BindingIdentifier,
FormalParameterList,
FunctionBody,
IdentifierExpression
} from 'traceur/src/syntax/trees/ParseTrees';
import {
PropertyConstructorAssignment,
ImplementsDeclaration
} from '../syntax/trees/ParseTrees';
/**
* Transforms class declaration:
* - rename constructor to the name of the class (default Dart constructor),
* - class fields are extracted from `this.field = expression;` in the ctor body,
* - `@CONST` annotations on the ctor result in a const constructor & final fields in Dart,
* - const constructor body is converted to an initializerList
*/
export class ClassTransformer extends ParseTreeTransformer {
constructor(idGenerator, reporter) {
super(idGenerator);
this.reporter_ = reporter;
}
/**
* @param {ClassDeclaration} tree
* @returns {ParseTree}
*/
transformClassDeclaration(tree) {
var className = tree.name.identifierToken.toString();
var argumentTypesMap = {};
var fields = [];
var isConst;
var hasConstructor = false;
var that = this;
tree.elements.forEach(function(elementTree, index) {
if (elementTree.type === PROPERTY_METHOD_ASSIGNMENT &&
!elementTree.isStatic &&
propName(elementTree) === CONSTRUCTOR) {
hasConstructor = true;
isConst = elementTree.annotations.some(that._isConstAnnotation);
// Store constructor argument types,
// so that we can use them to set the types of simple-assigned fields.
elementTree.parameterList.parameters.forEach(function(p) {
var binding = p.parameter.binding;
if (binding && binding.identifierToken) {
argumentTypesMap[binding.identifierToken.value] = p.typeAnnotation;
}
});
// Rename "constructor" to the class name.
elementTree.name.literalToken.value = className;
// Compute the initializer list
var initializerList = [];
var superCall = that._extractSuperCall(elementTree.body);
if (isConst) {
initializerList = that._extractFieldInitializers(elementTree.body);
if (elementTree.body.statements.length > 0) {
that.reporter_.reportError(
elementTree.location,
'Const constructor body can only contain field initialization & super call');
}
}
if (superCall) initializerList.push(superCall);
// Replace the `PROPERTY_METHOD_ASSIGNMENT` with a Dart specific
// `PROPERTY_CONSTRUCTOR_ASSIGNMENT`
tree.elements[index] = new PropertyConstructorAssignment(
elementTree.location,
elementTree.isStatic,
elementTree.functionKind,
elementTree.name,
elementTree.parameterList,
elementTree.typeAnnotation,
elementTree.annotations,
elementTree.body,
isConst,
initializerList
);
}
});
// If no constructor exists then look to see if we should create a const constructor
// when the class is annotated with @CONST.
if (!hasConstructor) {
let constClassAnnotation = this._extractConstAnnotation(tree);
if (constClassAnnotation !== null) {
tree.elements = [(new PropertyConstructorAssignment(
constClassAnnotation.location,
false,
null,
tree.name,
new FormalParameterList(constClassAnnotation.location, []),
null,
[constClassAnnotation],
new FunctionBody(constClassAnnotation.location, []),
true,
[]
))].concat(tree.elements);
}
}
let implementsAnnotation = this._extractImplementsAnnotation(tree);
if (implementsAnnotation !== null) {
tree.implements = new ImplementsDeclaration(
implementsAnnotation.location,
implementsAnnotation.args.args);
}
// Add the field definitions to the beginning of the class.
tree.elements = fields.concat(tree.elements);
if (isConst) {
tree.elements.forEach(function(element) {
element.isFinal = true;
});
}
return super.transformClassDeclaration(tree);
}
/**
* Extract field initialization (`this.field = <expression>;`) from the body of the constructor.
* The init statements are removed from the body statements and returned as an array.
*/
_extractFieldInitializers(body) {
var statements = [];
var fieldInitializers = [];
body.statements.forEach(function(statement) {
var exp = statement.expression;
if (exp.type === BINARY_EXPRESSION &&
exp.operator.type === EQUAL &&
exp.left.type === MEMBER_EXPRESSION &&
exp.left.operand.type === THIS_EXPRESSION) {
// `this.field = exp` -> `field = exp`
// todo(vicb): check for `this.` on rhs, not allowed in Dart
// -> remove if possible (arguments), throw otherwise.
var fieldName = exp.left.memberName.value;
fieldInitializers.push(new BinaryExpression(
statement.location,
new IdentifierExpression(statement.location, fieldName),
EQUAL,
exp.right
));
} else {
statements.push(statement);
}
});
body.statements = statements;
return fieldInitializers;
}
/**
* Extract the super call (`super(<arg list>)`) from the body of the constructor.
* When found the super call statement is removed from the body statements and returned.
*/
_extractSuperCall(body) {
var statements = [];
var superCall = null;
body.statements.forEach(function (statement) {
if (statement.expression &&
statement.expression.type === CALL_EXPRESSION &&
statement.expression.operand.type === SUPER_EXPRESSION) {
superCall = statement.expression;
} else {
statements.push(statement);
}
});
body.statements = statements;
return superCall;
}
/**
* Extract the @IMPLEMENTS annotation from the class annotations.
* When found the annotation is removed from the class annotations and returned.
*/
_extractImplementsAnnotation(tree) {
return this._extractAnnotation(tree, this._isImplementsAnnotation);
}
/**
* Extract the @CONST annotation from the class annotations.
* When found the annotation is removed from the class annotations and returned.
*/
_extractConstAnnotation(tree) {
return this._extractAnnotation(tree, this._isConstAnnotation);
}
_extractAnnotation(tree, predicate) {
var annotations = [];
var extractedAnnotation = null;
tree.annotations.forEach((annotation) => {
if (predicate(annotation)) {
extractedAnnotation = annotation;
} else {
annotations.push(annotation);
}
});
tree.annotations = annotations;
return extractedAnnotation;
}
/**
* Returns true if the annotation is @CONST
*/
_isConstAnnotation(annotation) {
return annotation.name.identifierToken.value === 'CONST';
}
/**
* Returns true if the annotation is @IMPLEMENTS
*/
_isImplementsAnnotation(annotation) {
return annotation.name.identifierToken.value === 'IMPLEMENTS';
}
}

View File

@ -1,39 +0,0 @@
import {MultiTransformer} from 'traceur/src/codegeneration/MultiTransformer';
import {UniqueIdentifierGenerator} from 'traceur/src/codegeneration/UniqueIdentifierGenerator';
import {options} from 'traceur/src/Options';
import {ArrowFunctionTransformer} from './ArrowFunctionTransformer';
import {ClassTransformer} from './ClassTransformer';
import {InstanceOfTransformer} from './InstanceOfTransformer';
import {MultiVarTransformer} from './MultiVarTransformer';
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
import {NamedParamsTransformer} from './NamedParamsTransformer';
import {ExportTransformer} from './ExportTransformer';
import {ForOfTransformer} from './ForOfTransformer';
import {DestructuringTransformer} from './DestructuringTransformer';
/**
* Transforms ES6 + annotations to Dart code.
*/
export class DartTransformer extends MultiTransformer {
constructor(reporter, options) {
super(reporter, options.validate);
let idGenerator = new UniqueIdentifierGenerator();
var append = (transformer) => {
this.append((tree) => {
return new transformer(idGenerator, reporter).transformAny(tree);
});
};
append(ArrowFunctionTransformer);
append(NamedParamsTransformer);
append(MultiVarTransformer);
append(InstanceOfTransformer);
append(StrictEqualityTransformer);
append(ClassTransformer);
append(ExportTransformer);
append(ForOfTransformer);
append(DestructuringTransformer);
}
}

View File

@ -1,41 +0,0 @@
import {
COMMA_EXPRESSION,
EXPRESSION_STATEMENT
} from 'traceur/src/syntax/trees/ParseTreeType';
import {
DestructuringTransformer as TraceurDestructuringTransformer
} from 'traceur/src/codegeneration/DestructuringTransformer';
import {
createExpressionStatement
} from 'traceur/src/codegeneration/ParseTreeFactory';
export class DestructuringTransformer extends TraceurDestructuringTransformer {
/**
* Overrides formal parameters to skip processing since they are already handled
* by the NamedParamsTransformer.
*/
transformFormalParameter(tree) {
return tree;
}
/**
* Converts the comma expressions created by Traceur into multiple statements.
*/
desugarBinding_(bindingTree, statements, declarationType) {
var binding = super.desugarBinding_(bindingTree, statements, declarationType);
for (var i = 0; i < statements.length; i++) {
if (statements[i].type === EXPRESSION_STATEMENT &&
statements[i].expression.type === COMMA_EXPRESSION) {
let expression = statements[i].expression;
let expressionStatements = expression.expressions.map(e => {
return createExpressionStatement(e);
});
statements.splice(i, 1, ...expressionStatements);
}
}
return binding;
}
}

View File

@ -1,109 +0,0 @@
import {ParseTreeTransformer} from './ParseTreeTransformer';
import {Map} from 'traceur/src/runtime/polyfills/Map';
import {
ExportDeclaration,
ExportSpecifierSet,
NamedExport,
EmptyStatement
} from 'traceur/src/syntax/trees/ParseTrees';
import {
IMPORT_DECLARATION,
NAMED_EXPORT
} from 'traceur/src/syntax/trees/ParseTreeType';
// Return the index of the first item that is not of IMPORT_DECLARATION type.
function getIndexOfFirstNonImportStatement(items) {
var index = 0;
while (index < items.length && items[index].type === IMPORT_DECLARATION) {
index++;
}
return index;
}
/**
* Transforms re-exports:
* ```
* import {Foo} from './foo';
* import {Bar} from './bar';
* var localVar = true;
*
* export {Foo, Bar, localVar}
*
* ===>
*
* import {Foo} from './foo';
* import {Bar} from './bar';
* var localVar = true;
*
* export {Foo} from './foo';
* export {Bar} from './bar';
* ```
*
* In Dart, all variables defined in the root context of a module that don't start with
* an underscore are exported. Thus we just drop the "export" keyword for the locally defined vars.
* Variables imported from other modules need to be exported with `export './foo' show Foo`.
* This transformer drops the local exports and add the information about module path for the
* imported variables.
*/
export class ExportTransformer extends ParseTreeTransformer {
constructor(idGenerator, reporter) {
super(idGenerator);
this.reporter_ = reporter;
this.importedVars_ = null;
this.collectedExports_ = null;
}
transformModule(tree) {
// New context for each file (module).
this.importedVars_ = new Map();
this.collectedExports_ = [];
tree = super.transformModule(tree);
// In Dart, imports and exports have to be at the top, before any other statement.
// Insert the collected exports before the first non-import statement (after all imports).
var items = tree.scriptItemList;
var index = getIndexOfFirstNonImportStatement(items);
tree.scriptItemList = items.slice(0, index).concat(this.collectedExports_, items.slice(index));
return tree;
}
// For each imported variable, store the module path where it comes from.
// For instance, `import {Foo} from './foo'` will map 'Foo' -> './foo'.
// TODO(vojta): deal with `import * as m from './foo'`.
transformImportDeclaration(tree) {
tree.importClause.specifiers.forEach((specifier) => {
this.importedVars_.set(specifier.binding.binding.identifierToken.value, tree.moduleSpecifier);
});
return tree;
}
transformExportDeclaration(tree) {
if (tree.declaration.type === NAMED_EXPORT && tree.declaration.moduleSpecifier === null) {
// export {...}
tree.declaration.specifierSet.specifiers.forEach((specifier) => {
// Filter out local variables, keep only imported ones.
if (!this.importedVars_.has(specifier.lhs.value)) {
return;
}
// For each specifier, create a new ExportDeclaration and attach the module path (collected
// in `transformImportDeclaration`) to it.
this.collectedExports_.push(new ExportDeclaration(tree.location,
new NamedExport(tree.declaration.location, this.importedVars_.get(specifier.lhs.value),
new ExportSpecifierSet(tree.declaration.specifierSet.location, [specifier])),
tree.annotations));
});
return new EmptyStatement(tree.location);
}
return tree;
}
}

View File

@ -1,16 +0,0 @@
import {ParseTreeTransformer} from 'traceur/src/codegeneration/ParseTreeTransformer';
import {ForInStatement} from 'traceur/src/syntax/trees/ParseTrees';
/**
* Transforms for-of into for-in.
*/
export class ForOfTransformer extends ParseTreeTransformer {
/**
* @param {ForOfStatement} tree
* @return {ParseTree}
*/
transformForOfStatement(original) {
var tree = super.transformForOfStatement(original);
return new ForInStatement(tree.location, tree.initializer, tree.collection, tree.body);
}
}

View File

@ -1,25 +0,0 @@
import {INSTANCEOF} from 'traceur/src/syntax/TokenType';
import {ParseTreeTransformer} from './ParseTreeTransformer';
import {
createBinaryExpression,
createOperatorToken
} from 'traceur/src/codegeneration/ParseTreeFactory';
/**
* Transforms `a instanceof b` to `a is b`,
*/
export class InstanceOfTransformer extends ParseTreeTransformer {
/**
* @param {BinaryExpression} tree
* @return {ParseTree}
*/
transformBinaryExpression(tree) {
tree = super.transformBinaryExpression(tree);
if (tree.operator.type === INSTANCEOF) {
return createBinaryExpression(tree.left, createOperatorToken('is'), tree.right);
}
return tree;
}
}

View File

@ -1,46 +0,0 @@
import {VariableStatement, VariableDeclarationList} from 'traceur/src/syntax/trees/ParseTrees';
import {ParseTreeTransformer} from './ParseTreeTransformer';
/**
* Transforms `var a, b;` to `var a; var b;`
*/
export class MultiVarTransformer extends ParseTreeTransformer {
// Individual item transformer can return an array of items.
// This is used in `transformVariableStatement`.
// Otherwise this is copy/pasted from `ParseTreeTransformer`.
transformList(list) {
var transformedList = [];
var transformedItem = null;
for (var i = 0, ii = list.length; i < ii; i++) {
transformedItem = this.transformAny(list[i]);
if (Array.isArray(transformedItem)) {
transformedList = transformedList.concat(transformedItem);
} else {
transformedList.push(transformedItem);
}
}
return transformedList;
}
/**
* @param {VariableStatement} tree
* @returns {ParseTree}
*/
transformVariableStatement(tree) {
var declarations = tree.declarations.declarations;
if (declarations.length === 1 || declarations.length === 0) {
return tree;
}
// Multiple var declaration, we will split it into multiple statements.
// TODO(vojta): We can leave the multi-definition as long as they are all the same type/untyped.
return declarations.map(function(declaration) {
return new VariableStatement(tree.location, new VariableDeclarationList(tree.location,
tree.declarations.declarationType, [declaration]));
});
}
}

View File

@ -1,133 +0,0 @@
import {ParseTreeTransformer} from './ParseTreeTransformer';
import {
BINDING_ELEMENT,
OBJECT_PATTERN,
OBJECT_LITERAL_EXPRESSION
} from 'traceur/src/syntax/trees/ParseTreeType';
import {
NamedParameterList,
ObjectPatternBindingElement
} from '../syntax/trees/ParseTrees';
/**
* Transforms maps into named parameters:
*
* First, it transform all calls where the last argument is an object literal
* with identifier keys, as follows:
*
* f({a: 1, b: 2}) -> f(a: 1, b: 2)
*
* Second, it removes the empty object initializer from the function definition:
*
* function f({a:1, b:2} = {}){} -> f({a:1, b:2}){}
*/
export class NamedParamsTransformer extends ParseTreeTransformer {
/**
* Transform function calls.
*
* @param {CallExpression} tree
* @return {ParseTree}
*/
transformCallExpression(tree) {
tree = super.transformCallExpression(tree);
this._handleNamedParams(tree);
return tree;
}
/**
* Transform new expressions.
*
* @param {NewExpression} tree
* @return {ParseTree}
*/
transformNewExpression(tree) {
tree = super.transformNewExpression(tree);
this._handleNamedParams(tree);
return tree;
}
transformAnnotation(tree) {
tree = super.transformAnnotation(tree);
if (tree.args) this._handleNamedParams(tree);
return tree;
}
_handleNamedParams(tree) {
if (this._isLastArgAnNonEmptyObjectLiteral(tree) &&
! this._isLastArgObjectLiteralWithQuotedKeys(tree)) {
this._replaceLastArgWithNamedParams(tree);
}
}
_isLastArgAnNonEmptyObjectLiteral(tree) {
var lastArg = this._last(tree.args.args);
if (!lastArg) return false;
var pairs = lastArg.propertyNameAndValues;
if (!pairs || pairs.length == 0) return false;
return true;
}
_isLastArgObjectLiteralWithQuotedKeys(tree) {
var pairs = this._last(tree.args.args).propertyNameAndValues;
for (var pair of pairs) {
var key = pair.name.literalToken.value;
if (key.charAt(0) == '"' || key.charAt(0) == "'") return true;
}
return false;
}
_replaceLastArgWithNamedParams(tree) {
var args = tree.args.args;
var last = this._last(args);
args[args.length - 1] = new NamedParameterList(last.location, last.propertyNameAndValues);
}
/**
* Transform function declaration.
*
* @param {ObjectPattern} tree
* @return {ParseTree}
*/
transformObjectPattern(tree) {
tree = super.transformObjectPattern(tree);
tree.fields = tree.fields.map(
(e) => new ObjectPatternBindingElement(e.location, e.binding, e.initializer));
return tree;
}
/**
* @param {FormalParameterList} tree
* @return {ParseTree}
*/
transformFormalParameterList(tree) {
tree = super.transformFormalParameterList(tree);
var last = this._last(tree.parameters);
if (last && this._isObjectPatternWithAnEmptyObjectInit(last.parameter)) {
last.parameter = last.parameter.binding;
}
return tree;
}
_isObjectPatternWithAnEmptyObjectInit(tree) {
return tree.type === BINDING_ELEMENT &&
tree.binding.type === OBJECT_PATTERN &&
this._isEmptyObjectInitializer(tree.initializer)
}
_isEmptyObjectInitializer(initializer) {
return initializer &&
initializer.type == OBJECT_LITERAL_EXPRESSION &&
initializer.propertyNameAndValues.length == 0;
}
_last(array) {
if (!array || array.length == 0) return undefined;
return array[array.length - 1];
}
}

View File

@ -1,50 +0,0 @@
import {
ParseTreeTransformer as TraceurParseTreeTransformer
} from 'traceur/src/codegeneration/ParseTreeTransformer';
import {
ClassFieldDeclaration,
PropertyConstructorAssignment,
NamedParameterList,
ObjectPatternBindingElement
} from '../syntax/trees/ParseTrees'
export class ParseTreeTransformer extends TraceurParseTreeTransformer {
transformClassFieldDeclaration(tree) {
var lvalue = this.transformAny(tree.lvalue);
var typeAnnotation = this.transformAny(tree.typeAnnotation);
if (lvalue === tree.lvalue && typeAnnotation === tree.typeAnnotation) {
return tree;
}
return new ClassFieldDeclaration(tree.location, lvalue, typeAnnotation, initializer);
}
transformPropertyConstructorAssignment(tree) {
tree = super.transformPropertyMethodAssignment(tree);
var initializerList = this.transformList(tree.initializerList);
if (initializerList === tree.initializerList) {
return tree;
}
return new PropertyConstructorAssignment(tree.location, tree.isStatic, tree.functionKind,
tree.name, tree.parameterList, tree.typeAnnotation, tree.annotations, tree.body, tree.isConst,
initializerList);
}
transformNamedParameterList(tree) {
var nvPairs = this.transformList(tree.parameterNameAndValues);
if (nvPairs === tree.parameterNameAndValues) {
return tree;
}
return new NamedParameterList(tree.location, nvPairs);
}
transformObjectPatternBindingElement(tree) {
var binding = this.transformAny(tree.binding);
var initializer = this.transformAny(tree.initializer);
if (binding === tree.binding && initializer === tree.initializer) {
return tree;
}
return new ObjectPatternBindingElement(tree.location, binding, initializer);
}
}

View File

@ -1,43 +0,0 @@
import {
createArgumentList,
createCallExpression,
createIdentifierExpression
} from 'traceur/src/codegeneration/ParseTreeFactory';
import {
EQUAL_EQUAL_EQUAL,
NOT_EQUAL_EQUAL
} from 'traceur/src/syntax/TokenType';
import {ParseTreeTransformer} from './ParseTreeTransformer';
/**
* Transforms:
* - `a === b` to `indentical(a, b)`,
* - `a !== b` to `!identical(a, b)`
*/
export class StrictEqualityTransformer extends ParseTreeTransformer {
/**
* @param {BinaryExpression} tree
* @return {ParseTree}
*/
transformBinaryExpression(tree) {
tree.left = this.transformAny(tree.left);
tree.right = this.transformAny(tree.right);
if (tree.operator.type === EQUAL_EQUAL_EQUAL) {
// `a === b` -> `identical(a, b)`
return createCallExpression(createIdentifierExpression('identical'),
createArgumentList([tree.left, tree.right]));
}
if (tree.operator.type === NOT_EQUAL_EQUAL) {
// `a !== b` -> `!identical(a, b)`
// TODO(vojta): do this in a cleaner way.
return createCallExpression(createIdentifierExpression('!identical'),
createArgumentList([tree.left, tree.right]));
}
return tree;
}
}

View File

@ -1,6 +1,4 @@
import {Compiler as TraceurCompiler} from 'traceur/src/Compiler'; import {Compiler as TraceurCompiler} from 'traceur/src/Compiler';
import {DartTransformer} from './codegeneration/DartTransformer';
import {DartParseTreeWriter} from './outputgeneration/DartParseTreeWriter';
import {CollectingErrorReporter} from 'traceur/src/util/CollectingErrorReporter'; import {CollectingErrorReporter} from 'traceur/src/util/CollectingErrorReporter';
import {Parser} from './parser'; import {Parser} from './parser';
import {SourceFile} from 'traceur/src/syntax/SourceFile'; import {SourceFile} from 'traceur/src/syntax/SourceFile';
@ -13,28 +11,6 @@ export class Compiler extends TraceurCompiler {
this.moduleName_ = sourceRoot; this.moduleName_ = sourceRoot;
} }
transform(tree, moduleName = undefined) {
if (this.options_.outputLanguage.toLowerCase() === 'dart') {
var errorReporter = new CollectingErrorReporter();
var transformer = new DartTransformer(errorReporter, this.options_);
var transformedTree = transformer.transform(tree);
this.throwIfErrors(errorReporter);
return transformedTree;
} else {
return super.transform(tree, moduleName);
}
}
write(tree, outputName = undefined, sourceRoot = undefined) {
if (this.options_.outputLanguage.toLowerCase() === 'dart') {
var writer = new DartParseTreeWriter(this.moduleName_, outputName);
writer.visitAny(tree);
return writer.toString();
} else {
return super.write(tree, outputName, sourceRoot);
}
}
// Copy of the original method to use our custom Parser // Copy of the original method to use our custom Parser
parse(content, sourceName) { parse(content, sourceName) {
if (!content) { if (!content) {

View File

@ -1,534 +0,0 @@
import {CONSTRUCTOR, FROM} from 'traceur/src/syntax/PredefinedName';
import {
AT,
CLASS,
CLOSE_CURLY,
CLOSE_PAREN,
CLOSE_SQUARE,
COLON,
COMMA,
EQUAL,
EQUAL_EQUAL_EQUAL,
EXTENDS,
IMPLEMENTS,
IMPORT,
OPEN_CURLY,
OPEN_PAREN,
OBJECT_PATTERN,
OPEN_SQUARE,
PERIOD,
SEMI_COLON,
STAR,
STATIC,
VAR,
OPEN_ANGLE,
CLOSE_ANGLE
} from 'traceur/src/syntax/TokenType';
import {
GET
} from 'traceur/src/syntax/PredefinedName';
import {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter';
import {ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees';
import {IdentifierToken} from 'traceur/src/syntax/IdentifierToken';
import {EXPORT_STAR, NAMED_EXPORT} from 'traceur/src/syntax/trees/ParseTreeType';
import {typeMapping} from '../type_mapping';
export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
constructor(moduleName, outputPath) {
super(outputPath);
this.libName = moduleName.replace(/\//g, '.').replace(/[^\w.\/]/g, '_');
this.annotationContextCounter = 0;
}
visitEmptyStatement() {}
// CLASS FIELDS
visitPropertyVariableDeclaration(tree) {
if (tree.isStatic) {
this.write_(STATIC);
this.writeSpace_();
}
if (tree.typeAnnotation === null) {
this.write_(tree.isFinal ? 'final' : VAR);
} else {
if (tree.isFinal) {
this.write_('final');
}
this.writeTypeAndSpace_(tree.typeAnnotation);
}
this.writeSpace_();
this.visitAny(tree.name);
this.write_(SEMI_COLON);
}
// VARIABLES - types
// ```
// var foo:bool = true;
// ==>
// bool foo = true;
// ```
visitVariableDeclarationList(tree) {
// Write `var`, only if no type declaration.
if (!tree.declarations[0].typeAnnotation) {
this.write_(tree.declarationType);
this.writeSpace_();
}
this.writeList_(tree.declarations, COMMA, true, 2);
}
visitVariableDeclaration(tree) {
this.writeTypeAndSpace_(tree.typeAnnotation);
this.visitAny(tree.lvalue);
if (tree.initializer !== null) {
this.writeSpace_();
this.write_(EQUAL);
this.writeSpace_();
this.visitAny(tree.initializer);
}
}
visitTemplateLiteralExpression(tree) {
if (tree.operand) {
throw new Error('tagged template strings are not supported');
}
this.writeRaw_("'''");
this.visitList(tree.elements);
this.writeRaw_("'''");
}
visitTemplateLiteralPortion(tree) {
this.writeRaw_(tree.value.toString()
.replace(/('|")/g, "\\$&")
.replace(/([^\\])\$/g, "$1\\\$")
.replace(/^\$/, '\\\$'));
}
visitLiteralExpression(tree) {
this.write_(('' + tree.literalToken).replace(/([^\\])\$/g, "$1\\\$"));
}
// FUNCTIONS
// - remove the "function" keyword
// - type annotation infront
visitFunction_(tree) {
this.writeAnnotations_(tree.annotations);
if (tree.isAsyncFunction()) {
this.write_(tree.functionKind);
}
if (tree.isGenerator()) {
this.write_(tree.functionKind);
}
if (tree.name) {
this.writeTypeAndSpace_(tree.typeAnnotation);
this.visitAny(tree.name);
}
this.write_(OPEN_PAREN);
this.visitAny(tree.parameterList);
this.write_(CLOSE_PAREN);
this.writeSpace_();
this.visitAny(tree.body);
};
// Class methods.
// - type annotation infront
visitPropertyMethodAssignment(tree) {
this.writeAnnotations_(tree.annotations);
if (tree.isStatic) {
this.write_(STATIC);
this.writeSpace_();
}
if (tree.isGenerator()) {
this.write_(STAR);
}
if (tree.isAsyncFunction()) {
this.write_(ASYNC);
}
this.writeTypeAndSpace_(tree.typeAnnotation);
this.visitAny(tree.name);
this.write_(OPEN_PAREN);
this.visitAny(tree.parameterList);
this.write_(CLOSE_PAREN);
this.writeSpace_();
this.visitAny(tree.body);
}
visitFormalParameterList(tree) {
var hasPosOptionalParams = false;
var first = true;
for (var i = 0; i < tree.parameters.length; i++) {
var parameter = tree.parameters[i];
if (first) {
first = false;
} else {
this.write_(COMMA);
this.writeSpace_();
}
if (!hasPosOptionalParams && this._isOptionalPositionParam(parameter.parameter)) {
hasPosOptionalParams = true;
this.write_(OPEN_SQUARE);
}
this.visitAny(parameter);
}
if (hasPosOptionalParams) {
this.write_(CLOSE_SQUARE);
}
}
_isOptionalPositionParam(parameter) {
return parameter.initializer && parameter.binding.type !== OBJECT_PATTERN;
}
/**
* @param {PropertyMethodAssignment} tree
*/
visitPropertyConstructorAssignment(tree) {
this.writeAnnotations_(tree.annotations);
if (tree.isConst) {
this.write_('const');
this.writeSpace_();
}
this.writeTypeAndSpace_(tree.typeAnnotation);
this.visitAny(tree.name);
this.write_(OPEN_PAREN);
this.visitAny(tree.parameterList);
this.write_(CLOSE_PAREN);
if (tree.initializerList.length > 0) {
this.write_(COLON);
this.writeSpace_();
this.writeList_(tree.initializerList, ', ');
}
if (tree.isConst) {
this.write_(SEMI_COLON);
} else {
this.writeSpace_();
this.visitAny(tree.body);
}
}
normalizeType_(typeName) {
return typeMapping[typeName] || typeName;
}
// FUNCTION/METHOD ARGUMENTS
// - type infront of the arg name
visitBindingElement(tree) {
this._visitBindingElement(tree, EQUAL);
}
visitObjectPatternBindingElement(tree) {
this._visitBindingElement(tree, COLON);
}
_visitBindingElement(tree, initSeparator) {
// TODO(vojta): This is awful, just copy/pasted from Traceur,
// we should still clean it up.
var typeAnnotation = this.currentParameterTypeAnnotation_;
// resetting type annotation so it doesn't filter down recursively
this.currentParameterTypeAnnotation_ = null;
this.writeTypeAndSpace_(typeAnnotation);
this.visitAny(tree.binding);
if (tree.initializer) {
this.writeSpace_();
this.write_(initSeparator);
this.writeSpace_();
this.visitAny(tree.initializer);
}
}
writeTypeAndSpace_(typeAnnotation) {
this.writeType_(typeAnnotation);
this.writeSpace_();
}
writeType_(typeAnnotation) {
if (!typeAnnotation) {
return;
}
var typeNameNode;
var args = [];
if (typeAnnotation.typeName) {
typeNameNode = typeAnnotation.typeName;
args = typeAnnotation.args.args;
} else {
typeNameNode = typeAnnotation;
args = [];
}
if (typeNameNode.moduleName && typeNameNode.moduleName.name && typeNameNode.moduleName.name.value) {
this.write_(typeNameNode.moduleName.name.value);
this.write_(PERIOD);
}
// TODO(vojta): Figure out why `typeNameNode` has different structure when used with a variable.
// This should probably be fixed in Traceur.
var typeName = typeNameNode.typeToken && typeNameNode.typeToken.value || (typeNameNode.name && typeNameNode.name.value) || null;
if (!typeName) {
return;
}
this.write_(this.normalizeType_(typeName));
if (args.length) {
this.write_(OPEN_ANGLE);
this.writeType_(args[0]);
for (var i=1; i<args.length; i++) {
this.write_(COMMA);
this.writeSpace_();
this.writeType_(args[i]);
}
this.write_(CLOSE_ANGLE);
}
}
// EXPORTS
visitExportDeclaration(tree) {
if (tree.declaration.type === NAMED_EXPORT) {
// export {...}
// export {...} from './foo'
// export * from './foo'
if (tree.declaration.moduleSpecifier) {
if (tree.declaration.specifierSet.type === EXPORT_STAR) {
// export * from './foo'
// ===>
// export './foo';
this.write_('export');
this.writeSpace_();
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
this.write_(SEMI_COLON);
} else {
// export {Foo, Bar} from './foo'
// ===>
// export './foo' show Foo, Bar;
this.write_('export');
this.writeSpace_();
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
this.writeSpace_();
this.write_('show');
this.writeSpace_();
this.writeList_(tree.declaration.specifierSet.specifiers, COMMA, false);
this.write_(SEMI_COLON);
}
} else {
// export {...}
// This case is handled in `ExportTransformer`.
throw new Error('Should never happen!');
}
} else {
// export var x = true
// export class Foo {}
// export function bar() {}
// Just remove "export" keyword.
this.writeAnnotations_(tree.annotations);
this.visitAny(tree.declaration);
}
}
// visitExportDefault
// visitNamedExport
// visitExportSpecifier
// visitExportSpecifierSet
// visitExportStar
// IMPORTS
visitImportDeclaration(tree) {
this.write_(IMPORT);
this.writeSpace_();
this.visitAny(tree.moduleSpecifier);
if (tree.importClause.binding) {
// Default import, not supported as dart does not distinguish
// between explicit exports and default exports
throw new Error('default imports/exports not supported');
} else {
// Regular - import list of members.
// import {Foo, Bar} from './baz';
this.visitAny(tree.importClause);
}
this.write_(SEMI_COLON);
}
// Translate './foo' -> './foo.dart'
transformModuleUrl(url) {
var prefix = url.charAt(1) === '.' ? '' : 'package:';
return "'" + prefix + url.substring(1, url.length - 1) + ".dart'";
}
visitModuleSpecifier(tree) {
this.write_(this.transformModuleUrl(tree.token.value));
}
visitImportSpecifier(tree) {
if (tree.name) {
throw new Error('"as" syntax not supported');
}
this.visitAny(tree.binding);
}
visitImportedBinding(tree) {
if (tree.binding && tree.binding.identifierToken) {
var b = tree.binding;
var t = b.identifierToken;
var token = new IdentifierToken(t.location, this.normalizeType_(t.value));
var binding = new BindingIdentifier(b.location, token);
super.visitImportedBinding(new ImportedBinding(tree.location, binding));
} else {
super.visitImportedBinding(tree);
}
}
visitImportSpecifierSet(tree) {
if (tree.specifiers.type == STAR) {
throw new Error('"*" syntax not supported');
} else {
this.write_(' show ');
this.writeList_(tree.specifiers, COMMA, false);
}
}
visitModuleDeclaration(tree) {
// module import - import the entire module.
// import * as foo from './bar';
this.write_(IMPORT);
this.writeSpace_();
this.visitAny(tree.expression);
this.write_(' as ');
this.visitAny(tree.binding);
this.write_(SEMI_COLON);
}
// ANNOTATIONS
// TODO(vojta): this is just fixing a bug in Traceur, send a PR.
visitAnnotation(tree) {
// TODO(tbosch): Disabled the removal of control annotations (annotations in uppercase),
// as they should be handeled by a transformer and right now lead
// to errors (unused import) in dartanalyzer.
// if (tree.name.identifierToken) {
// var nameValue = tree.name.identifierToken.value;
// if (nameValue === nameValue.toUpperCase()) {
// // control annotations for transpiler
// return;
// }
// }
this.write_(AT);
this.visitAny(tree.name);
if (tree.args !== null) {
this.annotationContextCounter++;
this.write_(OPEN_PAREN);
this.writeList_(tree.args.args, COMMA, false);
this.write_(CLOSE_PAREN);
this.annotationContextCounter--;
}
this.writeSpace_()
}
visitGetAccessor(tree) {
this.writeAnnotations_(tree.annotations);
if (tree.isStatic) {
this.write_(STATIC);
this.writeSpace_();
}
this.writeTypeAndSpace_(tree.typeAnnotation);
this.writeSpace_();
this.write_(GET);
this.writeSpace_();
this.visitAny(tree.name);
this.writeSpace_();
this.visitAny(tree.body);
}
visitObjectLiteralExpression(tree) {
if (this.annotationContextCounter) {
this.write_('const');
}
super.visitObjectLiteralExpression(tree);
}
visitArrayLiteralExpression(tree) {
if (this.annotationContextCounter) {
this.write_('const');
}
super.visitArrayLiteralExpression(tree);
}
visitNewExpression(tree) {
if (this.annotationContextCounter) {
this.write_('const');
this.writeSpace_();
this.visitAny(tree.operand);
this.visitAny(tree.args);
} else {
super.visitNewExpression(tree);
}
}
visitNamedParameterList(tree) {
this.writeList_(tree.parameterNameAndValues, COMMA, false);
}
visitClassDeclaration(tree) {
this.writeAnnotations_(tree.annotations);
this.write_(CLASS);
this.writeSpace_();
this.visitAny(tree.name);
if (tree.superClass) {
this.writeSpace_();
this.write_(EXTENDS);
this.writeSpace_();
this.visitAny(tree.superClass);
}
if (tree.implements) {
this.writeSpace_();
this.write_(IMPLEMENTS);
this.writeSpace_();
this.writeList_(tree.implements.interfaces, COMMA, false);
}
this.writeSpace_();
this.write_(OPEN_CURLY);
this.writelnList_(tree.elements);
this.write_(CLOSE_CURLY);
}
toString() {
return "library " + this._transformLibName(this.libName) + ";\n" + super.toString();
}
_transformLibName(libName) {
var parts = libName.split('.');
for (var part of parts) {
if (DART_RESERVED_WORDS.indexOf(part) != -1) {
return libName + '_dart';
}
}
return libName;
}
}
// see: https://www.dartlang.org/docs/dart-up-and-running/ch02.html for a full list.
const DART_RESERVED_WORDS = ['if', 'switch', 'for', 'class'];

View File

@ -1,5 +0,0 @@
export var CLASS_FIELD_DECLARATION = 'CLASS_FIELD_DECLARATION';
export var PROPERTY_CONSTRUCTOR_ASSIGNMENT = 'PROPERTY_CONSTRUCTOR_ASSIGNMENT';
export var NAMED_PARAMETER_LIST = 'NAMED_PARAMETER_LIST';
export var OBJECT_PATTERN_BINDING_ELEMENT = 'OBJECT_PATTERN_BINDING_ELEMENT';
export var IMPLEMENTS_DECLARATION = "IMPLEMENTS_DECLARATION";

View File

@ -1,177 +0,0 @@
import {ParseTree} from 'traceur/src/syntax/trees/ParseTree';
import {PropertyMethodAssignment} from 'traceur/src/syntax/trees/ParseTrees';
import * as ParseTreeType from './ParseTreeType';
// Class constructor
export class PropertyConstructorAssignment extends PropertyMethodAssignment {
/**
* @param {SourceRange} location
* @param {boolean} isStatic
* @param {Token} functionKind
* @param {ParseTree} name
* @param {FormalParameterList} parameterList
* @param {ParseTree} typeAnnotation
* @param {Array.<ParseTree>} annotations
* @param {FunctionBody} body
* @param {boolean} isConst
* @param {ParseTree} initializerList
*/
constructor(location, isStatic, functionKind, name, parameterList, typeAnnotation, annotations,
body, isConst, initializerList) {
super(location, isStatic, functionKind, name, parameterList, typeAnnotation, annotations,
body);
this.isConst = isConst;
this.initializerList = initializerList;
}
/**
* @param {ParseTreeTransformer} transformer
*/
transform(transformer) {
if (transformer.transformPropertyConstructorAssignment) {
return transformer.transformPropertyConstructorAssignment(this);
}
return this;
}
/**
* @param {ParseTreeVisitor} visitor
*/
visit(visitor) {
if (visitor.visitPropertyConstructorAssignment) {
visitor.visitPropertyConstructorAssignment(this);
}
}
/**
* @type {ParseTreeType}
*/
get type() {
return PROPERTY_CONSTRUCTOR_ASSIGNMENT;
}
}
var PROPERTY_CONSTRUCTOR_ASSIGNMENT = ParseTreeType.PROPERTY_CONSTRUCTOR_ASSIGNMENT;
// Named parameters
export class NamedParameterList extends ParseTree {
/**
* @param {SourceRange} location
* @param {Array.<ParseTree>} parameterNameAndValues
*/
constructor(location, parameterNameAndValues) {
super(location);
this.parameterNameAndValues = parameterNameAndValues;
}
/**
* @param {ParseTreeTransformer} transformer
*/
transform(transformer) {
if (transformer.transformNamedParameterList) {
return transformer.transformNamedParameterList(this);
}
return this;
}
/**
* @param {ParseTreeVisitor} visitor
*/
visit(visitor) {
if (visitor.visitNamedParameterList) {
visitor.visitNamedParameterList(this);
}
}
/**
* @type {ParseTreeType}
*/
get type() {
return NAMED_PARAMETER_LIST;
}
}
var NAMED_PARAMETER_LIST = ParseTreeType.NAMED_PARAMETER_LIST;
// Object pattern binding element
export class ObjectPatternBindingElement extends ParseTree {
/**
* @param {SourceRange} location
* @param {BindingIdentifier|ObjectPattern|ArrayPattern} binding
* @param {ParseTree} initializer
*/
constructor(location, binding, initializer) {
super(location);
this.binding = binding;
this.initializer = initializer;
}
/**
* @param {ParseTreeTransformer} transformer
*/
transform(transformer) {
if (transformer.transformObjectPatternBindingElement) {
return transformer.transformObjectPatternBindingElement(this);
}
return this;
}
/**
* @param {ParseTreeVisitor} visitor
*/
visit(visitor) {
if (visitor.visitObjectPatternBindingElement) {
visitor.visitObjectPatternBindingElement(this);
}
}
/**
* @type {ParseTreeType}
*/
get type() {
return OBJECT_PATTERN_BINDING_ELEMENT;
}
}
export class ImplementsDeclaration extends ParseTree {
/**
* @param {SourceRange} location
* @param {Array.<ParseTree>} interfaces
*/
constructor(location, interfaces) {
super(location);
this.interfaces = interfaces;
}
/**
* @param {ParseTreeTransformer} transformer
*/
transform(transformer) {
if (transformer.transformImplementsDeclaration) {
return transformer.transformImplementsDeclaration(this);
}
return this;
}
/**
* @param {ParseTreeVisitor} visitor
*/
visit(visitor) {
if (visitor.visitImplementsDeclaration) {
visitor.visitImplementsDeclaration(this);
}
}
/**
* @type {ParseTreeType}
*/
get type() {
return ParseTreeType.IMPLEMENTS_DECLARATION;
}
}
var OBJECT_PATTERN_BINDING_ELEMENT = ParseTreeType.OBJECT_PATTERN_BINDING_ELEMENT;

View File

@ -1,11 +0,0 @@
// JS -> Dart
export var typeMapping = {
'number': 'num',
'boolean': 'bool',
'string': 'String',
'any': 'dynamic',
'Promise': 'Future',
'Observable': 'Stream',
'Date': 'DateTime',
'StringMap': 'Map'
};

View File

@ -12,83 +12,6 @@ var DEFAULT_OPTIONS = {
memberVariables: true // parse class fields memberVariables: true // parse class fields
}; };
describe('transpile to dart', function(){
var options;
beforeEach(function() {
options = merge(DEFAULT_OPTIONS, {outputLanguage: 'dart'});
});
// https://github.com/angular/angular/issues/509
describe('string interpolation', function() {
it('should not interpolate inside old quotes', function(){
var result = compiler.compile(options, "test.js",
"var a:number = 1;" +
"var s1:string = \"${a}\";" +
"var s2:string = '\\${a}';" +
"var s3:string = '$a';");
expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = \"\\${a}\";\n" +
"String s2 = '\\${a}';\n" +
"String s3 = '\\$a';\n");
});
it('should not interpolate without curly braces', function() {
var result = compiler.compile(options, "test.js",
"var a:number = 1;" +
"var s1:string = `$a`;" +
"var s2:string = `\\$a`;");
expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = '''\\$a''';\n" +
"String s2 = '''\\$a''';\n");
});
it('should interpolate inside template quotes', function() {
var result = compiler.compile(options, "test.js",
"var a:number = 1;" +
"var s1:string = `${a}`;");
expect(result.js).toBe("library test;\n" +
"num a = 1;\n" +
"String s1 = '''${a}''';\n");
});
});
describe('generic', function() {
it('should support types without generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List = [];");
expect(result.js).toBe("library test;\nList a = [];\n");
});
it('should support one level generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List<string> = [];");
expect(result.js).toBe("library test;\nList<String> a = [];\n");
});
it('should support multiple one level generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List<A,B> = [];");
expect(result.js).toBe("library test;\nList<A, B> a = [];\n");
});
it('should support nested generics', function() {
var result = compiler.compile(options, "test.js",
"var a:List<A<B>> = [];");
expect(result.js).toBe("library test;\nList<A<B>> a = [];\n");
});
it('should add dart suffix to reserved words', function() {
var result = compiler.compile(options, "project/if.js",
"var a;");
expect(result.js).toBe("library project.if_dart;\nvar a;\n");
});
});
});
describe('transpile to es6', function() { describe('transpile to es6', function() {
var options; var options;