| Index: lib/src/js/js_types.dart
|
| diff --git a/lib/src/js/js_types.dart b/lib/src/js/js_types.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..526d19a6b067cd55e8d55d1b026373b9587e7b6b
|
| --- /dev/null
|
| +++ b/lib/src/js/js_types.dart
|
| @@ -0,0 +1,198 @@
|
| +// 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;
|
| +
|
| +final _any = new AnyTypeRef._();
|
| +final _unknown = new UnknownTypeRef._();
|
| +final _null = new NullTypeRef();
|
| +
|
| +/// JavaScript type reference, designed to support a subset of the type systems
|
| +/// of the Closure Compiler and TypeScript:
|
| +/// - https://developers.google.com/closure/compiler/docs/js-for-compiler#types
|
| +/// - https://github.com/Microsoft/TypeScript/blob/v1.8.0-beta/doc/spec.md#3
|
| +///
|
| +/// Note that some subtleties like "nullability" or "optionality" are handled
|
| +/// using unions (with a [NullTypeRef] or with an "undefined" named typeref).
|
| +/// Also, primitives aren't modeled differently than named / qualified types,
|
| +/// as it brings little value for now. Primitive-specific type formatting is
|
| +/// handled by the type printers (for instance, the knowledge that
|
| +/// `number|null` is just `number` in TypeScript, and is `number?` in Closure).
|
| +abstract class TypeRef extends Expression {
|
| +
|
| + int get precedenceLevel => PRIMARY;
|
| +
|
| + TypeRef();
|
| +
|
| + factory TypeRef.any() => _any;
|
| +
|
| + factory TypeRef.void_() => new TypeRef.named('void');
|
| +
|
| + factory TypeRef.unknown() => _unknown;
|
| +
|
| + factory TypeRef.generic(TypeRef rawType, Iterable<TypeRef> typeArgs) {
|
| + if (typeArgs.isEmpty) {
|
| + throw new ArgumentError.value(typeArgs, "typeArgs", "is empty");
|
| + }
|
| + return new GenericTypeRef(rawType, typeArgs.toList());
|
| + }
|
| +
|
| + factory TypeRef.array([TypeRef elementType]) =>
|
| + new ArrayTypeRef(elementType);
|
| +
|
| + factory TypeRef.object([TypeRef keyType, TypeRef valueType]) {
|
| + // TODO(ochafik): Roll out a dedicated ObjectTypeRef?
|
| + var rawType = new TypeRef.named('Object');
|
| + return keyType == null && valueType == null
|
| + ? rawType
|
| + : new GenericTypeRef(rawType, [keyType ?? _any, valueType ?? _any]);
|
| + }
|
| +
|
| + factory TypeRef.function(
|
| + [TypeRef returnType, Map<Identifier, TypeRef> paramTypes]) =>
|
| + new FunctionTypeRef(returnType, paramTypes);
|
| +
|
| + factory TypeRef.record(Map<Identifier, TypeRef> types) =>
|
| + new RecordTypeRef(types);
|
| +
|
| + factory TypeRef.string() => new TypeRef.named('string');
|
| +
|
| + factory TypeRef.number() => new TypeRef.named('number');
|
| +
|
| + factory TypeRef.undefined() => new TypeRef.named('undefined');
|
| +
|
| + factory TypeRef.boolean() => new TypeRef.named('boolean');
|
| +
|
| + factory TypeRef.qualified(List<Identifier> path) =>
|
| + new QualifiedTypeRef(path);
|
| +
|
| + factory TypeRef.named(String name) =>
|
| + new TypeRef.qualified(<Identifier>[new Identifier(name)]);
|
| +
|
| + bool get isAny => this is AnyTypeRef;
|
| + bool get isUnknown => this is UnknownTypeRef;
|
| + bool get isNull => this is NullTypeRef;
|
| +
|
| + TypeRef or(TypeRef other) => new UnionTypeRef([this, other]);
|
| +
|
| + TypeRef orUndefined() => or(new TypeRef.undefined());
|
| + TypeRef orNull() => or(_null);
|
| +
|
| + TypeRef toOptional() =>
|
| + new OptionalTypeRef(this);
|
| +}
|
| +
|
| +class AnyTypeRef extends TypeRef {
|
| + AnyTypeRef._() : super();
|
| +
|
| + factory AnyTypeRef() => _any;
|
| + accept(NodeVisitor visitor) => visitor.visitAnyTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {}
|
| + _clone() => new AnyTypeRef();
|
| +}
|
| +
|
| +class NullTypeRef extends QualifiedTypeRef {
|
| + NullTypeRef() : super([new Identifier("null")]);
|
| + _clone() => new NullTypeRef();
|
| +}
|
| +
|
| +class UnknownTypeRef extends TypeRef {
|
| + UnknownTypeRef._() : super();
|
| +
|
| + factory UnknownTypeRef() => _unknown;
|
| + accept(NodeVisitor visitor) => visitor.visitUnknownTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {}
|
| + _clone() => new UnknownTypeRef();
|
| +}
|
| +
|
| +class QualifiedTypeRef extends TypeRef {
|
| + final List<Identifier> path;
|
| + QualifiedTypeRef(this.path);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitQualifiedTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) =>
|
| + path.forEach((p) => p.accept(visitor));
|
| + _clone() => new QualifiedTypeRef(path);
|
| +}
|
| +
|
| +class ArrayTypeRef extends TypeRef {
|
| + final TypeRef elementType;
|
| + ArrayTypeRef(this.elementType);
|
| + accept(NodeVisitor visitor) => visitor.visitArrayTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + elementType.accept(visitor);
|
| + }
|
| + _clone() => new ArrayTypeRef(elementType);
|
| +}
|
| +
|
| +class GenericTypeRef extends TypeRef {
|
| + final TypeRef rawType;
|
| + final List<TypeRef> typeArgs;
|
| + GenericTypeRef(this.rawType, this.typeArgs);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitGenericTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + rawType.accept(visitor);
|
| + typeArgs.forEach((p) => p.accept(visitor));
|
| + }
|
| + _clone() => new GenericTypeRef(rawType, typeArgs);
|
| +}
|
| +
|
| +class UnionTypeRef extends TypeRef {
|
| + final List<TypeRef> types;
|
| + UnionTypeRef(this.types);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitUnionTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + types.forEach((p) => p.accept(visitor));
|
| + }
|
| + _clone() => new UnionTypeRef(types);
|
| +
|
| + @override
|
| + TypeRef or(TypeRef other) {
|
| + if (types.contains(other)) return this;
|
| + return new UnionTypeRef([]..addAll(types)..add(other));
|
| + }
|
| +}
|
| +
|
| +class OptionalTypeRef extends TypeRef {
|
| + final TypeRef type;
|
| + OptionalTypeRef(this.type);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitOptionalTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + type.accept(visitor);
|
| + }
|
| + _clone() => new OptionalTypeRef(type);
|
| +
|
| + @override
|
| + TypeRef orUndefined() => this;
|
| +}
|
| +
|
| +class RecordTypeRef extends TypeRef {
|
| + final Map<Identifier, TypeRef> types;
|
| + RecordTypeRef(this.types);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitRecordTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + types.values.forEach((p) => p.accept(visitor));
|
| + }
|
| + _clone() => new RecordTypeRef(types);
|
| +}
|
| +
|
| +class FunctionTypeRef extends TypeRef {
|
| + final TypeRef returnType;
|
| + final Map<Identifier, TypeRef> paramTypes;
|
| + FunctionTypeRef(this.returnType, this.paramTypes);
|
| +
|
| + accept(NodeVisitor visitor) => visitor.visitFunctionTypeRef(this);
|
| + void visitChildren(NodeVisitor visitor) {
|
| + returnType.accept(visitor);
|
| + paramTypes.forEach((n, t) {
|
| + n.accept(visitor);
|
| + t.accept(visitor);
|
| + });
|
| + }
|
| + _clone() => new FunctionTypeRef(returnType, paramTypes);
|
| +}
|
|
|