Initial AST structure for record literals

Change-Id: I225365b90d2e006116b3a91307479839df07ec10
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255140
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index e4f6a79..5038cbd 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -4063,6 +4063,25 @@
   Expression? get target;
 }
 
+/// A record literal.
+///
+///    recordLiteral ::= '(' recordField (',' recordField)* ','? ')'
+///
+///    recordField  ::= (identifier ':')? [Expression]
+///
+/// Clients may not extend, implement or mix-in this class.
+@experimental
+abstract class RecordLiteral implements Literal {
+  /// Return the syntactic elements used to compute the fields of the record.
+  NodeList<Expression> get fields;
+
+  /// Return the left parenthesis.
+  Token get leftParenthesis;
+
+  /// Return the right parenthesis.
+  Token get rightParenthesis;
+}
+
 /// A record type.
 ///
 /// recordType ::=
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 36e3ba0..1345044 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -9644,6 +9644,60 @@
       identical(descendant, _target);
 }
 
+class RecordLiteralImpl extends LiteralImpl implements RecordLiteral {
+  @override
+  Token leftParenthesis;
+
+  /// The syntactic elements used to compute the fields of the record.
+  final NodeListImpl<Expression> _fields = NodeListImpl._();
+
+  @override
+  Token rightParenthesis;
+
+  /// Initialize a newly created record literal.
+  RecordLiteralImpl(
+      {required this.leftParenthesis,
+      required List<Expression> fields,
+      required this.rightParenthesis}) {
+    _fields._initialize(this, fields);
+  }
+
+  @override
+  Token get beginToken => leftParenthesis;
+
+  @override
+  Token get endToken => rightParenthesis;
+
+  @override
+  NodeList<Expression> get fields => _fields;
+
+  @override
+  // TODO(paulberry): add commas.
+  ChildEntities get _childEntities => super._childEntities
+    ..addToken('leftParenthesis', leftParenthesis)
+    ..addNodeList('fields', fields)
+    ..addToken('rightParenthesis', rightParenthesis);
+
+  @override
+  E? accept<E>(AstVisitor<E> visitor) {
+    // TODO: implement accept
+    throw UnimplementedError();
+    // visitor.visitRecordLiteral(this);
+  }
+
+  @override
+  void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
+    // TODO: implement resolveExpression
+    throw UnimplementedError();
+    // resolver.visitRecordLiteral(this, contextType: contextType);
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _fields.accept(visitor);
+  }
+}
+
 /// The invocation of a constructor in the same class from within a
 /// constructor's initialization list.
 ///