-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #61 from nyxx-discord/dev
Release 4.2.0
- Loading branch information
Showing
37 changed files
with
3,389 additions
and
524 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,16 @@ | ||
# Files and directories created by pub. | ||
.dart_tool/ | ||
.packages | ||
pubspec.lock | ||
|
||
# Conventional directory for build output. | ||
build/ | ||
|
||
# Generated files | ||
*.g.dart | ||
*.exe | ||
|
||
# Local | ||
doc/ | ||
.vscode/ | ||
|
||
pubspec.lock | ||
|
||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright 2021 Abitofevrything and others. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:args/args.dart'; | ||
import 'package:logging/logging.dart'; | ||
|
||
import 'compile/generator.dart'; | ||
|
||
void main(List<String> args) async { | ||
late ArgParser parser; | ||
parser = ArgParser() | ||
..addFlag( | ||
'help', | ||
abbr: 'h', | ||
negatable: false, | ||
help: 'Print this help and exit', | ||
) | ||
..addOption( | ||
'output', | ||
abbr: 'o', | ||
defaultsTo: 'out.g.dart', | ||
help: 'The file where generated output should be written to', | ||
) | ||
..addOption( | ||
'verbosity', | ||
abbr: 'v', | ||
defaultsTo: 'info', | ||
allowed: Level.LEVELS.map((e) => e.name.toLowerCase()), | ||
help: 'Change the verbosity level of the command-line output', | ||
) | ||
..addFlag( | ||
'compile', | ||
abbr: 'c', | ||
defaultsTo: true, | ||
help: 'Compile the generated file with `dart compile exe`', | ||
) | ||
..addFlag( | ||
'format', | ||
abbr: 'f', | ||
defaultsTo: true, | ||
help: 'Format the generated output before compiling', | ||
) | ||
..addFlag( | ||
'complete', | ||
defaultsTo: false, | ||
help: 'Generate metadata for all the files in your program, instead of just the necessary' | ||
' ones. This can help in cases where your program does not run when using the normal' | ||
' compiler.', | ||
); | ||
|
||
if (args.isEmpty) { | ||
printHelp(parser); | ||
return; | ||
} | ||
|
||
ArgResults result = parser.parse(args); | ||
|
||
// Help | ||
|
||
if (result['help'] as bool) { | ||
printHelp(parser); | ||
return; | ||
} | ||
|
||
// Logging | ||
|
||
Logger.root.level = Level.LEVELS.firstWhere( | ||
(element) => element.name.toLowerCase() == result['verbosity'], | ||
); | ||
Logger.root.onRecord.listen((LogRecord rec) { | ||
print("[${rec.time}] [${rec.level.name}] ${rec.message}"); | ||
}); | ||
|
||
// Generation | ||
|
||
await generate( | ||
result.rest.first, | ||
result['output'] as String, | ||
result['format'] as bool, | ||
result['complete'] as bool, | ||
); | ||
|
||
// Compilation | ||
|
||
if (result['compile'] as bool) { | ||
logger.info('Compiling file to executable'); | ||
|
||
Process compiler = await Process.start('dart', ['compile', 'exe', result['output'] as String]); | ||
|
||
compiler.stdout.transform(utf8.decoder).listen(stdout.write); | ||
compiler.stderr.transform(utf8.decoder).listen(stderr.write); | ||
} | ||
} | ||
|
||
void printHelp(ArgParser p) { | ||
print( | ||
''' | ||
Generate code from a Dart program that contains metadata about types and function metadata, and can | ||
be compiled to run a program written with nyxx_commands. | ||
Usage: nyxx-compile [options] <file> | ||
Options: | ||
''', | ||
); | ||
print(p.usage); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2021 Abitofevrything and others. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:analyzer/dart/analysis/analysis_context.dart'; | ||
import 'package:analyzer/dart/analysis/results.dart'; | ||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
import 'package:analyzer/dart/element/element.dart'; | ||
import 'package:nyxx_commands/src/errors.dart'; | ||
|
||
import 'generator.dart'; | ||
|
||
/// An AST visitor that checks every file in the entire program, following imports, exports and part | ||
/// directives. Files that are deemed "interesting" are visited in full by this visitor. | ||
/// | ||
/// Files are deemed "interesting" if: | ||
/// - The file is part of `package:nyxx_commands` | ||
/// - The file imports an "interesting" file | ||
class EntireAstVisitor extends RecursiveAstVisitor<void> { | ||
static final Map<String, SomeResolvedUnitResult> _cache = {}; | ||
final List<String> _interestingSources = []; | ||
|
||
final AnalysisContext context; | ||
final bool slow; | ||
|
||
EntireAstVisitor(this.context, this.slow); | ||
|
||
/// Makes this visitor check all the imported, exported or "part-ed" files in [element], visiting | ||
/// ones that are deemed "interesting". | ||
Future<void> visitLibrary(LibraryElement element) async { | ||
List<String> visited = []; | ||
|
||
void recursivelyGatherSources(LibraryElement element) { | ||
String source = element.source.fullName; | ||
|
||
logger.finest('Checking source "$source"'); | ||
|
||
if (visited.contains(source)) { | ||
return; | ||
} | ||
|
||
visited.add(source); | ||
|
||
if (isLibraryInteresting(element)) { | ||
_interestingSources.add(source); | ||
} | ||
|
||
for (final library in [...element.importedLibraries, ...element.exportedLibraries]) { | ||
recursivelyGatherSources(library); | ||
} | ||
} | ||
|
||
recursivelyGatherSources(element); | ||
|
||
while (_interestingSources.isNotEmpty) { | ||
List<String> interestingSources = _interestingSources.sublist(0); | ||
_interestingSources.clear(); | ||
|
||
logger.fine('Visiting interesting sources $interestingSources'); | ||
|
||
await Future.wait(interestingSources.map(visitUnit)); | ||
} | ||
} | ||
|
||
final List<LibraryElement> _checkingLibraries = []; | ||
static final Map<LibraryElement, bool> _interestingCache = {}; | ||
|
||
/// Returns whether a given library is "interesting" | ||
bool isLibraryInteresting(LibraryElement element) { | ||
if (slow) { | ||
return true; | ||
} | ||
|
||
if (_interestingCache.containsKey(element)) { | ||
return _interestingCache[element]!; | ||
} | ||
|
||
if (_checkingLibraries.contains(element)) { | ||
return false; | ||
} | ||
|
||
bool ret; | ||
|
||
_checkingLibraries.add(element); | ||
|
||
if (element.identifier.startsWith('package:nyxx_commands')) { | ||
ret = true; | ||
} else { | ||
ret = element.importedLibraries.any((library) => isLibraryInteresting(library)) || | ||
element.exportedLibraries.any((library) => isLibraryInteresting(library)); | ||
} | ||
|
||
_checkingLibraries.removeLast(); | ||
|
||
return _interestingCache[element] = ret; | ||
} | ||
|
||
/// Makes this visitor get the full AST for a given source and visit it. | ||
Future<void> visitUnit(String source) async { | ||
logger.finer('Getting AST for source "$source"'); | ||
|
||
SomeResolvedUnitResult result = | ||
_cache[source] ??= await context.currentSession.getResolvedUnit(source); | ||
|
||
if (result is! ResolvedUnitResult) { | ||
throw CommandsError('Got invalid analysis result for source $source'); | ||
} | ||
|
||
logger.finer('Got AST for source "$source"'); | ||
|
||
result.unit.accept(this); | ||
} | ||
|
||
@override | ||
void visitPartDirective(PartDirective directive) { | ||
super.visitPartDirective(directive); | ||
|
||
// Visit "part-ed" files of interesting sources | ||
_interestingSources.add(directive.uriSource!.fullName); | ||
} | ||
} |
Oops, something went wrong.