| // 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/parser.dart'; |
| import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'; |
| import 'package:_fe_analyzer_shared/src/scanner/token.dart'; |
| import 'package:dart_style/dart_style.dart' show DartFormatter; |
| |
| import 'utils/io_utils.dart' show computeRepoDirUri; |
| |
| 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")); |
| List<int> rawBytes = f.readAsBytesSync(); |
| |
| Uint8List bytes = new Uint8List(rawBytes.length + 1); |
| bytes.setRange(0, rawBytes.length, rawBytes); |
| |
| Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, 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/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 Parser; |
| 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/fasta/fasta_codes.dart' as codes; |
| import 'package:front_end/src/fasta/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; |
| |
| TestParser(Listener listener, this.trace) |
| : super(listener, |
| useImplicitCreationExpression: useImplicitCreationExpressionInCfe); |
| |
| 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) { |
| String traceString = ""; |
| if (trace) traceString = " (${createTrace()})"; |
| sb.writeln((" " * indent) + s + traceString); |
| } |
| |
| """); |
| |
| ParserCreatorListener listener = new ParserCreatorListener(out); |
| ClassMemberParser parser = new ClassMemberParser(listener); |
| parser.parseUnit(firstToken); |
| |
| out.writeln("}"); |
| |
| return new DartFormatter().format("$out"); |
| } |
| |
| class ParserCreatorListener extends Listener { |
| final StringSink out; |
| bool insideParserClass = false; |
| String? currentMethodName; |
| List<String> parameters = []; |
| List<String?> parametersNamed = []; |
| |
| ParserCreatorListener(this.out); |
| |
| @override |
| void beginClassDeclaration(Token begin, Token? abstractToken, |
| Token? macroToken, Token? augmentToken, Token name) { |
| if (name.lexeme == "Parser") insideParserClass = true; |
| } |
| |
| @override |
| void endClassDeclaration(Token beginToken, Token endToken) { |
| insideParserClass = false; |
| } |
| |
| @override |
| void beginMethod( |
| DeclarationKind declarationKind, |
| Token? externalToken, |
| Token? staticToken, |
| Token? covariantToken, |
| Token? varFinalOrConst, |
| Token? getOrSet, |
| Token name) { |
| currentMethodName = name.lexeme; |
| } |
| |
| @override |
| void endClassConstructor(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| parameters.clear(); |
| parametersNamed.clear(); |
| currentMethodName = null; |
| } |
| |
| @override |
| void endClassMethod(Token? getOrSet, Token beginToken, Token beginParam, |
| Token? beginInitializers, Token endToken) { |
| if (insideParserClass && !currentMethodName!.startsWith("_")) { |
| 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? 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) { |
| parametersNamed.add(nameToken.lexeme); |
| } else { |
| parameters.add(nameToken.lexeme); |
| } |
| } |
| } |