← Commit history

refactor(front): move the optional standard library to ash-stdlib; compile core types into the front end

lennoxrose committed on Oct 18, 2026 at 01:05 UTC

6c14330parentd34035d

93 files changed+782−1662

CHANGELOG.mdmodified

+7−0
@@ -1,3 +1,10 @@
1+## 2026-10-18 (standard library is optional: ash-stdlib)
2+- **`hearth/front/stdlib` is gone.** `ash.util`, `ash.io`, `ash.json`, `ash.math`, `ash.time`, `ash.cli`, `ash.test`, `ash.concurrent`, `ash.net`, `ash.web`, `ash.game` and `ash.desktop` moved to the separate `ash-stdlib` package (`../ash-stdlib`, with an `ash.pkg` and README), to be published as its own repository and installed with forgepack.
3+- **Core types are compiled in.** `ash.lang`, `ash.lang.function` and `ash.util.Iterator` (the for-each cursor) are the types the type checker and lowering name directly; they now ship inside `libashfront.a` as C string data (`front/src/jcore`), looked up before the source roots and parsed only when reached. Nothing is read from disk for them, so programs that only use `ash.lang` run with no stdlib installed. They are still Ash source inside those strings: a native class table built directly in C would be a larger rewrite of the checker/lowering and was not done.
4+- `String.join` now takes `Iterable<String>` (was `List<String>`), which removes the only dependency of `ash.lang` on `ash.util`; every existing call still compiles.
5+- **Source roots**: the entry file's root, `./@ash-modules/*/src/main/ash`, `./ash.libs/*/src/main/ash` (or the package directory itself when it has no `src/main/ash`), then `ASH_PATH`. `ASH_STDLIB` and the compiled-in stdlib path are removed. A missing type now says the standard library is the optional `ash-stdlib` package.
6+- Test scripts default `ASH_PATH` to the sibling `../ash-stdlib/src/main/ash`.
7+
18 ## 2026-10-18 (frontend consolidation: hearth/front is the only frontend)
29 - **`ashvm` and `kiln` no longer have lexers, parsers or import systems of their own for Ash source.** Both link `libashfront.a` and call `jdriver_compile_file()` (`front/src/jdriver`): lex, parse, type-check, lower. The result is the internal IR, passed in memory to the `ashvm` compiler / `kiln` code generator. Deleted: `ashvm/src/lexer`, `kiln/src/lexer`, `@import` handling, import-path resolution, import aliases, circular/collision checks (`ashvm/src/compiler/*/stmt_import.*`, `*/import_paths.*`, `kiln/src/parser/*/imports`).
310 - **One IR lexer** (`front/src/ir`) replaces the two old lexers. The IR is one unit of top-level declarations whose `start` function the consumer calls; it has no `@import` and no user entry point. Old-syntax source is rejected by the front end with a message naming the replacement (D3).

MIGRATION.mdmodified

+2−1
@@ -199,6 +199,7 @@ Complete this table and implement it consistently:
199199 | D13 | Primitive boolean type is spelled `bool`. |
200200 | D14 | Checked exceptions are enforced (Exception subclasses not under RuntimeException must be caught or declared with `throws`). |
201201 | 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`. |
202203 | D15 | Performance (CLAUDE.md law): no change may make the recorded baselines slower. Baselines are recorded in `spec/performance-baseline.md` before runtime changes. |
203204
204205 ## Specification
@@ -396,7 +397,7 @@ Implemented in `hearth/front/src/jlower` as a **lowering to the internal IR** (s
396397
397398 ### Phase 5 — Standard library
398399
399-Source in `hearth/front/stdlib/ash/{lang,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.
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.
400401
401402 - [x] Implement `ash.lang`.
402403 - [x] Implement `ash.util`.

README.mdmodified

+15−6
@@ -45,17 +45,26 @@ bin/kiln Main.ash -o main # compile to a native ELF binary (no VM,
4545 bin/kiln Main.ash -o main --target=windows --link=shared --wrap-int
4646 ```
4747
48+The standard library is not built into the compiler. The compiler only contains the types it cannot work
49+without (`ash.lang`, the functional interfaces, `ash.util.Iterator`); `ash.util` (collections, `Optional`,
50+`Stream`), `ash.io`, `ash.json`, `ash.math`, `ash.time`, `ash.cli`, `ash.test` and the model packages live
51+in the separate `ash-stdlib` package. Install it with forgepack (`forgepack add ash-stdlib github:<user>/ash-stdlib`,
52+which lands in `./@ash-modules/ash-stdlib` and is found automatically), or set
53+`ASH_PATH=/path/to/ash-stdlib/src/main/ash`. Without it, programs that only use `ash.lang` still work and
54+anything else reports a `cannot find type` error that names the package.
55+
4856 `ashvm` and `kiln` are the only front doors. Both link the one shared front end in `hearth/front`
4957 (lexer, parser, AST, type checker, lowering) and differ only in the back end: a bytecode VM
5058 versus a native code generator. Source written in the removed pre-migration scripting syntax
5159 (`local`, `say`, `given`, `forge`, ...) is rejected with a message naming the new construct.
5260
5361 `examples/` has 18 runnable programs (classes, enums, records, generics, collections, lambdas,
5462 exceptions, file I/O, JSON, CLI, game, server, desktop-style); `hearth/ashvm/tests/scripts/run_regression.sh`
55-and `hearth/kiln/tests/scripts/run_regression.sh` run them on both engines. The standard library lives in
56-`hearth/front/stdlib` (`ash.lang`, `ash.util`, `ash.io`, `ash.json`, `ash.math`, `ash.cli`, `ash.test`,
57-`ash.time`, `ash.concurrent`, `ash.net`, `ash.web`, `ash.game`, `ash.desktop`; the last five are pure-Ash
58-models because the VM has no threads, sockets, windows or clock). Known limits of the current backend are
63+and `hearth/kiln/tests/scripts/run_regression.sh` run them on both engines. The standard library is the
64+`ash-stdlib` package (`ash.util`, `ash.io`, `ash.json`, `ash.math`, `ash.cli`, `ash.test`, `ash.time`,
65+`ash.concurrent`, `ash.net`, `ash.web`, `ash.game`, `ash.desktop`; the last five are pure-Ash
66+models because the VM has no threads, sockets, windows or clock); the test scripts expect it as a sibling
67+checkout (`../ash-stdlib`) or via `ASH_PATH`. Known limits of the current backend are
5968 tabulated in `MIGRATION.md`.
6069
6170 ### REPL
@@ -106,8 +115,8 @@ documentation, `examples/` and the build entry point.
106115
107116 ```
108117 hearth/front/ the only frontend: lexer, parser, AST, type checker, lowering, internal IR lexer,
109- REPL session model and the standard library (stdlib/). Built as libashfront.a,
110- linked by ashvm and kiln. There is no front-end executable.
118+ REPL session model and the compiler's core types (src/jcore, compiled in as C data).
119+ Built as libashfront.a, linked by ashvm and kiln. There is no front-end executable.
111120 hearth/ashvm/ the VM engine: compiler (IR -> bytecode), value, vm, builtins, diagnostics, app (CLI + REPL)
112121 hearth/kiln/ the native compiler: IR -> machine code -> ELF/PE (no VM, no libc)
113122 hearth/forgepack/ package manager: forgepack init/add/install/list, dependencies fetched from GitHub

hearth/ashvm/tests/scripts/gc_check.shmodified

+2−0
@@ -6,6 +6,8 @@
66 # so it is left as `make @ashvm` would leave it (no collector).
77 set -uo pipefail
88 cd "$(dirname "$0")/../.." # -> ashvm/
9+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
10+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
911 TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
1012
1113 make clean >/dev/null 2>&1; make >/dev/null 2>&1 || { echo "default build failed"; exit 1; }

hearth/ashvm/tests/scripts/run_regression.shmodified

+2−0
@@ -5,6 +5,8 @@
55 # (front/tests/cases/run/*_j.ash; *_wrap_* need --wrap-int) and ../../examples/*.ash.
66 set -uo pipefail
77 cd "$(dirname "$0")/../.." # -> ashvm/
8+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
9+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
810
911 make -s || { echo "build failed"; exit 1; }
1012 VM=../../bin/ashvm

hearth/front/Makefilemodified

+4−1
@@ -1,6 +1,6 @@
11 CC = gcc
22 .DEFAULT_GOAL := all
3-CFLAGS = -Wall -Wextra -std=c11 -O2 -Isrc -DASH_STDLIB_DIR=\"$(abspath stdlib)\"
3+CFLAGS = -Wall -Wextra -std=c11 -O2 -Isrc
44
55 # Shared front end for Ash: lexer, parser, AST, type checker, lowering and the internal IR
66 # lexer, built as libashfront.a and linked by both ashvm and kiln (see MIGRATION.md, D12).
@@ -9,6 +9,9 @@ CFLAGS = -Wall -Wextra -std=c11 -O2 -Isrc -DASH_STDLIB_DIR=\"$(abspath stdlib)\"
99 FRONT_SRC = \
1010 src/ir/C/ir_lex.c \
1111 src/jcommon/C/jcommon.c \
12+ src/jcore/C/jcore.c \
13+ src/jcore/C/core_lang.c \
14+ src/jcore/C/core_function.c \
1215 src/jlex/C/jlex.c \
1316 src/jparse/C/jparse_decl.c \
1417 src/jparse/C/jparse_expr.c \

hearth/front/src/jcore/C/core_function.cadded

+64−0
@@ -0,0 +1,64 @@
1+#include "jcore/H/jcore.h"
2+
3+/* Core types: ash.lang.function (the functional interfaces lambdas target).
4+ * Source of truth for these types: the compiler cannot work without them, so they ship
5+ * inside it instead of in the optional standard library (the ash-stdlib package). */
6+const JCoreEntry jcore_function[] = {
7+ { "ash/lang/function/BiFunction",
8+ "package ash.lang.function;\n"
9+ "\n"
10+ "/// Function of two arguments.\n"
11+ "public interface BiFunction<A, B, R> {\n"
12+ " /// Applies the function.\n"
13+ " R apply(A a, B b);\n"
14+ "}\n" },
15+ { "ash/lang/function/Comparator",
16+ "package ash.lang.function;\n"
17+ "\n"
18+ "/// Defines an order between two values; negative, zero or positive.\n"
19+ "public interface Comparator<T> {\n"
20+ " /// Orders two values: negative, zero or positive.\n"
21+ " int compare(T a, T b);\n"
22+ "}\n" },
23+ { "ash/lang/function/Consumer",
24+ "package ash.lang.function;\n"
25+ "\n"
26+ "/// Operation on one value with no result.\n"
27+ "public interface Consumer<T> {\n"
28+ " /// Performs the operation.\n"
29+ " void accept(T t);\n"
30+ "}\n" },
31+ { "ash/lang/function/Function",
32+ "package ash.lang.function;\n"
33+ "\n"
34+ "/// Function of one argument.\n"
35+ "public interface Function<T, R> {\n"
36+ " /// Applies the function.\n"
37+ " R apply(T t);\n"
38+ "}\n" },
39+ { "ash/lang/function/Predicate",
40+ "package ash.lang.function;\n"
41+ "\n"
42+ "/// Test of one value.\n"
43+ "public interface Predicate<T> {\n"
44+ " /// Evaluates the predicate.\n"
45+ " bool test(T t);\n"
46+ "}\n" },
47+ { "ash/lang/function/Runnable",
48+ "package ash.lang.function;\n"
49+ "\n"
50+ "/// Task with no arguments and no result.\n"
51+ "public interface Runnable {\n"
52+ " /// Performs the task.\n"
53+ " void run();\n"
54+ "}\n" },
55+ { "ash/lang/function/Supplier",
56+ "package ash.lang.function;\n"
57+ "\n"
58+ "/// Source of values with no arguments.\n"
59+ "public interface Supplier<T> {\n"
60+ " /// Element at the index (or the stored value).\n"
61+ " T get();\n"
62+ "}\n" },
63+ { 0, 0 }
64+};

hearth/front/src/jcore/C/core_lang.cadded

+604−0
Show diff (604 changed lines)
@@ -0,0 +1,604 @@
1+#include "jcore/H/jcore.h"
2+
3+/* Core types: ash.lang (Object, String, boxes, exceptions, System, ...) and ash.util.Iterator.
4+ * Source of truth for these types: the compiler cannot work without them, so they ship
5+ * inside it instead of in the optional standard library (the ash-stdlib package). */
6+const JCoreEntry jcore_lang[] = {
7+ { "ash/lang/ArithmeticException",
8+ "package ash.lang;\n"
9+ "\n"
10+ "/// Thrown for integer division or remainder by zero.\n"
11+ "public class ArithmeticException extends RuntimeException {\n"
12+ " public ArithmeticException() { }\n"
13+ "\n"
14+ " /// Creates a new ArithmeticException.\n"
15+ " public ArithmeticException(String message) {\n"
16+ " super(message);\n"
17+ " }\n"
18+ "\n"
19+ " /// Creates a new ArithmeticException.\n"
20+ " public ArithmeticException(String message, Throwable cause) {\n"
21+ " super(message, cause);\n"
22+ " }\n"
23+ "}\n" },
24+ { "ash/lang/Boolean",
25+ "package ash.lang;\n"
26+ "\n"
27+ "/// Boxed bool; the VM represents it as the plain value.\n"
28+ "public final class Boolean implements Comparable<Boolean> {\n"
29+ " /// The value as a bool.\n"
30+ " @Lower(\"$0\") public native bool toBoolValue();\n"
31+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
32+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Boolean other);\n"
33+ " /// Converts the argument to this type (text for String).\n"
34+ " @Lower(\"$1\") public static native Boolean valueOf(bool v);\n"
35+ " /// Parses text; throws ParseException when malformed.\n"
36+ " @Lower(\"($1 == \\\"true\\\")\") public static native bool parse(String s);\n"
37+ "}\n" },
38+ { "ash/lang/Byte",
39+ "package ash.lang;\n"
40+ "\n"
41+ "/// Boxed byte; represented as a plain number.\n"
42+ "public final class Byte extends Number implements Comparable<Byte> {\n"
43+ " /// The value as a double.\n"
44+ " @Lower(\"$0\") public native double toDoubleValue();\n"
45+ " /// The value as a byte.\n"
46+ " @Lower(\"$0\") public native byte toByteValue();\n"
47+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
48+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Byte other);\n"
49+ " /// Converts the argument to this type (text for String).\n"
50+ " @Lower(\"$1\") public static native Byte valueOf(byte v);\n"
51+ " /// Parses text; throws ParseException when malformed.\n"
52+ " @Lower(\"__parse_int($1)\") public static native byte parse(String s) throws ParseException;\n"
53+ "}\n" },
54+ { "ash/lang/Character",
55+ "package ash.lang;\n"
56+ "\n"
57+ "/// Boxed char; represented as its code point.\n"
58+ "public final class Character implements Comparable<Character> {\n"
59+ " /// The value as a char.\n"
60+ " @Lower(\"$0\") public native char toCharValue();\n"
61+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
62+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Character other);\n"
63+ " /// Converts the argument to this type (text for String).\n"
64+ " @Lower(\"$1\") public static native Character valueOf(char v);\n"
65+ "}\n" },
66+ { "ash/lang/Class",
67+ "package ash.lang;\n"
68+ "\n"
69+ "/// Runtime type descriptor returned by Object.getClass().\n"
70+ "public final class Class {\n"
71+ " /// Fully qualified class name.\n"
72+ " @Lower(\"$0[\\\"n\\\"]\") public native String getName();\n"
73+ "}\n" },
74+ { "ash/lang/ClassCastException",
75+ "package ash.lang;\n"
76+ "\n"
77+ "/// Thrown when a cast does not match the runtime type.\n"
78+ "public class ClassCastException extends RuntimeException {\n"
79+ " public ClassCastException() { }\n"
80+ "\n"
81+ " /// Creates a new ClassCastException.\n"
82+ " public ClassCastException(String message) {\n"
83+ " super(message);\n"
84+ " }\n"
85+ "\n"
86+ " /// Creates a new ClassCastException.\n"
87+ " public ClassCastException(String message, Throwable cause) {\n"
88+ " super(message, cause);\n"
89+ " }\n"
90+ "}\n" },
91+ { "ash/lang/Comparable",
92+ "package ash.lang;\n"
93+ "\n"
94+ "/// Types with a natural order.\n"
95+ "public interface Comparable<T> {\n"
96+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
97+ " int compareTo(T other);\n"
98+ "}\n" },
99+ { "ash/lang/Double",
100+ "package ash.lang;\n"
101+ "\n"
102+ "/// Boxed double; represented as a plain number.\n"
103+ "public final class Double extends Number implements Comparable<Double> {\n"
104+ " /// The value as a double.\n"
105+ " @Lower(\"$0\") public native double toDoubleValue();\n"
106+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
107+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Double other);\n"
108+ " /// Converts the argument to this type (text for String).\n"
109+ " @Lower(\"$1\") public static native Double valueOf(double v);\n"
110+ " /// Parses text; throws ParseException when malformed.\n"
111+ " @Lower(\"__parse_double($1)\") public static native double parse(String s) throws ParseException;\n"
112+ "}\n" },
113+ { "ash/lang/Enum",
114+ "package ash.lang;\n"
115+ "\n"
116+ "/// Base class of every enum: constant name and declaration order.\n"
117+ "public abstract class Enum<E> implements Comparable<E> {\n"
118+ " /// Declared name of the constant.\n"
119+ " @Lower(\"$0[\\\"__name\\\"]\") public final native String name();\n"
120+ " /// Position in the enum declaration, starting at 0.\n"
121+ " @Lower(\"$0[\\\"__ord\\\"]\") public final native int ordinal();\n"
122+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
123+ " @Lower(\"($0[\\\"__ord\\\"] - $1[\\\"__ord\\\"])\") public final native int compareTo(E other);\n"
124+ "\n"
125+ " /// Text form.\n"
126+ " public String toString() {\n"
127+ " return name();\n"
128+ " }\n"
129+ "}\n" },
130+ { "ash/lang/Exception",
131+ "package ash.lang;\n"
132+ "\n"
133+ "/// Base of recoverable (checked) failures; RuntimeException subclasses are unchecked.\n"
134+ "public class Exception extends Throwable {\n"
135+ " public Exception() { }\n"
136+ "\n"
137+ " /// Creates a new Exception.\n"
138+ " public Exception(String message) {\n"
139+ " super(message);\n"
140+ " }\n"
141+ "\n"
142+ " /// Creates a new Exception.\n"
143+ " public Exception(String message, Throwable cause) {\n"
144+ " super(message, cause);\n"
145+ " }\n"
146+ "}\n" },
147+ { "ash/lang/Float",
148+ "package ash.lang;\n"
149+ "\n"
150+ "/// Boxed float; represented as a plain number.\n"
151+ "public final class Float extends Number implements Comparable<Float> {\n"
152+ " /// The value as a double.\n"
153+ " @Lower(\"$0\") public native double toDoubleValue();\n"
154+ " /// The value as a float.\n"
155+ " @Lower(\"$0\") public native float toFloatValue();\n"
156+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
157+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Float other);\n"
158+ " /// Converts the argument to this type (text for String).\n"
159+ " @Lower(\"$1\") public static native Float valueOf(float v);\n"
160+ " /// Parses text; throws ParseException when malformed.\n"
161+ " @Lower(\"__parse_double($1)\") public static native float parse(String s) throws ParseException;\n"
162+ "}\n" },
163+ { "ash/lang/IOException",
164+ "package ash.lang;\n"
165+ "\n"
166+ "/// Checked failure of a file or stream operation.\n"
167+ "public class IOException extends Exception {\n"
168+ " public IOException() { }\n"
169+ "\n"
170+ " /// Creates a new IOException.\n"
171+ " public IOException(String message) {\n"
172+ " super(message);\n"
173+ " }\n"
174+ "\n"
175+ " /// Creates a new IOException.\n"
176+ " public IOException(String message, Throwable cause) {\n"
177+ " super(message, cause);\n"
178+ " }\n"
179+ "}\n" },
180+ { "ash/lang/IllegalArgumentException",
181+ "package ash.lang;\n"
182+ "\n"
183+ "/// Thrown when an argument is not acceptable.\n"
184+ "public class IllegalArgumentException extends RuntimeException {\n"
185+ " public IllegalArgumentException() { }\n"
186+ "\n"
187+ " /// Creates a new IllegalArgumentException.\n"
188+ " public IllegalArgumentException(String message) {\n"
189+ " super(message);\n"
190+ " }\n"
191+ "\n"
192+ " /// Creates a new IllegalArgumentException.\n"
193+ " public IllegalArgumentException(String message, Throwable cause) {\n"
194+ " super(message, cause);\n"
195+ " }\n"
196+ "}\n" },
197+ { "ash/lang/IllegalStateException",
198+ "package ash.lang;\n"
199+ "\n"
200+ "/// Thrown when an object is not in a state that allows the call.\n"
201+ "public class IllegalStateException extends RuntimeException {\n"
202+ " public IllegalStateException() { }\n"
203+ "\n"
204+ " /// Creates a new IllegalStateException.\n"
205+ " public IllegalStateException(String message) {\n"
206+ " super(message);\n"
207+ " }\n"
208+ "\n"
209+ " /// Creates a new IllegalStateException.\n"
210+ " public IllegalStateException(String message, Throwable cause) {\n"
211+ " super(message, cause);\n"
212+ " }\n"
213+ "}\n" },
214+ { "ash/lang/IndexOutOfBoundsException",
215+ "package ash.lang;\n"
216+ "\n"
217+ "/// Thrown for an array or list index outside its bounds.\n"
218+ "public class IndexOutOfBoundsException extends RuntimeException {\n"
219+ " public IndexOutOfBoundsException() { }\n"
220+ "\n"
221+ " /// Creates a new IndexOutOfBoundsException.\n"
222+ " public IndexOutOfBoundsException(String message) {\n"
223+ " super(message);\n"
224+ " }\n"
225+ "\n"
226+ " /// Creates a new IndexOutOfBoundsException.\n"
227+ " public IndexOutOfBoundsException(String message, Throwable cause) {\n"
228+ " super(message, cause);\n"
229+ " }\n"
230+ "}\n" },
231+ { "ash/lang/InputStream",
232+ "package ash.lang;\n"
233+ "\n"
234+ "/// Standard input; see System.in.\n"
235+ "public final class InputStream {\n"
236+ " /// Reads one line from standard input.\n"
237+ " @Lower(\"input()\") public native String readLine();\n"
238+ "}\n" },
239+ { "ash/lang/Integer",
240+ "package ash.lang;\n"
241+ "\n"
242+ "/// Boxed int; represented as a plain number.\n"
243+ "public final class Integer extends Number implements Comparable<Integer> {\n"
244+ " /// Largest int value, 2^31 - 1.\n"
245+ " @Lower(\"2147483647\") public static final int MAX_VALUE = 2147483647;\n"
246+ " /// Smallest int value, -2^31.\n"
247+ " @Lower(\"(-2147483648)\") public static final int MIN_VALUE = -2147483648;\n"
248+ " /// The value as a double.\n"
249+ " @Lower(\"$0\") public native double toDoubleValue();\n"
250+ " /// The value as an int.\n"
251+ " @Lower(\"$0\") public native int toIntValue();\n"
252+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
253+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Integer other);\n"
254+ " /// Converts the argument to this type (text for String).\n"
255+ " @Lower(\"$1\") public static native Integer valueOf(int v);\n"
256+ " /// Parses text; throws ParseException when malformed.\n"
257+ " @Lower(\"__parse_int($1)\") public static native int parse(String s) throws ParseException;\n"
258+ "}\n" },
259+ { "ash/lang/Iterable",
260+ "package ash.lang;\n"
261+ "\n"
262+ "import ash.util.Iterator;\n"
263+ "\n"
264+ "/// Types that can be the target of a for-each loop.\n"
265+ "public interface Iterable<T> {\n"
266+ " /// Cursor over the elements.\n"
267+ " @Lower(\"__iterof($0)\") Iterator<T> iterator();\n"
268+ "}\n" },
269+ { "ash/lang/KeyNotFoundException",
270+ "package ash.lang;\n"
271+ "\n"
272+ "/// Thrown when a map lookup that must succeed finds no entry.\n"
273+ "public class KeyNotFoundException extends RuntimeException {\n"
274+ " public KeyNotFoundException() { }\n"
275+ "\n"
276+ " /// Creates a new KeyNotFoundException.\n"
277+ " public KeyNotFoundException(String message) {\n"
278+ " super(message);\n"
279+ " }\n"
280+ "\n"
281+ " /// Creates a new KeyNotFoundException.\n"
282+ " public KeyNotFoundException(String message, Throwable cause) {\n"
283+ " super(message, cause);\n"
284+ " }\n"
285+ "}\n" },
286+ { "ash/lang/Long",
287+ "package ash.lang;\n"
288+ "\n"
289+ "/// Boxed long; a plain number while it fits in 2^53, an exact two-halves value beyond that (--wrap-int).\n"
290+ "public final class Long extends Number implements Comparable<Long> {\n"
291+ " /// Largest long value, 2^63 - 1 (exact with --wrap-int; the nearest double otherwise).\n"
292+ " @Lower(\"9223372036854775807||{\\\"__L\\\": 1, \\\"hi\\\": 2147483647, \\\"lo\\\": 4294967295}\") public static final long MAX_VALUE = 9223372036854775807L;\n"
293+ " /// Smallest long value, -2^63 (exact with --wrap-int; the nearest double otherwise).\n"
294+ " @Lower(\"(-9223372036854775807)||{\\\"__L\\\": 1, \\\"hi\\\": -2147483648, \\\"lo\\\": 0}\") public static final long MIN_VALUE = -9223372036854775807L - 1L;\n"
295+ " /// The value as a double.\n"
296+ " @Lower(\"__l2d($0)\") public native double toDoubleValue();\n"
297+ " /// The value as a long.\n"
298+ " @Lower(\"$0\") public native long toLongValue();\n"
299+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
300+ " @Lower(\"__lcmp($0, $1)\") public native int compareTo(Long other);\n"
301+ " /// Converts the argument to this type (text for String).\n"
302+ " @Lower(\"$1\") public static native Long valueOf(long v);\n"
303+ " /// Parses text; throws ParseException when malformed.\n"
304+ " @Lower(\"__lparse($1)\") public static native long parse(String s) throws ParseException;\n"
305+ "}\n" },
306+ { "ash/lang/Math",
307+ "package ash.lang;\n"
308+ "\n"
309+ "/// Basic numeric functions.\n"
310+ "public final class Math {\n"
311+ " /// Square root.\n"
312+ " @Lower(\"sqrt($1)\") public static native double sqrt(double x);\n"
313+ " /// Largest whole number not above the argument.\n"
314+ " @Lower(\"floor($1)\") public static native double floor(double x);\n"
315+ " /// Absolute value.\n"
316+ " @Lower(\"abs($1)\") public static native int abs(int x);\n"
317+ " /// Absolute value.\n"
318+ " @Lower(\"abs($1)\") public static native double abs(double x);\n"
319+ " /// Larger of two values.\n"
320+ " @Lower(\"__max($1, $2)\") public static native int max(int a, int b);\n"
321+ " /// Smaller of two values.\n"
322+ " @Lower(\"__min($1, $2)\") public static native int min(int a, int b);\n"
323+ " /// Larger of two values.\n"
324+ " @Lower(\"__max($1, $2)\") public static native double max(double a, double b);\n"
325+ " /// Smaller of two values.\n"
326+ " @Lower(\"__min($1, $2)\") public static native double min(double a, double b);\n"
327+ "}\n" },
328+ { "ash/lang/NullPointerException",
329+ "package ash.lang;\n"
330+ "\n"
331+ "/// Thrown when a null reference is used.\n"
332+ "public class NullPointerException extends RuntimeException {\n"
333+ " public NullPointerException() { }\n"
334+ "\n"
335+ " /// Creates a new NullPointerException.\n"
336+ " public NullPointerException(String message) {\n"
337+ " super(message);\n"
338+ " }\n"
339+ "\n"
340+ " /// Creates a new NullPointerException.\n"
341+ " public NullPointerException(String message, Throwable cause) {\n"
342+ " super(message, cause);\n"
343+ " }\n"
344+ "}\n" },
345+ { "ash/lang/Number",
346+ "package ash.lang;\n"
347+ "\n"
348+ "/// Base of the numeric box types.\n"
349+ "public abstract class Number {\n"
350+ " /// The value as a double.\n"
351+ " public abstract double toDoubleValue();\n"
352+ "}\n" },
353+ { "ash/lang/Object",
354+ "package ash.lang;\n"
355+ "\n"
356+ "/// Root of the class hierarchy.\n"
357+ "public class Object {\n"
358+ " @Lower(\"{}\") public Object() { }\n"
359+ " /// Value equality; identity unless overridden.\n"
360+ " @Lower(\"__eq($0, $1)\") public native bool equals(Object? o);\n"
361+ " /// Hash consistent with equals.\n"
362+ " @Lower(\"__hash($0)\") public native int hashCode();\n"
363+ " /// Text form.\n"
364+ " @Lower(\"__str($0)\") public native String toString();\n"
365+ " /// Runtime class of the object.\n"
366+ " @Lower(\"__classof($0)\") public native Class getClass();\n"
367+ "}\n" },
368+ { "ash/lang/ParseException",
369+ "package ash.lang;\n"
370+ "\n"
371+ "/// Checked failure to parse text (numbers, JSON, URLs).\n"
372+ "public class ParseException extends Exception {\n"
373+ " public ParseException() { }\n"
374+ "\n"
375+ " /// Creates a new ParseException.\n"
376+ " public ParseException(String message) {\n"
377+ " super(message);\n"
378+ " }\n"
379+ "\n"
380+ " /// Creates a new ParseException.\n"
381+ " public ParseException(String message, Throwable cause) {\n"
382+ " super(message, cause);\n"
383+ " }\n"
384+ "}\n" },
385+ { "ash/lang/PrintStream",
386+ "package ash.lang;\n"
387+ "\n"
388+ "/// Text output; System.out and System.err.\n"
389+ "public final class PrintStream {\n"
390+ " /// Prints the value followed by a newline.\n"
391+ " @Lower(\"__println(\\\"\\\")\") public native void println();\n"
392+ " /// Prints the value followed by a newline.\n"
393+ " @Lower(\"__println(__str($1))\") public native void println(Object? o);\n"
394+ " /// Prints the value followed by a newline.\n"
395+ " @Lower(\"__println(__str($1))\") public native void println(String? s);\n"
396+ " /// Prints the value followed by a newline.\n"
397+ " @Lower(\"__println(str($1))\") public native void println(int i);\n"
398+ " /// Prints the value followed by a newline.\n"
399+ " @Lower(\"__println(__lstr($1))\") public native void println(long l);\n"
400+ " /// Prints the value followed by a newline.\n"
401+ " @Lower(\"__println(__dstr($1))\") public native void println(double d);\n"
402+ " /// Prints the value followed by a newline.\n"
403+ " @Lower(\"__println(__fstr($1))\") public native void println(float f);\n"
404+ " /// Prints the value followed by a newline.\n"
405+ " @Lower(\"__println(__bs($1))\") public native void println(bool b);\n"
406+ " /// Prints the value followed by a newline.\n"
407+ " @Lower(\"__println(chr($1))\") public native void println(char c);\n"
408+ "}\n" },
409+ { "ash/lang/Record",
410+ "package ash.lang;\n"
411+ "\n"
412+ "/// Base class of every record.\n"
413+ "public abstract class Record { }\n" },
414+ { "ash/lang/RuntimeException",
415+ "package ash.lang;\n"
416+ "\n"
417+ "/// Base of unchecked failures that signal programming errors.\n"
418+ "public class RuntimeException extends Exception {\n"
419+ " public RuntimeException() { }\n"
420+ "\n"
421+ " /// Creates a new RuntimeException.\n"
422+ " public RuntimeException(String message) {\n"
423+ " super(message);\n"
424+ " }\n"
425+ "\n"
426+ " /// Creates a new RuntimeException.\n"
427+ " public RuntimeException(String message, Throwable cause) {\n"
428+ " super(message, cause);\n"
429+ " }\n"
430+ "}\n" },
431+ { "ash/lang/Short",
432+ "package ash.lang;\n"
433+ "\n"
434+ "/// Boxed short; represented as a plain number.\n"
435+ "public final class Short extends Number implements Comparable<Short> {\n"
436+ " /// The value as a double.\n"
437+ " @Lower(\"$0\") public native double toDoubleValue();\n"
438+ " /// The value as a short.\n"
439+ " @Lower(\"$0\") public native short toShortValue();\n"
440+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
441+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(Short other);\n"
442+ " /// Converts the argument to this type (text for String).\n"
443+ " @Lower(\"$1\") public static native Short valueOf(short v);\n"
444+ " /// Parses text; throws ParseException when malformed.\n"
445+ " @Lower(\"__parse_int($1)\") public static native short parse(String s) throws ParseException;\n"
446+ "}\n" },
447+ { "ash/lang/String",
448+ "package ash.lang;\n"
449+ "\n"
450+ "\n"
451+ "/// Immutable text. Represented natively by the VM.\n"
452+ "public final class String implements Comparable<String> {\n"
453+ " /// Number of characters.\n"
454+ " @Lower(\"len($0)\") public native int length();\n"
455+ " /// Character code at the given index.\n"
456+ " @Lower(\"ord($0[$1])\") public native char charAt(int index);\n"
457+ " /// Part of the text from the start index (to the end index, exclusive).\n"
458+ " @Lower(\"substring($0, $1, len($0))\") public native String substring(int begin);\n"
459+ " /// Part of the text from the start index (to the end index, exclusive).\n"
460+ " @Lower(\"substring($0, $1, $2)\") public native String substring(int begin, int end);\n"
461+ " /// Index of the first occurrence, or -1.\n"
462+ " @Lower(\"indexOf($0, $1)\") public native int indexOf(String s);\n"
463+ " /// True when the value is present.\n"
464+ " @Lower(\"contains($0, $1)\") public native bool contains(String s);\n"
465+ " /// True when the text begins with the prefix (at the offset, if given).\n"
466+ " @Lower(\"starts_with($0, $1)\") public native bool startsWith(String s);\n"
467+ " /// True when the text begins with the prefix (at the offset, if given).\n"
468+ " @Lower(\"__startsat($0, $1, $2)\") public native bool startsWith(String s, int offset);\n"
469+ " /// True when the text ends with the suffix.\n"
470+ " @Lower(\"ends_with($0, $1)\") public native bool endsWith(String s);\n"
471+ " /// Replaces every occurrence of a substring.\n"
472+ " @Lower(\"replace($0, $1, $2)\") public native String replace(String from, String to);\n"
473+ " /// The text repeated n times.\n"
474+ " @Lower(\"repeat($0, $1)\") public native String repeat(int n);\n"
475+ " /// Upper-case copy.\n"
476+ " @Lower(\"upper($0)\") public native String toUpperCase();\n"
477+ " /// Lower-case copy.\n"
478+ " @Lower(\"lower($0)\") public native String toLowerCase();\n"
479+ " /// Copy without leading and trailing whitespace.\n"
480+ " @Lower(\"trim($0)\") public native String trim();\n"
481+ " /// True when there are no elements or characters.\n"
482+ " @Lower(\"(len($0) == 0)\") public native bool isEmpty();\n"
483+ " /// Splits at a separator; trailing empty parts are dropped.\n"
484+ " @Lower(\"__split($0, $1)\") public native String[] split(String sep);\n"
485+ " /// Negative, zero or positive as this value orders before, equal to or after the other.\n"
486+ " @Lower(\"__cmp($0, $1)\") public native int compareTo(String other);\n"
487+ " /// Converts the argument to this type (text for String).\n"
488+ " @Lower(\"__str($1)\") public static native String valueOf(Object? o);\n"
489+ " /// Converts the argument to this type (text for String).\n"
490+ " @Lower(\"str($1)\") public static native String valueOf(int i);\n"
491+ " /// Converts the argument to this type (text for String).\n"
492+ " @Lower(\"__lstr($1)\") public static native String valueOf(long l);\n"
493+ " /// Converts the argument to this type (text for String).\n"
494+ " @Lower(\"__dstr($1)\") public static native String valueOf(double d);\n"
495+ " /// Converts the argument to this type (text for String).\n"
496+ " @Lower(\"__fstr($1)\") public static native String valueOf(float f);\n"
497+ " /// Converts the argument to this type (text for String).\n"
498+ " @Lower(\"__bs($1)\") public static native String valueOf(bool b);\n"
499+ " /// Converts the argument to this type (text for String).\n"
500+ " @Lower(\"chr($1)\") public static native String valueOf(char c);\n"
501+ " /// Joins strings with a separator.\n"
502+ " @Lower(\"join($2, $1)\") public static native String join(String sep, Iterable<String> parts);\n"
503+ "}\n" },
504+ { "ash/lang/StringBuilder",
505+ "package ash.lang;\n"
506+ "\n"
507+ "/// Mutable text accumulator; avoids quadratic string building.\n"
508+ "public final class StringBuilder {\n"
509+ " @Lower(\"{\\\"p\\\": []}\") public StringBuilder() { }\n"
510+ " /// Adds text to the end; returns this builder.\n"
511+ " @Lower(\"__sbappend($0, __str($1))\") public native StringBuilder append(String? s);\n"
512+ " /// Adds text to the end; returns this builder.\n"
513+ " @Lower(\"__sbappend($0, __str($1))\") public native StringBuilder append(Object? o);\n"
514+ " /// Adds text to the end; returns this builder.\n"
515+ " @Lower(\"__sbappend($0, str($1))\") public native StringBuilder append(int i);\n"
516+ " /// Adds text to the end; returns this builder.\n"
517+ " @Lower(\"__sbappend($0, chr($1))\") public native StringBuilder append(char c);\n"
518+ " /// Number of characters.\n"
519+ " @Lower(\"len(__sbstr($0))\") public native int length();\n"
520+ " /// Text form.\n"
521+ " @Lower(\"__sbstr($0)\") public native String toString();\n"
522+ "}\n" },
523+ { "ash/lang/System",
524+ "package ash.lang;\n"
525+ "\n"
526+ "/// Process-level facilities: standard streams and exit.\n"
527+ "public final class System {\n"
528+ " /// Standard output.\n"
529+ " public static final PrintStream out = new PrintStream();\n"
530+ " /// Standard error (the VM has a single output stream, so it shares stdout).\n"
531+ " public static final PrintStream err = new PrintStream();\n"
532+ " /// Standard input.\n"
533+ " public static final InputStream in = new InputStream();\n"
534+ " /// Ends the program with the given status.\n"
535+ " @Lower(\"exit($1)\") public static native void exit(int status);\n"
536+ "}\n" },
537+ { "ash/lang/Throwable",
538+ "package ash.lang;\n"
539+ "\n"
540+ "/// Root of everything that can be thrown; carries a message, a cause and the creation site.\n"
541+ "public class Throwable {\n"
542+ " private final String? message;\n"
543+ " private final Throwable? cause;\n"
544+ "\n"
545+ " /// Creates a new Throwable.\n"
546+ " public Throwable() {\n"
547+ " this.message = null;\n"
548+ " this.cause = null;\n"
549+ " }\n"
550+ "\n"
551+ " /// Creates a new Throwable.\n"
552+ " public Throwable(String? message) {\n"
553+ " this.message = message;\n"
554+ " this.cause = null;\n"
555+ " }\n"
556+ "\n"
557+ " /// Creates a new Throwable.\n"
558+ " public Throwable(String? message, Throwable? cause) {\n"
559+ " this.message = message;\n"
560+ " this.cause = cause;\n"
561+ " }\n"
562+ "\n"
563+ " /// Detail message, or null.\n"
564+ " public String? getMessage() {\n"
565+ " return message;\n"
566+ " }\n"
567+ "\n"
568+ " /// Underlying cause, or null.\n"
569+ " public Throwable? getCause() {\n"
570+ " return cause;\n"
571+ " }\n"
572+ "\n"
573+ " /// Prints the exception, its creation site and its causes.\n"
574+ " @Lower(\"__pst($0)\") public native void printStackTrace();\n"
575+ "}\n" },
576+ { "ash/lang/UnsupportedOperationException",
577+ "package ash.lang;\n"
578+ "\n"
579+ "/// Thrown when an operation is not available.\n"
580+ "public class UnsupportedOperationException extends RuntimeException {\n"
581+ " public UnsupportedOperationException() { }\n"
582+ "\n"
583+ " /// Creates a new UnsupportedOperationException.\n"
584+ " public UnsupportedOperationException(String message) {\n"
585+ " super(message);\n"
586+ " }\n"
587+ "\n"
588+ " /// Creates a new UnsupportedOperationException.\n"
589+ " public UnsupportedOperationException(String message, Throwable cause) {\n"
590+ " super(message, cause);\n"
591+ " }\n"
592+ "}\n" },
593+ { "ash/util/Iterator",
594+ "package ash.util;\n"
595+ "\n"
596+ "/// Cursor over a sequence of values.\n"
597+ "public interface Iterator<T> {\n"
598+ " /// True when next() will return another value.\n"
599+ " bool hasNext();\n"
600+ " /// Returns the next value.\n"
601+ " T next();\n"
602+ "}\n" },
603+ { 0, 0 }
604+};

hearth/front/src/jcore/C/jcore.cadded

+15−0
@@ -0,0 +1,15 @@
1+#include <string.h>
2+
3+#include "jcore/H/jcore.h"
4+
5+static const char *find(const JCoreEntry *table, const char *rel) {
6+ for (; table->name; table++)
7+ if (strcmp(table->name, rel) == 0) return table->source;
8+ return NULL;
9+}
10+
11+const char *jcore_source(const char *rel) {
12+ if (strncmp(rel, "ash/lang/function/", 18) == 0) return find(jcore_function, rel);
13+ const char *s = find(jcore_lang, rel);
14+ return s;
15+}

hearth/front/src/jcore/D/.gitkeepadded

+0−0

No content changes. View the file on GitHub

hearth/front/src/jcore/H/jcore.hadded

+23−0
@@ -0,0 +1,23 @@
1+#ifndef JCORE_H
2+#define JCORE_H
3+
4+/* Types the compiler itself depends on (Object, String, the boxes, exceptions, Iterable/Iterator,
5+ * the functional interfaces). They are compiled into the front end as C string data and parsed
6+ * lazily, only when a program reaches them; nothing is read from disk. Everything else in the
7+ * standard library (ash.util, ash.io, ash.json, ...) is the optional ash-stdlib package found
8+ * through the source roots (see jt_init_default_roots).
9+ *
10+ * Ownership: returned strings are static and read-only. */
11+
12+typedef struct {
13+ const char *name; /* source path without extension, e.g. "ash/lang/Object" */
14+ const char *source;
15+} JCoreEntry;
16+
17+extern const JCoreEntry jcore_lang[];
18+extern const JCoreEntry jcore_function[];
19+
20+/* Source of the core type in the file `rel` ("ash/lang/Object"), or NULL when it is not a core type. */
21+const char *jcore_source(const char *rel);
22+
23+#endif

hearth/front/src/jcore/O/.gitkeepadded

+0−0

No content changes. View the file on GitHub

hearth/front/src/jtypes/C/classes.cmodified

+34−11
@@ -4,13 +4,12 @@
44 #include <string.h>
55 #include <unistd.h>
66
7+#include <dirent.h>
8+
9+#include "jcore/H/jcore.h"
710 #include "jparse/H/jparse.h"
811 #include "jtypes/H/jtypes.h"
912
10-#ifndef ASH_STDLIB_DIR
11-#define ASH_STDLIB_DIR "stdlib"
12-#endif
13-
1413 static JList roots; /* char* */
1514 static JList all_classes; /* JClass* */
1615 static int method_ids;
@@ -31,6 +30,21 @@ void jt_add_root(const char *dir) { j_list_push(&roots, j_strdup(dir)); }
3130
3231 static int dir_exists(const char *d) { return access(d, F_OK) == 0; }
3332
33+/* Packages installed by forgepack: each child C of <project>/@ash-modules and <project>/ash.libs is a
34+ * source root, at C/src/main/ash when that exists and at C itself otherwise. */
35+static void add_package_roots(const char *project, const char *folder) {
36+ char *dir = j_fmt("%s/%s", project, folder);
37+ DIR *d = opendir(dir);
38+ if (!d) return;
39+ for (struct dirent *e = readdir(d); e; e = readdir(d)) {
40+ if (e->d_name[0] == '.') continue;
41+ char *pkg = j_fmt("%s/%s", dir, e->d_name);
42+ char *main_dir = j_fmt("%s/src/main/ash", pkg);
43+ jt_add_root(dir_exists(main_dir) ? main_dir : pkg);
44+ }
45+ closedir(d);
46+}
47+
3448 void jt_init_default_roots(const char *entry_path, const char *entry_pkg) {
3549 /* source root = entry file path minus its package directories */
3650 char *dir = j_strdup(entry_path);
@@ -47,15 +61,14 @@ void jt_init_default_roots(const char *entry_path, const char *entry_pkg) {
4761 }
4862 }
4963 jt_add_root(root);
50- /* extra source roots, e.g. forgepack-installed dependencies: ASH_PATH=dir1:dir2 */
64+ add_package_roots(".", "@ash-modules");
65+ add_package_roots(".", "ash.libs");
66+ /* extra source roots: ASH_PATH=dir1:dir2 (for example a checkout of ash-stdlib/src/main/ash) */
5167 const char *env = getenv("ASH_PATH");
5268 if (env) {
5369 char *e = j_strdup(env);
5470 for (char *tok = strtok(e, ":"); tok; tok = strtok(NULL, ":")) jt_add_root(tok);
5571 }
56- const char *std = getenv("ASH_STDLIB");
57- jt_add_root(std ? std : ASH_STDLIB_DIR);
58- (void)dir_exists;
5972 }
6073
6174 /* ---------------------------------------------------------------- registry */
@@ -124,11 +137,18 @@ static int path_has_decl(const char *file, const char *simple) { (void)file; (vo
124137 JClass *jt_find_class(const char *qname) {
125138 JClass *c = registry_find(qname);
126139 if (c) return c;
127- /* try to load <root>/<a/b/C>.ash; for nested names load the outer file */
140+ /* try to load <a/b/C>.ash from the compiler's core types, then from the source roots;
141+ * for nested names load the outer file */
128142 char *copy = j_strdup(qname);
129143 for (;;) {
130144 char *file = j_strdup(copy);
131145 for (char *p = file; *p; p++) if (*p == '.') *p = '/';
146+ const char *core = jcore_source(file);
147+ if (core) {
148+ jt_load_unit(j_fmt("<core>/%s.ash", file), core);
149+ c = registry_find(qname);
150+ if (c) return c;
151+ }
132152 for (int i = 0; i < roots.count; i++) {
133153 char *full = j_fmt("%s/%s.ash", (char *)roots.items[i], file);
134154 char *src = j_read_file(full);
@@ -147,7 +167,7 @@ JClass *jt_find_class(const char *qname) {
147167 JClass *jt_well_known(const char *qname) {
148168 JClass *c = jt_find_class(qname);
149169 if (!c) {
150- fprintf(stderr, "error: standard library type '%s' not found (looked in the Ash stdlib; set ASH_STDLIB)\n", qname);
170+ fprintf(stderr, "error: core type '%s' not found\n", qname);
151171 exit(1);
152172 }
153173 return c;
@@ -283,7 +303,10 @@ JType *jt_resolve_type(Node *tn, JClass *ctx, JMethod *mctx, int report) {
283303 if (!c) c = jt_find_class(tn->name);
284304 }
285305 if (!c) {
286- if (report) cerr(tn, "cannot find type '%s'", tn->name);
306+ if (report) {
307+ if (!jt_find_class("ash.util.List")) cerr(tn, "cannot find type '%s' (the standard library is the optional ash-stdlib package: install it with forgepack or point ASH_PATH at its src/main/ash)", tn->name);
308+ else cerr(tn, "cannot find type '%s'", tn->name);
309+ }
287310 return ty_error();
288311 }
289312 JType **args = NULL;

hearth/front/stdlib/ash/cli/Args.ashremoved

+0−50
@@ -1,50 +0,0 @@
1-package ash.cli;
2-
3-import ash.util.HashMap;
4-import ash.util.List;
5-import ash.util.ArrayList;
6-
7-/// Splits arguments into `--name value` options, `--flag` switches and positional values.
8-public final class Args {
9- private final HashMap<String, String> options = new HashMap<>();
10- private final List<String> positional = new ArrayList<>();
11-
12- /// Creates a new Args.
13- public Args(String[] args) {
14- int i = 0;
15- while (i < args.length) {
16- String a = args[i];
17- if (a.startsWith("--")) {
18- String name = a.substring(2);
19- if (i + 1 < args.length && !args[i + 1].startsWith("--")) {
20- options.put(name, args[i + 1]);
21- i++;
22- } else {
23- options.put(name, "true");
24- }
25- } else {
26- positional.add(a);
27- }
28- i++;
29- }
30- }
31-
32- /// True when the option was given.
33- public bool has(String name) {
34- return options.containsKey(name);
35- }
36-
37- /// Element at the index (or the stored value).
38- public String get(String name, String fallback) {
39- String? v = options.get(name);
40- if (v == null) {
41- return fallback;
42- }
43- return v;
44- }
45-
46- /// Arguments that are not options.
47- public List<String> positional() {
48- return positional;
49- }
50-}

hearth/front/stdlib/ash/concurrent/Executor.ashremoved

+0−18
@@ -1,18 +0,0 @@
1-package ash.concurrent;
2-
3-import ash.lang.function.Supplier;
4-
5-/// Deterministic single-threaded executor: the Ash VM has no threads, so tasks run to
6-/// completion on the caller in submission order. Failures are captured in the Future.
7-public final class Executor {
8- public Executor() { }
9-
10- /// Runs the task and captures its result or failure.
11- public <T> Future<T> submit(Supplier<T> task) {
12- try {
13- return new Future<T>(task.get(), null);
14- } catch (Exception e) {
15- return new Future<T>(null, e);
16- }
17- }
18-}

hearth/front/stdlib/ash/concurrent/Future.ashremoved

+0−31
@@ -1,31 +0,0 @@
1-package ash.concurrent;
2-
3-/// Result of a task run by an Executor.
4-public final class Future<T> {
5- private final T? value;
6- private final Exception? failure;
7-
8- /// Creates a new Future.
9- Future(T? value, Exception? failure) {
10- this.value = value;
11- this.failure = failure;
12- }
13-
14- /// True when the task threw.
15- public bool isFailed() {
16- return failure != null;
17- }
18-
19- /// Returns the task result or rethrows its failure wrapped in IllegalStateException.
20- public T get() {
21- Exception? f = failure;
22- if (f != null) {
23- throw new IllegalStateException("task failed: " + f.getMessage(), f);
24- }
25- T? v = value;
26- if (v == null) {
27- throw new IllegalStateException("task produced no value");
28- }
29- return v;
30- }
31-}

hearth/front/stdlib/ash/concurrent/Thread.ashremoved

+0−31
@@ -1,31 +0,0 @@
1-package ash.concurrent;
2-
3-import ash.lang.function.Runnable;
4-
5-/// A unit of work. The Ash VM has no threads, so `start()` runs the task to completion on the
6-/// caller and `join()` returns immediately; programs written against it stay deterministic.
7-public class Thread {
8- private final Runnable task;
9- private bool finished = false;
10-
11- /// Creates a new Thread.
12- public Thread(Runnable task) {
13- this.task = task;
14- }
15-
16- /// Runs the task now, on the calling flow of control.
17- public void start() {
18- if (!finished) {
19- finished = true;
20- task.run();
21- }
22- }
23-
24- /// Returns immediately: the task has already completed in start().
25- public void join() { }
26-
27- /// True once the task has run.
28- public bool isFinished() {
29- return finished;
30- }
31-}

hearth/front/stdlib/ash/desktop/Button.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-package ash.desktop;
2-
3-/// Clickable widget that counts its clicks.
4-public class Button extends Widget {
5- private final String label;
6- private int clicks = 0;
7-
8- /// Creates a new Button.
9- public Button(String label) {
10- this.label = label;
11- }
12-
13- /// Registers one click.
14- public void click() {
15- clicks++;
16- }
17-
18- /// Text form of this widget alone.
19- public String draw() {
20- return "(" + label + " x" + clicks + ")";
21- }
22-}

hearth/front/stdlib/ash/desktop/Label.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.desktop;
2-
3-/// Widget that shows fixed text.
4-public class Label extends Widget {
5- private final String text;
6-
7- /// Creates a new Label.
8- public Label(String text) {
9- this.text = text;
10- }
11-
12- /// Text form of this widget alone.
13- public String draw() {
14- return text;
15- }
16-}

hearth/front/stdlib/ash/desktop/Widget.ashremoved

+0−28
@@ -1,28 +0,0 @@
1-package ash.desktop;
2-
3-import ash.util.ArrayList;
4-import ash.util.List;
5-
6-/// Base of a retained widget tree. Rendering produces text: the VM has no windowing.
7-public abstract class Widget {
8- private final List<Widget> children = new ArrayList<>();
9-
10- protected Widget() { }
11-
12- /// Adds a value (at the index, if given).
13- public void add(Widget child) {
14- children.add(child);
15- }
16-
17- /// Text form of this widget alone.
18- public abstract String draw();
19-
20- /// Text form of the value or widget subtree.
21- public String render(int depth) {
22- String out = " ".repeat(depth) + draw() + "\n";
23- for (Widget c : children) {
24- out += c.render(depth + 1);
25- }
26- return out;
27- }
28-}

hearth/front/stdlib/ash/game/GameLoop.ashremoved

+0−23
@@ -1,23 +0,0 @@
1-package ash.game;
2-
3-import ash.lang.function.Consumer;
4-
5-/// Fixed-step loop: calls `update` with the tick number `ticks` times (no real-time clock).
6-public final class GameLoop {
7- private int tick = 0;
8-
9- public GameLoop() { }
10-
11- /// Performs the task.
12- public void run(int ticks, Consumer<Integer> update) {
13- for (int i = 0; i < ticks; i++) {
14- tick++;
15- update.accept(tick);
16- }
17- }
18-
19- /// Current tick number.
20- public int getTick() {
21- return tick;
22- }
23-}

hearth/front/stdlib/ash/game/Vec2.ashremoved

+0−8
@@ -1,8 +0,0 @@
1-package ash.game;
2-
3-/// Immutable 2D vector.
4-public record Vec2(double x, double y) {
5- public Vec2 plus(Vec2 o) { return new Vec2(x + o.x(), y + o.y()); }
6- public Vec2 scale(double k) { return new Vec2(x * k, y * k); }
7- public double length() { return Math.sqrt(x * x + y * y); }
8-}

hearth/front/stdlib/ash/io/Files.ashremoved

+0−65
@@ -1,65 +0,0 @@
1-package ash.io;
2-
3-import ash.util.List;
4-
5-/// Whole-file operations. Failures are reported as IOException.
6-public final class Files {
7- @Lower("file_exists($1)") private static native bool existsRaw(String path);
8- @Lower("read_file($1)") private static native String readRaw(String path);
9- @Lower("write_file($1, $2)") private static native void writeRaw(String path, String text);
10- @Lower("append_file($1, $2)") private static native void appendRaw(String path, String text);
11- @Lower("delete_file($1)") private static native void deleteRaw(String path);
12- @Lower("rename_file($1, $2)") private static native void moveRaw(String from, String to);
13- @Lower("make_dir($1)") private static native void mkdirRaw(String path);
14- @Lower("list_dir($1)") private static native List<String> listRaw(String path);
15-
16- /// True when the file or directory exists.
17- public static bool exists(Path path) {
18- return existsRaw(path.value());
19- }
20-
21- /// Whole file contents as text; throws IOException if missing.
22- public static String readString(Path path) throws IOException {
23- require(path);
24- return readRaw(path.value());
25- }
26-
27- /// Replaces the file contents; throws IOException on failure.
28- public static void writeString(Path path, String text) throws IOException {
29- writeRaw(path.value(), text);
30- }
31-
32- /// Appends text to the file.
33- public static void appendString(Path path, String text) throws IOException {
34- appendRaw(path.value(), text);
35- }
36-
37- /// Deletes the file; throws IOException if missing.
38- public static void delete(Path path) throws IOException {
39- require(path);
40- deleteRaw(path.value());
41- }
42-
43- /// Renames or moves a file.
44- public static void move(Path from, Path to) throws IOException {
45- require(from);
46- moveRaw(from.value(), to.value());
47- }
48-
49- /// Creates a directory.
50- public static void createDirectory(Path path) throws IOException {
51- mkdirRaw(path.value());
52- }
53-
54- /// Names of the directory entries.
55- public static List<String> list(Path dir) throws IOException {
56- require(dir);
57- return listRaw(dir.value());
58- }
59-
60- private static void require(Path path) throws IOException {
61- if (!existsRaw(path.value())) {
62- throw new IOException("no such file or directory: " + path.value());
63- }
64- }
65-}

hearth/front/stdlib/ash/io/Path.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-package ash.io;
2-
3-/// A file system path, kept as text.
4-public record Path(String value) {
5- /// Creates a value from the argument.
6- public static Path of(String value) {
7- return new Path(value);
8- }
9-
10- /// Child path below this one.
11- public Path resolve(String child) {
12- if (value.endsWith("/")) {
13- return new Path(value + child);
14- }
15- return new Path(value + "/" + child);
16- }
17-
18- /// Text form.
19- public String toString() {
20- return value;
21- }
22-}

hearth/front/stdlib/ash/json/Json.ashremoved

+0−208
@@ -1,208 +0,0 @@
1-package ash.json;
2-
3-import ash.util.List;
4-import ash.util.ArrayList;
5-import ash.util.Map;
6-import ash.util.HashMap;
7-
8-/// JSON text <-> Object trees: Map<String, Object>, List<Object>, String, numbers, Boolean, null.
9-public final class Json {
10- private final String text;
11- private int pos;
12-
13- private Json(String text) {
14- this.text = text;
15- this.pos = 0;
16- }
17-
18- /// Parses text; throws ParseException when malformed.
19- public static Object? parse(String text) throws ParseException {
20- Json p = new Json(text);
21- p.skip();
22- Object? v = p.value();
23- p.skip();
24- if (p.pos < text.length()) {
25- throw new ParseException("trailing characters at " + p.pos);
26- }
27- return v;
28- }
29-
30- /// JSON text for a tree of maps, lists, strings, numbers, booleans and null.
31- public static String stringify(Object? v) {
32- StringBuilder sb = new StringBuilder();
33- write(sb, v);
34- return sb.toString();
35- }
36-
37- private static void write(StringBuilder sb, Object? v) {
38- if (v == null) {
39- sb.append("null");
40- } else if (v instanceof String s) {
41- sb.append(quote(s));
42- } else if (v instanceof Boolean b) {
43- sb.append(String.valueOf(b));
44- } else if (v instanceof List l) {
45- sb.append("[");
46- for (int i = 0; i < l.size(); i++) {
47- if (i > 0) {
48- sb.append(",");
49- }
50- write(sb, l.get(i));
51- }
52- sb.append("]");
53- } else if (v instanceof Map m) {
54- sb.append("{");
55- bool first = true;
56- for (Object k : m.keys()) {
57- if (!first) {
58- sb.append(",");
59- }
60- first = false;
61- sb.append(quote(String.valueOf(k))).append(":");
62- write(sb, m.get(k));
63- }
64- sb.append("}");
65- } else {
66- sb.append(String.valueOf(v));
67- }
68- }
69-
70- private static String quote(String s) {
71- return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
72- }
73-
74- private void skip() {
75- while (pos < text.length() && text.charAt(pos) <= 32) {
76- pos++;
77- }
78- }
79-
80- private Object? value() throws ParseException {
81- if (pos >= text.length()) {
82- throw new ParseException("unexpected end of input");
83- }
84- char c = text.charAt(pos);
85- if (c == '{') {
86- return object();
87- }
88- if (c == '[') {
89- return array();
90- }
91- if (c == '"') {
92- return string();
93- }
94- if (text.startsWith("true", pos)) {
95- pos += 4;
96- return true;
97- }
98- if (text.startsWith("false", pos)) {
99- pos += 5;
100- return false;
101- }
102- if (text.startsWith("null", pos)) {
103- pos += 4;
104- return null;
105- }
106- return number();
107- }
108-
109- private Object number() throws ParseException {
110- int start = pos;
111- while (pos < text.length() && (text.charAt(pos) == '-' || text.charAt(pos) == '.' || (text.charAt(pos) >= '0' && text.charAt(pos) <= '9'))) {
112- pos++;
113- }
114- if (start == pos) {
115- throw new ParseException("unexpected character at " + pos);
116- }
117- return Double.parse(text.substring(start, pos));
118- }
119-
120- private String string() throws ParseException {
121- pos++;
122- StringBuilder sb = new StringBuilder();
123- while (pos < text.length() && text.charAt(pos) != '"') {
124- char c = text.charAt(pos);
125- if (c == '\\') {
126- pos++;
127- char e = text.charAt(pos);
128- if (e == 'n') {
129- sb.append('\n');
130- } else if (e == 't') {
131- sb.append('\t');
132- } else {
133- sb.append(e);
134- }
135- } else {
136- sb.append(c);
137- }
138- pos++;
139- }
140- if (pos >= text.length()) {
141- throw new ParseException("unterminated string");
142- }
143- pos++;
144- return sb.toString();
145- }
146-
147- private List<Object?> array() throws ParseException {
148- pos++;
149- List<Object?> out = new ArrayList<>();
150- skip();
151- if (text.charAt(pos) == ']') {
152- pos++;
153- return out;
154- }
155- while (true) {
156- skip();
157- out.add(value());
158- skip();
159- if (pos >= text.length()) {
160- throw new ParseException("unterminated array");
161- }
162- char c = text.charAt(pos);
163- pos++;
164- if (c == ']') {
165- return out;
166- }
167- if (c != ',') {
168- throw new ParseException("expected ',' or ']' at " + pos);
169- }
170- }
171- }
172-
173- private Map<String, Object?> object() throws ParseException {
174- pos++;
175- Map<String, Object?> out = new HashMap<>();
176- skip();
177- if (text.charAt(pos) == '}') {
178- pos++;
179- return out;
180- }
181- while (true) {
182- skip();
183- if (pos >= text.length() || text.charAt(pos) != '"') {
184- throw new ParseException("expected a string key at " + pos);
185- }
186- String key = string();
187- skip();
188- if (pos >= text.length() || text.charAt(pos) != ':') {
189- throw new ParseException("expected ':' at " + pos);
190- }
191- pos++;
192- skip();
193- out.put(key, value());
194- skip();
195- if (pos >= text.length()) {
196- throw new ParseException("unterminated object");
197- }
198- char c = text.charAt(pos);
199- pos++;
200- if (c == '}') {
201- return out;
202- }
203- if (c != ',') {
204- throw new ParseException("expected ',' or '}' at " + pos);
205- }
206- }
207- }
208-}

hearth/front/stdlib/ash/lang/ArithmeticException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown for integer division or remainder by zero.
4-public class ArithmeticException extends RuntimeException {
5- public ArithmeticException() { }
6-
7- /// Creates a new ArithmeticException.
8- public ArithmeticException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new ArithmeticException.
13- public ArithmeticException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Boolean.ashremoved

+0−13
@@ -1,13 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed bool; the VM represents it as the plain value.
4-public final class Boolean implements Comparable<Boolean> {
5- /// The value as a bool.
6- @Lower("$0") public native bool toBoolValue();
7- /// Negative, zero or positive as this value orders before, equal to or after the other.
8- @Lower("__cmp($0, $1)") public native int compareTo(Boolean other);
9- /// Converts the argument to this type (text for String).
10- @Lower("$1") public static native Boolean valueOf(bool v);
11- /// Parses text; throws ParseException when malformed.
12- @Lower("($1 == \"true\")") public static native bool parse(String s);
13-}

hearth/front/stdlib/ash/lang/Byte.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed byte; represented as a plain number.
4-public final class Byte extends Number implements Comparable<Byte> {
5- /// The value as a double.
6- @Lower("$0") public native double toDoubleValue();
7- /// The value as a byte.
8- @Lower("$0") public native byte toByteValue();
9- /// Negative, zero or positive as this value orders before, equal to or after the other.
10- @Lower("__cmp($0, $1)") public native int compareTo(Byte other);
11- /// Converts the argument to this type (text for String).
12- @Lower("$1") public static native Byte valueOf(byte v);
13- /// Parses text; throws ParseException when malformed.
14- @Lower("__parse_int($1)") public static native byte parse(String s) throws ParseException;
15-}

hearth/front/stdlib/ash/lang/Character.ashremoved

+0−11
@@ -1,11 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed char; represented as its code point.
4-public final class Character implements Comparable<Character> {
5- /// The value as a char.
6- @Lower("$0") public native char toCharValue();
7- /// Negative, zero or positive as this value orders before, equal to or after the other.
8- @Lower("__cmp($0, $1)") public native int compareTo(Character other);
9- /// Converts the argument to this type (text for String).
10- @Lower("$1") public static native Character valueOf(char v);
11-}

hearth/front/stdlib/ash/lang/Class.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang;
2-
3-/// Runtime type descriptor returned by Object.getClass().
4-public final class Class {
5- /// Fully qualified class name.
6- @Lower("$0[\"n\"]") public native String getName();
7-}

hearth/front/stdlib/ash/lang/ClassCastException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when a cast does not match the runtime type.
4-public class ClassCastException extends RuntimeException {
5- public ClassCastException() { }
6-
7- /// Creates a new ClassCastException.
8- public ClassCastException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new ClassCastException.
13- public ClassCastException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Comparable.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang;
2-
3-/// Types with a natural order.
4-public interface Comparable<T> {
5- /// Negative, zero or positive as this value orders before, equal to or after the other.
6- int compareTo(T other);
7-}

hearth/front/stdlib/ash/lang/Double.ashremoved

+0−13
@@ -1,13 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed double; represented as a plain number.
4-public final class Double extends Number implements Comparable<Double> {
5- /// The value as a double.
6- @Lower("$0") public native double toDoubleValue();
7- /// Negative, zero or positive as this value orders before, equal to or after the other.
8- @Lower("__cmp($0, $1)") public native int compareTo(Double other);
9- /// Converts the argument to this type (text for String).
10- @Lower("$1") public static native Double valueOf(double v);
11- /// Parses text; throws ParseException when malformed.
12- @Lower("__parse_double($1)") public static native double parse(String s) throws ParseException;
13-}

hearth/front/stdlib/ash/lang/Enum.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Base class of every enum: constant name and declaration order.
4-public abstract class Enum<E> implements Comparable<E> {
5- /// Declared name of the constant.
6- @Lower("$0[\"__name\"]") public final native String name();
7- /// Position in the enum declaration, starting at 0.
8- @Lower("$0[\"__ord\"]") public final native int ordinal();
9- /// Negative, zero or positive as this value orders before, equal to or after the other.
10- @Lower("($0[\"__ord\"] - $1[\"__ord\"])") public final native int compareTo(E other);
11-
12- /// Text form.
13- public String toString() {
14- return name();
15- }
16-}

hearth/front/stdlib/ash/lang/Exception.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Base of recoverable (checked) failures; RuntimeException subclasses are unchecked.
4-public class Exception extends Throwable {
5- public Exception() { }
6-
7- /// Creates a new Exception.
8- public Exception(String message) {
9- super(message);
10- }
11-
12- /// Creates a new Exception.
13- public Exception(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Float.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed float; represented as a plain number.
4-public final class Float extends Number implements Comparable<Float> {
5- /// The value as a double.
6- @Lower("$0") public native double toDoubleValue();
7- /// The value as a float.
8- @Lower("$0") public native float toFloatValue();
9- /// Negative, zero or positive as this value orders before, equal to or after the other.
10- @Lower("__cmp($0, $1)") public native int compareTo(Float other);
11- /// Converts the argument to this type (text for String).
12- @Lower("$1") public static native Float valueOf(float v);
13- /// Parses text; throws ParseException when malformed.
14- @Lower("__parse_double($1)") public static native float parse(String s) throws ParseException;
15-}

hearth/front/stdlib/ash/lang/IOException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Checked failure of a file or stream operation.
4-public class IOException extends Exception {
5- public IOException() { }
6-
7- /// Creates a new IOException.
8- public IOException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new IOException.
13- public IOException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/IllegalArgumentException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when an argument is not acceptable.
4-public class IllegalArgumentException extends RuntimeException {
5- public IllegalArgumentException() { }
6-
7- /// Creates a new IllegalArgumentException.
8- public IllegalArgumentException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new IllegalArgumentException.
13- public IllegalArgumentException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/IllegalStateException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when an object is not in a state that allows the call.
4-public class IllegalStateException extends RuntimeException {
5- public IllegalStateException() { }
6-
7- /// Creates a new IllegalStateException.
8- public IllegalStateException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new IllegalStateException.
13- public IllegalStateException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/IndexOutOfBoundsException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown for an array or list index outside its bounds.
4-public class IndexOutOfBoundsException extends RuntimeException {
5- public IndexOutOfBoundsException() { }
6-
7- /// Creates a new IndexOutOfBoundsException.
8- public IndexOutOfBoundsException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new IndexOutOfBoundsException.
13- public IndexOutOfBoundsException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/InputStream.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang;
2-
3-/// Standard input; see System.in.
4-public final class InputStream {
5- /// Reads one line from standard input.
6- @Lower("input()") public native String readLine();
7-}

hearth/front/stdlib/ash/lang/Integer.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed int; represented as a plain number.
4-public final class Integer extends Number implements Comparable<Integer> {
5- /// Largest int value, 2^31 - 1.
6- @Lower("2147483647") public static final int MAX_VALUE = 2147483647;
7- /// Smallest int value, -2^31.
8- @Lower("(-2147483648)") public static final int MIN_VALUE = -2147483648;
9- /// The value as a double.
10- @Lower("$0") public native double toDoubleValue();
11- /// The value as an int.
12- @Lower("$0") public native int toIntValue();
13- /// Negative, zero or positive as this value orders before, equal to or after the other.
14- @Lower("__cmp($0, $1)") public native int compareTo(Integer other);
15- /// Converts the argument to this type (text for String).
16- @Lower("$1") public static native Integer valueOf(int v);
17- /// Parses text; throws ParseException when malformed.
18- @Lower("__parse_int($1)") public static native int parse(String s) throws ParseException;
19-}

hearth/front/stdlib/ash/lang/Iterable.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-package ash.lang;
2-
3-import ash.util.Iterator;
4-
5-/// Types that can be the target of a for-each loop.
6-public interface Iterable<T> {
7- /// Cursor over the elements.
8- @Lower("__iterof($0)") Iterator<T> iterator();
9-}

hearth/front/stdlib/ash/lang/KeyNotFoundException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when a map lookup that must succeed finds no entry.
4-public class KeyNotFoundException extends RuntimeException {
5- public KeyNotFoundException() { }
6-
7- /// Creates a new KeyNotFoundException.
8- public KeyNotFoundException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new KeyNotFoundException.
13- public KeyNotFoundException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Long.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed long; a plain number while it fits in 2^53, an exact two-halves value beyond that (--wrap-int).
4-public final class Long extends Number implements Comparable<Long> {
5- /// Largest long value, 2^63 - 1 (exact with --wrap-int; the nearest double otherwise).
6- @Lower("9223372036854775807||{\"__L\": 1, \"hi\": 2147483647, \"lo\": 4294967295}") public static final long MAX_VALUE = 9223372036854775807L;
7- /// Smallest long value, -2^63 (exact with --wrap-int; the nearest double otherwise).
8- @Lower("(-9223372036854775807)||{\"__L\": 1, \"hi\": -2147483648, \"lo\": 0}") public static final long MIN_VALUE = -9223372036854775807L - 1L;
9- /// The value as a double.
10- @Lower("__l2d($0)") public native double toDoubleValue();
11- /// The value as a long.
12- @Lower("$0") public native long toLongValue();
13- /// Negative, zero or positive as this value orders before, equal to or after the other.
14- @Lower("__lcmp($0, $1)") public native int compareTo(Long other);
15- /// Converts the argument to this type (text for String).
16- @Lower("$1") public static native Long valueOf(long v);
17- /// Parses text; throws ParseException when malformed.
18- @Lower("__lparse($1)") public static native long parse(String s) throws ParseException;
19-}

hearth/front/stdlib/ash/lang/Math.ashremoved

+0−21
@@ -1,21 +0,0 @@
1-package ash.lang;
2-
3-/// Basic numeric functions.
4-public final class Math {
5- /// Square root.
6- @Lower("sqrt($1)") public static native double sqrt(double x);
7- /// Largest whole number not above the argument.
8- @Lower("floor($1)") public static native double floor(double x);
9- /// Absolute value.
10- @Lower("abs($1)") public static native int abs(int x);
11- /// Absolute value.
12- @Lower("abs($1)") public static native double abs(double x);
13- /// Larger of two values.
14- @Lower("__max($1, $2)") public static native int max(int a, int b);
15- /// Smaller of two values.
16- @Lower("__min($1, $2)") public static native int min(int a, int b);
17- /// Larger of two values.
18- @Lower("__max($1, $2)") public static native double max(double a, double b);
19- /// Smaller of two values.
20- @Lower("__min($1, $2)") public static native double min(double a, double b);
21-}

hearth/front/stdlib/ash/lang/NullPointerException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when a null reference is used.
4-public class NullPointerException extends RuntimeException {
5- public NullPointerException() { }
6-
7- /// Creates a new NullPointerException.
8- public NullPointerException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new NullPointerException.
13- public NullPointerException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Number.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang;
2-
3-/// Base of the numeric box types.
4-public abstract class Number {
5- /// The value as a double.
6- public abstract double toDoubleValue();
7-}

hearth/front/stdlib/ash/lang/Object.ashremoved

+0−14
@@ -1,14 +0,0 @@
1-package ash.lang;
2-
3-/// Root of the class hierarchy.
4-public class Object {
5- @Lower("{}") public Object() { }
6- /// Value equality; identity unless overridden.
7- @Lower("__eq($0, $1)") public native bool equals(Object? o);
8- /// Hash consistent with equals.
9- @Lower("__hash($0)") public native int hashCode();
10- /// Text form.
11- @Lower("__str($0)") public native String toString();
12- /// Runtime class of the object.
13- @Lower("__classof($0)") public native Class getClass();
14-}

hearth/front/stdlib/ash/lang/ParseException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Checked failure to parse text (numbers, JSON, URLs).
4-public class ParseException extends Exception {
5- public ParseException() { }
6-
7- /// Creates a new ParseException.
8- public ParseException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new ParseException.
13- public ParseException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/PrintStream.ashremoved

+0−23
@@ -1,23 +0,0 @@
1-package ash.lang;
2-
3-/// Text output; System.out and System.err.
4-public final class PrintStream {
5- /// Prints the value followed by a newline.
6- @Lower("__println(\"\")") public native void println();
7- /// Prints the value followed by a newline.
8- @Lower("__println(__str($1))") public native void println(Object? o);
9- /// Prints the value followed by a newline.
10- @Lower("__println(__str($1))") public native void println(String? s);
11- /// Prints the value followed by a newline.
12- @Lower("__println(str($1))") public native void println(int i);
13- /// Prints the value followed by a newline.
14- @Lower("__println(__lstr($1))") public native void println(long l);
15- /// Prints the value followed by a newline.
16- @Lower("__println(__dstr($1))") public native void println(double d);
17- /// Prints the value followed by a newline.
18- @Lower("__println(__fstr($1))") public native void println(float f);
19- /// Prints the value followed by a newline.
20- @Lower("__println(__bs($1))") public native void println(bool b);
21- /// Prints the value followed by a newline.
22- @Lower("__println(chr($1))") public native void println(char c);
23-}

hearth/front/stdlib/ash/lang/Record.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-package ash.lang;
2-
3-/// Base class of every record.
4-public abstract class Record { }

hearth/front/stdlib/ash/lang/RuntimeException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Base of unchecked failures that signal programming errors.
4-public class RuntimeException extends Exception {
5- public RuntimeException() { }
6-
7- /// Creates a new RuntimeException.
8- public RuntimeException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new RuntimeException.
13- public RuntimeException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/Short.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-package ash.lang;
2-
3-/// Boxed short; represented as a plain number.
4-public final class Short extends Number implements Comparable<Short> {
5- /// The value as a double.
6- @Lower("$0") public native double toDoubleValue();
7- /// The value as a short.
8- @Lower("$0") public native short toShortValue();
9- /// Negative, zero or positive as this value orders before, equal to or after the other.
10- @Lower("__cmp($0, $1)") public native int compareTo(Short other);
11- /// Converts the argument to this type (text for String).
12- @Lower("$1") public static native Short valueOf(short v);
13- /// Parses text; throws ParseException when malformed.
14- @Lower("__parse_int($1)") public static native short parse(String s) throws ParseException;
15-}

hearth/front/stdlib/ash/lang/String.ashremoved

+0−57
@@ -1,57 +0,0 @@
1-package ash.lang;
2-
3-import ash.util.List;
4-
5-/// Immutable text. Represented natively by the VM.
6-public final class String implements Comparable<String> {
7- /// Number of characters.
8- @Lower("len($0)") public native int length();
9- /// Character code at the given index.
10- @Lower("ord($0[$1])") public native char charAt(int index);
11- /// Part of the text from the start index (to the end index, exclusive).
12- @Lower("substring($0, $1, len($0))") public native String substring(int begin);
13- /// Part of the text from the start index (to the end index, exclusive).
14- @Lower("substring($0, $1, $2)") public native String substring(int begin, int end);
15- /// Index of the first occurrence, or -1.
16- @Lower("indexOf($0, $1)") public native int indexOf(String s);
17- /// True when the value is present.
18- @Lower("contains($0, $1)") public native bool contains(String s);
19- /// True when the text begins with the prefix (at the offset, if given).
20- @Lower("starts_with($0, $1)") public native bool startsWith(String s);
21- /// True when the text begins with the prefix (at the offset, if given).
22- @Lower("__startsat($0, $1, $2)") public native bool startsWith(String s, int offset);
23- /// True when the text ends with the suffix.
24- @Lower("ends_with($0, $1)") public native bool endsWith(String s);
25- /// Replaces every occurrence of a substring.
26- @Lower("replace($0, $1, $2)") public native String replace(String from, String to);
27- /// The text repeated n times.
28- @Lower("repeat($0, $1)") public native String repeat(int n);
29- /// Upper-case copy.
30- @Lower("upper($0)") public native String toUpperCase();
31- /// Lower-case copy.
32- @Lower("lower($0)") public native String toLowerCase();
33- /// Copy without leading and trailing whitespace.
34- @Lower("trim($0)") public native String trim();
35- /// True when there are no elements or characters.
36- @Lower("(len($0) == 0)") public native bool isEmpty();
37- /// Splits at a separator; trailing empty parts are dropped.
38- @Lower("__split($0, $1)") public native String[] split(String sep);
39- /// Negative, zero or positive as this value orders before, equal to or after the other.
40- @Lower("__cmp($0, $1)") public native int compareTo(String other);
41- /// Converts the argument to this type (text for String).
42- @Lower("__str($1)") public static native String valueOf(Object? o);
43- /// Converts the argument to this type (text for String).
44- @Lower("str($1)") public static native String valueOf(int i);
45- /// Converts the argument to this type (text for String).
46- @Lower("__lstr($1)") public static native String valueOf(long l);
47- /// Converts the argument to this type (text for String).
48- @Lower("__dstr($1)") public static native String valueOf(double d);
49- /// Converts the argument to this type (text for String).
50- @Lower("__fstr($1)") public static native String valueOf(float f);
51- /// Converts the argument to this type (text for String).
52- @Lower("__bs($1)") public static native String valueOf(bool b);
53- /// Converts the argument to this type (text for String).
54- @Lower("chr($1)") public static native String valueOf(char c);
55- /// Joins strings with a separator.
56- @Lower("join($2, $1)") public static native String join(String sep, List<String> parts);
57-}

hearth/front/stdlib/ash/lang/StringBuilder.ashremoved

+0−18
@@ -1,18 +0,0 @@
1-package ash.lang;
2-
3-/// Mutable text accumulator; avoids quadratic string building.
4-public final class StringBuilder {
5- @Lower("{\"p\": []}") public StringBuilder() { }
6- /// Adds text to the end; returns this builder.
7- @Lower("__sbappend($0, __str($1))") public native StringBuilder append(String? s);
8- /// Adds text to the end; returns this builder.
9- @Lower("__sbappend($0, __str($1))") public native StringBuilder append(Object? o);
10- /// Adds text to the end; returns this builder.
11- @Lower("__sbappend($0, str($1))") public native StringBuilder append(int i);
12- /// Adds text to the end; returns this builder.
13- @Lower("__sbappend($0, chr($1))") public native StringBuilder append(char c);
14- /// Number of characters.
15- @Lower("len(__sbstr($0))") public native int length();
16- /// Text form.
17- @Lower("__sbstr($0)") public native String toString();
18-}

hearth/front/stdlib/ash/lang/System.ashremoved

+0−13
@@ -1,13 +0,0 @@
1-package ash.lang;
2-
3-/// Process-level facilities: standard streams and exit.
4-public final class System {
5- /// Standard output.
6- public static final PrintStream out = new PrintStream();
7- /// Standard error (the VM has a single output stream, so it shares stdout).
8- public static final PrintStream err = new PrintStream();
9- /// Standard input.
10- public static final InputStream in = new InputStream();
11- /// Ends the program with the given status.
12- @Lower("exit($1)") public static native void exit(int status);
13-}

hearth/front/stdlib/ash/lang/Throwable.ashremoved

+0−38
@@ -1,38 +0,0 @@
1-package ash.lang;
2-
3-/// Root of everything that can be thrown; carries a message, a cause and the creation site.
4-public class Throwable {
5- private final String? message;
6- private final Throwable? cause;
7-
8- /// Creates a new Throwable.
9- public Throwable() {
10- this.message = null;
11- this.cause = null;
12- }
13-
14- /// Creates a new Throwable.
15- public Throwable(String? message) {
16- this.message = message;
17- this.cause = null;
18- }
19-
20- /// Creates a new Throwable.
21- public Throwable(String? message, Throwable? cause) {
22- this.message = message;
23- this.cause = cause;
24- }
25-
26- /// Detail message, or null.
27- public String? getMessage() {
28- return message;
29- }
30-
31- /// Underlying cause, or null.
32- public Throwable? getCause() {
33- return cause;
34- }
35-
36- /// Prints the exception, its creation site and its causes.
37- @Lower("__pst($0)") public native void printStackTrace();
38-}

hearth/front/stdlib/ash/lang/UnsupportedOperationException.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-package ash.lang;
2-
3-/// Thrown when an operation is not available.
4-public class UnsupportedOperationException extends RuntimeException {
5- public UnsupportedOperationException() { }
6-
7- /// Creates a new UnsupportedOperationException.
8- public UnsupportedOperationException(String message) {
9- super(message);
10- }
11-
12- /// Creates a new UnsupportedOperationException.
13- public UnsupportedOperationException(String message, Throwable cause) {
14- super(message, cause);
15- }
16-}

hearth/front/stdlib/ash/lang/function/BiFunction.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Function of two arguments.
4-public interface BiFunction<A, B, R> {
5- /// Applies the function.
6- R apply(A a, B b);
7-}

hearth/front/stdlib/ash/lang/function/Comparator.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Defines an order between two values; negative, zero or positive.
4-public interface Comparator<T> {
5- /// Orders two values: negative, zero or positive.
6- int compare(T a, T b);
7-}

hearth/front/stdlib/ash/lang/function/Consumer.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Operation on one value with no result.
4-public interface Consumer<T> {
5- /// Performs the operation.
6- void accept(T t);
7-}

hearth/front/stdlib/ash/lang/function/Function.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Function of one argument.
4-public interface Function<T, R> {
5- /// Applies the function.
6- R apply(T t);
7-}

hearth/front/stdlib/ash/lang/function/Predicate.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Test of one value.
4-public interface Predicate<T> {
5- /// Evaluates the predicate.
6- bool test(T t);
7-}

hearth/front/stdlib/ash/lang/function/Runnable.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Task with no arguments and no result.
4-public interface Runnable {
5- /// Performs the task.
6- void run();
7-}

hearth/front/stdlib/ash/lang/function/Supplier.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.lang.function;
2-
3-/// Source of values with no arguments.
4-public interface Supplier<T> {
5- /// Element at the index (or the stored value).
6- T get();
7-}

hearth/front/stdlib/ash/math/Numbers.ashremoved

+0−38
@@ -1,38 +0,0 @@
1-package ash.math;
2-
3-/// Integer and floating helpers that the core Math class does not provide.
4-public final class Numbers {
5- /// The ratio of a circle's circumference to its diameter.
6- public static final double PI = 3.141592653589793;
7-
8- /// Integer power.
9- public static long pow(long base, int exponent) {
10- long result = 1;
11- for (int i = 0; i < exponent; i++) {
12- result *= base;
13- }
14- return result;
15- }
16-
17- /// Greatest common divisor.
18- public static long gcd(long a, long b) {
19- long x = a < 0 ? -a : a;
20- long y = b < 0 ? -b : b;
21- while (y != 0) {
22- long t = x % y;
23- x = y;
24- y = t;
25- }
26- return x;
27- }
28-
29- /// Limits the value to the range.
30- public static int clamp(int value, int low, int high) {
31- return Math.max(low, Math.min(value, high));
32- }
33-
34- /// Nearest whole number.
35- public static long round(double value) {
36- return (long) Math.floor(value + 0.5);
37- }
38-}

hearth/front/stdlib/ash/net/Http.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-package ash.net;
2-
3-/// HTTP client facade. The Ash VM has no network access, so every request fails with an
4-/// IOException; the API exists so networked programs type-check and can handle the failure.
5-public final class Http {
6- /// Always throws IOException("network access is not available on this runtime").
7- public static String get(String url) throws IOException {
8- throw new IOException("network access is not available on this runtime: " + url);
9- }
10-}

hearth/front/stdlib/ash/net/Url.ashremoved

+0−27
@@ -1,27 +0,0 @@
1-package ash.net;
2-
3-/// Parsed `scheme://host[:port]/path`. Pure text handling: the VM has no sockets.
4-public record Url(String scheme, String host, int port, String path) {
5- /// Parses text; throws ParseException when malformed.
6- public static Url parse(String text) throws ParseException {
7- int sep = text.indexOf("://");
8- if (sep < 0) {
9- throw new ParseException("missing scheme in " + text);
10- }
11- String scheme = text.substring(0, sep);
12- String rest = text.substring(sep + 3);
13- String path = "/";
14- int slash = rest.indexOf("/");
15- if (slash >= 0) {
16- path = rest.substring(slash);
17- rest = rest.substring(0, slash);
18- }
19- int port = scheme.equals("https") ? 443 : 80;
20- int colon = rest.indexOf(":");
21- if (colon >= 0) {
22- port = Integer.parse(rest.substring(colon + 1));
23- rest = rest.substring(0, colon);
24- }
25- return new Url(scheme, rest, port, path);
26- }
27-}

hearth/front/stdlib/ash/test/Assert.ashremoved

+0−36
@@ -1,36 +0,0 @@
1-package ash.test;
2-
3-/// Minimal assertions; a failure throws AssertionError.
4-public final class Assert {
5- /// Fails unless the condition holds.
6- public static void assertTrue(bool condition, String message) {
7- if (!condition) {
8- throw new AssertionError(message);
9- }
10- }
11-
12- /// Fails unless the values are equal.
13- public static void assertEquals(Object? expected, Object? actual) {
14- if (expected == null) {
15- if (actual != null) {
16- throw new AssertionError("expected null but was " + actual);
17- }
18- return;
19- }
20- if (!expected.equals(actual)) {
21- throw new AssertionError("expected " + expected + " but was " + actual);
22- }
23- }
24-
25- /// Fails unless the value is null.
26- public static void assertNull(Object? actual) {
27- if (actual != null) {
28- throw new AssertionError("expected null but was " + actual);
29- }
30- }
31-
32- /// Fails unconditionally.
33- public static void fail(String message) {
34- throw new AssertionError(message);
35- }
36-}

hearth/front/stdlib/ash/test/AssertionError.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-package ash.test;
2-
3-/// Thrown by ash.test.Assert when a check fails.
4-public class AssertionError extends RuntimeException {
5- /// Creates a new AssertionError.
6- public AssertionError(String message) {
7- super(message);
8- }
9-}

hearth/front/stdlib/ash/time/Duration.ashremoved

+0−24
@@ -1,24 +0,0 @@
1-package ash.time;
2-
3-/// A length of time in milliseconds. (The VM has no clock; this is pure arithmetic.)
4-public record Duration(long millis) {
5- /// Duration of whole seconds.
6- public static Duration ofSeconds(long seconds) {
7- return new Duration(seconds * 1000);
8- }
9-
10- /// Duration of milliseconds.
11- public static Duration ofMillis(long millis) {
12- return new Duration(millis);
13- }
14-
15- /// Sum of two values.
16- public Duration plus(Duration other) {
17- return new Duration(millis + other.millis());
18- }
19-
20- /// Whole seconds.
21- public long toSeconds() {
22- return millis / 1000;
23- }
24-}

hearth/front/stdlib/ash/util/ArrayList.ashremoved

+0−37
@@ -1,37 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.function.Comparator;
4-import ash.lang.function.Consumer;
5-
6-/// Growable list backed by an Ash array.
7-public class ArrayList<T> implements List<T> {
8- @Lower("[]") public ArrayList() { }
9- /// Number of elements.
10- @Lower("len($0)") public native int size();
11- /// True when there are no elements or characters.
12- @Lower("(len($0) == 0)") public native bool isEmpty();
13- /// Element at the index (or the stored value).
14- @Lower("$0[$1]") public native T get(int index);
15- /// Replaces the element at the index; returns the old one.
16- @Lower("__lset($0, $1, $2)") public native T set(int index, T value);
17- /// Adds a value (at the index, if given).
18- @Lower("push($0, $1)") public native void add(T value);
19- /// Adds a value (at the index, if given).
20- @Lower("insert($0, $1, $2)") public native void add(int index, T value);
21- /// Removes and returns the entry.
22- @Lower("__lremove($0, $1)") public native T remove(int index);
23- /// Removes and returns the last element.
24- @Lower("pop($0)") public native T removeLast();
25- /// True when the value is present.
26- @Lower("__lcontains($0, $1)") public native bool contains(Object o);
27- /// Sorts in place with the comparator.
28- @Lower("sort($0, __cmpfn($1))") public native void sort(Comparator<T> c);
29- /// Elements from the start index to the end index, exclusive.
30- @Lower("slice($0, $1, $2)") public native List<T> subList(int from, int to);
31- /// Pipeline over a copy of the elements.
32- @Lower("slice($0, 0, len($0))") public native Stream<T> stream();
33- /// Cursor over the elements.
34- @Lower("__iter($0)") public native Iterator<T> iterator();
35- /// Runs the action for every element.
36- @Lower("__foreach($0, __fn1($1, \"accept/1\"))") public native void forEach(Consumer<T> c);
37-}

hearth/front/stdlib/ash/util/Collector.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.util;
2-
3-/// Turns the elements of a Stream into a single result; see Collectors.
4-public interface Collector<T, R> {
5- /// Combines all elements into the result.
6- R finish(List<T> items);
7-}

hearth/front/stdlib/ash/util/Collectors.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-package ash.util;
2-
3-/// Ready-made Collector implementations for Stream.collect.
4-public final class Collectors {
5- /// Collects into a new List.
6- public static <T> Collector<T, List<T>> toList() {
7- return items -> items;
8- }
9-
10- /// Joins strings with a separator.
11- public static Collector<String, String> joining(String separator) {
12- return items -> String.join(separator, items);
13- }
14-
15- /// Counts the elements.
16- public static <T> Collector<T, Integer> counting() {
17- return items -> items.size();
18- }
19-}

hearth/front/stdlib/ash/util/HashMap.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-package ash.util;
2-
3-/// Map backed by an Ash map; any key type is supported.
4-public class HashMap<K, V> implements Map<K, V> {
5- @Lower("{}") public HashMap() { }
6- /// Number of elements.
7- @Lower("__msize($0)") public native int size();
8- /// Stores a value under a key; returns the previous value or null.
9- @Lower("__mput($0, $1, $2)") public native V? put(K key, V value);
10- /// Element at the index (or the stored value).
11- @Lower("__mget($0, $1)") public native V? get(K key);
12- /// True when the key is present.
13- @Lower("__mhas($0, $1)") public native bool containsKey(K key);
14- /// Removes and returns the entry.
15- @Lower("__mremove($0, $1)") public native V? remove(K key);
16- /// Keys in insertion order.
17- @Lower("__mkeys($0)") public native List<K> keys();
18- /// Values in insertion order.
19- @Lower("__mvals($0)") public native List<V> values();
20-}

hearth/front/stdlib/ash/util/HashSet.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-package ash.util;
2-
3-/// Set backed by an Ash map; any element type is supported.
4-public class HashSet<T> implements Set<T> {
5- @Lower("{}") public HashSet() { }
6- /// Number of elements.
7- @Lower("__msize($0)") public native int size();
8- /// True when there are no elements or characters.
9- @Lower("(__msize($0) == 0)") public native bool isEmpty();
10- /// Adds a value (at the index, if given).
11- @Lower("__sadd($0, $1)") public native bool add(T value);
12- /// True when the value is present.
13- @Lower("__mhas($0, $1)") public native bool contains(T value);
14- /// Removes and returns the entry.
15- @Lower("__sremove($0, $1)") public native bool remove(T value);
16- /// The elements as a List.
17- @Lower("__mkeys($0)") public native List<T> toList();
18- /// Cursor over the elements.
19- @Lower("__iter(__mkeys($0))") public native Iterator<T> iterator();
20-}

hearth/front/stdlib/ash/util/Iterator.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-package ash.util;
2-
3-/// Cursor over a sequence of values.
4-public interface Iterator<T> {
5- /// True when next() will return another value.
6- bool hasNext();
7- /// Returns the next value.
8- T next();
9-}

hearth/front/stdlib/ash/util/List.ashremoved

+0−35
@@ -1,35 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.Iterable;
4-import ash.lang.function.Comparator;
5-import ash.lang.function.Consumer;
6-
7-/// Ordered, indexable collection.
8-public interface List<T> extends Iterable<T> {
9- /// Number of elements.
10- @Lower("len($0)") int size();
11- /// True when there are no elements or characters.
12- @Lower("(len($0) == 0)") bool isEmpty();
13- /// Element at the index (or the stored value).
14- @Lower("$0[$1]") T get(int index);
15- /// Replaces the element at the index; returns the old one.
16- @Lower("__lset($0, $1, $2)") T set(int index, T value);
17- /// Adds a value (at the index, if given).
18- @Lower("push($0, $1)") void add(T value);
19- /// Adds a value (at the index, if given).
20- @Lower("insert($0, $1, $2)") void add(int index, T value);
21- /// Removes and returns the entry.
22- @Lower("__lremove($0, $1)") T remove(int index);
23- /// Removes and returns the last element.
24- @Lower("pop($0)") T removeLast();
25- /// True when the value is present.
26- @Lower("__lcontains($0, $1)") bool contains(Object o);
27- /// Sorts in place with the comparator.
28- @Lower("sort($0, __cmpfn($1))") void sort(Comparator<T> c);
29- /// Elements from the start index to the end index, exclusive.
30- @Lower("slice($0, $1, $2)") List<T> subList(int from, int to);
31- /// Pipeline over a copy of the elements.
32- @Lower("slice($0, 0, len($0))") Stream<T> stream();
33- /// Runs the action for every element.
34- @Lower("__foreach($0, __fn1($1, \"accept/1\"))") void forEach(Consumer<T> c);
35-}

hearth/front/stdlib/ash/util/Map.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-package ash.util;
2-
3-/// Association of keys to values in insertion order.
4-public interface Map<K, V> {
5- /// Number of elements.
6- @Lower("__msize($0)") int size();
7- /// Stores a value under a key; returns the previous value or null.
8- @Lower("__mput($0, $1, $2)") V? put(K key, V value);
9- /// Element at the index (or the stored value).
10- @Lower("__mget($0, $1)") V? get(K key);
11- /// True when the key is present.
12- @Lower("__mhas($0, $1)") bool containsKey(K key);
13- /// Removes and returns the entry.
14- @Lower("__mremove($0, $1)") V? remove(K key);
15- /// Keys in insertion order.
16- @Lower("__mkeys($0)") List<K> keys();
17- /// Values in insertion order.
18- @Lower("__mvals($0)") List<V> values();
19-}

hearth/front/stdlib/ash/util/Optional.ashremoved

+0−54
@@ -1,54 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.function.Function;
4-
5-/// A value that may be absent. Prefer `T?` for fields and locals; use Optional for return values.
6-public final class Optional<T> {
7- private final T? value;
8-
9- private Optional(T? value) {
10- this.value = value;
11- }
12-
13- /// Creates a value from the argument.
14- public static <T> Optional<T> of(T value) {
15- return new Optional<T>(value);
16- }
17-
18- /// Empty value.
19- public static <T> Optional<T> empty() {
20- return new Optional<T>(null);
21- }
22-
23- /// True when a value is present.
24- public bool isPresent() {
25- return value != null;
26- }
27-
28- /// Element at the index (or the stored value).
29- public T get() {
30- T? v = value;
31- if (v == null) {
32- throw new IllegalStateException("Optional is empty");
33- }
34- return v;
35- }
36-
37- /// The value, or the fallback.
38- public T orElse(T other) {
39- T? v = value;
40- if (v == null) {
41- return other;
42- }
43- return v;
44- }
45-
46- /// Transforms every element.
47- public <R> Optional<R> map(Function<T, R> f) {
48- T? v = value;
49- if (v == null) {
50- return Optional.empty();
51- }
52- return Optional.of(f.apply(v));
53- }
54-}

hearth/front/stdlib/ash/util/Result.ashremoved

+0−62
@@ -1,62 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.function.Function;
4-
5-/// Success value or error value, for APIs that report failure without exceptions.
6-public final class Result<T, E> {
7- private final T? value;
8- private final E? error;
9-
10- private Result(T? value, E? error) {
11- this.value = value;
12- this.error = error;
13- }
14-
15- /// Creates a successful result.
16- public static <T, E> Result<T, E> ok(T value) {
17- return new Result<T, E>(value, null);
18- }
19-
20- /// Creates a failed result.
21- public static <T, E> Result<T, E> err(E error) {
22- return new Result<T, E>(null, error);
23- }
24-
25- /// True for a successful result.
26- public bool isOk() {
27- return error == null;
28- }
29-
30- /// Returns the value or throws IllegalStateException when this is an error.
31- public T unwrap() {
32- T? v = value;
33- if (v == null) {
34- throw new IllegalStateException("unwrap on an error result");
35- }
36- return v;
37- }
38-
39- /// The value, or the fallback.
40- public T unwrapOr(T fallback) {
41- T? v = value;
42- if (v == null) {
43- return fallback;
44- }
45- return v;
46- }
47-
48- /// The error of a failed result, or null.
49- public E? getError() {
50- return error;
51- }
52-
53- /// Transforms every element.
54- public <R> Result<R, E> map(Function<T, R> f) {
55- T? v = value;
56- E? e = error;
57- if (v == null) {
58- return new Result<R, E>(null, e);
59- }
60- return new Result<R, E>(f.apply(v), null);
61- }
62-}

hearth/front/stdlib/ash/util/Set.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.Iterable;
4-
5-/// Collection without duplicates.
6-public interface Set<T> extends Iterable<T> {
7- /// Number of elements.
8- @Lower("__msize($0)") int size();
9- /// True when there are no elements or characters.
10- @Lower("(__msize($0) == 0)") bool isEmpty();
11- /// Adds a value (at the index, if given).
12- @Lower("__sadd($0, $1)") bool add(T value);
13- /// True when the value is present.
14- @Lower("__mhas($0, $1)") bool contains(T value);
15- /// Removes and returns the entry.
16- @Lower("__sremove($0, $1)") bool remove(T value);
17- /// The elements as a List.
18- @Lower("__mkeys($0)") List<T> toList();
19-}

hearth/front/stdlib/ash/util/Stream.ashremoved

+0−25
@@ -1,25 +0,0 @@
1-package ash.util;
2-
3-import ash.lang.function.*;
4-
5-/// Eager collection pipeline over a List.
6-public interface Stream<T> {
7- /// Keeps the elements that pass the test.
8- @Lower("filter($0, __fn1($1, \"test/1\"))") Stream<T> filter(Predicate<T> p);
9- /// Transforms every element.
10- @Lower("map($0, __fn1($1, \"apply/1\"))") <R> Stream<R> map(Function<T, R> f);
11- /// Folds the elements into one value starting from the identity.
12- @Lower("reduce($0, __fn2($2, \"apply/2\"), $1)") T reduce(T identity, BiFunction<T, T, T> f);
13- /// The elements as a List.
14- @Lower("slice($0, 0, len($0))") List<T> toList();
15- /// Runs the action for every element.
16- @Lower("__foreach($0, __fn1($1, \"accept/1\"))") void forEach(Consumer<T> c);
17- /// Applies a Collector to the elements.
18- @Lower("__sam1($1, \"finish/1\", $0)") <R> R collect(Collector<T, R> collector);
19- /// Number of elements.
20- @Lower("len($0)") int count();
21- /// Sorted copy using the comparator.
22- @Lower("__sorted($0, __cmpfn($1))") Stream<T> sorted(Comparator<T> c);
23- /// True when some element passes the test.
24- @Lower("__anymatch($0, __fn1($1, \"test/1\"))") bool anyMatch(Predicate<T> p);
25-}

hearth/front/stdlib/ash/web/Handler.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-package ash.web;
2-
3-/// Handles one request.
4-public interface Handler {
5- /// Produces the response for a request.
6- Response handle(Request request);
7-}

hearth/front/stdlib/ash/web/Request.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-package ash.web;
2-
3-/// An HTTP-style request value.
4-public record Request(String method, String path) { }

hearth/front/stdlib/ash/web/Response.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-package ash.web;
2-
3-/// An HTTP-style response value.
4-public record Response(int status, String body) {
5- /// Text form of the value or widget subtree.
6- public String render() {
7- return status + " " + body;
8- }
9-}

hearth/front/stdlib/ash/web/Router.ashremoved

+0−29
@@ -1,29 +0,0 @@
1-package ash.web;
2-
3-import ash.util.HashMap;
4-import ash.util.Map;
5-
6-/// Routes requests by exact path; unknown paths give 404 and handler exceptions give 500.
7-public final class Router {
8- private final Map<String, Handler> routes = new HashMap<>();
9-
10- public Router() { }
11-
12- /// Handles requests for exactly this path.
13- public void register(String path, Handler handler) {
14- routes.put(path, handler);
15- }
16-
17- /// Routes a request to its handler; 404 and 500 are produced here.
18- public Response dispatch(Request request) {
19- Handler? h = routes.get(request.path());
20- if (h == null) {
21- return new Response(404, "not found: " + request.path());
22- }
23- try {
24- return h.handle(request);
25- } catch (RuntimeException e) {
26- return new Response(500, "error: " + e.getMessage());
27- }
28- }
29-}

hearth/front/tests/scripts/check_types.shmodified

+2−0
@@ -3,6 +3,8 @@
33 # print every "// expect: <text>" line of the file.
44 set -u
55 cd "$(dirname "$0")/../.."
6+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
7+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
68 VM=../../bin/ashvm
79 dir=tests/cases/types
810 fail=0

hearth/kiln/tests/scripts/run_regression.shmodified

+2−0
@@ -5,6 +5,8 @@
55 # (front/tests/cases/run/*_j.ash; *_wrap_* need --wrap-int) and ../../examples/*.ash.
66 set -uo pipefail
77 cd "$(dirname "$0")/../.." # -> kiln/
8+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
9+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
810
911 make -s || { echo "build failed"; exit 1; }
1012 KILN=../../bin/kiln

hearth/kiln/tests/scripts/shared_link_check.shmodified

+2−0
@@ -11,6 +11,8 @@
1111 # GOT/hash/dynsym table didn't disturb kiln's own runtime imports (heap_alloc, print_top, ...).
1212 set -uo pipefail
1313 cd "$(dirname "$0")/../.." # -> kiln/
14+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
15+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
1416
1517 make -s || { echo "build failed"; exit 1; }
1618 ../../bin/kiln --emit-runtime -o /usr/local/lib/kiln/libkilnrt.so || { echo "emit-runtime failed"; exit 1; }

hearth/kiln/tests/scripts/windows_emulated_check.shmodified

+2−0
@@ -6,6 +6,8 @@
66 # Needs python3 with `unicorn` and `pefile`; a venv is created in /tmp/kiln_winemu on first use.
77 set -uo pipefail
88 cd "$(dirname "$0")/../.." # -> kiln/
9+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
10+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
911 KILN="$PWD/../../bin/kiln"
1012 SCRIPTS="$PWD/tests/scripts"
1113 VENV=/tmp/kiln_winemu

hearth/kiln/tests/scripts/windows_wine_check.shmodified

+2−0
@@ -8,6 +8,8 @@
88 # https://github.com/Kron4ek/Wine-Builds (unpack the amd64 tarball, point WINE at bin/wine).
99 set -uo pipefail
1010 cd "$(dirname "$0")/../.." # -> kiln/
11+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise
12+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"
1113 KILN="$PWD/../../bin/kiln"
1214 WINE="${WINE:-wine}"
1315 command -v "$WINE" >/dev/null 2>&1 || [ -x "$WINE" ] || { echo "wine not found (set WINE=/path/to/wine)"; exit 1; }