← D4rt
Publishedrole: extensionlicense: MIT

tom_d4rt_exec

tom_d4rt_exec · v1.8.3

Parses Dart source via the generator, then executes on `tom_d4rt_ast` with no analyzer at runtime. The migration target replacing `tom_d4rt` for Flutter and server use.

View repository → See License
Status
Published
LOC
2.3k
Tests
2.5k
Test LOC
39.8k

Overview

`tom_d4rt_exec` is the embedding and CLI entry point of the analyzer-free line. It separates parsing from execution: source is parsed by the analyzer and mirrored into the `tom_d4rt_ast` tree via `tom_ast_generator`, then handed to the `tom_d4rt_ast` interpreter. The split means downstream packages — `tom_dcli_exec`, Flutter apps, servers — embed the interpreter and run scripts without a compile-time or tree-shake dependency on the analyzer; the analyzer step happens only here. It offers fresh, continued, REPL, file, and pre-bundled execution modes, and is the designated migration target away from `tom_d4rt` for all Flutter and server use.

What it enables

Enables analyzer-free script embedding, Flutter and server execution, pre-bundled script runs.

Relationships

Standalone — no declared relationships.

tom_d4rt_exec

Analyzer-free D4rt interpreter — the CLI and embedding entry point that parses Dart source via the `analyzer` package, mirrors the resulting AST into the `tom_d4rt_ast` serializable tree, and hands it to the `tom_d4rt_ast` interpreter for execution.

Overview

`tom_d4rt_exec` is the **migration target** for the D4rt interpreter ecosystem, replacing `tom_d4rt` for all Flutter and server use-cases. It separates the two responsibilities that were bundled together in the original package:

1. **Parsing** — Dart source is parsed by the `analyzer` package and converted 1:1 into the `tom_d4rt_ast` mirror AST via `tom_ast_generator`'s `AstConverter`. 2. **Execution** — The mirror AST is handed to `tom_d4rt_ast`'s `InterpreterVisitor` and `D4rtRunner`, which perform the actual interpretation entirely without `analyzer` at runtime.

This split means downstream packages (`tom_dcli_exec`, Flutter apps, servers) can embed the interpreter, run scripts, and hot-reload interpreted code **without taking a compile-time or tree-shake dependency on `analyzer`** — the analyzer step happens only here, at the execution entry point.

Execution modes

ModeAPIUse-case
Fresh-context execution `D4rt.execute()` Runs a script from scratch; resets global environment
Continued execution `D4rt.continuedExecute()` Adds declarations to an existing context without reset
REPL-style evaluation `D4rt.eval()` Evaluates a single expression in the current context
File-based execution `executeFile()` / `executeFileContinued()` Loads a `.d4rt.dart` or `.dart` script from disk with automatic import resolution
Source-from-string (with base path) `executeSource()` Runs source code with relative-import resolution against a base directory
Bundle execution `D4rt.executeBundle()` Runs a pre-bundled `AstBundle` produced by `AstBundler`; no parse step at runtime

Installation

dependencies:
  tom_d4rt_exec: ^1.8.3
dart pub add tom_d4rt_exec

Features

  • **Full Dart 3 syntax support** — classes, generics, patterns, extension types, sealed classes, records, async/await, async*/sync* generators, streams, mixins, enums with members, and more.
  • **Sandboxed execution** — scripts run in an isolated environment; sensitive operations (`dart:io`, `dart:isolate`) require explicit permission grants via `d4rt.grant(...)`.
  • **Bridging system** — expose native Dart classes, enums, extension methods, top-level functions, global variables, and global getters/setters to interpreted code.
  • **Bridge deduplication** — `sourceUri` tracking prevents duplicate bridge registration when the same type is re-exported through multiple barrel files.
  • **Module system** — full import/export with `show`, `hide`, and `as prefix` combinators; circular-import detection via module cache.
  • **Class aliases and function typedefs** — `registerClassAlias()` and `registerFunctionTypedef()` allow typedef names used in scripts to resolve to their target types.
  • **Library re-exports** — `registerLibraryReExport()` mirrors Dart's `export` directive for native bridge packages.
  • **Bridge validation** — `D4rt.validateRegistrations()` collects all registration errors in one pass without aborting on the first conflict.
  • **Configuration introspection** — `getConfiguration()` returns a `D4rtConfiguration` snapshot of all registered bridges, permissions, and globals.
  • **Environment introspection** — `getEnvironmentState()` returns the live global environment after execution.
  • **Debug logging** — `setDebug(true)` enables detailed trace output for all interpreter passes.
  • **Versioned build info** — `TomVersionInfo` carries version, git commit, and build timestamp.
  • **Multi-platform** — declared for Android, iOS, Linux, macOS, Web, and Windows.

Quick Start

import 'package:tom_d4rt_exec/d4rt.dart';

void main() {
  final d4rt = D4rt();

  // Execute a script with a main function
  d4rt.execute(
    source: '''
      void main() {
        print("Hello from D4rt!");
      }
    ''',
  );
}

Usage

Basic Execution

`execute()` parses the source, resets the interpreter environment, and calls the named function (default: `main`):

final d4rt = D4rt();

// Call main() by default
d4rt.execute(source: '''
  void main() {
    print("Hello!");
  }
''');

// Call a custom function with positional arguments
final result = d4rt.execute(
  source: '''
    String greet(String name, int age) {
      return "Hello \$name, you are \$age";
    }
  ''',
  name: 'greet',
  positionalArgs: ['Alice', 30],
);
print(result); // "Hello Alice, you are 30"

// Named arguments
d4rt.execute(
  source: 'String greet({required String name, int age = 0}) => "\$name (\$age)";',
  name: 'greet',
  namedArgs: {'name': 'Bob', 'age': 25},
);

REPL-Style Evaluation

After an initial `execute()` call establishes context, use `eval()` to evaluate expressions incrementally in the same environment:

final d4rt = D4rt();

// Establish context
d4rt.execute(source: '''
  var counter = 0;
  void increment() { counter++; }
''');

// Evaluate expressions in the established context
d4rt.eval('increment()');
d4rt.eval('increment()');
print(d4rt.eval('counter')); // 2

Continued Execution

`continuedExecute()` adds new declarations and executes them without resetting the global environment:

final d4rt = D4rt();

d4rt.execute(source: 'void main() {}');

d4rt.continuedExecute(source: '''
  int square(int x) => x * x;
  void main() {}
''');

print(d4rt.eval('square(5)')); // 25

File-Based Script Execution

`executeFile()` reads a `.dart` or `.d4rt.dart` script from disk and automatically resolves all relative imports before executing:

import 'package:tom_d4rt_exec/d4rt.dart';

void main() {
  final d4rt = D4rt();

  final result = executeFile(
    d4rt,
    '/path/to/scripts/main.d4rt.dart',
    log: print,
  );

  if (result.success) {
    print('Result: ${result.result}');
    print('Sources loaded: ${result.sourcesLoaded}');
  } else {
    print('Error: ${result.error}');
    print(result.stackTrace);
  }
}

Use `executeFileContinued()` to evaluate a script's files into an existing context via `eval()` rather than replacing it, and `executeSource()` to run source code from a string with a base path for import resolution.

Exposing Native Code (Bridging)

Register native classes, enums, and functions before execution to make them available in scripts:

// Register a bridged class
d4rt.registerBridgedClass(myClassBridge, 'package:my_app/types.dart');

// Register a bridged enum
d4rt.registerBridgedEnum(myEnumDefinition, 'package:my_app/types.dart');

// Register a top-level function
d4rt.registertopLevelFunction(
  'myFunc',
  (args, namedArgs) => doSomething(args),
  'package:my_app/types.dart',
);

// Register a global variable
d4rt.registerGlobalVariable('appName', 'MyApp', 'package:my_app/types.dart');

// Register a global getter (evaluated lazily on each access)
d4rt.registerGlobalGetter(
  'currentTime',
  () => DateTime.now().millisecondsSinceEpoch,
  'package:my_app/types.dart',
);

// Register a global getter + setter pair
d4rt.registerGlobalGetter('counter', () => _counter, 'package:my_app/types.dart');
d4rt.registerGlobalSetter('counter', (v) => _counter = v as int, 'package:my_app/types.dart');

// Scripts import and use them normally
d4rt.execute(source: '''
  import 'package:my_app/types.dart';

  void main() {
    final obj = MyClass();
    obj.doSomething();
    print(currentTime);
  }
''');

Use `tom_d4rt_generator` to generate bridge code automatically from your existing Dart classes. See the [Bridge Generator User Guide](../tom_d4rt_generator/doc/bridgegenerator_user_guide.md).

For manual bridging patterns, see the [Bridging Guide](doc/BRIDGING_GUIDE.md) and the [Advanced Bridging Guide](doc/advanced_bridging_user_guide.md).

Security and Permissions

D4rt is sandboxed by default. Access to `dart:io` and `dart:isolate` is blocked unless explicitly permitted:

final d4rt = D4rt();

// Grant filesystem access
d4rt.grant(FilesystemPermission.any);

// Grant isolate operations
d4rt.grant(IsolatePermission.any);

// Revoke a previously granted permission
d4rt.revoke(FilesystemPermission.any);

// Check permission state
print(d4rt.hasPermission(FilesystemPermission.any));

Bridge Validation

Catch registration conflicts across all bridge packages in one pass:

final d4rt = D4rt();
// ... register all bridges ...

final errors = d4rt.validateRegistrations(
  source: """
    import 'package:my_pkg/my_pkg.dart';
    import 'package:other_pkg/other_pkg.dart';
    void main() {}
  """,
);

if (errors.isNotEmpty) {
  for (final e in errors) print('  - $e');
}

Bundle Execution

For environments where the parse step must be eliminated at runtime (Flutter hot-reload, tight startup), use `AstBundler` (re-exported from `tom_ast_generator`) to pre-bundle scripts, then execute the bundle:

final bundler = AstBundler(config: AstBundlerConfig(...));
final bundle = await bundler.bundle('path/to/entry.dart');

final d4rt = D4rt();
// ... register bridges ...
d4rt.executeBundle(bundle);

Architecture and Key Concepts

Parse-Mirror-Interpret Pipeline

Dart source
    |
    v  (analyzer package — compile-time dependency of tom_d4rt_exec only)
analyzer AST
    |
    v  (tom_ast_generator: AstConverter — 1:1 structural copy)
SCompilationUnit (mirror AST — serializable, no analyzer types)
    |
    v  (tom_d4rt_ast: InterpreterVisitor / D4rtRunner)
Execution result

The `AstConverter` in `tom_ast_generator` performs a 1:1 structural mapping of every `analyzer` node to its corresponding `S*` node in `tom_d4rt_ast` (e.g., `ClassDeclaration` → `SClassDeclaration`). The interpreter in `tom_d4rt_ast` never sees `analyzer` types at all.

D4rt Class

`D4rt` (exported from `lib/d4rt.dart` and `lib/tom_d4rt.dart`) is the primary entry point. Internally it holds:

  • `AstConverter` — parses source via `analyzer` and converts to mirror AST.
  • `D4rtRunner` — the `tom_d4rt_ast` bundle-execution path; all bridge registrations and permissions are forwarded to it.
  • `ModuleLoader` — resolves imports, loads stdlib modules, and registers bridges per-import with deduplication.
  • `_moduleLoader.globalEnvironment` — the live interpreter environment, accessible after execution via `getEnvironmentState()`.

Two-Pass Execution

Each `execute()` call runs two passes over the `SCompilationUnit`:

1. **Declaration pass** (`DeclarationVisitor`) — registers class, function, and variable names in the environment without evaluating initializers. 2. **Interpretation pass** (`InterpreterVisitor`) — processes import directives (triggering bridge registration), evaluates top-level initializers, and then calls the named entry function.

ModuleLoader

`ModuleLoader` (in `lib/src/module_loader.dart`) implements `ModuleContext` from `tom_d4rt_ast`. It:

  • Resolves and caches loaded modules by URI.
  • Registers bridges lazily when their import is processed (with `show`/`hide` filter support).
  • Handles stdlib modules (`dart:core`, `dart:math`, `dart:convert`, `dart:io`, `dart:collection`, `dart:typed_data`, `dart:isolate`) via the `Stdlib` registry.
  • Auto-loads stdlib modules when resolving extension on-types that target stdlib types.
  • Accumulates registration errors in validation mode instead of throwing on the first one.

Import Path: `d4rt.dart` vs `tom_d4rt.dart`

ImportPurpose
`package:tom_d4rt_exec/d4rt.dart`Full public API
`package:tom_d4rt_exec/tom_d4rt.dart` Compatibility re-export — bridge files generated for `tom_d4rt` import `tom_d4rt/tom_d4rt.dart`; this alias lets the same files work with `tom_d4rt_exec` after a package rename
`package:tom_d4rt_exec/tom_d4rt_exec.dart`Convenience re-export of `d4rt.dart`

ScriptExecutionResult

The file- and source-based helpers in `lib/src/script_execution.dart` return `ScriptExecutionResult` with:

  • `success` — whether execution completed without error.
  • `result` — the return value of the called function.
  • `error` / `stackTrace` — populated on failure.
  • `sourcesLoaded` — number of source files resolved (main + all transitively imported files).

Ecosystem

`tom_d4rt_exec` sits in the middle of the D4rt interpreter stack:

tom_ast_model
    ^
    |  (defines serializable S* AST node types)
tom_d4rt_ast
    ^
    |  (interpreter runtime, D4rtRunner, InterpreterVisitor, stdlib, bridging API)
tom_ast_generator
    ^
    |  (AstConverter: analyzer AST -> mirror AST; AstBundler)
tom_d4rt_exec          <-- THIS PACKAGE
    ^
    |  (CLI runner, DCli scripting integration)
tom_dcli_exec

`tom_d4rt` is the original monolithic interpreter that bundles the analyzer, AST, and runtime together. `tom_d4rt_exec` replaces it for all new integrations. Bridge packages generated against `tom_d4rt` can be migrated by changing their import from `package:tom_d4rt/tom_d4rt.dart` to `package:tom_d4rt_exec/tom_d4rt.dart` — the compatibility alias keeps the public API identical.

Documentation

`tom_d4rt_exec` is the analyzer-using entry point; its docs are exec-specific and link to `tom_d4rt` for the (identical) language semantics and bridging model.

  • [User Guide](doc/tom_d4rt_exec_user_guide.md) — exec-specific: the parse → mirror-AST → interpret pipeline, source execution, and the bundle / typed-execute API. Links to the base guide for shared semantics.
  • [Limitations (delta)](doc/tom_d4rt_exec_limitations.md) — entry-point-specific limits (not web-safe; analyzer-boundary parse errors; bundle/runtime version alignment); links back to the canon.
  • [Bridging Guide](doc/BRIDGING_GUIDE.md) — how to bridge native Dart classes and functions manually.
  • [Advanced Bridging Guide](doc/advanced_bridging_user_guide.md) — `D4` helper class, type coercion, argument extraction, target validation, and global function bridging.
  • Base (shared) docs: [tom_d4rt User Guide](../tom_d4rt/doc/d4rt_user_guide.md) · [Limitations (canonical)](../tom_d4rt/doc/d4rt_limitations.md).
  • [Bridge Generator User Guide](../tom_d4rt_generator/doc/bridgegenerator_user_guide.md) — automating bridge creation with code generation.
  • [Bridge Generator Reference](../tom_d4rt_generator/doc/bridgegenerator_user_reference.md) — generator configuration options.

Status

**Version 1.8.3** — current release on pub.dev (first published at 1.8.2).

  • 1680+ tests passing (2 intentional won't-fix exclusions).
  • All 20 Dart language areas covered in the `dart_overview` test suite.
  • Supported platforms: Android, iOS, Linux, macOS, Web, Windows.

Repository: [https://github.com/al-the-bear/tom_d4rt/tree/main/tom_d4rt_exec](https://github.com/al-the-bear/tom_d4rt/tree/main/tom_d4rt_exec)

License
MIT License

Copyright (c) 2025 Moustapha Kodjo Amadou

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Extensions by Peter Nicolai Alexis Kyaw (find me on LinkedIn under Alexis Kyaw).
This is a very extended version from the original.