| // Copyright (c) 2019, 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. | |
| import 'dart:io'; | |
| import 'dart:typed_data'; | |
| import 'package:_fe_analyzer_shared/src/parser/experimental_features.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/parser.dart'; | |
| import 'package:_fe_analyzer_shared/src/scanner/token.dart'; | |
| import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'; | |
| import 'package:dart_style/dart_style.dart' show DartFormatter; | |
| import 'utils/io_utils.dart' show computeRepoDirUri, getPackageVersionFor; | |
| void main(List<String> args) { | |
| final Uri repoDir = computeRepoDirUri(); | |
| String generated = generateTestParser(repoDir); | |
| new File.fromUri(computeTestParserUri(repoDir)) | |
| .writeAsStringSync(generated, flush: true); | |
| } | |
| Uri computeTestParserUri(Uri repoDir) { | |
| return repoDir.resolve("pkg/front_end/test/parser_test_parser.dart"); | |
| } | |
| String generateTestParser(Uri repoDir) { | |
| StringBuffer out = new StringBuffer(); | |
| File f = new File.fromUri( | |
| repoDir.resolve("pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart"), | |
| ); | |
| Uint8List rawBytes = f.readAsBytesSync(); | |
| Utf8BytesScanner scanner = new Utf8BytesScanner( | |
| rawBytes, | |
| includeComments: true, | |
| ); | |
| Token firstToken = scanner.tokenize(); | |
| out.write(r""" | |
| // Copyright (c) 2019, 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. | |
| import 'package:_fe_analyzer_shared/src/experiments/flags.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/assert.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/block_kind.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/constructor_reference_context.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/declaration_kind.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/directive_context.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/identifier_context.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/listener.dart' show Listener; | |
| import 'package:_fe_analyzer_shared/src/parser/member_kind.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/parser.dart' | |
| show ConstantPatternContext, ExperimentalFeatures, Parser; | |
| import 'package:_fe_analyzer_shared/src/parser/parser_impl.dart' | |
| show AwaitOrYieldContext, ForPartsContext, PatternContext; | |
| import 'package:_fe_analyzer_shared/src/parser/token_stream_rewriter.dart'; | |
| import 'package:_fe_analyzer_shared/src/parser/type_info.dart'; | |
| import 'package:_fe_analyzer_shared/src/scanner/token.dart'; | |
| import 'package:front_end/src/codes/cfe_codes.dart' as codes; | |
| import 'package:front_end/src/source/diet_parser.dart' | |
| show useImplicitCreationExpressionInCfe; | |
| // THIS FILE IS AUTO GENERATED BY 'test/parser_test_parser_creator.dart' | |
| // Run this command to update it: | |
| // 'dart pkg/front_end/test/parser_test_parser_creator.dart' | |
| class TestParser extends Parser { | |
| int indent = 0; | |
| StringBuffer sb = new StringBuffer(); | |
| final bool trace; | |
| bool _inhibitPrinting = false; | |
| new(Listener listener, this.trace, | |
| {required ExperimentalFeatures experimentalFeatures}) | |
| : super(listener, | |
| useImplicitCreationExpression: useImplicitCreationExpressionInCfe, | |
| experimentalFeatures: experimentalFeatures); | |
| String createTrace() { | |
| List<String> traceLines = StackTrace.current.toString().split("\n"); | |
| for (int i = 0; i < traceLines.length; i++) { | |
| // Find first one that's not any of the denylisted ones. | |
| String line = traceLines[i]; | |
| if (line.contains("parser_test_listener.dart:") || | |
| line.contains("parser_suite.dart:") || | |
| line.contains("parser_test_parser.dart:") || | |
| line == "<asynchronous suspension>") { | |
| continue; | |
| } | |
| return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")")); | |
| } | |
| return "N/A"; | |
| } | |
| void doPrint(String s) { | |
| if (_inhibitPrinting) return; | |
| String traceString = ""; | |
| if (trace) traceString = " (${createTrace()})"; | |
| sb.writeln((" " * indent) + s + traceString); | |
| } | |
| @override | |
| T inhibitPrinting<T>(T Function() callback) { | |
| bool previousInhibitPrinting = _inhibitPrinting; | |
| _inhibitPrinting = true; | |
| try { | |
| return callback(); | |
| } finally { | |
| _inhibitPrinting = previousInhibitPrinting; | |
| } | |
| } | |
| """); | |
| ParserCreatorListener listener = new ParserCreatorListener(out); | |
| ClassMemberParser parser = new ClassMemberParser( | |
| listener, | |
| experimentalFeatures: const DefaultExperimentalFeatures(), | |
| ); | |
| parser.parseUnit(firstToken); | |
| out.writeln("}"); | |
| return new DartFormatter(languageVersion: getPackageVersionFor("front_end")) | |
| .format("$out"); | |
| } | |
| class ParserCreatorListener extends Listener { | |
| final StringSink out; | |
| bool insideParserClass = false; | |
| String? currentMethodName; | |
| List<String> parameters = []; | |
| List<String?> parametersNamed = []; | |
| new(this.out); | |
| @override | |
| void beginClassDeclaration( | |
| Token begin, | |
| Token? abstractToken, | |
| Token? sealedToken, | |
| Token? baseToken, | |
| Token? interfaceToken, | |
| Token? finalToken, | |
| Token? augmentToken, | |
| Token? mixinToken, | |
| Token name, | |
| ) { | |
| if (name.lexeme == "Parser") insideParserClass = true; | |
| } | |
| @override | |
| void endClassDeclaration(Token beginToken, Token endToken) { | |
| insideParserClass = false; | |
| } | |
| @override | |
| void beginConstructor( | |
| DeclarationKind declarationKind, | |
| Token? augmentToken, | |
| Token? externalToken, | |
| Token? staticToken, | |
| Token? covariantToken, | |
| Token? varFinalOrConst, | |
| Token? getOrSet, | |
| Token? newToken, | |
| Token name, | |
| String? enclosingDeclarationName, | |
| ) { | |
| currentMethodName = name.lexeme; | |
| } | |
| @override | |
| void beginMethod( | |
| DeclarationKind declarationKind, | |
| Token? augmentToken, | |
| Token? externalToken, | |
| Token? staticToken, | |
| Token? covariantToken, | |
| Token? varFinalOrConst, | |
| Token? getOrSet, | |
| Token name, | |
| String? enclosingDeclarationName, | |
| ) { | |
| currentMethodName = name.lexeme; | |
| } | |
| @override | |
| void endConstructor( | |
| DeclarationKind kind, | |
| Token beginToken, | |
| Token? newToken, | |
| Token beginParam, | |
| Token? beginInitializers, | |
| Token endToken, | |
| ) { | |
| parameters.clear(); | |
| parametersNamed.clear(); | |
| currentMethodName = null; | |
| } | |
| @override | |
| void endMethod( | |
| DeclarationKind kind, | |
| Token? getOrSet, | |
| Token beginToken, | |
| Token beginParam, | |
| Token? beginInitializers, | |
| Token endToken, | |
| ) { | |
| if (insideParserClass && | |
| !currentMethodName!.startsWith("_") && | |
| currentMethodName != 'inhibitPrinting') { | |
| Token token = beginToken; | |
| Token? latestToken; | |
| out.writeln(" @override"); | |
| out.write(" "); | |
| while (true) { | |
| if (troubleParameterTokens.containsKey(token)) { | |
| if (latestToken != null && latestToken.charEnd < token.charOffset) { | |
| out.write(" "); | |
| } | |
| out.write("dynamic"); | |
| token = troubleParameterTokens[token]!; | |
| } | |
| if (latestToken != null && latestToken.charEnd < token.charOffset) { | |
| out.write(" "); | |
| } | |
| if (token is SimpleToken && token.type == TokenType.FUNCTION) { | |
| // Don't write out the '=>'. | |
| out.write("{"); | |
| break; | |
| } | |
| out.write(token.lexeme); | |
| if (token is BeginToken && | |
| token.type == TokenType.OPEN_CURLY_BRACKET && | |
| (beginParam.endGroup == endToken || | |
| token.charOffset > beginParam.endGroup!.charOffset)) { | |
| break; | |
| } | |
| if (token == endToken) { | |
| throw token.runtimeType; | |
| } | |
| latestToken = token; | |
| token = token.next!; | |
| } | |
| out.write("\n "); | |
| out.write("doPrint('$currentMethodName("); | |
| String separator = ""; | |
| for (int i = 0; i < parameters.length; i++) { | |
| out.write(separator); | |
| out.write(r"' '$"); | |
| out.write(parameters[i]); | |
| separator = ", "; | |
| } | |
| for (int i = 0; i < parametersNamed.length; i++) { | |
| out.write(separator); | |
| out.write("' '"); | |
| out.write(parametersNamed[i]); | |
| out.write(r": $"); | |
| out.write(parametersNamed[i]); | |
| separator = ", "; | |
| } | |
| out.write(")');\n "); | |
| out.write("indent++;\n "); | |
| out.write("var result = super.$currentMethodName"); | |
| if (getOrSet != null && getOrSet.lexeme == "get") { | |
| // no parens | |
| out.write(";\n "); | |
| } else { | |
| out.write("("); | |
| String separator = ""; | |
| for (int i = 0; i < parameters.length; i++) { | |
| out.write(separator); | |
| out.write(parameters[i]); | |
| separator = ", "; | |
| } | |
| for (int i = 0; i < parametersNamed.length; i++) { | |
| out.write(separator); | |
| out.write(parametersNamed[i]); | |
| out.write(": "); | |
| out.write(parametersNamed[i]); | |
| separator = ", "; | |
| } | |
| out.write(");\n "); | |
| } | |
| out.write("indent--;\n "); | |
| out.write("return result;\n "); | |
| out.write("}"); | |
| out.write("\n\n"); | |
| } | |
| parameters.clear(); | |
| parametersNamed.clear(); | |
| currentMethodName = null; | |
| } | |
| int formalParametersNestLevel = 0; | |
| @override | |
| void beginFormalParameters(Token token, MemberKind kind) { | |
| formalParametersNestLevel++; | |
| } | |
| @override | |
| void endFormalParameters( | |
| int count, | |
| Token beginToken, | |
| Token endToken, | |
| MemberKind kind, | |
| ) { | |
| formalParametersNestLevel--; | |
| } | |
| Token? currentFormalParameterToken; | |
| @override | |
| void beginFormalParameter( | |
| Token token, | |
| MemberKind kind, | |
| Token? requiredToken, | |
| Token? covariantToken, | |
| Token? varFinalOrConst, | |
| ) { | |
| if (formalParametersNestLevel == 1) { | |
| currentFormalParameterToken = token; | |
| } | |
| } | |
| Map<Token?, Token?> troubleParameterTokens = {}; | |
| @override | |
| void handleIdentifier(Token token, IdentifierContext context) { | |
| if (formalParametersNestLevel > 0 && token.lexeme.startsWith("_")) { | |
| troubleParameterTokens[currentFormalParameterToken] = null; | |
| } | |
| } | |
| @override | |
| void endFormalParameter( | |
| Token? varOrFinal, | |
| Token? thisKeyword, | |
| Token? superKeyword, | |
| Token? periodAfterThisOrSuper, | |
| Token nameToken, | |
| Token? initializerStart, | |
| Token? initializerEnd, | |
| FormalParameterKind kind, | |
| MemberKind memberKind, | |
| ) { | |
| if (formalParametersNestLevel != 1) { | |
| return; | |
| } | |
| if (troubleParameterTokens.containsKey(currentFormalParameterToken)) { | |
| troubleParameterTokens[currentFormalParameterToken] = nameToken; | |
| } | |
| currentFormalParameterToken = null; | |
| if (kind == FormalParameterKind.optionalNamed || | |
| kind == FormalParameterKind.requiredNamed) { | |
| parametersNamed.add(nameToken.lexeme); | |
| } else { | |
| parameters.add(nameToken.lexeme); | |
| } | |
| } | |
| } |