From 0346977a66b809bf104e8485931dab45aec5c8dc Mon Sep 17 00:00:00 2001 From: Patrick Bowen Date: Sat, 23 Sep 2023 03:20:26 +0100 Subject: [PATCH] Support destructuring in `for`; improve ix further --- corpus/cobs-encoding.ix | 36 +++++++++++++++++++++++ package.json | 2 +- src/index.ts | 16 ++++++----- src/parse.ts | 9 ++++-- src/repl.ts | 63 +++++++++++++++++++++++------------------ src/test.ts | 5 ++++ 6 files changed, 92 insertions(+), 39 deletions(-) create mode 100644 corpus/cobs-encoding.ix diff --git a/corpus/cobs-encoding.ix b/corpus/cobs-encoding.ix new file mode 100644 index 0000000..c87d02a --- /dev/null +++ b/corpus/cobs-encoding.ix @@ -0,0 +1,36 @@ +(function COBS unencoded + (let chunk (take-until [0] unencoded) + length (len chunk) + encoded (append (first 254 chunk) (or %1 [])) + more? (< length (len unencoded))) + (if (or (and (= length 254) more?) (> length 254)) + (recur (skip 254 unencoded) encoded) + (if more? + (recur (skip (inc length) unencoded) encoded) + (append 0 (flat-map @(.. vec (inc (len %))) encoded))))) + +; A more compact but probably wobbly version: +; (function COBS unencoded +; (let chunk (take-until [0] unencoded) +; [c-len u-len] (proj len chunk unencoded) +; encoded (append (first 254 chunk) (or %1 []))) +; (if (<= 253 c-len 255 u-len) +; (recur (skip 254 unencoded) encoded) +; (if (< c-len u-len) +; (recur (skip (inc c-len) unencoded) encoded) +; (append 0 (flat-map @(.. vec (inc (len %))) encoded))))) + +(for [a b] [ + [[0x00] [0x01 0x01 0x00]] + [[0x00 0x00] [0x01 0x01 0x01 0x00]] + [[0x00 0x11 0x00] [0x01 0x02 0x11 0x01 0x00]] + [[0x11 0x22 0x00 0x33] [0x03 0x11 0x22 0x02 0x33 0x00]] + [[0x11 0x22 0x33 0x44] [0x05 0x11 0x22 0x33 0x44 0x00]] + [[0x11 0x00 0x00 0x00] [0x02 0x11 0x01 0x01 0x01 0x00]] + [(range 1 255) (.. vec 0xFF (range 1 255) 0x00)] + [(range 255) (.. vec 0x01 0xFF (range 1 255) 0x00)] + [(range 1 256) (.. vec 0xFF (range 1 255) 0x02 0xFF 0x00)] + [(.. vec (range 2 256) 0x00) (.. vec 0xFF (range 2 256) 0x01 0x01 0x00)] + [(.. vec (range 3 256) 0x00 0x01) (.. vec 0xFE (range 3 256) 0x02 0x01 0x00)] + ] + (assert (= (COBS a) b))) diff --git a/package.json b/package.json index c22b1f6..c01a3c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "insitux", - "version": "23.9.22", + "version": "23.9.23", "description": "Extensible scripting language written in portable TypeScript.", "main": "dist/invoker.js", "types": "dist/invoker.d.ts", diff --git a/src/index.ts b/src/index.ts index 97c5ccc..4885a45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -export const insituxVersion = 230922; +export const insituxVersion = 230923; import { asBoo } from "./checks"; import { arityCheck, keyOpErr, numOpErr, typeCheck, typeErr } from "./checks"; import { isLetter, isDigit, isSpace, isPunc } from "./checks"; @@ -993,8 +993,8 @@ function exeOp(op: string, args: Val[], ctx: Ctx, errCtx: ErrCtx): Val { case "lower?": { const s = str(args[0]); const code = charCode(s); - if (op === 'upper?') { - return _boo(code >= 65 && code < 91); + if (op === "upper?") { + return _boo(code >= 65 && code < 91); } return _boo(code >= 97 && code < 123); } @@ -1366,12 +1366,12 @@ function exeFunc( ctx: Ctx, func: Func, args: Val[], - sharedLets: boolean, + closureOrFor: boolean, ): Val | Val[] { --ctx.callBudget; const prevLets = lets; let myLets: { [key: string]: Val } = {}; - if (!sharedLets) { + if (!closureOrFor) { lets = myLets; } const stack: Val[] = []; @@ -1534,7 +1534,9 @@ function exeFunc( stack.push(_nul()); } i = lim; - forState = "ret"; + if (closureOrFor) { + forState = "ret"; + } break; case "clo": { //Ensure any in-scope declarations are captured here @@ -1656,7 +1658,7 @@ function exeFunc( } } lets = prevLets; - if (sharedLets) { + if (closureOrFor) { return stack; } return stack[len(stack) - 1]; diff --git a/src/parse.ts b/src/parse.ts index 5cfcd0c..89bf1a1 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -363,8 +363,8 @@ function parseForm( //Calculate jmp-to-ends for (let i = 0, max = len(ins); i < max; ++i) { const next = ins[i]; - if (next.typ === 'jmp' && !next.value) { - next.value = (max - i) - 1; + if (next.typ === "jmp" && !next.value) { + next.value = max - i - 1; } } return ins; @@ -547,7 +547,10 @@ function parseForm( const defAndVals: DefAndValIns[] = []; let bodyAt = 0; for (let n = 0, lim = len(nodes); n < lim; ++n) { - if (n === lim - 1 || !isToken(nodes[n])) { + if ( + n === lim - 1 || + (!isToken(nodes[n]) && symAt(nodes[n]) !== "vec") + ) { bodyAt = n; break; } diff --git a/src/repl.ts b/src/repl.ts index 71b3cac..e4c1af4 100644 --- a/src/repl.ts +++ b/src/repl.ts @@ -494,51 +494,54 @@ async function processCliArguments(args: string[]) { } const params = programArgs.map(_str); - const executeInline = args.includes("-e"); - const openReplAfter = !executeInline && args.includes("-r"); - const parts = openReplAfter ? args.filter(a => a !== "-r") : args; + let executeInline = ""; + const executeInlineIdx = args.indexOf("-e"); + if (executeInlineIdx !== -1) { + if (executeInlineIdx + 1 === args.length) { + console.error( + "Argument after -e (the code to be executed inline) was not provided.", + ); + } else { + executeInline = args[executeInlineIdx + 1]; + args.splice(executeInlineIdx, 2); + } + } - const matchParts = (b: RegExp[]) => - parts.length === b.length && parts.every((part, i) => b[i]?.test(part)); + let openReplAfter = false; + const openReplAfterIdx = args.indexOf("-r"); + if (openReplAfterIdx !== -1) { + openReplAfter = true; + args.splice(openReplAfterIdx, 1); + } + + const matchArgs = (b: RegExp[]) => + args.length === b.length && args.every((arg, i) => b[i]?.test(arg)); const invoke = (code: string, id = code) => printErrorOutput(invoker(ctx, code, id, params).output); - const [arg0, arg1, arg2] = parts; + if (matchArgs([/^\.$/])) { + args[0] = "entry.ix"; + } + + const [arg0, arg1, arg2] = args; if (["help", "-h"].includes(arg0)) { console.log(helpText); exit(); - } else if (executeInline) { - const switchIndex = args.findIndex(x => x === "-e"); - if (switchIndex + 1 === args.length) { - console.error("Code after -e was not provided."); - } else { - const code = args[switchIndex + 1]; - invoke(code); - } - } else if (matchParts([/^\.$/])) { - //Execute entry.ix in working directory - const path = "entry.ix"; - if (!existsSync(path)) { - console.log("entry.ix does not exist in this directory."); - } else { - const code = readFileSync(path).toString(); - invoke(code, path); - } - } else if (matchParts([/^i$/, githubRegex])) { + } else if (matchArgs([/^i$/, githubRegex])) { //Install dependency via Github await dependencyResolve({ kind: "Github install", repo: arg1 }); - } else if (matchParts([/^i$/, /.+/, /https*:/])) { + } else if (matchArgs([/^i$/, /.+/, /https*:/])) { //Install dependency via HTTP exitIfBadAlias(arg1); await dependencyResolve({ kind: "http install", url: arg2, alias: arg1 }); } else if (arg0 === "i") { await depsFileAction("install"); exit(); - } else if (matchParts([/^r$/, githubRegex])) { + } else if (matchArgs([/^r$/, githubRegex])) { //Remove Github dependency await dependencyResolve({ kind: "Github remove", repo: arg1 }); - } else if (matchParts([/^r$/, /.+/])) { + } else if (matchArgs([/^r$/, /.+/])) { //Remove aliased dependency exitIfBadAlias(arg1); await dependencyResolve({ kind: "alias remove", alias: arg1 }); @@ -547,7 +550,7 @@ async function processCliArguments(args: string[]) { exit(); } else { //Execute files - for (const path of parts) { + for (const path of args) { if (!existsSync(path)) { console.log(`${path} not found - ignored.`); } else { @@ -555,6 +558,10 @@ async function processCliArguments(args: string[]) { invoke(code, path); } } + //Execute optional inline + if (executeInline) { + invoke(executeInline); + } } if (openReplAfter) { diff --git a/src/test.ts b/src/test.ts index bddb4c7..1e9ce66 100644 --- a/src/test.ts +++ b/src/test.ts @@ -157,6 +157,11 @@ const tests: { code: `(for x [0 1 2 3] (when (= x 2) (break)) x)`, out: `[0 1]`, }, + { + name: "For destructure", + code: `(for [x y] [[1 2]] [x y])`, + out: `[[1 2]]` + }, { name: "Filter by integer", code: `(filter 2 [[1] [:a :b :c] "hello" "hi"])`,