bonescript-compiler 0.5.2 → 0.5.4

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 (187) hide show
  1. package/LICENSE +21 -21
  2. package/dist/algorithm_catalog.js +166 -166
  3. package/dist/cli.d.ts +1 -2
  4. package/dist/cli.js +543 -75
  5. package/dist/cli.js.map +1 -1
  6. package/dist/emit_capability.d.ts +0 -13
  7. package/dist/emit_capability.js +128 -292
  8. package/dist/emit_capability.js.map +1 -1
  9. package/dist/emit_composition.js +3 -37
  10. package/dist/emit_composition.js.map +1 -1
  11. package/dist/emit_deploy.js +162 -162
  12. package/dist/emit_events.d.ts +0 -1
  13. package/dist/emit_events.js +275 -342
  14. package/dist/emit_events.js.map +1 -1
  15. package/dist/emit_full.js +106 -268
  16. package/dist/emit_full.js.map +1 -1
  17. package/dist/emit_maintenance.js +249 -249
  18. package/dist/emit_runtime.d.ts +11 -17
  19. package/dist/emit_runtime.js +688 -29
  20. package/dist/emit_runtime.js.map +1 -1
  21. package/dist/emit_sourcemap.js +66 -66
  22. package/dist/emit_tests.js +0 -37
  23. package/dist/emit_tests.js.map +1 -1
  24. package/dist/emitter.js +16 -82
  25. package/dist/emitter.js.map +1 -1
  26. package/dist/extension_manager.d.ts +2 -2
  27. package/dist/extension_manager.js +3 -6
  28. package/dist/extension_manager.js.map +1 -1
  29. package/dist/ir.d.ts +0 -4
  30. package/dist/lowering.d.ts +14 -5
  31. package/dist/lowering.js +417 -66
  32. package/dist/lowering.js.map +1 -1
  33. package/dist/module_loader.d.ts +2 -2
  34. package/dist/module_loader.js +23 -20
  35. package/dist/module_loader.js.map +1 -1
  36. package/dist/optimizer.js +1 -1
  37. package/dist/optimizer.js.map +1 -1
  38. package/dist/scaffold.d.ts +2 -2
  39. package/dist/scaffold.js +319 -315
  40. package/dist/scaffold.js.map +1 -1
  41. package/dist/source_map.js.map +1 -0
  42. package/dist/test.js.map +1 -0
  43. package/dist/test_typechecker.d.ts +5 -0
  44. package/dist/test_typechecker.js +126 -0
  45. package/dist/test_typechecker.js.map +1 -0
  46. package/dist/typechecker.d.ts +0 -5
  47. package/dist/typechecker.js +13 -68
  48. package/dist/typechecker.js.map +1 -1
  49. package/dist/verifier.d.ts +1 -5
  50. package/dist/verifier.js +35 -140
  51. package/dist/verifier.js.map +1 -1
  52. package/package.json +52 -62
  53. package/src/algorithm_catalog.ts +345 -345
  54. package/src/ast.d.ts +244 -0
  55. package/src/ast.ts +334 -334
  56. package/src/cli.ts +624 -98
  57. package/src/emit_batch.ts +140 -140
  58. package/src/emit_capability.ts +436 -617
  59. package/src/emit_composition.ts +196 -229
  60. package/src/emit_deploy.ts +190 -190
  61. package/src/emit_events.ts +307 -377
  62. package/src/emit_extras.ts +240 -240
  63. package/src/emit_full.ts +309 -475
  64. package/src/emit_maintenance.ts +459 -459
  65. package/src/emit_runtime.ts +730 -17
  66. package/src/emit_sourcemap.ts +140 -140
  67. package/src/emit_tests.ts +205 -246
  68. package/src/emit_websocket.ts +229 -229
  69. package/src/emitter.ts +578 -642
  70. package/src/extension_manager.ts +187 -189
  71. package/src/formatter.ts +297 -297
  72. package/src/index.ts +88 -88
  73. package/src/ir.ts +215 -216
  74. package/src/lexer.d.ts +195 -0
  75. package/src/lexer.ts +630 -630
  76. package/src/lowering.ts +556 -168
  77. package/src/module_loader.ts +114 -112
  78. package/src/optimizer.ts +196 -196
  79. package/src/parse_decls.d.ts +13 -0
  80. package/src/parse_decls.ts +409 -409
  81. package/src/parse_decls2.d.ts +13 -0
  82. package/src/parse_decls2.ts +244 -244
  83. package/src/parse_expr.d.ts +7 -0
  84. package/src/parse_expr.ts +197 -197
  85. package/src/parse_types.d.ts +6 -0
  86. package/src/parse_types.ts +54 -54
  87. package/src/parser.d.ts +10 -0
  88. package/src/parser.ts +1 -1
  89. package/src/parser_base.d.ts +19 -0
  90. package/src/parser_base.ts +57 -57
  91. package/src/parser_recovery.ts +153 -153
  92. package/src/scaffold.ts +375 -371
  93. package/src/solver.ts +330 -330
  94. package/src/typechecker.d.ts +52 -0
  95. package/src/typechecker.ts +591 -657
  96. package/src/types.d.ts +38 -0
  97. package/src/types.ts +122 -122
  98. package/src/verifier.ts +46 -152
  99. package/README.md +0 -382
  100. package/dist/commands/check.d.ts +0 -5
  101. package/dist/commands/check.js +0 -34
  102. package/dist/commands/check.js.map +0 -1
  103. package/dist/commands/compile.d.ts +0 -5
  104. package/dist/commands/compile.js +0 -215
  105. package/dist/commands/compile.js.map +0 -1
  106. package/dist/commands/debug.d.ts +0 -5
  107. package/dist/commands/debug.js +0 -59
  108. package/dist/commands/debug.js.map +0 -1
  109. package/dist/commands/diff.d.ts +0 -5
  110. package/dist/commands/diff.js +0 -125
  111. package/dist/commands/diff.js.map +0 -1
  112. package/dist/commands/fmt.d.ts +0 -5
  113. package/dist/commands/fmt.js +0 -49
  114. package/dist/commands/fmt.js.map +0 -1
  115. package/dist/commands/init.d.ts +0 -5
  116. package/dist/commands/init.js +0 -96
  117. package/dist/commands/init.js.map +0 -1
  118. package/dist/commands/ir.d.ts +0 -5
  119. package/dist/commands/ir.js +0 -27
  120. package/dist/commands/ir.js.map +0 -1
  121. package/dist/commands/lex.d.ts +0 -5
  122. package/dist/commands/lex.js +0 -21
  123. package/dist/commands/lex.js.map +0 -1
  124. package/dist/commands/parse.d.ts +0 -5
  125. package/dist/commands/parse.js +0 -30
  126. package/dist/commands/parse.js.map +0 -1
  127. package/dist/commands/test.d.ts +0 -5
  128. package/dist/commands/test.js +0 -61
  129. package/dist/commands/test.js.map +0 -1
  130. package/dist/commands/verify_determinism.d.ts +0 -5
  131. package/dist/commands/verify_determinism.js +0 -64
  132. package/dist/commands/verify_determinism.js.map +0 -1
  133. package/dist/commands/watch.d.ts +0 -5
  134. package/dist/commands/watch.js +0 -50
  135. package/dist/commands/watch.js.map +0 -1
  136. package/dist/emit_auth.d.ts +0 -18
  137. package/dist/emit_auth.js +0 -507
  138. package/dist/emit_auth.js.map +0 -1
  139. package/dist/emit_database.d.ts +0 -7
  140. package/dist/emit_database.js +0 -74
  141. package/dist/emit_database.js.map +0 -1
  142. package/dist/emit_index.d.ts +0 -6
  143. package/dist/emit_index.js +0 -202
  144. package/dist/emit_index.js.map +0 -1
  145. package/dist/emit_models.d.ts +0 -12
  146. package/dist/emit_models.js +0 -171
  147. package/dist/emit_models.js.map +0 -1
  148. package/dist/emit_openapi.d.ts +0 -9
  149. package/dist/emit_openapi.js +0 -308
  150. package/dist/emit_openapi.js.map +0 -1
  151. package/dist/emit_package.d.ts +0 -7
  152. package/dist/emit_package.js +0 -70
  153. package/dist/emit_package.js.map +0 -1
  154. package/dist/emit_router.d.ts +0 -12
  155. package/dist/emit_router.js +0 -390
  156. package/dist/emit_router.js.map +0 -1
  157. package/dist/lowering_channels.d.ts +0 -11
  158. package/dist/lowering_channels.js +0 -103
  159. package/dist/lowering_channels.js.map +0 -1
  160. package/dist/lowering_entities.d.ts +0 -11
  161. package/dist/lowering_entities.js +0 -232
  162. package/dist/lowering_entities.js.map +0 -1
  163. package/dist/lowering_helpers.d.ts +0 -13
  164. package/dist/lowering_helpers.js +0 -76
  165. package/dist/lowering_helpers.js.map +0 -1
  166. package/src/commands/check.ts +0 -33
  167. package/src/commands/compile.ts +0 -191
  168. package/src/commands/debug.ts +0 -33
  169. package/src/commands/diff.ts +0 -108
  170. package/src/commands/fmt.ts +0 -22
  171. package/src/commands/init.ts +0 -72
  172. package/src/commands/ir.ts +0 -23
  173. package/src/commands/lex.ts +0 -17
  174. package/src/commands/parse.ts +0 -24
  175. package/src/commands/test.ts +0 -36
  176. package/src/commands/verify_determinism.ts +0 -66
  177. package/src/commands/watch.ts +0 -25
  178. package/src/emit_auth.ts +0 -513
  179. package/src/emit_database.ts +0 -75
  180. package/src/emit_index.ts +0 -210
  181. package/src/emit_models.ts +0 -176
  182. package/src/emit_openapi.ts +0 -318
  183. package/src/emit_package.ts +0 -69
  184. package/src/emit_router.ts +0 -409
  185. package/src/lowering_channels.ts +0 -108
  186. package/src/lowering_entities.ts +0 -258
  187. package/src/lowering_helpers.ts +0 -75
package/src/parse_expr.ts CHANGED
@@ -1,197 +1,197 @@
1
- /**
2
- * BoneScript Expression Parser — Pratt-style precedence climbing.
3
- */
4
-
5
- import { TokenKind } from "./lexer";
6
- import { TokenStream, ParseError } from "./parser_base";
7
- import * as AST from "./ast";
8
-
9
- export function parseExpr(s: TokenStream): AST.ExprNode {
10
- return parseLogicalOr(s);
11
- }
12
-
13
- export function parseExprList(s: TokenStream): AST.ExprNode[] {
14
- const exprs: AST.ExprNode[] = [];
15
- if (s.check(TokenKind.RBracket)) return exprs;
16
- do {
17
- exprs.push(parseExpr(s));
18
- } while (s.match(TokenKind.Comma));
19
- return exprs;
20
- }
21
-
22
- function parseLogicalOr(s: TokenStream): AST.ExprNode {
23
- let left = parseLogicalAnd(s);
24
- while (s.check(TokenKind.KwOr)) {
25
- const loc = s.peek().loc;
26
- s.advance();
27
- const right = parseLogicalAnd(s);
28
- left = { kind: "BinaryExpr", loc, op: "or", left, right };
29
- }
30
- return left;
31
- }
32
-
33
- function parseLogicalAnd(s: TokenStream): AST.ExprNode {
34
- let left = parseComparison(s);
35
- while (s.check(TokenKind.KwAnd)) {
36
- const loc = s.peek().loc;
37
- s.advance();
38
- const right = parseComparison(s);
39
- left = { kind: "BinaryExpr", loc, op: "and", left, right };
40
- }
41
- return left;
42
- }
43
-
44
- function parseComparison(s: TokenStream): AST.ExprNode {
45
- let left = parseAdditive(s);
46
- const compOps = [
47
- TokenKind.EqEq, TokenKind.NotEq, TokenKind.LAngle, TokenKind.RAngle,
48
- TokenKind.LtEq, TokenKind.GtEq, TokenKind.KwIn, TokenKind.KwContains,
49
- ];
50
- if (compOps.includes(s.peek().kind)) {
51
- const loc = s.peek().loc;
52
- const op = s.advance().value;
53
- const right = parseAdditive(s);
54
- // Check for range: expr in expr..expr
55
- if (op === "in" && s.check(TokenKind.DotDot)) {
56
- const dotLoc = s.peek().loc;
57
- s.advance(); // consume ..
58
- const upper = parseAdditive(s);
59
- // Desugar "x in low..high" into BinaryExpr with op "in_range"
60
- const range: AST.BinaryExprNode = { kind: "BinaryExpr", loc: dotLoc, op: "..", left: right, right: upper };
61
- left = { kind: "BinaryExpr", loc, op: "in", left, right: range };
62
- } else {
63
- left = { kind: "BinaryExpr", loc, op, left, right };
64
- }
65
- }
66
- return left;
67
- }
68
-
69
- function parseAdditive(s: TokenStream): AST.ExprNode {
70
- let left = parseMultiplicative(s);
71
- while (s.check(TokenKind.Plus) || s.check(TokenKind.Minus)) {
72
- const loc = s.peek().loc;
73
- const op = s.advance().value;
74
- const right = parseMultiplicative(s);
75
- left = { kind: "BinaryExpr", loc, op, left, right };
76
- }
77
- return left;
78
- }
79
-
80
- function parseMultiplicative(s: TokenStream): AST.ExprNode {
81
- let left = parseUnary(s);
82
- while (s.check(TokenKind.Star) || s.check(TokenKind.Slash) || s.check(TokenKind.Percent)) {
83
- const loc = s.peek().loc;
84
- const op = s.advance().value;
85
- const right = parseUnary(s);
86
- left = { kind: "BinaryExpr", loc, op, left, right };
87
- }
88
- return left;
89
- }
90
-
91
- function parseUnary(s: TokenStream): AST.ExprNode {
92
- if (s.check(TokenKind.KwNot)) {
93
- const loc = s.peek().loc;
94
- s.advance();
95
- const operand = parseUnary(s);
96
- return { kind: "UnaryExpr", loc, op: "not", operand };
97
- }
98
- if (s.check(TokenKind.Minus)) {
99
- const loc = s.peek().loc;
100
- s.advance();
101
- const operand = parseUnary(s);
102
- return { kind: "UnaryExpr", loc, op: "-", operand };
103
- }
104
- return parsePrimary(s);
105
- }
106
-
107
- function parsePrimary(s: TokenStream): AST.ExprNode {
108
- const tok = s.peek();
109
- const loc = tok.loc;
110
-
111
- // Parenthesized expression
112
- if (tok.kind === TokenKind.LParen) {
113
- s.advance();
114
- const expr = parseExpr(s);
115
- s.expect(TokenKind.RParen, "parenthesized expression");
116
- return expr;
117
- }
118
-
119
- // List literal
120
- if (tok.kind === TokenKind.LBracket) {
121
- s.advance();
122
- const elements: AST.ExprNode[] = [];
123
- if (!s.check(TokenKind.RBracket)) {
124
- do { elements.push(parseExpr(s)); } while (s.match(TokenKind.Comma));
125
- }
126
- s.expect(TokenKind.RBracket, "list literal close");
127
- return { kind: "Literal", loc, type: "list", value: elements };
128
- }
129
-
130
- // String literal
131
- if (tok.kind === TokenKind.StringLiteral) {
132
- s.advance();
133
- return { kind: "Literal", loc, type: "string", value: tok.value };
134
- }
135
-
136
- // Int literal
137
- if (tok.kind === TokenKind.IntLiteral) {
138
- s.advance();
139
- return { kind: "Literal", loc, type: "int", value: parseInt(tok.value, 10) };
140
- }
141
-
142
- // Float literal
143
- if (tok.kind === TokenKind.FloatLiteral) {
144
- s.advance();
145
- return { kind: "Literal", loc, type: "float", value: parseFloat(tok.value) };
146
- }
147
-
148
- // Boolean
149
- if (tok.kind === TokenKind.KwTrue) { s.advance(); return { kind: "Literal", loc, type: "bool", value: true }; }
150
- if (tok.kind === TokenKind.KwFalse) { s.advance(); return { kind: "Literal", loc, type: "bool", value: false }; }
151
-
152
- // None
153
- if (tok.kind === TokenKind.KwNone) { s.advance(); return { kind: "Literal", loc, type: "none", value: null }; }
154
-
155
- // now()
156
- if (tok.kind === TokenKind.KwNow) {
157
- s.advance();
158
- if (s.match(TokenKind.LParen)) { s.expect(TokenKind.RParen, "now()"); }
159
- return { kind: "CallExpr", loc, name: "now", args: [] };
160
- }
161
-
162
- // Identifier — field ref or function call
163
- if (tok.kind === TokenKind.Identifier || isKeywordIdentifier(tok)) {
164
- const path: string[] = [];
165
- path.push(s.advance().value);
166
-
167
- // Function call
168
- if (s.check(TokenKind.LParen)) {
169
- s.advance();
170
- const args: AST.ExprNode[] = [];
171
- if (!s.check(TokenKind.RParen)) {
172
- do { args.push(parseExpr(s)); } while (s.match(TokenKind.Comma));
173
- }
174
- s.expect(TokenKind.RParen, "function call close");
175
- return { kind: "CallExpr", loc, name: path[0], args };
176
- }
177
-
178
- // Dotted field reference
179
- while (s.match(TokenKind.Dot)) {
180
- const next = s.peek();
181
- if (next.kind === TokenKind.Identifier || next.kind === TokenKind.KwUnique || isKeywordIdentifier(next)) {
182
- path.push(s.advance().value);
183
- } else {
184
- break;
185
- }
186
- }
187
- return { kind: "FieldRef", loc, path };
188
- }
189
-
190
- throw new ParseError(`Expected expression, got ${tok.kind} ('${tok.value}')`, tok.loc);
191
- }
192
-
193
- /** Check if a token is a keyword that can also serve as an identifier */
194
- function isKeywordIdentifier(tok: { kind: TokenKind; value: string }): boolean {
195
- // Keywords that are commonly used as variable/field names
196
- return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tok.value) && tok.kind !== TokenKind.EOF;
197
- }
1
+ /**
2
+ * BoneScript Expression Parser — Pratt-style precedence climbing.
3
+ */
4
+
5
+ import { TokenKind } from "./lexer";
6
+ import { TokenStream, ParseError } from "./parser_base";
7
+ import * as AST from "./ast";
8
+
9
+ export function parseExpr(s: TokenStream): AST.ExprNode {
10
+ return parseLogicalOr(s);
11
+ }
12
+
13
+ export function parseExprList(s: TokenStream): AST.ExprNode[] {
14
+ const exprs: AST.ExprNode[] = [];
15
+ if (s.check(TokenKind.RBracket)) return exprs;
16
+ do {
17
+ exprs.push(parseExpr(s));
18
+ } while (s.match(TokenKind.Comma));
19
+ return exprs;
20
+ }
21
+
22
+ function parseLogicalOr(s: TokenStream): AST.ExprNode {
23
+ let left = parseLogicalAnd(s);
24
+ while (s.check(TokenKind.KwOr)) {
25
+ const loc = s.peek().loc;
26
+ s.advance();
27
+ const right = parseLogicalAnd(s);
28
+ left = { kind: "BinaryExpr", loc, op: "or", left, right };
29
+ }
30
+ return left;
31
+ }
32
+
33
+ function parseLogicalAnd(s: TokenStream): AST.ExprNode {
34
+ let left = parseComparison(s);
35
+ while (s.check(TokenKind.KwAnd)) {
36
+ const loc = s.peek().loc;
37
+ s.advance();
38
+ const right = parseComparison(s);
39
+ left = { kind: "BinaryExpr", loc, op: "and", left, right };
40
+ }
41
+ return left;
42
+ }
43
+
44
+ function parseComparison(s: TokenStream): AST.ExprNode {
45
+ let left = parseAdditive(s);
46
+ const compOps = [
47
+ TokenKind.EqEq, TokenKind.NotEq, TokenKind.LAngle, TokenKind.RAngle,
48
+ TokenKind.LtEq, TokenKind.GtEq, TokenKind.KwIn, TokenKind.KwContains,
49
+ ];
50
+ if (compOps.includes(s.peek().kind)) {
51
+ const loc = s.peek().loc;
52
+ const op = s.advance().value;
53
+ const right = parseAdditive(s);
54
+ // Check for range: expr in expr..expr
55
+ if (op === "in" && s.check(TokenKind.DotDot)) {
56
+ const dotLoc = s.peek().loc;
57
+ s.advance(); // consume ..
58
+ const upper = parseAdditive(s);
59
+ // Desugar "x in low..high" into BinaryExpr with op "in_range"
60
+ const range: AST.BinaryExprNode = { kind: "BinaryExpr", loc: dotLoc, op: "..", left: right, right: upper };
61
+ left = { kind: "BinaryExpr", loc, op: "in", left, right: range };
62
+ } else {
63
+ left = { kind: "BinaryExpr", loc, op, left, right };
64
+ }
65
+ }
66
+ return left;
67
+ }
68
+
69
+ function parseAdditive(s: TokenStream): AST.ExprNode {
70
+ let left = parseMultiplicative(s);
71
+ while (s.check(TokenKind.Plus) || s.check(TokenKind.Minus)) {
72
+ const loc = s.peek().loc;
73
+ const op = s.advance().value;
74
+ const right = parseMultiplicative(s);
75
+ left = { kind: "BinaryExpr", loc, op, left, right };
76
+ }
77
+ return left;
78
+ }
79
+
80
+ function parseMultiplicative(s: TokenStream): AST.ExprNode {
81
+ let left = parseUnary(s);
82
+ while (s.check(TokenKind.Star) || s.check(TokenKind.Slash) || s.check(TokenKind.Percent)) {
83
+ const loc = s.peek().loc;
84
+ const op = s.advance().value;
85
+ const right = parseUnary(s);
86
+ left = { kind: "BinaryExpr", loc, op, left, right };
87
+ }
88
+ return left;
89
+ }
90
+
91
+ function parseUnary(s: TokenStream): AST.ExprNode {
92
+ if (s.check(TokenKind.KwNot)) {
93
+ const loc = s.peek().loc;
94
+ s.advance();
95
+ const operand = parseUnary(s);
96
+ return { kind: "UnaryExpr", loc, op: "not", operand };
97
+ }
98
+ if (s.check(TokenKind.Minus)) {
99
+ const loc = s.peek().loc;
100
+ s.advance();
101
+ const operand = parseUnary(s);
102
+ return { kind: "UnaryExpr", loc, op: "-", operand };
103
+ }
104
+ return parsePrimary(s);
105
+ }
106
+
107
+ function parsePrimary(s: TokenStream): AST.ExprNode {
108
+ const tok = s.peek();
109
+ const loc = tok.loc;
110
+
111
+ // Parenthesized expression
112
+ if (tok.kind === TokenKind.LParen) {
113
+ s.advance();
114
+ const expr = parseExpr(s);
115
+ s.expect(TokenKind.RParen, "parenthesized expression");
116
+ return expr;
117
+ }
118
+
119
+ // List literal
120
+ if (tok.kind === TokenKind.LBracket) {
121
+ s.advance();
122
+ const elements: AST.ExprNode[] = [];
123
+ if (!s.check(TokenKind.RBracket)) {
124
+ do { elements.push(parseExpr(s)); } while (s.match(TokenKind.Comma));
125
+ }
126
+ s.expect(TokenKind.RBracket, "list literal close");
127
+ return { kind: "Literal", loc, type: "list", value: elements };
128
+ }
129
+
130
+ // String literal
131
+ if (tok.kind === TokenKind.StringLiteral) {
132
+ s.advance();
133
+ return { kind: "Literal", loc, type: "string", value: tok.value };
134
+ }
135
+
136
+ // Int literal
137
+ if (tok.kind === TokenKind.IntLiteral) {
138
+ s.advance();
139
+ return { kind: "Literal", loc, type: "int", value: parseInt(tok.value, 10) };
140
+ }
141
+
142
+ // Float literal
143
+ if (tok.kind === TokenKind.FloatLiteral) {
144
+ s.advance();
145
+ return { kind: "Literal", loc, type: "float", value: parseFloat(tok.value) };
146
+ }
147
+
148
+ // Boolean
149
+ if (tok.kind === TokenKind.KwTrue) { s.advance(); return { kind: "Literal", loc, type: "bool", value: true }; }
150
+ if (tok.kind === TokenKind.KwFalse) { s.advance(); return { kind: "Literal", loc, type: "bool", value: false }; }
151
+
152
+ // None
153
+ if (tok.kind === TokenKind.KwNone) { s.advance(); return { kind: "Literal", loc, type: "none", value: null }; }
154
+
155
+ // now()
156
+ if (tok.kind === TokenKind.KwNow) {
157
+ s.advance();
158
+ if (s.match(TokenKind.LParen)) { s.expect(TokenKind.RParen, "now()"); }
159
+ return { kind: "CallExpr", loc, name: "now", args: [] };
160
+ }
161
+
162
+ // Identifier — field ref or function call
163
+ if (tok.kind === TokenKind.Identifier || isKeywordIdentifier(tok)) {
164
+ const path: string[] = [];
165
+ path.push(s.advance().value);
166
+
167
+ // Function call
168
+ if (s.check(TokenKind.LParen)) {
169
+ s.advance();
170
+ const args: AST.ExprNode[] = [];
171
+ if (!s.check(TokenKind.RParen)) {
172
+ do { args.push(parseExpr(s)); } while (s.match(TokenKind.Comma));
173
+ }
174
+ s.expect(TokenKind.RParen, "function call close");
175
+ return { kind: "CallExpr", loc, name: path[0], args };
176
+ }
177
+
178
+ // Dotted field reference
179
+ while (s.match(TokenKind.Dot)) {
180
+ const next = s.peek();
181
+ if (next.kind === TokenKind.Identifier || next.kind === TokenKind.KwUnique || isKeywordIdentifier(next)) {
182
+ path.push(s.advance().value);
183
+ } else {
184
+ break;
185
+ }
186
+ }
187
+ return { kind: "FieldRef", loc, path };
188
+ }
189
+
190
+ throw new ParseError(`Expected expression, got ${tok.kind} ('${tok.value}')`, tok.loc);
191
+ }
192
+
193
+ /** Check if a token is a keyword that can also serve as an identifier */
194
+ function isKeywordIdentifier(tok: { kind: TokenKind; value: string }): boolean {
195
+ // Keywords that are commonly used as variable/field names
196
+ return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tok.value) && tok.kind !== TokenKind.EOF;
197
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * BoneScript Type Expression Parser
3
+ */
4
+ import { TokenStream } from "./parser_base";
5
+ import * as AST from "./ast";
6
+ export declare function parseTypeExpr(s: TokenStream): AST.TypeExprNode;
@@ -1,54 +1,54 @@
1
- /**
2
- * BoneScript Type Expression Parser
3
- */
4
-
5
- import { TokenKind } from "./lexer";
6
- import { TokenStream, ParseError } from "./parser_base";
7
- import * as AST from "./ast";
8
-
9
- export function parseTypeExpr(s: TokenStream): AST.TypeExprNode {
10
- const loc = s.peek().loc;
11
- const tok = s.peek();
12
-
13
- // Generic types
14
- const generics = [TokenKind.KwSet, TokenKind.KwList, TokenKind.KwOptional, TokenKind.KwResult, TokenKind.KwMap];
15
- if (generics.includes(tok.kind)) {
16
- const name = s.advance().value;
17
- s.expect(TokenKind.LAngle, "generic type arg");
18
- const typeArgs: AST.TypeExprNode[] = [];
19
- typeArgs.push(parseTypeExpr(s));
20
- while (s.match(TokenKind.Comma)) {
21
- typeArgs.push(parseTypeExpr(s));
22
- }
23
- s.expect(TokenKind.RAngle, "generic type arg close");
24
- return { kind: "GenericType", loc, name, typeArgs };
25
- }
26
-
27
- // Primitive types
28
- const primitives = [
29
- TokenKind.KwString, TokenKind.KwUint, TokenKind.KwInt, TokenKind.KwFloat,
30
- TokenKind.KwBool, TokenKind.KwTimestamp, TokenKind.KwUuid, TokenKind.KwBytes, TokenKind.KwJson,
31
- ];
32
- if (primitives.includes(tok.kind)) {
33
- return { kind: "PrimitiveType", loc, name: s.advance().value };
34
- }
35
-
36
- // Tuple type
37
- if (tok.kind === TokenKind.LParen) {
38
- s.advance();
39
- const elements: AST.TypeExprNode[] = [];
40
- elements.push(parseTypeExpr(s));
41
- while (s.match(TokenKind.Comma)) {
42
- elements.push(parseTypeExpr(s));
43
- }
44
- s.expect(TokenKind.RParen, "tuple type close");
45
- return { kind: "TupleType", loc, elements };
46
- }
47
-
48
- // Entity reference
49
- if (tok.kind === TokenKind.Identifier) {
50
- return { kind: "EntityRefType", loc, name: s.advance().value };
51
- }
52
-
53
- throw new ParseError(`Expected type expression, got ${tok.kind}`, tok.loc);
54
- }
1
+ /**
2
+ * BoneScript Type Expression Parser
3
+ */
4
+
5
+ import { TokenKind } from "./lexer";
6
+ import { TokenStream, ParseError } from "./parser_base";
7
+ import * as AST from "./ast";
8
+
9
+ export function parseTypeExpr(s: TokenStream): AST.TypeExprNode {
10
+ const loc = s.peek().loc;
11
+ const tok = s.peek();
12
+
13
+ // Generic types
14
+ const generics = [TokenKind.KwSet, TokenKind.KwList, TokenKind.KwOptional, TokenKind.KwResult, TokenKind.KwMap];
15
+ if (generics.includes(tok.kind)) {
16
+ const name = s.advance().value;
17
+ s.expect(TokenKind.LAngle, "generic type arg");
18
+ const typeArgs: AST.TypeExprNode[] = [];
19
+ typeArgs.push(parseTypeExpr(s));
20
+ while (s.match(TokenKind.Comma)) {
21
+ typeArgs.push(parseTypeExpr(s));
22
+ }
23
+ s.expect(TokenKind.RAngle, "generic type arg close");
24
+ return { kind: "GenericType", loc, name, typeArgs };
25
+ }
26
+
27
+ // Primitive types
28
+ const primitives = [
29
+ TokenKind.KwString, TokenKind.KwUint, TokenKind.KwInt, TokenKind.KwFloat,
30
+ TokenKind.KwBool, TokenKind.KwTimestamp, TokenKind.KwUuid, TokenKind.KwBytes, TokenKind.KwJson,
31
+ ];
32
+ if (primitives.includes(tok.kind)) {
33
+ return { kind: "PrimitiveType", loc, name: s.advance().value };
34
+ }
35
+
36
+ // Tuple type
37
+ if (tok.kind === TokenKind.LParen) {
38
+ s.advance();
39
+ const elements: AST.TypeExprNode[] = [];
40
+ elements.push(parseTypeExpr(s));
41
+ while (s.match(TokenKind.Comma)) {
42
+ elements.push(parseTypeExpr(s));
43
+ }
44
+ s.expect(TokenKind.RParen, "tuple type close");
45
+ return { kind: "TupleType", loc, elements };
46
+ }
47
+
48
+ // Entity reference
49
+ if (tok.kind === TokenKind.Identifier) {
50
+ return { kind: "EntityRefType", loc, name: s.advance().value };
51
+ }
52
+
53
+ throw new ParseError(`Expected type expression, got ${tok.kind}`, tok.loc);
54
+ }
@@ -0,0 +1,10 @@
1
+ import { Token } from "./lexer";
2
+ import * as AST from "./ast";
3
+ export { ParseError } from "./parser_base";
4
+ export declare class Parser {
5
+ private s;
6
+ constructor(tokens: Token[]);
7
+ parse(): AST.ProgramNode;
8
+ private parseSystemDecl;
9
+ private parseDeclaration;
10
+ }
package/src/parser.ts CHANGED
@@ -61,4 +61,4 @@ export class Parser {
61
61
  throw new ParseError("Expected declaration, got " + tok.kind, tok.loc);
62
62
  }
63
63
  }
64
- }
64
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * bone parser Base — Token stream utilities.
3
+ */
4
+ import { Token, TokenKind, SourceLocation } from "./lexer";
5
+ export declare class ParseError extends Error {
6
+ loc: SourceLocation;
7
+ constructor(message: string, loc: SourceLocation);
8
+ }
9
+ export declare class TokenStream {
10
+ private tokens;
11
+ private pos;
12
+ constructor(tokens: Token[]);
13
+ peek(offset?: number): Token;
14
+ check(kind: TokenKind): boolean;
15
+ checkAny(...kinds: TokenKind[]): boolean;
16
+ advance(): Token;
17
+ expect(kind: TokenKind, context: string): Token;
18
+ match(kind: TokenKind): boolean;
19
+ }
@@ -1,57 +1,57 @@
1
- /**
2
- * bone parser Base — Token stream utilities.
3
- */
4
-
5
- import { Token, TokenKind, SourceLocation } from "./lexer";
6
-
7
- export class ParseError extends Error {
8
- constructor(message: string, public loc: SourceLocation) {
9
- super(`Parse error at ${loc.line}:${loc.column}: ${message}`);
10
- this.name = "ParseError";
11
- }
12
- }
13
-
14
- export class TokenStream {
15
- private tokens: Token[];
16
- private pos: number = 0;
17
-
18
- constructor(tokens: Token[]) {
19
- this.tokens = tokens;
20
- }
21
-
22
- peek(offset: number = 0): Token {
23
- return this.tokens[this.pos + offset] ?? this.tokens[this.tokens.length - 1];
24
- }
25
-
26
- check(kind: TokenKind): boolean {
27
- return this.peek().kind === kind;
28
- }
29
-
30
- checkAny(...kinds: TokenKind[]): boolean {
31
- return kinds.includes(this.peek().kind);
32
- }
33
-
34
- advance(): Token {
35
- const t = this.tokens[this.pos];
36
- if (this.pos < this.tokens.length - 1) this.pos++;
37
- return t;
38
- }
39
-
40
- expect(kind: TokenKind, context: string): Token {
41
- if (!this.check(kind)) {
42
- throw new ParseError(
43
- `Expected ${kind} in ${context}, got ${this.peek().kind} ('${this.peek().value}')`,
44
- this.peek().loc
45
- );
46
- }
47
- return this.advance();
48
- }
49
-
50
- match(kind: TokenKind): boolean {
51
- if (this.check(kind)) {
52
- this.advance();
53
- return true;
54
- }
55
- return false;
56
- }
57
- }
1
+ /**
2
+ * bone parser Base — Token stream utilities.
3
+ */
4
+
5
+ import { Token, TokenKind, SourceLocation } from "./lexer";
6
+
7
+ export class ParseError extends Error {
8
+ constructor(message: string, public loc: SourceLocation) {
9
+ super(`Parse error at ${loc.line}:${loc.column}: ${message}`);
10
+ this.name = "ParseError";
11
+ }
12
+ }
13
+
14
+ export class TokenStream {
15
+ private tokens: Token[];
16
+ private pos: number = 0;
17
+
18
+ constructor(tokens: Token[]) {
19
+ this.tokens = tokens;
20
+ }
21
+
22
+ peek(offset: number = 0): Token {
23
+ return this.tokens[this.pos + offset] ?? this.tokens[this.tokens.length - 1];
24
+ }
25
+
26
+ check(kind: TokenKind): boolean {
27
+ return this.peek().kind === kind;
28
+ }
29
+
30
+ checkAny(...kinds: TokenKind[]): boolean {
31
+ return kinds.includes(this.peek().kind);
32
+ }
33
+
34
+ advance(): Token {
35
+ const t = this.tokens[this.pos];
36
+ if (this.pos < this.tokens.length - 1) this.pos++;
37
+ return t;
38
+ }
39
+
40
+ expect(kind: TokenKind, context: string): Token {
41
+ if (!this.check(kind)) {
42
+ throw new ParseError(
43
+ `Expected ${kind} in ${context}, got ${this.peek().kind} ('${this.peek().value}')`,
44
+ this.peek().loc
45
+ );
46
+ }
47
+ return this.advance();
48
+ }
49
+
50
+ match(kind: TokenKind): boolean {
51
+ if (this.check(kind)) {
52
+ this.advance();
53
+ return true;
54
+ }
55
+ return false;
56
+ }
57
+ }