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.
Files changed (314) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -2
  3. package/README.ru.md +178 -0
  4. package/dist/ast/declarations.d.ts +185 -0
  5. package/dist/ast/declarations.js +1 -0
  6. package/dist/ast/expressions.d.ts +201 -0
  7. package/dist/ast/expressions.js +1 -0
  8. package/dist/ast/markup.d.ts +141 -0
  9. package/dist/ast/markup.js +1 -0
  10. package/dist/ast/statements.d.ts +173 -0
  11. package/dist/ast/statements.js +1 -0
  12. package/dist/ast.d.ts +18 -0
  13. package/dist/ast.js +18 -0
  14. package/dist/attrs.d.ts +8 -0
  15. package/dist/attrs.js +23 -0
  16. package/dist/browser.d.ts +30 -0
  17. package/dist/browser.js +36 -0
  18. package/dist/build.d.ts +48 -0
  19. package/dist/build.js +112 -0
  20. package/dist/checker/assignments.d.ts +14 -0
  21. package/dist/checker/assignments.js +197 -0
  22. package/dist/checker/base.d.ts +124 -0
  23. package/dist/checker/base.js +180 -0
  24. package/dist/checker/bigint.d.ts +15 -0
  25. package/dist/checker/bigint.js +85 -0
  26. package/dist/checker/builtins.d.ts +9 -0
  27. package/dist/checker/builtins.js +307 -0
  28. package/dist/checker/bytes.d.ts +11 -0
  29. package/dist/checker/bytes.js +72 -0
  30. package/dist/checker/calls.d.ts +23 -0
  31. package/dist/checker/calls.js +210 -0
  32. package/dist/checker/channel.d.ts +14 -0
  33. package/dist/checker/channel.js +44 -0
  34. package/dist/checker/channels.d.ts +9 -0
  35. package/dist/checker/channels.js +95 -0
  36. package/dist/checker/checker.d.ts +4 -0
  37. package/dist/checker/checker.js +22 -0
  38. package/dist/checker/classes.d.ts +24 -0
  39. package/dist/checker/classes.js +223 -0
  40. package/dist/checker/completion-names.d.ts +11 -0
  41. package/dist/checker/completion-names.js +100 -0
  42. package/dist/checker/completion.d.ts +25 -0
  43. package/dist/checker/completion.js +222 -0
  44. package/dist/checker/component-values.d.ts +11 -0
  45. package/dist/checker/component-values.js +88 -0
  46. package/dist/checker/components.d.ts +37 -0
  47. package/dist/checker/components.js +287 -0
  48. package/dist/checker/context.d.ts +196 -0
  49. package/dist/checker/context.js +35 -0
  50. package/dist/checker/control-flow.d.ts +24 -0
  51. package/dist/checker/control-flow.js +237 -0
  52. package/dist/checker/declarations.d.ts +26 -0
  53. package/dist/checker/declarations.js +259 -0
  54. package/dist/checker/decorator-exports.d.ts +5 -0
  55. package/dist/checker/decorator-exports.js +40 -0
  56. package/dist/checker/decorator-members.d.ts +28 -0
  57. package/dist/checker/decorator-members.js +140 -0
  58. package/dist/checker/decorator-wrappers.d.ts +20 -0
  59. package/dist/checker/decorator-wrappers.js +132 -0
  60. package/dist/checker/decorators.d.ts +28 -0
  61. package/dist/checker/decorators.js +265 -0
  62. package/dist/checker/dom-svg.d.ts +7 -0
  63. package/dist/checker/dom-svg.js +19 -0
  64. package/dist/checker/dom.d.ts +22 -0
  65. package/dist/checker/dom.js +361 -0
  66. package/dist/checker/expressions.d.ts +32 -0
  67. package/dist/checker/expressions.js +244 -0
  68. package/dist/checker/flow.d.ts +18 -0
  69. package/dist/checker/flow.js +134 -0
  70. package/dist/checker/forwarding.d.ts +15 -0
  71. package/dist/checker/forwarding.js +78 -0
  72. package/dist/checker/functions.d.ts +24 -0
  73. package/dist/checker/functions.js +154 -0
  74. package/dist/checker/go-for.d.ts +12 -0
  75. package/dist/checker/go-for.js +93 -0
  76. package/dist/checker/goroutines.d.ts +19 -0
  77. package/dist/checker/goroutines.js +110 -0
  78. package/dist/checker/helpers.d.ts +35 -0
  79. package/dist/checker/helpers.js +162 -0
  80. package/dist/checker/imports.d.ts +7 -0
  81. package/dist/checker/imports.js +83 -0
  82. package/dist/checker/initializers.d.ts +22 -0
  83. package/dist/checker/initializers.js +104 -0
  84. package/dist/checker/iterables.d.ts +5 -0
  85. package/dist/checker/iterables.js +17 -0
  86. package/dist/checker/iterators.d.ts +13 -0
  87. package/dist/checker/iterators.js +95 -0
  88. package/dist/checker/loops.d.ts +10 -0
  89. package/dist/checker/loops.js +82 -0
  90. package/dist/checker/markup.d.ts +28 -0
  91. package/dist/checker/markup.js +220 -0
  92. package/dist/checker/members.d.ts +29 -0
  93. package/dist/checker/members.js +233 -0
  94. package/dist/checker/operators.d.ts +13 -0
  95. package/dist/checker/operators.js +177 -0
  96. package/dist/checker/promise.d.ts +17 -0
  97. package/dist/checker/promise.js +49 -0
  98. package/dist/checker/refs.d.ts +26 -0
  99. package/dist/checker/refs.js +136 -0
  100. package/dist/checker/resolution.d.ts +23 -0
  101. package/dist/checker/resolution.js +173 -0
  102. package/dist/checker/statements.d.ts +28 -0
  103. package/dist/checker/statements.js +212 -0
  104. package/dist/checker/styles.d.ts +14 -0
  105. package/dist/checker/styles.js +49 -0
  106. package/dist/checker/transfer.d.ts +5 -0
  107. package/dist/checker/transfer.js +83 -0
  108. package/dist/checker/types/bytes.d.ts +4 -0
  109. package/dist/checker/types/bytes.js +51 -0
  110. package/dist/checker/types/classes.d.ts +22 -0
  111. package/dist/checker/types/classes.js +93 -0
  112. package/dist/checker/types/constructors.d.ts +27 -0
  113. package/dist/checker/types/constructors.js +129 -0
  114. package/dist/checker/types/generics.d.ts +20 -0
  115. package/dist/checker/types/generics.js +75 -0
  116. package/dist/checker/types/lazy.d.ts +30 -0
  117. package/dist/checker/types/lazy.js +92 -0
  118. package/dist/checker/types/model.d.ts +149 -0
  119. package/dist/checker/types/model.js +15 -0
  120. package/dist/checker/types/params.d.ts +7 -0
  121. package/dist/checker/types/params.js +220 -0
  122. package/dist/checker/types/printing.d.ts +6 -0
  123. package/dist/checker/types/printing.js +109 -0
  124. package/dist/checker/types/relations.d.ts +16 -0
  125. package/dist/checker/types/relations.js +294 -0
  126. package/dist/checker/types.d.ts +9 -0
  127. package/dist/checker/types.js +10 -0
  128. package/dist/cli.d.ts +2 -0
  129. package/dist/cli.js +195 -0
  130. package/dist/codegen/analysis.d.ts +18 -0
  131. package/dist/codegen/analysis.js +144 -0
  132. package/dist/codegen/attributes.d.ts +40 -0
  133. package/dist/codegen/attributes.js +227 -0
  134. package/dist/codegen/calls.d.ts +22 -0
  135. package/dist/codegen/calls.js +106 -0
  136. package/dist/codegen/chan-helpers.d.ts +2 -0
  137. package/dist/codegen/chan-helpers.js +253 -0
  138. package/dist/codegen/component-helpers.d.ts +33 -0
  139. package/dist/codegen/component-helpers.js +18 -0
  140. package/dist/codegen/component-props.d.ts +42 -0
  141. package/dist/codegen/component-props.js +173 -0
  142. package/dist/codegen/component-values.d.ts +27 -0
  143. package/dist/codegen/component-values.js +146 -0
  144. package/dist/codegen/components.d.ts +53 -0
  145. package/dist/codegen/components.js +268 -0
  146. package/dist/codegen/control-flow.d.ts +25 -0
  147. package/dist/codegen/control-flow.js +152 -0
  148. package/dist/codegen/control-statements.d.ts +28 -0
  149. package/dist/codegen/control-statements.js +226 -0
  150. package/dist/codegen/creation.d.ts +31 -0
  151. package/dist/codegen/creation.js +113 -0
  152. package/dist/codegen/early-returns.d.ts +59 -0
  153. package/dist/codegen/early-returns.js +244 -0
  154. package/dist/codegen/element-helpers.d.ts +12 -0
  155. package/dist/codegen/element-helpers.js +54 -0
  156. package/dist/codegen/elements.d.ts +71 -0
  157. package/dist/codegen/elements.js +293 -0
  158. package/dist/codegen/emitter.d.ts +135 -0
  159. package/dist/codegen/emitter.js +296 -0
  160. package/dist/codegen/expressions.d.ts +49 -0
  161. package/dist/codegen/expressions.js +262 -0
  162. package/dist/codegen/functions.d.ts +28 -0
  163. package/dist/codegen/functions.js +170 -0
  164. package/dist/codegen/go-helpers.d.ts +9 -0
  165. package/dist/codegen/go-helpers.js +307 -0
  166. package/dist/codegen/helpers.d.ts +10 -0
  167. package/dist/codegen/helpers.js +356 -0
  168. package/dist/codegen/imported.d.ts +38 -0
  169. package/dist/codegen/imported.js +71 -0
  170. package/dist/codegen/js.d.ts +20 -0
  171. package/dist/codegen/js.js +113 -0
  172. package/dist/codegen/mutations.d.ts +10 -0
  173. package/dist/codegen/mutations.js +102 -0
  174. package/dist/codegen/parallel.d.ts +7 -0
  175. package/dist/codegen/parallel.js +63 -0
  176. package/dist/codegen/reactive.d.ts +95 -0
  177. package/dist/codegen/reactive.js +280 -0
  178. package/dist/codegen/refs.d.ts +62 -0
  179. package/dist/codegen/refs.js +160 -0
  180. package/dist/codegen/select-helpers.d.ts +2 -0
  181. package/dist/codegen/select-helpers.js +135 -0
  182. package/dist/codegen/simple-statements.d.ts +42 -0
  183. package/dist/codegen/simple-statements.js +253 -0
  184. package/dist/codegen/statements.d.ts +22 -0
  185. package/dist/codegen/statements.js +142 -0
  186. package/dist/codegen/styles.d.ts +54 -0
  187. package/dist/codegen/styles.js +157 -0
  188. package/dist/codegen/syntax.d.ts +18 -0
  189. package/dist/codegen/syntax.js +70 -0
  190. package/dist/codegen/thread-helpers.d.ts +2 -0
  191. package/dist/codegen/thread-helpers.js +198 -0
  192. package/dist/codegen/updates.d.ts +51 -0
  193. package/dist/codegen/updates.js +201 -0
  194. package/dist/codegen/web-components.d.ts +20 -0
  195. package/dist/codegen/web-components.js +149 -0
  196. package/dist/compile-file.d.ts +11 -0
  197. package/dist/compile-file.js +24 -0
  198. package/dist/compile.d.ts +53 -0
  199. package/dist/compile.js +187 -0
  200. package/dist/completion.d.ts +10 -0
  201. package/dist/completion.js +134 -0
  202. package/dist/config.d.ts +2 -0
  203. package/dist/config.js +44 -0
  204. package/dist/css/hash.d.ts +1 -0
  205. package/dist/css/hash.js +10 -0
  206. package/dist/css/parse.d.ts +42 -0
  207. package/dist/css/parse.js +138 -0
  208. package/dist/css/print.d.ts +9 -0
  209. package/dist/css/print.js +35 -0
  210. package/dist/css/selectors.d.ts +29 -0
  211. package/dist/css/selectors.js +168 -0
  212. package/dist/declarations.d.ts +3 -0
  213. package/dist/declarations.js +207 -0
  214. package/dist/decorator-copy.d.ts +18 -0
  215. package/dist/decorator-copy.js +158 -0
  216. package/dist/decorators.d.ts +61 -0
  217. package/dist/decorators.js +241 -0
  218. package/dist/diagnostics.d.ts +17 -0
  219. package/dist/diagnostics.js +22 -0
  220. package/dist/go-for.d.ts +26 -0
  221. package/dist/go-for.js +155 -0
  222. package/dist/goroutines.d.ts +37 -0
  223. package/dist/goroutines.js +253 -0
  224. package/dist/html-tag.d.ts +21 -0
  225. package/dist/html-tag.js +103 -0
  226. package/dist/index.d.ts +33 -0
  227. package/dist/index.js +55 -0
  228. package/dist/inline-packages.d.ts +32 -0
  229. package/dist/inline-packages.js +129 -0
  230. package/dist/iterators.d.ts +10 -0
  231. package/dist/iterators.js +33 -0
  232. package/dist/lexer/base.d.ts +24 -0
  233. package/dist/lexer/base.js +87 -0
  234. package/dist/lexer/lexer.d.ts +8 -0
  235. package/dist/lexer/lexer.js +134 -0
  236. package/dist/lexer/literals.d.ts +18 -0
  237. package/dist/lexer/literals.js +203 -0
  238. package/dist/lexer/markup.d.ts +10 -0
  239. package/dist/lexer/markup.js +93 -0
  240. package/dist/lexer/style.d.ts +17 -0
  241. package/dist/lexer/style.js +97 -0
  242. package/dist/lexer/tables.d.ts +53 -0
  243. package/dist/lexer/tables.js +101 -0
  244. package/dist/lexer/token.d.ts +42 -0
  245. package/dist/lexer/token.js +108 -0
  246. package/dist/loader.d.ts +1 -0
  247. package/dist/loader.js +50 -0
  248. package/dist/methods.d.ts +5 -0
  249. package/dist/methods.js +81 -0
  250. package/dist/modules.d.ts +3 -0
  251. package/dist/modules.js +49 -0
  252. package/dist/names.d.ts +23 -0
  253. package/dist/names.js +267 -0
  254. package/dist/parser/base.d.ts +96 -0
  255. package/dist/parser/base.js +202 -0
  256. package/dist/parser/classes.d.ts +8 -0
  257. package/dist/parser/classes.js +164 -0
  258. package/dist/parser/control-flow.d.ts +29 -0
  259. package/dist/parser/control-flow.js +232 -0
  260. package/dist/parser/declarations.d.ts +27 -0
  261. package/dist/parser/declarations.js +238 -0
  262. package/dist/parser/decorators.d.ts +30 -0
  263. package/dist/parser/decorators.js +176 -0
  264. package/dist/parser/expressions.d.ts +15 -0
  265. package/dist/parser/expressions.js +255 -0
  266. package/dist/parser/literals.d.ts +27 -0
  267. package/dist/parser/literals.js +206 -0
  268. package/dist/parser/markup.d.ts +22 -0
  269. package/dist/parser/markup.js +193 -0
  270. package/dist/parser/parser.d.ts +14 -0
  271. package/dist/parser/parser.js +22 -0
  272. package/dist/parser/simple-statements.d.ts +22 -0
  273. package/dist/parser/simple-statements.js +156 -0
  274. package/dist/parser/statements.d.ts +37 -0
  275. package/dist/parser/statements.js +267 -0
  276. package/dist/parser/syntax.d.ts +51 -0
  277. package/dist/parser/syntax.js +173 -0
  278. package/dist/parser/types.d.ts +23 -0
  279. package/dist/parser/types.js +218 -0
  280. package/dist/recursion.d.ts +25 -0
  281. package/dist/recursion.js +170 -0
  282. package/dist/refs.d.ts +49 -0
  283. package/dist/refs.js +210 -0
  284. package/dist/run.d.ts +1 -0
  285. package/dist/run.js +21 -0
  286. package/dist/source.d.ts +15 -0
  287. package/dist/source.js +34 -0
  288. package/dist/style-modules.d.ts +17 -0
  289. package/dist/style-modules.js +49 -0
  290. package/dist/styles.d.ts +36 -0
  291. package/dist/styles.js +160 -0
  292. package/dist/svg.d.ts +8 -0
  293. package/dist/svg.js +77 -0
  294. package/dist/ts-types.d.ts +11 -0
  295. package/dist/ts-types.js +133 -0
  296. package/dist/typed-arrays.d.ts +8 -0
  297. package/dist/typed-arrays.js +43 -0
  298. package/dist/typescript/convert-base.d.ts +42 -0
  299. package/dist/typescript/convert-base.js +135 -0
  300. package/dist/typescript/convert-objects.d.ts +28 -0
  301. package/dist/typescript/convert-objects.js +245 -0
  302. package/dist/typescript/convert.d.ts +14 -0
  303. package/dist/typescript/convert.js +67 -0
  304. package/dist/typescript/importer.d.ts +37 -0
  305. package/dist/typescript/importer.js +152 -0
  306. package/dist/typescript/library.d.ts +23 -0
  307. package/dist/typescript/library.js +81 -0
  308. package/dist/vite.d.ts +11 -0
  309. package/dist/vite.js +86 -0
  310. package/dist/walk-types.d.ts +4 -0
  311. package/dist/walk-types.js +56 -0
  312. package/dist/walk.d.ts +5 -0
  313. package/dist/walk.js +315 -0
  314. package/package.json +105 -4
@@ -0,0 +1,267 @@
1
+ import { SimpleStatementParser } from "./simple-statements.js";
2
+ import { FOREIGN_KEYWORDS, FUNCTION_BODY, describe } from "./syntax.js";
3
+ // Statements: blocks, `return`, `mount()`, and which statement a token starts.
4
+ export class StatementParser extends SimpleStatementParser {
5
+ parseStatements(isEnd) {
6
+ const body = [];
7
+ this.parseSeparated(isEnd, () => {
8
+ body.push(this.parseStatement());
9
+ });
10
+ return body;
11
+ }
12
+ parseStatement() {
13
+ if (!this.context.inMarkup)
14
+ return this.parseOrdinaryStatement();
15
+ const start = this.peek().start;
16
+ if (this.check('JsxTagOpen')) {
17
+ const element = this.parseJsxElement();
18
+ this.endStatement();
19
+ return { kind: 'JsxElementStatement', element, ...this.span(start) };
20
+ }
21
+ const statement = this.parseOrdinaryStatement();
22
+ const allowed = statement.kind === 'IfStatement' ||
23
+ statement.kind === 'ForStatement' ||
24
+ (statement.kind === 'ForInStatement' && !statement.go) ||
25
+ statement.kind === 'SwitchStatement' ||
26
+ (statement.kind === 'VariableDeclaration' && statement.keyword === 'const');
27
+ if (statement.kind === 'BreakStatement' || statement.kind === 'ContinueStatement') {
28
+ const word = statement.kind === 'BreakStatement' ? 'break' : 'continue';
29
+ this.error(`"${word}" cannot be used inside markup: put the content in an if instead`, statement.start, statement.end);
30
+ }
31
+ else if (!allowed) {
32
+ this.error('inside markup only elements, if, for, switch and const can be written', statement.start, statement.end);
33
+ }
34
+ return statement;
35
+ }
36
+ parseOrdinaryStatement() {
37
+ const token = this.peek();
38
+ const declaration = this.parseDeclaration(token.start, false);
39
+ if (declaration)
40
+ return declaration;
41
+ switch (token.kind) {
42
+ case 'import':
43
+ return this.parseImport();
44
+ case 'export':
45
+ return this.parseExport();
46
+ case '{':
47
+ return this.parseBlock();
48
+ case 'return':
49
+ return this.parseReturn();
50
+ case 'if':
51
+ return this.parseIf();
52
+ case 'for':
53
+ return this.parseFor();
54
+ case 'go':
55
+ if (this.peek(1).kind === 'for')
56
+ return this.parseGoFor();
57
+ break;
58
+ case 'switch':
59
+ return this.parseSwitch();
60
+ case 'break':
61
+ case 'continue':
62
+ return this.parseBreakOrContinue();
63
+ case 'throw':
64
+ return this.parseThrow();
65
+ case 'try':
66
+ return this.parseTry();
67
+ case 'defer':
68
+ return this.parseDefer();
69
+ default:
70
+ break;
71
+ }
72
+ const hint = token.kind === 'Identifier' ? FOREIGN_KEYWORDS.get(token.text) : undefined;
73
+ if (hint !== undefined && this.peek(1).kind === 'Identifier') {
74
+ this.fail(`"${token.text}" is not a Rook keyword: ${hint}`);
75
+ }
76
+ // `select` is a keyword only before `{`: elsewhere it is a name, such as a function's.
77
+ if (this.checkWord('select') && this.peek(1).kind === '{')
78
+ return this.parseSelect();
79
+ if (this.isStyleBlock()) {
80
+ // The lexer has read the block as CSS, so it is parsed as one to report a single error.
81
+ const style = this.parseStyle();
82
+ this.error(this.context.inComponent
83
+ ? 'style is declared at the top level of a component, not inside blocks or functions'
84
+ : 'style can only be declared inside a component', style.start, style.start + 'style'.length);
85
+ this.endStatement();
86
+ return style;
87
+ }
88
+ const misplaced = this.isStateDeclaration() || this.isRefDeclaration()
89
+ ? this.peek().text
90
+ : this.isMountDeclaration()
91
+ ? 'mount()'
92
+ : this.isEffectDeclaration()
93
+ ? 'effect'
94
+ : null;
95
+ if (misplaced !== null) {
96
+ this.fail(this.context.inComponent
97
+ ? `${misplaced} is declared at the top level of a component, not inside blocks or functions`
98
+ : `${misplaced} can only be declared inside a component`);
99
+ }
100
+ const statement = this.parseSimpleStatement();
101
+ if (statement.kind === 'ExpressionStatement') {
102
+ const { expression } = statement;
103
+ // `await save()` and `<-done` wait for something.
104
+ const awaited = expression.kind === 'UnaryExpression' &&
105
+ (expression.operator === 'await' || expression.operator === '<-');
106
+ const call = expression.kind === 'CallExpression' ||
107
+ expression.kind === 'NewExpression' ||
108
+ expression.kind === 'GoExpression';
109
+ if (!call && !awaited) {
110
+ this.error('this expression does nothing: only function calls can be used as statements', expression.start, expression.end);
111
+ }
112
+ }
113
+ this.endStatement();
114
+ return statement;
115
+ }
116
+ /** Parses a declaration if the current token starts one, otherwise returns `undefined`. */
117
+ parseDeclaration(start, exported) {
118
+ switch (this.peek().kind) {
119
+ case 'func':
120
+ // `func(...)` without a name is a function literal, e.g. one that is called right away.
121
+ if (this.peek(1).kind !== 'Identifier')
122
+ return undefined;
123
+ return this.parseFuncDeclaration(start, exported);
124
+ case 'async':
125
+ if (this.peek(1).kind === 'comp') {
126
+ this.fail('a component cannot be async: load the data in mount() or in an async func');
127
+ }
128
+ if (this.peek(1).kind !== 'func' || this.peek(2).kind !== 'Identifier')
129
+ return undefined;
130
+ return this.parseFuncDeclaration(start, exported);
131
+ case 'let':
132
+ case 'const': {
133
+ const declaration = this.parseVariableDeclaration(start, exported);
134
+ this.endStatement();
135
+ return declaration;
136
+ }
137
+ case 'class':
138
+ return this.parseClass(start, exported);
139
+ case 'comp':
140
+ return this.parseComponent(start, exported);
141
+ case '@':
142
+ // `@visible.show()` is a call; `@html-tag comp Page() {...}` and
143
+ // `@visible("300px") export comp Page() {...}` are components with decorators.
144
+ if (this.isDecoratorMember())
145
+ return undefined;
146
+ return this.parseDecorated(start, exported);
147
+ case 'interface':
148
+ return this.parseInterface(start, exported);
149
+ case 'type': {
150
+ const declaration = this.parseTypeAlias(start, exported);
151
+ this.endStatement();
152
+ return declaration;
153
+ }
154
+ default:
155
+ if (this.isDecoratorDeclaration())
156
+ return this.parseDecoratorDeclaration(start, exported);
157
+ return undefined;
158
+ }
159
+ }
160
+ /** A statement ends with a newline or `;`, or right before the `}` that closes its block. */
161
+ endStatement() {
162
+ if (this.accept(';') || this.check('}') || this.check('EOF'))
163
+ return;
164
+ const token = this.peek();
165
+ if (token.kind === '++' || token.kind === '--') {
166
+ this.fail(`"${token.kind}" is a statement and cannot be used inside an expression`);
167
+ }
168
+ this.fail(`expected newline or ";" after statement, found ${describe(token)}`);
169
+ }
170
+ /**
171
+ * `state count = 0` or `derived double = count * 2`: `state` and `derived` are keywords only at
172
+ * the start of a statement in a component.
173
+ */
174
+ isStateDeclaration() {
175
+ return ((this.checkWord('state') || this.checkWord('derived')) && this.peek(1).kind === 'Identifier');
176
+ }
177
+ /** `ref input`: like `state`, a keyword only at the start of a statement in a component. */
178
+ isRefDeclaration() {
179
+ return this.checkWord('ref') && this.peek(1).kind === 'Identifier';
180
+ }
181
+ /** `style {`: the lexer reads the block as CSS where it starts a statement. */
182
+ isStyleBlock() {
183
+ return this.checkWord('style') && this.peek(1).kind === '{';
184
+ }
185
+ /** `style { ... }`: CSS text and, in the values of declarations, `{expression}`. */
186
+ parseStyle() {
187
+ const { start } = this.next();
188
+ const parts = [];
189
+ this.expect('{');
190
+ while (!this.check('}') && !this.check('EOF')) {
191
+ const token = this.peek();
192
+ if (token.kind === 'CssText') {
193
+ this.next();
194
+ parts.push({ kind: 'CssText', value: token.value, start: token.start, end: token.end });
195
+ }
196
+ else {
197
+ this.expect('{');
198
+ parts.push(this.withContext({ noObjectLiteral: false }, () => this.parseExpression()));
199
+ this.expect('}');
200
+ }
201
+ }
202
+ this.expect('}');
203
+ return { kind: 'StyleStatement', parts, ...this.span(start) };
204
+ }
205
+ /** `effect {`: like `state`, a keyword only at the start of a statement in a component. */
206
+ isEffectDeclaration() {
207
+ return this.checkWord('effect') && this.peek(1).kind === '{';
208
+ }
209
+ /** `mount() {`: like `state`, a keyword only at the start of a statement in a component. */
210
+ isMountDeclaration() {
211
+ return (this.checkWord('mount') &&
212
+ this.peek(1).kind === '(' &&
213
+ this.peek(2).kind === ')' &&
214
+ this.peek(3).kind === '{');
215
+ }
216
+ /** `mount() { ... }`; its body is a function that runs later, so `return` is its own. */
217
+ parseMount() {
218
+ const { start } = this.next();
219
+ this.expect('(');
220
+ this.expect(')');
221
+ const body = this.withContext({ ...FUNCTION_BODY, inComponent: true }, () => this.parseBlock());
222
+ return { kind: 'MountStatement', body, ...this.span(start) };
223
+ }
224
+ /** `effect { ... }`: its body runs again later, so `return` and `defer` are its own. */
225
+ parseEffect() {
226
+ const { start } = this.next();
227
+ const body = this.withContext({ ...FUNCTION_BODY, inComponent: true }, () => this.parseBlock());
228
+ return { kind: 'EffectStatement', body, ...this.span(start) };
229
+ }
230
+ parseBlock() {
231
+ const start = this.expect('{').start;
232
+ const body = this.withContext({ topLevel: false, noObjectLiteral: false }, () => this.parseStatements(() => this.check('}')));
233
+ this.expect('}');
234
+ return { kind: 'BlockStatement', body, ...this.span(start) };
235
+ }
236
+ parseFunctionBody(async = false) {
237
+ return this.withContext({ ...FUNCTION_BODY, inAsync: async }, () => this.parseBlock());
238
+ }
239
+ /** An if/for/switch header, where `{` starts the block rather than an object literal. */
240
+ parseHeaderExpression() {
241
+ return this.withContext({ noObjectLiteral: true }, () => this.parseExpression());
242
+ }
243
+ parseReturn() {
244
+ const start = this.next().start;
245
+ if (this.context.inGoFor) {
246
+ this.error('"return" cannot leave "go for": its body runs in workers; skip an element with "continue"', start, this.span(start).end);
247
+ }
248
+ else if (!this.context.inFunction) {
249
+ this.error('"return" outside of a function', start, this.span(start).end);
250
+ }
251
+ else if (this.context.inDefer) {
252
+ this.error('"return" is not allowed inside "defer"', start, this.span(start).end);
253
+ }
254
+ const values = this.check(';') || this.check('}') || this.check('EOF') ? [] : this.parseExpressionList();
255
+ const statement = { kind: 'ReturnStatement', values, ...this.span(start) };
256
+ this.endStatement();
257
+ return statement;
258
+ }
259
+ /** `}` + newline + `else`: the newline ends the `if`, so explain the error instead of failing. */
260
+ checkSameLine(keyword) {
261
+ if (this.isImplicitSemicolon() && this.peek(1).kind === keyword) {
262
+ const token = this.peek(1);
263
+ this.error(`"${keyword}" must be on the same line as the closing "}"`, token.start, token.end);
264
+ this.next();
265
+ }
266
+ }
267
+ }
@@ -0,0 +1,51 @@
1
+ import type * as ast from '../ast.ts';
2
+ import type { StringToken, Token, TokenKind } from '../lexer/token.ts';
3
+ /** Binary operators and their precedence (higher binds tighter), as in JS. */
4
+ export declare const BINARY_PRECEDENCE: Readonly<Record<ast.BinaryOperator, number>>;
5
+ export declare const UNARY_OPERATORS: ReadonlySet<string>;
6
+ export declare const ASSIGNMENT_OPERATORS: ReadonlySet<string>;
7
+ export declare function isBinaryOperator(kind: TokenKind): kind is ast.BinaryOperator;
8
+ export declare function isUnaryOperator(kind: TokenKind): kind is ast.UnaryOperator;
9
+ export declare function isAssignmentOperator(kind: TokenKind): kind is ast.AssignmentOperator;
10
+ export declare const RESERVED: ReadonlySet<string>;
11
+ export declare const MODIFIERS: ReadonlySet<string>;
12
+ /** Words from JS that Rook spells differently. */
13
+ export declare const FOREIGN_KEYWORDS: ReadonlyMap<string, string>;
14
+ /** Keywords that start a statement; used to find where to resume after a syntax error. */
15
+ export declare const STATEMENT_KEYWORDS: ReadonlySet<TokenKind>;
16
+ /** Closing brackets and the opening brackets they match. */
17
+ export declare const BRACKETS: Readonly<Partial<Record<TokenKind, TokenKind>>>;
18
+ export interface Context {
19
+ /** At the top level of the module, where imports and exports are allowed. */
20
+ topLevel: boolean;
21
+ inFunction: boolean;
22
+ inLoop: boolean;
23
+ /** Inside a loop or switch, where `break` is allowed. */
24
+ inBreakable: boolean;
25
+ inDefer: boolean;
26
+ /** In the body of `go for`, which `return` and `break` cannot leave. */
27
+ inGoFor: boolean;
28
+ /** In an async function or at the top level of the module, where `await` is allowed. */
29
+ inAsync: boolean;
30
+ /** In an if/for/switch header, where `{` starts the block rather than an object literal. */
31
+ noObjectLiteral: boolean;
32
+ /** Inside a component, for the error about `state` in a nested block. */
33
+ inComponent: boolean;
34
+ /** In the blocks of `{if ...}` and `{for ...}` inside markup, where elements are statements. */
35
+ inMarkup: boolean;
36
+ }
37
+ export declare const FUNCTION_BODY: Partial<Context>;
38
+ /** Thrown to abandon the current statement after its syntax error has been reported. */
39
+ export declare class ParseError extends Error {
40
+ }
41
+ export declare function describe(token: Token): string;
42
+ export declare function plural(count: number, word: string): string;
43
+ /** The text of a template part without its delimiters: "`" or "}" before it, "`" or "${" after it. */
44
+ /**
45
+ * Whitespace in markup text as in JSX: lines are trimmed and joined with a space, and lines with
46
+ * only whitespace disappear. Text without line breaks is kept as it is.
47
+ */
48
+ export declare function cleanJsxText(text: string): string;
49
+ /** In `on*` attributes, these are the handler itself rather than code to run. */
50
+ export declare function isHandlerReference(node: ast.Expression): boolean;
51
+ export declare function templateElement(token: StringToken): ast.TemplateElement;
@@ -0,0 +1,173 @@
1
+ // Tables and small functions of the parser: operators and their precedence, keywords, the parsing context.
2
+ /** Binary operators and their precedence (higher binds tighter), as in JS. */
3
+ export const BINARY_PRECEDENCE = {
4
+ '??': 1,
5
+ '||': 2,
6
+ '&&': 3,
7
+ '|': 4,
8
+ '^': 5,
9
+ '&': 6,
10
+ '==': 7,
11
+ '!=': 7,
12
+ '<': 8,
13
+ '>': 8,
14
+ '<=': 8,
15
+ '>=': 8,
16
+ instanceof: 8,
17
+ '<<': 9,
18
+ '>>': 9,
19
+ '>>>': 9,
20
+ '+': 10,
21
+ '-': 10,
22
+ '*': 11,
23
+ '/': 11,
24
+ '%': 11,
25
+ '**': 12,
26
+ };
27
+ export const UNARY_OPERATORS = new Set([
28
+ '!',
29
+ '-',
30
+ '+',
31
+ '~',
32
+ 'typeof',
33
+ 'await',
34
+ '<-',
35
+ ]);
36
+ export const ASSIGNMENT_OPERATORS = new Set([
37
+ '=',
38
+ '+=',
39
+ '-=',
40
+ '*=',
41
+ '/=',
42
+ '%=',
43
+ '**=',
44
+ '&=',
45
+ '|=',
46
+ '^=',
47
+ '<<=',
48
+ '>>=',
49
+ '>>>=',
50
+ '&&=',
51
+ '||=',
52
+ '??=',
53
+ ]);
54
+ export function isBinaryOperator(kind) {
55
+ return Object.hasOwn(BINARY_PRECEDENCE, kind);
56
+ }
57
+ export function isUnaryOperator(kind) {
58
+ return UNARY_OPERATORS.has(kind);
59
+ }
60
+ export function isAssignmentOperator(kind) {
61
+ return ASSIGNMENT_OPERATORS.has(kind);
62
+ }
63
+ export const RESERVED = new Set(['map']);
64
+ export const MODIFIERS = new Set(['public', 'protected', 'private', 'static']);
65
+ /** Words from JS that Rook spells differently. */
66
+ export const FOREIGN_KEYWORDS = new Map([
67
+ ['function', 'declare functions with "func"'],
68
+ ['var', 'declare variables with "let" or "const"'],
69
+ ['while', 'write loops as "for condition { ... }"'],
70
+ ]);
71
+ /** Keywords that start a statement; used to find where to resume after a syntax error. */
72
+ export const STATEMENT_KEYWORDS = new Set([
73
+ 'import',
74
+ 'export',
75
+ 'func',
76
+ 'comp',
77
+ 'let',
78
+ 'const',
79
+ 'class',
80
+ 'interface',
81
+ 'type',
82
+ 'return',
83
+ 'if',
84
+ 'for',
85
+ 'switch',
86
+ 'break',
87
+ 'continue',
88
+ 'throw',
89
+ 'try',
90
+ 'defer',
91
+ ]);
92
+ /** Closing brackets and the opening brackets they match. */
93
+ export const BRACKETS = {
94
+ ')': '(',
95
+ ']': '[',
96
+ '}': '{',
97
+ TemplateTail: 'TemplateHead',
98
+ };
99
+ export const FUNCTION_BODY = {
100
+ topLevel: false,
101
+ inFunction: true,
102
+ inLoop: false,
103
+ inBreakable: false,
104
+ inDefer: false,
105
+ inGoFor: false,
106
+ inAsync: false,
107
+ noObjectLiteral: false,
108
+ inMarkup: false,
109
+ };
110
+ /** Thrown to abandon the current statement after its syntax error has been reported. */
111
+ export class ParseError extends Error {
112
+ }
113
+ export function describe(token) {
114
+ switch (token.kind) {
115
+ case 'EOF':
116
+ return 'end of file';
117
+ case ';':
118
+ return token.text === '' ? 'newline' : '";"';
119
+ case 'String':
120
+ return 'string';
121
+ case 'Number':
122
+ return `number ${token.text}`;
123
+ case 'BigInt':
124
+ return `bigint ${token.text}`;
125
+ case 'Template':
126
+ case 'TemplateHead':
127
+ return 'template literal';
128
+ default:
129
+ return `"${token.text}"`;
130
+ }
131
+ }
132
+ export function plural(count, word) {
133
+ return `${count} ${word}${count === 1 ? '' : 's'}`;
134
+ }
135
+ /** The text of a template part without its delimiters: "`" or "}" before it, "`" or "${" after it. */
136
+ /**
137
+ * Whitespace in markup text as in JSX: lines are trimmed and joined with a space, and lines with
138
+ * only whitespace disappear. Text without line breaks is kept as it is.
139
+ */
140
+ export function cleanJsxText(text) {
141
+ const lines = text.split(/\r?\n/);
142
+ const kept = [];
143
+ lines.forEach((line, i) => {
144
+ let part = line.replace(/\t/g, ' ');
145
+ if (i > 0)
146
+ part = part.trimStart();
147
+ if (i < lines.length - 1)
148
+ part = part.trimEnd();
149
+ if (part !== '')
150
+ kept.push(part);
151
+ });
152
+ return kept.join(' ');
153
+ }
154
+ /** In `on*` attributes, these are the handler itself rather than code to run. */
155
+ export function isHandlerReference(node) {
156
+ if (node.kind === 'Identifier' ||
157
+ node.kind === 'ArrowFunction' ||
158
+ node.kind === 'FuncExpression') {
159
+ return true;
160
+ }
161
+ return node.kind === 'MemberExpression' && !node.optional && isHandlerReference(node.object);
162
+ }
163
+ export function templateElement(token) {
164
+ const text = token.text;
165
+ const end = text.endsWith('${') ? -2 : text.length > 1 && text.endsWith('`') ? -1 : text.length;
166
+ return {
167
+ kind: 'TemplateElement',
168
+ value: token.value,
169
+ raw: text.slice(1, end),
170
+ start: token.start,
171
+ end: token.end,
172
+ };
173
+ }
@@ -0,0 +1,23 @@
1
+ import type * as ast from '../ast.ts';
2
+ import { ClassParser } from './classes.ts';
3
+ export declare abstract class TypeParser extends ClassParser {
4
+ /** `<number, string>` after the name of a generic type. */
5
+ protected parseTypeArgs(): ast.TypeNode[];
6
+ protected canStartType(): boolean;
7
+ /** A type, possibly a union: `string | number`. */
8
+ protected parseType(): ast.TypeNode;
9
+ protected parsePrimaryType(): ast.TypeNode;
10
+ /**
11
+ * Grouping, `[](string | number)`, or a function type written as an arrow,
12
+ * `(paths []string) => Shape`, the same as `func([]string) Shape`. Its parameters may have
13
+ * names, which only document them.
14
+ */
15
+ protected parseParenthesizedType(): ast.TypeNode;
16
+ /** The type of a parameter of a function type, after its name if it has one, kept in `names`. */
17
+ private parseParamType;
18
+ /** `paths []string` in `(paths []string) => Shape`: a name before the type of a parameter. */
19
+ private startsNamedParam;
20
+ /** `{ name string; x, y number; area() number }`, separated by newlines, `;` or `,`. */
21
+ protected parseTypeMembers(): ast.TypeMember[];
22
+ protected parseTypeMember(): ast.TypeMember[];
23
+ }