Index: lib/src/js/type_printer.dart |
diff --git a/lib/src/js/type_printer.dart b/lib/src/js/type_printer.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5f47711e294adab525c5cd6d5abc9f6d252bf135 |
--- /dev/null |
+++ b/lib/src/js/type_printer.dart |
@@ -0,0 +1,226 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of js_ast; |
+ |
+abstract class _TypePrinterBase implements TypeRefVisitor { |
+ void out(String s); |
+ void visit(Node node); |
+ |
+ void outSeparated(String separator, Iterable items, [action(dynamic item)]) { |
+ action ??= visit; |
+ var first = true; |
+ for (var item in items) { |
+ if (first) { |
+ first = false; |
+ } else { |
+ out(separator); |
+ } |
+ action(item); |
+ } |
+ } |
+ |
+ void outTypeArg(Iterable<TypeRef> typeArgs) { |
+ if (typeArgs.isNotEmpty) { |
+ // TODO(ochafik): Double-check precedence issues when we start emitting |
+ // type arguments outside type literals (generic method call, etc). |
+ out('<'); |
+ outSeparated(", ", typeArgs); |
+ out('>'); |
+ } |
+ } |
+ |
+ @override |
+ visitQualifiedTypeRef(QualifiedTypeRef node) { |
+ outSeparated(".", node.path); |
+ } |
+} |
+ |
+abstract class TypeScriptTypePrinter extends _TypePrinterBase { |
+ |
+ void _outTypeAnnotation(TypeRef type) { |
+ if (type is OptionalTypeRef) { |
+ out("?: "); |
+ visit(type.type); |
+ } else { |
+ out(": "); |
+ visit(type); |
+ } |
+ } |
+ |
+ @override |
+ visitGenericTypeRef(GenericTypeRef node) { |
+ if (node.rawType is FunctionTypeRef) { |
+ outTypeArg(node.typeArgs); |
+ visit(node.rawType); |
+ } else { |
+ visit(node.rawType); |
+ outTypeArg(node.typeArgs); |
+ } |
+ } |
+ |
+ @override |
+ visitArrayTypeRef(ArrayTypeRef node) { |
+ if (node.elementType == null) { |
+ out("Array"); |
+ } else { |
+ visit(node.elementType); |
+ out("[]"); |
+ } |
+ } |
+ |
+ @override |
+ visitOptionalTypeRef(OptionalTypeRef node) { |
+ visit(node.type); |
+ } |
+ |
+ @override |
+ visitRecordTypeRef(RecordTypeRef node) { |
+ out('{'); |
+ outSeparated(", ", node.types.keys, (Identifier name) { |
+ var type = node.types[name]; |
+ visit(name); |
+ _outTypeAnnotation(type); |
+ }); |
+ out('}'); |
+ } |
+ |
+ @override |
+ visitUnionTypeRef(UnionTypeRef node) { |
+ outSeparated("|", node.types.where((t) => !t.isNull)); |
+ } |
+ |
+ @override |
+ visitFunctionTypeRef(FunctionTypeRef node) { |
+ if (node.returnType == null) { |
+ out('Function'); |
+ } else { |
+ out('('); |
+ if (node.paramTypes == null) { |
+ out('...any'); |
+ } else { |
+ outSeparated(", ", node.paramTypes.keys, (name) { |
+ var paramType = node.paramTypes[name]; |
+ visit(name); |
+ _outTypeAnnotation(paramType); |
+ }); |
+ } |
+ out(') => '); |
+ visit(node.returnType); |
+ } |
+ } |
+ |
+ @override |
+ visitAnyTypeRef(AnyTypeRef node) { |
+ out("any"); |
+ } |
+ |
+ @override |
+ visitUnknownTypeRef(UnknownTypeRef node) { |
+ out("any"); |
+ } |
+} |
+ |
+class ClosureTypePrinter extends _TypePrinterBase implements NodeVisitor { |
+ final _buffer = new StringBuffer(); |
+ |
+ @override |
+ void out(String s) => _buffer.write(s); |
+ |
+ @override |
+ void visit(Node node) => node.accept(this); |
+ |
+ noSuchMethod(Invocation i) => super.noSuchMethod(i); |
+ |
+ @override |
+ visitGenericTypeRef(GenericTypeRef node) { |
+ visit(node.rawType); |
+ outTypeArg(node.typeArgs); |
+ } |
+ |
+ @override |
+ visitIdentifier(Identifier node) { |
+ //out(localNamer.getName(node)); |
+ out(node.name); |
+ } |
+ |
+ @override |
+ visitAccess(PropertyAccess node) { |
+ var selector = node.selector; |
+ assert(selector is LiteralString); |
+ if (selector is! LiteralString) { |
+ out("?"); |
+ return; |
+ } |
+ visit(node.receiver); |
+ out("."); |
+ out(selector.valueWithoutQuotes); |
+ } |
+ |
+ @override toString() => _buffer.toString(); |
+ |
+ @override |
+ visitArrayTypeRef(ArrayTypeRef node) { |
+ out("Array"); |
+ if (node.elementType != null) { |
+ out("<"); |
+ visit(node.elementType); |
+ out(">"); |
+ } |
+ } |
+ |
+ @override |
+ visitOptionalTypeRef(OptionalTypeRef node) { |
+ visit(node.type); |
+ out("="); |
+ } |
+ |
+ @override |
+ visitRecordTypeRef(RecordTypeRef node) { |
+ out('{'); |
+ outSeparated(", ", node.types.keys, (Identifier name) { |
+ var type = node.types[name]; |
+ visit(name); |
+ out(": "); |
+ visit(type is OptionalTypeRef ? type.orUndefined() : type); |
+ }); |
+ out('}'); |
+ } |
+ |
+ @override |
+ visitAnyTypeRef(AnyTypeRef node) { |
+ out("*"); |
+ } |
+ |
+ @override |
+ visitUnknownTypeRef(UnknownTypeRef node) { |
+ out("?"); |
+ } |
+ |
+ @override |
+ visitUnionTypeRef(UnionTypeRef node) { |
+ out("("); |
+ outSeparated("|", node.types); |
+ out(")"); |
+ } |
+ |
+ @override |
+ visitFunctionTypeRef(FunctionTypeRef node) { |
+ if (node.returnType == null) { |
+ out('Function'); |
+ } else { |
+ out('function('); |
+ if (node.paramTypes == null) { |
+ out("...*"); |
+ } else { |
+ outSeparated(", ", node.paramTypes.values); |
+ } |
+ out(')'); |
+ if (node.returnType != null) { |
+ out(":"); |
+ visit(node.returnType); |
+ } |
+ } |
+ } |
+} |