OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of js_ast; | 5 part of js_ast; |
6 | 6 |
7 abstract class NodeVisitor<T> { | 7 abstract class NodeVisitor<T> implements TypeRefVisitor<T> { |
8 T visitProgram(Program node); | 8 T visitProgram(Program node); |
9 | 9 |
10 T visitBlock(Block node); | 10 T visitBlock(Block node); |
11 T visitExpressionStatement(ExpressionStatement node); | 11 T visitExpressionStatement(ExpressionStatement node); |
12 T visitEmptyStatement(EmptyStatement node); | 12 T visitEmptyStatement(EmptyStatement node); |
13 T visitIf(If node); | 13 T visitIf(If node); |
14 T visitFor(For node); | 14 T visitFor(For node); |
15 T visitForIn(ForIn node); | 15 T visitForIn(ForIn node); |
16 T visitForOf(ForOf node); | 16 T visitForOf(ForOf node); |
17 T visitWhile(While node); | 17 T visitWhile(While node); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 T visitInterpolatedStatement(InterpolatedStatement node); | 88 T visitInterpolatedStatement(InterpolatedStatement node); |
89 T visitInterpolatedMethod(InterpolatedMethod node); | 89 T visitInterpolatedMethod(InterpolatedMethod node); |
90 T visitInterpolatedIdentifier(InterpolatedIdentifier node); | 90 T visitInterpolatedIdentifier(InterpolatedIdentifier node); |
91 | 91 |
92 T visitArrayBindingPattern(ArrayBindingPattern node); | 92 T visitArrayBindingPattern(ArrayBindingPattern node); |
93 T visitObjectBindingPattern(ObjectBindingPattern node); | 93 T visitObjectBindingPattern(ObjectBindingPattern node); |
94 T visitDestructuredVariable(DestructuredVariable node); | 94 T visitDestructuredVariable(DestructuredVariable node); |
95 T visitSimpleBindingPattern(SimpleBindingPattern node); | 95 T visitSimpleBindingPattern(SimpleBindingPattern node); |
96 } | 96 } |
97 | 97 |
| 98 abstract class TypeRefVisitor<T> { |
| 99 T visitQualifiedTypeRef(QualifiedTypeRef node); |
| 100 T visitGenericTypeRef(GenericTypeRef node); |
| 101 T visitUnionTypeRef(UnionTypeRef node); |
| 102 T visitRecordTypeRef(RecordTypeRef node); |
| 103 T visitOptionalTypeRef(OptionalTypeRef node); |
| 104 T visitFunctionTypeRef(FunctionTypeRef node); |
| 105 T visitAnyTypeRef(AnyTypeRef node); |
| 106 T visitUnknownTypeRef(UnknownTypeRef node); |
| 107 T visitArrayTypeRef(ArrayTypeRef node); |
| 108 } |
| 109 |
98 class BaseVisitor<T> implements NodeVisitor<T> { | 110 class BaseVisitor<T> implements NodeVisitor<T> { |
99 T visitNode(Node node) { | 111 T visitNode(Node node) { |
100 node.visitChildren(this); | 112 node.visitChildren(this); |
101 return null; | 113 return null; |
102 } | 114 } |
103 | 115 |
104 T visitProgram(Program node) => visitNode(node); | 116 T visitProgram(Program node) => visitNode(node); |
105 | 117 |
106 T visitStatement(Statement node) => visitModuleItem(node); | 118 T visitStatement(Statement node) => visitModuleItem(node); |
107 T visitLoop(Loop node) => visitStatement(node); | 119 T visitLoop(Loop node) => visitStatement(node); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 T visitAwait(Await node) => visitExpression(node); | 228 T visitAwait(Await node) => visitExpression(node); |
217 T visitDartYield(DartYield node) => visitStatement(node); | 229 T visitDartYield(DartYield node) => visitStatement(node); |
218 | 230 |
219 T visitBindingPattern(BindingPattern node) => visitNode(node); | 231 T visitBindingPattern(BindingPattern node) => visitNode(node); |
220 T visitArrayBindingPattern(ArrayBindingPattern node) | 232 T visitArrayBindingPattern(ArrayBindingPattern node) |
221 => visitBindingPattern(node); | 233 => visitBindingPattern(node); |
222 T visitObjectBindingPattern(ObjectBindingPattern node) | 234 T visitObjectBindingPattern(ObjectBindingPattern node) |
223 => visitBindingPattern(node); | 235 => visitBindingPattern(node); |
224 T visitDestructuredVariable(DestructuredVariable node) => visitNode(node); | 236 T visitDestructuredVariable(DestructuredVariable node) => visitNode(node); |
225 T visitSimpleBindingPattern(SimpleBindingPattern node) => visitNode(node); | 237 T visitSimpleBindingPattern(SimpleBindingPattern node) => visitNode(node); |
| 238 |
| 239 T visitTypeRef(TypeRef node) => visitNode(node); |
| 240 T visitQualifiedTypeRef(QualifiedTypeRef node) => visitTypeRef(node); |
| 241 T visitGenericTypeRef(GenericTypeRef node) => visitTypeRef(node); |
| 242 T visitOptionalTypeRef(OptionalTypeRef node) => visitTypeRef(node); |
| 243 T visitRecordTypeRef(RecordTypeRef node) => visitTypeRef(node); |
| 244 T visitUnionTypeRef(UnionTypeRef node) => visitTypeRef(node); |
| 245 T visitFunctionTypeRef(FunctionTypeRef node) => visitTypeRef(node); |
| 246 T visitAnyTypeRef(AnyTypeRef node) => visitTypeRef(node); |
| 247 T visitUnknownTypeRef(UnknownTypeRef node) => visitTypeRef(node); |
| 248 T visitArrayTypeRef(ArrayTypeRef node) => visitTypeRef(node); |
226 } | 249 } |
227 | 250 |
228 abstract class Node { | 251 abstract class Node { |
229 /// Sets the source location of this node. For performance reasons, we allow | 252 /// Sets the source location of this node. For performance reasons, we allow |
230 /// setting this after construction. | 253 /// setting this after construction. |
231 Object sourceInformation; | 254 Object sourceInformation; |
232 | 255 |
233 ClosureAnnotation _closureAnnotation; | 256 ClosureAnnotation _closureAnnotation; |
234 /// Closure annotation of this node. | 257 /// Closure annotation of this node. |
235 ClosureAnnotation get closureAnnotation => _closureAnnotation; | 258 ClosureAnnotation get closureAnnotation => _closureAnnotation; |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 } | 799 } |
777 | 800 |
778 abstract class VariableBinding extends Expression { | 801 abstract class VariableBinding extends Expression { |
779 } | 802 } |
780 | 803 |
781 class DestructuredVariable extends Expression implements Parameter { | 804 class DestructuredVariable extends Expression implements Parameter { |
782 /// [LiteralString] or [Identifier]. | 805 /// [LiteralString] or [Identifier]. |
783 final Expression name; | 806 final Expression name; |
784 final BindingPattern structure; | 807 final BindingPattern structure; |
785 final Expression defaultValue; | 808 final Expression defaultValue; |
786 DestructuredVariable({this.name, this.structure, this.defaultValue}) { | 809 final TypeRef type; |
| 810 DestructuredVariable({this.name, this.structure, this.defaultValue, this.type}
) { |
787 assert(name != null || structure != null); | 811 assert(name != null || structure != null); |
788 } | 812 } |
789 | 813 |
790 accept(NodeVisitor visitor) => visitor.visitDestructuredVariable(this); | 814 accept(NodeVisitor visitor) => visitor.visitDestructuredVariable(this); |
791 void visitChildren(NodeVisitor visitor) { | 815 void visitChildren(NodeVisitor visitor) { |
792 name?.accept(visitor); | 816 name?.accept(visitor); |
793 structure?.accept(visitor); | 817 structure?.accept(visitor); |
794 defaultValue?.accept(visitor); | 818 defaultValue?.accept(visitor); |
795 } | 819 } |
796 | 820 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 | 1053 |
1030 Postfix _clone() => new Postfix(op, argument); | 1054 Postfix _clone() => new Postfix(op, argument); |
1031 | 1055 |
1032 void visitChildren(NodeVisitor visitor) { | 1056 void visitChildren(NodeVisitor visitor) { |
1033 argument.accept(visitor); | 1057 argument.accept(visitor); |
1034 } | 1058 } |
1035 | 1059 |
1036 int get precedenceLevel => UNARY; | 1060 int get precedenceLevel => UNARY; |
1037 } | 1061 } |
1038 | 1062 |
1039 abstract class Parameter implements Expression, VariableBinding {} | 1063 abstract class Parameter implements Expression, VariableBinding { |
| 1064 TypeRef get type; |
| 1065 } |
1040 | 1066 |
1041 class Identifier extends Expression implements Parameter, VariableBinding { | 1067 class Identifier extends Expression implements Parameter, VariableBinding { |
1042 final String name; | 1068 final String name; |
1043 final bool allowRename; | 1069 final bool allowRename; |
| 1070 final TypeRef type; |
1044 | 1071 |
1045 Identifier(this.name, {this.allowRename: true}) { | 1072 Identifier(this.name, {this.allowRename: true, this.type}) { |
1046 assert(_identifierRE.hasMatch(name)); | 1073 if (!_identifierRE.hasMatch(name)) { |
| 1074 throw new ArgumentError.value(name, "name", "not a valid identifier"); |
| 1075 } |
1047 } | 1076 } |
1048 static RegExp _identifierRE = new RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$'); | 1077 static RegExp _identifierRE = new RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$'); |
1049 | 1078 |
1050 Identifier _clone() => | 1079 Identifier _clone() => |
1051 new Identifier(name, allowRename: allowRename); | 1080 new Identifier(name, allowRename: allowRename); |
1052 accept(NodeVisitor visitor) => visitor.visitIdentifier(this); | 1081 accept(NodeVisitor visitor) => visitor.visitIdentifier(this); |
1053 int get precedenceLevel => PRIMARY; | 1082 int get precedenceLevel => PRIMARY; |
1054 void visitChildren(NodeVisitor visitor) {} | 1083 void visitChildren(NodeVisitor visitor) {} |
1055 } | 1084 } |
1056 | 1085 |
1057 // This is an expression for convenience in the AST. | 1086 // This is an expression for convenience in the AST. |
1058 class RestParameter extends Expression implements Parameter { | 1087 class RestParameter extends Expression implements Parameter { |
1059 final Identifier parameter; | 1088 final Identifier parameter; |
| 1089 TypeRef get type => null; |
1060 | 1090 |
1061 RestParameter(this.parameter); | 1091 RestParameter(this.parameter); |
1062 | 1092 |
1063 RestParameter _clone() => new RestParameter(parameter); | 1093 RestParameter _clone() => new RestParameter(parameter); |
1064 accept(NodeVisitor visitor) => visitor.visitRestParameter(this); | 1094 accept(NodeVisitor visitor) => visitor.visitRestParameter(this); |
1065 void visitChildren(NodeVisitor visitor) { | 1095 void visitChildren(NodeVisitor visitor) { |
1066 parameter.accept(visitor); | 1096 parameter.accept(visitor); |
1067 } | 1097 } |
1068 int get precedenceLevel => PRIMARY; | 1098 int get precedenceLevel => PRIMARY; |
1069 } | 1099 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 name.accept(visitor); | 1144 name.accept(visitor); |
1115 function.accept(visitor); | 1145 function.accept(visitor); |
1116 } | 1146 } |
1117 NamedFunction _clone() => new NamedFunction(name, function); | 1147 NamedFunction _clone() => new NamedFunction(name, function); |
1118 | 1148 |
1119 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; | 1149 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; |
1120 } | 1150 } |
1121 | 1151 |
1122 abstract class FunctionExpression extends Expression { | 1152 abstract class FunctionExpression extends Expression { |
1123 List<Parameter> get params; | 1153 List<Parameter> get params; |
| 1154 |
1124 get body; // Expression or block | 1155 get body; // Expression or block |
| 1156 /// Type parameters passed to this generic function, if any. `null` otherwise. |
| 1157 // TODO(ochafik): Support type bounds. |
| 1158 List<Identifier> get typeParams; |
| 1159 /// Return type of this function, if any. `null` otherwise. |
| 1160 TypeRef get returnType; |
1125 } | 1161 } |
1126 | 1162 |
1127 class Fun extends FunctionExpression { | 1163 class Fun extends FunctionExpression { |
1128 final List<Parameter> params; | 1164 final List<Parameter> params; |
1129 final Block body; | 1165 final Block body; |
| 1166 @override final List<Identifier> typeParams; |
| 1167 @override final TypeRef returnType; |
1130 /** Whether this is a JS generator (`function*`) that may contain `yield`. */ | 1168 /** Whether this is a JS generator (`function*`) that may contain `yield`. */ |
1131 final bool isGenerator; | 1169 final bool isGenerator; |
1132 | 1170 |
1133 final AsyncModifier asyncModifier; | 1171 final AsyncModifier asyncModifier; |
1134 | 1172 |
1135 Fun(this.params, this.body, {this.isGenerator: false, | 1173 Fun(this.params, this.body, {this.isGenerator: false, |
1136 this.asyncModifier: const AsyncModifier.sync()}); | 1174 this.asyncModifier: const AsyncModifier.sync(), |
| 1175 this.typeParams, this.returnType}); |
1137 | 1176 |
1138 accept(NodeVisitor visitor) => visitor.visitFun(this); | 1177 accept(NodeVisitor visitor) => visitor.visitFun(this); |
1139 | 1178 |
1140 void visitChildren(NodeVisitor visitor) { | 1179 void visitChildren(NodeVisitor visitor) { |
1141 for (Parameter param in params) param.accept(visitor); | 1180 for (Parameter param in params) param.accept(visitor); |
1142 body.accept(visitor); | 1181 body.accept(visitor); |
1143 } | 1182 } |
1144 | 1183 |
1145 Fun _clone() => new Fun(params, body, | 1184 Fun _clone() => new Fun(params, body, |
1146 isGenerator: isGenerator, asyncModifier: asyncModifier); | 1185 isGenerator: isGenerator, asyncModifier: asyncModifier); |
1147 | 1186 |
1148 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; | 1187 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; |
1149 } | 1188 } |
1150 | 1189 |
1151 class ArrowFun extends FunctionExpression { | 1190 class ArrowFun extends FunctionExpression { |
1152 final List<Parameter> params; | 1191 final List<Parameter> params; |
1153 final body; // Expression or Block | 1192 final body; // Expression or Block |
| 1193 @override final List<Identifier> typeParams; |
| 1194 @override final TypeRef returnType; |
1154 | 1195 |
1155 ArrowFun(this.params, this.body); | 1196 ArrowFun(this.params, this.body, {this.typeParams, this.returnType}); |
1156 | 1197 |
1157 accept(NodeVisitor visitor) => visitor.visitArrowFun(this); | 1198 accept(NodeVisitor visitor) => visitor.visitArrowFun(this); |
1158 | 1199 |
1159 void visitChildren(NodeVisitor visitor) { | 1200 void visitChildren(NodeVisitor visitor) { |
1160 for (Parameter param in params) param.accept(visitor); | 1201 for (Parameter param in params) param.accept(visitor); |
1161 body.accept(visitor); | 1202 body.accept(visitor); |
1162 } | 1203 } |
1163 | 1204 |
1164 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; | 1205 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; |
1165 | 1206 |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1432 | 1473 |
1433 accept(NodeVisitor visitor) => visitor.visitClassDeclaration(this); | 1474 accept(NodeVisitor visitor) => visitor.visitClassDeclaration(this); |
1434 visitChildren(NodeVisitor visitor) => classExpr.accept(visitor); | 1475 visitChildren(NodeVisitor visitor) => classExpr.accept(visitor); |
1435 ClassDeclaration _clone() => new ClassDeclaration(classExpr); | 1476 ClassDeclaration _clone() => new ClassDeclaration(classExpr); |
1436 } | 1477 } |
1437 | 1478 |
1438 class ClassExpression extends Expression { | 1479 class ClassExpression extends Expression { |
1439 final Identifier name; | 1480 final Identifier name; |
1440 final Expression heritage; // Can be null. | 1481 final Expression heritage; // Can be null. |
1441 final List<Method> methods; | 1482 final List<Method> methods; |
| 1483 /// Type parameters of this class, if any. `null` otherwise. |
| 1484 // TODO(ochafik): Support type bounds. |
| 1485 final List<Identifier> typeParams; |
| 1486 /// Field declarations of this class (TypeScript / ES6_TYPED). |
| 1487 final List<VariableDeclarationList> fields; |
1442 | 1488 |
1443 ClassExpression(this.name, this.heritage, this.methods); | 1489 ClassExpression(this.name, this.heritage, this.methods, |
| 1490 {this.typeParams, this.fields}); |
1444 | 1491 |
1445 accept(NodeVisitor visitor) => visitor.visitClassExpression(this); | 1492 accept(NodeVisitor visitor) => visitor.visitClassExpression(this); |
1446 | 1493 |
1447 void visitChildren(NodeVisitor visitor) { | 1494 void visitChildren(NodeVisitor visitor) { |
1448 name.accept(visitor); | 1495 name.accept(visitor); |
1449 if (heritage != null) heritage.accept(visitor); | 1496 if (heritage != null) heritage.accept(visitor); |
1450 for (Method element in methods) element.accept(visitor); | 1497 for (Method element in methods) element.accept(visitor); |
| 1498 if (fields != null) { |
| 1499 for (var field in fields) { |
| 1500 field.accept(visitor); |
| 1501 } |
| 1502 } |
| 1503 if (typeParams != null) { |
| 1504 for (var typeParam in typeParams) { |
| 1505 typeParam.accept(visitor); |
| 1506 } |
| 1507 } |
1451 } | 1508 } |
1452 | 1509 |
1453 ClassExpression _clone() => new ClassExpression(name, heritage, methods); | 1510 ClassExpression _clone() => new ClassExpression( |
| 1511 name, heritage, methods, typeParams: typeParams, fields: fields); |
1454 | 1512 |
1455 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; | 1513 int get precedenceLevel => PRIMARY_LOW_PRECEDENCE; |
1456 } | 1514 } |
1457 | 1515 |
1458 class Method extends Property { | 1516 class Method extends Property { |
1459 final bool isGetter; | 1517 final bool isGetter; |
1460 final bool isSetter; | 1518 final bool isSetter; |
1461 final bool isStatic; | 1519 final bool isStatic; |
1462 | 1520 |
1463 Method(Expression name, Fun function, | 1521 Method(Expression name, Fun function, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1508 InterpolatedLiteral(this.nameOrPosition); | 1566 InterpolatedLiteral(this.nameOrPosition); |
1509 | 1567 |
1510 accept(NodeVisitor visitor) => visitor.visitInterpolatedLiteral(this); | 1568 accept(NodeVisitor visitor) => visitor.visitInterpolatedLiteral(this); |
1511 void visitChildren(NodeVisitor visitor) {} | 1569 void visitChildren(NodeVisitor visitor) {} |
1512 InterpolatedLiteral _clone() => new InterpolatedLiteral(nameOrPosition); | 1570 InterpolatedLiteral _clone() => new InterpolatedLiteral(nameOrPosition); |
1513 } | 1571 } |
1514 | 1572 |
1515 class InterpolatedParameter extends Expression with InterpolatedNode | 1573 class InterpolatedParameter extends Expression with InterpolatedNode |
1516 implements Identifier { | 1574 implements Identifier { |
1517 final nameOrPosition; | 1575 final nameOrPosition; |
| 1576 TypeRef get type => null; |
1518 | 1577 |
1519 String get name { throw "InterpolatedParameter.name must not be invoked"; } | 1578 String get name { throw "InterpolatedParameter.name must not be invoked"; } |
1520 bool get allowRename => false; | 1579 bool get allowRename => false; |
1521 | 1580 |
1522 InterpolatedParameter(this.nameOrPosition); | 1581 InterpolatedParameter(this.nameOrPosition); |
1523 | 1582 |
1524 accept(NodeVisitor visitor) => visitor.visitInterpolatedParameter(this); | 1583 accept(NodeVisitor visitor) => visitor.visitInterpolatedParameter(this); |
1525 void visitChildren(NodeVisitor visitor) {} | 1584 void visitChildren(NodeVisitor visitor) {} |
1526 InterpolatedParameter _clone() => new InterpolatedParameter(nameOrPosition); | 1585 InterpolatedParameter _clone() => new InterpolatedParameter(nameOrPosition); |
1527 | 1586 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 bool get isGetter => _unsupported; | 1626 bool get isGetter => _unsupported; |
1568 bool get isSetter => _unsupported; | 1627 bool get isSetter => _unsupported; |
1569 bool get isStatic => _unsupported; | 1628 bool get isStatic => _unsupported; |
1570 Fun get function => _unsupported; | 1629 Fun get function => _unsupported; |
1571 get _unsupported => throw '$runtimeType does not support this member.'; | 1630 get _unsupported => throw '$runtimeType does not support this member.'; |
1572 } | 1631 } |
1573 | 1632 |
1574 class InterpolatedIdentifier extends Expression with InterpolatedNode | 1633 class InterpolatedIdentifier extends Expression with InterpolatedNode |
1575 implements Identifier { | 1634 implements Identifier { |
1576 final nameOrPosition; | 1635 final nameOrPosition; |
| 1636 TypeRef get type => null; |
1577 | 1637 |
1578 InterpolatedIdentifier(this.nameOrPosition); | 1638 InterpolatedIdentifier(this.nameOrPosition); |
1579 | 1639 |
1580 accept(NodeVisitor visitor) => | 1640 accept(NodeVisitor visitor) => |
1581 visitor.visitInterpolatedIdentifier(this); | 1641 visitor.visitInterpolatedIdentifier(this); |
1582 void visitChildren(NodeVisitor visitor) {} | 1642 void visitChildren(NodeVisitor visitor) {} |
1583 InterpolatedIdentifier _clone() => new InterpolatedIdentifier(nameOrPosition); | 1643 InterpolatedIdentifier _clone() => new InterpolatedIdentifier(nameOrPosition); |
1584 | 1644 |
1585 int get precedenceLevel => PRIMARY; | 1645 int get precedenceLevel => PRIMARY; |
1586 String get name => throw '$runtimeType does not support this member.'; | 1646 String get name => throw '$runtimeType does not support this member.'; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1769 | 1829 |
1770 final List<ModuleItem> body; | 1830 final List<ModuleItem> body; |
1771 Module(this.body, {this.name}); | 1831 Module(this.body, {this.name}); |
1772 | 1832 |
1773 accept(NodeVisitor visitor) => visitor.visitModule(this); | 1833 accept(NodeVisitor visitor) => visitor.visitModule(this); |
1774 void visitChildren(NodeVisitor visitor) { | 1834 void visitChildren(NodeVisitor visitor) { |
1775 for (ModuleItem item in body) item.accept(visitor); | 1835 for (ModuleItem item in body) item.accept(visitor); |
1776 } | 1836 } |
1777 Module _clone() => new Module(body); | 1837 Module _clone() => new Module(body); |
1778 } | 1838 } |
OLD | NEW |