From 5e4a65eacec5f5a2e5c1f8bd8c5ef55c18875262 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sun, 21 Aug 2022 23:45:42 +0200 Subject: [PATCH] First draft for intermediate results --- drift_dev/lib/src/analysis/backend.dart | 2 + drift_dev/lib/src/analysis/cache.dart | 79 +++++++++++++++++++ drift_dev/lib/src/analysis/driver.dart | 70 ++++++++++++++++ drift_dev/lib/src/analysis/error.dart | 1 + .../analysis/{outline => results}/column.dart | 0 .../analysis/{outline => results}/dart.dart | 0 .../{outline => results}/element.dart | 1 + .../analysis/{outline => results}/table.dart | 0 .../analysis/runner/temporary_results.dart | 15 ++++ drift_dev/pubspec.yaml | 2 +- 10 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 drift_dev/lib/src/analysis/cache.dart create mode 100644 drift_dev/lib/src/analysis/driver.dart create mode 100644 drift_dev/lib/src/analysis/error.dart rename drift_dev/lib/src/analysis/{outline => results}/column.dart (100%) rename drift_dev/lib/src/analysis/{outline => results}/dart.dart (100%) rename drift_dev/lib/src/analysis/{outline => results}/element.dart (93%) rename drift_dev/lib/src/analysis/{outline => results}/table.dart (100%) create mode 100644 drift_dev/lib/src/analysis/runner/temporary_results.dart diff --git a/drift_dev/lib/src/analysis/backend.dart b/drift_dev/lib/src/analysis/backend.dart index 7c8a3279..b38d1ca3 100644 --- a/drift_dev/lib/src/analysis/backend.dart +++ b/drift_dev/lib/src/analysis/backend.dart @@ -1,7 +1,9 @@ +import 'package:analyzer/dart/element/element.dart'; import 'package:logging/logging.dart'; abstract class DriftBackend { Logger get log; Future readAsString(Uri uri); + Future readDart(Uri uri); } diff --git a/drift_dev/lib/src/analysis/cache.dart b/drift_dev/lib/src/analysis/cache.dart new file mode 100644 index 00000000..04b8f322 --- /dev/null +++ b/drift_dev/lib/src/analysis/cache.dart @@ -0,0 +1,79 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:collection/collection.dart'; +import 'package:sqlparser/sqlparser.dart'; +import 'package:path/path.dart' show url; + +import 'results/element.dart'; + +class DriftAnalysisCache { + final Map knownFiles = {}; + final Map knownElements = {}; + + FileState notifyFileChanged(Uri uri) { + // todo: Mark references for files that import this one as stale. + // todo: Mark elements that reference an element in this file as stale. + + return knownFiles.putIfAbsent(uri, () => FileState(uri)) + ..errors.clear() + ..kind = null + ..parsedDartFile = null + ..parsedDriftFile = null; + } + + void notifyFileDeleted(Uri uri) {} +} + +/// A [DriftElement] that is known to exist, but perhaps hasn't fully been +/// resolved yet. +class PendingDriftElement { + final DriftElementId ownId; + final List dependencies; + + bool cleanState = false; + bool isOnCircularReferencePath = false; + + PendingDriftElement(this.ownId, List dependencies) + : dependencies = UnmodifiableListView(dependencies); +} + +abstract class Dependency {} + +class ReferencesElement extends Dependency { + final DriftElementId referencedElement; + + ReferencesElement(this.referencedElement); +} + +class ReferencesUnknownElement extends Dependency { + final String name; + + ReferencesUnknownElement(this.name); +} + +enum FileKind { + driftFile, + dartLibrary, + + /// A Dart part file, a file with an unknown extension or a file that doesn't + /// exist. + invalid, +} + +class FileState { + final Uri uri; + + final List locallyDefinedElements = []; + final List directImports = []; + final List errors = []; + + bool contentsFresh = false; + bool referencesFresh = false; + + FileKind? kind; + DriftFile? parsedDriftFile; + LibraryElement? parsedDartFile; + + FileState(this.uri); + + String get extension => url.extension(uri.path); +} diff --git a/drift_dev/lib/src/analysis/driver.dart b/drift_dev/lib/src/analysis/driver.dart new file mode 100644 index 00000000..c24a6542 --- /dev/null +++ b/drift_dev/lib/src/analysis/driver.dart @@ -0,0 +1,70 @@ +import 'package:sqlparser/sqlparser.dart'; + +import '../analyzer/options.dart'; +import 'backend.dart'; +import 'cache.dart'; + +class DriftAnalysisDriver { + final DriftBackend backend; + final DriftAnalysisCache cache = DriftAnalysisCache(); + final DriftOptions options; + + DriftAnalysisDriver(this.backend, this.options); + + SqlEngine _newSqlEngine() { + return SqlEngine( + EngineOptions( + useDriftExtensions: true, + enabledExtensions: [ + // todo: Map from options + ], + version: options.sqliteVersion, + ), + ); + } + + /// Identify all [PendingDriftElement]s in a file. + Future _discover(FileState state) async { + final extension = state.extension; + + switch (extension) { + case '.dart': + try { + state + ..parsedDartFile = await backend.readDart(state.uri) + ..kind = FileKind.dartLibrary; + } catch (e, s) { + backend.log + .fine('Could not read Dart library from ${state.uri}', e, s); + state.kind = FileKind.invalid; + } + break; + case '.drift': + case '.moor': + final engine = _newSqlEngine(); + String contents; + try { + contents = await backend.readAsString(state.uri); + state.kind = FileKind.driftFile; + } catch (e, s) { + backend.log.fine('Could not read drift sources ${state.uri}', e, s); + state.kind = FileKind.invalid; + break; + } + + // todo: Handle parse errors + final parsed = engine.parseDriftFile(contents); + state.parsedDriftFile = parsed.rootNode as DriftFile; + + break; + } + } + + Future fullyAnalyze(Uri uri) async { + var known = cache.knownFiles[uri]; + + if (known == null || !known.contentsFresh) { + await _discover(cache.notifyFileChanged(uri)); + } + } +} diff --git a/drift_dev/lib/src/analysis/error.dart b/drift_dev/lib/src/analysis/error.dart new file mode 100644 index 00000000..8a4f52ee --- /dev/null +++ b/drift_dev/lib/src/analysis/error.dart @@ -0,0 +1 @@ +class AnalysisError {} diff --git a/drift_dev/lib/src/analysis/outline/column.dart b/drift_dev/lib/src/analysis/results/column.dart similarity index 100% rename from drift_dev/lib/src/analysis/outline/column.dart rename to drift_dev/lib/src/analysis/results/column.dart diff --git a/drift_dev/lib/src/analysis/outline/dart.dart b/drift_dev/lib/src/analysis/results/dart.dart similarity index 100% rename from drift_dev/lib/src/analysis/outline/dart.dart rename to drift_dev/lib/src/analysis/results/dart.dart diff --git a/drift_dev/lib/src/analysis/outline/element.dart b/drift_dev/lib/src/analysis/results/element.dart similarity index 93% rename from drift_dev/lib/src/analysis/outline/element.dart rename to drift_dev/lib/src/analysis/results/element.dart index a44de54d..69d92519 100644 --- a/drift_dev/lib/src/analysis/outline/element.dart +++ b/drift_dev/lib/src/analysis/results/element.dart @@ -19,4 +19,5 @@ class DriftDeclaration { abstract class DriftElement { DriftElementId get id; + DriftDeclaration get declaration; } diff --git a/drift_dev/lib/src/analysis/outline/table.dart b/drift_dev/lib/src/analysis/results/table.dart similarity index 100% rename from drift_dev/lib/src/analysis/outline/table.dart rename to drift_dev/lib/src/analysis/results/table.dart diff --git a/drift_dev/lib/src/analysis/runner/temporary_results.dart b/drift_dev/lib/src/analysis/runner/temporary_results.dart new file mode 100644 index 00000000..47f67710 --- /dev/null +++ b/drift_dev/lib/src/analysis/runner/temporary_results.dart @@ -0,0 +1,15 @@ +import 'package:sqlparser/sqlparser.dart'; + +abstract class TemporaryResult {} + +class TemporaryDriftTable extends TemporaryResult { + final TableInducingStatement statement; + + TemporaryDriftTable(this.statement); +} + +class TemporaryDriftView extends TemporaryResult { + final CreateViewStatement statement; + + TemporaryDriftView(this.statement); +} diff --git a/drift_dev/pubspec.yaml b/drift_dev/pubspec.yaml index 8ba1ef2d..124710f5 100644 --- a/drift_dev/pubspec.yaml +++ b/drift_dev/pubspec.yaml @@ -6,7 +6,7 @@ homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/drift/issues environment: - sdk: '>=2.14.0 <3.0.0' + sdk: '>=2.17.0 <3.0.0' dependencies: charcode: ^1.2.0