Skip to content

Instantly share code, notes, and snippets.

@munificent
Created January 12, 2023 19:32
Show Gist options
  • Select an option

  • Save munificent/e0dee4d695a5e5db5a0725dd65293334 to your computer and use it in GitHub Desktop.

Select an option

Save munificent/e0dee4d695a5e5db5a0725dd65293334 to your computer and use it in GitHub Desktop.

Revisions

  1. munificent created this gist Jan 12, 2023.
    107 changes: 107 additions & 0 deletions parameter_numbers.dart
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    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');
    }
    }
    }