rooklang 0.3.3 → 0.4.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 +34 -7
- package/README.ru.md +34 -7
- package/dist/ast/declarations.d.ts +39 -4
- package/dist/ast/expressions.d.ts +34 -8
- package/dist/ast/markup.d.ts +6 -1
- package/dist/ast/statements.d.ts +28 -2
- package/dist/auto-import.d.ts +11 -0
- package/dist/auto-import.js +81 -0
- package/dist/breaks.d.ts +6 -0
- package/dist/breaks.js +36 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +23 -2
- package/dist/checker/array-literals.d.ts +6 -0
- package/dist/checker/array-literals.js +59 -0
- package/dist/checker/assignments.d.ts +4 -0
- package/dist/checker/assignments.js +23 -3
- package/dist/checker/base.d.ts +8 -2
- package/dist/checker/base.js +7 -7
- package/dist/checker/builtins.js +22 -8
- package/dist/checker/bytes.d.ts +2 -2
- package/dist/checker/bytes.js +2 -2
- package/dist/checker/calls.js +3 -0
- package/dist/checker/channel-objects.d.ts +3 -0
- package/dist/checker/channel-objects.js +40 -0
- package/dist/checker/channels.d.ts +1 -0
- package/dist/checker/channels.js +17 -4
- package/dist/checker/checker.d.ts +1 -1
- package/dist/checker/checker.js +19 -0
- package/dist/checker/class-members.d.ts +22 -0
- package/dist/checker/class-members.js +105 -0
- package/dist/checker/classes.d.ts +5 -4
- package/dist/checker/classes.js +48 -13
- package/dist/checker/closing.d.ts +21 -0
- package/dist/checker/closing.js +164 -0
- package/dist/checker/completion.d.ts +3 -3
- package/dist/checker/completion.js +4 -3
- package/dist/checker/component-bindings.d.ts +7 -0
- package/dist/checker/component-bindings.js +45 -0
- package/dist/checker/component-values.js +10 -7
- package/dist/checker/components.d.ts +2 -2
- package/dist/checker/components.js +8 -3
- package/dist/checker/context.d.ts +41 -5
- package/dist/checker/context.js +23 -0
- package/dist/checker/control-flow.d.ts +11 -5
- package/dist/checker/control-flow.js +65 -40
- package/dist/checker/declarations.d.ts +2 -2
- package/dist/checker/declarations.js +4 -2
- package/dist/checker/decode.d.ts +8 -0
- package/dist/checker/decode.js +32 -0
- package/dist/checker/decorator-exports.js +4 -0
- package/dist/checker/decorator-includes.d.ts +9 -0
- package/dist/checker/decorator-includes.js +71 -0
- package/dist/checker/decorator-members.d.ts +8 -10
- package/dist/checker/decorator-members.js +28 -31
- package/dist/checker/decorator-wrappers.d.ts +1 -1
- package/dist/checker/decorator-wrappers.js +3 -2
- package/dist/checker/decorators.d.ts +14 -5
- package/dist/checker/decorators.js +52 -25
- package/dist/checker/expressions.d.ts +6 -2
- package/dist/checker/expressions.js +20 -40
- package/dist/checker/flow.d.ts +25 -3
- package/dist/checker/flow.js +56 -12
- package/dist/checker/functions.d.ts +2 -2
- package/dist/checker/functions.js +9 -5
- package/dist/checker/helpers.d.ts +5 -2
- package/dist/checker/helpers.js +16 -4
- package/dist/checker/imports.js +5 -2
- package/dist/checker/iterables.d.ts +3 -1
- package/dist/checker/iterables.js +13 -0
- package/dist/checker/iterators.d.ts +4 -1
- package/dist/checker/iterators.js +12 -4
- package/dist/checker/json.d.ts +5 -0
- package/dist/checker/json.js +92 -0
- package/dist/checker/loops.d.ts +2 -0
- package/dist/checker/loops.js +50 -5
- package/dist/checker/markup.js +14 -2
- package/dist/checker/members.js +10 -1
- package/dist/checker/operators.d.ts +2 -2
- package/dist/checker/operators.js +7 -5
- package/dist/checker/queues.d.ts +2 -2
- package/dist/checker/queues.js +2 -2
- package/dist/checker/resolution.js +5 -3
- package/dist/checker/shared-state.d.ts +11 -0
- package/dist/checker/shared-state.js +37 -0
- package/dist/checker/signals.d.ts +8 -0
- package/dist/checker/signals.js +48 -0
- package/dist/checker/statements.d.ts +5 -2
- package/dist/checker/statements.js +51 -22
- package/dist/checker/tagged-unions.d.ts +37 -0
- package/dist/checker/tagged-unions.js +132 -0
- package/dist/checker/topics.d.ts +6 -0
- package/dist/checker/topics.js +17 -0
- package/dist/checker/transfer.d.ts +3 -1
- package/dist/checker/transfer.js +25 -5
- package/dist/checker/try.d.ts +6 -0
- package/dist/checker/try.js +19 -0
- package/dist/checker/types/constructors.d.ts +1 -1
- package/dist/checker/types/constructors.js +2 -2
- package/dist/checker/types/generics.js +1 -1
- package/dist/checker/types/iterables.d.ts +13 -0
- package/dist/checker/types/iterables.js +52 -0
- package/dist/checker/types/model.d.ts +25 -0
- package/dist/checker/types/params.js +22 -3
- package/dist/checker/types/printing.js +4 -3
- package/dist/checker/types/relations.js +19 -25
- package/dist/checker/types/topic.d.ts +6 -0
- package/dist/checker/types/topic.js +23 -0
- package/dist/checker/types.d.ts +2 -0
- package/dist/checker/types.js +2 -0
- package/dist/checker/untyped-globals.d.ts +1 -0
- package/dist/checker/untyped-globals.js +3 -1
- package/dist/cli.js +18 -36
- package/dist/codegen/attributes.d.ts +4 -0
- package/dist/codegen/attributes.js +24 -2
- package/dist/codegen/calls.d.ts +23 -0
- package/dist/codegen/calls.js +88 -7
- package/dist/codegen/component-helpers.d.ts +6 -1
- package/dist/codegen/component-helpers.js +6 -1
- package/dist/codegen/component-props.d.ts +11 -2
- package/dist/codegen/component-props.js +50 -5
- package/dist/codegen/components.d.ts +6 -5
- package/dist/codegen/components.js +44 -21
- package/dist/codegen/control-flow.d.ts +2 -0
- package/dist/codegen/control-flow.js +23 -9
- package/dist/codegen/control-statements.d.ts +10 -2
- package/dist/codegen/control-statements.js +56 -19
- package/dist/codegen/creation.js +5 -2
- package/dist/codegen/decode.d.ts +14 -0
- package/dist/codegen/decode.js +93 -0
- package/dist/codegen/early-returns.d.ts +4 -3
- package/dist/codegen/early-returns.js +17 -5
- package/dist/codegen/emitter.d.ts +13 -41
- package/dist/codegen/emitter.js +27 -8
- package/dist/codegen/expressions.d.ts +9 -0
- package/dist/codegen/expressions.js +15 -26
- package/dist/codegen/functions.d.ts +11 -1
- package/dist/codegen/functions.js +31 -3
- package/dist/codegen/js.d.ts +2 -2
- package/dist/codegen/js.js +5 -2
- package/dist/codegen/live.d.ts +60 -0
- package/dist/codegen/live.js +29 -0
- package/dist/codegen/mutations.d.ts +7 -0
- package/dist/codegen/mutations.js +43 -2
- package/dist/codegen/options.d.ts +42 -0
- package/dist/codegen/options.js +1 -0
- package/dist/codegen/reactive.d.ts +4 -59
- package/dist/codegen/reactive.js +34 -72
- package/dist/codegen/runtime.d.ts +7 -3
- package/dist/codegen/runtime.js +33 -14
- package/dist/codegen/shared.d.ts +22 -0
- package/dist/codegen/shared.js +93 -0
- package/dist/codegen/simple-statements.d.ts +11 -5
- package/dist/codegen/simple-statements.js +40 -15
- package/dist/codegen/statements.d.ts +5 -0
- package/dist/codegen/statements.js +99 -4
- package/dist/codegen/try.d.ts +5 -0
- package/dist/codegen/try.js +40 -0
- package/dist/codegen/updates.d.ts +11 -3
- package/dist/codegen/updates.js +52 -4
- package/dist/codegen/web-components.d.ts +2 -2
- package/dist/codegen/web-components.js +2 -2
- package/dist/compile.d.ts +9 -0
- package/dist/compile.js +25 -8
- package/dist/completion.d.ts +4 -2
- package/dist/completion.js +10 -5
- package/dist/declarations.js +32 -6
- package/dist/decorator-copy.d.ts +1 -1
- package/dist/decorator-copy.js +6 -2
- package/dist/decorator-names.d.ts +14 -0
- package/dist/decorator-names.js +56 -0
- package/dist/decorators.d.ts +2 -3
- package/dist/decorators.js +36 -14
- package/dist/goroutines.d.ts +1 -1
- package/dist/goroutines.js +5 -4
- package/dist/index.d.ts +6 -2
- package/dist/index.js +14 -5
- package/dist/inline-packages.d.ts +2 -1
- package/dist/inline-packages.js +9 -4
- package/dist/lexer/base.d.ts +2 -0
- package/dist/lexer/base.js +6 -1
- package/dist/lexer/lexer.js +3 -0
- package/dist/lexer/literals.d.ts +5 -0
- package/dist/lexer/literals.js +51 -1
- package/dist/lexer/markup.js +3 -4
- package/dist/lexer/tables.js +2 -0
- package/dist/lexer/token.d.ts +4 -3
- package/dist/lexer/token.js +0 -2
- package/dist/loader.js +30 -8
- package/dist/names.d.ts +4 -0
- package/dist/names.js +29 -0
- package/dist/parser/base.d.ts +5 -0
- package/dist/parser/base.js +2 -1
- package/dist/parser/classes.d.ts +2 -0
- package/dist/parser/classes.js +88 -23
- package/dist/parser/control-flow.d.ts +8 -1
- package/dist/parser/control-flow.js +49 -26
- package/dist/parser/declarations.d.ts +5 -12
- package/dist/parser/declarations.js +14 -79
- package/dist/parser/decorators.d.ts +6 -2
- package/dist/parser/decorators.js +43 -19
- package/dist/parser/expressions.js +27 -3
- package/dist/parser/jumps.d.ts +11 -0
- package/dist/parser/jumps.js +77 -0
- package/dist/parser/literals.d.ts +9 -0
- package/dist/parser/literals.js +45 -6
- package/dist/parser/markup.js +1 -1
- package/dist/parser/params.d.ts +21 -0
- package/dist/parser/params.js +143 -0
- package/dist/parser/simple-statements.d.ts +2 -1
- package/dist/parser/simple-statements.js +38 -15
- package/dist/parser/statements.d.ts +5 -5
- package/dist/parser/statements.js +39 -35
- package/dist/parser/syntax.d.ts +11 -1
- package/dist/parser/syntax.js +16 -2
- package/dist/parser/types.js +8 -3
- package/dist/project-modules.d.ts +12 -0
- package/dist/project-modules.js +106 -0
- package/dist/run-file.d.ts +6 -0
- package/dist/run-file.js +111 -0
- package/dist/runtime/sources.js +13 -6
- package/dist/source-map.d.ts +17 -0
- package/dist/source-map.js +75 -0
- package/dist/ts-types.js +4 -1
- package/dist/typescript/convert-objects.d.ts +2 -1
- package/dist/typescript/convert-objects.js +18 -9
- package/dist/vite.js +12 -4
- package/dist/walk-types.js +1 -0
- package/dist/walk.d.ts +0 -2
- package/dist/walk.js +14 -31
- package/package.json +2 -2
- package/src/runtime/chan.js +15 -5
- package/src/runtime/channel.js +28 -0
- package/src/runtime/classes.js +32 -0
- package/src/runtime/core.js +10 -1
- package/src/runtime/decode.js +221 -0
- package/src/runtime/go.js +3 -0
- package/src/runtime/index.js +7 -0
- package/src/runtime/markup.js +27 -17
- package/src/runtime/select.js +14 -9
- package/src/runtime/shared.js +17 -0
- package/src/runtime/signals.js +59 -0
- package/src/runtime/threads.js +32 -5
- package/src/runtime/topic.js +118 -0
- package/src/runtime/try.js +45 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { SourceFile } from "./source.js";
|
|
2
|
+
const MARK = /([0-9a-z]+)/g;
|
|
3
|
+
/** The mark of a place in the source, `<offset in base 36>`, which code cannot contain. */
|
|
4
|
+
export function sourceMark(offset) {
|
|
5
|
+
return `${offset.toString(36)}`;
|
|
6
|
+
}
|
|
7
|
+
/** The code without its marks, and the source map of them. */
|
|
8
|
+
export function withoutMarks(code, source, sourceName) {
|
|
9
|
+
const file = new SourceFile(sourceName, source);
|
|
10
|
+
const lines = [];
|
|
11
|
+
const segments = [];
|
|
12
|
+
// The previous segment, relative to which the next one is written.
|
|
13
|
+
let previous = { line: 0, column: 0 };
|
|
14
|
+
let started = false;
|
|
15
|
+
for (const text of code.split('\n')) {
|
|
16
|
+
const places = [];
|
|
17
|
+
let removed = 0;
|
|
18
|
+
const clean = text.replace(MARK, (mark, offset, index) => {
|
|
19
|
+
const { line, column } = file.position(parseInt(offset, 36));
|
|
20
|
+
places.push({ generated: index - removed, line: line - 1, column: column - 1 });
|
|
21
|
+
removed += mark.length;
|
|
22
|
+
return '';
|
|
23
|
+
});
|
|
24
|
+
if (places.length === 0 && started && clean.trim() !== '') {
|
|
25
|
+
places.push({ generated: 0, ...previous });
|
|
26
|
+
}
|
|
27
|
+
let generated = 0;
|
|
28
|
+
segments.push(places
|
|
29
|
+
.map((place) => {
|
|
30
|
+
const segment = vlq([
|
|
31
|
+
place.generated - generated,
|
|
32
|
+
// The index of the source, which is always the one.
|
|
33
|
+
0,
|
|
34
|
+
place.line - previous.line,
|
|
35
|
+
place.column - previous.column,
|
|
36
|
+
]);
|
|
37
|
+
generated = place.generated;
|
|
38
|
+
previous = { line: place.line, column: place.column };
|
|
39
|
+
started = true;
|
|
40
|
+
return segment;
|
|
41
|
+
})
|
|
42
|
+
.join(','));
|
|
43
|
+
lines.push(clean);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
code: lines.join('\n'),
|
|
47
|
+
map: {
|
|
48
|
+
version: 3,
|
|
49
|
+
sources: [sourceName],
|
|
50
|
+
sourcesContent: [source],
|
|
51
|
+
names: [],
|
|
52
|
+
mappings: segments.join(';'),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** The comment at the end of a module that tells where its source map is. */
|
|
57
|
+
export function sourceMapComment(url) {
|
|
58
|
+
return `//# sourceMappingURL=${url}\n`;
|
|
59
|
+
}
|
|
60
|
+
const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
61
|
+
/** Numbers in base 64 VLQ: five bits a digit, the lowest first, and the sign in the lowest bit. */
|
|
62
|
+
function vlq(numbers) {
|
|
63
|
+
let text = '';
|
|
64
|
+
for (const number of numbers) {
|
|
65
|
+
let value = number < 0 ? (-number << 1) | 1 : number << 1;
|
|
66
|
+
do {
|
|
67
|
+
let digit = value & 31;
|
|
68
|
+
value >>>= 5;
|
|
69
|
+
if (value > 0)
|
|
70
|
+
digit |= 32;
|
|
71
|
+
text += BASE64[digit];
|
|
72
|
+
} while (value > 0);
|
|
73
|
+
}
|
|
74
|
+
return text;
|
|
75
|
+
}
|
package/dist/ts-types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CONTENT } from "./checker/dom.js";
|
|
2
2
|
import { guardedByError } from "./checker/error-results.js";
|
|
3
|
-
import { ERROR_CLASS, isQueue, memberNames, queueElement, } from "./checker/types.js";
|
|
3
|
+
import { ERROR_CLASS, isQueue, isTopic, memberNames, queueElement, } from "./checker/types.js";
|
|
4
4
|
// Types of the checker in TypeScript syntax, for declaration files (declarations.ts).
|
|
5
5
|
/** A nullable property may be left out of an object: `name?: string | null`. */
|
|
6
6
|
export function property(name, type) {
|
|
@@ -108,6 +108,9 @@ function objectType(type) {
|
|
|
108
108
|
if (type.name === 'chan' || type.name === 'chan<-' || type.name === '<-chan') {
|
|
109
109
|
return `{ readonly $$chan: string }`;
|
|
110
110
|
}
|
|
111
|
+
// A topic is an object with its name, and so is it for TypeScript code.
|
|
112
|
+
if (isTopic(type))
|
|
113
|
+
return `{ readonly $$topic: string }`;
|
|
111
114
|
// A queue is an instance of $$Queue of the runtime (src/runtime/queue.js): TypeScript code uses its
|
|
112
115
|
// members.
|
|
113
116
|
if (isQueue(type)) {
|
|
@@ -17,7 +17,8 @@ export declare abstract class ObjectConverter extends ConverterBase {
|
|
|
17
17
|
protected object(type: TS.Type, name: string | null, typeParams?: TypeParam[]): ObjectType;
|
|
18
18
|
/**
|
|
19
19
|
* What `for v in x` gives: the `value` of what `next()` of `[Symbol.iterator]()` returns while
|
|
20
|
-
* it is not `done
|
|
20
|
+
* it is not `done`, or of what its Promise gives for `[Symbol.asyncIterator]()`. Found when it is
|
|
21
|
+
* first needed, as most types are never looped over.
|
|
21
22
|
*/
|
|
22
23
|
private iterates;
|
|
23
24
|
protected member(type: TS.Type, name: string, owner: ClassInfo | null): Member | undefined;
|
|
@@ -9,10 +9,13 @@ export class ObjectConverter extends ConverterBase {
|
|
|
9
9
|
const [element] = checker.getTypeArguments(type);
|
|
10
10
|
return arrayOf(element ? this.convert(element) : ANY);
|
|
11
11
|
}
|
|
12
|
-
// A tuple is an array of any of its elements: `[string, number]` is `[](string | number)
|
|
12
|
+
// A tuple is an array of any of its elements: `[string, number]` is `[](string | number)`,
|
|
13
|
+
// which keeps them by position too, to infer the type parameters of `[K, V]`.
|
|
13
14
|
if (checker.isTupleType(type)) {
|
|
14
|
-
const elements = checker
|
|
15
|
-
|
|
15
|
+
const elements = checker
|
|
16
|
+
.getTypeArguments(type)
|
|
17
|
+
.map((each) => this.convert(each));
|
|
18
|
+
return elements.length > 0 ? arrayOf(union(elements), elements) : arrayOf(ANY);
|
|
16
19
|
}
|
|
17
20
|
if (type.objectFlags & ObjectFlags.Reference) {
|
|
18
21
|
const reference = type;
|
|
@@ -116,23 +119,26 @@ export class ObjectConverter extends ConverterBase {
|
|
|
116
119
|
object.index = this.convert(index);
|
|
117
120
|
if (numberIndex && numberIndex !== index)
|
|
118
121
|
object.numberIndex = this.convert(numberIndex);
|
|
119
|
-
this.iterates(object, type);
|
|
122
|
+
this.iterates(object, type, 'iterates');
|
|
123
|
+
this.iterates(object, type, 'asyncIterates');
|
|
120
124
|
return object;
|
|
121
125
|
}
|
|
122
126
|
/**
|
|
123
127
|
* What `for v in x` gives: the `value` of what `next()` of `[Symbol.iterator]()` returns while
|
|
124
|
-
* it is not `done
|
|
128
|
+
* it is not `done`, or of what its Promise gives for `[Symbol.asyncIterator]()`. Found when it is
|
|
129
|
+
* first needed, as most types are never looped over.
|
|
125
130
|
*/
|
|
126
|
-
iterates(object, type) {
|
|
131
|
+
iterates(object, type, key) {
|
|
127
132
|
const { checker } = this;
|
|
133
|
+
const prefix = key === 'iterates' ? '__@iterator@' : '__@asyncIterator@';
|
|
128
134
|
const iterator = type
|
|
129
135
|
.getProperties()
|
|
130
|
-
.find((property) => String(property.escapedName).startsWith(
|
|
136
|
+
.find((property) => String(property.escapedName).startsWith(prefix));
|
|
131
137
|
if (!iterator)
|
|
132
138
|
return;
|
|
133
139
|
let found;
|
|
134
140
|
let done = false;
|
|
135
|
-
Object.defineProperty(object,
|
|
141
|
+
Object.defineProperty(object, key, {
|
|
136
142
|
enumerable: true,
|
|
137
143
|
get: () => {
|
|
138
144
|
if (done)
|
|
@@ -143,7 +149,8 @@ export class ObjectConverter extends ConverterBase {
|
|
|
143
149
|
.getCallSignatures()[0]
|
|
144
150
|
?.getReturnType()
|
|
145
151
|
.getProperty('next');
|
|
146
|
-
const
|
|
152
|
+
const returned = next && checker.getTypeOfSymbol(next).getCallSignatures()[0]?.getReturnType();
|
|
153
|
+
const result = returned && key === 'asyncIterates' ? checker.getAwaitedType(returned) : returned;
|
|
147
154
|
const results = result?.isUnion() ? result.types : result ? [result] : [];
|
|
148
155
|
const yielded = results.find((each) => {
|
|
149
156
|
const flag = each.getProperty('done');
|
|
@@ -240,6 +247,8 @@ export class ObjectConverter extends ConverterBase {
|
|
|
240
247
|
if (base)
|
|
241
248
|
info.superClass = this.classInfo(base.symbol);
|
|
242
249
|
info.ctor = this.signatures(checker.getSignaturesOfType(statics, SignatureKind.Construct));
|
|
250
|
+
// A stream of Node is a class, gone over with `for await` in JS.
|
|
251
|
+
this.iterates(info, instance, 'asyncIterates');
|
|
243
252
|
return info;
|
|
244
253
|
}
|
|
245
254
|
}
|
package/dist/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
2
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { RUNTIME_MODULE } from "./runtime-module.js";
|
|
5
5
|
import { formatDiagnostic } from "./diagnostics.js";
|
|
@@ -12,6 +12,8 @@ import { SourceFile } from "./source.js";
|
|
|
12
12
|
// path has no query, since Vite drops the query of a worker's URL. The compiled code imports the
|
|
13
13
|
// runtime, "rooklang/runtime", of the plugin's own package.
|
|
14
14
|
const GOROUTINES = '.goroutines.js';
|
|
15
|
+
/** The loader of `.rk` files of `rook run`, next to this file: .ts in src, .js in the package. */
|
|
16
|
+
const LOADER = new URL(`./loader${extname(fileURLToPath(import.meta.url))}`, import.meta.url).href;
|
|
15
17
|
export function rook(options = {}) {
|
|
16
18
|
const typeCheck = options.typeCheck ?? true;
|
|
17
19
|
let root = process.cwd();
|
|
@@ -46,7 +48,7 @@ export function rook(options = {}) {
|
|
|
46
48
|
return null;
|
|
47
49
|
return readFileSync(path.slice(0, -GOROUTINES.length), 'utf8');
|
|
48
50
|
},
|
|
49
|
-
transform(source, id) {
|
|
51
|
+
transform(source, id, transformOptions) {
|
|
50
52
|
const [name = id, query] = id.split('?');
|
|
51
53
|
const worker = name.endsWith(`.rk${GOROUTINES}`);
|
|
52
54
|
const path = worker ? name.slice(0, -GOROUTINES.length) : name;
|
|
@@ -59,7 +61,11 @@ export function rook(options = {}) {
|
|
|
59
61
|
rewriteImports: false,
|
|
60
62
|
typeCheck,
|
|
61
63
|
markup: options.markup,
|
|
62
|
-
|
|
64
|
+
// In Node, as under Vitest, a worker thread loads the module itself, `app.rk?goroutines`,
|
|
65
|
+
// with the loader of `rook run`, which it imports first: it has no Vite.
|
|
66
|
+
...(transformOptions?.ssr === true
|
|
67
|
+
? { workerUrl: `./${basename(path)}?goroutines`, nodeLoader: LOADER }
|
|
68
|
+
: { workerUrl: `./${basename(path)}${GOROUTINES}` }),
|
|
63
69
|
});
|
|
64
70
|
const file = new SourceFile(relative(root, path), source);
|
|
65
71
|
// Vite counts columns from 0.
|
|
@@ -86,7 +92,9 @@ export function rook(options = {}) {
|
|
|
86
92
|
for (const dependency of result.dependencies) {
|
|
87
93
|
this.addWatchFile(resolve(dirname(path), dependency));
|
|
88
94
|
}
|
|
89
|
-
return
|
|
95
|
+
return worker
|
|
96
|
+
? { code: result.worker ?? '', map: result.workerMap ?? null }
|
|
97
|
+
: { code: result.code, map: result.map ?? null };
|
|
90
98
|
},
|
|
91
99
|
};
|
|
92
100
|
}
|
package/dist/walk-types.js
CHANGED
package/dist/walk.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import type * as ast from './ast.ts';
|
|
2
2
|
/** Calls `visit` for each direct child of `node`, in source order. */
|
|
3
3
|
export declare function forEachChild(node: ast.Node, visit: (child: ast.Node) => void): void;
|
|
4
|
-
/** Whether a `break` in these statements leaves the enclosing loop or switch. */
|
|
5
|
-
export declare function containsBreak(statements: readonly ast.Statement[]): boolean;
|
package/dist/walk.js
CHANGED
|
@@ -30,7 +30,7 @@ export function forEachChild(node, visit) {
|
|
|
30
30
|
visit(node.name);
|
|
31
31
|
each(node.params);
|
|
32
32
|
each(node.results);
|
|
33
|
-
|
|
33
|
+
optional(node.body);
|
|
34
34
|
break;
|
|
35
35
|
case 'Parameter':
|
|
36
36
|
visit(node.name);
|
|
@@ -47,19 +47,18 @@ export function forEachChild(node, visit) {
|
|
|
47
47
|
// The names after `needs` are other decorators', not values in scope.
|
|
48
48
|
visit(node.name);
|
|
49
49
|
each(node.params);
|
|
50
|
+
each(node.includes);
|
|
50
51
|
visit(node.body);
|
|
51
52
|
break;
|
|
52
53
|
case 'DecoratorUse':
|
|
53
54
|
// The name is the decorator's, not a value in scope.
|
|
54
55
|
each(node.arguments);
|
|
55
56
|
break;
|
|
56
|
-
case 'DecoratorGet':
|
|
57
|
-
visit(node.target);
|
|
58
|
-
break;
|
|
59
57
|
case 'VariableDeclaration':
|
|
60
58
|
each(node.names);
|
|
61
59
|
optional(node.type);
|
|
62
60
|
each(node.values);
|
|
61
|
+
optional(node.body);
|
|
63
62
|
break;
|
|
64
63
|
case 'ClassDeclaration':
|
|
65
64
|
visit(node.name);
|
|
@@ -111,11 +110,16 @@ export function forEachChild(node, visit) {
|
|
|
111
110
|
visit(node.element);
|
|
112
111
|
optional(node.items);
|
|
113
112
|
break;
|
|
113
|
+
case 'TopicExpression':
|
|
114
|
+
visit(node.element);
|
|
115
|
+
visit(node.name);
|
|
116
|
+
break;
|
|
114
117
|
case 'MakeExpression':
|
|
115
118
|
visit(node.type);
|
|
116
119
|
visit(node.length);
|
|
117
120
|
break;
|
|
118
121
|
case 'ConversionExpression':
|
|
122
|
+
case 'DecodeExpression':
|
|
119
123
|
visit(node.type);
|
|
120
124
|
visit(node.argument);
|
|
121
125
|
break;
|
|
@@ -123,6 +127,7 @@ export function forEachChild(node, visit) {
|
|
|
123
127
|
each(node.values);
|
|
124
128
|
break;
|
|
125
129
|
case 'IfStatement':
|
|
130
|
+
optional(node.init);
|
|
126
131
|
visit(node.condition);
|
|
127
132
|
visit(node.consequent);
|
|
128
133
|
optional(node.alternate);
|
|
@@ -137,9 +142,11 @@ export function forEachChild(node, visit) {
|
|
|
137
142
|
optional(node.key);
|
|
138
143
|
visit(node.value);
|
|
139
144
|
visit(node.iterable);
|
|
145
|
+
optional(node.withKey ?? null);
|
|
140
146
|
visit(node.body);
|
|
141
147
|
break;
|
|
142
148
|
case 'SwitchStatement':
|
|
149
|
+
optional(node.init);
|
|
143
150
|
optional(node.discriminant);
|
|
144
151
|
each(node.cases);
|
|
145
152
|
break;
|
|
@@ -204,6 +211,7 @@ export function forEachChild(node, visit) {
|
|
|
204
211
|
visit(node.body);
|
|
205
212
|
break;
|
|
206
213
|
case 'UnaryExpression':
|
|
214
|
+
case 'TryExpression':
|
|
207
215
|
visit(node.argument);
|
|
208
216
|
break;
|
|
209
217
|
case 'GoExpression':
|
|
@@ -265,6 +273,7 @@ export function forEachChild(node, visit) {
|
|
|
265
273
|
case 'ArrayType':
|
|
266
274
|
case 'ChanType':
|
|
267
275
|
case 'QueueType':
|
|
276
|
+
case 'TopicType':
|
|
268
277
|
case 'NullableType':
|
|
269
278
|
case 'FuncType':
|
|
270
279
|
case 'ComponentType':
|
|
@@ -287,6 +296,7 @@ export function forEachChild(node, visit) {
|
|
|
287
296
|
case 'NumberLiteral':
|
|
288
297
|
case 'BigIntLiteral':
|
|
289
298
|
case 'StringLiteral':
|
|
299
|
+
case 'RegExpLiteral':
|
|
290
300
|
case 'TemplateElement':
|
|
291
301
|
case 'BooleanLiteral':
|
|
292
302
|
case 'NullLiteral':
|
|
@@ -295,30 +305,3 @@ export function forEachChild(node, visit) {
|
|
|
295
305
|
break;
|
|
296
306
|
}
|
|
297
307
|
}
|
|
298
|
-
/** Whether a `break` in these statements leaves the enclosing loop or switch. */
|
|
299
|
-
export function containsBreak(statements) {
|
|
300
|
-
let found = false;
|
|
301
|
-
const visit = (node) => {
|
|
302
|
-
switch (node.kind) {
|
|
303
|
-
case 'BreakStatement':
|
|
304
|
-
found = true;
|
|
305
|
-
return;
|
|
306
|
-
// A `break` inside these belongs to them.
|
|
307
|
-
case 'ForStatement':
|
|
308
|
-
case 'ForInStatement':
|
|
309
|
-
case 'SwitchStatement':
|
|
310
|
-
case 'SelectStatement':
|
|
311
|
-
case 'FuncDeclaration':
|
|
312
|
-
case 'FuncExpression':
|
|
313
|
-
case 'ArrowFunction':
|
|
314
|
-
case 'ClassDeclaration':
|
|
315
|
-
case 'MountStatement':
|
|
316
|
-
case 'EffectStatement':
|
|
317
|
-
return;
|
|
318
|
-
default:
|
|
319
|
-
forEachChild(node, visit);
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
statements.forEach(visit);
|
|
323
|
-
return found;
|
|
324
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rooklang",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A language with JavaScript semantics, Go-style syntax, goroutines on real threads and static types that compiles to readable JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rooklang",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"rook": "node src/cli.ts",
|
|
59
59
|
"site:dev": "vite",
|
|
60
|
-
"site:build": "vite build",
|
|
60
|
+
"site:build": "vite build && node scripts/prerender.ts",
|
|
61
61
|
"site": "npm run site:build && node src/cli.ts run site/server.rk",
|
|
62
62
|
"site:images": "node scripts/og-image.ts",
|
|
63
63
|
"vscode:build": "node scripts/build-vscode.ts",
|
package/src/runtime/chan.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Channels: sending, receiving and closing, here or in the thread that made the channel
|
|
2
2
|
// (threads.js), and the queues of a channel. Receiving from a closed channel gives
|
|
3
|
-
// the zero value of its type, as in Go.
|
|
3
|
+
// the zero value of its type, as in Go. Channel.EMPTY is closed and belongs to no thread: a send to
|
|
4
|
+
// it goes nowhere, and receiving gives the zero value that the code that receives passes.
|
|
4
5
|
|
|
5
6
|
import { $$Queue } from './queue.js';
|
|
6
7
|
import { $$commit, $$lock, $$select, $$try, $$unlock, $$unwait } from './select.js';
|
|
7
|
-
import { $$adopt, $$ask, $$ownerOf, $$post, $$registry, $$stopped } from './threads.js';
|
|
8
|
+
import { $$adopt, $$ask, $$isEmpty, $$ownerOf, $$post, $$registry, $$stopped } from './threads.js';
|
|
8
9
|
|
|
9
10
|
$$registry().handle ??= { message: $$message, pump: $$pump };
|
|
10
11
|
|
|
@@ -32,6 +33,9 @@ export function $$chan(size, zero) {
|
|
|
32
33
|
// that made the channel.
|
|
33
34
|
export function $$send(channel, value) {
|
|
34
35
|
const id = channel.$$chan;
|
|
36
|
+
|
|
37
|
+
if ($$isEmpty(id)) return Promise.resolve();
|
|
38
|
+
|
|
35
39
|
const owner = $$ownerOf(id);
|
|
36
40
|
|
|
37
41
|
if (owner !== $$registry().key) return $$ask(owner, { op: 'send', channel: id, value });
|
|
@@ -41,11 +45,12 @@ export function $$send(channel, value) {
|
|
|
41
45
|
);
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
export function $$receive(channel, withOk = false) {
|
|
48
|
+
export function $$receive(channel, withOk = false, zero = null) {
|
|
45
49
|
const id = channel.$$chan;
|
|
46
50
|
const owner = $$ownerOf(id);
|
|
47
|
-
const received =
|
|
48
|
-
|
|
51
|
+
const received = $$isEmpty(id)
|
|
52
|
+
? Promise.resolve([zero, false])
|
|
53
|
+
: owner !== $$registry().key
|
|
49
54
|
? $$ask(owner, { op: 'receive', channel: id })
|
|
50
55
|
: new Promise((resolve, reject) => $$wait(id, 'receivers', { done: resolve, fail: reject }));
|
|
51
56
|
|
|
@@ -55,6 +60,9 @@ export function $$receive(channel, withOk = false) {
|
|
|
55
60
|
// Closing a channel of another thread fails this one if it was closed already, as a panic would.
|
|
56
61
|
export function $$close(channel) {
|
|
57
62
|
const id = channel.$$chan;
|
|
63
|
+
|
|
64
|
+
if ($$isEmpty(id)) return;
|
|
65
|
+
|
|
58
66
|
const owner = $$ownerOf(id);
|
|
59
67
|
|
|
60
68
|
if (owner === $$registry().key) return $$closeHere(id);
|
|
@@ -70,6 +78,8 @@ export function $$closeHere(id) {
|
|
|
70
78
|
|
|
71
79
|
if (state.closed) throw new Error('close of a closed channel');
|
|
72
80
|
state.closed = true;
|
|
81
|
+
// What made the channel stops with it, as signal() does (signals.js).
|
|
82
|
+
state.onClose?.();
|
|
73
83
|
$$pump(id);
|
|
74
84
|
}
|
|
75
85
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// `Channel`: what Rook code and the code compiled from it do with channels, by name. The functions
|
|
2
|
+
// themselves are in chan.js, select.js, signals.js, streams.js and timers.js.
|
|
3
|
+
|
|
4
|
+
import { $$chan, $$close, $$range, $$receive, $$send } from './chan.js';
|
|
5
|
+
import { $$select, $$try } from './select.js';
|
|
6
|
+
import { $$abortSignal, $$done, $$signal } from './signals.js';
|
|
7
|
+
import { $$fromStream, $$stream } from './streams.js';
|
|
8
|
+
import { $$after, $$tick } from './timers.js';
|
|
9
|
+
|
|
10
|
+
export const $$Channel = Object.freeze({
|
|
11
|
+
// The zero value of channel types: closed, and the same in every thread (threads.js).
|
|
12
|
+
EMPTY: Object.freeze({ $$chan: 'empty', size: 0, zero: null }),
|
|
13
|
+
make: $$chan,
|
|
14
|
+
send: $$send,
|
|
15
|
+
receive: $$receive,
|
|
16
|
+
close: $$close,
|
|
17
|
+
range: $$range,
|
|
18
|
+
select: $$select,
|
|
19
|
+
// [] for a send and [value, ok] for a receive that goes on at once, else null.
|
|
20
|
+
try: (channel, send, value) => $$try(channel.$$chan, send, value),
|
|
21
|
+
fromStream: $$fromStream,
|
|
22
|
+
stream: $$stream,
|
|
23
|
+
after: $$after,
|
|
24
|
+
tick: $$tick,
|
|
25
|
+
signal: $$signal,
|
|
26
|
+
done: $$done,
|
|
27
|
+
abortSignal: $$abortSignal,
|
|
28
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Data classes: `data class Point` registers its class with an id of its own, the name and a hash
|
|
2
|
+
// of its code, the same in a module and in its worker module, which has a copy of the class. A copy
|
|
3
|
+
// of a value that goes to another thread loses the class of its instances (structuredClone); the
|
|
4
|
+
// thread that sends lists them with their ids (threads.js), and the one that gets the copy gives
|
|
5
|
+
// them their class again.
|
|
6
|
+
|
|
7
|
+
function registry() {
|
|
8
|
+
return (globalThis[Symbol.for('rook.classes')] ??= { byId: new Map(), ids: new WeakMap() });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function $$dataClass(cls, id) {
|
|
12
|
+
const { byId, ids } = registry();
|
|
13
|
+
|
|
14
|
+
byId.set(id, cls.prototype);
|
|
15
|
+
ids.set(cls.prototype, id);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The id of the data class of an instance, or undefined. */
|
|
19
|
+
export function $$classOf(value) {
|
|
20
|
+
return registry().ids.get(Object.getPrototypeOf(value));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Gives the copies of instances their classes back: `[object, id]` pairs of a copied message. */
|
|
24
|
+
export function $$reclass(instances) {
|
|
25
|
+
const { byId } = registry();
|
|
26
|
+
|
|
27
|
+
for (const [object, id] of instances) {
|
|
28
|
+
const prototype = byId.get(id);
|
|
29
|
+
|
|
30
|
+
if (prototype) Object.setPrototypeOf(object, prototype);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/runtime/core.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// What the code of any module may need: `for` over a value of unknown type, and
|
|
1
|
+
// What the code of any module may need: `for` over a value of unknown type, `defer`, and wrapped
|
|
2
|
+
// errors.
|
|
2
3
|
|
|
3
4
|
// `for v in x` over an untyped value: a Map gives its values, as a typed one does.
|
|
4
5
|
export function $$values(iterable) {
|
|
@@ -21,3 +22,11 @@ export function $$runDeferred(deferred) {
|
|
|
21
22
|
|
|
22
23
|
if (failure) throw failure.error;
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
// `error("load user", err)`: an error whose message ends with that of its cause, as `%w` of Go
|
|
27
|
+
// gives "load user: not found", and whose `cause` is the error itself, for code that looks at it.
|
|
28
|
+
export function $$wrap(message, cause) {
|
|
29
|
+
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
30
|
+
|
|
31
|
+
return new Error(`${message}: ${reason}`, { cause });
|
|
32
|
+
}
|