@yabgu_gm/tensionscript 0.11.4 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/asc.generated.d.ts +477 -3
- package/dist/asc.js +40 -1
- package/dist/asc.js.map +2 -2
- package/dist/assemblyscript.generated.d.ts +477 -3
- package/dist/assemblyscript.js +131 -131
- package/dist/assemblyscript.js.map +3 -3
- package/dist/importmap.json +2 -2
- package/dist/web.js +3 -3
- package/package.json +3 -1
- package/std/assembly/dynamicarray.ts +39 -0
package/README.md
CHANGED
|
@@ -52,7 +52,9 @@ shares, and how it stays current: [`docs/fork-posture.md`](docs/fork-posture.md)
|
|
|
52
52
|
TensionScript name), `COPY_STRUCT`, and a C-compatible `sizeof` that includes
|
|
53
53
|
trailing padding. A `layout_hash` computed against the engine catches layout
|
|
54
54
|
drift when a session opens. See [showcase §1](docs/showcase.md) and
|
|
55
|
-
§2 for `@managed struct`.
|
|
55
|
+
§2 for `@managed struct`. The external contract for the dynamic-array form —
|
|
56
|
+
`include/`, and [`docs/interop-c-abi.md`](docs/interop-c-abi.md) — is what a C
|
|
57
|
+
consumer includes; it is checked by `npm run check:headers`.
|
|
56
58
|
- **Value types.** `@inline struct` gives a record value semantics: SROA locals,
|
|
57
59
|
copy on assignment, flattened (SROA) parameters, sret returns through a hidden
|
|
58
60
|
destination parameter, an `@external` argument temp, and an export-side byval
|
package/dist/asc.generated.d.ts
CHANGED
|
@@ -1763,6 +1763,8 @@ declare module "types:tensionscript/src/common" {
|
|
|
1763
1763
|
const Object = "Object";
|
|
1764
1764
|
const Array = "Array";
|
|
1765
1765
|
const StaticArray = "StaticArray";
|
|
1766
|
+
/** The descriptor behind `@managed @dynamic [T * n]` (Landing 4d.1). */
|
|
1767
|
+
const DynamicArray = "DynamicArray";
|
|
1766
1768
|
const Set = "Set";
|
|
1767
1769
|
const Map = "Map";
|
|
1768
1770
|
const Function = "Function";
|
|
@@ -3083,6 +3085,57 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3083
3085
|
* `@unmanaged` records carry GC edges they cannot describe. Refused by name.
|
|
3084
3086
|
*/
|
|
3085
3087
|
private resolveFixedArrayType;
|
|
3088
|
+
/**
|
|
3089
|
+
* Resolves an {@link UnmanagedArrayTypeNode} to a
|
|
3090
|
+
* {@link TypeKind.UnmanagedArray}.
|
|
3091
|
+
*
|
|
3092
|
+
* Deliberately **not** a copy of {@link resolveFixedArrayType}: none of that
|
|
3093
|
+
* function's refusals belong here, and copying them would refuse the form's
|
|
3094
|
+
* whole purpose.
|
|
3095
|
+
*
|
|
3096
|
+
* A fixed array *contains* its elements, so a record element would claim `N`
|
|
3097
|
+
* records sit inline -- refused by name (`resolver.ts`, the `AS100` record
|
|
3098
|
+
* arm). An unmanaged array contains one address, so a record element is the
|
|
3099
|
+
* ordinary case: `[BodyState *]` is a pointer to a run of records, which is
|
|
3100
|
+
* exactly what the collision solver needs and what `BodyState[N]` cannot say.
|
|
3101
|
+
*
|
|
3102
|
+
* What *is* refused is an element with no bytes to point at, which is the same
|
|
3103
|
+
* `byteSize` question `sizeof` asks. An `@inline` element is admitted here on
|
|
3104
|
+
* purpose: it is a value type with a layout, and a pointer to it is a pointer
|
|
3105
|
+
* to those bytes -- the refusal that applies to it is the *field* form's, not
|
|
3106
|
+
* the pointer's.
|
|
3107
|
+
*
|
|
3108
|
+
* A **GC-managed** element is refused (see the arm below). Measured before it
|
|
3109
|
+
* existed: `[Foo *]` over a `class Foo` compiled and emitted
|
|
3110
|
+
* `base + i*4`, `i32.load`, `call Foo#get:x` -- the buffer holds bare
|
|
3111
|
+
* references that nothing scans.
|
|
3112
|
+
*/
|
|
3113
|
+
private resolveUnmanagedArrayType;
|
|
3114
|
+
/**
|
|
3115
|
+
* Resolves a {@link DynamicArrayTypeNode} to a {@link TypeKind.DynamicArray}.
|
|
3116
|
+
*
|
|
3117
|
+
* The type is **one pointer** to a `[u32 length][pad][data]` header; the length
|
|
3118
|
+
* is not in the type, which is the whole point — it is a runtime value, read
|
|
3119
|
+
* from the buffer. `n` is spelling here and a binding where a function scope
|
|
3120
|
+
* exists (see `Program#bindDynamicLengthLocals`).
|
|
3121
|
+
*
|
|
3122
|
+
* Three refusals, each for a different reason:
|
|
3123
|
+
*
|
|
3124
|
+
* - **`@managed`** is Landing 4d. The buffer would need a collector-visible
|
|
3125
|
+
* header, which this landing does not produce.
|
|
3126
|
+
*
|
|
3127
|
+
* - **No model at all** cannot be honoured by any emitter: an inline
|
|
3128
|
+
* runtime-length array would need variable stack allocation, which WASM does
|
|
3129
|
+
* not have. Naming a model is the source saying where the bytes live.
|
|
3130
|
+
*
|
|
3131
|
+
* - **A GC-managed element** is the same hazard Landing 3's CX1 closed for
|
|
3132
|
+
* `[T *]`: the buffer is not scanned, so a reference stored in it is not a
|
|
3133
|
+
* root.
|
|
3134
|
+
*
|
|
3135
|
+
* An `@inline` element is accepted: it is a value type, so its extent is
|
|
3136
|
+
* `byteSize` and Landing 3 measured that stride works.
|
|
3137
|
+
*/
|
|
3138
|
+
private resolveDynamicArrayType;
|
|
3086
3139
|
private resolveTupleType;
|
|
3087
3140
|
private resolveBuiltinNotNullableType;
|
|
3088
3141
|
/** Resolves a type name to the program element it refers to. */
|
|
@@ -3195,6 +3248,28 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3195
3248
|
private lookupPropertyAccessExpression;
|
|
3196
3249
|
/** Resolves a property access expression to its static type. */
|
|
3197
3250
|
private resolvePropertyAccessExpression;
|
|
3251
|
+
/**
|
|
3252
|
+
* The element type of an array-kind receiver, or `null` when `type` is not one.
|
|
3253
|
+
*
|
|
3254
|
+
* Three kinds answer here, and they are one family even though only two are a
|
|
3255
|
+
* `TypeKind`:
|
|
3256
|
+
*
|
|
3257
|
+
* - `[T *]` — `TypeKind.UnmanagedArray`, element on the type;
|
|
3258
|
+
* - `@unmanaged @dynamic [T * n]` — `TypeKind.DynamicArray`, element on the type;
|
|
3259
|
+
* - `@managed @dynamic [T * n]` — a **class reference** to the std
|
|
3260
|
+
* `DynamicArray<T>` descriptor (Landing 4d.1), so the element is the class's
|
|
3261
|
+
* type argument.
|
|
3262
|
+
*
|
|
3263
|
+
* The third case is why this is a helper. Landing 2 added the first arm by
|
|
3264
|
+
* hand, Landing 4b added the second by hand, and the managed form would be the
|
|
3265
|
+
* third copy of the same two-line idea — in two places, since the element is
|
|
3266
|
+
* wanted both as a *type* (`resolveElementAccessExpression`) and as an
|
|
3267
|
+
* *element* (`lookupElementAccessExpression`, which peels `y[i].field` through
|
|
3268
|
+
* the element's class). One definition, three kinds, two consumers.
|
|
3269
|
+
*/
|
|
3270
|
+
private arrayKindElementType;
|
|
3271
|
+
/** Whether `classReference` is the std `DynamicArray<T>` descriptor class. */
|
|
3272
|
+
private isManagedDynamicArrayClass;
|
|
3198
3273
|
/** Looks up the program element the specified element access expression refers to. */
|
|
3199
3274
|
private lookupElementAccessExpression;
|
|
3200
3275
|
/** Resolves an element access expression to its static type. */
|
|
@@ -3465,6 +3540,25 @@ declare module "types:tensionscript/src/parser" {
|
|
|
3465
3540
|
finish(): void;
|
|
3466
3541
|
/** Parses a type name. */
|
|
3467
3542
|
parseTypeName(tn: Tokenizer): TypeName | null;
|
|
3543
|
+
/**
|
|
3544
|
+
* Whether a `[` at the start of a type begins the unmanaged-array family
|
|
3545
|
+
* (`[T *]`, `[T * N]`) rather than a tuple.
|
|
3546
|
+
*
|
|
3547
|
+
* The discriminator is one token after the element type: `*` commits, and
|
|
3548
|
+
* anything else (`]`, `,`, `:`, `|`) belongs to the tuple arm. The lookahead
|
|
3549
|
+
* speculates with errors suppressed and rewinds either way -- the same shape
|
|
3550
|
+
* as `tryParseFunctionType` / `tryParseSignatureIsSignature`, and the reason
|
|
3551
|
+
* the tuple arm's body needs no change: it is entered with the tokenizer
|
|
3552
|
+
* exactly where its own `tn.skip(Token.CloseBracket)` expects it.
|
|
3553
|
+
*
|
|
3554
|
+
* A pre-type decorator is excluded before speculating. `parseType`'s decorator
|
|
3555
|
+
* arm reports `AS212` ("Decorator '@x' is not valid here") *before*
|
|
3556
|
+
* `suppressErrors` is consulted, so speculating into `[@unmanaged T *]` would
|
|
3557
|
+
* emit a diagnostic for a form this family does not accept anyway -- and then
|
|
3558
|
+
* emit the tuple/`Type expected` error on the rewind, giving two errors for
|
|
3559
|
+
* one mistake.
|
|
3560
|
+
*/
|
|
3561
|
+
startsUnmanagedArrayType(tn: Tokenizer): boolean;
|
|
3468
3562
|
/** Parses a type. */
|
|
3469
3563
|
parseType(tn: Tokenizer, acceptParenthesized?: boolean, suppressErrors?: boolean): TypeNode | null;
|
|
3470
3564
|
private tryParseSignatureIsSignature;
|
|
@@ -3764,6 +3858,17 @@ declare module "types:tensionscript/src/program" {
|
|
|
3764
3858
|
/** Gets the standard `StaticArray` prototype. */
|
|
3765
3859
|
get staticArrayPrototype(): ClassPrototype;
|
|
3766
3860
|
private _staticArrayPrototype;
|
|
3861
|
+
/**
|
|
3862
|
+
* Gets the `DynamicArray` prototype — the descriptor class behind
|
|
3863
|
+
* `@managed @dynamic [T * n]`.
|
|
3864
|
+
*
|
|
3865
|
+
* Follows `staticArrayPrototype` exactly: a lazily-cached `require` of the
|
|
3866
|
+
* std prototype, so `@managed @dynamic [T * n]` can resolve through
|
|
3867
|
+
* `resolveClass(program.dynamicArrayPrototype, [elementType])` and come back
|
|
3868
|
+
* as an ordinary generic class instance.
|
|
3869
|
+
*/
|
|
3870
|
+
get dynamicArrayPrototype(): ClassPrototype;
|
|
3871
|
+
private _dynamicArrayPrototype;
|
|
3767
3872
|
/** Gets the standard `Set` prototype. */
|
|
3768
3873
|
get setPrototype(): ClassPrototype;
|
|
3769
3874
|
private _setPrototype;
|
|
@@ -4430,6 +4535,15 @@ declare module "types:tensionscript/src/program" {
|
|
|
4430
4535
|
* is what gives it one `i32` slot instead of the record's reference type.
|
|
4431
4536
|
*/
|
|
4432
4537
|
isViewLocal: boolean;
|
|
4538
|
+
/**
|
|
4539
|
+
* Whether this local is a **dynamic-array length binding** — the `n` in
|
|
4540
|
+
* `[T * n]`, introduced by the signature rather than written as a declaration.
|
|
4541
|
+
*
|
|
4542
|
+
* It is read-only by construction: its value comes from the buffer header at
|
|
4543
|
+
* function entry, so assigning it would make the compiler's idea of the length
|
|
4544
|
+
* disagree with the buffer's. The assignment and shadowing rules key on this.
|
|
4545
|
+
*/
|
|
4546
|
+
isDynamicLength: boolean;
|
|
4433
4547
|
/** Constructs a new local variable. */
|
|
4434
4548
|
constructor(
|
|
4435
4549
|
/** Simple name. */
|
|
@@ -4886,7 +5000,37 @@ declare module "types:tensionscript/src/types" {
|
|
|
4886
5000
|
/** String iterator. */
|
|
4887
5001
|
StringviewIter = 25,
|
|
4888
5002
|
/** No return type. */
|
|
4889
|
-
Void = 26
|
|
5003
|
+
Void = 26,
|
|
5004
|
+
/**
|
|
5005
|
+
* A pointer to `T` with unknown length, `[T *]`.
|
|
5006
|
+
*
|
|
5007
|
+
* **Appended at the end**, not beside {@link FixedArray}, on purpose. This is
|
|
5008
|
+
* a `const enum` with implicit numbering, so an insert would renumber the
|
|
5009
|
+
* twelve kinds between `FixedArray` and `Void`; the compiler is self-hosted, so
|
|
5010
|
+
* a partial rebuild could then disagree with `dist/` about what
|
|
5011
|
+
* `TypeKind.Extern` means -- silently. The order here carries no meaning.
|
|
5012
|
+
*
|
|
5013
|
+
* One slot holding an address: not a value (no extent to inline), not a
|
|
5014
|
+
* reference (the collector owns nothing). `toRef` answers the pointer type,
|
|
5015
|
+
* which is what lets a `[T *]` parameter, local, global and return bind as one
|
|
5016
|
+
* slot where `T[N]` reaches `Type#toRef`'s `assert(false)`.
|
|
5017
|
+
*/
|
|
5018
|
+
UnmanagedArray = 27,
|
|
5019
|
+
/**
|
|
5020
|
+
* `@unmanaged @dynamic [T * n]` — a header-prefixed array whose length is a
|
|
5021
|
+
* runtime value.
|
|
5022
|
+
*
|
|
5023
|
+
* Appended for the same reason {@link UnmanagedArray} was: an insert would
|
|
5024
|
+
* renumber every kind after it, and the compiler is self-hosted.
|
|
5025
|
+
*
|
|
5026
|
+
* A separate kind rather than a flag on `UnmanagedArray` because the two have
|
|
5027
|
+
* different layouts — one addresses bare elements, the other a
|
|
5028
|
+
* `[u32 length][pad][data]` header — and every element access has to know
|
|
5029
|
+
* which it is looking at. The storage *model* is a field
|
|
5030
|
+
* ({@link dynamicMemoryModel}), not a kind, so `@managed @dynamic` (Landing 4d)
|
|
5031
|
+
* is the same kind under a different owner.
|
|
5032
|
+
*/
|
|
5033
|
+
DynamicArray = 28
|
|
4890
5034
|
}
|
|
4891
5035
|
/** Indicates capabilities of a type. */
|
|
4892
5036
|
export const enum TypeFlags {
|
|
@@ -4936,6 +5080,28 @@ declare module "types:tensionscript/src/types" {
|
|
|
4936
5080
|
fixedElementType: Type | null;
|
|
4937
5081
|
/** Element count of a {@link TypeKind.FixedArray}, else `0`. */
|
|
4938
5082
|
fixedLength: number;
|
|
5083
|
+
/**
|
|
5084
|
+
* Element type of a {@link TypeKind.UnmanagedArray}, else `null`.
|
|
5085
|
+
*
|
|
5086
|
+
* Kept apart from {@link fixedElementType} rather than shared. The two kinds
|
|
5087
|
+
* say different things -- an extent versus an address -- and a shared field
|
|
5088
|
+
* would force every `kind == FixedArray` test in the compiler to become a
|
|
5089
|
+
* three-way test, with the risk that one of them silently starts treating an
|
|
5090
|
+
* address as an extent. `size` differs for the same reason: this kind's size is
|
|
5091
|
+
* the pointer's, not the element's replicated.
|
|
5092
|
+
*/
|
|
5093
|
+
unmanagedElementType: Type | null;
|
|
5094
|
+
/** Element type of a {@link TypeKind.DynamicArray}, else `null`. */
|
|
5095
|
+
dynamicArrayElementType: Type | null;
|
|
5096
|
+
/**
|
|
5097
|
+
* Who owns a {@link TypeKind.DynamicArray}'s buffer.
|
|
5098
|
+
*
|
|
5099
|
+
* {@link MemoryModelCode.Unmanaged} for a C-compatible header-prefixed buffer;
|
|
5100
|
+
* {@link MemoryModelCode.Managed} is Landing 4d. Part of {@link equals}, so the
|
|
5101
|
+
* two cannot be confused for one another even though they share a kind and a
|
|
5102
|
+
* layout.
|
|
5103
|
+
*/
|
|
5104
|
+
dynamicMemoryModel: MemoryModelCode;
|
|
4939
5105
|
/**
|
|
4940
5106
|
* Alignment (log2) of a {@link TypeKind.FixedArray}: its element's.
|
|
4941
5107
|
*
|
|
@@ -4959,7 +5125,15 @@ declare module "types:tensionscript/src/types" {
|
|
|
4959
5125
|
get exceptVoid(): Type;
|
|
4960
5126
|
/** Size in bytes. */
|
|
4961
5127
|
get byteSize(): number;
|
|
4962
|
-
/**
|
|
5128
|
+
/**
|
|
5129
|
+
* Gets this type's logarithmic alignment in memory.
|
|
5130
|
+
*
|
|
5131
|
+
* An `UnmanagedArray` deliberately does **not** take the {@link fixedAlignLog2}
|
|
5132
|
+
* branch. It is one pointer, so its alignment is the pointer's -- which is what
|
|
5133
|
+
* the `byteSize` fallback already yields, since this kind's `size` is the
|
|
5134
|
+
* pointer's and not the element's replicated. There is no element alignment to
|
|
5135
|
+
* borrow here; the element is not stored in this type.
|
|
5136
|
+
*/
|
|
4963
5137
|
get alignLog2(): number;
|
|
4964
5138
|
/** Tests if this type represents a basic value. */
|
|
4965
5139
|
get isValue(): boolean;
|
|
@@ -5099,6 +5273,55 @@ declare module "types:tensionscript/src/types" {
|
|
|
5099
5273
|
static fixedArray(elementType: Type, length: number): Type;
|
|
5100
5274
|
/** Gets the element type of a {@link TypeKind.FixedArray}. */
|
|
5101
5275
|
get fixedArrayElementType(): Type;
|
|
5276
|
+
/** Interned unmanaged-array types, keyed by element type and pointer width. */
|
|
5277
|
+
private static _unmanagedArrays;
|
|
5278
|
+
/**
|
|
5279
|
+
* Gets the {@link TypeKind.UnmanagedArray} of `elementType`: a pointer to a run
|
|
5280
|
+
* of `elementType`, with no length.
|
|
5281
|
+
*
|
|
5282
|
+
* `pointerSize` is `options.usizeType.size` -- 32 or 64 bits. It is a
|
|
5283
|
+
* parameter rather than a constant because a `Type` carries its own size, and
|
|
5284
|
+
* `size` here must be the **pointer's**, not the element's: there is no extent
|
|
5285
|
+
* to measure. It is part of the cache key for the same reason -- `equals`
|
|
5286
|
+
* compares element types only, so two types differing solely in pointer width
|
|
5287
|
+
* must not be the same object.
|
|
5288
|
+
*
|
|
5289
|
+
* Unlike {@link Type.fixedArray} this consults nothing about the element but
|
|
5290
|
+
* its identity: the count is unknown, which is the entire point of the kind.
|
|
5291
|
+
*
|
|
5292
|
+
* The cache is validated by **identity** of the element, not just by the key.
|
|
5293
|
+
* This is what keeps interning a per-program property rather than a
|
|
5294
|
+
* per-process one: the map is a static that outlives a `Program`, so a second
|
|
5295
|
+
* `asc.main` in the same process (which is exactly what the compiler test
|
|
5296
|
+
* harness does -- debug then release) would otherwise be handed the first
|
|
5297
|
+
* program's `Type`, whose `unmanagedElementType` carries the first program's
|
|
5298
|
+
* `Class`. A property read through that class then emitted a call to a getter
|
|
5299
|
+
* the new module never compiled, and the module failed to validate:
|
|
5300
|
+
* `wasm-validator error ... call target must exist`.
|
|
5301
|
+
*
|
|
5302
|
+
* So a cached entry is returned only when its element is the *same object* the
|
|
5303
|
+
* current program just resolved. Within one program that is always true --
|
|
5304
|
+
* `resolveType` interns a record's `Type` -- so interning still holds there.
|
|
5305
|
+
*/
|
|
5306
|
+
static unmanagedArray(elementType: Type, pointerSize: number): Type;
|
|
5307
|
+
/** Gets the element type of a {@link TypeKind.UnmanagedArray}. */
|
|
5308
|
+
get unmanagedArrayElementType(): Type;
|
|
5309
|
+
/** Interned dynamic-array types, keyed by model, element and pointer width. */
|
|
5310
|
+
private static _dynamicArrays;
|
|
5311
|
+
/**
|
|
5312
|
+
* Gets the {@link TypeKind.DynamicArray} of `elementType`.
|
|
5313
|
+
*
|
|
5314
|
+
* The key carries the **model** as well as the element, because `equals`
|
|
5315
|
+
* compares both: two models over one element are different types, and
|
|
5316
|
+
* interning them together would make them the same object.
|
|
5317
|
+
*
|
|
5318
|
+
* Like {@link Type.unmanagedArray} the entry is validated by element identity
|
|
5319
|
+
* on the way out — the map outlives a `Program`, so a second compile in one
|
|
5320
|
+
* process must not be handed the first one's element `Class`.
|
|
5321
|
+
*/
|
|
5322
|
+
static dynamicArray(elementType: Type, memoryModel: MemoryModelCode, pointerSize: number): Type;
|
|
5323
|
+
/** Gets the element type of a {@link TypeKind.DynamicArray}. */
|
|
5324
|
+
get dynamicElementType(): Type;
|
|
5102
5325
|
static readonly f64: Type;
|
|
5103
5326
|
/** A 128-bit vector. */
|
|
5104
5327
|
static readonly v128: Type;
|
|
@@ -7778,7 +8001,26 @@ declare module "types:tensionscript/src/ast" {
|
|
|
7778
8001
|
ExportMember = 67,
|
|
7779
8002
|
SwitchCase = 68,
|
|
7780
8003
|
IndexSignature = 69,
|
|
7781
|
-
Comment = 70
|
|
8004
|
+
Comment = 70,
|
|
8005
|
+
/**
|
|
8006
|
+
* `[T *]` — a pointer to T with unknown length.
|
|
8007
|
+
*
|
|
8008
|
+
* Appended at the end rather than beside {@link FixedArrayType}. `NodeKind`
|
|
8009
|
+
* is a `const enum` with implicit numbering, so an insert would renumber every
|
|
8010
|
+
* node kind after it; the compiler is self-hosted, so a partial rebuild could
|
|
8011
|
+
* then disagree with `dist/` about what `NodeKind.Comment` means -- silently.
|
|
8012
|
+
* The position carries no meaning.
|
|
8013
|
+
*/
|
|
8014
|
+
UnmanagedArrayType = 71,
|
|
8015
|
+
/**
|
|
8016
|
+
* `@unmanaged @dynamic [T * n]` — a header-prefixed array whose length is a
|
|
8017
|
+
* runtime value read from the buffer.
|
|
8018
|
+
*
|
|
8019
|
+
* Appended for the same reason {@link UnmanagedArrayType} was: this is an
|
|
8020
|
+
* implicit-numbering `const enum`, so an insert would renumber every node kind
|
|
8021
|
+
* after it.
|
|
8022
|
+
*/
|
|
8023
|
+
DynamicArrayType = 72
|
|
7782
8024
|
}
|
|
7783
8025
|
/** Base class of all nodes. */
|
|
7784
8026
|
export abstract class Node {
|
|
@@ -7796,6 +8038,8 @@ declare module "types:tensionscript/src/ast" {
|
|
|
7796
8038
|
static createFunctionType(parameters: ParameterNode[], returnType: TypeNode, explicitThisType: NamedTypeNode | null, isNullable: boolean, range: Range): FunctionTypeNode;
|
|
7797
8039
|
static createTupleType(elements: TypeNode[], elementNames: (IdentifierExpression | null)[] | null, isNullable: boolean, range: Range): TupleTypeNode;
|
|
7798
8040
|
static createFixedArrayType(elementType: TypeNode, length: number, range: Range): FixedArrayTypeNode;
|
|
8041
|
+
static createUnmanagedArrayType(elementType: TypeNode, range: Range): UnmanagedArrayTypeNode;
|
|
8042
|
+
static createDynamicArrayType(elementType: TypeNode, lengthName: IdentifierExpression, memoryModel: MemoryModel, range: Range): DynamicArrayTypeNode;
|
|
7799
8043
|
static createOmittedType(range: Range): NamedTypeNode;
|
|
7800
8044
|
static createTypeParameter(name: IdentifierExpression, extendsType: NamedTypeNode | null, defaultType: NamedTypeNode | null, range: Range): TypeParameterNode;
|
|
7801
8045
|
static createParameter(parameterKind: ParameterKind, name: IdentifierExpression, type: TypeNode, initializer: Expression | null, range: Range): ParameterNode;
|
|
@@ -8035,6 +8279,56 @@ declare module "types:tensionscript/src/ast" {
|
|
|
8035
8279
|
/** Source range. */
|
|
8036
8280
|
range: Range);
|
|
8037
8281
|
}
|
|
8282
|
+
/**
|
|
8283
|
+
* Represents an unmanaged array type, `[T *]` — a pointer to `T` with no length.
|
|
8284
|
+
*
|
|
8285
|
+
* The difference from {@link FixedArrayTypeNode} is the missing `length`, and it
|
|
8286
|
+
* is the whole difference: a fixed array *contains* its elements, so it has an
|
|
8287
|
+
* extent the layout can size; this one *addresses* them, so its own size is the
|
|
8288
|
+
* pointer's. That is why `[T *]` binds as one `i32` slot where `T[N]` has no
|
|
8289
|
+
* reference representation at all (`Type#toRef` asserts on a fixed array).
|
|
8290
|
+
*
|
|
8291
|
+
* Not a reference: the collector owns nothing here, the address is the caller's.
|
|
8292
|
+
* Not a value either: there is nothing to inline. `changetype` and a parameter
|
|
8293
|
+
* are the two ways one comes into being.
|
|
8294
|
+
*/
|
|
8295
|
+
export class UnmanagedArrayTypeNode extends TypeNode {
|
|
8296
|
+
/** Element type. */
|
|
8297
|
+
elementType: TypeNode;
|
|
8298
|
+
constructor(
|
|
8299
|
+
/** Element type. */
|
|
8300
|
+
elementType: TypeNode,
|
|
8301
|
+
/** Source range. */
|
|
8302
|
+
range: Range);
|
|
8303
|
+
}
|
|
8304
|
+
/**
|
|
8305
|
+
* Represents a dynamic array type, `@unmanaged @dynamic [T * n]`.
|
|
8306
|
+
*
|
|
8307
|
+
* The `n` is **spelling, not an expression**: the parser cannot evaluate it (it
|
|
8308
|
+
* has no symbol table), so it is carried as a name and the length is read at
|
|
8309
|
+
* runtime from the buffer header. That is why the form is admissible at parse
|
|
8310
|
+
* time without knowing whether `n` is a constant — resolution decides that, and
|
|
8311
|
+
* `resolveDynamicArrayType` refuses a name that turns out to be compile-time.
|
|
8312
|
+
*
|
|
8313
|
+
* One i32 slot at the ABI, holding a pointer to `[u32 length][pad][T data[n]]`.
|
|
8314
|
+
*/
|
|
8315
|
+
export class DynamicArrayTypeNode extends TypeNode {
|
|
8316
|
+
/** Element type. */
|
|
8317
|
+
elementType: TypeNode;
|
|
8318
|
+
/** The length's name. Bound as a read-only local where a function scope exists. */
|
|
8319
|
+
lengthName: IdentifierExpression;
|
|
8320
|
+
/** Storage model of the buffer. `Unmanaged` for now; `Managed` is Landing 4d. */
|
|
8321
|
+
dynamicMemoryModel: MemoryModel;
|
|
8322
|
+
constructor(
|
|
8323
|
+
/** Element type. */
|
|
8324
|
+
elementType: TypeNode,
|
|
8325
|
+
/** The length's name. Bound as a read-only local where a function scope exists. */
|
|
8326
|
+
lengthName: IdentifierExpression,
|
|
8327
|
+
/** Storage model of the buffer. `Unmanaged` for now; `Managed` is Landing 4d. */
|
|
8328
|
+
dynamicMemoryModel: MemoryModel,
|
|
8329
|
+
/** Source range. */
|
|
8330
|
+
range: Range);
|
|
8331
|
+
}
|
|
8038
8332
|
/** Represents a type parameter. */
|
|
8039
8333
|
export class TypeParameterNode extends Node {
|
|
8040
8334
|
/** Identifier reference. */
|
|
@@ -10387,6 +10681,15 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
10387
10681
|
indexExpression: Expression | null,
|
|
10388
10682
|
/** Whether to tee the value. */
|
|
10389
10683
|
tee: boolean): ExpressionRef;
|
|
10684
|
+
/**
|
|
10685
|
+
* The {@link DynamicArrayTypeNode} a declaration names, if it names one.
|
|
10686
|
+
*
|
|
10687
|
+
* Two spellings carry the length's name: the annotation (`const y: [T * n]`)
|
|
10688
|
+
* and `changetype`'s type argument (`const y = changetype<[T * n]>(p)`). Both
|
|
10689
|
+
* are read here so the local-position binding does not depend on which one the
|
|
10690
|
+
* source chose.
|
|
10691
|
+
*/
|
|
10692
|
+
private dynamicArrayTypeNodeOf;
|
|
10390
10693
|
/** Makes an assignment to a local, keeping track of wrap and null states. */
|
|
10391
10694
|
private makeLocalAssignment;
|
|
10392
10695
|
/** Makes an assignment to a global. */
|
|
@@ -10459,6 +10762,177 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
10459
10762
|
/** Creates an indirect call to a first-class function. */
|
|
10460
10763
|
makeCallIndirect(signature: Signature, functionArg: ExpressionRef, reportNode: Node, operands?: ExpressionRef[] | null, immediatelyDropped?: boolean): ExpressionRef;
|
|
10461
10764
|
private compileCommaExpression;
|
|
10765
|
+
/**
|
|
10766
|
+
* The byte extent of one element of a `[T *]` — the stride `y[i]` walks by.
|
|
10767
|
+
*
|
|
10768
|
+
* For a scalar this is `Type.byteSize`. For a record it is **not**: an
|
|
10769
|
+
* `@unmanaged`/`@managed` record's `Type` is reference-like, so its `byteSize`
|
|
10770
|
+
* is the 4-byte address, and the extent lives on the `Class` that laid the
|
|
10771
|
+
* fields out. `builtin_sizeof` already answers this way for the same reason
|
|
10772
|
+
* (`builtins.ts`, the `Unmanaged | ManagedStruct` branch answers
|
|
10773
|
+
* `nextMemoryOffset`), so the two cannot disagree about how big a record is.
|
|
10774
|
+
*
|
|
10775
|
+
* An `@inline struct` needs no arm: it *is* a value type, so its
|
|
10776
|
+
* `byteSize` is already the extent. Measured — `[Inl *]` over
|
|
10777
|
+
* `@inline struct Inl { x: f64; y: f64 }` strides 16, which is
|
|
10778
|
+
* `sizeof<Inl>()`.
|
|
10779
|
+
*
|
|
10780
|
+
* Measured, and the reason this helper exists: using `byteSize` directly gave
|
|
10781
|
+
* a stride of 4 for a two-`f64` record of 16 bytes — the same "alignment or
|
|
10782
|
+
* reference size instead of the extent" mistake the fixed-array arm avoids
|
|
10783
|
+
* only because it refuses records outright.
|
|
10784
|
+
*/
|
|
10785
|
+
private unmanagedArrayElementSize;
|
|
10786
|
+
/**
|
|
10787
|
+
* Whether `type` is a record whose elements live **at** the address rather
|
|
10788
|
+
* than being a value loaded from it: `@unmanaged`, `@managed` or `@inline`.
|
|
10789
|
+
*
|
|
10790
|
+
* This is the discriminator between "the address is the element" and "load the
|
|
10791
|
+
* element from the address", and it is deliberately about the *element kind*
|
|
10792
|
+
* rather than about type equality — see {@link compileUnmanagedArrayElementAccess}.
|
|
10793
|
+
*/
|
|
10794
|
+
private isRecordValueType;
|
|
10795
|
+
/**
|
|
10796
|
+
* The header an `@unmanaged @dynamic [T * n]` buffer carries in front of its
|
|
10797
|
+
* elements: `align_up(4, alignof(T))`.
|
|
10798
|
+
*
|
|
10799
|
+
* Four bytes hold the `u32` length; anything needing stronger alignment than
|
|
10800
|
+
* that gets padding after it. So `u32` elements sit at `ptr + 4`, and a
|
|
10801
|
+
* two-`f64` record sits at `ptr + 8`.
|
|
10802
|
+
*
|
|
10803
|
+
* Reported in Landing 4a: **no header-size helper existed**, because nothing
|
|
10804
|
+
* in 4a needed one — `.length` reads offset 0, and 4a's own V5 recorded that
|
|
10805
|
+
* the constant could not be observed from outside. This is its first
|
|
10806
|
+
* definition; `.length` and the element address both go through it so they
|
|
10807
|
+
* cannot drift.
|
|
10808
|
+
*
|
|
10809
|
+
* A record's alignment is `Class#alignLog2` rather than `Type#alignLog2` for
|
|
10810
|
+
* the same reason its size is `nextMemoryOffset`: a record's `Type` is
|
|
10811
|
+
* reference-like and would report the 4-byte pointer's alignment for every
|
|
10812
|
+
* record, including the `f64`-only ones that are aligned 8.
|
|
10813
|
+
*/
|
|
10814
|
+
/**
|
|
10815
|
+
* Whether `type` is the **managed** dynamic-array descriptor — the std
|
|
10816
|
+
* `DynamicArray<T>` class that `@managed @dynamic [T * n]` resolves to
|
|
10817
|
+
* (Landing 4d.1).
|
|
10818
|
+
*
|
|
10819
|
+
* Answered by class identity rather than by a memory-model field, because the
|
|
10820
|
+
* managed form is a class reference now: its `Type` is the class instance's
|
|
10821
|
+
* type, and the "model" is implicit in `isManaged`. That is the whole point of
|
|
10822
|
+
* the redesign — `TypeKind.DynamicArray` carries `TypeFlags.None` and is not
|
|
10823
|
+
* traced, so a descriptor stored as one would not be rooted.
|
|
10824
|
+
*/
|
|
10825
|
+
/**
|
|
10826
|
+
* The element type of either dynamic-array form.
|
|
10827
|
+
*
|
|
10828
|
+
* `@unmanaged @dynamic [T * n]` carries the element on its type;
|
|
10829
|
+
* `@managed @dynamic [T * n]` is a `DynamicArray<T>` class reference, so the
|
|
10830
|
+
* element is the class's type argument. One accessor for both, because every
|
|
10831
|
+
* consumer below — access, compound, increment — would otherwise branch.
|
|
10832
|
+
*/
|
|
10833
|
+
private dynamicArrayElementOf;
|
|
10834
|
+
private isManagedDynamicArrayType;
|
|
10835
|
+
private dynamicArrayHeaderSize;
|
|
10836
|
+
/**
|
|
10837
|
+
* Compiles the byte address of `y[i]` for a dynamic array:
|
|
10838
|
+
* `ptr + headerSize + i*sizeof(T)`.
|
|
10839
|
+
*
|
|
10840
|
+
* Shared by the read and the write arm, so the two cannot disagree about which
|
|
10841
|
+
* bytes they address — the same split the fixed and unmanaged arms use.
|
|
10842
|
+
*
|
|
10843
|
+
* Two constants, each of which was a bug somewhere else in this family:
|
|
10844
|
+
*
|
|
10845
|
+
* - **`headerSize` is present.** It is what separates a dynamic array from a
|
|
10846
|
+
* `[T *]`: the data starts after the length word and its padding.
|
|
10847
|
+
* - **The stride is a multiply by the element's extent**, not a shift by its
|
|
10848
|
+
* alignment. For a two-`f64` record those differ (16 vs 8), which is Landing
|
|
10849
|
+
* 2's lesson and the reason `unmanagedArrayElementSize` exists.
|
|
10850
|
+
*/
|
|
10851
|
+
private compileDynamicArrayElementAddress;
|
|
10852
|
+
/**
|
|
10853
|
+
* The bounds check an `@unmanaged @dynamic [T * n]` access performs before it
|
|
10854
|
+
* touches memory: `if ((u32)index >= (u32)length) trap`.
|
|
10855
|
+
*
|
|
10856
|
+
* **Unsigned** on purpose. A negative index is a huge `u32`, so it fails the
|
|
10857
|
+
* same comparison as any other out-of-range value — one check covers both ends
|
|
10858
|
+
* without a second comparison, and `y[-1]` cannot walk backwards out of the
|
|
10859
|
+
* buffer.
|
|
10860
|
+
*
|
|
10861
|
+
* The length comes from the header directly rather than from the `n` binding.
|
|
10862
|
+
* `n` is a snapshot taken at entry (D5 of 4a); the header is what the buffer
|
|
10863
|
+
* currently says, and a bounds check is about the memory that exists now.
|
|
10864
|
+
*
|
|
10865
|
+
* The message is a literal: `makeAbort` takes a string expression, and nothing
|
|
10866
|
+
* in this compiler formats an index and a length into one (measured — 4a's
|
|
10867
|
+
* `changetype` trap is the same shape). Naming the two causes would mean
|
|
10868
|
+
* building a string at every check.
|
|
10869
|
+
*/
|
|
10870
|
+
private compileDynamicArrayBoundsCheck;
|
|
10871
|
+
/**
|
|
10872
|
+
* Compiles the byte address of `y[i]` for an unmanaged array: `base + i*sizeof(T)`.
|
|
10873
|
+
*
|
|
10874
|
+
* Shared by the read and the write arm, so the two cannot disagree about which
|
|
10875
|
+
* bytes they address — the same reason `compileFixedArrayElementAccess` and
|
|
10876
|
+
* `compileFixedArrayElementAddress` are split.
|
|
10877
|
+
*
|
|
10878
|
+
* The stride is a **multiply**, not the fixed-array arm's `1 << alignof(T)`.
|
|
10879
|
+
* That shift is right only for the elements the fixed arm admits (records are
|
|
10880
|
+
* refused there, so every element is a scalar, where size and alignment
|
|
10881
|
+
* coincide). A record element is the ordinary case here, and for a record the
|
|
10882
|
+
* two disagree: two `f64`s give `sizeof` 16 and `alignof` 8.
|
|
10883
|
+
*/
|
|
10884
|
+
private compileUnmanagedArrayElementAddress;
|
|
10885
|
+
/**
|
|
10886
|
+
* Compiles `y[i]` for an unmanaged array, `[T *]` — both directions.
|
|
10887
|
+
*
|
|
10888
|
+
* Two things separate this from {@link compileFixedArrayElementAccess}:
|
|
10889
|
+
*
|
|
10890
|
+
* - **The stride is a multiply** (see the address helper).
|
|
10891
|
+
*
|
|
10892
|
+
* - **A record element compiles to an address, not a load.** A record's
|
|
10893
|
+
* `toRef` is the 4-byte reference, so loading there would read the record's
|
|
10894
|
+
* first four bytes and call them a pointer. So the address is yielded typed
|
|
10895
|
+
* as the element, and `.field` on it resolves through the record's own
|
|
10896
|
+
* accessor — a load or a store at `addr + offsetof`. **That is also how a
|
|
10897
|
+
* field write works**: `y[i].x = v` reaches the property setter, whose
|
|
10898
|
+
* `this` is this address. No separate arm.
|
|
10899
|
+
*
|
|
10900
|
+
* Reads are unchecked. `*` says the length is unknown, so there is nothing to
|
|
10901
|
+
* check against; `@dynamic` is where a checked form lives.
|
|
10902
|
+
*
|
|
10903
|
+
* A whole-record **write** is refused, keyed on the element being a record.
|
|
10904
|
+
* The key is the element kind, not "both sides have the same type": a scalar
|
|
10905
|
+
* element assignment (`a[i] = 5` over `[u32 *]`) is an ordinary store and must
|
|
10906
|
+
* keep compiling. Refusing by type equality would have caught that case too,
|
|
10907
|
+
* which is the trap this comment exists to keep shut.
|
|
10908
|
+
*/
|
|
10909
|
+
private compileUnmanagedArrayElementAccess;
|
|
10910
|
+
/**
|
|
10911
|
+
* Compiles `y[i]` for an `@unmanaged @dynamic [T * n]` — both directions.
|
|
10912
|
+
*
|
|
10913
|
+
* Differs from {@link compileUnmanagedArrayElementAccess} in exactly one place,
|
|
10914
|
+
* and it is the whole point of the kind: **the bounds check**. A `[T *]` has no
|
|
10915
|
+
* length to check against, so its access is unchecked by contract; a dynamic
|
|
10916
|
+
* array carries one in its header, and an index outside it is a diagnostic
|
|
10917
|
+
* rather than whatever memory happens to follow.
|
|
10918
|
+
*
|
|
10919
|
+
* Everything else is the unmanaged arm's shape, deliberately:
|
|
10920
|
+
*
|
|
10921
|
+
* - a **record element** compiles to the address, typed as the element, so
|
|
10922
|
+
* `.field` reads and writes go through the record's own accessor — which is
|
|
10923
|
+
* also how `y[i].field = v` works, with no arm of its own;
|
|
10924
|
+
* - a **scalar element** is loaded or stored at its own width;
|
|
10925
|
+
* - a whole-record **write** is refused, keyed on the element being a record
|
|
10926
|
+
* rather than on type equality, so `a[i] = 5` over `[u32 * n]` still
|
|
10927
|
+
* compiles.
|
|
10928
|
+
*
|
|
10929
|
+
* Compound assignment and increment call this **twice** — once by way of the
|
|
10930
|
+
* read the operator performs, once for the store — so the check is emitted
|
|
10931
|
+
* twice. That is the smaller of the two correct shapes: sharing one check
|
|
10932
|
+
* would mean threading the checked address through the operator's own codegen,
|
|
10933
|
+
* which does not know this arm exists.
|
|
10934
|
+
*/
|
|
10935
|
+
private compileDynamicArrayElementAccess;
|
|
10462
10936
|
/**
|
|
10463
10937
|
* Compiles `array[index]` for a `T[N]` inline array: read and write.
|
|
10464
10938
|
*
|