feat(transpiler): handle named params
This commit is contained in:
parent
f9923ea7db
commit
64fe73e20d
@ -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) {
|
function sum(a, b) {
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('functions', function() {
|
describe('functions', function() {
|
||||||
it('should work', function() {
|
it('should work', function() {
|
||||||
expect(sum(1, 2)).toBe(3);
|
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
tools/transpiler/src/ast/named_params.js
Normal file
16
tools/transpiler/src/ast/named_params.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import {BindingElement} from 'traceur/src/syntax/trees/ParseTrees';
|
||||||
|
|
||||||
|
export class ObjectPatternBindingElement extends BindingElement {
|
||||||
|
visit(visitor) {
|
||||||
|
visitor.visitObjectPatternBindingElement(this);
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import {ClassTransformer} from './ClassTransformer';
|
|||||||
import {InstanceOfTransformer} from './InstanceOfTransformer';
|
import {InstanceOfTransformer} from './InstanceOfTransformer';
|
||||||
import {MultiVarTransformer} from './MultiVarTransformer';
|
import {MultiVarTransformer} from './MultiVarTransformer';
|
||||||
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
|
import {StrictEqualityTransformer} from './StrictEqualityTransformer';
|
||||||
|
import {NamedParamsTransformer} from './NamedParamsTransformer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms ES6 + annotations to Dart code.
|
* Transforms ES6 + annotations to Dart code.
|
||||||
@ -20,6 +21,7 @@ export class DartTransformer extends MultiTransformer {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
append(NamedParamsTransformer);
|
||||||
append(MultiVarTransformer);
|
append(MultiVarTransformer);
|
||||||
append(InstanceOfTransformer);
|
append(InstanceOfTransformer);
|
||||||
append(StrictEqualityTransformer);
|
append(StrictEqualityTransformer);
|
||||||
|
104
tools/transpiler/src/codegeneration/NamedParamsTransformer.js
Normal file
104
tools/transpiler/src/codegeneration/NamedParamsTransformer.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import {ParseTreeTransformer} from 'traceur/src/codegeneration/ParseTreeTransformer';
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import {CONSTRUCTOR, FROM} from 'traceur/src/syntax/PredefinedName';
|
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 {
|
export class DartTreeWriter extends JavaScriptParseTreeWriter {
|
||||||
constructor(moduleName, outputPath) {
|
constructor(moduleName, outputPath) {
|
||||||
@ -123,6 +123,14 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {
|
|||||||
// FUNCTION/METHOD ARGUMENTS
|
// FUNCTION/METHOD ARGUMENTS
|
||||||
// - type infront of the arg name
|
// - type infront of the arg name
|
||||||
visitBindingElement(tree) {
|
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,
|
// TODO(vojta): This is awful, just copy/pasted from Traceur,
|
||||||
// we should still clean it up.
|
// we should still clean it up.
|
||||||
var typeAnnotation = this.currentParameterTypeAnnotation_;
|
var typeAnnotation = this.currentParameterTypeAnnotation_;
|
||||||
@ -134,7 +142,7 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {
|
|||||||
|
|
||||||
if (tree.initializer) {
|
if (tree.initializer) {
|
||||||
this.writeSpace_();
|
this.writeSpace_();
|
||||||
this.write_(EQUAL);
|
this.write_(initSeparator);
|
||||||
this.writeSpace_();
|
this.writeSpace_();
|
||||||
this.visitAny(tree.initializer);
|
this.visitAny(tree.initializer);
|
||||||
}
|
}
|
||||||
@ -266,6 +274,10 @@ export class DartTreeWriter extends JavaScriptParseTreeWriter {
|
|||||||
this.writeSpace_()
|
this.writeSpace_()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitNamedParamsExpression(tree) {
|
||||||
|
this.writeList_(tree.propertyNameAndValues, COMMA, false);
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return "library " + this.libName + ";\n" + super.toString();
|
return "library " + this.libName + ";\n" + super.toString();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user