diff --git a/tools/transpiler/spec/interfaces_spec.js b/tools/transpiler/spec/interfaces_spec.js new file mode 100644 index 0000000000..40a62ec968 --- /dev/null +++ b/tools/transpiler/spec/interfaces_spec.js @@ -0,0 +1,22 @@ +import {ddescribe, describe, it, expect, IS_DARTIUM} from 'test_lib/test_lib'; +import {IMPLEMENTS} from './fixtures/annotations'; + +class Interface1 {} +class Interface2 {} + +@IMPLEMENTS(Interface1, Interface2) +class SomeClass {} + +export function main() { + describe('interfaces', function() { + //TODO: remvoe when interfaces are supported in AtScript + if (IS_DARTIUM) { + it('should work', function () { + var s = new SomeClass(); + expect(s instanceof Interface1).toBeTrue(); + expect(s instanceof Interface2).toBeTrue(); + }); + } + }); + +} diff --git a/tools/transpiler/src/codegeneration/ClassTransformer.js b/tools/transpiler/src/codegeneration/ClassTransformer.js index 05f8a26c3c..cd4496f797 100644 --- a/tools/transpiler/src/codegeneration/ClassTransformer.js +++ b/tools/transpiler/src/codegeneration/ClassTransformer.js @@ -25,7 +25,8 @@ import { } from 'traceur/src/syntax/trees/ParseTrees'; import { - PropertyConstructorAssignment + PropertyConstructorAssignment, + ImplementsDeclaration } from '../syntax/trees/ParseTrees'; /** @@ -122,6 +123,13 @@ export class ClassTransformer extends ParseTreeTransformer { } } + 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) { @@ -187,26 +195,38 @@ export class ClassTransformer extends ParseTreeTransformer { 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 constAnnotation = null; - var that = this; + var extractedAnnotation = null; tree.annotations.forEach((annotation) => { - if (that._isConstAnnotation(annotation)) { - constAnnotation = annotation; + if (predicate(annotation)) { + extractedAnnotation = annotation; } else { annotations.push(annotation); } }); tree.annotations = annotations; - return constAnnotation; + return extractedAnnotation; } + /** * Returns true if the annotation is @CONST */ @@ -214,4 +234,11 @@ export class ClassTransformer extends ParseTreeTransformer { return annotation.name.identifierToken.value === 'CONST'; } + /** + * Returns true if the annotation is @IMPLEMENTS + */ + _isImplementsAnnotation(annotation) { + return annotation.name.identifierToken.value === 'IMPLEMENTS'; + } + } diff --git a/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js b/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js index 55c3cb4f7e..609cde6b57 100644 --- a/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js +++ b/tools/transpiler/src/outputgeneration/DartParseTreeWriter.js @@ -1,6 +1,7 @@ import {CONSTRUCTOR, FROM} from 'traceur/src/syntax/PredefinedName'; import { AT, + CLASS, CLOSE_CURLY, CLOSE_PAREN, CLOSE_SQUARE, @@ -8,6 +9,8 @@ import { COMMA, EQUAL, EQUAL_EQUAL_EQUAL, + EXTENDS, + IMPLEMENTS, IMPORT, OPEN_CURLY, OPEN_PAREN, @@ -456,6 +459,32 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter { 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.libName + ";\n" + super.toString(); } diff --git a/tools/transpiler/src/syntax/trees/ParseTreeType.js b/tools/transpiler/src/syntax/trees/ParseTreeType.js index 9fe08500df..a20fb797a9 100644 --- a/tools/transpiler/src/syntax/trees/ParseTreeType.js +++ b/tools/transpiler/src/syntax/trees/ParseTreeType.js @@ -2,3 +2,4 @@ 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"; diff --git a/tools/transpiler/src/syntax/trees/ParseTrees.js b/tools/transpiler/src/syntax/trees/ParseTrees.js index 6a991cbc63..4e66fe3aaf 100644 --- a/tools/transpiler/src/syntax/trees/ParseTrees.js +++ b/tools/transpiler/src/syntax/trees/ParseTrees.js @@ -137,4 +137,41 @@ export class ObjectPatternBindingElement extends ParseTree { return OBJECT_PATTERN_BINDING_ELEMENT; } } + +export class ImplementsDeclaration extends ParseTree { + /** + * @param {SourceRange} location + * @param {Array.} interfaces + */ + constructor(location, interfaces) { + this.location = 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;