← Commit history
docs: delete MIGRATION.md and main.ash; drop references to them
lennoxrose committed on Oct 18, 2026 at 01:07 UTC
7 files changed+7−596
MIGRATION.mdremoved
+0−466@@ -1,466 +0,0 @@1
-# Ash → Enterprise Java-like Ash Migration Checklist2
-3
-This document defines the target design for Ash and the ordered migration plan.4
-5
-Ash must become a strictly enterprise-grade, Java-like, high-level, statically typed language.6
-It must always use classes, packages, explicit types, access modifiers, constructors, interfaces, enums, records, generics, and exceptions.7
-8
-The old Ash syntax is deprecated. The new syntax is the only supported application-level syntax.9
-10
-## Design principles11
-12
-- [x] Ash is object-oriented at the application level.13
-- [x] Ash is statically typed.14
-- [x] Ash is explicit and predictable.15
-- [x] Ash is suitable for backend services, desktop apps, games, CLI tools, and frontend libraries.16
-- [x] Ash is familiar to Java, C#, Kotlin, and TypeScript developers.17
-- [x] Ash is more ergonomic than Java, but never script-like.18
-- [x] Ash is designed for eventual fast native compilation.19
-- [x] Every program uses a package and a class-based entry point.20
-- [x] `//` comments remain supported.21
-- [x] `/* ... */` and `///` comments are supported.22
-23
-## Target syntax24
-25
-- [x] Use `package` declarations.26
-- [x] Use `import` declarations.27
-- [x] Use `public`, `private`, `protected`, and package-private access modifiers.28
-- [x] Use `class`, `interface`, `enum`, `record`, `abstract`, `sealed`, and `permits`.29
-- [x] Use `extends` and `implements`.30
-- [x] Use `new` for object creation.31
-- [x] Use `this` and `super`.32
-- [x] Use `static`, `final`, and `const`.33
-- [x] Use `public static void main(String[] args)` as the standard entry point.34
-- [x] Use `return`, `if`, `else`, `else if`, `switch`, `case`, `default`.35
-- [x] Use `while`, `for`, `do`, `break`, and `continue`.36
-- [x] Use `try`, `catch`, `finally`, `throw`, and `throws`.37
-- [x] Use `true`, `false`, and `null`.38
-- [x] Use `instanceof`.39
-- [x] Use `var` only for obvious local type inference.40
-- [x] Use Java-style generics: `List<Player>`, `Map<String, Player>`, `Set<T>`.41
-- [x] Use lambdas and method references.42
-- [x] Use `Optional<T>` and `Result<T, E>` where appropriate.43
-44
-## Keyword migration45
-46
-Complete this table and implement it consistently:47
-48
-| Old Ash | New Ash | Status |49
-|---|---|---|50
-| `local x = 5;` | `int x = 5;` or `var x = 5;` | [x] |51
-| `say x;` | `System.out.println(x);` or `Console.println(x);` | [x] |52
-| `given` | `if` | [x] |53
-| `otherwise` | `else` | [x] |54
-| `during` | `while` | [x] |55
-| `each x in xs` | `for (Type x : xs)` | [x] |56
-| `stop;` | `break;` | [x] |57
-| `next;` | `continue;` | [x] |58
-| `forge name(args)` | method declaration | [x] |59
-| `yield value;` | `return value;` | [x] |60
-| `attempt` | `try` | [x] |61
-| `handle (e)` | `catch (Exception e)` | [x] |62
-| `raise value;` | `throw new SomeException(...);` | [x] |63
-| `yes` | `true` | [x] |64
-| `no` | `false` | [x] |65
-| `none` | `null` | [x] |66
-| `@import <file.ash>;` | `import package.module;` | [x] |67
-| `@import <file.ash> as x;` | `import package.Type;` (aliases are dropped, decision D1) | [x] |68
-| `forge(args) { ... }` (anonymous) | lambda `(args) -> expr` or `(args) -> { ... }` | [x] |69
-| `a and b` / `a or b` / `not a` | `a && b` / `a \|\| b` / `!a` | [x] |70
-| `each x in xs` (`in`) | `:` separator; `in` becomes a plain identifier | [x] |71
-| `e.message` | `e.getMessage()` | [x] |72
-| `file.NAME` (module variable) | `static` field, `ClassName.NAME` | [x] |73
-| builtin functions (`len`, `push`, ...) | stdlib methods (see Builtin mapping) | [x] |74
-75
-## Type system76
-77
-- [x] Define primitive types: `int`, `long`, `float`, `double`, `bool`, `char`, `byte`, `short`, `void`.78
-- [x] Define core object types: `String`, `Object`, `Array<T>`, `List<T>`, `Map<K, V>`, `Set<T>`, `Optional<T>`, `Result<T, E>`.79
-- [x] Require explicit parameter and return types on public methods.80
-- [x] Allow `var` only for local variables with obvious inferred types.81
-- [x] Require `final` for immutable locals and fields.82
-- [x] Make fields `private` by default.83
-- [x] Forbid public mutable fields except with explicit approval.84
-- [x] Define nullable types using `?`, for example `String?`.85
-- [x] Make non-nullable types reject possible null assignments at compile time.86
-- [x] Define integer, floating-point, and mixed numeric behavior precisely.87
-- [x] Define integer division and modulo behavior precisely.88
-- [x] Define generic classes, interfaces, methods, and collections.89
-- [x] Define type inference rules.90
-- [x] Define casting rules.91
-- [x] Define equality and hashing rules.92
-93
-## Object model94
-95
-- [x] Support classes.96
-- [x] Support interfaces.97
-- [x] Support abstract classes.98
-- [x] Support enums.99
-- [x] Support immutable records.100
-- [x] Support constructors.101
-- [x] Support static fields and methods.102
-- [x] Support instance fields and methods.103
-- [x] Support method overloading.104
-- [x] Support method overriding.105
-- [x] Support `@Override`.106
-- [x] Support interface default methods.107
-- [x] Support sealed types.108
-- [x] Support nested classes.109
-- [x] Support generics.110
-- [x] Support lambdas.111
-- [x] Support method references.112
-- [x] Support streams or an equivalent collection pipeline API.113
-- [x] Do not make structs, traits, mixins, or top-level functions the primary application model.114
-115
-## Error handling116
-117
-- [x] Use `try`, `catch`, `finally`, `throw`, and `throws`.118
-- [x] Define checked exceptions for recoverable I/O, parsing, network, and domain failures.119
-- [x] Define runtime exceptions for programming errors.120
-- [x] Define a base `Exception` type.121
-- [x] Define a base `RuntimeException` type.122
-- [x] Require custom exceptions to extend the appropriate base exception.123
-- [x] Require public methods to declare checked exceptions with `throws`.124
-- [x] Define stack traces. (single-frame creation site plus `Caused by:` chain, see Exceptions)125
-- [x] Define error messages.126
-- [x] Define exception chaining.127
-- [x] Do not use hidden error values or implicit panics.128
-129
-## Standard library130
-131
-- [x] Define `ash.lang`.132
-- [x] Define `ash.util`.133
-- [x] Define `ash.io`.134
-- [x] Define `ash.net`.135
-- [x] Define `ash.math`.136
-- [x] Define `ash.time`.137
-- [x] Define `ash.concurrent`.138
-- [x] Define `ash.json`.139
-- [x] Define `ash.cli`.140
-- [x] Define `ash.test`.141
-- [x] Define `ash.desktop`.142
-- [x] Define `ash.game`.143
-- [x] Define `ash.web`.144
-- [x] Define `System.out.println`.145
-- [x] Define `Console.println`.146
-- [x] Define `String`, `StringBuilder`, `Math`, `Object`.147
-- [x] Define `List<T>`, `ArrayList<T>`, `Map<K, V>`, `HashMap<K, V>`, `Set<T>`, `HashSet<T>`.148
-- [x] Define `Optional<T>`, `Result<T, E>`, and `Stream<T>`.149
-- [x] Define `Files`, `Path`, `Json`, `Http`, `Thread`, and `Executor`. (`Http` always fails and `Thread`/`Executor` run on the caller: the VM has no network or threads)150
-- [x] Define collection methods or stream operations: `filter`, `map`, `reduce`, `sorted`, `toList`, `collect`, `forEach`.151
-152
-## Formatting rules153
-154
-- [x] Use four-space indentation.155
-- [x] Put `{` on the same line as the declaration or statement.156
-- [x] Put `}` on its own line.157
-- [x] Use one statement per line.158
-- [x] Use `PascalCase` for classes, interfaces, enums, and records.159
-- [x] Use `lowerCamelCase` for methods, variables, fields, and parameters.160
-- [x] Use `UPPER_SNAKE_CASE` for constants.161
-- [x] Use lowercase dot-separated package names.162
-- [x] Use `isX()` for boolean getters.163
-- [x] Use `getX()` and `setX()` only when valuable.164
-- [x] Use `of()`, `from()`, `parse()`, and `create()` for factory methods.165
-- [x] Use `toString()`, `toInt()`, and similar conversion names consistently.166
-167
-## Performance model168
-169
-- [x] Choose the first implementation strategy: interpreter, bytecode VM, or direct tree-walking evaluator.170
-- [x] Choose the long-term execution strategy: AOT native compilation, JIT, or hybrid.171
-- [x] Define whether Ash uses tracing GC, reference counting, arenas, or a hybrid memory model.172
-- [x] Define primitive value representation.173
-- [x] Define object representation.174
-- [x] Define string representation.175
-- [x] Define array/list representation.176
-- [x] Define map representation.177
-- [x] Define function/closure representation.178
-- [x] Avoid unnecessary boxing.179
-- [x] Support value-like records.180
-- [x] Define concurrency: threads, executors, synchronization, and optional async/await.181
-- [x] Define startup-time and memory predictability requirements for games and desktop applications. (see below)182
-183
-## Approved decisions (Phase 0)184
-185
-| ID | Decision |186
-|---|---|187
-| D1 | `import ... as` is dropped. Imports name a type or package: `import ash.util.List;`, `import ash.util.*;`. |188
-| D2 | The old front end is deleted (executed 2026-10-18): `ashvm` and `kiln` accept only new Ash. Old-syntax source is rejected by the new front end with migration messages (D3). |189
-| D3 | Old syntax is diagnosed by context (e.g. `say` followed by an expression start at statement position), not by reserving the words. `next`, `stop`, `each`, `no`, `in`, `as`, `say` ... are ordinary identifiers in new Ash. |190
-| D4 | `T[]` is the surface array syntax; `Array<T>` is its canonical type name. |191
-| D5 | `System.out.println` is the print API. `Console.println` is removed from the spec. |192
-| D6 | `const` = `static final` compile-time constant. `final` alone = variable assigned once. |193
-| D7 | Default access: package-private for classes/methods/constructors, `private` for fields. Public mutable fields need `@PublicField`. |194
-| D8 | `T?` is the nullable type. `Optional<T>` for return values that may be absent. `Result<T, E>` exists only in the stdlib. Non-null `T` rejects `null` at compile time. |195
-| D9 | The REPL is an explicit exception: each line is wrapped in a hidden class body. It is not application syntax. |196
-| D10 | `} else {`, `} catch (...) {`, `} finally {` and `} while (...);` may share a line with `}` (Java style). |197
-| D11 | Memory model: tracing GC, reference semantics for objects. The `goals.md` ownership model is shelved. A collector now exists for `ashvm` as an opt-in build (`make GC=1`); default builds and `kiln` binaries still allocate bump/never-free. |198
-| D12 | One shared front end (lexer, parser, AST, type checker) lives in `hearth/front/` and is linked by both `ashvm` and `kiln`. |199
-| D13 | Primitive boolean type is spelled `bool`. |200
-| D14 | Checked exceptions are enforced (Exception subclasses not under RuntimeException must be caught or declared with `throws`). |201
-| D2a | **Resolved (2026-10-18).** The old-Ash-shaped text the front end lowers to is kept as a compiler-internal IR, owned by `hearth/front/src/ir` (one shared IR lexer) and passed in memory from `hearth/front/src/jdriver` to the `ashvm` compiler and the `kiln` code generator. It is not Ash source: no tool reads it from a file, there is no `@import` in it (the lowering emits one unit and the consumer calls its `start`), and no CLI, REPL, example, test or document presents it as a language. Replacing it with a binary IR driven directly by the typed AST remains possible but is not required. |202
-| D16 | **The standard library is optional (2026-10-18).** Only what the compiler cannot work without is built in: `ash.lang` (including `ash.lang.function`) and `ash.util.Iterator`, compiled into `libashfront.a` as C string data (`hearth/front/src/jcore`) and parsed lazily, never read from disk. Everything else (`ash.util`, `ash.io`, `ash.json`, `ash.math`, `ash.time`, `ash.cli`, `ash.test`, `ash.concurrent`, `ash.net`, `ash.web`, `ash.game`, `ash.desktop`) is the separate `ash-stdlib` package, installed with forgepack (`@ash-modules/<pkg>/src/main/ash` and `ash.libs/<pkg>/src/main/ash` are source roots) or pointed at with `ASH_PATH`. `String.join` takes `Iterable<String>` so `ash.lang` does not depend on `ash.util.List`. |203
-| D15 | Performance (CLAUDE.md law): no change may make the recorded baselines slower. Baselines are recorded in `spec/performance-baseline.md` before runtime changes. |204
-205
-## Specification206
-207
-### Keywords208
-209
-Reserved: `package import class interface enum record extends implements permits sealed abstract new this super public private protected static final const native if else switch case default while for do break continue return try catch finally throw throws instanceof void true false null int long float double bool char byte short`.210
-Contextual: `var`, `record`, `sealed`, `permits`. `else if` is `else` followed by `if`.211
-212
-### Operators (highest precedence first)213
-214
-| Level | Operators | Assoc |215
-|---|---|---|216
-| 1 | `() [] . :: x++ x--` | left |217
-| 2 | `++x --x +x -x ! ~ (Type)cast new` | right |218
-| 3 | `* / %` | left |219
-| 4 | `+ -` | left |220
-| 5 | `<< >> >>>` | left |221
-| 6 | `< <= > >= instanceof` | left |222
-| 7 | `== !=` | left |223
-| 8 | `&` | left |224
-| 9 | `^` | left |225
-| 10 | `\|` | left |226
-| 11 | `&&` | left |227
-| 12 | `\|\|` | left |228
-| 13 | `?:` | right |229
-| 14 | `= += -= *= /= %= &= \|= ^= <<= >>=` | right |230
-| 15 | `->` (lambda) | right |231
-232
-`&&` and `||` short-circuit. Conditions of `if`/`while`/`for`/`?:` must be `bool`; numbers, strings and `null` are not truthy.233
-234
-### Numerics235
-236
-- `int` is 32-bit two's complement, `long` 64-bit, `short` 16, `byte` 8, `char` 16-bit unsigned, `float` 32-bit IEEE, `double` 64-bit IEEE. Integer overflow wraps (`int` exactly with `--wrap-int`; `long` exactly with the same flag; without it `long` is limited to 2^53). Division by zero for integers throws `ArithmeticException`; for floating point it yields inf/NaN.237
-- Integer `/` truncates toward zero; `%` takes the sign of the dividend (`-7 % 3 == -1`).238
-- Mixed arithmetic widens: byte/short/char -> int -> long -> float -> double. Narrowing needs an explicit cast.239
-- Literals: `42` int, `42L` long, `1.5` double, `1.5f` float, `1e3` double, `0x1F`, `'a'` char, escapes `\n \t \r \\ \" \' \0 \xHH`.240
-- `double` prints in shortest round-trip form with a mandatory `.0` for whole values (`5.0`); the old Ash "plain integer" format is retired for doubles. `int`/`long` print as integers.241
-- String `+` converts the other operand with `toString()`.242
-243
-### Nullability244
-245
-`T` is non-null; `T?` may be `null`. Assigning a `T?` to `T`, dereferencing a `T?` without a check, or passing `null` for `T` is a compile error. `x != null` narrows `x` inside the guarded branch. `Optional<T>` is a library type, not a replacement for `T?`.246
-247
-### Exceptions248
-249
-`Object <- Throwable <- Exception <- RuntimeException`. Checked: `Exception` subclasses outside `RuntimeException` (`IOException`, `ParseException`, ...). Unchecked: `RuntimeException` and subclasses (`IndexOutOfBoundsException`, `KeyNotFoundException`, `ArithmeticException`, `NullPointerException`, `ClassCastException`, `IllegalArgumentException`, `IllegalStateException`). Chaining: `new X(message, cause)`, `getCause()`. Stack traces: `printStackTrace()` prints `Type: message`, then one ` at Class.method(File.ash:line)` line for the place the exception was created (the backend keeps no call stack, so there are no outer frames and no runtime cost on normal calls), then `Caused by: ...` for each cause. An uncaught exception prints that trace to stderr and exits with status 1. Runtime error text of the old VM maps as: `index out of bounds` -> `IndexOutOfBoundsException`, `key not found` -> `KeyNotFoundException`.250
-251
-### Packages and compilation units252
-253
-One public top-level type per file; file name equals the type name plus `.ash`. A package maps to a directory under the source root (`src/main/ash/com/acme/Main.ash` is `package com.acme;`). The program entry is the class named on the command line (or the sole class declaring `public static void main(String[] args)`). `ash.lang` is imported implicitly. Dependencies installed by forgepack (`ash.libs/`, `@ash-modules/`) are additional source roots; `ash.pkg` format is unchanged.254
-255
-### Types256
-257
-Primitives: `int long float double bool char byte short void`. Object types: `String Object Array<T> List<T> ArrayList<T> Map<K,V> HashMap<K,V> Set<T> HashSet<T> Optional<T> Result<T,E> Stream<T> StringBuilder Math`. Functional interfaces in `ash.lang.function`: `Function<T,R> Predicate<T> Supplier<T> Consumer<T> BiFunction<A,B,R> Runnable Comparator<T>`. Generics use erasure: type arguments are checked at compile time and not materialised at runtime; primitive type arguments are not allowed (use `Integer`, `Double` etc. boxes, which the VM represents as unboxed tagged values to avoid allocation).258
-259
-### Object model details260
-261
-- Enums may have fields, constructors, methods; `values()`, `ordinal()`, `name()`, `valueOf(String)`. Switch over an enum or sealed type must be exhaustive when used as an expression.262
-- Records: `record Point(int x, int y) { }` generate private final fields, accessors `x()`, canonical constructor (compact form allowed), `equals`, `hashCode`, `toString`.263
-- Interfaces: abstract methods, `default` methods, `static` methods. An interface with a single abstract method is a functional interface and is the target type for lambdas and method references.264
-- Switch: statement form `case X:` and expression form `case X -> expr;`. No `yield`; a block arm uses `return`-free `-> { ... }` only in statement switches; expression switches use single-expression arms.265
-- Lambdas capture effectively-final locals by value.266
-- Overloading resolves by arity then most specific applicable parameter types; ambiguity is a compile error.267
-- `equals`/`hashCode`: `Object` defaults to identity; strings, boxes, records and enums define value equality.268
-- `native` methods bind to C functions through the C ABI in `hearth/ashvm/src/builtins` and `kiln` runtime.269
-270
-### Builtin mapping271
-272
-| Old builtin | New API |273
-|---|---|274
-| `len(s)`, `len(a)` | `s.length()`, `a.length` / `list.size()` / `map.size()` |275
-| `str(x)` | `String.valueOf(x)` / `x.toString()` |276
-| `num(s)` | `Double.parse(s)` / `Integer.parse(s)` |277
-| `type(x)` | `x.getClass().getName()` |278
-| `sqrt abs floor` | `Math.sqrt Math.abs Math.floor` |279
-| `chr ord` | `(char) n`, `(int) c` |280
-| `input()` | `System.in.readLine()` |281
-| `exit(n)` | `System.exit(n)` |282
-| `push pop insert slice delete sort` | `list.add list.removeLast list.add(i,x) list.subList list.remove list.sort` |283
-| `keys values has` | `map.keys() map.values() map.containsKey` |284
-| `map filter reduce` | `list.stream().map/filter/reduce` |285
-| `split join substring indexOf contains starts_with ends_with replace repeat upper lower trim` | `split String.join substring indexOf contains startsWith endsWith replace repeat toUpperCase toLowerCase trim` |286
-| `read_file write_file append_file file_exists rename_file delete_file make_dir list_dir` | `Files.readString writeString appendString exists move delete createDirectory list` (throw `IOException`) |287
-288
-### Formatting289
-290
-Four spaces, `{` same line, `}` own line except `} else`/`} catch`/`} finally`/`} while`, one statement per line, Java naming, `isX()` boolean getters.291
-292
-### Runtime representation (as implemented)293
-294
-| Ash value | VM runtime value |295
-|---|---|296
-| `int long short byte float double char` | number (char is its code point; ints are exact below 2^53, see limits table) |297
-| `bool`, `null` | IR booleans, IR none |298
-| `String` | string; `Integer`, `Double`, `Boolean`... are the same unboxed values (no allocation) |299
-| `T[]`, `List<T>`, `Stream<T>` | array |300
-| `Map`, `Set` | map keyed by a string form of the key, entries `[key, value]` |301
-| object | map `{"__c", "__vt", "__is", fields...}`; methods are top-level functions, `__vt` is a flat key to function table, `__is` the set of supertype names |302
-| lambda / method reference | closure (captures by value, matching effectively-final locals) |303
-| record | object with synthesised accessors, `toString`, `equals`, `hashCode` |304
-| enum constant | object with `__name`/`__ord`, held in the class's static map |305
-| static state | one module-level map per class |306
-307
-Startup and memory requirements for games and desktop apps: startup cost is proportional to the *reachable* classes only (tree-shaken module, no stdlib loaded unless used); there is no garbage collector yet, so a long-running program must bound its allocation (reuse objects, avoid building strings in loops) or its memory grows until exit. A collector is the prerequisite for unbounded-lifetime programs and is not part of this migration. Memory: allocation never frees until exit (D11 until a collector exists). Concurrency: no threads on this VM; `ash.concurrent.Executor` runs tasks to completion on the caller, there is no `async/await`.308
-309
-### Transition and performance protocol310
-311
-1. The old front end is deleted (D2). Old-syntax tests were deleted or migrated; the regression suites compare every program with its `.out` file.312
-2. Shared runtime tests live in `hearth/front/tests/cases/run/` with names ending `_j.ash`; project-specific ones in `<project>/tests/cases/<feature>/`.313
-3. Before runtime changes, `spec/performance-baseline.md` records `fib(30)` and sum-to-20M for `ashvm`; they are re-measured after each major runtime change.314
-315
-## Migration phases316
-317
-### Phase 0 — Specification lock318
-319
-- [x] Finalize the complete keyword list.320
-- [x] Finalize operator precedence and associativity.321
-- [x] Finalize primitive and object types.322
-- [x] Finalize nullability rules.323
-- [x] Finalize exception model.324
-- [x] Finalize package/import model.325
-- [x] Finalize class/interface/enum/record model.326
-- [x] Finalize formatting rules.327
-- [x] Produce before/after examples for every old construct.328
-329
-### Phase 1 — Lexer migration330
-331
-- [x] Remove old keywords from the lexer.332
-- [x] Add all new keywords.333
-- [x] Add new operators and punctuation where needed.334
-- [x] Preserve `//` comments.335
-- [x] Add `/* ... */` comments.336
-- [x] Add `///` documentation comments.337
-- [x] Update lexer tests.338
-- [x] Ensure old Ash programs fail with clear migration errors.339
-340
-### Phase 2 — Parser and AST migration341
-342
-- [x] Parse package declarations.343
-- [x] Parse imports.344
-- [x] Parse classes.345
-- [x] Parse interfaces.346
-- [x] Parse enums.347
-- [x] Parse records.348
-- [x] Parse fields.349
-- [x] Parse constructors.350
-- [x] Parse methods.351
-- [x] Parse access modifiers.352
-- [x] Parse static and final modifiers.353
-- [x] Parse generics.354
-- [x] Parse `new` expressions.355
-- [x] Parse `this` and `super`.356
-- [x] Parse Java-style control flow.357
-- [x] Parse enhanced for loops.358
-- [x] Parse switch statements and/or expressions.359
-- [x] Parse try/catch/finally.360
-- [x] Parse throw and throws.361
-- [x] Parse lambdas.362
-- [x] Parse method references.363
-- [x] Update AST tests.364
-365
-### Phase 3 — Type system366
-367
-Implemented in `hearth/front/src/jtypes` (`check_expr.c`, `check_stmt.c`, `check_class.c`), driven by `ashvm check`. Covered by `hearth/front/tests/cases/types/*_j.ash`, run with `hearth/front/tests/scripts/check_types.sh`. Generics use erasure with argument-driven inference; wildcards are approximated (see `jtypes.h`).368
-369
-- [x] Implement primitive type checking.370
-- [x] Implement class and interface type checking.371
-- [x] Implement generics.372
-- [x] Implement nullability checking.373
-- [x] Implement access-control checking.374
-- [x] Implement inheritance and override checks.375
-- [x] Implement interface implementation checks.376
-- [x] Implement method overload resolution.377
-- [x] Implement casting and `instanceof`.378
-- [x] Implement type inference for `var`.379
-- [x] Produce clear type errors.380
-381
-### Phase 4 — Compiler/VM execution382
-383
-Implemented in `hearth/front/src/jlower` as a **lowering to the internal IR** (see D2a) that `ashvm` runs and `kiln` compiles natively (no VM change, so the performance law holds by construction). The program becomes one IR unit whose `start` function is called by the consumer; objects are maps with a flat vtable, methods are top-level functions, `instanceof`/`catch` use per-class supertype tables, and native stdlib methods are `@Lower("...")` templates over the old builtins. `ashvm run file.ash` executes on `ashvm`, `kiln file.ash -o out` compiles natively. Covered by `hearth/front/tests/cases/run/*_j.ash` and `examples/`, run on both engines by `hearth/ashvm/tests/scripts/run_regression.sh` and `hearth/kiln/tests/scripts/run_regression.sh`.384
-385
-- [x] Compile or interpret class declarations.386
-- [x] Compile or interpret constructors.387
-- [x] Compile or interpret methods.388
-- [x] Compile or interpret static members.389
-- [x] Compile or interpret object creation.390
-- [x] Compile or interpret inheritance and interfaces.391
-- [x] Compile or interpret exceptions.392
-- [x] Compile or interpret generics.393
-- [x] Compile or interpret lambdas and closures.394
-- [x] Compile or interpret collections.395
-- [x] Implement `public static void main(String[] args)`.396
-- [x] Update runtime tests.397
-398
-### Phase 5 — Standard library399
-400
-Source: `ash.lang` and `ash.util.Iterator` in `hearth/front/src/jcore` (core, built in); the rest in the separate `ash-stdlib` package, `src/main/ash/ash/{util,io,json,math,time,cli,test,concurrent,net,web,game,desktop}` (written in new Ash, lowered with the program; only reachable classes are emitted). Packages that need OS capabilities the old VM does not have are provided as **pure-Ash models** and say so in their doc comments: `ash.net.Url` (parsing only, no sockets), `ash.web` (Request/Response/Handler/Router, no server socket), `ash.game` (Vec2, fixed-step GameLoop, no real-time clock), `ash.desktop` (retained Widget tree rendered as text, no window), `ash.concurrent` (tasks run to completion on the caller, no threads), `ash.time.Duration` (no clock). Real sockets, windows, threads, clocks and command-line arguments need new native builtins in `ashvm` **and** `kiln` (a separate change that must be benchmarked against the performance law). `Result<T, E>` exists in `ash.util`. Not done: documentation comments on every public method.401
-402
-- [x] Implement `ash.lang`.403
-- [x] Implement `ash.util`.404
-- [x] Implement `ash.io`.405
-- [x] Implement `ash.math`.406
-- [x] Implement `ash.time`. (pure `Duration`; no wall clock on this VM)407
-- [x] Implement `ash.concurrent`. (deterministic single-threaded `Executor`/`Future`; no real threads on this VM)408
-- [x] Implement `ash.json`.409
-- [x] Implement `ash.cli`.410
-- [x] Implement `ash.test`.411
-- [x] Add documentation for every public API. (every public stdlib type, method, constructor and constant has a `///` comment)412
-413
-### Phase 6 — Examples and documentation414
-415
-- [x] Hello world.416
-- [x] Variables and primitives.417
-- [x] Classes and constructors.418
-- [x] Interfaces and implementations.419
-- [x] Inheritance and abstract classes.420
-- [x] Enums and switch.421
-- [x] Records.422
-- [x] Generics.423
-- [x] Collections and streams.424
-- [x] Lambdas and method references.425
-- [x] Exceptions.426
-- [x] File I/O.427
-- [x] JSON.428
-- [x] CLI program.429
-- [x] Game program.430
-- [x] Backend/server program.431
-- [x] Desktop-style program.432
-- [x] Update README.433
-- [x] Update language reference.434
-- [x] Update migration guide.435
-436
-## Known differences and limits of the current backend437
-438
-What still differs from the spec, and why. Everything else in the Numerics, Exceptions and Switch sections is implemented and tested.439
-440
-| Area | Current behaviour | Spec says | To lift it |441
-|---|---|---|---|442
-| `int` overflow | **exact Java 32-bit wrap with `--wrap-int`** (`ashvm run --wrap-int`, `kiln --wrap-int`) (`+ - * << >>>`, unary `-`, `++ --`, compound assignment, narrowing casts; `(int) double` saturates). Default is off because it costs about 2x on arithmetic-heavy loops (the performance law); for-loop counters bounded by their own condition never pay it | wraps | none needed; choose the flag |443
-| `long` | **exact 64-bit with `--wrap-int`**: a plain number while it fits in 2^53, an exact two-halves value beyond (`+ - * / % << >> >>> & | ^ ~`, comparisons, casts, `Long.parse`, printing, `Long.MAX_VALUE/MIN_VALUE`), checked against an independent 64-bit model. Without the flag it is a double (exact below 2^53, printed correctly) so default speed is unchanged | 64-bit | none needed; choose the flag |444
-| `double` / `float` | Java's shortest round-trip printing for both (`7.068577499999999`, `1.0E-4`, `3.3000002`), verified against independent oracles; `float` operations round to 24 bits after every operation; every finite value, including denormals and `Double.MAX_VALUE`, via an exact big-integer expansion for exponents outside -5..22 (`Double.MIN_VALUE` prints `4.9E-324`, as in Java) | same | none |445
-| Assignment, `++`, `--` inside expressions | supported with Java evaluation order (`a[k] = k++`, `x = y = 5`, `while ((n += 3) < 10)`) | allowed | none |446
-| `switch` | full Java semantics: fallthrough, `default` anywhere, early `break`, `continue` through a switch (simple switches stay a plain if-chain) | same | none |447
-| `return` through `finally` | supported (finally body is inlined); `break`/`continue` out of a try-with-finally are not specially handled | Java semantics | |448
-| Calls | at most 6 arguments through dynamic dispatch | unlimited | more `__vcN` helpers |449
-| VM limits | **256 functions** (the call opcode has a one-byte operand; `ashvm` now reports it instead of silently calling the wrong function), 128 locals per function, 256 module variables, 256 call frames, 32 nested `try`. The lowering drops unreachable code, so typical programs use a fraction of this | none | widen the operands in `ashvm` and `kiln` |450
-| Output | no `print` without newline, no stderr (uncaught exceptions print to stdout, exit status 1) | stderr | new builtins |451
-| Memory | default: allocation is never freed (D11). **`make GC=1` in `ashvm` builds a precise mark-sweep collector** (`src/vm/C/gc.c`): objects are appended to a registry as tagged pointers at their four constructors (inlined, no hashing on the allocation path; the lookup table and mark bits exist only during a collection), collection runs only at the start of opcodes that allocate (string concat, array/map literals, string indexing, closures, builtin calls; never inside a builtin callback), roots are the value stack, module globals, chunk constants and the pending raised value. The call, loop and arithmetic paths carry no added instruction. Churn program: 212 MB default vs 47 MB with the collector; identical output on every `ashvm` case with the collector running at every safe point (`tests/scripts/gc_check.sh`) and on every generated test and example (49 of 49, `ashvm` and `kiln` native). **Cost, median of 12 alternating runs, collector build / collector-free build: hashmap 1.008, fib 1.006, loop 0.998, countdown 1.007, loop_varbound 1.000** - the noise floor was measured: two collector-free builds of identical source that differ only in function alignment differ from each other by up to 0.7% (1.000, 0.993, 1.000, 0.998, 1.000), so the collector's 0.995-1.007 is inside that band; on the allocation-heavy `hashmap` it is at the top edge and it does append to a registry per allocation, so a cost of zero is not provable and it stays opt-in under the performance rule. `kiln` native binaries have no collector (its runtime is machine code on a bump/`brk` heap) | tracing GC | owner decision to enable by default, and a port to `kiln`'s runtime |452
-| `HashMap`/`HashSet` keys | `equals`/`hashCode`-based for any key type (collision chains; String and number keys use a fast path), size is tracked in O(1) | same | none |453
-| Unsupported syntax (clear parser errors) | anonymous classes, local classes, try-with-resources, static imports, `Iface.super.m()`, import aliases (D1) | | |454
-455
-## Definition of done456
-457
-The migration is complete when:458
-459
-- [x] No old Ash keywords remain in the supported language. (both tools reject them; the old-shaped text survives only as the internal IR, see D2a)460
-- [x] All examples use the new enterprise Java-like syntax.461
-- [x] The lexer, parser, type checker, and runtime support the new model.462
-- [x] Every public API has explicit types.463
-- [x] Every recoverable I/O or parsing failure uses the defined exception model.464
-- [x] Every language feature has at least one example and one test. (audited by script over `examples/` and `front/tests/cases/run`)465
-- [x] The README documents the new language.466
-- [x] `MIGRATION.md` reflects the final implemented state.\ No newline at end of fileREADME.mdmodified
+2−3@@ -10,7 +10,7 @@1010
1111
Ash is an enterprise-style, statically typed, Java-like language built from scratch in C with no1212
external dependencies: packages, classes, interfaces, enums, records, generics, `T?` null safety,13
-checked exceptions, lambdas. The design contract is `MIGRATION.md`.13
+checked exceptions, lambdas.1414
1515
```java1616
package demo;@@ -64,8 +64,7 @@ and `hearth/kiln/tests/scripts/run_regression.sh` run them on both engines. The6464
`ash-stdlib` package (`ash.util`, `ash.io`, `ash.json`, `ash.math`, `ash.cli`, `ash.test`, `ash.time`,6565
`ash.concurrent`, `ash.net`, `ash.web`, `ash.game`, `ash.desktop`; the last five are pure-Ash6666
models because the VM has no threads, sockets, windows or clock); the test scripts expect it as a sibling67
-checkout (`../ash-stdlib`) or via `ASH_PATH`. Known limits of the current backend are68
-tabulated in `MIGRATION.md`.67
+checkout (`../ash-stdlib`) or via `ASH_PATH`.6968
7069
### REPL7170
hearth/front/Makefilemodified
+1−1@@ -3,7 +3,7 @@ CC = gcc33
CFLAGS = -Wall -Wextra -std=c11 -O2 -Isrc 44
55
# Shared front end for Ash: lexer, parser, AST, type checker, lowering and the internal IR6
-# lexer, built as libashfront.a and linked by both ashvm and kiln (see MIGRATION.md, D12).6
+# lexer, built as libashfront.a and linked by both ashvm and kiln.77
# There is no front-end executable: ashvm and kiln are the user-facing tools.88
# Same layout rule as the other subprojects: src/<sub>/C/x.c -> src/<sub>/O/x.o.99
FRONT_SRC = \hearth/front/src/jparse/C/jparse_old.cmodified
+2−2@@ -40,7 +40,7 @@ static int after_group(Parser *p, int from) {4040
}4141
4242
static void old(Parser *p, const char *word, const char *use) {43
- p_fail(p, "'%s' is old Ash syntax and was removed; %s (see MIGRATION.md)", word, use);43
+ p_fail(p, "'%s' is old Ash syntax and was removed; %s", word, use);4444
}4545
4646
void p_old_syntax(Parser *p, int where) {@@ -55,7 +55,7 @@ void p_old_syntax(Parser *p, int where) {5555
if (!strcmp(w, "local") || !strcmp(w, "say") || !strcmp(w, "forge") || !strcmp(w, "given") || !strcmp(w, "during") ||5656
!strcmp(w, "each") || !strcmp(w, "attempt") || !strcmp(w, "raise")) {5757
p_fail(p, "this looks like an old Ash script ('%s' at the top level); new Ash programs declare a package and a class "58
- "with `public static void main(String[] args)` (see MIGRATION.md)", w);58
+ "with `public static void main(String[] args)`", w);5959
}6060
return;6161
}hearth/front/src/jrepl/H/jrepl.hmodified
+1−1@@ -1,7 +1,7 @@11
#ifndef JREPL_H22
#define JREPL_H33
4
-/* Session model for the ashvm REPL (MIGRATION.md D9: the REPL is an explicit exception to the4
+/* Session model for the ashvm REPL (the REPL is an explicit exception to the55
* class-per-file rule; each accepted line is wrapped into a hidden class body).66
*77
* A session is the accepted history: imports, type declarations, static methods and statements. To run ahearth/front/tests/scripts/check_types.shmodified
+1−1@@ -22,7 +22,7 @@ for f in "$dir"/err_*_j.ash; do2222
done < <(sed -n 's#^// expect: ##p' "$f")2323
if [ $miss -eq 1 ]; then echo "$out"; fail=1; else echo "ok $f"; fi2424
done25
-for f in tests/cases/syntax/*.ash ../../main.ash; do25
+for f in tests/cases/syntax/*.ash; do2626
if $VM check "$f" >/dev/null 2>&1; then echo "ok $f (checks)"; else echo "FAIL $f (check)"; fail=1; fi2727
done2828
exit $failmain.ashremoved
+0−122@@ -1,122 +0,0 @@1
-package demo;2
-3
-import ash.util.List;4
-import ash.util.ArrayList;5
-import ash.util.Map;6
-import ash.util.HashMap;7
-8
-// ---------------------------------------------------------------------------9
-// main.ash - living showcase of the new Java-like Ash syntax.10
-// Updated after each larger migration milestone (see MIGRATION.md).11
-//12
-// Milestone status13
-// [x] Phase 0 specification locked (MIGRATION.md decisions D1-D15)14
-// [x] Phase 1 lexer: new keywords, // /* */ /// comments15
-// [x] Phase 2 parser + AST: everything in this file parses16
-// [x] Phase 3 type checker: `ashvm check main.ash` passes17
-// (types, nullability, generics, overloads, exceptions, switch)18
-// [x] Phase 4 lowering: `ashvm run main.ash`, `kiln main.ash -o main` (native)19
-// [x] Phase 5 stdlib: lang util io json math cli test time concurrent net web game desktop20
-// (the last five are pure-Ash models; real OS access needs new VM builtins)21
-// [x] Phase 6 examples/ (18 programs), README, API docs on every stdlib declaration22
-// ---------------------------------------------------------------------------23
-24
-/// A sealed interface with a default method.25
-public sealed interface Shape permits Circle, Square {26
- double area();27
-28
- default String describe() {29
- return "shape with area " + area();30
- }31
-}32
-33
-/// Records are immutable value types.34
-record Circle(double radius) implements Shape {35
- public double area() {36
- return 3.14159 * radius * radius;37
- }38
-}39
-40
-record Square(double side) implements Shape {41
- Square {42
- if (side < 0) {43
- throw new IllegalArgumentException("negative side");44
- }45
- }46
-47
- public double area() {48
- return side * side;49
- }50
-}51
-52
-enum Level {53
- LOW(1), HIGH(3);54
-55
- private final int weight;56
-57
- Level(int weight) {58
- this.weight = weight;59
- }60
-61
- public int getWeight() {62
- return weight;63
- }64
-}65
-66
-public class Main {67
- private static final int LIMIT = 5;68
-69
- public static int fib(int n) {70
- return n < 2 ? n : fib(n - 1) + fib(n - 2);71
- }72
-73
- static String name(Shape s) {74
- return switch (s) {75
- case Circle c -> "circle " + c.radius();76
- case Square q -> "square " + q.side();77
- };78
- }79
-80
- static <T> T pick(T a, T b, bool first) {81
- return first ? a : b;82
- }83
-84
- public static void main(String[] args) {85
- Function<Integer, Integer> twice = v -> v * 2;86
- System.out.println(name(new Circle(1.0)) + " " + twice.apply(pick(2, 3, true)));87
- List<Shape> shapes = new ArrayList<>();88
- shapes.add(new Circle(1.5));89
- shapes.add(new Square(2.0));90
-91
- for (Shape s : shapes) {92
- System.out.println(s.describe());93
- }94
-95
- Map<String, Integer> counts = new HashMap<>();96
- counts.put("fib", fib(10));97
-98
- String? maybe = counts.containsKey("x") ? "present" : null;99
- if (maybe != null) {100
- System.out.println(maybe.length());101
- }102
-103
- try {104
- Shape bad = new Square(-1.0);105
- } catch (IllegalArgumentException e) {106
- System.out.println("caught: " + e.getMessage());107
- }108
-109
- int total = 0;110
- for (int i = 0; i < 10; i++) {111
- if (i == 3) { continue; }112
- if (i == LIMIT + 2) { break; }113
- total += i;114
- }115
-116
- String label = switch (Level.HIGH) {117
- case LOW -> "low";118
- case HIGH -> "high";119
- };120
- System.out.println(label + " " + total);121
- }122
-}