Compare commits

..

No commits in common. "290ac59cee905792f1b0703e54e488cfb7808351" and "146d2a22ee4918642af916d86704b438ad585cfd" have entirely different histories.

11 changed files with 133 additions and 345 deletions

View File

@ -2,7 +2,7 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "shrimp", "name": "bun-react-template",
"dependencies": { "dependencies": {
"@codemirror/view": "^6.38.3", "@codemirror/view": "^6.38.3",
"@lezer/generator": "^1.8.0", "@lezer/generator": "^1.8.0",
@ -20,39 +20,39 @@
}, },
}, },
"packages": { "packages": {
"@codemirror/autocomplete": ["@codemirror/autocomplete@6.19.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw=="], "@codemirror/autocomplete": ["@codemirror/autocomplete@6.19.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg=="],
"@codemirror/commands": ["@codemirror/commands@6.10.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w=="], "@codemirror/commands": ["@codemirror/commands@6.8.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw=="],
"@codemirror/language": ["@codemirror/language@6.11.3", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.1.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA=="], "@codemirror/language": ["@codemirror/language@6.11.3", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.1.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA=="],
"@codemirror/lint": ["@codemirror/lint@6.9.2", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ=="], "@codemirror/lint": ["@codemirror/lint@6.8.5", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA=="],
"@codemirror/search": ["@codemirror/search@6.5.11", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "crelt": "^1.0.5" } }, "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA=="], "@codemirror/search": ["@codemirror/search@6.5.11", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "crelt": "^1.0.5" } }, "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA=="],
"@codemirror/state": ["@codemirror/state@6.5.2", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA=="], "@codemirror/state": ["@codemirror/state@6.5.2", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA=="],
"@codemirror/view": ["@codemirror/view@6.38.6", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw=="], "@codemirror/view": ["@codemirror/view@6.38.3", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-x2t87+oqwB1mduiQZ6huIghjMt4uZKFEdj66IcXw7+a5iBEvv9lh7EWDRHI7crnD4BMGpnyq/RzmCGbiEZLcvQ=="],
"@lezer/common": ["@lezer/common@1.3.0", "", {}, "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ=="], "@lezer/common": ["@lezer/common@1.2.3", "", {}, "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="],
"@lezer/generator": ["@lezer/generator@1.8.0", "", { "dependencies": { "@lezer/common": "^1.1.0", "@lezer/lr": "^1.3.0" }, "bin": { "lezer-generator": "src/lezer-generator.cjs" } }, "sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg=="], "@lezer/generator": ["@lezer/generator@1.8.0", "", { "dependencies": { "@lezer/common": "^1.1.0", "@lezer/lr": "^1.3.0" }, "bin": { "lezer-generator": "src/lezer-generator.cjs" } }, "sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg=="],
"@lezer/highlight": ["@lezer/highlight@1.2.3", "", { "dependencies": { "@lezer/common": "^1.3.0" } }, "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g=="], "@lezer/highlight": ["@lezer/highlight@1.2.1", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA=="],
"@lezer/lr": ["@lezer/lr@1.4.3", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA=="], "@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="],
"@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="], "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="],
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], "@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
"@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="], "@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], "@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.0.15", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-qtAXMNGG4R0UGGI8zWrqm2B7BdXqx48vunJXBPzfDOHPA5WkRUZdTSbE7TFwO4jLhYqSE23YMWsM9NhE6ovobw=="], "bun-plugin-tailwind": ["bun-plugin-tailwind@0.0.15", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-qtAXMNGG4R0UGGI8zWrqm2B7BdXqx48vunJXBPzfDOHPA5WkRUZdTSbE7TFwO4jLhYqSE23YMWsM9NhE6ovobw=="],
"bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
"codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="],
@ -60,17 +60,17 @@
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"hono": ["hono@4.10.4", "", {}, "sha512-YG/fo7zlU3KwrBL5vDpWKisLYiM+nVstBQqfr7gCPbSYURnNEP9BDxEMz8KfsDR9JX0lJWDRNc6nXX31v7ZEyg=="], "hono": ["hono@4.9.8", "", {}, "sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg=="],
"reefvm": ["reefvm@git+https://git.nose.space/defunkt/reefvm#bffb83a5280a4d74e424c4e0f4fbd46f790227a3", { "peerDependencies": { "typescript": "^5" } }, "bffb83a5280a4d74e424c4e0f4fbd46f790227a3"], "reefvm": ["reefvm@git+https://git.nose.space/defunkt/reefvm#0f39e9401eb7a0a7c906e150127f9829458a79b6", { "peerDependencies": { "typescript": "^5" } }, "0f39e9401eb7a0a7c906e150127f9829458a79b6"],
"style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], "style-mod": ["style-mod@4.1.2", "", {}, "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="],
"tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="], "tailwindcss": ["tailwindcss@4.1.13", "", {}, "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
} }

View File

@ -8,7 +8,7 @@
"dev": "bun generate-parser && bun --hot src/server/server.tsx", "dev": "bun generate-parser && bun --hot src/server/server.tsx",
"generate-parser": "lezer-generator src/parser/shrimp.grammar --typeScript -o src/parser/shrimp.ts", "generate-parser": "lezer-generator src/parser/shrimp.grammar --typeScript -o src/parser/shrimp.ts",
"repl": "bun generate-parser && bun bin/repl", "repl": "bun generate-parser && bun bin/repl",
"update-reef": "rm -rf ~/.bun/install/cache/ && rm bun.lock && bun update reefvm" "update-reef": "rm -rf ~/.bun/install/cache/ && bun update reefvm"
}, },
"dependencies": { "dependencies": {
"@codemirror/view": "^6.38.3", "@codemirror/view": "^6.38.3",

View File

@ -7,40 +7,6 @@ export { Compiler } from '#compiler/compiler'
export { parser } from '#parser/shrimp' export { parser } from '#parser/shrimp'
export { globals } from '#prelude' export { globals } from '#prelude'
export class Shrimp {
vm: VM
private globals?: Record<string, any>
constructor(globals?: Record<string, any>) {
const emptyBytecode = { instructions: [], constants: [], labels: new Map() }
this.vm = new VM(emptyBytecode, Object.assign({}, shrimpGlobals, globals ?? {}))
this.globals = globals
}
async run(code: string | Bytecode, locals?: Record<string, any>): Promise<any> {
let bytecode
if (typeof code === 'string') {
const compiler = new Compiler(code, Object.keys(Object.assign({}, shrimpGlobals, this.globals ?? {}, locals ?? {})))
bytecode = compiler.bytecode
} else {
bytecode = code
}
if (locals) this.vm.pushScope(locals)
this.vm.appendBytecode(bytecode)
await this.vm.continue()
if (locals) this.vm.popScope()
return this.vm.stack.length ? fromValue(this.vm.stack.at(-1)!) : null
}
get(name: string): any {
const value = this.vm.scope.get(name)
return value ? fromValue(value) : null
}
}
export async function runFile(path: string, globals?: Record<string, any>): Promise<any> { export async function runFile(path: string, globals?: Record<string, any>): Promise<any> {
const code = readFileSync(path, 'utf-8') const code = readFileSync(path, 'utf-8')
return await runCode(code, globals) return await runCode(code, globals)

View File

@ -120,16 +120,12 @@ FunctionDef {
Do Params colon (consumeToTerminator | newlineOrSemicolon block) CatchExpr? FinallyExpr? end Do Params colon (consumeToTerminator | newlineOrSemicolon block) CatchExpr? FinallyExpr? end
} }
ifTest {
ConditionalOp | expression | FunctionCall
}
IfExpr { IfExpr {
if ifTest colon Block ElseIfExpr* ElseExpr? end if (ConditionalOp | expression) colon Block ElseIfExpr* ElseExpr? end
} }
ElseIfExpr { ElseIfExpr {
else if ifTest colon Block else if (ConditionalOp | expression) colon Block
} }
ElseExpr { ElseExpr {
@ -188,7 +184,7 @@ BinOp {
} }
ParenExpr { ParenExpr {
leftParen (IfExpr | ambiguousFunctionCall | BinOp | expressionWithoutIdentifier | ConditionalOp | PipeExpr | FunctionDef) rightParen leftParen (ambiguousFunctionCall | BinOp | expressionWithoutIdentifier | ConditionalOp | PipeExpr | FunctionDef) rightParen
} }
expression { expression {

View File

@ -31,36 +31,36 @@ export const
DotGet = 29, DotGet = 29,
Number = 30, Number = 30,
ParenExpr = 31, ParenExpr = 31,
IfExpr = 32, FunctionCallOrIdentifier = 32,
keyword = 70, BinOp = 33,
ConditionalOp = 34, String = 34,
String = 35, StringFragment = 35,
StringFragment = 36, Interpolation = 36,
Interpolation = 37, EscapeSeq = 37,
EscapeSeq = 38, Boolean = 38,
Boolean = 39, Regex = 39,
Regex = 40, Dict = 40,
Dict = 41, NamedArg = 41,
NamedArg = 42, NamedArgPrefix = 42,
NamedArgPrefix = 43, FunctionDef = 43,
FunctionDef = 44, Params = 44,
Params = 45, NamedParam = 45,
NamedParam = 46, Null = 46,
Null = 47, colon = 47,
colon = 48, CatchExpr = 48,
CatchExpr = 49, keyword = 69,
Block = 51, Block = 50,
FinallyExpr = 52, FinallyExpr = 51,
Underscore = 55, Underscore = 54,
Array = 56, Array = 55,
ElseIfExpr = 57, ConditionalOp = 56,
ElseExpr = 59, PositionalArg = 57,
FunctionCallOrIdentifier = 60, WhileExpr = 59,
BinOp = 61, FunctionCallWithBlock = 61,
PositionalArg = 62, TryExpr = 62,
WhileExpr = 64, Throw = 64,
FunctionCallWithBlock = 66, IfExpr = 66,
TryExpr = 67, ElseIfExpr = 68,
Throw = 69, ElseExpr = 70,
CompoundAssign = 71, CompoundAssign = 71,
Assign = 72 Assign = 72

View File

@ -4,24 +4,24 @@ import {operatorTokenizer} from "./operatorTokenizer"
import {tokenizer, specializeKeyword} from "./tokenizer" import {tokenizer, specializeKeyword} from "./tokenizer"
import {trackScope} from "./scopeTracker" import {trackScope} from "./scopeTracker"
import {highlighting} from "./highlight" import {highlighting} from "./highlight"
const spec_Identifier = {__proto__:null,if:66, null:94, catch:100, finally:106, end:108, else:116, while:130, try:136, throw:140} const spec_Identifier = {__proto__:null,null:92, catch:98, finally:104, end:106, while:120, try:126, throw:130, if:134, else:138}
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 14, version: 14,
states: "9[QYQbOOO!dOSO'#DPOOQa'#DV'#DVO#mQbO'#DfO%RQcO'#E^OOQa'#E^'#E^O&XQcO'#E^O'ZQcO'#E]O'qQcO'#E]O)^QRO'#DOO*mQcO'#EWO*wQcO'#EWO+XQbO'#C{O,SOpO'#CyOOQ`'#EX'#EXO,XQbO'#EWO,cQRO'#DuOOQ`'#EW'#EWO,wQQO'#EVOOQ`'#EV'#EVOOQ`'#Dw'#DwQYQbOOO-PQbO'#DYO-[QbO'#C|O.PQbO'#DnO.tQQO'#DqO.PQbO'#DsO.yQbO'#DRO/RQWO'#DSOOOO'#E`'#E`OOOO'#Dx'#DxO/gOSO,59kOOQa,59k,59kOOQ`'#Dy'#DyO/uQbO,5:QO/|QbO'#DWO0WQQO,59qOOQa,5:Q,5:QO0cQbO,5:QOOQa'#E]'#E]OOQ`'#Dl'#DlOOQ`'#El'#ElOOQ`'#EQ'#EQO0mQbO,59dO1gQbO,5:bO.PQbO,59jO.PQbO,59jO.PQbO,59jO.PQbO,5:VO.PQbO,5:VO.PQbO,5:VO1wQRO,59gO2OQRO,59gO2ZQRO,59gO2UQQO,59gO2lQQO,59gO2tObO,59eO3PQbO'#ERO3[QbO,59cO3vQbO,5:[O1gQbO,5:aOOQ`,5:q,5:qOOQ`-E7u-E7uOOQ`'#Dz'#DzO4ZQbO'#DZO4fQbO'#D[OOQO'#D{'#D{O4^QQO'#DZO4tQQO,59tO4yQcO'#E]O6_QRO'#E[O6fQRO'#E[OOQO'#E['#E[O6qQQO,59hO6vQRO,5:YO6}QRO,5:YO3vQbO,5:]O7YQcO,5:_O8UQcO,5:_O8`QcO,5:_OOOO,59m,59mOOOO,59n,59nOOOO-E7v-E7vOOQa1G/V1G/VOOQ`-E7w-E7wO8pQQO1G/]OOQa1G/l1G/lO8{QbO1G/lOOQ`,59r,59rOOQO'#D}'#D}O8pQQO1G/]OOQa1G/]1G/]OOQ`'#EO'#EOO8{QbO1G/lOOQ`-E8O-E8OOOQ`1G/|1G/|OOQa1G/U1G/UO:WQcO1G/UO:_QcO1G/UO:fQcO1G/UOOQa1G/q1G/qO;_QcO1G/qO;iQcO1G/qO;sQcO1G/qOOQa1G/R1G/ROOQa1G/P1G/PO<hQbO'#DjO=_QbO'#CxOOQ`,5:m,5:mOOQ`-E8P-E8POOQ`'#Da'#DaO=lQbO'#DaO>]QbO1G/vOOQ`1G/{1G/{OOQ`-E7x-E7xO>hQQO,59uOOQO,59v,59vOOQO-E7y-E7yO>pQbO1G/`O3vQbO1G/SO3vQbO1G/tO?TQbO1G/wO?`QQO7+$wOOQa7+$w7+$wO?kQbO7+%WOOQa7+%W7+%WOOQO-E7{-E7{OOQ`-E7|-E7|OOQ`'#D|'#D|O?uQQO'#D|O?zQbO'#EiOOQ`,59{,59{O@kQbO'#D_O@pQQO'#DbOOQ`7+%b7+%bO@uQbO7+%bO@zQbO7+%bOASQbO7+$zOA_QbO7+$zOA{QbO7+$nOBTQbO7+%`OOQ`7+%c7+%cOBYQbO7+%cOB_QbO7+%cOOQa<<Hc<<HcOOQa<<Hr<<HrOOQ`,5:h,5:hOOQ`-E7z-E7zOBgQQO,59yO3vQbO,59|OOQ`<<H|<<H|OBlQbO<<H|OOQ`<<Hf<<HfOBqQbO<<HfOBvQbO<<HfOCOQbO<<HfOOQ`'#EP'#EPOCZQbO<<HYOCcQbO'#DiOOQ`<<HY<<HYOCkQbO<<HYOOQ`<<Hz<<HzOOQ`<<H}<<H}OCpQbO<<H}O3vQbO1G/eOOQ`1G/h1G/hOOQ`AN>hAN>hOOQ`AN>QAN>QOCuQbOAN>QOCzQbOAN>QOOQ`-E7}-E7}OOQ`AN=tAN=tODSQbOAN=tO-[QbO,5:RO3vQbO,5:TOOQ`AN>iAN>iOOQ`7+%P7+%POOQ`G23lG23lODXQbOG23lPD^QbO'#DgOOQ`G23`G23`ODcQQO1G/mOOQ`1G/o1G/oOOQ`LD)WLD)WO3vQbO7+%XOOQ`<<Hs<<Hs", states: "9OQYQbOOO#zQcO'#C|O$zOSO'#DOOOQa'#DU'#DUO&TQbO'#DeO'iQcO'#E]OOQa'#E]'#E]O(lQcO'#E]O)nQcO'#E[O*UQRO'#C}O+eQcO'#EWO+uQcO'#EWO,PQbO'#C{O,wOpO'#CyOOQ`'#EX'#EXO,|QbO'#EWO-WQRO'#DuOOQ`'#EW'#EWO-lQQO'#EVOOQ`'#EV'#EVOOQ`'#Dw'#DwQYQbOOO-tQbO'#DXO.PQbO'#DiO.tQQO'#DlO.PQbO'#DnO.PQbO'#DpO.yQbO'#DVOOQa'#E['#E[OOQ`'#Dg'#DgOOQ`'#Ek'#EkOOQ`'#EP'#EPO/TQbO,59dO/}QbO'#DQO0VQWO'#DROOOO'#E_'#E_OOOO'#Dx'#DxO0kOSO,59jOOQa,59j,59jOOQ`'#Dy'#DyO0yQbO,5:PO1QQQO,59pOOQa,5:P,5:PO1]QbO,5:PO1gQbO,5:bO.PQbO,59iO.PQbO,59iO.PQbO,59iO.PQbO,5:QO.PQbO,5:QO.PQbO,5:QO1zQRO,59gO2RQRO,59gO2dQRO,59gO2_QQO,59gO2oQQO,59gO2wObO,59eO3SQbO'#EQO3_QbO,59cO3yQbO,5:VO1gQbO,5:aOOQ`,5:q,5:qOOQ`-E7u-E7uOOQ`'#Dz'#DzO4aQbO'#DYO4lQbO'#DZOOQO'#D{'#D{O4dQQO'#DYO4zQQO,59sO5kQRO,5:TO5rQRO,5:TO3yQbO,5:WO5}QcO,5:YO6yQcO,5:YO7ZQcO,5:YO7eQRO,5:[O7lQRO,5:[OOQ`,59q,59qOOQ`-E7}-E7}OOOO,59l,59lOOOO,59m,59mOOOO-E7v-E7vOOQa1G/U1G/UOOQ`-E7w-E7wO7wQQO1G/[OOQa1G/k1G/kO8SQbO1G/kOOQO'#D}'#D}O7wQQO1G/[OOQa1G/[1G/[OOQ`'#EO'#EOO8SQbO1G/kOOQ`1G/|1G/|OOQa1G/T1G/TO9OQcO1G/TO9YQcO1G/TO9dQcO1G/TOOQa1G/l1G/lO;YQcO1G/lO;aQcO1G/lO;hQcO1G/lOOQa1G/R1G/ROOQa1G/P1G/PO!dQbO'#C|O;oQbO'#CxOOQ`,5:l,5:lOOQ`-E8O-E8OOOQ`'#D`'#D`O;|QbO'#D`O<pQbO1G/qOOQ`1G/{1G/{OOQ`-E7x-E7xO<{QQO,59tOOQO,59u,59uOOQO-E7y-E7yO=TQbO1G/_O3yQbO1G/oO=kQbO1G/rO3yQbO1G/vO=vQQO7+$vOOQa7+$v7+$vO>RQbO7+%VOOQa7+%V7+%VOOQO-E7{-E7{OOQ`-E7|-E7|OOQ`'#D|'#D|O>]QQO'#D|O>bQbO'#EhOOQ`,59z,59zO?UQbO'#D^O?ZQQO'#DaOOQ`7+%]7+%]O?`QbO7+%]O?eQbO7+%]O?mQbO7+$yO?xQbO7+$yO@iQbO7+%ZOOQ`7+%^7+%^O@nQbO7+%^O@sQbO7+%^O@{QbO7+%bOOQa<<Hb<<HbOOQa<<Hq<<HqOOQ`,5:h,5:hOOQ`-E7z-E7zOATQQO,59xO3yQbO,59{OOQ`<<Hw<<HwOAYQbO<<HwOOQ`<<He<<HeOA_QbO<<HeOAdQbO<<HeOAlQbO<<HeOOQ`<<Hu<<HuOOQ`<<Hx<<HxOAwQbO<<HxOOQ`'#ER'#EROA|QbO<<H|OBUQbO'#DtOOQ`<<H|<<H|OB^QbO<<H|O3yQbO1G/dOOQ`1G/g1G/gOOQ`AN>cAN>cOOQ`AN>PAN>POBcQbOAN>POBhQbOAN>POOQ`AN>dAN>dOOQ`-E8P-E8POOQ`AN>hAN>hOBpQbOAN>hO.PQbO,5:^O3yQbO,5:`OOQ`7+%O7+%OOOQ`G23kG23kOBuQbOG23kPBXQbO'#DrOOQ`G24SG24SOBzQRO1G/xOCRQRO1G/xOOQ`1G/z1G/zOOQ`LD)VLD)VO3yQbO7+%dOOQ`<<IO<<IO",
stateData: "Dk~O!xOSiOS~OdWOe`OfTOg]OhfOnTOqgOwTOxTO!PTO!chO!fiO!hjO!}[O#RPO#YQO#ZRO#[cO~OtmO#RpO#TkO#UlO~OdwOfTOg]OnTOwTOxTO{sO!PTO!}[O#RPO#YQO#ZRO#[qO~O#^uO~P!rOP#QXQ#QXR#QXS#QXT#QXU#QXW#QXX#QXY#QXZ#QX[#QX]#QX^#QX#[#QX#a#QX!S#QX!V#QX!W#QX![#QX~OdwOfTOg]OhfOnTOwTOxTO{sO!PTO!XxO!}[O#RPO#YQO#ZRO#_#QX!Q#QX~P#tOV|O~P#tOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX~O#[!zX#a!zX!S!zX!V!zX!W!zX![!zX~P&`OdwOfTOg]OhfOnTOwTOxTO{sO!PTO!XxO!}[O#RPO#YQO#ZRO!Q!^X!a!^X#[!^X#a!^X#_!^X!S!^X!V!^X!W!^X![!^X~P&`OP!ROQ!ROR!SOS!SOT!OOU!POW}OX}OY}OZ}O[}O]}O^!QO~O#[!zX#a!zX!S!zX!V!zX!W!zX![!zX~OT!OOU!PO~P*XOP!ROQ!ROR!SOS!SO~P*XOdWOfTOg]OhfOnTOqgOwTOxTO!PTO!}[O#RPO#YQO#ZRO~O!|!YO~O!Q!]O!a!ZO~P*XOV|O_!^O`!^Oa!^Ob!^Oc!^O~O#[!_O#a!_O~Od!aO{!cO!Q}P~Od!gOfTOg]OnTOwTOxTO!PTO!}[O#RPO#YQO#ZRO~OdwOfTOg]OnTOwTOxTO!PTO!}[O#RPO#YQO#ZRO~O!Q!nO~Od!rO!}[O~O#R!sO#T!sO#U!sO#V!sO#W!sO#X!sO~OtmO#R!uO#TkO#UlO~O#^!xO~P!rOhfO!X!zO~P.PO{sO#[!{O#^!}O~O#[#OO#^!xO~P.POhfO{sO!XxO!Qla!ala#[la#ala#_la!Sla!Vla!Wla![la~P.POe`O!chO!fiO!hjO~P+XO#_#[O~P&`OT!OOU!PO#_#[O~OP!ROQ!ROR!SOS!SO#_#[O~O!a!ZO#_#[O~Od#]On#]O!}[O~Od#^Og]O!}[O~O!a!ZO#[ka#aka#_ka!Ska!Vka!Wka![ka~Oe`O!chO!fiO!hjO#[#cO~P+XOd!aO{!cO!Q}X~On#hOw#hO!P#hO#RPO~O!Q#jO~OhfO{sO!XxOT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX!Q#PX~P.POT!OOU!POW}OX}OY}OZ}O[}O]}O~O!Q#OX~P5sOT!OOU!PO!Q#OX~O!Q#kO~O!Q#lO~P5sOT!OOU!PO!Q#lO~O#[!ga#a!ga!S!ga!V!ga!W!ga![!ga~P)^O#[!ga#a!ga!S!ga!V!ga!W!ga![!ga~OT!OOU!PO~P7pOP!ROQ!ROR!SOS!SO~P7pO{sO#[!{O#^#oO~O#[#OO#^#qO~P.POW}OX}OY}OZ}O[}O]}OTri#[ri#ari#_ri!Qri!Sri!Vri!Wri![ri~OU!PO~P9VOU!PO~P9iOUri~P9VO^!QOR!_iS!_i#[!_i#a!_i#_!_i!S!_i!V!_i!W!_i![!_i~OP!_iQ!_i~P:mOP!ROQ!RO~P:mOP!ROQ!ROR!_iS!_i#[!_i#a!_i#_!_i!S!_i!V!_i!W!_i![!_i~OhfO{sO!XxO!a!^X#[!^X#a!^X#_!^X!S!^X!V!^X!W!^X![!^X~P.POhfO{sO!XxO~P.POe`O!chO!fiO!hjO#[#tO!S#]P!V#]P!W#]P![#]P~P+XO!S#xO!V#yO!W#zO~O{!cO!Q}a~Oe`O!chO!fiO!hjO#[$OO~P+XO!S#xO!V#yO!W$RO~O{sO#[!{O#^$UO~O#[#OO#^$VO~P.PO#[$WO~Oe`O!chO!fiO!hjO#[#tO!S#]X!V#]X!W#]X![#]X~P+XOd$YO~O!Q$ZO~O!W$[O~O!V#yO!W$[O~O!S#xO!V#yO!W$^O~Oe`O!chO!fiO!hjO#[#tO!S#]P!V#]P!W#]P~P+XO!W$eO![$dO~O!W$gO~O!W$hO~O!V#yO!W$hO~O!Q$jO~O!W$lO~O!W$mO~O!V#yO!W$mO~O!S#xO!V#yO!W$mO~O!W$qO![$dO~Oq$sO!Q$tO~O!W$qO~O!W$uO~O!W$wO~O!V#yO!W$wO~O!W$zO~O!W$}O~Oq$sO~O!Q%OO~Onx~", stateData: "Ca~O!xOSiOS~OdPOe`OfUOg]OhfOnUOvUOwUO!OUO!^gO!ahO!ciO!ejO!}[O#QQO#XRO#YSO#ZcO~OdlOfUOg]OhfOnUOvUOwUOzkO!OUO!WmO!}[O#QQO#XRO#YSO![pX#ZpX#`pX#^pX!RpX!UpX!VpX!gpX~OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX!PpX~P!dOssO#QvO#SqO#TrO~OdlOfUOg]OnUOvUOwUOzkO!OUO!}[O#QQO#XRO#YSO#ZwO~O#]zO~P%YOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX#Z#PX#`#PX!R#PX!U#PX!V#PX!g#PX~OdlOfUOg]OhfOnUOvUOwUOzkO!OUO!WmO!}[O#QQO#XRO#YSO#^#PX~P&[OV|O~P&[OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX~O#Z!zX#`!zX!R!zX!U!zX!V!zX!g!zX~P(sOP!OOQ!OOR!POS!POT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO^}O~O#Z!zX#`!zX!R!zX!U!zX!V!zX!g!zX~OP!OOQ!OOR!POS!PO~P+POT!ROU!SO~P+POdPOfUOg]OhfOnUOvUOwUO!OUO!}[O#QQO#XRO#YSO~O!|!YO~O!P!]O![!ZO~P+POV|O_!^O`!^Oa!^Ob!^Oc!^O~O#Z!_O#`!_O~Od!aOz!cO!P|P~OdlOfUOg]OnUOvUOwUO!OUO!}[O#QQO#XRO#YSO~O!P!iO~OhfO!W!oO~P.POhfOzkO!WmO!Pla![la#Zla#`la#^la!Rla!Ula!Vla!gla~P.POd!qO!}[O~O#Q!rO#S!rO#T!rO#U!rO#V!rO#W!rO~OssO#Q!tO#SqO#TrO~O#]!wO~P%YOzkO#Z!yO#]!{O~O#Z!|O#]!wO~P.POe`O!^gO!ahO!ciO!ejO~P,PO#^#XO~P(sOP!OOQ!OOR!POS!PO#^#XO~OT!ROU!SO#^#XO~O![!ZO#^#XO~Od#YOn#YO!}[O~Od#ZOg]O!}[O~O![!ZO#Zka#`ka#^ka!Rka!Uka!Vka!gka~Oe`O!^gO!ahO!ciO!ejO#Z#`O~P,POd!aOz!cO!P|X~On#eOv#eO!O#eO#QQO~O!P#gO~OT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO~O!P#hO~P5POT!ROU!SO!P#hO~O#Z!ba#`!ba!R!ba!U!ba!V!ba!g!ba~P*UO#Z!ba#`!ba!R!ba!U!ba!V!ba!g!ba~OP!OOQ!OOR!POS!PO~P6eOT!ROU!SO~P6eO!P#jO~P5POT!ROU!SO!P#jO~OzkO#Z!yO#]#lO~O#Z!|O#]#nO~P.PO^}ORqiSqi#Zqi#`qi#^qi!Rqi!Uqi!Vqi!gqi~OPqiQqi~P8^OP!OOQ!OO~P8^OP!OOQ!OORqiSqi#Zqi#`qi#^qi!Rqi!Uqi!Vqi!gqi~OW!QOX!QOY!QOZ!QO[!QO]!QOT!Yi#Z!Yi#`!Yi#^!Yi!P!Yi!R!Yi!U!Yi!V!Yi!g!Yi~OU!SO~P:XOU!SO~P:kOU!Yi~P:XOhfOzkO!WmO~P.POe`O!^gO!ahO!ciO!ejO#Z#qO!R#[P!U#[P!V#[P!g#[P~P,PO!R#uO!U#vO!V#wO~Oz!cO!P|a~Oe`O!^gO!ahO!ciO!ejO#Z#{O~P,PO!R#uO!U#vO!V#}O~OzkO#Z!yO#]$RO~O#Z!|O#]$SO~P.PO#Z$TO~Oe`O!^gO!ahO!ciO!ejO#Z#qO!R#[X!U#[X!V#[X!g#[X~P,POd$VO~O!P$WO~O!V$XO~O!U#vO!V$XO~O!R#uO!U#vO!V$ZO~Oe`O!^gO!ahO!ciO!ejO#Z#qO!R#[P!U#[P!V#[P~P,PO!V$_O~O!V$`O~O!U#vO!V$`O~O!V$eO!g$dO~O!P$gO~O!V$iO~O!V$jO~O!U#vO!V$jO~O!R#uO!U#vO!V$jO~O!V$mO~O!V$oO!g$dO~O!P$rO!e$qO~O!V$oO~O!V$tO~O!U#vO!V$tO~O!V$wO~O!V${O~O!P$|O~P5POT!ROU!SO!P$|O~Onw~",
goto: "4x#aPPPPPPPPPPPPPPPPPPPPPPPPPPP#b#w$aP%d#bP&k'bP(a(aPP(e)aP)u*g*jPP*pP*|+fPPP+|,zP-O-U-j.YP.bP.b.bP.bP.b.b.t.z/Q/W/^/h/o/y0T0Z0ePPP0l0p1^PP1v1|3fP4fPPPPPPPP4jPP4ppaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OR!W[t^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OT!jg$srWO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OzwRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pS!gg$sR#^!ZvSO[eg|!]!^!n#c#j#k#l#v$O$Z$j$s$t%OzTRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pQ!rkQ#]!YR#_!ZpYOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!U[S!ig$sQ!mhQ!pjQ#S!PR#U!O!rTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OR#h!cTmPo!sTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OQtR[ySW{!g#^#_Q!wrX!{t!w!|#npaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O[xSW{!g#^#_Q!W[R!zsR!ffX!df!b!e#gQ#|#dQ$T#mQ$`#}R$o$aQ#d!]Q#m!nQ$P#kQ$Q#lQ$k$ZQ$v$jQ$|$tR%P%OQ#{#dQ$S#mQ$]#|Q$_#}Q$i$TS$n$`$aR$x$o!QTRSW[ghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sqUOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OT$b$P$cQ$f$PR$r$cu^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OpZOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!V[Q!qjQ#W!RR#Z!S]ySW{!g#^#_qaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQeOR!`eQoPR!toQrRR!vrQ!bfR#f!bQ!efQ#g!bT#i!e#gS#v#c$OR$X#vQ!|tQ#n!wT#r!|#nQ#PvQ#p!yT#s#P#pQ$c$PR$p$cY{SW!g#^#_R#Q{S![_!XR#a![TdOeSbOeQ#R|`#b!]!n#k#l$Z$j$t%OQ#e!^U#u#c#v$OR#}#jp_Oe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!X[R#`!ZQ!kgR${$srXO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OQvR[xSW{!g#^#_S!hg$sQ!lhQ!ojQ!yrQ!zsW#Ov!y#P#pQ#S}Q#T!OQ#V!PQ#W!QQ#X!RR#Y!SpVOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O!OwRSWghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sR!T[TnPoQ#w#cR$a$O]zSW{!g#^#_", goto: "3}#`PPPPPPPPPPPPPPPPPPPPPPPPPPP#a#v$[P%[#v&b'QP(O(OPP(S(}P)b*R*UPP*[P*h+QPPP+h,e-^P-eP-e-eP-eP-eP-wP-{-e-e.R.X._.e.k.u.|/W/b/k/rPPP/x/|0jPP1S2mP3lPPPPPPPP3pPP3vpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|R!W[u^O[e|!Z!]!^!i#`#g#h#j#s#{$W$g$r$|rPO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR#Z!ZrTO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||UPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qQ!qqQ#Y!YR#[!ZpYOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!U[Q!kiQ#P!OR#S!P!pUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|R#e!cTsQu!qUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|YnPTp#Z#[QySQ!vxX!yy!v!z#kpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q!W[R!okR!ffX!df!b!e#dQ#y#aQ$P#iQ$]#zR$l$^Q#a!]Q#i!iQ#|#hQ$Q#jQ$h$WQ$s$gQ$z$rR$}$|Q#x#aQ$O#iQ$Y#yQ$[#zQ$a$PS$k$]$^R$u$l!OUPST[gijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qqVOe|!]!^!i#`#g#h#j#s#{$W$g$r$|pZOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!V[Q!hgQ!liQ!njQ#T!SQ#V!RR$y$qZnPTp#Z#[qaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|T$b$Q$cQ$f$QR$p$cQeOR!`eQuQR!suQxSR!uxQ!bfR#c!bQ!efQ#d!bT#f!e#dS#s#`#{R$U#sQ!zyQ#k!vT#o!z#kQ!}{Q#m!xT#p!}#mWpPT#Z#[R!ppS![_!XR#^![Q$c$QR$n$cTdOeSbOeQ#O|`#_!]!i#h#j$W$g$r$|Q#b!^U#r#`#s#{R#z#gp_Oe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!X[R#]!ZrXO[e|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q{SQ!ggQ!jiQ!mjQ!okQ!xxW!|{!x!}#mQ#P}Q#Q!OQ#R!PQ#T!QQ#U!RQ#W!SR$x$qpWOe|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR!T[TtQuQ#t#`R$^#{ZoPTp#Z#[",
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Comment Program PipeExpr FunctionCall DotGet Number ParenExpr IfExpr keyword ConditionalOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ElseIfExpr keyword ElseExpr FunctionCallOrIdentifier BinOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword CompoundAssign Assign", nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Comment Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword ElseIfExpr keyword ElseExpr CompoundAssign Assign",
maxTerm: 109, maxTerm: 108,
context: trackScope, context: trackScope,
nodeProps: [ nodeProps: [
["closedBy", 48,"end"] ["closedBy", 47,"end"]
], ],
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0,25], skippedNodes: [0,25],
repeatNodeCount: 11, repeatNodeCount: 11,
tokenData: "C|~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'tuw#{wx'yxy(Oyz(iz{#{{|)S|}#{}!O+v!O!P#{!P!Q.]!Q![)q![!]6x!]!^%T!^!}#{!}#O7c#O#P9X#P#Q9^#Q#R#{#R#S9w#S#T#{#T#Y,w#Y#Z:b#Z#b,w#b#c?`#c#f,w#f#g@]#g#h,w#h#iAY#i#o,w#o#p#{#p#qC^#q;'S#{;'S;=`$d<%l~#{~O#{~~CwS$QUtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUtS!xYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UtS#[QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%sWtSOp#{pq&]qt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^&dZiYtSOY&]YZ#{Zt&]tu'Vuw&]wx'Vx#O&]#O#P'V#P;'S&];'S;=`'n<%lO&]Y'[SiYOY'VZ;'S'V;'S;=`'h<%lO'VY'kP;=`<%l'V^'qP;=`<%l&]~'yO#T~~(OO#R~U(VUtS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(pUtS#_QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U)XWtSOt#{uw#{x!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U)xYtSnQOt#{uw#{x!O#{!O!P*h!P!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U*mWtSOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+^WtSnQOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+{^tSOt#{uw#{x}#{}!O,w!O!Q#{!Q![)q![!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U,|[tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U-yU{QtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U.bWtSOt#{uw#{x!P#{!P!Q.z!Q#O#{#P;'S#{;'S;=`$d<%lO#{U/P^tSOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q#{!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{U0S^tSxQOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q3s!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{Q1TXxQOY1OZ!P1O!P!Q1p!Q!}1O!}#O2_#O#P3^#P;'S1O;'S;=`3m<%lO1OQ1sP!P!Q1vQ1{UxQ#Z#[1v#]#^1v#a#b1v#g#h1v#i#j1v#m#n1vQ2bVOY2_Z#O2_#O#P2w#P#Q1O#Q;'S2_;'S;=`3W<%lO2_Q2zSOY2_Z;'S2_;'S;=`3W<%lO2_Q3ZP;=`<%l2_Q3aSOY1OZ;'S1O;'S;=`3m<%lO1OQ3pP;=`<%l1OU3xWtSOt#{uw#{x!P#{!P!Q4b!Q#O#{#P;'S#{;'S;=`$d<%lO#{U4ibtSxQOt#{uw#{x#O#{#P#Z#{#Z#[4b#[#]#{#]#^4b#^#a#{#a#b4b#b#g#{#g#h4b#h#i#{#i#j4b#j#m#{#m#n4b#n;'S#{;'S;=`$d<%lO#{U5v[tSOY5qYZ#{Zt5qtu2_uw5qwx2_x#O5q#O#P2w#P#Q/{#Q;'S5q;'S;=`6l<%lO5qU6oP;=`<%l5qU6uP;=`<%l/{U7PUtS!QQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7jW#ZQtSOt#{uw#{x!_#{!_!`8S!`#O#{#P;'S#{;'S;=`$d<%lO#{U8XVtSOt#{uw#{x#O#{#P#Q8n#Q;'S#{;'S;=`$d<%lO#{U8uU#YQtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~9^O#U~U9eU#^QtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:OUtS!XQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:g]tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#U;`#U#o,w#o;'S#{;'S;=`$d<%lO#{U;e^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#`,w#`#a<a#a#o,w#o;'S#{;'S;=`$d<%lO#{U<f^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#g,w#g#h=b#h#o,w#o;'S#{;'S;=`$d<%lO#{U=g^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#X,w#X#Y>c#Y#o,w#o;'S#{;'S;=`$d<%lO#{U>j[wQtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^?g[#VWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^@d[#XWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^Aa^#WWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#f,w#f#gB]#g#o,w#o;'S#{;'S;=`$d<%lO#{UBb^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#i,w#i#j=b#j#o,w#o;'S#{;'S;=`$d<%lO#{UCeU!aQtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C|O#a~", tokenData: "C|~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'tuw#{wx'yxy(Oyz(iz{#{{|)S|}#{}!O+v!O!P#{!P!Q.]!Q![)q![!]6x!]!^%T!^!}#{!}#O7c#O#P9X#P#Q9^#Q#R#{#R#S9w#S#T#{#T#Y,w#Y#Z:b#Z#b,w#b#c?`#c#f,w#f#g@]#g#h,w#h#iAY#i#o,w#o#p#{#p#qC^#q;'S#{;'S;=`$d<%l~#{~O#{~~CwS$QUsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUsS!xYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UsS#ZQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%sWsSOp#{pq&]qt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^&dZiYsSOY&]YZ#{Zt&]tu'Vuw&]wx'Vx#O&]#O#P'V#P;'S&];'S;=`'n<%lO&]Y'[SiYOY'VZ;'S'V;'S;=`'h<%lO'VY'kP;=`<%l'V^'qP;=`<%l&]~'yO#S~~(OO#Q~U(VUsS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(pUsS#^QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U)XWsSOt#{uw#{x!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U)xYsSnQOt#{uw#{x!O#{!O!P*h!P!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U*mWsSOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+^WsSnQOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+{^sSOt#{uw#{x}#{}!O,w!O!Q#{!Q![)q![!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U,|[sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U-yUzQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U.bWsSOt#{uw#{x!P#{!P!Q.z!Q#O#{#P;'S#{;'S;=`$d<%lO#{U/P^sSOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q#{!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{U0S^sSwQOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q3s!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{Q1TXwQOY1OZ!P1O!P!Q1p!Q!}1O!}#O2_#O#P3^#P;'S1O;'S;=`3m<%lO1OQ1sP!P!Q1vQ1{UwQ#Z#[1v#]#^1v#a#b1v#g#h1v#i#j1v#m#n1vQ2bVOY2_Z#O2_#O#P2w#P#Q1O#Q;'S2_;'S;=`3W<%lO2_Q2zSOY2_Z;'S2_;'S;=`3W<%lO2_Q3ZP;=`<%l2_Q3aSOY1OZ;'S1O;'S;=`3m<%lO1OQ3pP;=`<%l1OU3xWsSOt#{uw#{x!P#{!P!Q4b!Q#O#{#P;'S#{;'S;=`$d<%lO#{U4ibsSwQOt#{uw#{x#O#{#P#Z#{#Z#[4b#[#]#{#]#^4b#^#a#{#a#b4b#b#g#{#g#h4b#h#i#{#i#j4b#j#m#{#m#n4b#n;'S#{;'S;=`$d<%lO#{U5v[sSOY5qYZ#{Zt5qtu2_uw5qwx2_x#O5q#O#P2w#P#Q/{#Q;'S5q;'S;=`6l<%lO5qU6oP;=`<%l5qU6uP;=`<%l/{U7PUsS!PQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7jW#YQsSOt#{uw#{x!_#{!_!`8S!`#O#{#P;'S#{;'S;=`$d<%lO#{U8XVsSOt#{uw#{x#O#{#P#Q8n#Q;'S#{;'S;=`$d<%lO#{U8uU#XQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~9^O#T~U9eU#]QsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:OUsS!WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:g]sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#U;`#U#o,w#o;'S#{;'S;=`$d<%lO#{U;e^sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#`,w#`#a<a#a#o,w#o;'S#{;'S;=`$d<%lO#{U<f^sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#g,w#g#h=b#h#o,w#o;'S#{;'S;=`$d<%lO#{U=g^sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#X,w#X#Y>c#Y#o,w#o;'S#{;'S;=`$d<%lO#{U>j[vQsSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^?g[#UWsSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^@d[#WWsSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^Aa^#VWsSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#f,w#f#gB]#g#o,w#o;'S#{;'S;=`$d<%lO#{UBb^sSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#i,w#i#j=b#j#o,w#o;'S#{;'S;=`$d<%lO#{UCeU![QsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C|O#`~",
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)], tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)],
topRules: {"Program":[0,26]}, topRules: {"Program":[0,26]},
specialized: [{term: 20, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 20, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}], specialized: [{term: 20, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 20, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
tokenPrec: 1634 tokenPrec: 1578
}) })

View File

@ -156,103 +156,6 @@ describe('if/else if/else', () => {
keyword end keyword end
`) `)
}) })
test('parses function calls in if tests', () => {
expect(`if var? 'abc': true end`).toMatchTree(`
IfExpr
keyword if
FunctionCall
Identifier var?
PositionalArg
String
StringFragment abc
colon :
Block
Boolean true
keyword end
`)
})
test('parses function calls in if tests', () => {
expect(`if (var? 'abc'): true end`).toMatchTree(`
IfExpr
keyword if
ParenExpr
FunctionCall
Identifier var?
PositionalArg
String
StringFragment abc
colon :
Block
Boolean true
keyword end
`)
})
test('parses function calls in else-if tests', () => {
expect(`if false: true else if var? 'abc': true end`).toMatchTree(`
IfExpr
keyword if
Boolean false
colon :
Block
Boolean true
ElseIfExpr
keyword else
keyword if
FunctionCall
Identifier var?
PositionalArg
String
StringFragment abc
colon :
Block
Boolean true
keyword end
`)
})
test('parses function calls in else-if tests', () => {
expect(`if false: true else if (var? 'abc'): true end`).toMatchTree(`
IfExpr
keyword if
Boolean false
colon :
Block
Boolean true
ElseIfExpr
keyword else
keyword if
ParenExpr
FunctionCall
Identifier var?
PositionalArg
String
StringFragment abc
colon :
Block
Boolean true
keyword end
`)
})
test('allows if/else in parens', () => {
expect(`eh? = (if true: true end)`).toMatchTree(`
Assign
AssignableIdentifier eh?
Eq =
ParenExpr
IfExpr
keyword if
Boolean true
colon :
Block
Boolean true
keyword end
`)
})
}) })
describe('while', () => { describe('while', () => {

View File

@ -1,7 +1,7 @@
// The prelude creates all the builtin Shrimp functions. // The prelude creates all the builtin Shrimp functions.
import { import {
type Value, type VM, toValue, type Value, toValue,
extractParamInfo, isWrapped, getOriginalFunction, extractParamInfo, isWrapped, getOriginalFunction,
} from 'reefvm' } from 'reefvm'
@ -34,11 +34,13 @@ export const globals = {
const val = toValue(v) const val = toValue(v)
return `#<${val.type}: ${formatValue(val)}>` return `#<${val.type}: ${formatValue(val)}>`
}, },
var: function (this: VM, v: any) { length: (v: any) => {
return typeof v === 'string' ? this.scope.get(v) : v const value = toValue(v)
}, switch (value.type) {
'var?': function (this: VM, v: string) { case 'string': case 'array': return value.value.length
return typeof v !== 'string' || this.scope.has(v) case 'dict': return value.value.size
default: throw new Error(`length: expected string, array, or dict, got ${value.type}`)
}
}, },
// type predicates // type predicates
@ -63,14 +65,6 @@ export const globals = {
identity: (v: any) => v, identity: (v: any) => v,
// collections // collections
length: (v: any) => {
const value = toValue(v)
switch (value.type) {
case 'string': case 'array': return value.value.length
case 'dict': return value.value.size
default: throw new Error(`length: expected string, array, or dict, got ${value.type}`)
}
},
at: (collection: any, index: number | string) => { at: (collection: any, index: number | string) => {
const value = toValue(collection) const value = toValue(collection)
if (value.type === 'string' || value.type === 'array') { if (value.type === 'string' || value.type === 'array') {

View File

@ -1,79 +0,0 @@
import { expect, describe, test } from 'bun:test'
import { globals } from '#prelude'
describe('var and var?', () => {
test('var? checks if a variable exists', async () => {
await expect(`var? 'nada'`).toEvaluateTo(false, globals)
await expect(`var? 'info'`).toEvaluateTo(false, globals)
await expect(`abc = abc; var? 'abc'`).toEvaluateTo(true, globals)
await expect(`var? 'var?'`).toEvaluateTo(true, globals)
await expect(`var? 'dict'`).toEvaluateTo(true, globals)
await expect(`var? dict`).toEvaluateTo(true, globals)
})
test('var returns a value or null', async () => {
await expect(`var 'nada'`).toEvaluateTo(null, globals)
await expect(`var nada`).toEvaluateTo(null, globals)
await expect(`var 'info'`).toEvaluateTo(null, globals)
await expect(`abc = my-string; var 'abc'`).toEvaluateTo('my-string', globals)
await expect(`abc = my-string; var abc`).toEvaluateTo(null, globals)
})
})
describe('type predicates', () => {
test('string? checks for string type', async () => {
await expect(`string? 'hello'`).toEvaluateTo(true, globals)
await expect(`string? 42`).toEvaluateTo(false, globals)
})
test('number? checks for number type', async () => {
await expect(`number? 42`).toEvaluateTo(true, globals)
await expect(`number? 'hello'`).toEvaluateTo(false, globals)
})
test('boolean? checks for boolean type', async () => {
await expect(`boolean? true`).toEvaluateTo(true, globals)
await expect(`boolean? 42`).toEvaluateTo(false, globals)
})
test('array? checks for array type', async () => {
await expect(`array? [1 2 3]`).toEvaluateTo(true, globals)
await expect(`array? 42`).toEvaluateTo(false, globals)
})
test('dict? checks for dict type', async () => {
await expect(`dict? [a=1]`).toEvaluateTo(true, globals)
await expect(`dict? []`).toEvaluateTo(false, globals)
})
test('null? checks for null type', async () => {
await expect(`null? null`).toEvaluateTo(true, globals)
await expect(`null? 42`).toEvaluateTo(false, globals)
})
test('some? checks for non-null', async () => {
await expect(`some? 42`).toEvaluateTo(true, globals)
await expect(`some? null`).toEvaluateTo(false, globals)
})
})
describe('introspection', () => {
test('type returns proper types', async () => {
await expect(`type 'hello'`).toEvaluateTo('string', globals)
await expect(`type 42`).toEvaluateTo('number', globals)
await expect(`type true`).toEvaluateTo('boolean', globals)
await expect(`type false`).toEvaluateTo('boolean', globals)
await expect(`type null`).toEvaluateTo('null', globals)
await expect(`type [1 2 3]`).toEvaluateTo('array', globals)
await expect(`type [a=1 b=2]`).toEvaluateTo('dict', globals)
})
test('inspect formats values', async () => {
await expect(`inspect 'hello'`).toEvaluateTo("\u001b[32m'hello\u001b[32m'\u001b[0m", globals)
})
test('describe describes values', async () => {
await expect(`describe 'hello'`).toEvaluateTo("#<string: \u001b[32m'hello\u001b[32m'\u001b[0m>", globals)
})
})

View File

@ -98,6 +98,43 @@ describe('string operations', () => {
}) })
}) })
describe('type predicates', () => {
test('string? checks for string type', async () => {
await expect(`string? 'hello'`).toEvaluateTo(true, globals)
await expect(`string? 42`).toEvaluateTo(false, globals)
})
test('number? checks for number type', async () => {
await expect(`number? 42`).toEvaluateTo(true, globals)
await expect(`number? 'hello'`).toEvaluateTo(false, globals)
})
test('boolean? checks for boolean type', async () => {
await expect(`boolean? true`).toEvaluateTo(true, globals)
await expect(`boolean? 42`).toEvaluateTo(false, globals)
})
test('array? checks for array type', async () => {
await expect(`array? [1 2 3]`).toEvaluateTo(true, globals)
await expect(`array? 42`).toEvaluateTo(false, globals)
})
test('dict? checks for dict type', async () => {
await expect(`dict? [a=1]`).toEvaluateTo(true, globals)
await expect(`dict? []`).toEvaluateTo(false, globals)
})
test('null? checks for null type', async () => {
await expect(`null? null`).toEvaluateTo(true, globals)
await expect(`null? 42`).toEvaluateTo(false, globals)
})
test('some? checks for non-null', async () => {
await expect(`some? 42`).toEvaluateTo(true, globals)
await expect(`some? null`).toEvaluateTo(false, globals)
})
})
describe('boolean logic', () => { describe('boolean logic', () => {
test('not negates value', async () => { test('not negates value', async () => {
await expect(`not true`).toEvaluateTo(false, globals) await expect(`not true`).toEvaluateTo(false, globals)
@ -124,7 +161,17 @@ describe('utilities', () => {
}) })
}) })
describe('collections', () => { describe('introspection', () => {
test('type returns proper types', async () => {
await expect(`type 'hello'`).toEvaluateTo('string', globals)
await expect(`type 42`).toEvaluateTo('number', globals)
await expect(`type true`).toEvaluateTo('boolean', globals)
await expect(`type false`).toEvaluateTo('boolean', globals)
await expect(`type null`).toEvaluateTo('null', globals)
await expect(`type [1 2 3]`).toEvaluateTo('array', globals)
await expect(`type [a=1 b=2]`).toEvaluateTo('dict', globals)
})
test('length', async () => { test('length', async () => {
await expect(`length 'hello'`).toEvaluateTo(5, globals) await expect(`length 'hello'`).toEvaluateTo(5, globals)
await expect(`length [1 2 3]`).toEvaluateTo(3, globals) await expect(`length [1 2 3]`).toEvaluateTo(3, globals)
@ -137,6 +184,20 @@ describe('collections', () => {
await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals) await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals)
}) })
test('inspect formats values', async () => {
// Just test that inspect returns something for now
// (we'd need more complex assertion to check the actual format)
await expect(`type (inspect 'hello')`).toEvaluateTo('string', globals)
})
test('describe describes values', async () => {
// Just test that inspect returns something for now
// (we'd need more complex assertion to check the actual format)
await expect(`describe 'hello'`).toEvaluateTo("#<string: \u001b[32m'hello\u001b[32m'\u001b[0m>", globals)
})
})
describe('collections', () => {
test('literal array creates array from arguments', async () => { test('literal array creates array from arguments', async () => {
await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3], globals) await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3], globals)
await expect(`['a' 'b']`).toEvaluateTo(['a', 'b'], globals) await expect(`['a' 'b']`).toEvaluateTo(['a', 'b'], globals)

View File

@ -1,53 +0,0 @@
import { describe } from 'bun:test'
import { expect, test } from 'bun:test'
import { Shrimp } from '..'
describe('Shrimp', () => {
test('allows running Shrimp code', async () => {
const shrimp = new Shrimp()
expect(await shrimp.run(`1 + 5`)).toEqual(6)
expect(await shrimp.run(`type 5`)).toEqual('number')
})
test('maintains state across runs', async () => {
const shrimp = new Shrimp()
await shrimp.run(`abc = true`)
expect(shrimp.get('abc')).toEqual(true)
await shrimp.run(`name = Bob`)
expect(shrimp.get('abc')).toEqual(true)
expect(shrimp.get('name')).toEqual('Bob')
await shrimp.run(`abc = false`)
expect(shrimp.get('abc')).toEqual(false)
})
test('allows setting your own globals', async () => {
const shrimp = new Shrimp({ hiya: () => 'hey there' })
await shrimp.run('abc = hiya')
expect(shrimp.get('abc')).toEqual('hey there')
expect(await shrimp.run('type abc')).toEqual('string')
// still there
expect(await shrimp.run('hiya')).toEqual('hey there')
})
test('allows setting your own locals', async () => {
const shrimp = new Shrimp({ 'my-global': () => 'hey there' })
await shrimp.run('abc = my-global')
expect(shrimp.get('abc')).toEqual('hey there')
await shrimp.run('abc = my-global', { 'my-global': 'now a local' })
expect(shrimp.get('abc')).toEqual('now a local')
await shrimp.run('abc = nothing')
expect(shrimp.get('abc')).toEqual('nothing')
await shrimp.run('abc = nothing', { nothing: 'something' })
expect(shrimp.get('abc')).toEqual('something')
await shrimp.run('abc = nothing')
expect(shrimp.get('abc')).toEqual('nothing')
})
})