Skip to content

Instantly share code, notes, and snippets.

@munificent
Created January 12, 2023 19:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save munificent/e0dee4d695a5e5db5a0725dd65293334 to your computer and use it in GitHub Desktop.
Save munificent/e0dee4d695a5e5db5a0725dd65293334 to your computer and use it in GitHub Desktop.
Scrapes Dart codebases to collect data on sequential numbered parameters and type parameters
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:path/path.dart' as p;
import 'package:scrape/scrape.dart';
final _numberSuffix = RegExp(r'^([a-zA-Z_]+)([0-9]+)$');
final Map<String, Pkg> _packages = {};
void main(List<String> arguments) {
Scrape()
..addHistogram('Parameters')
..addHistogram('Parameters start')
..addHistogram('Type parameters')
..addHistogram('Type parameters start')
..addHistogram('Numbered names')
// ..addHistogram('Non-numbered names')
..addHistogram('Start')
..addHistogram('Package')
..addHistogram('By package')
..addHistogram('Zero packages')
..addHistogram('One packages')
..addVisitor(() => OrdinalVisitor())
..runCommandLine(arguments);
var hist = Histogram();
_packages.forEach((name, pkg) {
if (pkg.hasZero && pkg.hasOne) {
hist.add('Both zero-based and one-based');
} else if (pkg.hasZero) {
hist.add('Only zero-based');
} else if (pkg.hasOne) {
hist.add('Only one-based');
// } else {
// hist.add('No sequences starting at zero or one');
}
});
hist.printCounts('By package/author');
}
class Pkg {
bool hasZero = false;
bool hasOne = false;
}
class OrdinalVisitor extends ScrapeVisitor {
@override
void visitCompilationUnit(CompilationUnit node) {
super.visitCompilationUnit(node);
}
@override
void visitFormalParameterList(FormalParameterList node) {
_checkOrdinals('Parameters',
node.parameters.map((p) => p.name?.lexeme).whereType<String>());
}
@override
void visitTypeParameterList(TypeParameterList node) {
_checkOrdinals(
'Type parameters', node.typeParameters.map((p) => p.name.lexeme));
}
void _checkOrdinals(String label, Iterable<String> names) {
var numbered = <String, SplayTreeSet<int>>{};
for (var name in names) {
var match = _numberSuffix.firstMatch(name);
if (match != null) {
record('Numbered names', name);
numbered
.putIfAbsent(match[1]!, () => SplayTreeSet())
.add(int.parse(match[2]!));
} else {
// record('Non-numbered names', name);
}
}
if (numbered.isNotEmpty) {
var package = p.split(path).first;
record('Package', package);
var pkg = _packages.putIfAbsent(package, () => Pkg());
for (var prefix in numbered.keys) {
var numbers = numbered[prefix]!.toList();
if (numbers.length > 1) {
record(label, numbers.join(','));
record('$label start', numbers[0]);
record('Start', numbers[0]);
if (numbers[0] == 0) {
record('Zero packages', package);
pkg.hasZero = true;
} else if (numbers[0] == 1) {
record('One packages', package);
pkg.hasOne = true;
}
}
}
} else {
record(label, 'Not numbered');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment