From 8e6326f838b778d53f20b065c3134752007c116e Mon Sep 17 00:00:00 2001 From: Tommy Odom Date: Sun, 2 Nov 2014 14:21:11 -0500 Subject: [PATCH] feat(transpiler): allow @CONST annotation on class Closes #148 --- tools/transpiler/spec/classes_spec.js | 8 +++ .../src/codegeneration/ClassTransformer.js | 55 ++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/tools/transpiler/spec/classes_spec.js b/tools/transpiler/spec/classes_spec.js index 5032b4fd24..da87bb2507 100644 --- a/tools/transpiler/spec/classes_spec.js +++ b/tools/transpiler/spec/classes_spec.js @@ -21,6 +21,9 @@ class SubFoo extends Foo { } } +@CONST +class ConstClass {} + class Const { @CONST constructor(a:number) { @@ -62,6 +65,11 @@ export function main() { expect(subConst.b).toBe(2); }); + it('@CONST on class without constructor should generate const constructor', function () { + var constClass = new ConstClass(); + expect(constClass).not.toBe(null); + }); + describe('inheritance', function() { it('should support super call', function () { var subFoo = new SubFoo(1, 2); diff --git a/tools/transpiler/src/codegeneration/ClassTransformer.js b/tools/transpiler/src/codegeneration/ClassTransformer.js index 60706a5cfa..0dd5fc7a3a 100644 --- a/tools/transpiler/src/codegeneration/ClassTransformer.js +++ b/tools/transpiler/src/codegeneration/ClassTransformer.js @@ -19,6 +19,8 @@ import {propName} from 'traceur/src/staticsemantics/PropName'; import { BinaryExpression, BindingIdentifier, + FormalParameterList, + FunctionBody, IdentifierExpression } from 'traceur/src/syntax/trees/ParseTrees'; @@ -48,6 +50,7 @@ export class ClassTransformer extends ParseTreeTransformer { var argumentTypesMap = {}; var fields = []; var isConst; + var hasConstructor = false; var that = this; tree.elements.forEach(function(elementTree, index) { @@ -55,8 +58,8 @@ export class ClassTransformer extends ParseTreeTransformer { !elementTree.isStatic && propName(elementTree) === CONSTRUCTOR) { - isConst = elementTree.annotations.some((annotation) => - annotation.name.identifierToken.value === 'CONST'); + 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. @@ -124,6 +127,26 @@ export class ClassTransformer extends ParseTreeTransformer { } }); + // 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); + } + } + // Add the field definitions to the beginning of the class. tree.elements = fields.concat(tree.elements); @@ -183,4 +206,32 @@ export class ClassTransformer extends ParseTreeTransformer { body.statements = statements; return superCall; } + + /** + * Extract the @CONST annotation from the class annotations. + * When found the annotation is removed from the class annotations and returned. + */ + _extractConstAnnotation(tree) { + var annotations = []; + var constAnnotation = null; + var that = this; + + tree.annotations.forEach((annotation) => { + if (that._isConstAnnotation(annotation)) { + constAnnotation = annotation; + } else { + annotations.push(annotation); + } + }); + + tree.annotations = annotations; + return constAnnotation; + } + /** + * Returns true if the annotation is @CONST + */ + _isConstAnnotation(annotation) { + return annotation.name.identifierToken.value === 'CONST'; + } + }