Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion tools/transpiler/spec/functions_spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
import {describe, it, expect} from 'test_lib/test_lib';
import {describe, ddescribe, it, iit, expect} from 'test_lib/test_lib';

function sum(a, b) {
return a + b;
}


export function main() {
describe('functions', function() {
it('should work', function() {
expect(sum(1, 2)).toBe(3);
});

describe("named parameters", function() {
it('should pass named params as named params by using identifier keys', function() {
function f(a, {b, c}) {return a + b + c;}
expect(f(1, {b: 2, c: 3})).toBe(6);
});

it('should pass named params as a map by using quoted keys', function() {
function f(m) {return m["a"] + m["b"];}

expect(f({"a": 1, "b": 2})).toBe(3);
});

it('should compile initializers', function() {
function f({a=1, b=2}) {return a + b;}
expect(f({a:10})).toBe(12);
});

it("should call function with named params without passing any" +
"params by providing an empty object initializer", function() {
function f({a=1, b=2}={}) {return a + b;}

expect(f({a: 10})).toBe(12);
expect(f()).toBe(3);
});
});
});
}
16 changes: 16 additions & 0 deletions tools/transpiler/src/ast/named_params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {ParseTree} from 'traceur/src/syntax/trees/ParseTree';

export class NamedParams extends ParseTree {
constructor(location, propertyNameAndValues) {
this.location = location;
this.propertyNameAndValues = propertyNameAndValues;
}

visit(visitor) {
visitor.visitNamedParamsExpression(this);
}

transform(transformer) {
return this;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline is missing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tbosch I have always wonder why new line at eof are important ?

7 changes: 7 additions & 0 deletions tools/transpiler/src/ast/object_pattern_binding_element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {BindingElement} from 'traceur/src/syntax/trees/ParseTrees';

export class ObjectPatternBindingElement extends BindingElement {
visit(visitor) {
visitor.visitObjectPatternBindingElement(this);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline is missing

2 changes: 2 additions & 0 deletions tools/transpiler/src/codegeneration/DartTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {ClassTransformer} from './ClassTransformer';
import {InstanceOfTransformer} from './InstanceOfTransformer';
import {MultiVarTransformer} from './MultiVarTransformer';
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
import {NamedParamsTransformer} from './NamedParamsTransformer';

/**
* Transforms ES6 + annotations to Dart code.
Expand All @@ -20,6 +21,7 @@ export class DartTransformer extends MultiTransformer {
});
};

append(NamedParamsTransformer);
append(MultiVarTransformer);
append(InstanceOfTransformer);
append(StrictEqualityTransformer);
Expand Down
104 changes: 104 additions & 0 deletions tools/transpiler/src/codegeneration/NamedParamsTransformer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {ParseTreeTransformer} from 'traceur/src/codegeneration/ParseTreeTransformer';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name should either have Dart in front of it, or we should have a subfolder dart for the dart related transformers...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the filename...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we check that the keys are quoted?

import {
BINDING_ELEMENT,
OBJECT_PATTERN,
OBJECT_LITERAL_EXPRESSION
} from 'traceur/src/syntax/trees/ParseTreeType';

import {NamedParams} from '../ast/named_params';
import {ObjectPatternBindingElement} from '../ast/object_pattern_binding_element';

/**
* 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 {
/**
* @param {CallExpression} tree
* @return {ParseTree}
*/
transformCallExpression(tree) {
tree = super.transformCallExpression(tree);
if (this._isLastArgAnNonEmptyObjectLiteral(tree) &&
! this._isLastArgObjectLiteralWithQuotedKeys(tree)) {
this._replaceLastArgWithNamedParams(tree);
}
return 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 NamedParams(last.location, last.propertyNameAndValues);
}

/**
* @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];
}
}
18 changes: 15 additions & 3 deletions tools/transpiler/src/dart_writer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {CONSTRUCTOR, FROM} from 'traceur/src/syntax/PredefinedName';
import {EQUAL_EQUAL_EQUAL, OPEN_PAREN, CLOSE_PAREN, IMPORT, SEMI_COLON, STAR, OPEN_CURLY, CLOSE_CURLY, COMMA, AT, EQUAL} from 'traceur/src/syntax/TokenType';
import {EQUAL_EQUAL_EQUAL, OPEN_PAREN, CLOSE_PAREN, IMPORT, SEMI_COLON, STAR, OPEN_CURLY, CLOSE_CURLY, COMMA, AT, EQUAL, COLON} from 'traceur/src/syntax/TokenType';

import {ParseTreeWriter as JavaScriptParseTreeWriter} from 'traceur/src/outputgeneration/ParseTreeWriter';
import {ParseTreeWriter as JavaScriptParseTreeWriter, ObjectLiteralExpression} from 'traceur/src/outputgeneration/ParseTreeWriter';

export class DartTreeWriter extends JavaScriptParseTreeWriter {
constructor(moduleName, outputPath) {
Expand Down Expand Up @@ -108,6 +108,14 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {
// 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_;
Expand All @@ -119,7 +127,7 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {

if (tree.initializer) {
this.writeSpace_();
this.write_(EQUAL);
this.write_(initSeparator);
this.writeSpace_();
this.visitAny(tree.initializer);
}
Expand Down Expand Up @@ -251,6 +259,10 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {
this.writeSpace_()
}

visitNamedParamsExpression(tree) {
this.writeList_(tree.propertyNameAndValues, COMMA, false);
}

toString() {
return "library " + this.libName + ";\n" + super.toString();
}
Expand Down