From 89aa120fd25c42578d400f6042402462e60f339c Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 9 Nov 2025 18:55:31 -0800 Subject: [PATCH] add `import` keyword for importing keys of dicts into local scope --- src/compiler/compiler.ts | 17 +++++++++++++++++ src/compiler/tests/compiler.test.ts | 18 ++++++++++++++++++ src/parser/shrimp.grammar | 7 +++++++ src/parser/shrimp.terms.ts | 7 ++++--- src/parser/shrimp.ts | 20 ++++++++++---------- src/parser/tests/basics.test.ts | 20 ++++++++++++++++++++ src/prelude/index.ts | 13 +++++++++++++ 7 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 7cf9255..3883022 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -797,6 +797,23 @@ export class Compiler { return instructions } + case terms.Import: { + const instructions: ProgramItem[] = [] + const [_import, ...dicts] = getAllChildren(node) + + instructions.push(['LOAD', 'import']) + + dicts.forEach((dict) => + instructions.push(['PUSH', input.slice(dict.from, dict.to)]) + ) + + instructions.push(['PUSH', dicts.length]) + instructions.push(['PUSH', 0]) + instructions.push(['CALL']) + + return instructions + } + case terms.Comment: { return [] // ignore comments } diff --git a/src/compiler/tests/compiler.test.ts b/src/compiler/tests/compiler.test.ts index 1965e89..5194300 100644 --- a/src/compiler/tests/compiler.test.ts +++ b/src/compiler/tests/compiler.test.ts @@ -448,3 +448,21 @@ describe('Compound assignment operators', () => { expect('x = 10; x %= 3; x').toEvaluateTo(1) }) }) + +describe('import', () => { + test('imports single dict', () => { + expect(`import str; starts-with? abc a`).toEvaluateTo(true) + }) + + test('imports multiple dicts', () => { + expect(`import str math list; map [1 2 3] do x: x * 2 end`).toEvaluateTo([2, 4, 6]) + }) + + test('imports non-prelude dicts', () => { + expect(` + abc = [a=true b=yes c=si] + import abc + abc.b + `).toEvaluateTo('yes') + }) +}) \ No newline at end of file diff --git a/src/parser/shrimp.grammar b/src/parser/shrimp.grammar index c01fd18..248020a 100644 --- a/src/parser/shrimp.grammar +++ b/src/parser/shrimp.grammar @@ -40,6 +40,7 @@ try { @specialize[@name=keyword] } catch { @specialize[@name=keyword] } finally { @specialize[@name=keyword] } throw { @specialize[@name=keyword] } +import { @specialize[@name=keyword] } null { @specialize[@name=Null] } @external tokens tokenizer from "./tokenizer" { Identifier, AssignableIdentifier, Word, IdentifierBeforeDot, CurlyString } @@ -71,6 +72,7 @@ consumeToTerminator { ambiguousFunctionCall | TryExpr | Throw | + Import | IfExpr | FunctionDef | CompoundAssign | @@ -160,6 +162,11 @@ Throw { throw (BinOp | ConditionalOp | expression) } +// this has to be in the parse tree so the scope tracker can use it +Import { + import AssignableIdentifier+ +} + ConditionalOp { expression !comparison EqEq expression | expression !comparison Neq expression | diff --git a/src/parser/shrimp.terms.ts b/src/parser/shrimp.terms.ts index 0f49afe..0f3ba5b 100644 --- a/src/parser/shrimp.terms.ts +++ b/src/parser/shrimp.terms.ts @@ -37,7 +37,7 @@ export const Program = 35, PipeExpr = 36, WhileExpr = 38, - keyword = 81, + keyword = 83, ConditionalOp = 40, ParenExpr = 41, FunctionCallWithNewlines = 42, @@ -73,5 +73,6 @@ export const FunctionCallWithBlock = 77, TryExpr = 78, Throw = 80, - CompoundAssign = 82, - Assign = 83 + Import = 82, + CompoundAssign = 84, + Assign = 85 diff --git a/src/parser/shrimp.ts b/src/parser/shrimp.ts index 3f09fb1..087cc22 100644 --- a/src/parser/shrimp.ts +++ b/src/parser/shrimp.ts @@ -4,24 +4,24 @@ import {operatorTokenizer} from "./operatorTokenizer" import {tokenizer, specializeKeyword} from "./tokenizer" import {trackScope} from "./parserScopeContext" import {highlighting} from "./highlight" -const spec_Identifier = {__proto__:null,while:78, null:112, catch:118, finally:124, end:126, if:134, else:140, try:158, throw:162} +const spec_Identifier = {__proto__:null,while:78, null:112, catch:118, finally:124, end:126, if:134, else:140, try:158, throw:162, import:166} export const parser = LRParser.deserialize({ version: 14, - states: "UQQO,5:[O>ZQRO,59nO>bQRO,59nO:lQbO,5:hO>pQcO,5:jO@OQcO,5:jO@lQcO,5:jOOQa1G/_1G/_OOOO,59|,59|OOOO,59},59}OOOO-E8V-E8VOOQa1G/f1G/fOOQ`,5:Z,5:ZOOQ`-E8Y-E8YOOQa1G/}1G/}OBhQcO1G/}OBrQcO1G/}ODQQcO1G/}OD[QcO1G/}ODiQcO1G/}OOQa1G/[1G/[OEzQcO1G/[OFRQcO1G/[OFYQcO1G/[OGXQcO1G/[OFaQcO1G/[OOQ`-E8S-E8SOGoQRO1G/]OGyQQO1G/]OHOQQO1G/]OHWQQO1G/]OHcQRO1G/]OHjQRO1G/]OHqQbO,59rOH{QQO1G/]OOQa1G/]1G/]OITQQO1G0POOQa1G0Q1G0QOI`QbO1G0QOOQO'#E^'#E^OITQQO1G0POOQa1G0P1G0POOQ`'#E_'#E_OI`QbO1G0QOIjQbO1G0XOJUQbO1G0WOJpQbO'#DjOKRQbO'#DjOKfQbO1G0ROOQ`-E8R-E8ROOQ`,5:o,5:oOOQ`-E8T-E8TOKqQQO,59wOOQO,59x,59xOOQO-E8U-E8UOKyQbO1G/bO:lQbO1G/vO:lQbO1G/YOLQQbO1G0SOL]QQO7+$wOOQa7+$w7+$wOLeQQO1G/^OLmQQO7+%kOOQa7+%k7+%kOLxQbO7+%lOOQa7+%l7+%lOOQO-E8[-E8[OOQ`-E8]-E8]OOQ`'#EY'#EYOMSQQO'#EYOM[QbO'#ErOOQ`,5:U,5:UOMoQbO'#DhOMtQQO'#DkOOQ`7+%m7+%mOMyQbO7+%mONOQbO7+%mONWQbO7+$|ONfQbO7+$|ONvQbO7+%bO! OQbO7+$tOOQ`7+%n7+%nO! TQbO7+%nO! YQbO7+%nOOQa<sAN>sOOQ`AN>SAN>SO!#dQbOAN>SO!#iQbOAN>SOOQ`-E8Z-E8ZOOQ`AN>hAN>hO!#qQbOAN>hO2sQbO,5:_O:lQbO,5:aOOQ`AN>tAN>tPHqQbO'#EUOOQ`7+%Y7+%YOOQ`G23nG23nO!#vQbOG23nP!!vQbO'#DsOOQ`G24SG24SO!#{QQO1G/yOOQ`1G/{1G/{OOQ`LD)YLD)YO:lQbO7+%eOOQ`<]QRO'#EvOOQO'#Ev'#EvO>dQQO,5:[O>iQRO,59nO>pQRO,59nO:zQbO,5:hO?OQcO,5:jO@^QcO,5:jO@zQcO,5:jOOQ`'#Eb'#EbOAoQbO,5:lOOQa1G/_1G/_OOOO,59|,59|OOOO,59},59}OOOO-E8X-E8XOOQa1G/f1G/fOOQ`,5:Z,5:ZOOQ`-E8[-E8[OOQa1G/}1G/}OCeQcO1G/}OCoQcO1G/}OD}QcO1G/}OEXQcO1G/}OEfQcO1G/}OOQa1G/[1G/[OFwQcO1G/[OGOQcO1G/[OGVQcO1G/[OHUQcO1G/[OG^QcO1G/[OOQ`-E8U-E8UOHlQRO1G/]OHvQQO1G/]OH{QQO1G/]OITQQO1G/]OI`QRO1G/]OIgQRO1G/]OInQbO,59rOIxQQO1G/]OOQa1G/]1G/]OJQQQO1G0POOQa1G0Q1G0QOJ]QbO1G0QOOQO'#E`'#E`OJQQQO1G0POOQa1G0P1G0POOQ`'#Ea'#EaOJ]QbO1G0QOJgQbO1G0ZOKRQbO1G0YOKmQbO'#DjOLOQbO'#DjOLcQbO1G0ROOQ`-E8T-E8TOOQ`,5:q,5:qOOQ`-E8V-E8VOLnQQO,59wOOQO,59x,59xOOQO-E8W-E8WOLvQbO1G/bO:zQbO1G/vO:zQbO1G/YOL}QbO1G0SOOQ`-E8`-E8`OMYQQO7+$wOOQa7+$w7+$wOMbQQO1G/^OMjQQO7+%kOOQa7+%k7+%kOMuQbO7+%lOOQa7+%l7+%lOOQO-E8^-E8^OOQ`-E8_-E8_OOQ`'#E['#E[ONPQQO'#E[ONXQbO'#EuOOQ`,5:U,5:UONlQbO'#DhONqQQO'#DkOOQ`7+%m7+%mONvQbO7+%mON{QbO7+%mO! TQbO7+$|O! cQbO7+$|O! sQbO7+%bO! {QbO7+$tOOQ`7+%n7+%nO!!QQbO7+%nO!!VQbO7+%nOOQa<sAN>sOOQ`AN>SAN>SO!$aQbOAN>SO!$fQbOAN>SOOQ`-E8]-E8]OOQ`AN>hAN>hO!$nQbOAN>hO2yQbO,5:_O:zQbO,5:aOOQ`AN>tAN>tPInQbO'#EWOOQ`7+%Y7+%YOOQ`G23nG23nO!$sQbOG23nP!#sQbO'#DsOOQ`G24SG24SO!$xQQO1G/yOOQ`1G/{1G/{OOQ`LD)YLD)YO:zQbO7+%eOOQ`<d#S#T$R#T#Y>}#Y#Z@i#Z#b>}#b#cFV#c#f>}#f#gGY#g#h>}#h#iH]#i#o>}#o#p$R#p#qJm#q;'S$R;'S;=`$j<%l~$R~O$R~~KWS$WU!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RS$mP;=`<%l$R^$wU!TS#UYOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU%bU!TS#[QOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU%yZ!TSOr%trs&lst%ttu'Vuw%twx'Vx#O%t#O#P'V#P;'S%t;'S;=`'t<%lO%tU&sU!WQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RQ'YTOr'Vrs'is;'S'V;'S;=`'n<%lO'VQ'nO!WQQ'qP;=`<%l'VU'wP;=`<%l%t^(RZrY!TSOY'zYZ$RZt'ztu(tuw'zwx(tx#O'z#O#P(t#P;'S'z;'S;=`)]<%lO'zY(ySrYOY(tZ;'S(t;'S;=`)V<%lO(tY)YP;=`<%l(t^)`P;=`<%l'z~)hO#a~~)mO#_~U)tU!TS#ZQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU*_U!TS#iQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU*vX!TSOt$Ruw$Rx!Q$R!Q!R+c!R![.Q![#O$R#P;'S$R;'S;=`$j<%lO$RU+j`!TS|QOt$Ruw$Rx!O$R!O!P,l!P!Q$R!Q![.Q![#O$R#P#R$R#R#S.}#S#U$R#U#V/l#V#l$R#l#m1Q#m;'S$R;'S;=`$j<%lO$RU,qW!TSOt$Ruw$Rx!Q$R!Q![-Z![#O$R#P;'S$R;'S;=`$j<%lO$RU-bY!TS|QOt$Ruw$Rx!Q$R!Q![-Z![#O$R#P#R$R#R#S,l#S;'S$R;'S;=`$j<%lO$RU.X[!TS|QOt$Ruw$Rx!O$R!O!P,l!P!Q$R!Q![.Q![#O$R#P#R$R#R#S.}#S;'S$R;'S;=`$j<%lO$RU/SW!TSOt$Ruw$Rx!Q$R!Q![.Q![#O$R#P;'S$R;'S;=`$j<%lO$RU/qX!TSOt$Ruw$Rx!Q$R!Q!R0^!R!S0^!S#O$R#P;'S$R;'S;=`$j<%lO$RU0eX!TS|QOt$Ruw$Rx!Q$R!Q!R0^!R!S0^!S#O$R#P;'S$R;'S;=`$j<%lO$RU1V[!TSOt$Ruw$Rx!Q$R!Q![1{![!c$R!c!i1{!i#O$R#P#T$R#T#Z1{#Z;'S$R;'S;=`$j<%lO$RU2S[!TS|QOt$Ruw$Rx!Q$R!Q![1{![!c$R!c!i1{!i#O$R#P#T$R#T#Z1{#Z;'S$R;'S;=`$j<%lO$RU2}W!TSOt$Ruw$Rx!P$R!P!Q3g!Q#O$R#P;'S$R;'S;=`$j<%lO$RU3l^!TSOY4hYZ$RZt4htu5kuw4hwx5kx!P4h!P!Q$R!Q!}4h!}#O:^#O#P7y#P;'S4h;'S;=`;_<%lO4hU4o^!TS!lQOY4hYZ$RZt4htu5kuw4hwx5kx!P4h!P!Q8`!Q!}4h!}#O:^#O#P7y#P;'S4h;'S;=`;_<%lO4hQ5pX!lQOY5kZ!P5k!P!Q6]!Q!}5k!}#O6z#O#P7y#P;'S5k;'S;=`8Y<%lO5kQ6`P!P!Q6cQ6hU!lQ#Z#[6c#]#^6c#a#b6c#g#h6c#i#j6c#m#n6cQ6}VOY6zZ#O6z#O#P7d#P#Q5k#Q;'S6z;'S;=`7s<%lO6zQ7gSOY6zZ;'S6z;'S;=`7s<%lO6zQ7vP;=`<%l6zQ7|SOY5kZ;'S5k;'S;=`8Y<%lO5kQ8]P;=`<%l5kU8eW!TSOt$Ruw$Rx!P$R!P!Q8}!Q#O$R#P;'S$R;'S;=`$j<%lO$RU9Ub!TS!lQOt$Ruw$Rx#O$R#P#Z$R#Z#[8}#[#]$R#]#^8}#^#a$R#a#b8}#b#g$R#g#h8}#h#i$R#i#j8}#j#m$R#m#n8}#n;'S$R;'S;=`$j<%lO$RU:c[!TSOY:^YZ$RZt:^tu6zuw:^wx6zx#O:^#O#P7d#P#Q4h#Q;'S:^;'S;=`;X<%lO:^U;[P;=`<%l:^U;bP;=`<%l4hU;lU!TS!ZQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RUQU#lQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU>kU!TS!bQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU?S^!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$RU@VU!RQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU@n_!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#UAm#U#o>}#o;'S$R;'S;=`$j<%lO$RUAr`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#`>}#`#aBt#a#o>}#o;'S$R;'S;=`$j<%lO$RUBy`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#g>}#g#hC{#h#o>}#o;'S$R;'S;=`$j<%lO$RUDQ`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#X>}#X#YES#Y#o>}#o;'S$R;'S;=`$j<%lO$RUEZ^!XQ!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^F^^#cW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^Ga^#eW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^Hd`#dW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#f>}#f#gIf#g#o>}#o;'S$R;'S;=`$j<%lO$RUIk`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#i>}#i#jC{#j#o>}#o;'S$R;'S;=`$j<%lO$RUJtUuQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$R~K]O#m~", - tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO#]~~", 11)], + repeatNodeCount: 13, + tokenData: "K]~R!OOX$RXY$pYZ%ZZp$Rpq$pqr$Rrs%tst'ztu)cuw$Rwx)hxy)myz*Wz{$R{|*q|}$R}!O*q!O!P$R!P!Q2x!Q!R+c!R![.Q![!];e!]!^%Z!^!}$R!}#Od#S#T$R#T#Y>}#Y#Z@i#Z#b>}#b#cFV#c#f>}#f#gGY#g#h>}#h#iH]#i#o>}#o#p$R#p#qJm#q;'S$R;'S;=`$j<%l~$R~O$R~~KWS$WU!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RS$mP;=`<%l$R^$wU!TS#XYOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU%bU!TS#_QOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU%yZ!TSOr%trs&lst%ttu'Vuw%twx'Vx#O%t#O#P'V#P;'S%t;'S;=`'t<%lO%tU&sU!WQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RQ'YTOr'Vrs'is;'S'V;'S;=`'n<%lO'VQ'nO!WQQ'qP;=`<%l'VU'wP;=`<%l%t^(RZrY!TSOY'zYZ$RZt'ztu(tuw'zwx(tx#O'z#O#P(t#P;'S'z;'S;=`)]<%lO'zY(ySrYOY(tZ;'S(t;'S;=`)V<%lO(tY)YP;=`<%l(t^)`P;=`<%l'z~)hO#d~~)mO#b~U)tU!TS#^QOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU*_U!TS#lQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU*vX!TSOt$Ruw$Rx!Q$R!Q!R+c!R![.Q![#O$R#P;'S$R;'S;=`$j<%lO$RU+j`!TS|QOt$Ruw$Rx!O$R!O!P,l!P!Q$R!Q![.Q![#O$R#P#R$R#R#S.}#S#U$R#U#V/l#V#l$R#l#m1Q#m;'S$R;'S;=`$j<%lO$RU,qW!TSOt$Ruw$Rx!Q$R!Q![-Z![#O$R#P;'S$R;'S;=`$j<%lO$RU-bY!TS|QOt$Ruw$Rx!Q$R!Q![-Z![#O$R#P#R$R#R#S,l#S;'S$R;'S;=`$j<%lO$RU.X[!TS|QOt$Ruw$Rx!O$R!O!P,l!P!Q$R!Q![.Q![#O$R#P#R$R#R#S.}#S;'S$R;'S;=`$j<%lO$RU/SW!TSOt$Ruw$Rx!Q$R!Q![.Q![#O$R#P;'S$R;'S;=`$j<%lO$RU/qX!TSOt$Ruw$Rx!Q$R!Q!R0^!R!S0^!S#O$R#P;'S$R;'S;=`$j<%lO$RU0eX!TS|QOt$Ruw$Rx!Q$R!Q!R0^!R!S0^!S#O$R#P;'S$R;'S;=`$j<%lO$RU1V[!TSOt$Ruw$Rx!Q$R!Q![1{![!c$R!c!i1{!i#O$R#P#T$R#T#Z1{#Z;'S$R;'S;=`$j<%lO$RU2S[!TS|QOt$Ruw$Rx!Q$R!Q![1{![!c$R!c!i1{!i#O$R#P#T$R#T#Z1{#Z;'S$R;'S;=`$j<%lO$RU2}W!TSOt$Ruw$Rx!P$R!P!Q3g!Q#O$R#P;'S$R;'S;=`$j<%lO$RU3l^!TSOY4hYZ$RZt4htu5kuw4hwx5kx!P4h!P!Q$R!Q!}4h!}#O:^#O#P7y#P;'S4h;'S;=`;_<%lO4hU4o^!TS!lQOY4hYZ$RZt4htu5kuw4hwx5kx!P4h!P!Q8`!Q!}4h!}#O:^#O#P7y#P;'S4h;'S;=`;_<%lO4hQ5pX!lQOY5kZ!P5k!P!Q6]!Q!}5k!}#O6z#O#P7y#P;'S5k;'S;=`8Y<%lO5kQ6`P!P!Q6cQ6hU!lQ#Z#[6c#]#^6c#a#b6c#g#h6c#i#j6c#m#n6cQ6}VOY6zZ#O6z#O#P7d#P#Q5k#Q;'S6z;'S;=`7s<%lO6zQ7gSOY6zZ;'S6z;'S;=`7s<%lO6zQ7vP;=`<%l6zQ7|SOY5kZ;'S5k;'S;=`8Y<%lO5kQ8]P;=`<%l5kU8eW!TSOt$Ruw$Rx!P$R!P!Q8}!Q#O$R#P;'S$R;'S;=`$j<%lO$RU9Ub!TS!lQOt$Ruw$Rx#O$R#P#Z$R#Z#[8}#[#]$R#]#^8}#^#a$R#a#b8}#b#g$R#g#h8}#h#i$R#i#j8}#j#m$R#m#n8}#n;'S$R;'S;=`$j<%lO$RU:c[!TSOY:^YZ$RZt:^tu6zuw:^wx6zx#O:^#O#P7d#P#Q4h#Q;'S:^;'S;=`;X<%lO:^U;[P;=`<%l:^U;bP;=`<%l4hU;lU!TS!ZQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RUQU#oQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU>kU!TS!bQOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU?S^!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$RU@VU!RQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$RU@n_!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#UAm#U#o>}#o;'S$R;'S;=`$j<%lO$RUAr`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#`>}#`#aBt#a#o>}#o;'S$R;'S;=`$j<%lO$RUBy`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#g>}#g#hC{#h#o>}#o;'S$R;'S;=`$j<%lO$RUDQ`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#X>}#X#YES#Y#o>}#o;'S$R;'S;=`$j<%lO$RUEZ^!XQ!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^F^^#fW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^Ga^#hW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#o>}#o;'S$R;'S;=`$j<%lO$R^Hd`#gW!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#f>}#f#gIf#g#o>}#o;'S$R;'S;=`$j<%lO$RUIk`!TSOt$Ruw$Rx}$R}!O>}!O!Q$R!Q![>}![!_$R!_!`@O!`#O$R#P#T$R#T#i>}#i#jC{#j#o>}#o;'S$R;'S;=`$j<%lO$RUJtUuQ!TSOt$Ruw$Rx#O$R#P;'S$R;'S;=`$j<%lO$R~K]O#p~", + tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO#`~~", 11)], topRules: {"Program":[0,35]}, specialized: [{term: 28, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 28, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}], - tokenPrec: 2256 + tokenPrec: 2299 }) diff --git a/src/parser/tests/basics.test.ts b/src/parser/tests/basics.test.ts index 28731f9..b9e7c76 100644 --- a/src/parser/tests/basics.test.ts +++ b/src/parser/tests/basics.test.ts @@ -1017,3 +1017,23 @@ Assign `) }) }) + +describe('import', () => { + test('parses single import', () => { + expect(`import str`).toMatchTree(` + Import + keyword import + AssignableIdentifier str + `) + }) + + test('parses multiple imports', () => { + expect(`import str math list`).toMatchTree(` + Import + keyword import + AssignableIdentifier str + AssignableIdentifier math + AssignableIdentifier list + `) + }) +}) \ No newline at end of file diff --git a/src/prelude/index.ts b/src/prelude/index.ts index c153870..0d8cae0 100644 --- a/src/prelude/index.ts +++ b/src/prelude/index.ts @@ -43,6 +43,19 @@ export const globals = { return typeof v !== 'string' || this.scope.has(v) }, ref: (fn: Function) => fn, + import: function (this: VM, ...idents: string[]) { + for (const ident of idents) { + const module = this.get(ident) + + if (!module) throw new Error(`import: can't find ${ident}`) + if (module.type !== 'dict') throw new Error(`import: can't import ${module.type}`) + + for (const [name, value] of module.value.entries()) { + if (value.type === 'dict') throw new Error(`import: can't import dicts in dicts`) + this.set(name, value) + } + } + }, // env args: Bun.argv.slice(1),