kopscript 0.11.1 → 0.13.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/LLM.md +63 -34
- package/README.md +55 -31
- package/dist/checker.js +325 -161
- package/dist/codegen.js +1 -1
- package/dist/parser.js +51 -24
- package/dist/printer.js +8 -5
- package/dist/types.js +29 -24
- package/package.json +1 -1
package/LLM.md
CHANGED
|
@@ -133,8 +133,8 @@ Dog d = new Dog("Rex");
|
|
|
133
133
|
the interface in the base list and provide matching public methods, checked at compile time.
|
|
134
134
|
- No nested classes/functions.
|
|
135
135
|
- No multiple inheritance (at most one class in the base list; the rest must be interfaces).
|
|
136
|
-
- `class Box<T> { ... }`
|
|
137
|
-
full (deliberately scoped-down) rules.
|
|
136
|
+
- `class Box<T> { ... }` / `class Pair<K, V> { ... }` — one or more type parameters are
|
|
137
|
+
allowed; see Generics below for the full (deliberately scoped-down) rules.
|
|
138
138
|
|
|
139
139
|
### Interfaces
|
|
140
140
|
|
|
@@ -145,7 +145,7 @@ interface IShape {
|
|
|
145
145
|
interface INamedShape : IShape { // interfaces can extend other interfaces (not classes)
|
|
146
146
|
string GetName();
|
|
147
147
|
}
|
|
148
|
-
interface IContainer<T> { // interfaces take
|
|
148
|
+
interface IContainer<T> { // interfaces take type parameters too — see Generics
|
|
149
149
|
T Get();
|
|
150
150
|
}
|
|
151
151
|
```
|
|
@@ -281,7 +281,7 @@ Not a use of user-declared generics (see below) — `state<T>` is one of exactly
|
|
|
281
281
|
hardcoded parametrized forms in the type system (the other is `task<T>`), each with only
|
|
282
282
|
ever one built-in meaning, unlike a real generic class/interface.
|
|
283
283
|
|
|
284
|
-
## Generics —
|
|
284
|
+
## Generics — one or more type parameters on classes/interfaces
|
|
285
285
|
|
|
286
286
|
```ks
|
|
287
287
|
class Box<T> {
|
|
@@ -293,38 +293,64 @@ class Box<T> {
|
|
|
293
293
|
Box<number> nb = new Box<number>(5); // type argument required on both the type AND `new`
|
|
294
294
|
Box<string> sb = new Box<string>("hi");
|
|
295
295
|
print(nb.Get()); // 5
|
|
296
|
+
|
|
297
|
+
class Pair<K, V> {
|
|
298
|
+
public K First;
|
|
299
|
+
public V Second;
|
|
300
|
+
constructor(K k, V v) { this.First = k; this.Second = v; }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
Pair<number, string> p = new Pair<number, string>(1, "a");
|
|
296
304
|
```
|
|
297
305
|
|
|
298
|
-
One unconstrained, invariant type
|
|
299
|
-
the `extern` section below)
|
|
306
|
+
One or more unconstrained, invariant type parameters per class/interface (real *or*
|
|
307
|
+
`extern` — see the `extern` section below), comma-separated: `<T>`, `<K, V>`, `<A, B, C>`,
|
|
308
|
+
however many the declaration needs.
|
|
300
309
|
Erased at codegen (JS has no generics either; `Box<number>` and `Box<string>` both
|
|
301
310
|
compile to the exact same plain `class Box`), so there's no runtime cost and no way to
|
|
302
|
-
inspect
|
|
311
|
+
inspect a type parameter at runtime.
|
|
303
312
|
|
|
304
313
|
**Rules:**
|
|
305
|
-
- The type argument
|
|
306
|
-
type (`Box<number>`) and separately on `new` (`new Box<number>(...)`); a bare
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
314
|
+
- The type argument(s) are **required everywhere** a generic type is named — on the
|
|
315
|
+
variable type (`Box<number>`) and separately on `new` (`new Box<number>(...)`); a bare
|
|
316
|
+
`Box`/`Pair` (no arguments) is a compile error, not "any"/inferred. The count must match
|
|
317
|
+
the declaration exactly — `Pair<number>` (too few) and `Pair<number, string, bool>` (too
|
|
318
|
+
many) are both arity errors, not truncated/padded.
|
|
319
|
+
- **Invariant, per slot**: `Box<Dog>` is not assignable to `Box<Animal>` even if `Dog :
|
|
320
|
+
Animal`, and `Pair<number, string>` is not assignable to `Pair<string, number>` — every
|
|
321
|
+
type argument must match exactly, in the same position, not just be compatible.
|
|
322
|
+
- Nesting works: `Box<Box<number>>`, `Box<number[]>`, `Box<number>?`, `Box<number>?[]`,
|
|
323
|
+
`Pair<number, Pair<string, bool>>`.
|
|
324
|
+
- Inside the class/interface's own body, each type parameter is fully abstract — you can
|
|
325
|
+
store it, return it, pass it around, but (unconstrained) you **cannot call any member on
|
|
326
|
+
a bare type-parameter value** (`this.value.Foo()` where `value: T` is a compile error:
|
|
327
|
+
"Cannot access member 'Foo' on type 'T'"). This is correct, not a bug — same as an
|
|
328
|
+
unconstrained type parameter in C#/Java/TypeScript.
|
|
329
|
+
|
|
330
|
+
**Generic inheritance**: a class/interface base list CAN name a generic base, with its own
|
|
331
|
+
type arguments, in either direction:
|
|
332
|
+
```ks
|
|
333
|
+
class IntBox : Box<number> { } // concrete — threads a fixed type through
|
|
334
|
+
class Container<T> : Box<T> { // generic — threads its OWN T through
|
|
335
|
+
public T GetAgain() { return this.Get(); }
|
|
336
|
+
}
|
|
337
|
+
interface INumberContainer : IContainer<number> { } // interfaces work the same way
|
|
338
|
+
```
|
|
339
|
+
Member resolution (fields, methods, an inherited constructor via `base(...)` or an implicit
|
|
340
|
+
default) composes substitutions correctly however many generic-base links up the chain a
|
|
341
|
+
member was actually declared — `Container<number>.Get()` (declared on `Box<T>`, two links
|
|
342
|
+
away in a longer chain) resolves to `number`, not the abstract `T`. **v1 limit**: at most
|
|
343
|
+
one generic entry across a class/interface's *whole* base list (its superclass, or one
|
|
344
|
+
implemented/extended interface — never more than one) — `class Foo<T> : Box<T>,
|
|
345
|
+
IContainer<T>` is a compile error ("has more than one generic entry in its base list") even
|
|
346
|
+
though either half alone would work.
|
|
316
347
|
|
|
317
348
|
**Does not exist (v1 scope cuts, each deliberate)**:
|
|
318
349
|
- **Generic functions.** `T Identity<T>(T x)` doesn't parse — only classes and interfaces
|
|
319
|
-
take
|
|
320
|
-
generic class can use that class's own
|
|
321
|
-
- **Multiple type parameters.** No `Map<K, V>` — exactly one `<T>` or none.
|
|
350
|
+
take type parameters, not free functions/methods themselves (a method *inside* a
|
|
351
|
+
generic class can use that class's own type parameters freely, same as any other member).
|
|
322
352
|
- **Constraints.** No `T : IComparable` — a type parameter is always fully unconstrained,
|
|
323
|
-
which is why you can't call members on a bare
|
|
324
|
-
- **Generic inheritance.** A class/interface's base list can only name a *non-generic*
|
|
325
|
-
type — `class Foo : Box<number>` and even `class Foo<T> : SomeGenericBase<T>` are both
|
|
326
|
-
compile errors ("cannot extend/implement generic type '...' — not supported in v1"). A
|
|
327
|
-
generic class/interface can still extend/implement ordinary non-generic bases normally.
|
|
353
|
+
which is why you can't call members on a bare one (see above).
|
|
328
354
|
- **Variance.** No `out`/`in`/covariance/contravariance — see invariance above.
|
|
329
355
|
|
|
330
356
|
## Nullable types — `T?`
|
|
@@ -402,11 +428,13 @@ KopScript-declared name exactly. Extern class members use real JS member names v
|
|
|
402
428
|
(camelCase, no rename mechanism). No inheritance modeling between two `extern class`
|
|
403
429
|
declarations — each stands alone.
|
|
404
430
|
|
|
405
|
-
`extern class` can carry
|
|
406
|
-
from "some-package";`) — identical rules to a real generic class (see "Generics"
|
|
407
|
-
one unconstrained invariant
|
|
408
|
-
from another package instantiates and type-checks exactly
|
|
409
|
-
(`Box<number>`, arity/invariance errors included)
|
|
431
|
+
`extern class` can carry type parameters (`extern class Box<T> { constructor(T v); T Value
|
|
432
|
+
{ get; } } from "some-package";`) — identical rules to a real generic class (see "Generics"
|
|
433
|
+
above: one or more unconstrained invariant parameters, erased, generic inheritance
|
|
434
|
+
included), so a generic type from another package instantiates and type-checks exactly
|
|
435
|
+
like a local one (`Box<number>`, arity/invariance errors included) — and a real KopScript
|
|
436
|
+
class can extend a generic `extern class` with a concrete or threaded-through type
|
|
437
|
+
argument, same as extending a real generic base.
|
|
410
438
|
|
|
411
439
|
**Never write `async` on an extern function/method signature** — declare its return type
|
|
412
440
|
as `task`/`task<T>` directly (`task<string> text();`, not `async task<string> text();`).
|
|
@@ -493,9 +521,10 @@ Locals/params: **camelCase**. This is convention, not enforced by the compiler.
|
|
|
493
521
|
|
|
494
522
|
## Does not exist (don't reach for these)
|
|
495
523
|
|
|
496
|
-
Generics beyond
|
|
497
|
-
constraints, no generic functions, no
|
|
498
|
-
above for what *is* supported) ·
|
|
524
|
+
Generics beyond one or more unconstrained type parameters and single-generic-base
|
|
525
|
+
inheritance (no `T : IFoo` constraints, no generic functions, no variance, no more than one
|
|
526
|
+
generic entry per base list — see Generics above for what *is* supported) ·
|
|
527
|
+
`any`/`unknown` annotations ·
|
|
499
528
|
a `let`/`var` keyword (locals are just `Type name = value;`) · decorators/annotations ·
|
|
500
529
|
reflection · type inference on declarations · ternary expression · union/tuple types ·
|
|
501
530
|
**object-literal syntax** (`{ key: value }` as a value — this doesn't exist *anywhere* in
|
package/README.md
CHANGED
|
@@ -22,9 +22,9 @@ LLM's context, as opposed to this README's narrative explanation.
|
|
|
22
22
|
explicit `virtual`/`override` dispatch (methods are sealed unless marked `virtual`), and a full
|
|
23
23
|
`public`/`protected`/`private` access model enforced at compile time.
|
|
24
24
|
- **Strongly typed**: every declaration is explicitly typed and checked at compile time.
|
|
25
|
-
- **Generics**:
|
|
26
|
-
interfaces (`class Box<T> { public T Value; }`) — erased at
|
|
27
|
-
cost, the same way `task<T>`/`state<T>` already are.
|
|
25
|
+
- **Generics**: one or more unconstrained, invariant type parameters on classes and
|
|
26
|
+
interfaces (`class Box<T> { public T Value; }`, `class Pair<K, V> { ... }`) — erased at
|
|
27
|
+
codegen with zero runtime cost, the same way `task<T>`/`state<T>` already are.
|
|
28
28
|
- **Nullable types with compiler-enforced null-checking**: `T?` (`string?`, `Dog?`,
|
|
29
29
|
`number[]?`) — a `T?` can't be used where a `T` is expected without an `if (x != null)`
|
|
30
30
|
check first (checked statically, not just at runtime), and comparing a value that can
|
|
@@ -221,7 +221,7 @@ void Announce(ISpeaker s) {
|
|
|
221
221
|
|
|
222
222
|
### Generics
|
|
223
223
|
|
|
224
|
-
Classes and interfaces can take
|
|
224
|
+
Classes and interfaces can take one or more type parameters:
|
|
225
225
|
|
|
226
226
|
```ks
|
|
227
227
|
class Box<T> {
|
|
@@ -233,34 +233,58 @@ class Box<T> {
|
|
|
233
233
|
Box<number> nb = new Box<number>(5);
|
|
234
234
|
Box<string> sb = new Box<string>("hi");
|
|
235
235
|
print(nb.Get()); // 5
|
|
236
|
+
|
|
237
|
+
class Pair<K, V> {
|
|
238
|
+
public K First;
|
|
239
|
+
public V Second;
|
|
240
|
+
constructor(K k, V v) { this.First = k; this.Second = v; }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
Pair<number, string> p = new Pair<number, string>(1, "a");
|
|
236
244
|
```
|
|
237
245
|
|
|
238
|
-
The type argument
|
|
246
|
+
The type argument(s) are required everywhere the generic type is named — on the variable's
|
|
239
247
|
declared type *and* separately on `new` (`Box<number> nb = new Box<number>(5);`, not
|
|
240
|
-
just one or the other)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
more later
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
call any member on a bare `T` value
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
`Dog
|
|
248
|
+
just one or the other) — and the count must match the declaration exactly (`Pair<number>`
|
|
249
|
+
alone, or `Pair<number, string, bool>`, are both arity errors). Generics are erased at
|
|
250
|
+
codegen exactly like `task<T>`/`state<T>` already are — `Box<number>` and `Box<string>`
|
|
251
|
+
compile to the identical plain `class Box`, so there's no runtime cost.
|
|
252
|
+
|
|
253
|
+
Still a deliberately small slice of generics, not a scaled-down promise of more later
|
|
254
|
+
inside v1:
|
|
255
|
+
|
|
256
|
+
- **Invariant, unconstrained.** No `T : ISomething` (constraints) — and because a type
|
|
257
|
+
parameter is fully unconstrained, you can't call any member on a bare `T`/`K`/`V` value
|
|
258
|
+
inside the generic class's own body (that's correct behavior, the same restriction
|
|
259
|
+
C#/Java/TypeScript put on an unconstrained parameter, not a bug). Invariant means
|
|
260
|
+
`Box<Dog>` is **not** assignable to `Box<Animal>` even though `Dog : Animal`, and
|
|
261
|
+
`Pair<number, string>` is not assignable to `Pair<string, number>` — every slot must
|
|
262
|
+
match exactly, in order.
|
|
253
263
|
- **No generic functions.** `T Identity<T>(T x)` isn't supported — only classes and
|
|
254
|
-
interfaces take
|
|
255
|
-
class's own
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
interfaces take type parameters. A method *inside* a generic class can still use that
|
|
265
|
+
class's own type parameters freely; it's just not introducing one of its own.
|
|
266
|
+
|
|
267
|
+
A class or interface *can* extend/implement a generic base, type arguments and all:
|
|
268
|
+
|
|
269
|
+
```ks
|
|
270
|
+
class IntBox : Box<number> { } // concrete: threads a fixed type through
|
|
271
|
+
class Container<T> : Box<T> { // generic: threads its OWN T through
|
|
272
|
+
public T GetAgain() { return this.Get(); }
|
|
273
|
+
}
|
|
274
|
+
Container<number> c = new Container<number>(5);
|
|
275
|
+
print(c.GetAgain()); // 5, and c.Value/c.Get() work too
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Member lookup (fields, methods, an inherited constructor) resolves correctly however many
|
|
279
|
+
generic-base links up the chain a member was actually declared, substituting all the way
|
|
280
|
+
down. **v1 limit**: at most one generic entry across a whole base list (the superclass, or
|
|
281
|
+
one implemented interface — not several at once) — `class Foo<T> : Box<T>, IContainer<T>`
|
|
282
|
+
is a compile error even though each half would work alone.
|
|
260
283
|
|
|
261
284
|
See `LLM.md`'s "Generics" section for the exhaustive rules if you're generating code
|
|
262
|
-
against this — nested generics (`Box<Box<number>>`, `Box<number>?[]`
|
|
263
|
-
interfaces used as standalone parameter types both work
|
|
285
|
+
against this — nested generics (`Box<Box<number>>`, `Box<number>?[]`, `Pair<number,
|
|
286
|
+
Pair<string, bool>>`) and generic interfaces used as standalone parameter types both work
|
|
287
|
+
and are covered there.
|
|
264
288
|
|
|
265
289
|
### Enums
|
|
266
290
|
|
|
@@ -359,11 +383,11 @@ consumes `Component`/`Router` themselves via `extern class ... from "kopular/...
|
|
|
359
383
|
proving `extern` works as a real cross-*package* boundary, not just for describing DOM
|
|
360
384
|
globals within a single project.
|
|
361
385
|
|
|
362
|
-
An `extern class` can carry its own type parameter, `extern class Box<T> { ... }`
|
|
363
|
-
exactly the same
|
|
364
|
-
above: invariant, unconstrained, erased,
|
|
365
|
-
from another package (e.g. Kopular's `FormField<T>`) can
|
|
366
|
-
generically, not just per concrete type:
|
|
386
|
+
An `extern class` can carry its own type parameter(s), `extern class Box<T> { ... }` or
|
|
387
|
+
`extern class Pair<K, V> { ... }` — exactly the same rules as a real generic class (see
|
|
388
|
+
"Generics" above: invariant, unconstrained, erased, and a real class can extend it as a
|
|
389
|
+
generic base), so a generic type from another package (e.g. Kopular's `FormField<T>`) can
|
|
390
|
+
be described and instantiated generically, not just per concrete type:
|
|
367
391
|
|
|
368
392
|
```ks
|
|
369
393
|
extern class Box<T> {
|