tova 0.11.22 → 0.11.26
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/package.json +2 -2
- package/src/analyzer/analyzer.js +41 -0
- package/src/cli/compile.js +12 -0
- package/src/cli/repl.js +8 -4
- package/src/codegen/base-codegen.js +44 -0
- package/src/lexer/tokens.js +2 -0
- package/src/lsp/server.js +1 -1
- package/src/parser/ast.js +27 -0
- package/src/parser/parser.js +73 -9
- package/src/stdlib/inline.js +14 -0
- package/src/version.js +1 -1
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tova",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.26",
|
|
4
4
|
"description": "Tova — a modern programming language that transpiles to JavaScript, unifying frontend and backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"tova": "
|
|
8
|
+
"tova": "bin/tova.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"bin/",
|
package/src/analyzer/analyzer.js
CHANGED
|
@@ -133,6 +133,7 @@ export class Analyzer {
|
|
|
133
133
|
this._allScopes = []; // Track all scopes for unused variable checking
|
|
134
134
|
this._functionReturnTypeStack = []; // Stack of expected return types for type checking
|
|
135
135
|
this._asyncDepth = 0; // Track nesting inside async functions for await validation
|
|
136
|
+
this._hasDefaultExport = false; // Track duplicate default exports
|
|
136
137
|
|
|
137
138
|
// Propagate strict mode to the type system
|
|
138
139
|
Type.strictMode = this.strict;
|
|
@@ -779,6 +780,8 @@ export class Analyzer {
|
|
|
779
780
|
case 'ImportDefault': return this.visitImportDefault(node);
|
|
780
781
|
case 'ImportWildcard': return this.visitImportWildcard(node);
|
|
781
782
|
case 'ReExportDeclaration': return; // re-exports don't define local symbols
|
|
783
|
+
case 'ExportDefault': return this.visitExportDefault(node);
|
|
784
|
+
case 'ExportList': return this.visitExportList(node);
|
|
782
785
|
case 'IfStatement': return this.visitIfStatement(node);
|
|
783
786
|
case 'ForStatement': return this.visitForStatement(node);
|
|
784
787
|
case 'WhileStatement': return this.visitWhileStatement(node);
|
|
@@ -1689,6 +1692,44 @@ export class Analyzer {
|
|
|
1689
1692
|
}
|
|
1690
1693
|
}
|
|
1691
1694
|
|
|
1695
|
+
visitExportDefault(node) {
|
|
1696
|
+
// Module-level restriction: not valid inside server/browser/edge/shared blocks
|
|
1697
|
+
const ctx = this.currentScope.getContext();
|
|
1698
|
+
if (ctx === 'server' || ctx === 'client' || ctx === 'browser' || ctx === 'shared') {
|
|
1699
|
+
this.warn("'export default' is only valid at module level", node.loc, null, { code: 'W_EXPORT_NOT_MODULE_LEVEL' });
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
// Track duplicate default exports
|
|
1703
|
+
if (this._hasDefaultExport) {
|
|
1704
|
+
this.warn('Module already has a default export', node.loc, null, { code: 'W_DUPLICATE_DEFAULT_EXPORT' });
|
|
1705
|
+
}
|
|
1706
|
+
this._hasDefaultExport = true;
|
|
1707
|
+
|
|
1708
|
+
// Visit the inner value
|
|
1709
|
+
if (node.value) {
|
|
1710
|
+
this.visitNode(node.value);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
visitExportList(node) {
|
|
1715
|
+
// Module-level restriction: not valid inside server/browser/edge/shared blocks
|
|
1716
|
+
const ctx = this.currentScope.getContext();
|
|
1717
|
+
if (ctx === 'server' || ctx === 'client' || ctx === 'browser' || ctx === 'shared') {
|
|
1718
|
+
this.warn("'export { }' is only valid at module level", node.loc, null, { code: 'W_EXPORT_NOT_MODULE_LEVEL' });
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
for (const spec of node.specifiers) {
|
|
1722
|
+
// Check that the referenced name exists in scope
|
|
1723
|
+
const sym = this.currentScope.lookup(spec.local);
|
|
1724
|
+
if (!sym) {
|
|
1725
|
+
this.warn(`'${spec.local}' is not defined`, spec.loc, null, { code: 'W201' });
|
|
1726
|
+
} else {
|
|
1727
|
+
// Mark as public so it doesn't trigger unused warnings
|
|
1728
|
+
sym.isPublic = true;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1692
1733
|
// ─── Statement visitors ───────────────────────────────────
|
|
1693
1734
|
|
|
1694
1735
|
visitBlock(node) {
|
package/src/cli/compile.js
CHANGED
|
@@ -396,6 +396,18 @@ export function collectExports(ast, filename) {
|
|
|
396
396
|
// Wildcard re-exports: pub * from "module" — can't enumerate statically,
|
|
397
397
|
// but mark as having re-exports so import validation can allow through
|
|
398
398
|
}
|
|
399
|
+
if (node.type === 'ExportDefault') {
|
|
400
|
+
publicExports.add('default');
|
|
401
|
+
allNames.add('default');
|
|
402
|
+
// Also collect the inner value's name if it's a named declaration
|
|
403
|
+
if (node.value) collectFromNode(node.value);
|
|
404
|
+
}
|
|
405
|
+
if (node.type === 'ExportList') {
|
|
406
|
+
for (const spec of node.specifiers) {
|
|
407
|
+
publicExports.add(spec.exported);
|
|
408
|
+
allNames.add(spec.exported);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
399
411
|
}
|
|
400
412
|
|
|
401
413
|
for (const node of ast.body) {
|
package/src/cli/repl.js
CHANGED
|
@@ -416,10 +416,14 @@ async function startRepl() {
|
|
|
416
416
|
}
|
|
417
417
|
} catch (e) {
|
|
418
418
|
// If return-wrapping fails, fall back to plain execution
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
419
|
+
try {
|
|
420
|
+
const fallbackCode = replCode + (allSave ? '\n' + allSave : '');
|
|
421
|
+
// REPL context: fallback execution of compiled Tova code (intentional dynamic eval)
|
|
422
|
+
const fn = new Function('__ctx', `${destructure}${fallbackCode}`);
|
|
423
|
+
fn(context);
|
|
424
|
+
} catch (e2) {
|
|
425
|
+
console.error(` Error: ${e2.message}`);
|
|
426
|
+
}
|
|
423
427
|
}
|
|
424
428
|
}
|
|
425
429
|
} catch (err) {
|
|
@@ -3,6 +3,9 @@ import { RESULT_OPTION, PROPAGATE, BUILTIN_NAMES, STDLIB_DEPS } from '../stdlib/
|
|
|
3
3
|
import { PIPE_TARGET } from '../parser/ast.js';
|
|
4
4
|
import { compileWasmFunction, compileWasmModule, generateWasmGlue, generateMultiWasmGlue, generateWasmBytesExport } from './wasm-codegen.js';
|
|
5
5
|
|
|
6
|
+
// Async stdlib functions that should be auto-awaited at the top level (script context)
|
|
7
|
+
const _ASYNC_STDLIB_FUNCS = new Set(['read', 'write', 'readParquet', 'readExcel']);
|
|
8
|
+
|
|
6
9
|
export class BaseCodegen {
|
|
7
10
|
constructor() {
|
|
8
11
|
this.indent = 0;
|
|
@@ -34,6 +37,8 @@ export class BaseCodegen {
|
|
|
34
37
|
this._typedArrayLocals = new Map(); // varName -> 'Float64Array' | 'Int32Array' | 'Uint8Array'
|
|
35
38
|
// Track shadowed parameter names to prevent incorrect substitution in nested lambdas
|
|
36
39
|
this._substitutionShadowed = new Set(); // names shadowed by lambda/function params
|
|
40
|
+
// Track function nesting depth for auto-await of async stdlib functions
|
|
41
|
+
this._functionDepth = 0; // 0 = top level (scripts run in AsyncFunction wrapper)
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
static TYPED_ARRAY_MAP = {
|
|
@@ -282,6 +287,8 @@ export class BaseCodegen {
|
|
|
282
287
|
case 'ImportDefault': result = this.genImportDefault(node); break;
|
|
283
288
|
case 'ImportWildcard': result = this.genImportWildcard(node); break;
|
|
284
289
|
case 'ReExportDeclaration': result = this.genReExport(node); break;
|
|
290
|
+
case 'ExportDefault': result = this.genExportDefault(node); break;
|
|
291
|
+
case 'ExportList': result = this.genExportList(node); break;
|
|
285
292
|
case 'IfStatement': result = this.genIfStatement(node); break;
|
|
286
293
|
case 'ForStatement': result = this.genForStatement(node); break;
|
|
287
294
|
case 'WhileStatement': result = this.genWhileStatement(node); break;
|
|
@@ -573,6 +580,7 @@ export class BaseCodegen {
|
|
|
573
580
|
}
|
|
574
581
|
|
|
575
582
|
this.pushScope();
|
|
583
|
+
this._functionDepth++;
|
|
576
584
|
for (const p of node.params) {
|
|
577
585
|
if (p.destructure) {
|
|
578
586
|
this._declareDestructureVars(p.destructure);
|
|
@@ -581,6 +589,7 @@ export class BaseCodegen {
|
|
|
581
589
|
}
|
|
582
590
|
}
|
|
583
591
|
const body = this.genBlockBody(node.body);
|
|
592
|
+
this._functionDepth--;
|
|
584
593
|
this.popScope();
|
|
585
594
|
|
|
586
595
|
// Restore shadowing state
|
|
@@ -700,6 +709,31 @@ export class BaseCodegen {
|
|
|
700
709
|
return `${this.i()}export { ${specs} } from ${JSON.stringify(node.source)};`;
|
|
701
710
|
}
|
|
702
711
|
|
|
712
|
+
genExportDefault(node) {
|
|
713
|
+
if (node.value && node.value.type === 'FunctionDeclaration') {
|
|
714
|
+
// Generate the function without isPublic (ExportDefault handles export)
|
|
715
|
+
const savedPublic = node.value.isPublic;
|
|
716
|
+
node.value.isPublic = false;
|
|
717
|
+
const fnCode = this.genFunctionDeclaration(node.value);
|
|
718
|
+
node.value.isPublic = savedPublic;
|
|
719
|
+
// Insert 'export default ' before the function declaration
|
|
720
|
+
// Must handle: function, async function, async function*
|
|
721
|
+
return fnCode.replace(/^(\s*)(async\s+)?(?=function)/, '$1export default $2');
|
|
722
|
+
}
|
|
723
|
+
// Expression: export default <expr>;
|
|
724
|
+
// Unwrap ExpressionStatement if present
|
|
725
|
+
const valueNode = node.value.type === 'ExpressionStatement' ? node.value.expression : node.value;
|
|
726
|
+
const expr = this.genExpression(valueNode);
|
|
727
|
+
return `${this.i()}export default ${expr};`;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
genExportList(node) {
|
|
731
|
+
const specs = node.specifiers.map(s =>
|
|
732
|
+
s.local === s.exported ? s.local : `${s.local} as ${s.exported}`
|
|
733
|
+
).join(', ');
|
|
734
|
+
return `${this.i()}export { ${specs} };`;
|
|
735
|
+
}
|
|
736
|
+
|
|
703
737
|
genIfStatement(node) {
|
|
704
738
|
const p = [];
|
|
705
739
|
p.push(`${this.i()}if (${this.genExpression(node.condition)}) {\n`);
|
|
@@ -1669,6 +1703,10 @@ export class BaseCodegen {
|
|
|
1669
1703
|
}
|
|
1670
1704
|
|
|
1671
1705
|
const args = node.arguments.map(a => this.genExpression(a)).join(', ');
|
|
1706
|
+
// Auto-await known async stdlib functions at top level (scripts run in AsyncFunction wrapper)
|
|
1707
|
+
if (this._functionDepth === 0 && node.callee.type === 'Identifier' && _ASYNC_STDLIB_FUNCS.has(node.callee.name)) {
|
|
1708
|
+
return `(await ${callee}(${args}))`;
|
|
1709
|
+
}
|
|
1672
1710
|
return `${callee}(${args})`;
|
|
1673
1711
|
}
|
|
1674
1712
|
|
|
@@ -2507,8 +2545,10 @@ export class BaseCodegen {
|
|
|
2507
2545
|
|
|
2508
2546
|
if (node.body.type === 'BlockStatement') {
|
|
2509
2547
|
this.pushScope();
|
|
2548
|
+
this._functionDepth++;
|
|
2510
2549
|
for (const p of node.params) { if (p.destructure) this._declareDestructureVars(p.destructure); else this.declareVar(p.name); }
|
|
2511
2550
|
const body = this.genBlockBody(node.body);
|
|
2551
|
+
this._functionDepth--;
|
|
2512
2552
|
this.popScope();
|
|
2513
2553
|
// Restore shadowing state
|
|
2514
2554
|
for (const name of shadowedNames) {
|
|
@@ -2532,10 +2572,12 @@ export class BaseCodegen {
|
|
|
2532
2572
|
// Statement bodies (compound assignment, assignment in lambda)
|
|
2533
2573
|
if (node.body.type === 'CompoundAssignment' || node.body.type === 'Assignment' || node.body.type === 'VarDeclaration') {
|
|
2534
2574
|
this.pushScope();
|
|
2575
|
+
this._functionDepth++;
|
|
2535
2576
|
for (const p of node.params) { if (p.destructure) this._declareDestructureVars(p.destructure); else this.declareVar(p.name); }
|
|
2536
2577
|
this.indent++;
|
|
2537
2578
|
const stmt = this.generateStatement(node.body);
|
|
2538
2579
|
this.indent--;
|
|
2580
|
+
this._functionDepth--;
|
|
2539
2581
|
this.popScope();
|
|
2540
2582
|
// Restore shadowing state
|
|
2541
2583
|
for (const name of shadowedNames) {
|
|
@@ -2545,12 +2587,14 @@ export class BaseCodegen {
|
|
|
2545
2587
|
}
|
|
2546
2588
|
|
|
2547
2589
|
// Expression body
|
|
2590
|
+
this._functionDepth++;
|
|
2548
2591
|
let bodyCode;
|
|
2549
2592
|
if (hasPropagate) {
|
|
2550
2593
|
bodyCode = `${asyncPrefix}(${params}) => { try { return ${this.genExpression(node.body)}; } catch (__e) { if (__e && __e.__tova_propagate) return __e.value; throw __e; } }`;
|
|
2551
2594
|
} else {
|
|
2552
2595
|
bodyCode = `${asyncPrefix}(${params}) => ${this.genExpression(node.body)}`;
|
|
2553
2596
|
}
|
|
2597
|
+
this._functionDepth--;
|
|
2554
2598
|
// Restore shadowing state
|
|
2555
2599
|
for (const name of shadowedNames) {
|
|
2556
2600
|
this._substitutionShadowed.delete(name);
|
package/src/lexer/tokens.js
CHANGED
|
@@ -56,6 +56,7 @@ export const TokenType = {
|
|
|
56
56
|
|
|
57
57
|
// Visibility
|
|
58
58
|
PUB: 'PUB',
|
|
59
|
+
DEFAULT: 'DEFAULT',
|
|
59
60
|
|
|
60
61
|
// Impl blocks / traits
|
|
61
62
|
IMPL: 'IMPL',
|
|
@@ -224,6 +225,7 @@ export const Keywords = {
|
|
|
224
225
|
'loop': TokenType.LOOP,
|
|
225
226
|
'when': TokenType.WHEN,
|
|
226
227
|
'extern': TokenType.EXTERN,
|
|
228
|
+
'default': TokenType.DEFAULT,
|
|
227
229
|
'is': TokenType.IS,
|
|
228
230
|
'with': TokenType.WITH,
|
|
229
231
|
'server': TokenType.SERVER,
|
package/src/lsp/server.js
CHANGED
|
@@ -518,7 +518,7 @@ class TovaLanguageServer {
|
|
|
518
518
|
const keywords = [
|
|
519
519
|
'fn', 'if', 'elif', 'else', 'for', 'while', 'loop', 'when', 'in',
|
|
520
520
|
'return', 'match', 'type', 'import', 'from', 'true', 'false',
|
|
521
|
-
'nil', 'server', 'browser', 'client', 'shared', 'pub', 'mut',
|
|
521
|
+
'nil', 'server', 'browser', 'client', 'shared', 'pub', 'export', 'default', 'mut',
|
|
522
522
|
'try', 'catch', 'finally', 'break', 'continue', 'async', 'await',
|
|
523
523
|
'guard', 'interface', 'derive', 'route', 'model', 'db',
|
|
524
524
|
];
|
package/src/parser/ast.js
CHANGED
|
@@ -235,6 +235,33 @@ export class ReExportSpecifier {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
// export default <value>
|
|
239
|
+
export class ExportDefault {
|
|
240
|
+
constructor(value, loc) {
|
|
241
|
+
this.type = 'ExportDefault';
|
|
242
|
+
this.value = value; // FunctionDeclaration or expression node
|
|
243
|
+
this.loc = loc;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// export { a, b as c } (post-declaration, no source/from)
|
|
248
|
+
export class ExportList {
|
|
249
|
+
constructor(specifiers, loc) {
|
|
250
|
+
this.type = 'ExportList';
|
|
251
|
+
this.specifiers = specifiers; // [{local, exported}]
|
|
252
|
+
this.loc = loc;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export class ExportListSpecifier {
|
|
257
|
+
constructor(local, exported, loc) {
|
|
258
|
+
this.type = 'ExportListSpecifier';
|
|
259
|
+
this.local = local; // name in current scope
|
|
260
|
+
this.exported = exported; // exported name (same as local if no alias)
|
|
261
|
+
this.loc = loc;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
238
265
|
// ============================================================
|
|
239
266
|
// Statements
|
|
240
267
|
// ============================================================
|
package/src/parser/parser.js
CHANGED
|
@@ -109,7 +109,7 @@ export class Parser {
|
|
|
109
109
|
tok.type === TokenType.BROWSER || tok.type === TokenType.SHARED ||
|
|
110
110
|
tok.type === TokenType.GUARD || tok.type === TokenType.INTERFACE ||
|
|
111
111
|
tok.type === TokenType.IMPL || tok.type === TokenType.TRAIT ||
|
|
112
|
-
tok.type === TokenType.PUB || tok.type === TokenType.DEFER ||
|
|
112
|
+
tok.type === TokenType.PUB || tok.type === TokenType.EXPORT || tok.type === TokenType.DEFER ||
|
|
113
113
|
tok.type === TokenType.EXTERN ||
|
|
114
114
|
tok.type === TokenType.VAR || tok.type === TokenType.ASYNC) {
|
|
115
115
|
return;
|
|
@@ -160,7 +160,7 @@ export class Parser {
|
|
|
160
160
|
tok.type === TokenType.BROWSER || tok.type === TokenType.SHARED ||
|
|
161
161
|
tok.type === TokenType.GUARD || tok.type === TokenType.INTERFACE ||
|
|
162
162
|
tok.type === TokenType.IMPL || tok.type === TokenType.TRAIT ||
|
|
163
|
-
tok.type === TokenType.PUB || tok.type === TokenType.DEFER ||
|
|
163
|
+
tok.type === TokenType.PUB || tok.type === TokenType.EXPORT || tok.type === TokenType.DEFER ||
|
|
164
164
|
tok.type === TokenType.EXTERN || tok.type === TokenType.VAR || tok.type === TokenType.MUT ||
|
|
165
165
|
tok.type === TokenType.STATE || tok.type === TokenType.ROUTE ||
|
|
166
166
|
tok.type === TokenType.IDENTIFIER) {
|
|
@@ -549,6 +549,7 @@ export class Parser {
|
|
|
549
549
|
parseStatement() {
|
|
550
550
|
// pub modifier: pub fn, pub type, pub x = ...
|
|
551
551
|
if (this.check(TokenType.PUB)) return this.parsePubDeclaration();
|
|
552
|
+
if (this.check(TokenType.EXPORT)) return this.parsePubDeclaration();
|
|
552
553
|
if (this.check(TokenType.ASYNC) && this.peek(1).type === TokenType.FOR) {
|
|
553
554
|
this.advance(); // consume async
|
|
554
555
|
return this.parseForStatement(null, true);
|
|
@@ -595,17 +596,35 @@ export class Parser {
|
|
|
595
596
|
|
|
596
597
|
parsePubDeclaration() {
|
|
597
598
|
const l = this.loc();
|
|
598
|
-
this.
|
|
599
|
-
|
|
600
|
-
|
|
599
|
+
const keyword = this.current().type; // PUB or EXPORT
|
|
600
|
+
this.advance(); // consume 'pub' or 'export'
|
|
601
|
+
if (this.check(TokenType.PUB) || this.check(TokenType.EXPORT)) {
|
|
602
|
+
this.error("Duplicate visibility modifier");
|
|
601
603
|
}
|
|
602
|
-
//
|
|
604
|
+
// export default: only valid with 'export', not 'pub'
|
|
605
|
+
if (this.check(TokenType.DEFAULT)) {
|
|
606
|
+
if (keyword === TokenType.PUB) {
|
|
607
|
+
this.error("Use 'export default', not 'pub default'");
|
|
608
|
+
}
|
|
609
|
+
this.advance(); // consume 'default'
|
|
610
|
+
// export default type is invalid (types generate multiple statements)
|
|
611
|
+
if (this.check(TokenType.TYPE)) {
|
|
612
|
+
this.error("Cannot use 'export default' with type declarations. Use 'export type' instead");
|
|
613
|
+
}
|
|
614
|
+
const stmt = this.parseStatement();
|
|
615
|
+
return new AST.ExportDefault(stmt, l);
|
|
616
|
+
}
|
|
617
|
+
// Re-export: pub/export { a, b } from "module" or pub/export * from "module"
|
|
603
618
|
if (this.check(TokenType.STAR) && this.peek(1).type === TokenType.FROM) {
|
|
604
619
|
return this.parseReExport(l);
|
|
605
620
|
}
|
|
606
621
|
if (this.check(TokenType.LBRACE) && this._looksLikeReExport()) {
|
|
607
622
|
return this.parseReExport(l);
|
|
608
623
|
}
|
|
624
|
+
// Post-declaration export list: pub/export { a, b } (no 'from')
|
|
625
|
+
if (this.check(TokenType.LBRACE) && this._looksLikeExportList()) {
|
|
626
|
+
return this.parseExportList(l);
|
|
627
|
+
}
|
|
609
628
|
// Handle pub component at top level (parseComponent is installed by browser-parser plugin)
|
|
610
629
|
if (this.check(TokenType.COMPONENT) && typeof this.parseComponent === 'function') {
|
|
611
630
|
const comp = this.parseComponent();
|
|
@@ -644,10 +663,55 @@ export class Parser {
|
|
|
644
663
|
}
|
|
645
664
|
}
|
|
646
665
|
|
|
666
|
+
// Check if pub/export { ... } is a post-declaration export list (no 'from' after })
|
|
667
|
+
_looksLikeExportList() {
|
|
668
|
+
let i = 1; // start after {
|
|
669
|
+
while (true) {
|
|
670
|
+
const tok = this.peek(i);
|
|
671
|
+
if (!tok || tok.type === TokenType.EOF) return false;
|
|
672
|
+
if (tok.type === TokenType.RBRACE) {
|
|
673
|
+
// After }, must NOT see FROM (that would be a re-export)
|
|
674
|
+
const after = this.peek(i + 1);
|
|
675
|
+
return !after || after.type !== TokenType.FROM;
|
|
676
|
+
}
|
|
677
|
+
if (tok.type !== TokenType.IDENTIFIER) return false;
|
|
678
|
+
i++;
|
|
679
|
+
const next = this.peek(i);
|
|
680
|
+
if (next && next.type === TokenType.AS) {
|
|
681
|
+
i++; // skip as
|
|
682
|
+
i++; // skip alias identifier
|
|
683
|
+
}
|
|
684
|
+
const afterId = this.peek(i);
|
|
685
|
+
if (!afterId) return false;
|
|
686
|
+
if (afterId.type === TokenType.COMMA) { i++; continue; }
|
|
687
|
+
if (afterId.type === TokenType.RBRACE) continue;
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
parseExportList(l) {
|
|
693
|
+
this.expect(TokenType.LBRACE);
|
|
694
|
+
const specifiers = [];
|
|
695
|
+
while (!this.check(TokenType.RBRACE)) {
|
|
696
|
+
const specL = this.loc();
|
|
697
|
+
const local = this.expect(TokenType.IDENTIFIER, "Expected export name").value;
|
|
698
|
+
let exported = local;
|
|
699
|
+
if (this.match(TokenType.AS)) {
|
|
700
|
+
exported = this.expect(TokenType.IDENTIFIER, "Expected alias name after 'as'").value;
|
|
701
|
+
}
|
|
702
|
+
specifiers.push(new AST.ExportListSpecifier(local, exported, specL));
|
|
703
|
+
if (!this.check(TokenType.RBRACE)) {
|
|
704
|
+
this.expect(TokenType.COMMA, "Expected ',' or '}' in export list");
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
this.expect(TokenType.RBRACE);
|
|
708
|
+
return new AST.ExportList(specifiers, l);
|
|
709
|
+
}
|
|
710
|
+
|
|
647
711
|
parseReExport(l) {
|
|
648
712
|
if (this.match(TokenType.STAR)) {
|
|
649
|
-
// pub * from "module"
|
|
650
|
-
this.expect(TokenType.FROM, "Expected 'from' after '
|
|
713
|
+
// pub/export * from "module"
|
|
714
|
+
this.expect(TokenType.FROM, "Expected 'from' after '*'");
|
|
651
715
|
const source = this.expect(TokenType.STRING, "Expected module path string").value;
|
|
652
716
|
return new AST.ReExportDeclaration(null, source, l);
|
|
653
717
|
}
|
|
@@ -989,7 +1053,7 @@ export class Parser {
|
|
|
989
1053
|
params.push(param);
|
|
990
1054
|
} else {
|
|
991
1055
|
let name;
|
|
992
|
-
if (this._isContextualKeyword()) {
|
|
1056
|
+
if (this._isContextualKeyword() || this.check(TokenType.DEFAULT)) {
|
|
993
1057
|
name = this.advance().value;
|
|
994
1058
|
} else {
|
|
995
1059
|
name = this.expect(TokenType.IDENTIFIER, "Expected parameter name").value;
|
package/src/stdlib/inline.js
CHANGED
|
@@ -74,6 +74,7 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
74
74
|
var _pretty = function(v) {
|
|
75
75
|
if (v === null || v === undefined) return v;
|
|
76
76
|
if (typeof v !== 'object') return v;
|
|
77
|
+
if (v && typeof v._format === 'function') return v._format();
|
|
77
78
|
if (Array.isArray(v) && v.length > 0 && typeof v[0] === 'object' && v[0] !== null && !Array.isArray(v[0])) {
|
|
78
79
|
var headers = Object.keys(v[0]);
|
|
79
80
|
var rows = v.map(function(r) { return headers.map(function(h) { return String(r[h] != null ? r[h] : ''); }); });
|
|
@@ -1897,6 +1898,19 @@ export const STDLIB_DEPS = {
|
|
|
1897
1898
|
lazy: ['LazyTable', 'Table'],
|
|
1898
1899
|
collect: ['LazyTable'],
|
|
1899
1900
|
LazyTable: ['Table', 'table_where', 'table_group_by'],
|
|
1901
|
+
// Table wrapper functions reference LazyTable + their table_* implementation
|
|
1902
|
+
where: ['LazyTable', 'table_where', 'Table'],
|
|
1903
|
+
select: ['LazyTable', 'table_select', 'Table'],
|
|
1904
|
+
derive: ['LazyTable', 'table_derive', 'Table'],
|
|
1905
|
+
sort_by: ['LazyTable', 'table_sort_by', 'Table'],
|
|
1906
|
+
limit: ['LazyTable', 'table_limit', 'Table'],
|
|
1907
|
+
drop_duplicates: ['LazyTable', 'table_drop_duplicates', 'Table'],
|
|
1908
|
+
rename: ['LazyTable', 'table_rename', 'Table'],
|
|
1909
|
+
agg: ['table_agg', 'Table'],
|
|
1910
|
+
// Table functions that reference Table constructor
|
|
1911
|
+
drop_nil: ['Table'],
|
|
1912
|
+
fill_nil: ['Table'],
|
|
1913
|
+
cast: ['Table'],
|
|
1900
1914
|
// Seq uses Some/None
|
|
1901
1915
|
Seq: ['Some', 'None'],
|
|
1902
1916
|
// Channel uses Some/None
|
package/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by scripts/embed-runtime.js — do not edit
|
|
2
|
-
export const VERSION = "0.11.
|
|
2
|
+
export const VERSION = "0.11.26";
|