cleanup(build): remove traceur-based Dart transpiler
This commit is contained in:
parent
3d62546314
commit
4c1e978536
|
@ -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);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -71,10 +71,7 @@ export function main() {
|
|||
|
||||
expect(function() {
|
||||
wf.name = true;
|
||||
}).toThrowError(IS_DARTIUM ?
|
||||
// Dart
|
||||
"type 'bool' is not a subtype of type 'String' of 'value'" :
|
||||
// JavaScript
|
||||
}).toThrowError(
|
||||
// TODO(vojta): Better error, it's not first argument, it's setting a field.
|
||||
'Invalid arguments given!\n' +
|
||||
' - 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() {
|
||||
expect(function() {
|
||||
WithFields.id = true;
|
||||
}).toThrowError(IS_DARTIUM ?
|
||||
// Dart
|
||||
"type 'bool' is not a subtype of type 'num' of 'id'" :
|
||||
// JavaScript
|
||||
}).toThrowError(
|
||||
// TODO(vojta): Better error, it's not first argument, it's setting a field.
|
||||
'Invalid arguments given!\n' +
|
||||
' - 1st argument has to be an instance of number, got true'
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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]));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
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 {Parser} from './parser';
|
||||
import {SourceFile} from 'traceur/src/syntax/SourceFile';
|
||||
|
@ -13,28 +11,6 @@ export class Compiler extends TraceurCompiler {
|
|||
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
|
||||
parse(content, sourceName) {
|
||||
if (!content) {
|
||||
|
|
|
@ -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'];
|
|
@ -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";
|
|
@ -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;
|
|
@ -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'
|
||||
};
|
|
@ -12,83 +12,6 @@ var DEFAULT_OPTIONS = {
|
|||
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() {
|
||||
var options;
|
||||
|
||||
|
|
Loading…
Reference in New Issue