NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #4465 most downloaded on pub.dev
Portable multi-language VM: parse, run and translate Dart, Java, Kotlin, Go, C#, JavaScript, TypeScript, Lua and Python — with on-the-fly Wasm compilation and MCP/LSP servers.
Last release 24 days ago
09 Sep 2026
Ships unpredictably
gaps range from 8 days to 2.1 years
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
159 releases · first in 2021
Fixed garbage values when a rich-enum instance field or method result was passed through print(...) / string interpolation (e.g. print(p.gravity) or p
print contextprint(...) / string interpolation (e.g. print(p.gravity)
or print('${p.mult(2)}')). The lazily-generated enum-entry initializer
baked its constructor call index during an early discovery pass, before the
print/double_to_str host imports were registered; those imports then
shifted every function index, so the cached call landed on a host import
instead of the enum constructor. Enum-entry initializer bodies are now
generated lazily (after the import count is final), so the call indices are
correct. Reading the same field/method outside a print (e.g. return p.gravity) was already correct.Unqualified sibling class-method calls now resolve: a method can call a sibling static method by bare name (dbl(x) instead of Foo.dbl(x)), including w
static method by bare name (dbl(x) instead of Foo.dbl(x)),
including with named arguments and omitted default parameters.String + <number> concatenation (from Java/Kotlin/C#/JS/TS, e.g.
"n=" + n) compiles, coercing the numeric operand to a String.switch on a String scrutinee (content equality) and switch on an
enum scrutinee (compared by ordinal). switch on int already worked.
Also fixes a general function-end edge case: a control construct
(switch/if/while) that returns on all paths as the last statement (e.g.
after a var declaration) compiled to a function that fell off its end
without a return value.double ratio(Planet p)) compile; C#/TypeScript explicit-value enums expose .value.on Exception catch (e) / catch (Exception e)) compile instead of failing on the declared exception type.Map/
List → String coercion, generic (Box<T>) primitive fields, lambdas, and
switch on a boxed dynamic/Object scrutinee.One column per quarter.
Function, method and constructor calls can now pass arguments by name, bound to parameters by name rather than position (so call-site order is free):
foo(a: 1, b: 2), Kotlin foo(a = 1), C# foo(a: 1), Python
foo(a=1).int f({int a, int b})), optional-positional groups ([int b]), and the same forms in
constructors (Box({this.w, this.h})); the other languages declare parameters
positionally and allow any of them to be passed by name, matching each
language's semantics.a: v / a = v / a=v) and re-parse
to the same result. Languages without a native named-argument concept (Java,
JavaScript, TypeScript, Lua) are unaffected and keep positional calls.int f({int a = 5}) / [int b = 3],
Kotlin fun f(a: Int = 5), C# void F(int a = 5), Python def f(a=5)
(including default-bearing constructor parameters, e.g. Box({this.w = 2})).
Defaults are evaluated at call time, round-trip through code generation, and
are overridden by any supplied positional or named argument. The Wasm compiler
also fills omitted parameters with their (constant) default expressions.compile command (WebAssembly)apollovm compile [-o out.wasm] [--target wasm] <source> command compiles
a source file to a WebAssembly binary via the on-the-fly Wasm compiler,
writing one .wasm file per generated module (alongside run and
translate).test/ suite is grouped into unit/, features/, languages/,
wasm/, integration/ and meta/ subdirectories (no behavior change).Breaking change: an enum entry is no longer an int — use Color.blue.index (and .value for explicit = N entries) instead of int x = Color.blue.
const class instances)const
instance — a singleton, so == is identity — replacing the int-ordinal model.
Every entry carries index (ordinal) and name, and EnumName.values lists
them. Dart enhanced enums work: entries with constructor arguments, fields,
and methods (Planet.earth.gravity()). Explicit-value entries (C#/TypeScript
Medium = 5) expose the value via .value.static-const-instances idiom (simple enums are unchanged)..index/.name/fields/methods and EnumName.values all work.int — use
Color.blue.index (and .value for explicit = N entries) instead of
int x = Color.blue.constructor(...) class method is now parsed as a real
constructor, and new Foo(...) / Foo(...) instantiate the class (running the
constructor, which can assign this.x = …). Round-trips to constructor(...)
and translates to other languages.self.x = … attribute assignment is now parsed, __init__ is
treated as the constructor, and Foo(...) instantiates the class. The
generator emits def __init__(self, …). (Previously instance-field assignment
was unimplemented, so __init__ wasn't usable end-to-end.)async/await for JavaScript, TypeScript, C# and Pythonasync functions/methods (and async arrows /
lambdas) and the await expression, joining Dart. Parsed code executes on the
shared async runtime, round-trips back to its source language, and translates
across languages (e.g. C# async Task<int> ⇄ Dart Future<int> … async).async code generation (async/async def); the
JavaScript and TypeScript generators already emitted it.await now unwraps any awaitable type — Future<T>, Promise<T> (TypeScript)
and Task<T> (C#) — to its value type T, so awaiting a typed result infers
the correct type. A shared word-boundary keyword token keeps identifiers like
awaiter from being read as await + er.async/await row.Objectstatic class methods: each is
synthesized as an exported module function under the qualified Class.method
name (no this), generated like a top-level function. ApolloRunnerWasm
gains executeClassMethod, resolving the export by that name.Object/dynamic values: an i32 pointer to a
16-byte heap cell [tag@0][typeId@4][payload@8]. Concrete values flowing into
an Object slot are boxed, and toString() dispatches on the box tag
(int/double/bool/String, plus boxed instances by typeId). Enables
List<Object>/List<dynamic> literals and arguments with mixed element
types, marshalled host-side by ApolloRunnerWasm.List<Object>/List<dynamic>
variable (e.g. List<Object> x = [1, 2, 3]) now boxes its elements. The
literal infers a concrete element type (List<int>) and previously stored
unboxed values that the boxed read path misread (garbage output or an
out-of-bounds trap); the declared target element type is now honored.executeClassMethod (and any internal call that reaches a
non-static method with no this in context, e.g. a static method calling an
instance sibling) throws ApolloVMRuntimeError instead of silently running
against an auto-created instance. Pass classInstanceObject /
classInstanceFields to run a non-static method, or mark the entry method
static. This matches the Wasm backend, where only static methods are
exported.ApolloRunnerWasm.executeClassMethod now reports a clear error for a
non-static target (only static methods are exported) and rejects being given a
class instance (the Wasm backend has no instance-method entry points).static method calling an instance sibling) with a clear UnsupportedError.static where they hold no
instance state, or supply an instance otherwise.dart test tags: a backend tag (wasm, plus
wasm-gc/wasm-chrome for browser-only Wasm tests) and per-source-language
tags (dart, java, kotlin, javascript, typescript, lua, csharp,
python). E.g. dart test -t wasm, dart test -t kotlin, or
dart test -x wasm-gc for the native wasm_run CI.The WebAssembly compiler now supports do/while, switch/case (integer, C-style fall-through), break, continue, and the bitwise operators & | ^ << >> an
do/while, switch/case (integer,
C-style fall-through), break, continue, and the bitwise operators
& | ^ << >> and unary ~. Loops now wrap their body in a continue block
and WasmContext tracks structured-control depth so break/continue emit
correct relative branch labels. Each construct is validated against both the
AST interpreter and the compiled+executed Wasm module.and/or/xor/shl/shr and x.inv() (bitwise NOT).&/|/~ (xor)/<</>> and unary ~, leaving ~= (not-equals)
and ^ (exponent) intact.private/public/internal/
protected, plus open/override/abstract/final/const) on Kotlin
methods/fields/constructors; method visibility round-trips.private members no longer fail with "Can't be private and public"
(the modifiers parser derived isPublic from private).EnumType.entry now resolves at runtime to the entry's value: its explicit value when present (C# Level.Medium → 5), otherwise its ordinal index (Dart
EnumType.entry now resolves at runtime to the entry's value: its explicit
value when present (C# Level.Medium → 5), otherwise its ordinal index
(Dart Color.blue → 2). ASTRoot.getNodeIdentifier resolves user
classes/enums by name; enum entry access short-circuits in
ASTExpressionObjectGetterAccess.List<Integer>,
Map<String,Integer> m, Box<T>); well-known collections map to the shared
array/map types, other generic types keep their type arguments and round-trip.class Wrapper<T> { T value; … } plus new Wrapper<int>(10) /
Wrapper<int>(10). Class type parameters are erased to dynamic in member
types; generic type arguments on calls are parsed. Runs end-to-end in Dart,
Java, C#, Kotlin and TypeScript.ASTType.acceptsType — a raw type and a
parameterized one of the same name are mutually compatible (so a Wrapper
instance binds to a Wrapper<int> variable).for (Type x : coll) instead of the
invalid for (var x in coll), so generated Java re-parses.val/var keywords now require a word boundary, so identifiers like
value are no longer mangled (e.g. a constructor parameter value was read as
ue).constructor(...)) resolves its type
from the enclosing class, and TypeScript constructor(...) is parsed as a real
constructor so new Foo(...) works.Parse C# lambda expressions (x => x * 2, (a, b) => a + b, (int a) => { ... }, () => 0); previously C# could only *generate* lambda syntax, not read it
x => x * 2, (a, b) => a + b, (int a) => { ... },
() => 0); previously C# could only generate lambda syntax, not read it.Func, Action, Delegate, Function) map to the shared
function type, so a lambda value binds to a delegate-typed parameter.switch/case, break, continue, do/whileASTStatementBreak, ASTStatementContinue,
ASTStatementDoWhileLoop, ASTStatementSwitch/ASTSwitchCase). break/
continue propagate through ASTBlock and are consumed by the enclosing
loop/switch; for still runs its increment on continue.switch uses C-style fall-through (break ends a case; default runs when no
case matches). An ASTStatementSwitch.fallThrough flag disables fall-through
for languages whose construct has none.case body accepts a braced block or a bare run
of statements).break/continue, do { } while (c), and when (e) { v -> …; else -> … } (no fall-through).break/continue, and match/case (case _: is the
default; no fall-through). Python has no do/while.break, and repeat … until <cond> mapped to a do-while (the
condition is negated; the generator unwraps it to emit until <cond>).test/tests_definitions/*_control_flow*.test.xml for
all eight languages.&, |, ^, <<, >> (binary) and ~ (unary complement),
with shared AST/runtime evaluation (int operands) and precedence (shift,
then AND/XOR/OR, between arithmetic and comparison).%, && and || operators.and/or/shl/inv) or
Lua (~ is xor and ^ is exponentiation) — their non-symbolic forms need
bespoke handling.test/tests_definitions/*_bitwise.test.xml.enum E { … }),
C# (enum E { A = 1, … }), Kotlin (enum class E { … }) and
Python (class E(Enum): …), joining the existing Dart/TypeScript support.test/tests_definitions/*_enum.test.xml.New self-contained C# language support (csharp, also accepting cs and c#) able to parse, run and translate, at the same level of compatibility as Dart
csharp, also accepting cs and
c#) able to parse, run and translate, at the same level of compatibility as
Dart and Java: classes, fields (incl. initial values), constructors, methods
and modifiers (public/private/static/readonly/…), using directives,
variable declarations (var and typed), the full expression set
(arithmetic/comparison/logical operators, ternary ?:, ++/--, negation),
string concatenation, if/else if/else, for, foreach (T x in coll),
while, try/catch/finally, throw, lambdas (=>), and List<T> /
Dictionary<K,V> collection initializers.int/long/short → int, double/float/
decimal → double, bool, string, object, …) so code translates
cleanly to/from every other supported language.ApolloVM (getParser, createRunner, createCodeGenerator)
and exported from apollovm.dart; .cs files resolve to the csharp
language.test/tests_definitions/csharp_*.test.xml.(a, b) -> expr, (int a) -> { ... },
x -> x * 2, () -> 0 (typed or untyped parameters).{ x -> x * 2 }, { x: Int, y: Int -> x + y },
{ 42 }; the last expression is the implicit return value.function(x) ... end.call index is importCount + position, but host imports
(env.print, env.int_to_str, …) are registered lazily while bodies are
generated. A call emitted before an import was registered (e.g. calling a
function and then print-ing, including across await points) got a stale
index and produced invalid Wasm (type mismatch). The import-discovery pass
that freezes importCount before the real pass now runs for all modules (it
only touches idempotent state, so import-free modules stay byte-identical).async/await functions that call other functions and print between
awaits, which now run identically on the interpreter and Wasm.Parse condition ? a : b in Dart, Java, JavaScript and TypeScript, plus the native conditional-expression forms a if condition else b (Python) and if (
condition ? a : b in Dart, Java, JavaScript and TypeScript, plus the
native conditional-expression forms a if condition else b (Python) and
if (condition) a else b (Kotlin).ASTExpressionConditional AST node (only the selected branch is
evaluated); generated idiomatically per target: ?: (Dart/Java/JS/TS),
a if c else b (Python), if (c) a else b (Kotlin), c and a or b (Lua),
and a value-typed if/else block in Wasm.ASTExpressionLiteralFunction AST node that captures the defining scope
(closure semantics); function values held in variables/parameters are now
invocable.(x) => … / (x) { … } (Dart), (x) => … /
x => … (JavaScript, TypeScript) and lambda x: … (Python).(x) -> …, Kotlin { x -> … }, Lua function(x) … end, Python
lambda x: ….int Function(int n), void Function() and
Function(int n) (omitted return type → dynamic); ASTTypeFunction accepts
any other function type, and function types are generated as
int Function(int) (Dart) / bare Function elsewhere.call_indirectcall_indirect instruction. A
function value is an i32 pointer to a heap environment struct
[tableSlot, captured…]; each closure function takes a hidden environment
pointer and reads its captured variables from it.Function return type. Each closure instance gets its own heap environment.Function(int) parameter called with both an int- and a double-returning
lambda) — these report a clear error and still work on the interpreter.self.method() and self.field now round-trip correctly; fixed a
self.field getter parse crash and a stack overflow on self-referential
bindings (s = s + i) during code generation.addFunction is now idempotent and block generation
no longer emits a statement-level function twice).Python
language section and updated the TODO list).Added Python language support (parse, run, and code-generation target), emitting strict, idiomatic Python 3.
PythonIndentationPreprocessor), so the petitparser grammar
consumes Python suites like braces; implicit ((/[/{) and explicit (\)
line continuations, blank/comment lines, and string literals are handled,
and the source is dedented by its common minimum indentation (so a
uniformly-indented embedded block parses like a flush-left one).def f(x: int) -> int:, x: str = ..., List[T]/Dict[K, V]), with a
dynamic/untyped fallback; ==/!=, and/or/not, // integer division,
True/False/None, f-strings for interpolation, and self-based methods.if/elif/else, while,
for ... in, try/except/finally + raise, class with methods, lists
& dicts, and import/from ... import.python (py / .py) across getParser, createRunner,
createCodeGenerator, and the CLI.print accepts any value (not only String)int / double reuse the host number-to-string imports (env.int_to_str /
env.double_to_str); bool lowers in-module to the interned "true" /
"false" literals (via select); print(null) prints "null". String
interpolation gained the same parity.print now accepts null (nullable Object?), and a
bool argument passed to a public Wasm function is marshalled to its i32 ABI
value.new keyword is now parsed in Dart and Java (new User()); new User()
and User() resolve to the same constructor (boundary-safe, so identifiers
like newValue are unaffected). Java also gained a generic
new ClassName(args) rule (previously only new ArrayList<…>() /
new HashMap<…>() were recognized).this.field parameters, and constructor
bodies that assign fields (this.field = value and bare field = value,
with parameters shadowing same-named fields, e.g. User(int id) { this.id = id; }).
Fixed empty-parameter constructors with a body (User() { … }), which threw a
parser cast error.ASTClass.getFunction falls back to the enclosing ASTRoot) — essential for
Java, where all code lives in a class.T name(params) => expr;
(e.g. String toString() => '…';), for top-level functions and instance
methods, including void bodies. Desugars to { return expr; }.int / double / bool / String / object-reference
fields, constructors (this.field params, field initializers, default and
body constructors), instance methods, in-code instantiation, and method calls
(p.sum() and implicit-this foo()). An object is an i32 pointer to a
bump-allocated struct; methods take this as the first parameter; a discovery
pass registers host imports before the code section so cross-function call
indices stay correct.obj.field = value (and this.field = value), including
compound operators (+=, -=, *=, /=, ~/=), via a new
ASTExpressionObjectSetterAssignment node — added to the Dart, Java, Kotlin,
JavaScript and TypeScript grammars, the shared source generator (round-trips
back to obj.field = value), and the Wasm backend (stores at recv + offset).obj.field is now supported in Java (which had no object
getter-access rule); this.field reads resolve to the current instance's field
across all languages (previously routed to a local-getter lookup and failed
with "Can't find getter").print(obj) calls the user-defined toString()print(instance) invokes a user-declared toString() (a class
without one still prints the default Class{…} representation), and
ASTExternalFunction.call now awaits resolved argument values so an async
resolver result isn't passed through as a Future.print(instance) (and string coercion / interpolation) calls the
instance's compiled toString() and prints the resulting string handle.This makes programs like the following compile and run on Wasm with interpreter-parity:
class User {
int id;
String name;
User(this.id, this.name);
String toString() => 'User#$id<$name>';
}
void main() {
var user = new User(123, 'Joe');
print(user);
print(user.id * 1000);
}
Not included: inheritance / interfaces / abstract / static members /
polymorphism.
Wasm throw / try / catch / finally: exception handling now compiles to WebAssembly (previously deferred / loud-failure), engine-agnostic — no Wasm exc
throw / try / catch / finally: exception handling now compiles to
WebAssembly (previously deferred / loud-failure), engine-agnostic — no Wasm
exception-handling proposal required.
$pc-dispatched CFG (like the Asyncify transform but without suspension), so
a throw is an absolute jump to the nearest handler — no fragile relative
br bookkeeping. The thrown value + an in-flight flag live in a small fixed
exception region of linear memory.throw of int/double/bool/String/object values; typed
(on T catch), untyped, and multiple catch clauses; type matching that
mirrors the interpreter (ASTType.acceptsType, e.g. on double accepts an
int); finally on every exit path (normal, caught, propagated, and
return-through-finally, with return-in-finally overriding); throw
inside if/while/for; cross-function propagation (a callee sets the
pending flag + returns, each call site re-checks it); and catching VM
traps — integer division by zero (1 ~/ 0) raises a catchable String
instead of trapping the module.async/await combined
with exceptions in the same function, for-each containing a throw,
multiple raising operations in a single statement, and return <throwing call> directly inside a try.Exception handling: `throw`, `try` / `catch` / `finally` for Dart, Java, Kotlin, JavaScript and TypeScript (parse, run and translate).
throw, try / catch / finally for Dart, Java,
Kotlin, JavaScript and TypeScript (parse, run and translate).
ASTStatementThrow, ASTStatementTryCatch and ASTCatchClause;
a thrown value is carried by the new ApolloVMThrownException.catch (e)): an untyped catch
catches both user thrown values and built-in VM runtime errors (e.g.
integer division by zero, surfaced as their message String); a typed
clause matches user-thrown values by type. The universal supertypes
(Object, dynamic, Exception, Throwable, Error) act as catch-all so
an untyped catch round-trips faithfully across languages.finally always runs (on normal completion, after a caught throw, or on a
return inside try/catch), and a return inside finally overrides.on T catch (e)
/ catch (e), Java catch (T e) (untyped → catch (Exception e)), Kotlin
catch (e: T) (untyped → catch (e: Throwable)), JS/TS catch (e).try/catch/throw is deferred: it fails loudly (no silent
miscompile).Wasm Asyncify: awaits inside `for-each` over a list. for (T e in it) is desugared in the CFG into an indexed loop (__i = 0; while (__i < it.length) {
for-each over a list. for (T e in it) is
desugared in the CFG into an indexed loop (__i = 0; while (__i < it.length) { T e = it[__i]; body; __i++ }), so awaits in the body really suspend. it[__i]
uses the normal list index-access; the index/length are temp locals
spilled/restored on the Asyncify frame stack, and the only non-AST bit (the
length read + index reset) is emitted via a small per-block raw hook. The
iterable must be a list variable; other iterables fall back to
synchronous-collapse. Tested end-to-end through ApolloRunnerWasm.TypeScript language support (parse, run, translate):
TypeScript language support (parse, run, translate):
lib/src/languages/typescript/ts/: ApolloParserTypeScript,
TypeScriptGrammarDefinition, TypeScriptGrammarLexer,
ApolloCodeGeneratorTypeScript, ApolloRunnerTypeScript.number/string/boolean/any/void, T[]/Array<T>), interfaces,
enums, and access modifiers (public/private/protected/readonly/
static/abstract).interface,
enum, abstract class, member modifiers) and erases types cleanly when
targeting JavaScript.'typescript'/'ts' in the parser/runner/generator factories and
the .ts file-extension mapping; CLI apollovm run/translate support .ts.test/tests_definitions/ plus the
test/hello_world.ts fixture and example/apollovm_example_typescript.dart.Generalized class/member modeling in the shared AST (used by Dart and TypeScript):
ASTModifiers: added isAbstract and isProtected (and modifierAbstract).ASTClassNormal: added kind (ASTClassKind.normalClass / abstractClass /
interface), plus optional superClassName and implementsTypes.ASTClassEnum (extends ASTClassNormal) with ASTEnumEntry entries.ASTClassField: added a modifiers field (e.g. static/private/readonly).abstract class, enum, extends/implements,
abstract (body-less) methods, and static fields; these cross-translate
between Dart, TypeScript and JavaScript.Wasm Asyncify: awaits inside control flow (if/if-else/else if, while, for), plus return await ... and x = await .... The generator lowers such async f
Wasm Asyncify: awaits inside control flow (if/if-else/else if,
while, for), plus return await ... and x = await .... The generator
lowers such async functions into a CFG of basic blocks and emits a
program-counter state machine — a loop + br_table dispatch over a $pc
local, with $pc spilled/restored on the Asyncify frame stack alongside the
locals. Awaits become block boundaries; leaf (host) and internal (module-
async) awaits both work inside loops/branches, composing with multi-frame
unwinding. Functions whose awaits are all top-level keep the linear path.
Awaits nested inside expressions (t = t + await f(), return await f() + 1,
await f() + await g()) are hoisted into temp locals automatically. Remaining
unsupported shapes (for-each, awaits in loop/branch conditions) fall back to
synchronous-collapse. Tested end-to-end through ApolloRunnerWasm.
async/await support (real asynchrony) — Dart parse/run/translate and
JavaScript translation:
ASTModifiers.isAsync, new ASTExpressionAwait expression, and a
new abstract generateASTExpressionAwait generator hook. Reuses the
existing ASTTypeFuture/ASTValueFuture (added ASTTypeFuture.futureValueType).async function returns a first-class future immediately
(a non-awaited call yields an ASTValueFuture that can be stored and
awaited later); await suspends on real Dart Futures, including those
returned by external functions declared with a Future<...> return type.
ASTEntryPointBlock.execute awaits the entry future before tearing down the
entry-point context (external mapper, current context).async body keyword (after the parameter list) and
the await prefix expression; Future<T> types parse to ASTTypeFuture;
the await/async contextual keywords no longer shadow identifiers
(e.g. awaiter) or get read as a type name.... ) async { and await ; JavaScript emits
async function / async name( and await .Future<T> collapses to T (effectiveReturnType) and
await is a value pass-through. Compute-style async Dart compiles to Wasm
and matches the AST interpreter.test/apollovm_wasm_asyncify_prototype_test.dart): a hand-assembled
two-frame module proves real suspension against the live WasmRuntime — a
running call unwinds to the host (saving live locals to linear memory), the
host awaits a real Dart Future, then re-invokes the export which rewinds
and resumes. Demonstrates multi-frame state preservation, exactly-once
prologue execution, and two concurrent computations interleaving by host
delay.async function whose awaits are statement-level
calls — a low-memory Asyncify control region (WasmModuleContext) with a
LIFO frame stack, live-local spill/restore, br_table resume dispatch
supporting multiple await points in one function, and multi-frame
unwinding: an async function may await another module async function
(an internal frame) as well as a host import (a leaf). The unwind
propagates up every frame on the call stack to the host and rewinds back
down (an eligibility fixed-point decides which async functions transform;
the rest use synchronous-collapse). Validated against the live runtime in
test/apollovm_wasm_asyncify_codegen_test.dart and the multi-frame /
mixed-await cases in test/apollovm_wasm_asyncify_runner_test.dart. Shapes
that still fall back to synchronous-collapse: awaits nested in control flow,
multiple awaits in one statement, and async recursion.ApolloRunnerWasm.executeFunction
now detects real-suspension async functions (flagged in apollovm_sig)
and drives their unwind/rewind loop, awaiting a real Dart Future from a
host function registered via the new ApolloRunnerWasm.mapWasmAsyncFunction
API. So real-suspension async/await works end-to-end through the VM
(test/apollovm_wasm_asyncify_runner_test.dart). A br_table
multi-await/multi-frame transform is the remaining follow-up.async function maps to a suspend fun
(the declared Future<T> collapses to T), and await e becomes just e
(suspension is implicit when calling a suspend function in coroutines).test/apollovm_async_test.dart (parse, real-suspension ordering,
await chains, top-level async, identifier guard, Dart/JS/Kotlin translation)
and test/apollovm_wasm_async_test.dart (AST-vs-compiled-Wasm parity).Lua language support (parse, run, and translate):
lib/src/languages/lua/ module: ApolloParserLua,
LuaGrammarDefinition/LuaGrammarLexer, ApolloCodeGeneratorLua and
ApolloRunnerLua, all built on the shared AST (no AST changes).local functions, local/global variables,
if/elseif/else, while, numeric and generic for ... in ipairs(...),
return, expressions/operators (and/or/not, ~=, .. concatenation),
table constructors (list and map), and a table-based class convention
(Name = {}, Name.__index = Name, function Name:method(...)) grouped
into the shared class AST. Return types are inferred (void vs dynamic).end, local
variables, .. string concatenation, and/or/not/~=, table literals,
and self./self: prefixing inside methods.ApolloVM (getParser/createRunner/createCodeGenerator).test/apollovm_lua_test.dart cover parse+run, translate+re-execute
to Dart/Lua/Kotlin, and bidirectional table-based classes.Kotlin language support (parse, run, and translate), reaching parity with the existing Java feature set:
lib/src/languages/kotlin/ module: ApolloParserKotlin,
KotlinGrammarDefinition/KotlinGrammarLexer, ApolloCodeGeneratorKotlin
and ApolloRunnerKotlin, all built on the shared AST (no AST changes).fun declarations, val/var
declarations (with type inference), Int/Double/Boolean/String/
Unit/Any/List/Map types, if/else, for (x in ...), while,
expressions/operators, listOf/mapOf literals, and "$x" / "${expr}"
string templates. println is normalized to the VM's print.ApolloVM (getParser/createRunner/createCodeGenerator);
.kt files already mapped to kotlin.test/apollovm_kotlin_test.dart cover parse+run and
Kotlin→Dart/Java/Kotlin translation round-trips.ApolloParserJavaScript, JavaScriptGrammarDefinition, JavaScriptGrammarLexer): parses .js/javascript source into the shared ApolloVM AST. Covers classes (fields + methods, static, constructor), top-level function declarations, let/const/var, for/for...of/while, if/else if/else, list literals, ++/--, compound assignment, strict equality (===/!==), and single/double-quoted strings plus back-tick template literals with ${ … } interpolation. Untyped sites map to dynamic; method/function return types are inferred as void (no value-return) or dynamic.ApolloCodeGeneratorJavaScript): emits idiomatic modern JS from any loaded AST (Dart, Java, or JS) — let/const, template literals for string interpolation, for...of, top-level functions, untyped params/fields, ===/!==, and Math.trunc(a / b) for integer division.ApolloRunnerJavaScript): executes JS-parsed ASTs in the VM (subject to the VM's existing limitation that arithmetic requires concrete/inferable types — dynamic-typed arithmetic is unsupported, as for Dart dynamic).javascript/js in ApolloVM.getParser, createRunner, and createCodeGenerator.apollovm run/translate now work on .js files (the .js extension already mapped to javascript); added a test/hello_world.js fixture and updated the CLI banner to "Dart, Java and JavaScript".javascript_basic_* definitions (parse + execute + round-trip + cross-translation to Dart/Java) and a JavaScript generation block to the Dart class-function test.constructor semantics with this.x parameters, and full ESM are not yet supported.apollovm translate printed Instance of 'Future<StringBuffer>' instead of the translated source — writeAllSources() was stringified without await. Fixed for all languages.for-each / for...of over any iterable: ASTStatementForEach only accepted an ASTValueArray, so iterating a list bound to a dynamic/Object variable (which resolves to a plain ASTValueStatic) threw at runtime. It now iterates any resolved Iterable (and Map values), and wraps each element into a concretely-typed ASTValue (via ASTValue.fromValue) so per-element operations (e.g. arithmetic, string concatenation) work. Affects all languages; enables JavaScript for...of over arrays.+ - * / % == != > < …) dispatched on the operand's static ASTValue.type and only handled concrete primitives, so two dynamic/var/Object operands (e.g. untyped JavaScript parameters) threw Can't perform '+' operation with types: dynamic + dynamic even when the runtime values were real numbers/strings. ASTExpressionOperation.run now resolves each "boxed"/untyped operand to its concrete ASTValue (via ASTValue.fromValue) before dispatching. Affects all languages; enables executing parsed JavaScript arithmetic./ is now floating-point division (ASTExpressionOperator.divideAsDouble), matching JS semantics (7 / 2 === 3.5) instead of integer division.const add = (a, b) => a + b;, const square = n => n * n;, const greet = () => { … };) is parsed and desugared to a named function declaration — callable by name (add(1, 2)), at top level or as a local statement, with expression or block bodies. Translates to a regular function/method on output. Anonymous arrows passed as callbacks (true closures) are a follow-up.!(a > b) was emitted as !a > b (which re-parses as (!a) > b). The negated operand is now parenthesized when complex. Affects all languages.javascript_basic_vars, branches, while_loop, for_loop, comparisons, division, negation, this_method, plus the earlier class_function, control_flow, for_of, arithmetic, and arrow-function definitions.example/ — apollovm_example_java.dart, apollovm_example_kotlin.dart and apollovm_example_javascript.dart (each load + run + translate to Dart, with verified output) — and fixed the existing apollovm_example.dart to await writeAllSources() (was printing Instance of 'Future<StringBuffer>'). README updated with a Kotlin section and the CLI banner now reads "Dart, Java, Kotlin and JavaScript".Wasm collections — compound subscript assignment (P3, part 9):
Wasm collections — compound subscript assignment (P3, part 9):
m[k] += v (and -=, *=, /=, ~/=) and the same for list indices a[i] += v now compile to Wasm. Lowered by desugaring c[k] OP= v into c[k] = c[k] OP v, so it reuses the existing get/set codegen and works for maps (int/String keys) and lists across int/double values. Matches the interpreter on both wasm_run and Chrome (e.g. a frequency counter can now use m[w] += 1 directly).Wasm collections — map parameters & returns (P3, part 8):
Maps across the host boundary. The runner marshals a Dart Map into the module's map layout (header + parallel key/value buffers, via the exported __alloc) for Map parameters, and decodes a returned map-header pointer back into a Dart Map. Covers int/String keys × int/double/String/bool values, including round-tripping and returning a map built with m[k] = v.apollovm_sig custom section now encodes a map type as [7, <key tag>, <value tag>], so raw-byte modules self-describe their key/value types. Element read/write was factored into shared helpers used by both list and map marshalling.Wasm collections — map .keys / .values + iteration (P3, part 7):
m.keys and m.values now compile to Wasm: each materializes a fresh list by copying the map's parallel key (or value) buffer (which already has the list element layout), so for (var k in m.keys) / for (var v in m.values) work via the existing list for-each. Matches the interpreter on both wasm_run and Chrome.m.keys → key type, m.values → value type) so the loop variable is correctly typed.Wasm collections — maps with String keys (P3, part 6):
Map<String, V> now compiles to Wasm (V = int/double/String/bool): literals, m[k] get, m[k] = v set, .length/.isEmpty/.isNotEmpty, and .containsKey(k). Matches the interpreter on both wasm_run and Chrome.__streq(a, b) helper (length check + byte loop), so e.g. containsKey("app") correctly returns false for a map keyed by "apple", and multi-byte UTF-8 keys work.Wasm collections — maps with int keys (P3, part 5):
Map<int, V> now compiles to Wasm (V = int/double/String/bool). A map value is an i32 pointer to a 16-byte header [length][capacity][keysPtr][valuesPtr] with parallel key/value buffers; lookup/set is a linear scan with i64 key equality. Matches the interpreter on both wasm_run and Chrome.{}), m[k] get, m[k] = v set (in-place update or append, growing both buffers when full), .length, .isEmpty/.isNotEmpty, and .containsKey(k).a[i] = v (the subscript-assignment AST node now lowers to Wasm for both maps and lists).String keys (need a string-equality helper), .keys/.values/iteration, map parameters/returns, and compound subscript assignment (m[k] += v) — note m[k] = m[k] + 1 already works.Dart subscript assignment — m[k] = v and a[i] = v (frontend + interpreter):
m[k] = v / a[i] = v failed with a SyntaxError). Compound operators (+=, -=, *=, /=, ~/=) are supported, e.g. m["x"] += 1 for building a frequency map.ASTExpressionVariableEntryAssignment; new ASTValue.writeKey/writeIndex write into the underlying Map/List in place. A Map is always written by key (even a numeric one); a List by index. Round-trips through the code generators (parse → regenerate → re-parse).{} literal (typed Map<dynamic,dynamic>) is now assignable to a typed map such as Map<String,int> — ASTTypeMap.acceptsType treats a dynamic key/value component as a wildcard, matching how lists already ignore their element type for assignment (so Map<String,int> m = {}; works, like List<int> a = [];).Dart Map support — frontend + interpreter (read/query; prerequisite for Wasm maps):
Map<K,V> type annotations now parse. mapTyped() was missing the value-type parser (it accepted only Map<K,> and read the , token as the value type), so every Map<int,int> declaration failed with a SyntaxError. Key/value types also accept List<...> (e.g. Map<String,List<int>>).Map<dynamic,dynamic>, so Map<int,int> m = {1:10} assigns cleanly. ASTExpressionMapLiteral.resolveType returns the Map type (it previously returned just the value type).m[k] now does a key lookup for any Map (the access was incorrectly routed to positional/list indexing whenever the key was numeric, so int-keyed maps failed).Map class (CoreClassMap): getters .length/.isEmpty/.isNotEmpty/.keys/.values and methods .containsKey/.containsValue/.remove/.clear. .keys/.values resolve to List<keyType>/List<valueType> so iterating them yields properly-typed elements.m[k] = v) is a follow-up (the grammar's assignment target is still a bare variable).List into module memory (header + elements buffer, via the exported __alloc) for List parameters, and decodes a returned list-header pointer back into a Dart List. Covers int/double/String/bool element lists, including round-tripping (List<int> echo(List<int> a)) and building a result with .add before returning it.apollovm_sig custom section now carries list types as [6, <element tag>] (was a single opaque tag), so modules loaded from raw bytes self-describe their list element types; the runner uses 64-bit element reads/writes via BigInt so it works on both the Dart VM and dart2js (Chrome).String/List parameter now also forces an exported __alloc (previously only String params did), so list-only functions can be fed their arguments.Wasm collections — String & bool element lists (P3, part 3):
List<String> and List<bool> now compile to Wasm: literals, index reads a[i], for (var e in a), .add, and the .first/.last/.isEmpty/.isNotEmpty/.length getters all work (elements stored as i32 — a string pointer or a 0/1 boolean). Matches the interpreter on both wasm_run and Chrome.Wasm collections — growable lists .add + getters (P3, part 2):
[length:i32][capacity:i32][dataPtr:i32] pointing at a separately-allocated elements buffer. This makes .add aliasing-safe — growing reallocates the data buffer (doubling capacity, memory.copying existing elements) and updates the header in place, so existing references observe the new length/contents.list.add(x) now compiles to Wasm for int/double lists (including starting from an empty [] literal), growing linear memory on demand..first, .last, .isEmpty, .isNotEmpty.bool-returning functions loaded from raw Wasm bytes now decode correctly: the apollovm_sig custom section is emitted for bool returns (not just String signatures), and the runner maps the i32 0/1 back to a Dart bool.Wasm collections — lists, read + iterate (P3, part 1):
int/double list literals compile to linear-memory blocks; index reads a[i], the .length getter, and for (var e in a) now compile to Wasm (matching the interpreter, on both wasm_run and Chrome).Wasm generator — major feature expansion (ApolloGeneratorWasm), moving toward full Dart parity:
while and for loops now compile to Wasm (block/loop/br_if/br), including return from inside a loop. Added the br opcode helper and recursion into loop bodies when collecting function locals.Wasm.call.% (i64.rem_s), logical &&/|| (i32.and/i32.or), logical negation ! (i32.eqz), and unary minus - (f64.neg / i64 multiply-by--1).bool literals and bool-typed locals (represented as Wasm i32).== 0 fast-path (i64.eqz) was incorrectly applied to any operator with a literal-0 right operand (e.g. x > 0 compiled as x == 0). It is now restricted to the equals operator.&& / ||: now compile to an if/else so the right operand is only evaluated when needed. The AST interpreter was also made short-circuiting, so interpreted and compiled execution stay consistent (and match Dart).% semantics: integer and double modulo now return the Dart-correct non-negative result in [0, |b|) for negative operands (sign-corrected via scratch locals); double % is computed as a - trunc(a / b) * b.+=, -=, *=, …) emitted its operation to a discarded buffer (missing out/context), producing broken code; now applied to the real output.Tests: added Wasm coverage for every feature above plus a combined integration test (prime counting / sum-of-squares using loops + calls + logic + modulo), all executed against the real compiled-and-run Wasm module.
Wasm strings — String parameters + memory.grow (P2, part 5, completes the strings milestone):
String parameters now work: the runner encodes the Dart string into module memory (via the exported __alloc, guided by the apollovm_sig param tags) and passes the i32 pointer. Enables String echo(String s), String greet(String name), etc.__alloc and the inline concat allocator) now grows linear memory on demand (memory.size/memory.grow), so large strings/concatenations no longer trap.Wasm strings — number→string interpolation (P2, part 4):
int/double ("n=$n", "${a + b}") now compiles to Wasm via host imports env.int_to_str/env.double_to_str; the host formats the number (matching the interpreter; doubles via ASTTypeDouble.doubleToString) and writes it into module memory.__alloc bump-allocator function so host imports can allocate strings in the module's memory (reentrant host→module calls), plus value-returning host imports and i64↔BigInt marshalling on the web.Wasm strings — String-returning functions (P2, part 3):
String now work: the value is an i32 pointer the runner decodes back into a Dart String.apollovm_sig section records each public function's high-level return/parameter type tags, so the runner can marshal strings even for modules loaded from raw bytes. Emitted only when a public signature involves a String (pure-numeric modules stay byte-identical).Wasm strings — concatenation + bump allocator (P2, part 2):
$hp) bump allocator; runtime string allocation via __alloc + memory.copy.+, adjacent string literals, and $var interpolation of String variables now compile to Wasm (left-folded binary concatenation producing a fresh [len:i32][utf8] string). Validated on wasm_run and Chrome.Wasm linear-memory foundation + strings (P2, part 1 — print of string literals):
[len:i32][utf8]; a String value is an i32 pointer into the exported linear memory.print(stringLiteral) lowers to a host import env.print(i32). The runtime layer (WasmRuntime/WasmModule) now wires host imports at instantiation and exposes exported memory reads, on both the native (wasm_run) and browser runtimes; the runner decodes the pointer and routes to externalPrintFunction.wasm.dart memory opcodes (i32/i64 load/store, load8_u/store8, memory.size/grow/copy/fill) and section-id helpers.Test infrastructure — WebAssembly GC validation path:
dart test -p chrome) parity harness that runs generated Wasm on Chrome's own engine. The native wasm_run backend (wasmtime 14 / wasmi 0.31) does not support the WebAssembly GC proposal; Chrome (v119+) does.wasm-gc test tag (dart_test.yaml) and a WasmGC capability spike; CI's wasm_run-based jobs exclude the tag (--exclude-tags wasm-gc) while the Chrome job runs it. This gates the planned dual-target (linear-memory + WasmGC) backend work.Bug fixes:
return propagation: a return inside a for, while, or for-each loop was ignored (the loop shadowed runStatus with a fresh instance and never broke on return). Returns now propagate and stop iteration correctly.ASTType equality: ASTTypeBool, ASTTypeString, ASTTypeObject, ASTTypeConstructorThis, ASTTypeVar, ASTTypeDynamic, ASTTypeNull, and ASTTypeVoid mistakenly checked other is ASTTypeInt, so equal instances never compared equal. Each now checks its own type.ASTTypeMap: building a map from a flat key/value list read from the (empty) target map instead of the input list, producing an empty map._escapeString): backslashes were not escaped, producing invalid Java string literals (e.g. "a\b" instead of "a\\b").ASTExpression.literalNumType returned ASTNumType.int for double literals.ASTValueString/ASTValueNum comparison/equality error messages.Tests:
ASTValue, ASTType, ApolloVM, expressions, the core library, and the Wasm generator.Dependencies:
Updated getTypeByName to treat 'const' as an unmodifiable variable type alongside 'final'.
DartGrammarDefinition:
getTypeByName to treat 'const' as an unmodifiable variable type alongside 'final'.classFieldDeclaration, constructorTypedParameterDeclaration, statementVariableDeclaration, and parameterDeclaration parsers to accept both final and const tokens as optional modifiers.statementVariableDeclaration to recognize 'const' as unmodifiable and handle it similarly to 'final'.Fixed string template merging logic to correctly handle variable accesses and literal strings by swapping checks on expression1 and expression2.
ApolloCodeGeneratorDart:
generateASTExpression:
expression1 and expression2._tryMergeQuotedStrings and related helper methods._isQuotedString, _isSingleQuoteString, _isDoubleQuoteString_canConvertQuote, _convertQuote_mergeQuotedStrings, _tryMergeQuotedStringsDartGrammarDefinition:
computeFinalExpression.DartGrammarLexer:
BaseGrammarLexer abstract class.BaseGrammarLexer.BaseGrammarLexer (new):
computeFinalExpression and reduceExpressionBlock.Java11GrammarLexer:
BaseGrammarLexer.Java11GrammarDefinition:
computeFinalExpression for operator precedence.a + (b + c) to (a + b) + c for consistent operator associativity.ASTExpressionFunctionInvocation and related classes:
ASTExpressionFunctionInvocation and related classes:
WithCallChainFunction to support chained function invocations.chainFunctionInvocation to hold chained calls.ApolloCodeGenerator).ApolloCodeGenerator:
_generateChainFunctionInvocation helper for chained calls.Dart grammar (dart_grammar.dart):
expressionGetterAccess parser to parse and attach chained function invocations.CoreClassPrimitive:
_functionToString field and initialization.CoreClassString:
_functionToString external class function returning self.toString().CoreClassInt:
_functionToString external class function returning self.toString().CoreClassDouble:
_functionToString external class function with custom logic:
.0 suffix.toString().ASTExpressionVariableEntryAccess:
ASTExpressionVariableEntryAccess:
_asyncTry with _run2 to improve element access with proper type casting._readElement<V> method to read elements with type safety.readIndexASTValue and readKeyASTValue to return typed ASTValue<V>.ASTExpressionFunctionInvocation and subclasses:
chainFunctionInvocation field.run methods to invoke chained functions sequentially after the initial call._callChainFunction helper to process chained calls asynchronously.ASTExpressionChainFunctionInvocation class representing chained function calls.toString methods to include chained function calls.ASTExpressionObjectFunctionInvocation, ASTExpressionObjectEntryFunctionInvocation, ASTExpressionGroupFunctionInvocation:
run methods to support chained function invocations.lib/src/apollovm_code_generator.dart:
Grammar updates (dart_grammar.dart, java11_grammar.dart):
expressionChainFunctionInvocation).ASTValue:
fromValue<V> to convert dynamic values to typed ASTValue<V>.readIndexASTValue<V> and readKeyASTValue<V> methods returning typed ASTValue<V>.CoreClassString:
replaceFirst, trimLeft, trimRight, padLeft, padRight, lastIndexOf, codeUnitAt.getFunction with case-insensitive support.ASTClass:
toString override for better debug output.ASTExpressionVariableEntryAccess:
ASTExpressionVariableEntryAccess:
run method to use nested resolveMapped calls for asynchronous handling._asyncTry to unify index/key reading logic with async support.__throwReadNPE to throw detailed ApolloVMNullPointerException with stack trace on read failures.ASTExpressionObjectEntryFunctionInvocation:
obj[i].fx(args) and obj[key].fx(args).ASTValue:
readKey method signature to accept nullable Object? key parameter for better null safety.ASTValueStatic:
readKey method signature to accept nullable Object? key.CoreClassBase and CoreClassPrimitive:
CoreClassBase and CoreClassPrimitive:
_functionToString external function returning the string representation of the instance.CoreClassString, CoreClassInt, CoreClassDouble, CoreClassList:
toString core function, returning the respective _functionToString.Added new subclass of ASTBlock that allows only a single statement.
ASTSingleLineStatementBlock:
ASTBlock that allows only a single statement.addStatement to enforce single statement constraint.toString to output the single statement without braces.ApolloCodeGenerator:
ASTSingleLineStatementBlock in generateASTNode dispatch.generateASTSingleLineStatementBlock method to generate single-line statement blocks.generateASTBlock to delegate to generateASTSingleLineStatementBlock if block is single-line.generateASTBranchIfBlock to generate single-line blocks without braces.ApolloGenerator:
generateASTSingleLineStatementBlock.ASTSingleLineStatementBlock in generateASTNode dispatch.ApolloGeneratorWasm:
generateASTSingleLineStatementBlock to generate the single statement.Dart and Java11 grammars:
ASTSingleLineStatementBlock parsing support.codeBlockOrSingleLineBlock parser to accept either a block or a single-line block.branchIfBlock parser to accept single-line blocks as branch bodies.Added new AST statement classes:
Added new AST statement classes:
ASTStatementBlock representing a block of statements.ASTStatementFunctionDeclaration representing a function declaration statement.ApolloCodeGenerator:
ASTStatementFunctionDeclaration and ASTStatementBlock.generateASTStatementFunctionDeclaration and generateASTStatementBlock.ApolloGenerator interface:
generateASTStatementFunctionDeclaration and generateASTStatementBlock.ASTStatementFunctionDeclaration and ASTStatementBlock.ApolloGeneratorWasm:
generateASTStatementBlock implementation.generateASTStatementFunctionDeclaration (throws UnimplementedError).apollovm_ast_statement.dart:
ASTStatementBlock class wrapping an ASTBlock with proper context and run behavior.ASTStatementFunctionDeclaration class wrapping an ASTFunctionDeclaration with run behavior registering the function in the context.apollovm_ast_toplevel.dart:
ASTFunctionDeclaration with:
toASTValueFunction method to convert to ASTValueFunction.toFunction method to convert to a Dart Function with limited support for zero or one positional parameter.resolveFunctionType and callFunctionTyped helpers for function type resolution and invocation.apollovm_ast_type.dart:
ASTTypeFunction representing function types with optional return type and parameters.callCasted helper method for generic type casting.apollovm_ast_value.dart:
ASTValueFunction wrapping a Dart Function with proper type and invocation support.ASTValueFunction.apollovm_utils.dart:
resolveGeneric<T>() helper function for generic type resolution.dart_grammar.dart:
ASTStatementFunctionDeclaration and ASTStatementBlock.ASTExpressionObjectEntryFunctionInvocation:
ASTExpressionObjectEntryFunctionInvocation:
run and toString methods for execution and debugging.ApolloCodeGenerator:
ASTExpressionObjectEntryFunctionInvocation.generateASTExpression method to handle ASTExpressionObjectEntryFunctionInvocation.ApolloGenerator interface:
generateASTExpressionObjectEntryFunctionInvocation.ApolloGeneratorWasm:
generateASTExpressionObjectEntryFunctionInvocation throwing UnimplementedError.Dart and Java11 grammars:
expressionObjectEntryFunctionInvocation to support syntax for object entry function invocation expressions.Added ApolloImportManager to manage package/library imports and resolve core packages.
ApolloImportManager to manage package/library imports and resolve core packages.VMContext:
importManager field and import method to support import resolution and delegation to parent contexts.VMScopeContext as a final subclass of VMContext for scoped runtime contexts.VMClassContext and other runtime contexts to be final and use VMScopeContext for nested scopes.ASTStatementImport:
ASTRoot:
ApolloRunner:
importManager field and initialization with default import manager.dart:math core package.importManager to execution and function lookup calls.CorePackageBase and CorePackageMath:
path getter for core package identification.dart, java11, wasm):
ASTStatementImport).ASTStatementImport.auto-import-dart-math attribute in test XML.dart:math and use pow function.VMScopeContext instead of base VMContext for nested scopes.VMObject field value methods to use VMScopeContext.Changed type of finalExpressionOp from ASTExpressionOperation? to ASTExpression?.
DartGrammarDefinition:
finalExpressionOp from ASTExpressionOperation? to ASTExpression?.expressionOp from ASTExpressionOperation to ASTExpression.generateASTValueDouble: replaced manual double string formatting with ASTTypeDouble.doubleToString for consistent double string representation.
ApolloCodeGenerator:
generateASTValueDouble: replaced manual double string formatting with ASTTypeDouble.doubleToString for consistent double string representation.ASTStatementVariableDeclaration:
_runImpl2: updated type cast check to allow dynamic type to bypass cast validation.ASTTypeDouble:
doubleToString to format double values consistently, optionally allowing scientific notation.toString method of ASTTypeNum to return 'num' instead of 'double'.ASTValueAsString and ASTValuesListAsString:
valueToString method that formats doubles using ASTTypeDouble.doubleToString.CorePackageMath:
num and return ASTTypeDouble.instance for functions returning double values.Test framework (apollovm_languages_test_definition.dart):
_testCall for clearer test logs.Added new ASTExpression subclass ASTExpressionNegative to represent unary negative expressions.
ASTExpression subclass ASTExpressionNegative to represent unary negative expressions.ASTExpression subclass ASTExpressionGroupFunctionInvocation to represent function calls on grouped expressions (e.g., (-d).toStringAsFixed(4)).ApolloCodeGenerator:
generateASTExpression to handle ASTExpressionNegative and ASTExpressionGroupFunctionInvocation.generateASTExpressionNegative and generateASTExpressionGroupFunctionInvocation._generateFunctionInvocation helper.ApolloGenerator interface:
generateASTExpressionNegative and generateASTExpressionGroupFunctionInvocation.generateASTExpression to support new expression types.apollovm_ast_expression.dart:
ASTExpressionNegative with type resolution, runtime evaluation, and string representation.ASTExpressionGroupFunctionInvocation with function resolution and invocation logic.-expr).(expr).func(args)).ApolloGeneratorWasm:
generateASTExpressionNegative and generateASTExpressionGroupFunctionInvocation.Added new AST node class representing a while loop statement.
ASTStatementWhileLoop:
run method to execute the loop with proper context handling.ASTTypeVoid.instance.ApolloCodeGenerator:
ASTStatementWhileLoop in generateASTStatement.generateASTStatementWhileLoop method to generate while loop source code.ApolloGenerator:
generateASTStatementWhileLoop.ASTStatementWhileLoop in generateASTStatement.DartGrammarDefinition:
statementWhileLoop parser to parse while loop statements.statementWhileLoop into the main statement parser.Java11GrammarDefinition:
statementWhileLoop parser to parse while loop statements.statementWhileLoop into the main statement parser.ApolloGeneratorWasm:
generateASTStatementWhileLoop method throwing UnimplementedError.ASTStatementWhileLoop in generateASTStatement.Tests:
dart_basic_printFibonacci.test.xml demonstrating while loop usage in Dart source and generated code.Replaced ASTFunctionDeclaration with generic ASTInvocableDeclaration for function and constructor declarations.
ASTInvocableDeclaration:
ASTFunctionDeclaration with generic ASTInvocableDeclaration for function and constructor declarations.ASTClassConstructorDeclaration for class constructors with support for this parameters.resolveRuntimeType method to support runtime type resolution with context and node.call and run methods to support async and context-aware execution.initializeVariables for constructor variable initialization.ASTParametersDeclaration:
P.ASTConstructorParametersDeclaration and ASTFunctionParametersDeclaration subclasses.ASTParameterDeclaration:
ASTConstructorParameterDeclaration with thisParameter flag.this parameters.ASTFunctionSet and ASTConstructorSet:
ASTInvokableSet with single and multiple implementations.ASTConstructorSet for constructors, similar to function sets.ASTClassNormal:
ASTConstructorSet.resolveNode to resolve constructors.ASTRoot:
getFunction to return constructors if matching class name and signature.ASTExpression and ASTValue:
resolveRuntimeType and getHashcodeValue methods for runtime type and value hashing.getHashcodeValue.ASTExpressionFunctionInvocation and subclasses:
ASTInvocableDeclaration for function retrieval.run method to support async and context-aware invocation.ASTExpressionObjectGetterAccess:
_runGetter helper for getter invocation.ASTStatementVariableDeclaration:
unmodifiable flag.resolveRuntimeType.ASTType:
ASTTypeConstructorThis singleton for constructor this parameter.resolveRuntimeType method.ASTVariable:
resolveRuntimeType method.CorePackageBase and CoreClassMixin:
ASTFunctionParametersDeclaration.CoreClassList:
first and last getters with runtime component type resolution.DartGrammarDefinition and Java11GrammarDefinition:
ASTFunctionParametersDeclaration and ASTConstructorParametersDeclaration.this constructor parameters.ApolloCodeGeneratorDart and ApolloCodeGeneratorJava11:
generateASTClassConstructorDeclaration method to generate constructor code.ApolloParserWasm:
ASTFunctionParametersDeclaration.Test:
dart_basic_linearRegression.test.xml with Dart source for linear regression and forecast.dart_basic_calculateShippingCost.test.xml for shipping cost calculation.Added optional asDouble parameter to control numeric type coercion.
ASTValueNum:
from method:
asDouble parameter to control numeric type coercion.asDouble is specified.Added ASTExpressionNullValue class to represent null literal expressions.
ASTScopeVariable:
'null' to resolve as ASTValueNull.ApolloCodeGenerator:
generateASTExpressionNullValue method to generate code for null expressions.generateASTExpression to handle ASTExpressionNullValue.generateASTValueDouble:
fractionDigitsFromScientificNotation to determine the number of fraction digits needed for doubles in scientific notation.ApolloGenerator interface:
generateASTExpressionNullValue method.generateASTExpression to handle ASTExpressionNullValue.ApolloRunner:
importCorePackageMath parameter to constructor and createRunner method.importCorePackageMath is true, maps math functions from CorePackageMath to external functions.CorePackageMath:
dart:math functions as external functions for ApolloVM.pow, sqrt, sin, cos, tan, asin, acos, atan, atan2, log, exp, abs, min, max.Language grammars (dart, java11):
null literal expressions producing ASTExpressionNullValue.Language runners (dart, java11, wasm):
importCorePackageMath parameter in constructors.ApolloGeneratorWasm:
generateASTExpressionNullValue throwing UnimplementedError.generateASTExpression to handle ASTExpressionNullValue.Test framework:
dart_basic_stdv.test.xml demonstrating usage of math functions (pow, sqrt) and null checks.importCorePackageMath: true to enable math functions in tests.Added new operator divideAsInt with symbol '~/'.
ASTAssignmentOperator:
divideAsInt with symbol '~/'.asASTExpressionOperator getter to support divideAsInt.getASTAssignmentOperator and getASTAssignmentOperatorText to handle divideAsInt and its assignment form '~/='.ASTExpressionVariableAssignment:
divideAsInt operator in evaluation and string representation.dart_grammar.dart):
assigmentOperator parser to recognize '~/=' operator.java11_grammar.dart):
divideAsInt operator (remains unsupported).resolveType: updated to return ASTTypeArray of the specified type or deduced common element type.
ASTExpressionListLiteral:
resolveType: updated to return ASTTypeArray of the specified type or deduced common element type.children: fixed to include type correctly.ASTStatementVariableDeclaration:
ASTExpressionListLiteral values with type adjustments or cast exceptions.ASTStatementForEach:
variableType field.variableType.ASTType:
commonType method to find common compatible type between two types.ASTTypeArray:
toValue: improved to cast ASTValueArray to correct generic type if needed.ASTValueArray:
cast method to convert to another generic type with optional component type.Dart grammar (dart_grammar.dart):
statementForEach parser updated to parse explicit variable type before variable name.expressionListLiteral parser updated to infer common element type if not specified.Java11 grammar (java11_grammar.dart):
statementForEach parser updated to parse explicit variable type before variable name.Tests:
findMax(List<int> numbers) function with multiple test cases including empty list handling.Added new AST statement class representing a for-each loop with a variable name, iterable expression, and loop block.
ASTStatementForEach:
run method to iterate over an iterable AST value, declaring the loop variable in a nested context and running the loop block.void.ApolloCodeGenerator:
ASTStatementForEach in generateASTStatement.generateASTStatementForEach method to output a for-in loop syntax with variable declaration and loop block.ApolloGenerator:
generateASTStatementForEach.generateASTStatement to dispatch to generateASTStatementForEach for ASTStatementForEach.Dart language grammar (dart_grammar.dart):
statementForEach to parse Dart-style for-each loops (for (var x in iterable) { ... })._forEachVariableDecl to parse optional var or final before variable name.Java language grammar (java11_grammar.dart):
statementForEach to parse Java-style for-each loops (for (Type var : iterable) { ... })..github/workflows/dart.yml: updated actions/checkout from v3 to v6 and codecov/codecov-action from v3 to v5.
CI:
.github/workflows/dart.yml: updated actions/checkout from v3 to v6 and codecov/codecov-action from v3 to v5.apollovm.dart:
src/apollovm_utils.dart.apollovm_runner.dart:
ApolloRunner:
executeClassMethod: changed to async, added parameter normalization before execution.normalizeParameters method to normalize positional and named parameters against AST function declarations.executeFunction: added parameter normalization for top-level functions.apollovm_utils.dart (new):
List for typed list creation and on Map for case-insensitive key lookup.apollovm_ast_toplevel.dart:
ASTFunctionDeclaration:
normalizeParameters, normalizePositionalParameters, and normalizeNamedParameters methods to convert and normalize parameters according to function declarations.IterableASTFunctionDeclarationExtension with resolveBestMatchBySignature to select best matching function overload by parameter signature.apollovm_ast_type.dart:
ASTType:
fromType factory to create ASTType from Dart Type.toASTValue method to convert native values to ASTValue according to type.toASTValue overrides in primitive and collection types (ASTTypeBool, ASTTypeNum, ASTTypeInt, ASTTypeDouble, ASTTypeString, ASTTypeNull, ASTTypeVoid, ASTTypeArray, ASTTypeArray2D, ASTTypeMap, ASTTypeFuture).fromType methods for ASTTypeArray and ASTTypeMap to create instances from Dart generic types.ASTTypeArray and CoreClassList:
List<String>, List<int>, etc.).fromType methods to resolve types generically.ASTTypeMap:
fromType method for common map generic types.ASTTypeFuture:
toASTValue override to handle conversion from native or future values.apollovm_ast_value.dart:
ASTValue.from factory:
ASTTypeBool to create ASTValueBool.apollovm_core_base.dart:
ApolloVMCore.getClass:
generics parameter.List class resolution now uses CoreClassList.fromType with generic type.CoreClassList:
CoreClassList<T>.fromType static method to resolve generic list classes.ASTTypeArray accordingly.wasm_runner.dart:
ApolloRunnerWasm:
wasm_runtime.dart:
ensureBooted() method and lastBootError getter to WasmRuntime interface.wasm_runtime_dart_html.dart, wasm_runtime_generic.dart, wasm_runtime_web.dart:
ensureBooted() as no-op and lastBootError as null.wasm_runtime_io.dart:
ensureBooted() to call boot.lastBootError getter.Tests (apollovm_languages_test_definition.dart):
_parseJsonList to return untyped List without generic type conversion..toListOfType() extension for typed list checks.Tests (apollovm_wasm_test.dart):
wasmRuntime.ensureBooted() before checking support.Added support for external getters in ApolloVM:
Added support for external getters in ApolloVM:
ApolloExternalGetterMapper to map Dart getters to ApolloVM.getGetter and getMappedExternalGetter methods in VMContext for getter resolution.ASTBlock with getter management (addGetter, getGetter, etc.).ASTGetterDeclaration and related classes (ASTClassGetterDeclaration, ASTExternalGetter, ASTExternalClassGetter) to represent getters in the AST.ASTExpressionGetterAccess base class and subclasses ASTExpressionLocalGetterAccess and ASTExpressionObjectGetterAccess for getter expressions.DartGrammarDefinition to parse getter access expressions.ApolloCodeGenerator and ApolloGenerator interfaces and implementations to generate code for getter access expressions.externalGetterMapper field to VMContext to support external getter mapping.Core library updates:
CoreClassList class implementing core List type support with external class functions and getters for common list operations (add, remove, length, isEmpty, sublist, etc.).CoreClassMixin for external function and getter creation.Added new operators: remainder, and, or.
ASTExpressionOperator:
remainder, and, or.getASTExpressionOperator and getASTExpressionOperatorText to support %, &&, and ||.ASTExpressionOperation:
resolveType to handle remainder, and, and or operators.operatorRemainder for % operator supporting int and double operands.operatorAnd and operatorOr for logical && and || with boolean coercion._toBoolean to convert various ASTValue types to boolean.throwOperationError to handle new operators.ASTValue and subclasses:
% operator support in ASTValueNum, ASTValueInt, and ASTValueDouble.ASTValue operator overrides.operator ~/(ASTValue other) implementations in ASTValueInt and ASTValueDouble.ASTValueNum).DartGrammarDefinition:
expressionOperator parser to recognize %, &&, and ||.&& and ||.% operator with higher precedence within blocks.&& and ||.WasmGenerator:
UnsupportedError for unsupported operators in WASM code generation.Added unmodifiable field to distinguish var and final types.
ASTTypeVar:
unmodifiable field to distinguish var and final types.instanceUnmodifiable for final.unmodifiable flag and set name accordingly.toString and equality to reflect unmodifiable state.ApolloVMCore:
double and Double core classes returning CoreClassDouble.CoreClassPrimitive:
_externalClassFunctionArgs2 for external class functions with two parameters.CoreClassString:
length, isEmpty, isNotEmptysubstring, indexOf, startsWith, endsWithtrim, split, replaceAllgetFunction to support these new string functions.CoreClassInt:
tryParse.compareTo, abs, sign, clamp, remainder, toRadixString, toDoublegetFunction to support new int functions.Added new class CoreClassDouble:
parseDouble (alias parse), tryParse, valueOf.compareTo, abs, sign, clamp, remainder,
toStringAsFixed, toStringAsExponential, toStringAsPrecision,
toInt, round, floor, ceil, truncate.getFunction to provide these functions.ApolloCodeGeneratorDart:
writeAllStrings to write concatenated string parts correctly.DartGrammarDefinition:
final keyword returning ASTTypeVar(unmodifiable: true).literalString parser to support concatenation of multiple string literals into ASTValueStringConcatenation.Java11GrammarDefinition:
final keyword returning ASTTypeVar(unmodifiable: true).getTypeByName: added support for Dart types void and bool.
DartGrammarDefinition:
getTypeByName: added support for Dart types void and bool.DartGrammarLexer:
stringContentQuotedLexicalTokenEscaped: added handling of unnecessary escape sequences for characters (, ), {, }, and space in string literals.Tests:
dart_basic_sumOrDouble.test.xml with a test for a Dart function sumOrDouble.dart_basic_main_print_multi_line.test.xml testing multi-line string printing.dart_basic_main_print_unnecessary_escape.test.xml testing string literals with unnecessary escape sequences and ASCII art printing.ApolloCodeGenerator and ApolloCodeGeneratorDart:
ApolloCodeGenerator and ApolloCodeGeneratorDart:
generateASTExpressionOperation: updated to conditionally group complex expressions with parentheses based on operator and presence of literal strings to improve expression formatting and string interpolation merging.add operator when involving variables and literal strings.ASTExpression and subclasses (ASTExpressionOperation, ASTExpressionVariableAssignment, ASTExpressionVariableDirectOperation, ASTExpressionNegation, ASTExpressionFunctionInvocation, etc.):
isComplex getter to distinguish complex expressions.hasLiteralString and hasDescendantLiteralString to detect literal strings in expression trees.toString methods to support optional grouping with parentheses for clarity.ASTExpressionOperation.toString to optionally wrap expressions in parentheses.ASTExpressionVariableAssignment and ASTExpressionVariableDirectOperation to provide detailed toString implementations reflecting operators.childrenOperations and descendantChildrenOperations helpers for expression traversal.ASTAssignmentOperator enum:
symbol field for operator symbol representation.Added library-level documentation describing ApolloVM as a portable VM supporting Dart, Java, and WebAssembly compilation.
lib/apollovm.dart:
library apollovm; to a library directive without a name.AST classes (lib/src/ast/):
children getters to use null-aware spread operators (...? and ?) for optional fields in:
ASTExpressionListLiteralASTExpressionMapLiteralASTStatementVariableDeclarationASTBranchIfElseBlockASTBranchIfElseIfsElseBlockASTTypeASTTypeGenericVariablepubspec.yaml:
petitparser from ^6.1.0 to ^7.0.2lints from ^3.0.0 to ^6.1.0dependency_validator from ^3.2.3 to ^5.0.5xml from ^6.5.0 to ^6.6.1Tests (test/apollovm_languages_extended_test.dart, test/apollovm_version_test.dart):
library; directive at the top of test files for consistency.Deprecated WasmRuntimeDartHTML in favor of WasmRuntimeWeb.
WasmRuntime:
WasmModuleFunction typedef to represent a WebAssembly-exported function with metadata including the Dart function and a varArgs flag.WasmModule.getFunction signature to return WasmModuleFunction<F>? instead of just F?.WasmRunnerWasm:
ApolloRunnerWasm to handle WasmModuleFunction with varArgs flag.List argument.wasm_runtime_generic.dart:
WasmModuleGeneric.getFunction to return null as WasmModuleFunction<F>?.wasm_runtime_io.dart:
WasmModuleIO.getFunction to return a WasmModuleFunction with varArgs: true.wasm_runtime_dart_html.dart:
WasmRuntimeDartHTML in favor of WasmRuntimeWeb.WasmModuleBrowser.getFunction to return a WasmModuleFunction with varArgs: true.createWasmRuntime to return WasmRuntimeDartHTML with deprecation warning.wasm_runtime_web.dart:
WasmRuntimeWeb implementation using dart:js_interop and web package.WasmModuleBrowser wrapping _WasmInstance with proper JS interop.getFunction returns a Dart function wrapping JS function calls with argument conversion and varArgs: false.num or BigInt.createWasmRuntime to return WasmRuntimeWeb.pubspec.yaml:
web: ^1.1.1.Tests:
operation3 and operation4 verifying multi-parameter Dart functions compiled to Wasm and executed correctly.Suppress deprecated dart:html usage warning with // ignore: deprecated_member_use import directive
Updated minimum Dart SDK constraint to >=3.10.0 <4.0.0.
Dependency updates:
swiss_knife: ^3.3.14async_extension: ^1.2.22data_serializer: ^1.2.1petitparser: ^6.1.0collection: ^1.19.1args: ^2.7.0wasm_run: ^0.1.0+2crypto: ^3.0.7path: ^1.9.1test: ^1.31.0Reformatted code for Dart 3.10+
lib/src/languages/wasm/wasm_runtime_browser.dart
dart:html usage warning with
// ignore: deprecated_member_use import directive- wasm_run: ^0.1.0+1
New ASTExpressionVariableDirectOperation (++ and -- operators).
New ASTExpressionVariableDirectOperation (++ and -- operators).
New StrictType interface for equalsStrict over ASTTypeInt and ASTTypeDouble.
ApolloGeneratorWasm:
generateASTExpressionVariableDirectOperation.- sdk: '>=3.3.0 <4.0.0' - swiss_knife: ^3.2.0 - data_serializer: ^1.1.0 - petitparser: ^6.0.2 - path: ^1.9.0 - lints: ^3.0.0 - dependency_validator: ^
sdk: '>=3.3.0 <4.0.0'
swiss_knife: ^3.2.0
data_serializer: ^1.1.0
petitparser: ^6.0.2
path: ^1.9.0
lints: ^3.0.0
dependency_validator: ^3.2.3
test: ^1.25.2
xml: ^6.5.0
WasmRuntime: new VM implementation.
WasmRuntime: new VM implementation.wasm_runtime_io.dart:acceptsType: now also accepts an ASTTypeInt.
ASTTypeDouble:
acceptsType: now also accepts an ASTTypeInt.wasm_generator.dart:
isBits64.getNodeIdentifier: added optional parameter requester.
ASTNode:
getNodeIdentifier: added optional parameter requester.children and descendantChildren.ASTFunctionDeclaration:
getNodeIdentifier: now can also resolve identifiers inside statements.Wasm:
Wasm64: added i64WrapToi32.WasmContext:
returns state.ApolloGeneratorWasm:
_autoConvertStackTypes.generateASTStatementReturnValue and generateASTStatementReturnVariable:
Dart CI: added job test_exe.
Improve variable type resolution while compiling to Wasm.
Improve type resolution of ASTTypeVar.
ASTTypeVar.async methods.ASTBranchIfElseBlock and ASTBranchIfElseIfsElseBlock:
ASTBranchIfElseBlock and ASTBranchIfElseIfsElseBlock:
blockElse: optional.ASTParametersDeclaration:
allParameters.ASTTypeInt and ASTTypeDouble:
bitsASTTypeInt.instance32 and ASTTypeInt.instance64.ASTTypeDouble.instance32 and ASTTypeDouble.instance64.ASTValueNum:
negative.ApolloGeneratorWasm:
Wasm: split in Wasm32 and Wasm64 with improved opcodes.unreachable end of function cases.generateASTValue, generateASTValueDouble, generateASTValueInt.generateASTExpressionVariableAssignment, generateASTStatementExpressiongenerateASTBranchIfBlock, generateASTBranchIfElseBlock, generateASTBranchIfElseIfsElseBlock.generateASTStatementReturnWithExpression, generateASTStatementReturn, generateASTStatementReturnValue.ApolloParserWasm:
ASTTypeInt or ASTTypeDouble type is a 32 or 64 bits.ApolloRunnerWasm:
WasmModule:
resolveReturnedValue.
f64, the JS bigint needs to be converted to a Dart BigInt.New WasmModuleExecutionError.
pubspec.yaml: update description.
pubspec.yaml: update description.getFunctionCodeUnit: fix returned codeUnit when allowClassMethod = true.
ApolloRunner:
getFunctionCodeUnit: fix returned codeUnit when allowClassMethod = true.New SourceCodeUnit and BinaryCodeUnit.
New SourceCodeUnit and BinaryCodeUnit.
CodeUnit now is abstract:
source to code.Using SourceCodeUnit instead of CodeUnit when necessary.
ApolloParser renamed to ApolloCodeParser:
ApolloSourceCodeParser.ApolloRunner:
getFunctionCodeUnit.Using Leb128 from package data_serializer.
BytesOutput now extends BytesEmitter (from data_serializer).
ApolloGeneratorWasm:
generateASTExpressionOperation: allow operations with different types (auto casting from int to double).New WasmRuntime and WasmModule.
WasmRuntimeBrowser.New WasmModuleLoadError.
WasmContext:
data_serializer: ^1.0.11
wasm_interop: ^2.0.1
crypto: ^3.0.3
path: ^1.8.3
- README.md: added Wasm example. - Minor fixes.
README.md: added Wasm example.Basic support to compile the AST tree to Wasm.
New ApolloGeneratorWasm.
New BytesOutput for binary code generation.
data_serializer: ^1.0.10
Your coding agent can read these notes before it upgrades. Set up the MCP server →