rooklang 0.0.0-stage → 0.3.1
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/LICENSE +21 -0
- package/README.md +177 -2
- package/README.ru.md +178 -0
- package/dist/ast/declarations.d.ts +185 -0
- package/dist/ast/declarations.js +1 -0
- package/dist/ast/expressions.d.ts +201 -0
- package/dist/ast/expressions.js +1 -0
- package/dist/ast/markup.d.ts +141 -0
- package/dist/ast/markup.js +1 -0
- package/dist/ast/statements.d.ts +173 -0
- package/dist/ast/statements.js +1 -0
- package/dist/ast.d.ts +18 -0
- package/dist/ast.js +18 -0
- package/dist/attrs.d.ts +8 -0
- package/dist/attrs.js +23 -0
- package/dist/browser.d.ts +30 -0
- package/dist/browser.js +36 -0
- package/dist/build.d.ts +48 -0
- package/dist/build.js +112 -0
- package/dist/checker/assignments.d.ts +14 -0
- package/dist/checker/assignments.js +197 -0
- package/dist/checker/base.d.ts +124 -0
- package/dist/checker/base.js +180 -0
- package/dist/checker/bigint.d.ts +15 -0
- package/dist/checker/bigint.js +85 -0
- package/dist/checker/builtins.d.ts +9 -0
- package/dist/checker/builtins.js +307 -0
- package/dist/checker/bytes.d.ts +11 -0
- package/dist/checker/bytes.js +72 -0
- package/dist/checker/calls.d.ts +23 -0
- package/dist/checker/calls.js +210 -0
- package/dist/checker/channel.d.ts +14 -0
- package/dist/checker/channel.js +44 -0
- package/dist/checker/channels.d.ts +9 -0
- package/dist/checker/channels.js +95 -0
- package/dist/checker/checker.d.ts +4 -0
- package/dist/checker/checker.js +22 -0
- package/dist/checker/classes.d.ts +24 -0
- package/dist/checker/classes.js +223 -0
- package/dist/checker/completion-names.d.ts +11 -0
- package/dist/checker/completion-names.js +100 -0
- package/dist/checker/completion.d.ts +25 -0
- package/dist/checker/completion.js +222 -0
- package/dist/checker/component-values.d.ts +11 -0
- package/dist/checker/component-values.js +88 -0
- package/dist/checker/components.d.ts +37 -0
- package/dist/checker/components.js +287 -0
- package/dist/checker/context.d.ts +196 -0
- package/dist/checker/context.js +35 -0
- package/dist/checker/control-flow.d.ts +24 -0
- package/dist/checker/control-flow.js +237 -0
- package/dist/checker/declarations.d.ts +26 -0
- package/dist/checker/declarations.js +259 -0
- package/dist/checker/decorator-exports.d.ts +5 -0
- package/dist/checker/decorator-exports.js +40 -0
- package/dist/checker/decorator-members.d.ts +28 -0
- package/dist/checker/decorator-members.js +140 -0
- package/dist/checker/decorator-wrappers.d.ts +20 -0
- package/dist/checker/decorator-wrappers.js +132 -0
- package/dist/checker/decorators.d.ts +28 -0
- package/dist/checker/decorators.js +265 -0
- package/dist/checker/dom-svg.d.ts +7 -0
- package/dist/checker/dom-svg.js +19 -0
- package/dist/checker/dom.d.ts +22 -0
- package/dist/checker/dom.js +361 -0
- package/dist/checker/expressions.d.ts +32 -0
- package/dist/checker/expressions.js +244 -0
- package/dist/checker/flow.d.ts +18 -0
- package/dist/checker/flow.js +134 -0
- package/dist/checker/forwarding.d.ts +15 -0
- package/dist/checker/forwarding.js +78 -0
- package/dist/checker/functions.d.ts +24 -0
- package/dist/checker/functions.js +154 -0
- package/dist/checker/go-for.d.ts +12 -0
- package/dist/checker/go-for.js +93 -0
- package/dist/checker/goroutines.d.ts +19 -0
- package/dist/checker/goroutines.js +110 -0
- package/dist/checker/helpers.d.ts +35 -0
- package/dist/checker/helpers.js +162 -0
- package/dist/checker/imports.d.ts +7 -0
- package/dist/checker/imports.js +83 -0
- package/dist/checker/initializers.d.ts +22 -0
- package/dist/checker/initializers.js +104 -0
- package/dist/checker/iterables.d.ts +5 -0
- package/dist/checker/iterables.js +17 -0
- package/dist/checker/iterators.d.ts +13 -0
- package/dist/checker/iterators.js +95 -0
- package/dist/checker/loops.d.ts +10 -0
- package/dist/checker/loops.js +82 -0
- package/dist/checker/markup.d.ts +28 -0
- package/dist/checker/markup.js +220 -0
- package/dist/checker/members.d.ts +29 -0
- package/dist/checker/members.js +233 -0
- package/dist/checker/operators.d.ts +13 -0
- package/dist/checker/operators.js +177 -0
- package/dist/checker/promise.d.ts +17 -0
- package/dist/checker/promise.js +49 -0
- package/dist/checker/refs.d.ts +26 -0
- package/dist/checker/refs.js +136 -0
- package/dist/checker/resolution.d.ts +23 -0
- package/dist/checker/resolution.js +173 -0
- package/dist/checker/statements.d.ts +28 -0
- package/dist/checker/statements.js +212 -0
- package/dist/checker/styles.d.ts +14 -0
- package/dist/checker/styles.js +49 -0
- package/dist/checker/transfer.d.ts +5 -0
- package/dist/checker/transfer.js +83 -0
- package/dist/checker/types/bytes.d.ts +4 -0
- package/dist/checker/types/bytes.js +51 -0
- package/dist/checker/types/classes.d.ts +22 -0
- package/dist/checker/types/classes.js +93 -0
- package/dist/checker/types/constructors.d.ts +27 -0
- package/dist/checker/types/constructors.js +129 -0
- package/dist/checker/types/generics.d.ts +20 -0
- package/dist/checker/types/generics.js +75 -0
- package/dist/checker/types/lazy.d.ts +30 -0
- package/dist/checker/types/lazy.js +92 -0
- package/dist/checker/types/model.d.ts +149 -0
- package/dist/checker/types/model.js +15 -0
- package/dist/checker/types/params.d.ts +7 -0
- package/dist/checker/types/params.js +220 -0
- package/dist/checker/types/printing.d.ts +6 -0
- package/dist/checker/types/printing.js +109 -0
- package/dist/checker/types/relations.d.ts +16 -0
- package/dist/checker/types/relations.js +294 -0
- package/dist/checker/types.d.ts +9 -0
- package/dist/checker/types.js +10 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +195 -0
- package/dist/codegen/analysis.d.ts +18 -0
- package/dist/codegen/analysis.js +144 -0
- package/dist/codegen/attributes.d.ts +40 -0
- package/dist/codegen/attributes.js +227 -0
- package/dist/codegen/calls.d.ts +22 -0
- package/dist/codegen/calls.js +106 -0
- package/dist/codegen/chan-helpers.d.ts +2 -0
- package/dist/codegen/chan-helpers.js +253 -0
- package/dist/codegen/component-helpers.d.ts +33 -0
- package/dist/codegen/component-helpers.js +18 -0
- package/dist/codegen/component-props.d.ts +42 -0
- package/dist/codegen/component-props.js +173 -0
- package/dist/codegen/component-values.d.ts +27 -0
- package/dist/codegen/component-values.js +146 -0
- package/dist/codegen/components.d.ts +53 -0
- package/dist/codegen/components.js +268 -0
- package/dist/codegen/control-flow.d.ts +25 -0
- package/dist/codegen/control-flow.js +152 -0
- package/dist/codegen/control-statements.d.ts +28 -0
- package/dist/codegen/control-statements.js +226 -0
- package/dist/codegen/creation.d.ts +31 -0
- package/dist/codegen/creation.js +113 -0
- package/dist/codegen/early-returns.d.ts +59 -0
- package/dist/codegen/early-returns.js +244 -0
- package/dist/codegen/element-helpers.d.ts +12 -0
- package/dist/codegen/element-helpers.js +54 -0
- package/dist/codegen/elements.d.ts +71 -0
- package/dist/codegen/elements.js +293 -0
- package/dist/codegen/emitter.d.ts +135 -0
- package/dist/codegen/emitter.js +296 -0
- package/dist/codegen/expressions.d.ts +49 -0
- package/dist/codegen/expressions.js +262 -0
- package/dist/codegen/functions.d.ts +28 -0
- package/dist/codegen/functions.js +170 -0
- package/dist/codegen/go-helpers.d.ts +9 -0
- package/dist/codegen/go-helpers.js +307 -0
- package/dist/codegen/helpers.d.ts +10 -0
- package/dist/codegen/helpers.js +356 -0
- package/dist/codegen/imported.d.ts +38 -0
- package/dist/codegen/imported.js +71 -0
- package/dist/codegen/js.d.ts +20 -0
- package/dist/codegen/js.js +113 -0
- package/dist/codegen/mutations.d.ts +10 -0
- package/dist/codegen/mutations.js +102 -0
- package/dist/codegen/parallel.d.ts +7 -0
- package/dist/codegen/parallel.js +63 -0
- package/dist/codegen/reactive.d.ts +95 -0
- package/dist/codegen/reactive.js +280 -0
- package/dist/codegen/refs.d.ts +62 -0
- package/dist/codegen/refs.js +160 -0
- package/dist/codegen/select-helpers.d.ts +2 -0
- package/dist/codegen/select-helpers.js +135 -0
- package/dist/codegen/simple-statements.d.ts +42 -0
- package/dist/codegen/simple-statements.js +253 -0
- package/dist/codegen/statements.d.ts +22 -0
- package/dist/codegen/statements.js +142 -0
- package/dist/codegen/styles.d.ts +54 -0
- package/dist/codegen/styles.js +157 -0
- package/dist/codegen/syntax.d.ts +18 -0
- package/dist/codegen/syntax.js +70 -0
- package/dist/codegen/thread-helpers.d.ts +2 -0
- package/dist/codegen/thread-helpers.js +198 -0
- package/dist/codegen/updates.d.ts +51 -0
- package/dist/codegen/updates.js +201 -0
- package/dist/codegen/web-components.d.ts +20 -0
- package/dist/codegen/web-components.js +149 -0
- package/dist/compile-file.d.ts +11 -0
- package/dist/compile-file.js +24 -0
- package/dist/compile.d.ts +53 -0
- package/dist/compile.js +187 -0
- package/dist/completion.d.ts +10 -0
- package/dist/completion.js +134 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +44 -0
- package/dist/css/hash.d.ts +1 -0
- package/dist/css/hash.js +10 -0
- package/dist/css/parse.d.ts +42 -0
- package/dist/css/parse.js +138 -0
- package/dist/css/print.d.ts +9 -0
- package/dist/css/print.js +35 -0
- package/dist/css/selectors.d.ts +29 -0
- package/dist/css/selectors.js +168 -0
- package/dist/declarations.d.ts +3 -0
- package/dist/declarations.js +207 -0
- package/dist/decorator-copy.d.ts +18 -0
- package/dist/decorator-copy.js +158 -0
- package/dist/decorators.d.ts +61 -0
- package/dist/decorators.js +241 -0
- package/dist/diagnostics.d.ts +17 -0
- package/dist/diagnostics.js +22 -0
- package/dist/go-for.d.ts +26 -0
- package/dist/go-for.js +155 -0
- package/dist/goroutines.d.ts +37 -0
- package/dist/goroutines.js +253 -0
- package/dist/html-tag.d.ts +21 -0
- package/dist/html-tag.js +103 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +55 -0
- package/dist/inline-packages.d.ts +32 -0
- package/dist/inline-packages.js +129 -0
- package/dist/iterators.d.ts +10 -0
- package/dist/iterators.js +33 -0
- package/dist/lexer/base.d.ts +24 -0
- package/dist/lexer/base.js +87 -0
- package/dist/lexer/lexer.d.ts +8 -0
- package/dist/lexer/lexer.js +134 -0
- package/dist/lexer/literals.d.ts +18 -0
- package/dist/lexer/literals.js +203 -0
- package/dist/lexer/markup.d.ts +10 -0
- package/dist/lexer/markup.js +93 -0
- package/dist/lexer/style.d.ts +17 -0
- package/dist/lexer/style.js +97 -0
- package/dist/lexer/tables.d.ts +53 -0
- package/dist/lexer/tables.js +101 -0
- package/dist/lexer/token.d.ts +42 -0
- package/dist/lexer/token.js +108 -0
- package/dist/loader.d.ts +1 -0
- package/dist/loader.js +50 -0
- package/dist/methods.d.ts +5 -0
- package/dist/methods.js +81 -0
- package/dist/modules.d.ts +3 -0
- package/dist/modules.js +49 -0
- package/dist/names.d.ts +23 -0
- package/dist/names.js +267 -0
- package/dist/parser/base.d.ts +96 -0
- package/dist/parser/base.js +202 -0
- package/dist/parser/classes.d.ts +8 -0
- package/dist/parser/classes.js +164 -0
- package/dist/parser/control-flow.d.ts +29 -0
- package/dist/parser/control-flow.js +232 -0
- package/dist/parser/declarations.d.ts +27 -0
- package/dist/parser/declarations.js +238 -0
- package/dist/parser/decorators.d.ts +30 -0
- package/dist/parser/decorators.js +176 -0
- package/dist/parser/expressions.d.ts +15 -0
- package/dist/parser/expressions.js +255 -0
- package/dist/parser/literals.d.ts +27 -0
- package/dist/parser/literals.js +206 -0
- package/dist/parser/markup.d.ts +22 -0
- package/dist/parser/markup.js +193 -0
- package/dist/parser/parser.d.ts +14 -0
- package/dist/parser/parser.js +22 -0
- package/dist/parser/simple-statements.d.ts +22 -0
- package/dist/parser/simple-statements.js +156 -0
- package/dist/parser/statements.d.ts +37 -0
- package/dist/parser/statements.js +267 -0
- package/dist/parser/syntax.d.ts +51 -0
- package/dist/parser/syntax.js +173 -0
- package/dist/parser/types.d.ts +23 -0
- package/dist/parser/types.js +218 -0
- package/dist/recursion.d.ts +25 -0
- package/dist/recursion.js +170 -0
- package/dist/refs.d.ts +49 -0
- package/dist/refs.js +210 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +21 -0
- package/dist/source.d.ts +15 -0
- package/dist/source.js +34 -0
- package/dist/style-modules.d.ts +17 -0
- package/dist/style-modules.js +49 -0
- package/dist/styles.d.ts +36 -0
- package/dist/styles.js +160 -0
- package/dist/svg.d.ts +8 -0
- package/dist/svg.js +77 -0
- package/dist/ts-types.d.ts +11 -0
- package/dist/ts-types.js +133 -0
- package/dist/typed-arrays.d.ts +8 -0
- package/dist/typed-arrays.js +43 -0
- package/dist/typescript/convert-base.d.ts +42 -0
- package/dist/typescript/convert-base.js +135 -0
- package/dist/typescript/convert-objects.d.ts +28 -0
- package/dist/typescript/convert-objects.js +245 -0
- package/dist/typescript/convert.d.ts +14 -0
- package/dist/typescript/convert.js +67 -0
- package/dist/typescript/importer.d.ts +37 -0
- package/dist/typescript/importer.js +152 -0
- package/dist/typescript/library.d.ts +23 -0
- package/dist/typescript/library.js +81 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +86 -0
- package/dist/walk-types.d.ts +4 -0
- package/dist/walk-types.js +56 -0
- package/dist/walk.d.ts +5 -0
- package/dist/walk.js +315 -0
- package/package.json +105 -4
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { ControlFlowParser } from "./control-flow.js";
|
|
2
|
+
import { describe, FUNCTION_BODY } from "./syntax.js";
|
|
3
|
+
// Imports and exports, functions and components with their parameters and results.
|
|
4
|
+
export class DeclarationParser extends ControlFlowParser {
|
|
5
|
+
parseImport() {
|
|
6
|
+
const start = this.next().start;
|
|
7
|
+
if (!this.context.topLevel) {
|
|
8
|
+
this.error('imports are only allowed at the top level of a module', start, this.span(start).end);
|
|
9
|
+
}
|
|
10
|
+
let defaultImport = null;
|
|
11
|
+
let namespaceImport = null;
|
|
12
|
+
let namedImports = [];
|
|
13
|
+
if (!this.check('String')) {
|
|
14
|
+
const hasDefault = this.check('Identifier');
|
|
15
|
+
if (hasDefault)
|
|
16
|
+
defaultImport = this.parseIdentifier('import name');
|
|
17
|
+
if (!hasDefault || this.accept(',')) {
|
|
18
|
+
if (this.accept('*')) {
|
|
19
|
+
this.expectWord('as');
|
|
20
|
+
namespaceImport = this.parseIdentifier('namespace name');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
this.expect('{', '"{", "*" or a name');
|
|
24
|
+
namedImports = this.parseList('}', () => this.parseImportSpecifier());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
this.expectWord('from');
|
|
28
|
+
}
|
|
29
|
+
const source = this.parseStringLiteral('module path');
|
|
30
|
+
const declaration = {
|
|
31
|
+
kind: 'ImportDeclaration',
|
|
32
|
+
defaultImport,
|
|
33
|
+
namespaceImport,
|
|
34
|
+
namedImports,
|
|
35
|
+
source,
|
|
36
|
+
...this.span(start),
|
|
37
|
+
};
|
|
38
|
+
this.endStatement();
|
|
39
|
+
return declaration;
|
|
40
|
+
}
|
|
41
|
+
parseImportSpecifier() {
|
|
42
|
+
const token = this.peek();
|
|
43
|
+
const imported = this.parsePropertyName('import name');
|
|
44
|
+
let local = imported;
|
|
45
|
+
if (this.acceptWord('as')) {
|
|
46
|
+
local = this.parseIdentifier('import name');
|
|
47
|
+
}
|
|
48
|
+
else if (token.kind !== 'Identifier') {
|
|
49
|
+
this.error(`"${token.text}" is a keyword: rename it with "as"`, token.start, token.end);
|
|
50
|
+
}
|
|
51
|
+
return { kind: 'ImportSpecifier', imported, local, ...this.span(token.start) };
|
|
52
|
+
}
|
|
53
|
+
parseExport() {
|
|
54
|
+
const start = this.next().start;
|
|
55
|
+
if (!this.context.topLevel) {
|
|
56
|
+
this.error('"export" is only allowed at the top level of a module', start, this.span(start).end);
|
|
57
|
+
}
|
|
58
|
+
return (this.parseDeclaration(start, true) ??
|
|
59
|
+
this.fail(`expected a declaration after "export", found ${describe(this.peek())}`));
|
|
60
|
+
}
|
|
61
|
+
parseFuncDeclaration(start, exported) {
|
|
62
|
+
const async = this.accept('async');
|
|
63
|
+
this.expect('func');
|
|
64
|
+
const name = this.parseIdentifier('function name');
|
|
65
|
+
const typeParams = this.parseTypeParams();
|
|
66
|
+
const params = this.parseParams(false);
|
|
67
|
+
const results = this.parseResults();
|
|
68
|
+
const body = this.parseFunctionBody(async);
|
|
69
|
+
return {
|
|
70
|
+
kind: 'FuncDeclaration',
|
|
71
|
+
exported,
|
|
72
|
+
isPublic: false,
|
|
73
|
+
...(async ? { async } : {}),
|
|
74
|
+
name,
|
|
75
|
+
typeParams,
|
|
76
|
+
params,
|
|
77
|
+
results,
|
|
78
|
+
body,
|
|
79
|
+
...this.span(start),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `<T any, U Shape>` after a name; `<K, V any>` gives both the constraint, as in Go.
|
|
84
|
+
*/
|
|
85
|
+
parseTypeParams() {
|
|
86
|
+
if (!this.check('<') || this.peek(1).kind !== 'Identifier')
|
|
87
|
+
return [];
|
|
88
|
+
this.next();
|
|
89
|
+
const params = [];
|
|
90
|
+
let pending = [];
|
|
91
|
+
const finish = (constraint) => {
|
|
92
|
+
for (const name of pending) {
|
|
93
|
+
params.push({
|
|
94
|
+
kind: 'TypeParameter',
|
|
95
|
+
name,
|
|
96
|
+
constraint,
|
|
97
|
+
start: name.start,
|
|
98
|
+
end: constraint?.end ?? name.end,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
pending = [];
|
|
102
|
+
};
|
|
103
|
+
do {
|
|
104
|
+
pending.push(this.parseIdentifier('type parameter name'));
|
|
105
|
+
if (!this.check(',') && !this.peek().kind.startsWith('>'))
|
|
106
|
+
finish(this.parseType());
|
|
107
|
+
} while (this.accept(','));
|
|
108
|
+
finish(null);
|
|
109
|
+
this.expectTypeClose('">" after the type parameters');
|
|
110
|
+
return params;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* `(a, b number, c string)`. Names without a type take the type of the next typed name, as in
|
|
114
|
+
* Go; only arrow functions may leave types out entirely.
|
|
115
|
+
*/
|
|
116
|
+
parseParams(typesOptional, allowDefaults = false, allowRest = false) {
|
|
117
|
+
this.expect('(');
|
|
118
|
+
const params = [];
|
|
119
|
+
let untyped = 0;
|
|
120
|
+
while (!this.check(')')) {
|
|
121
|
+
if (this.check('...')) {
|
|
122
|
+
params.push(this.parseRestParam(allowRest));
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const name = this.parseIdentifier('parameter name');
|
|
126
|
+
const type = this.canStartType() ? this.parseType() : null;
|
|
127
|
+
const defaultValue = allowDefaults && this.accept('=') ? this.parseExpression() : null;
|
|
128
|
+
params.push({ kind: 'Parameter', name, type, defaultValue, ...this.span(name.start) });
|
|
129
|
+
if (type === null) {
|
|
130
|
+
untyped++;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
for (const param of params.slice(params.length - 1 - untyped))
|
|
134
|
+
param.type = type;
|
|
135
|
+
untyped = 0;
|
|
136
|
+
}
|
|
137
|
+
if (!this.accept(','))
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
this.expect(')');
|
|
141
|
+
if (untyped > 0 && !typesOptional) {
|
|
142
|
+
const param = params[params.length - untyped];
|
|
143
|
+
this.error(`missing type for parameter "${param.name.name}"`, param.start, param.end);
|
|
144
|
+
}
|
|
145
|
+
return params;
|
|
146
|
+
}
|
|
147
|
+
/** `...attrs`: the attributes that a component passes on to one of its elements. */
|
|
148
|
+
parseRestParam(allowed) {
|
|
149
|
+
const start = this.next().start;
|
|
150
|
+
const name = this.parseIdentifier('parameter name');
|
|
151
|
+
if (!allowed) {
|
|
152
|
+
this.error(`...${name.name} is only for components: it takes the attributes of an element`, start, name.end);
|
|
153
|
+
}
|
|
154
|
+
if (this.canStartType() || this.check('=')) {
|
|
155
|
+
const at = this.peek().start;
|
|
156
|
+
// After the error, the type and the default are read, so they are not reported again.
|
|
157
|
+
if (this.canStartType())
|
|
158
|
+
this.parseType();
|
|
159
|
+
if (this.accept('='))
|
|
160
|
+
this.parseExpression();
|
|
161
|
+
this.error(`...${name.name} has no type and no default: it gets the type of the element it is spread on`, at, this.span(at).end);
|
|
162
|
+
}
|
|
163
|
+
// After the error, the rest of the list is skipped up to the `)`.
|
|
164
|
+
if (this.check(',')) {
|
|
165
|
+
this.error(`...${name.name} is the last property of a component`, start, name.end);
|
|
166
|
+
while (!this.check(')') && !this.check('EOF'))
|
|
167
|
+
this.next();
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
kind: 'Parameter',
|
|
171
|
+
name,
|
|
172
|
+
type: null,
|
|
173
|
+
defaultValue: null,
|
|
174
|
+
rest: true,
|
|
175
|
+
...this.span(start),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** Result types after a parameter list: nothing, `T`, or `(T1, T2)`. */
|
|
179
|
+
parseResults() {
|
|
180
|
+
if (this.accept('('))
|
|
181
|
+
return this.parseList(')', () => this.parseType());
|
|
182
|
+
// `{` after the parameters starts the body, so an object result type needs parentheses.
|
|
183
|
+
if (this.canStartType() && !this.check('{'))
|
|
184
|
+
return [this.parseType()];
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
/** `comp Name(properties) { ...; return <markup> }`, maybe after decorators. */
|
|
188
|
+
parseComponent(start, exported, htmlTag = null, decorators = []) {
|
|
189
|
+
this.requireMarkup('components are');
|
|
190
|
+
const keyword = this.expect('comp');
|
|
191
|
+
if (!this.context.topLevel) {
|
|
192
|
+
this.error('components can only be declared at the top level of a module', keyword.start, keyword.end);
|
|
193
|
+
}
|
|
194
|
+
const name = this.parseIdentifier('component name');
|
|
195
|
+
// A web component is used by its tag, so its name may start with a lowercase letter.
|
|
196
|
+
if (!htmlTag && !/^[A-Z]/.test(name.name)) {
|
|
197
|
+
this.error(`component names start with a capital letter, as in <${name.name.charAt(0).toUpperCase()}${name.name.slice(1)} />`, name.start, name.end);
|
|
198
|
+
}
|
|
199
|
+
const params = this.parseParams(false, true, true);
|
|
200
|
+
const body = this.withContext({ ...FUNCTION_BODY, inComponent: true }, () => this.parseComponentBody());
|
|
201
|
+
return {
|
|
202
|
+
kind: 'ComponentDeclaration',
|
|
203
|
+
exported,
|
|
204
|
+
name,
|
|
205
|
+
params,
|
|
206
|
+
body,
|
|
207
|
+
htmlTag,
|
|
208
|
+
decorators,
|
|
209
|
+
...this.span(start),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/** Like a function body, but its own statements may also declare `state`, `ref` and `mount()`. */
|
|
213
|
+
parseComponentBody() {
|
|
214
|
+
const start = this.expect('{').start;
|
|
215
|
+
const body = [];
|
|
216
|
+
this.parseSeparated(() => this.check('}'), () => body.push(this.parseComponentStatement()));
|
|
217
|
+
this.expect('}');
|
|
218
|
+
return { kind: 'BlockStatement', body, ...this.span(start) };
|
|
219
|
+
}
|
|
220
|
+
/** A statement at the top level of a component or a decorator. */
|
|
221
|
+
parseComponentStatement() {
|
|
222
|
+
if (this.isStyleBlock()) {
|
|
223
|
+
const style = this.parseStyle();
|
|
224
|
+
this.endStatement();
|
|
225
|
+
return style;
|
|
226
|
+
}
|
|
227
|
+
if (this.isMountDeclaration() || this.isEffectDeclaration()) {
|
|
228
|
+
const statement = this.isMountDeclaration() ? this.parseMount() : this.parseEffect();
|
|
229
|
+
this.endStatement();
|
|
230
|
+
return statement;
|
|
231
|
+
}
|
|
232
|
+
if (!this.isStateDeclaration() && !this.isRefDeclaration())
|
|
233
|
+
return this.parseStatement();
|
|
234
|
+
const declaration = this.parseVariableDeclaration(this.peek().start, false);
|
|
235
|
+
this.endStatement();
|
|
236
|
+
return declaration;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { DeclarationParser } from './declarations.ts';
|
|
3
|
+
export declare abstract class DecoratorParser extends DeclarationParser {
|
|
4
|
+
/** `dec visible(margin string = "0px") { ... }`: `dec` is a keyword only here. */
|
|
5
|
+
protected isDecoratorDeclaration(): boolean;
|
|
6
|
+
protected parseDecoratorDeclaration(start: number, exported: boolean): ast.DecoratorDeclaration;
|
|
7
|
+
/** `needs cart, auth` after the parameters: `needs` is a keyword only here. */
|
|
8
|
+
protected parseNeeds(): ast.Identifier[];
|
|
9
|
+
/** Like the body of a component, but `state`, `const` and `func` may be `public`. */
|
|
10
|
+
protected parseDecoratorBody(): ast.BlockStatement;
|
|
11
|
+
/** `public` followed by a declaration; `public = 1` assigns a variable named `public`. */
|
|
12
|
+
protected isPublicModifier(): boolean;
|
|
13
|
+
protected parsePublicMember(): ast.VariableDeclaration | ast.FuncDeclaration;
|
|
14
|
+
/**
|
|
15
|
+
* The decorators before `comp`: `@html-tag` first, then the others in the order they apply.
|
|
16
|
+
* Each is on its own line or followed by the next one.
|
|
17
|
+
*/
|
|
18
|
+
protected parseDecorated(start: number, exported: boolean): ast.ComponentDeclaration;
|
|
19
|
+
protected isHtmlTag(): boolean;
|
|
20
|
+
/** `@html-tag` or `@html-tag("app-page")`. */
|
|
21
|
+
protected parseHtmlTag(): ast.HtmlTag;
|
|
22
|
+
/** `@visible("300px")` or `@visible`: the arguments are positional, as in a call. */
|
|
23
|
+
protected parseDecoratorUse(): ast.DecoratorUse;
|
|
24
|
+
/** `@visible.show`: a member of a decorator; a statement may start with it. */
|
|
25
|
+
protected isDecoratorMember(): boolean;
|
|
26
|
+
protected parseDecoratorMember(): ast.DecoratorMember;
|
|
27
|
+
/** `get(@visible.shown)`: `get` is special only when its argument starts with `@`. */
|
|
28
|
+
protected isDecoratorGet(): boolean;
|
|
29
|
+
protected parseDecoratorGet(): ast.DecoratorGet;
|
|
30
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { DeclarationParser } from "./declarations.js";
|
|
2
|
+
import { describe, FUNCTION_BODY } from "./syntax.js";
|
|
3
|
+
// Decorators: their declarations `dec name(...) { ... }`, the decorators written before `comp`
|
|
4
|
+
// (`@html-tag` and `@visible("300px")`), and the access to their members, `get(@visible.shown)`
|
|
5
|
+
// and `@visible.show()`.
|
|
6
|
+
export class DecoratorParser extends DeclarationParser {
|
|
7
|
+
/** `dec visible(margin string = "0px") { ... }`: `dec` is a keyword only here. */
|
|
8
|
+
isDecoratorDeclaration() {
|
|
9
|
+
return this.checkWord('dec') && this.peek(1).kind === 'Identifier';
|
|
10
|
+
}
|
|
11
|
+
parseDecoratorDeclaration(start, exported) {
|
|
12
|
+
this.requireMarkup('decorators are');
|
|
13
|
+
const keyword = this.next();
|
|
14
|
+
if (!this.context.topLevel) {
|
|
15
|
+
this.error('decorators can only be declared at the top level of a module', keyword.start, keyword.end);
|
|
16
|
+
}
|
|
17
|
+
const name = this.parseIdentifier('decorator name');
|
|
18
|
+
const params = this.parseParams(false, true);
|
|
19
|
+
const needs = this.parseNeeds();
|
|
20
|
+
const body = this.withContext({ ...FUNCTION_BODY, inComponent: true }, () => this.parseDecoratorBody());
|
|
21
|
+
return {
|
|
22
|
+
kind: 'DecoratorDeclaration',
|
|
23
|
+
exported,
|
|
24
|
+
name,
|
|
25
|
+
params,
|
|
26
|
+
needs,
|
|
27
|
+
body,
|
|
28
|
+
...this.span(start),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** `needs cart, auth` after the parameters: `needs` is a keyword only here. */
|
|
32
|
+
parseNeeds() {
|
|
33
|
+
if (!this.checkWord('needs'))
|
|
34
|
+
return [];
|
|
35
|
+
if (this.peek(1).kind !== 'Identifier') {
|
|
36
|
+
this.fail('"needs" is followed by the decorators this one uses, e.g. needs cart');
|
|
37
|
+
}
|
|
38
|
+
this.next();
|
|
39
|
+
const needs = [this.parseIdentifier('decorator name')];
|
|
40
|
+
while (this.accept(','))
|
|
41
|
+
needs.push(this.parseIdentifier('decorator name'));
|
|
42
|
+
return needs;
|
|
43
|
+
}
|
|
44
|
+
/** Like the body of a component, but `state`, `const` and `func` may be `public`. */
|
|
45
|
+
parseDecoratorBody() {
|
|
46
|
+
const start = this.expect('{').start;
|
|
47
|
+
const body = [];
|
|
48
|
+
this.parseSeparated(() => this.check('}'), () => {
|
|
49
|
+
if (this.isPublicModifier())
|
|
50
|
+
body.push(this.parsePublicMember());
|
|
51
|
+
else
|
|
52
|
+
body.push(this.parseComponentStatement());
|
|
53
|
+
});
|
|
54
|
+
this.expect('}');
|
|
55
|
+
return { kind: 'BlockStatement', body, ...this.span(start) };
|
|
56
|
+
}
|
|
57
|
+
/** `public` followed by a declaration; `public = 1` assigns a variable named `public`. */
|
|
58
|
+
isPublicModifier() {
|
|
59
|
+
const next = this.peek(1).kind;
|
|
60
|
+
return (this.checkWord('public') &&
|
|
61
|
+
(next === 'Identifier' ||
|
|
62
|
+
next === 'let' ||
|
|
63
|
+
next === 'const' ||
|
|
64
|
+
next === 'func' ||
|
|
65
|
+
next === 'async'));
|
|
66
|
+
}
|
|
67
|
+
parsePublicMember() {
|
|
68
|
+
const modifier = this.next();
|
|
69
|
+
if (this.check('func') || this.check('async')) {
|
|
70
|
+
const declaration = this.parseFuncDeclaration(modifier.start, false);
|
|
71
|
+
declaration.isPublic = true;
|
|
72
|
+
return declaration;
|
|
73
|
+
}
|
|
74
|
+
if (!this.check('const') && !this.check('let') && !this.isStateDeclaration()) {
|
|
75
|
+
this.fail(`only state, derived, const and func can be public, not ${describe(this.peek())}`);
|
|
76
|
+
}
|
|
77
|
+
const declaration = this.parseVariableDeclaration(modifier.start, false);
|
|
78
|
+
this.endStatement();
|
|
79
|
+
if (declaration.keyword === 'let') {
|
|
80
|
+
this.error('a decorator has no "public let": a value that changes and is read outside is a state, one that does not change is a const', modifier.start, declaration.end);
|
|
81
|
+
}
|
|
82
|
+
declaration.isPublic = true;
|
|
83
|
+
return declaration;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The decorators before `comp`: `@html-tag` first, then the others in the order they apply.
|
|
87
|
+
* Each is on its own line or followed by the next one.
|
|
88
|
+
*/
|
|
89
|
+
parseDecorated(start, exported) {
|
|
90
|
+
this.requireMarkup('decorators are');
|
|
91
|
+
let htmlTag = null;
|
|
92
|
+
const decorators = [];
|
|
93
|
+
while (this.check('@')) {
|
|
94
|
+
if (this.isHtmlTag()) {
|
|
95
|
+
const node = this.parseHtmlTag();
|
|
96
|
+
if (htmlTag) {
|
|
97
|
+
this.error('@html-tag is written once', node.start, node.end);
|
|
98
|
+
}
|
|
99
|
+
else if (decorators.length > 0) {
|
|
100
|
+
this.error('@html-tag must be the first decorator: the element is built from what the others give', node.start, node.end);
|
|
101
|
+
}
|
|
102
|
+
htmlTag ??= node;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
decorators.push(this.parseDecoratorUse());
|
|
106
|
+
}
|
|
107
|
+
// A line break after the decorator inserted a semicolon.
|
|
108
|
+
if (this.isImplicitSemicolon())
|
|
109
|
+
this.next();
|
|
110
|
+
}
|
|
111
|
+
const isExported = this.accept('export') || exported;
|
|
112
|
+
if (!this.check('comp')) {
|
|
113
|
+
this.fail(`decorators are written before a component, as in @${decorators[0]?.name.name ?? 'html-tag'} comp MainPage() { ... }`);
|
|
114
|
+
}
|
|
115
|
+
return this.parseComponent(start, isExported, htmlTag, decorators);
|
|
116
|
+
}
|
|
117
|
+
isHtmlTag() {
|
|
118
|
+
return (this.peek(1).kind === 'Identifier' &&
|
|
119
|
+
this.peek(1).text === 'html' &&
|
|
120
|
+
this.peek(2).kind === '-' &&
|
|
121
|
+
this.peek(3).kind === 'Identifier' &&
|
|
122
|
+
this.peek(3).text === 'tag');
|
|
123
|
+
}
|
|
124
|
+
/** `@html-tag` or `@html-tag("app-page")`. */
|
|
125
|
+
parseHtmlTag() {
|
|
126
|
+
const at = this.expect('@');
|
|
127
|
+
this.next();
|
|
128
|
+
this.next();
|
|
129
|
+
this.next();
|
|
130
|
+
let name = null;
|
|
131
|
+
if (this.accept('(')) {
|
|
132
|
+
name = this.parseStringLiteral('tag name');
|
|
133
|
+
this.expect(')');
|
|
134
|
+
}
|
|
135
|
+
return { kind: 'HtmlTag', name, ...this.span(at.start) };
|
|
136
|
+
}
|
|
137
|
+
/** `@visible("300px")` or `@visible`: the arguments are positional, as in a call. */
|
|
138
|
+
parseDecoratorUse() {
|
|
139
|
+
const at = this.expect('@');
|
|
140
|
+
const name = this.parseIdentifier('decorator name');
|
|
141
|
+
const args = this.check('(') ? this.parseArguments() : [];
|
|
142
|
+
const spread = args.find((arg) => arg.kind === 'SpreadElement');
|
|
143
|
+
if (spread) {
|
|
144
|
+
this.error('arguments of a decorator cannot be spread', spread.start, spread.end);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
kind: 'DecoratorUse',
|
|
148
|
+
name,
|
|
149
|
+
arguments: args.filter((arg) => arg.kind !== 'SpreadElement'),
|
|
150
|
+
...this.span(at.start),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** `@visible.show`: a member of a decorator; a statement may start with it. */
|
|
154
|
+
isDecoratorMember() {
|
|
155
|
+
return this.check('@') && this.peek(1).kind === 'Identifier' && this.peek(2).kind === '.';
|
|
156
|
+
}
|
|
157
|
+
parseDecoratorMember() {
|
|
158
|
+
this.requireMarkup('decorators are');
|
|
159
|
+
const at = this.expect('@');
|
|
160
|
+
const decorator = this.parseIdentifier('decorator name');
|
|
161
|
+
this.expect('.', '"." and a member, e.g. @visible.show()');
|
|
162
|
+
const member = this.parsePropertyName('member name');
|
|
163
|
+
return { kind: 'DecoratorMember', decorator, member, ...this.span(at.start) };
|
|
164
|
+
}
|
|
165
|
+
/** `get(@visible.shown)`: `get` is special only when its argument starts with `@`. */
|
|
166
|
+
isDecoratorGet() {
|
|
167
|
+
return this.checkWord('get') && this.peek(1).kind === '(' && this.peek(2).kind === '@';
|
|
168
|
+
}
|
|
169
|
+
parseDecoratorGet() {
|
|
170
|
+
const start = this.next().start;
|
|
171
|
+
this.expect('(');
|
|
172
|
+
const target = this.parseDecoratorMember();
|
|
173
|
+
this.expect(')', '")": get takes one member of a decorator, e.g. get(@visible.shown)');
|
|
174
|
+
return { kind: 'DecoratorGet', target, ...this.span(start) };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { TypeParser } from './types.ts';
|
|
3
|
+
export declare abstract class ExpressionParser extends TypeParser {
|
|
4
|
+
protected parseExpression(): ast.Expression;
|
|
5
|
+
/** Precedence climbing: parses operators that bind at least as tight as `minPrecedence`. */
|
|
6
|
+
protected parseBinary(minPrecedence: number): ast.Expression;
|
|
7
|
+
/** Rejects combinations that JS forbids without parentheses, since the output must be valid JS. */
|
|
8
|
+
protected makeBinary(operator: ast.BinaryOperator, left: ast.Expression, right: ast.Expression): ast.BinaryExpression;
|
|
9
|
+
protected parseUnary(): ast.Expression;
|
|
10
|
+
/** `make([]float64` starts a `make`: an array literal is not followed by a name. */
|
|
11
|
+
private isMake;
|
|
12
|
+
/** Member access, indexing and calls: `a.b`, `a?.b`, `a[i]`, `a?.[i]`, `f(x)`, `f?.(x)`. */
|
|
13
|
+
protected parsePostfix(expression: ast.Expression): ast.Expression;
|
|
14
|
+
protected parsePrimary(): ast.Expression;
|
|
15
|
+
}
|