From 93992029bd349185d15de02e0f633e95c62695a9 Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 9 Nov 2025 12:34:02 -0800 Subject: tostring test, fixes --- package.json | 2 +- src/lang/js-lang/builtin/builtin.ts | 14 ++++++++--- src/lang/ts-lang/util/string.ts | 5 +++- tests/type-consistency/harness.ts | 2 +- tests/type-consistency/spec/index.ts | 3 ++- tests/type-consistency/spec/tostring.ts | 41 +++++++++++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 tests/type-consistency/spec/tostring.ts diff --git a/package.json b/package.json index 96d70b6..f4d09b8 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.2.4", "repository": { "type": "git", - "url": "git+https://git.aberrantflux.xyz/kai-script.git/" + "url": "https://git.aberrantflux.xyz/kai-script.git/" }, "scripts": { "build": "tsc --declaration", diff --git a/src/lang/js-lang/builtin/builtin.ts b/src/lang/js-lang/builtin/builtin.ts index bc40794..a984ca8 100644 --- a/src/lang/js-lang/builtin/builtin.ts +++ b/src/lang/js-lang/builtin/builtin.ts @@ -2,9 +2,17 @@ type BUILTIN = (args: any[]) => any; export const V_BUILTIN_Arr: BUILTIN = (args) => args; -// FIXME actually implement this properly -export const V_BUILTIN_ToString: BUILTIN = (args) => - args.length === 1 ? JSON.stringify(args[0]) : JSON.stringify(args); +const toStringInner = (o: any): string => { + if (Array.isArray(o)) { + return `[${o.map(toStringInner).join(", ")}]`; + } + + return o.toString(); +}; + +export const V_BUILTIN_ToString: BUILTIN = (args) => { + return args.length === 1 ? toStringInner(args[0]) : toStringInner(args); +}; export const V_BUILTIN_Add: BUILTIN = (args) => { if (args.every((arg) => ["string", "number"].includes(typeof arg))) { diff --git a/src/lang/ts-lang/util/string.ts b/src/lang/ts-lang/util/string.ts index 5772f40..ae17c2c 100644 --- a/src/lang/ts-lang/util/string.ts +++ b/src/lang/ts-lang/util/string.ts @@ -5,7 +5,10 @@ export type AddStrings< ? AddStrings : Carry; -export type ToString = T extends string | number +export type ToString = T extends + | string + | number + | boolean ? `${T}` : T extends readonly any[] ? T extends readonly [infer Head, ...infer Tail] diff --git a/tests/type-consistency/harness.ts b/tests/type-consistency/harness.ts index a08e397..0102387 100644 --- a/tests/type-consistency/harness.ts +++ b/tests/type-consistency/harness.ts @@ -64,13 +64,13 @@ describe(\`${harnessName}\`, () => { }) { tests.push(`describe(\`${name}\`, () => { const PROGRAM = \`${program}\` as const; + const fn = createFn()(PROGRAM) ${cases.map( ({ input, output }) => `test(\`${JSON.stringify( input )} -> ${JSON.stringify(output)}\`, () => { const input: ${JSON.stringify(input)} = ${JSON.stringify(input)}; const expected: ${JSON.stringify(output)} = ${JSON.stringify(output)}; - const fn = createFn()(PROGRAM) const result = fn(input) expect(result).toStrictEqual(expected); diff --git a/tests/type-consistency/spec/index.ts b/tests/type-consistency/spec/index.ts index 4532493..b2da682 100644 --- a/tests/type-consistency/spec/index.ts +++ b/tests/type-consistency/spec/index.ts @@ -1,5 +1,6 @@ import array from "./array"; import functions from "./function"; import types from "./types"; +import tostring from "./tostring"; -export default [array, functions, types]; +export default [array, functions, types, tostring]; diff --git a/tests/type-consistency/spec/tostring.ts b/tests/type-consistency/spec/tostring.ts new file mode 100644 index 0000000..4fcb803 --- /dev/null +++ b/tests/type-consistency/spec/tostring.ts @@ -0,0 +1,41 @@ +import path from "path"; +import { createTestHarness } from "../harness"; + +export default createTestHarness({ + harnessName: "ToString", + generatedPath: path.join(__dirname, "..", "generated"), +}) + .createFunctionTest({ + name: "Passes through strings literally", + program: "fn(x, tostring(x))", + cases: [ + { input: "hello", output: "hello" }, + { input: "1", output: "1" }, + { input: "[1,2,3]", output: "[1,2,3]" }, + ], + }) + .createFunctionTest({ + name: "Is idempotent", + program: "fn(x, tostring(tostring(x)))", + cases: [ + { input: "hello", output: "hello" }, + { input: "1", output: "1" }, + { input: "[1,2,3]", output: "[1,2,3]" }, + ], + }) + .createFunctionTest({ + name: "Handles primitives", + program: "fn(x, tostring(x))", + cases: [ + { input: 5, output: "5" }, + { input: true, output: "true" }, + ], + }) + .createFunctionTest({ + name: "Handles arrays and nested arrays", + program: "fn(x, tostring(x))", + cases: [ + { input: [1, 2, 3], output: "[1, 2, 3]" }, + { input: [1, 2, [3, 4, 5]], output: "[1, 2, [3, 4, 5]]" }, + ], + }); -- cgit v1.2.3-70-g09d2