← 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
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** (s396397
397398
### Phase 5 — Standard library398399
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-int4646
```4747
48
+The standard library is not built into the compiler. The compiler only contains the types it cannot work49
+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 live51
+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 set53
+`ASH_PATH=/path/to/ash-stdlib/src/main/ash`. Without it, programs that only use `ash.lang` still work and54
+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 VM5058
versus a native code generator. Source written in the removed pre-migration scripting syntax5159
(`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 in56
-`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-Ash58
-models because the VM has no threads, sockets, windows or clock). Known limits of the current backend are63
+and `hearth/kiln/tests/scripts/run_regression.sh` run them on both engines. The standard library is the64
+`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-Ash66
+models because the VM has no threads, sockets, windows or clock); the test scripts expect it as a sibling67
+checkout (`../ash-stdlib`) or via `ASH_PATH`. Known limits of the current backend are5968
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 GitHubhearth/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 pipefail88
cd "$(dirname "$0")/../.." # -> ashvm/9
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise10
+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"911
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT1012
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 pipefail77
cd "$(dirname "$0")/../.." # -> ashvm/8
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise9
+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"810
911
make -s || { echo "build failed"; exit 1; }1012
VM=../../bin/ashvmhearth/front/Makefilemodified
+4−1@@ -1,6 +1,6 @@11
CC = gcc22
.DEFAULT_GOAL := all3
-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 IR66
# 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 ship5
+ * 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−0Show 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 ship5
+ * 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−0No content changes. View the file on GitHub
hearth/front/src/jcore/H/jcore.hadded
+23−0@@ -0,0 +1,23 @@1
+#ifndef JCORE_H2
+#define JCORE_H3
+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 parsed6
+ * lazily, only when a program reaches them; nothing is read from disk. Everything else in the7
+ * standard library (ash.util, ash.io, ash.json, ...) is the optional ash-stdlib package found8
+ * 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
+#endifhearth/front/src/jcore/O/.gitkeepadded
+0−0No 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_DIR11
-#define ASH_STDLIB_DIR "stdlib"12
-#endif13
-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 a34
+ * 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; (vo124137
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 to6
-/// 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 the6
-/// 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 an4
-/// 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 -u55
cd "$(dirname "$0")/../.."6
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise7
+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"68
VM=../../bin/ashvm79
dir=tests/cases/types810
fail=0hearth/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 pipefail77
cd "$(dirname "$0")/../.." # -> kiln/8
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise9
+export ASH_PATH="${ASH_PATH:-$PWD/../../../ash-stdlib/src/main/ash}"810
911
make -s || { echo "build failed"; exit 1; }1012
KILN=../../bin/kilnhearth/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 pipefail1313
cd "$(dirname "$0")/../.." # -> kiln/14
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise15
+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 pipefail88
cd "$(dirname "$0")/../.." # -> kiln/9
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise10
+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_winemuhearth/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 pipefail1010
cd "$(dirname "$0")/../.." # -> kiln/11
+# the optional standard library (ash-stdlib) is a sibling checkout unless ASH_PATH says otherwise12
+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; }