73a059d406
Also add functionality for the tool to do offsets. Finally run in on the pkg/vm_service/test/ folder. Change-Id: Ifa4ca60ed0707e6211baf4b9df140802d5cecf6f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404881 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
180 lines
5.5 KiB
Dart
180 lines
5.5 KiB
Dart
// Copyright (c) 2023, 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';
|
|
|
|
Never usage() {
|
|
print('Usage: ${Platform.executable} ${Platform.script} <test-file/folder>');
|
|
exit(1);
|
|
}
|
|
|
|
/// This script updates LINE_* and OFFSET_* constants in the given test or
|
|
/// directory.
|
|
void main(List<String> args) {
|
|
if (args.length != 1) {
|
|
usage();
|
|
}
|
|
|
|
final inputFolder = Directory(args[0]);
|
|
if (inputFolder.existsSync()) {
|
|
return processFolder(inputFolder);
|
|
}
|
|
final inputFile = File(args[0]);
|
|
if (inputFile.existsSync() && args[0].endsWith('.dart')) {
|
|
return processFile(inputFile);
|
|
}
|
|
usage();
|
|
}
|
|
|
|
void processFolder(Directory inputFolder) {
|
|
for (var file in inputFolder.listSync()) {
|
|
if (file is File && file.path.endsWith('.dart')) {
|
|
processFile(file);
|
|
}
|
|
}
|
|
}
|
|
|
|
void processFile(File inputFile) {
|
|
final rawContent = inputFile.readAsStringSync();
|
|
final content = rawContent.trim().split('\n');
|
|
|
|
const autogeneratedStart = '// AUTOGENERATED START';
|
|
const autogeneratedEnd = '// AUTOGENERATED END';
|
|
|
|
final lineConstantPattern = RegExp(r'^const( int)? LINE_\w+ = \d+;$');
|
|
final offsetConstantPattern = RegExp(r'^const( int)? OFFSET_\w+ = \d+;$');
|
|
|
|
final prefix = content
|
|
.takeWhile(
|
|
(line) =>
|
|
!lineConstantPattern.hasMatch(line) &&
|
|
!offsetConstantPattern.hasMatch(line) &&
|
|
autogeneratedStart != line,
|
|
)
|
|
.toList();
|
|
|
|
final suffix = content
|
|
.skip(prefix.length)
|
|
.skipWhile(
|
|
(line) =>
|
|
line.startsWith('//') ||
|
|
lineConstantPattern.hasMatch(line) ||
|
|
offsetConstantPattern.hasMatch(line),
|
|
)
|
|
.toList();
|
|
|
|
final lineCommentPattern =
|
|
RegExp(r' // (LINE_\w+)\.?$|/\*\s*(LINE_\w+)\s*\*/');
|
|
final offsetCommentPattern =
|
|
RegExp(r'// (OFFSET_\w+)\.?$|(/\*\s*(OFFSET_\w+)\s*\*/\s*)');
|
|
final firstNonSpace = RegExp(r'(\s*)\S');
|
|
final lineMapping = <String, int>{};
|
|
final offsetMapping = <String, int>{};
|
|
var suffixTextLengthSoFar = 0;
|
|
for (var i = 0; i < suffix.length; i++) {
|
|
final line = suffix[i];
|
|
final m = lineCommentPattern.firstMatch(line);
|
|
if (m != null) {
|
|
lineMapping[(m[1] ?? m[2])!] = i;
|
|
}
|
|
for (var match in offsetCommentPattern.allMatches(line)) {
|
|
if (match[1] != null) {
|
|
// E.g. '// OFFSET_FOO'.
|
|
// Points to the offset on the start of the next line.
|
|
offsetMapping[match[1]!] = suffixTextLengthSoFar + line.length + i + 1;
|
|
} else if (match[3] != null) {
|
|
// E.g. '/* OFFSET_INLINE */'.
|
|
// Points to the offset on the start of the next "word".
|
|
if (match.end == line.length && suffix.length > i + 1) {
|
|
// At end of line with another line. Go to the next "word"
|
|
// on the next line.
|
|
final nextLine = suffix[i + 1];
|
|
offsetMapping[match[3]!] = suffixTextLengthSoFar +
|
|
line.length +
|
|
(firstNonSpace.firstMatch(nextLine)?.end ?? 0) +
|
|
i;
|
|
} else {
|
|
offsetMapping[match[3]!] = suffixTextLengthSoFar + match.end + i;
|
|
}
|
|
}
|
|
}
|
|
suffixTextLengthSoFar += line.length;
|
|
}
|
|
|
|
if (lineMapping.isEmpty && offsetMapping.isEmpty) return;
|
|
|
|
final fileUri = Uri.base.resolveUri(inputFile.uri);
|
|
final fileUriString = fileUri.toString();
|
|
final sdkRootString =
|
|
Uri.base.resolveUri(Platform.script).resolve('../../../').toString();
|
|
|
|
var testFileString = '<test.dart>';
|
|
if (sdkRootString.length < fileUriString.length &&
|
|
fileUriString.substring(0, sdkRootString.length) == sdkRootString) {
|
|
testFileString = fileUriString.substring(sdkRootString.length);
|
|
}
|
|
|
|
final header = [
|
|
...prefix,
|
|
autogeneratedStart,
|
|
'//',
|
|
'// Update these constants by running:',
|
|
'//',
|
|
'// dart pkg/vm_service/test/update_line_numbers.dart $testFileString',
|
|
'//',
|
|
];
|
|
|
|
// Mapping currently contains 0 based indices into suffix.
|
|
// Convert them into 1 based line numbers taking into account that we will
|
|
// generate a header + one line for each LINE_* constant plus
|
|
// autogeneratedEnd marker.
|
|
lineMapping.updateAll(
|
|
(_, value) =>
|
|
1 +
|
|
header.length +
|
|
lineMapping.length +
|
|
offsetMapping.length +
|
|
1 +
|
|
value,
|
|
);
|
|
|
|
final offsetFixedLengthInt = 4;
|
|
|
|
if (offsetMapping.isNotEmpty) {
|
|
final newHeaderMockLength = [
|
|
...header,
|
|
for (var entry in lineMapping.entries)
|
|
'const ${entry.key} = ${entry.value};',
|
|
for (var entry in offsetMapping.entries)
|
|
'const ${entry.key} = ${entry.value.toString().padLeft(offsetFixedLengthInt, '0')};',
|
|
autogeneratedEnd,
|
|
].join('\n').length;
|
|
|
|
// Mapping currently contains 0 based char-indices into suffix.
|
|
// Convert them to take into account that we will
|
|
// generate a header + one line for each constant plus
|
|
// autogeneratedEnd marker.
|
|
offsetMapping.updateAll(
|
|
(_, value) => newHeaderMockLength + 1 + value,
|
|
);
|
|
}
|
|
|
|
final newContent = [
|
|
...header,
|
|
for (var entry in lineMapping.entries)
|
|
'const ${entry.key} = ${entry.value};',
|
|
for (var entry in offsetMapping.entries)
|
|
'const ${entry.key} = ${entry.value.toString().padLeft(offsetFixedLengthInt, '0')};',
|
|
autogeneratedEnd,
|
|
...suffix,
|
|
'',
|
|
].join('\n');
|
|
if (newContent != rawContent) {
|
|
inputFile.writeAsString(newContent);
|
|
print('Updated: ${inputFile.path}');
|
|
} else {
|
|
print('Unchanged: ${inputFile.path}');
|
|
}
|
|
}
|