From 726d4c6e968a3847f269f9f0cad09dc1e5bffa85 Mon Sep 17 00:00:00 2001 From: Lukas Renggli Date: Fri, 22 Sep 2023 18:50:17 +0300 Subject: [PATCH] Add some more strict linter rules. --- analysis_options.yaml | 25 ++++++++++++++++-- bin/benchmark/util/runner.dart | 5 ++-- bin/prolog/prolog.dart | 2 +- lib/dart.dart | 2 ++ lib/json.dart | 2 ++ lib/lisp.dart | 2 ++ lib/math.dart | 2 ++ lib/prolog.dart | 2 ++ lib/regexp.dart | 2 ++ lib/smalltalk.dart | 2 ++ lib/src/lisp/native.dart | 47 +++++++++++++++------------------- lib/src/math/parser.dart | 2 +- lib/src/regexp/nfa.dart | 2 +- lib/src/regexp/parser.dart | 8 +++--- lib/src/smalltalk/objects.dart | 2 +- lib/src/smalltalk/parser.dart | 28 +++++++++----------- lib/src/uri/authority.dart | 2 ++ lib/src/uri/query.dart | 2 ++ lib/uri.dart | 2 ++ test/dart_file_tests.dart | 37 -------------------------- test/lisp_test.dart | 5 ++-- test/smalltalk_test.dart | 6 ++--- web/xml/xml.dart | 10 ++++---- 23 files changed, 95 insertions(+), 104 deletions(-) delete mode 100644 test/dart_file_tests.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 2fa5fb09..0f97a491 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,7 +9,11 @@ linter: # - avoid_dynamic_calls - avoid_final_parameters - avoid_print + - avoid_unused_constructor_parameters - camel_case_types + - combinators_ordering + - comment_references + - dangling_library_doc_comments - implicit_call_tearoffs - invalid_case_patterns - no_self_assignments @@ -19,13 +23,30 @@ linter: - prefer_const_constructors_in_immutables - prefer_const_declarations - prefer_const_literals_to_create_immutables + - prefer_expression_function_bodies + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable - prefer_function_declarations_over_variables + - prefer_if_elements_to_conditional_expressions - prefer_relative_imports - - sort_constructors_first - type_literal_in_constant_pattern + - unnecessary_await_in_return + - unnecessary_brace_in_string_interps - unnecessary_breaks + - unnecessary_const + - unnecessary_constructor_name + - unnecessary_getters_setters + # - unnecessary_lambdas - unnecessary_late - - unnecessary_library_directive + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_aware_operator_on_extension_on_nullable + - unnecessary_null_checks + - unnecessary_null_in_if_null_operators + - unnecessary_parenthesis - unnecessary_statements + - unnecessary_to_list_in_spreads - unreachable_from_main - use_super_parameters \ No newline at end of file diff --git a/bin/benchmark/util/runner.dart b/bin/benchmark/util/runner.dart index ddbe8cb6..2b0bdf40 100644 --- a/bin/benchmark/util/runner.dart +++ b/bin/benchmark/util/runner.dart @@ -8,14 +8,13 @@ import 'package:petitparser/petitparser.dart'; import 'benchmark.dart'; -final defaultCharsInput = - List.generate(0xff, (value) => String.fromCharCode(value)); +final defaultCharsInput = List.generate(0xff, String.fromCharCode); final defaultStringInput = defaultCharsInput.join(); final List> _benchmarkEntries = (() { Future.delayed(const Duration(milliseconds: 1)).then((_) { stdout.writeln(['name', 'parser', 'accept', 'native'].join('\t')); - for (var benchmarkEntry in _benchmarkEntries) { + for (final benchmarkEntry in _benchmarkEntries) { benchmarkEntry.value(); } }); diff --git a/bin/prolog/prolog.dart b/bin/prolog/prolog.dart index 6b69469e..9ab8fdc0 100644 --- a/bin/prolog/prolog.dart +++ b/bin/prolog/prolog.dart @@ -35,7 +35,7 @@ void main(List arguments) { stdin .transform(systemEncoding.decoder) .transform(const LineSplitter()) - .map((query) => Term.parse(query)) + .map(Term.parse) .asyncMap((goal) async { await db.query(goal).forEach(stdout.writeln); }).forEach((each) => stdout.write('?- ')); diff --git a/lib/dart.dart b/lib/dart.dart index d1c4a490..5e12fcfc 100644 --- a/lib/dart.dart +++ b/lib/dart.dart @@ -2,4 +2,6 @@ /// /// The grammar is adapted from [Dart programming language specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-408/). /// Unfortunately, it is unable to parse all valid Dart programs yet. +library dart; + export 'src/dart/grammar.dart'; diff --git a/lib/json.dart b/lib/json.dart index b8dc5276..b52cbe5f 100644 --- a/lib/json.dart +++ b/lib/json.dart @@ -1,4 +1,6 @@ /// This package contains a complete implementation of [JSON](https://json.org/). +library json; + import 'src/json/definition.dart'; import 'src/json/types.dart'; diff --git a/lib/lisp.dart b/lib/lisp.dart index 19fe8374..b57cc790 100644 --- a/lib/lisp.dart +++ b/lib/lisp.dart @@ -2,6 +2,8 @@ /// /// The code is reasonably complete to run and evaluate reasonably complex /// programs from the console or the web browser. +library lisp; + export 'src/lisp/cons.dart'; export 'src/lisp/environment.dart'; export 'src/lisp/evaluator.dart'; diff --git a/lib/math.dart b/lib/math.dart index d5914d47..676cbd75 100644 --- a/lib/math.dart +++ b/lib/math.dart @@ -1,4 +1,6 @@ /// This package contains a simple expression parser. +library math; + export 'src/math/ast.dart'; export 'src/math/common.dart'; export 'src/math/parser.dart'; diff --git a/lib/prolog.dart b/lib/prolog.dart index caabda48..83600c90 100644 --- a/lib/prolog.dart +++ b/lib/prolog.dart @@ -3,6 +3,8 @@ /// /// The code is reasonably complete to run and evaluate reasonably complex /// programs from the console or the web browser. +library prolog; + export 'src/prolog/evaluator.dart'; export 'src/prolog/grammar.dart'; export 'src/prolog/parser.dart'; diff --git a/lib/regexp.dart b/lib/regexp.dart index e77e5b78..48ac4047 100644 --- a/lib/regexp.dart +++ b/lib/regexp.dart @@ -3,6 +3,8 @@ // Based on the following blog posts: // - http://xysun.github.io/posts/regex-parsing-thompsons-algorithm.html // - https://deniskyashif.com/2019/02/17/implementing-a-regular-expression-engine/. +library regexp; + export 'src/regexp/nfa.dart'; export 'src/regexp/node.dart'; export 'src/regexp/parser.dart'; diff --git a/lib/smalltalk.dart b/lib/smalltalk.dart index 56139e45..c239e139 100644 --- a/lib/smalltalk.dart +++ b/lib/smalltalk.dart @@ -1,6 +1,8 @@ /// This package contains the complete grammar of Smalltalk. /// /// It was automatically exported from PetitParser for Smalltalk. +library smalltalk; + export 'src/smalltalk/ast.dart'; export 'src/smalltalk/grammar.dart'; export 'src/smalltalk/parser.dart'; diff --git a/lib/src/lisp/native.dart b/lib/src/lisp/native.dart index b873ebaf..c8fed700 100644 --- a/lib/src/lisp/native.dart +++ b/lib/src/lisp/native.dart @@ -58,27 +58,23 @@ class NativeEnvironment extends Environment { throw ArgumentError('Invalid define: $args'); } - static Lambda _lambda(Environment lambdaEnv, dynamic lambdaArgs) { - return (evalEnv, evalArgs) { - final inner = lambdaEnv.create(); - var names = lambdaArgs.head; - var values = evalArguments(evalEnv, evalArgs); - while (names != null && values != null) { - inner.define(names.head, values.head); - names = names.tail; - values = values.tail; - } - return evalList(inner, lambdaArgs.tail); - }; - } - - static dynamic _quote(Environment env, dynamic args) { - return args.head; - } - - static dynamic _eval(Environment env, dynamic args) { - return eval(env.create(), eval(env, args.head)); - } + static Lambda _lambda(Environment lambdaEnv, dynamic lambdaArgs) => + (evalEnv, evalArgs) { + final inner = lambdaEnv.create(); + var names = lambdaArgs.head; + var values = evalArguments(evalEnv, evalArgs); + while (names != null && values != null) { + inner.define(names.head, values.head); + names = names.tail; + values = values.tail; + } + return evalList(inner, lambdaArgs.tail); + }; + + static dynamic _quote(Environment env, dynamic args) => args.head; + + static dynamic _eval(Environment env, dynamic args) => + eval(env.create(), eval(env, args.head)); static dynamic _apply(Environment env, dynamic args) { final Function function = eval(env, args.head); @@ -100,9 +96,8 @@ class NativeEnvironment extends Environment { return evalList(inner, args.tail); } - static dynamic _set(Environment env, dynamic args) { - return env[args.head] = eval(env, args.tail.head); - } + static dynamic _set(Environment env, dynamic args) => + env[args.head] = eval(env, args.tail.head); static dynamic _print(Environment env, dynamic args) { final buffer = StringBuffer(); @@ -156,9 +151,7 @@ class NativeEnvironment extends Environment { return false; } - static dynamic _not(Environment env, dynamic args) { - return !eval(env, args.head); - } + static dynamic _not(Environment env, dynamic args) => !eval(env, args.head); static dynamic _plus(Environment env, dynamic args) { num value = eval(env, args.head); diff --git a/lib/src/math/parser.dart b/lib/src/math/parser.dart index cb3f05a4..291e18e7 100644 --- a/lib/src/math/parser.dart +++ b/lib/src/math/parser.dart @@ -41,7 +41,7 @@ final parser = () { builder.group() ..left(char('+').trim(), (a, op, b) => Binary('+', a, b, (x, y) => x + y)) ..left(char('-').trim(), (a, op, b) => Binary('-', a, b, (x, y) => x - y)); - return builder.build().end(); + return resolve(builder.build()).end(); }(); Expression _createValue(String value) => Value(num.parse(value)); diff --git a/lib/src/regexp/nfa.dart b/lib/src/regexp/nfa.dart index 61434240..1431c793 100644 --- a/lib/src/regexp/nfa.dart +++ b/lib/src/regexp/nfa.dart @@ -33,7 +33,7 @@ class Nfa extends RegexpPattern { void _addStates(NfaState state, Set states) { if (!states.add(state)) return; - for (var other in state.epsilons) { + for (final other in state.epsilons) { _addStates(other, states); } } diff --git a/lib/src/regexp/parser.dart b/lib/src/regexp/parser.dart index d787d85f..5c1b2a20 100644 --- a/lib/src/regexp/parser.dart +++ b/lib/src/regexp/parser.dart @@ -1,3 +1,4 @@ +import 'package:petitparser/definition.dart'; import 'package:petitparser/expression.dart'; import 'package:petitparser/parser.dart'; @@ -8,9 +9,8 @@ final nodeParser = () { const meta = r'\.()!*+?|&'; builder - ..primitive(noneOf(meta).map((char) => LiteralNode(char))) - ..primitive( - anyOf(meta).skip(before: char(r'\')).map((char) => LiteralNode(char))) + ..primitive(noneOf(meta).map(LiteralNode.new)) + ..primitive(anyOf(meta).skip(before: char(r'\')).map(LiteralNode.new)) ..primitive(char('.').map((_) => DotNode())); builder.group().wrapper(char('('), char(')'), (_, value, __) => value); @@ -38,5 +38,5 @@ final nodeParser = () { ..left(char('|'), (left, _, right) => AlternationNode(left, right)) ..left(char('&'), (left, _, right) => IntersectionNode(left, right)); - return builder.build().end(); + return resolve(builder.build()).end(); }(); diff --git a/lib/src/smalltalk/objects.dart b/lib/src/smalltalk/objects.dart index cb3d53a3..6b92f5a9 100644 --- a/lib/src/smalltalk/objects.dart +++ b/lib/src/smalltalk/objects.dart @@ -104,5 +104,5 @@ void bootstrap() { arrayBehavior.addMethod( 'at:put:', (self, index, object) => self[index] = object); - classBehavior.addMethod('new', (self) => SmalltalkObject(self)); + classBehavior.addMethod('new', SmalltalkObject.new); } diff --git a/lib/src/smalltalk/parser.dart b/lib/src/smalltalk/parser.dart index 6b73b359..5a8a6564 100644 --- a/lib/src/smalltalk/parser.dart +++ b/lib/src/smalltalk/parser.dart @@ -133,12 +133,10 @@ ArrayNode buildArray(List statements) { return result; } -ValueNode buildAssignment(ValueNode node, List parts) { - return parts.reversed.fold( - node, - (result, variableAndToken) => - AssignmentNode(variableAndToken[0], variableAndToken[1], result)); -} +ValueNode buildAssignment(ValueNode node, List parts) => parts.reversed.fold( + node, + (result, variableAndToken) => + AssignmentNode(variableAndToken[0], variableAndToken[1], result)); ValueNode buildBlock(List arguments, SequenceNode body) { final result = BlockNode(body); @@ -161,16 +159,14 @@ ValueNode buildCascade(ValueNode value, List parts) { return value; } -ValueNode buildMessage(ValueNode receiver, List parts) { - return parts - .where((selectorAndArguments) => selectorAndArguments.isNotEmpty) - .fold(receiver, (receiver, selectorAndArguments) { - final message = MessageNode(receiver); - addTo(message.selectorToken, selectorAndArguments); - addTo(message.arguments, selectorAndArguments); - return message; - }); -} +ValueNode buildMessage(ValueNode receiver, List parts) => parts + .where((selectorAndArguments) => selectorAndArguments.isNotEmpty) + .fold(receiver, (receiver, selectorAndArguments) { + final message = MessageNode(receiver); + addTo(message.selectorToken, selectorAndArguments); + addTo(message.arguments, selectorAndArguments); + return message; + }); MethodNode buildMethod(List parts) { final result = MethodNode(); diff --git a/lib/src/uri/authority.dart b/lib/src/uri/authority.dart index bd39c8aa..0f6fbea3 100644 --- a/lib/src/uri/authority.dart +++ b/lib/src/uri/authority.dart @@ -1,6 +1,8 @@ /// Further parse the URI authority into username, password, hostname and port. /// /// Accepts input of the form "[username[:password]@]hostname[:port]". +library authority; + import 'package:petitparser/petitparser.dart'; final authority = seq3( diff --git a/lib/src/uri/query.dart b/lib/src/uri/query.dart index c9195c79..77a9cf07 100644 --- a/lib/src/uri/query.dart +++ b/lib/src/uri/query.dart @@ -1,6 +1,8 @@ /// Parsers an URI query. /// /// Accepts input of the form "{key[=value]}&...". +library query; + import 'package:petitparser/petitparser.dart'; final query = _param.plusSeparated('&'.toParser()).map( diff --git a/lib/uri.dart b/lib/uri.dart index 26134be0..4824874e 100644 --- a/lib/uri.dart +++ b/lib/uri.dart @@ -2,6 +2,8 @@ /// /// The accepted inputs and decomposition matches the example given in /// Appendix B of the standard: https://tools.ietf.org/html/rfc3986#appendix-B. +library uri; + import 'package:petitparser/petitparser.dart'; import 'src/uri/authority.dart' as lib_authority; diff --git a/test/dart_file_tests.dart b/test/dart_file_tests.dart deleted file mode 100644 index 48ec69b1..00000000 --- a/test/dart_file_tests.dart +++ /dev/null @@ -1,37 +0,0 @@ -/// This test-case automatically generates various tests from Dart source -/// code. Unfortunately the parser is currently unable to parse most of -/// these files. -import 'dart:io'; - -import 'package:collection/collection.dart'; -import 'package:petitparser/core.dart'; -import 'package:petitparser_examples/dart.dart'; -import 'package:test/test.dart'; - -final grammar = DartGrammarDefinition().build(); - -String addLineNumbers(String input) => input - .split('\n') - .mapIndexed( - (index, value) => '${(index + 1).toString().padLeft(4)}: $value') - .join('\n'); - -void generateTests(String title, Directory root) { - group(title, () { - final files = root - .listSync(recursive: true) - .whereType() - .where((file) => file.path.endsWith('.dart')); - for (final file in files) { - test(file.path.substring(root.path.length + 1), () async { - final input = await file.readAsString(); - final result = grammar.parse(input); - if (result is Failure) fail('$result\n\n${addLineNumbers(input)}'); - }); - } - }); -} - -void main() { - generateTests('PetitParser', Directory.current); -} diff --git a/test/lisp_test.dart b/test/lisp_test.dart index 4b0990cf..b7b051d1 100644 --- a/test/lisp_test.dart +++ b/test/lisp_test.dart @@ -13,9 +13,8 @@ void main() { final native = NativeEnvironment(); final standard = StandardEnvironment(native); - dynamic exec(String value, [Environment? env]) { - return evalString(lispParser, env ?? standard.create(), value); - } + dynamic exec(String value, [Environment? env]) => + evalString(lispParser, env ?? standard.create(), value); group('Cell', () { test('Name', () { diff --git a/test/smalltalk_test.dart b/test/smalltalk_test.dart index 42d9fdc7..c54516c4 100644 --- a/test/smalltalk_test.dart +++ b/test/smalltalk_test.dart @@ -76,7 +76,7 @@ TypeMatcher isSequenceNode( List statements = const []}) => isA() .having((node) => node.temporaries, 'temporaries', - temporaries.map((each) => isVariableNode(each))) + temporaries.map(isVariableNode)) .having((node) => node.statements, 'statements', statements); TypeMatcher isReturnNode(Matcher value) => @@ -88,7 +88,7 @@ TypeMatcher isBlockNode( List statements = const []}) => isA() .having((node) => node.arguments, 'arguments', - arguments.map((each) => isVariableNode(each))) + arguments.map(isVariableNode)) .having((node) => node.body, 'body', isSequenceNode(temporaries: temporaries, statements: statements)); @@ -108,7 +108,7 @@ TypeMatcher isMethodNode(String selector, SelectorType selectorType, .having((node) => node.selector, 'selector', selector) .having((node) => node.selectorType, 'selectorType', selectorType) .having((node) => node.arguments, 'arguments', - arguments.map((each) => isVariableNode(each))) + arguments.map(isVariableNode)) .having((node) => node.pragmas, 'pragmas', pragmas) .having((node) => node.body, 'body', isSequenceNode(temporaries: temporaries, statements: statements)); diff --git a/web/xml/xml.dart b/web/xml/xml.dart index dd78008e..8bbc9d94 100644 --- a/web/xml/xml.dart +++ b/web/xml/xml.dart @@ -16,8 +16,8 @@ Element appendString(Element element, String object) { object .split('\n') .where((each) => each.trim().isNotEmpty) - .map((each) => Text(each)) - .separatedBy(() => Element.br()) + .map(Text.new) + .separatedBy(Element.br) .forEach(element.append); return element; } @@ -133,8 +133,8 @@ class HtmlBuffer implements StringSink { object .toString() .split('\n') - .map((each) => Text(each)) - .separatedBy(() => Element.br()) + .map(Text.new) + .separatedBy(Element.br) .forEach(stack.last.append); } @@ -167,6 +167,6 @@ void main() { xmlInput.onInput.listen((event) => update()); xpathInput.onInput.listen((event) => update()); domPretty.onInput.listen((event) => update()); - domOutput.onClick.listen((event) => selectDom(event)); + domOutput.onClick.listen(selectDom); update(); }