@forthix/forthic 0.7.2 → 0.8.0
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/dist/cjs/forthic/decorators/schemaUtils.d.ts +70 -0
- package/dist/cjs/forthic/decorators/schemaUtils.js +77 -0
- package/dist/cjs/forthic/decorators/schemaUtils.js.map +1 -0
- package/dist/cjs/forthic/decorators/stackEffect.d.ts +63 -0
- package/dist/cjs/forthic/decorators/stackEffect.js +179 -0
- package/dist/cjs/forthic/decorators/stackEffect.js.map +1 -0
- package/dist/cjs/forthic/interpreter.d.ts +21 -0
- package/dist/cjs/forthic/interpreter.js +76 -1
- package/dist/cjs/forthic/interpreter.js.map +1 -1
- package/dist/cjs/forthic/module.d.ts +2 -0
- package/dist/cjs/forthic/module.js +4 -0
- package/dist/cjs/forthic/module.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/forthic/decorators/schemaUtils.d.ts +70 -0
- package/dist/esm/forthic/decorators/schemaUtils.js +72 -0
- package/dist/esm/forthic/decorators/schemaUtils.js.map +1 -0
- package/dist/esm/forthic/decorators/stackEffect.d.ts +63 -0
- package/dist/esm/forthic/decorators/stackEffect.js +174 -0
- package/dist/esm/forthic/decorators/stackEffect.js.map +1 -0
- package/dist/esm/forthic/interpreter.d.ts +21 -0
- package/dist/esm/forthic/interpreter.js +74 -1
- package/dist/esm/forthic/interpreter.js.map +1 -1
- package/dist/esm/forthic/module.d.ts +2 -0
- package/dist/esm/forthic/module.js +4 -0
- package/dist/esm/forthic/module.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/grpc/server.test.d.ts +0 -1
- package/dist/cjs/grpc/server.test.js +0 -156
- package/dist/cjs/grpc/server.test.js.map +0 -1
- package/dist/cjs/grpc/temporal_utils.d.ts +0 -36
- package/dist/cjs/grpc/temporal_utils.js +0 -80
- package/dist/cjs/grpc/temporal_utils.js.map +0 -1
- package/dist/cjs/websocket/action_cable_client.d.ts +0 -106
- package/dist/cjs/websocket/action_cable_client.js +0 -269
- package/dist/cjs/websocket/action_cable_client.js.map +0 -1
- package/dist/cjs/websocket/client.d.ts +0 -103
- package/dist/cjs/websocket/client.js +0 -266
- package/dist/cjs/websocket/client.js.map +0 -1
- package/dist/cjs/websocket/remote_module.d.ts +0 -68
- package/dist/cjs/websocket/remote_module.js +0 -107
- package/dist/cjs/websocket/remote_module.js.map +0 -1
- package/dist/cjs/websocket/remote_word.d.ts +0 -53
- package/dist/cjs/websocket/remote_word.js +0 -93
- package/dist/cjs/websocket/remote_word.js.map +0 -1
- package/dist/cjs/websocket/runtime_manager.d.ts +0 -69
- package/dist/cjs/websocket/runtime_manager.js +0 -112
- package/dist/cjs/websocket/runtime_manager.js.map +0 -1
- package/dist/esm/grpc/server.test.d.ts +0 -1
- package/dist/esm/grpc/server.test.js +0 -121
- package/dist/esm/grpc/server.test.js.map +0 -1
- package/dist/esm/grpc/temporal_utils.d.ts +0 -36
- package/dist/esm/grpc/temporal_utils.js +0 -72
- package/dist/esm/grpc/temporal_utils.js.map +0 -1
- package/dist/esm/websocket/action_cable_client.d.ts +0 -106
- package/dist/esm/websocket/action_cable_client.js +0 -265
- package/dist/esm/websocket/action_cable_client.js.map +0 -1
- package/dist/esm/websocket/client.d.ts +0 -103
- package/dist/esm/websocket/client.js +0 -262
- package/dist/esm/websocket/client.js.map +0 -1
- package/dist/esm/websocket/remote_module.d.ts +0 -68
- package/dist/esm/websocket/remote_module.js +0 -103
- package/dist/esm/websocket/remote_module.js.map +0 -1
- package/dist/esm/websocket/remote_word.d.ts +0 -53
- package/dist/esm/websocket/remote_word.js +0 -89
- package/dist/esm/websocket/remote_word.js.map +0 -1
- package/dist/esm/websocket/runtime_manager.d.ts +0 -69
- package/dist/esm/websocket/runtime_manager.js +0 -108
- package/dist/esm/websocket/runtime_manager.js.map +0 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Registry metadata types for stack objects and class instances.
|
|
4
|
+
*/
|
|
5
|
+
type StackObjectMetadata = {
|
|
6
|
+
objectType: "stackObject";
|
|
7
|
+
stackObjectType: string;
|
|
8
|
+
className?: undefined;
|
|
9
|
+
OriginalClass?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
objectType: "class";
|
|
12
|
+
OriginalClass: new (...args: any[]) => any;
|
|
13
|
+
className: string;
|
|
14
|
+
stackObjectType?: undefined;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Track metadata for schema comparison in tests and documentation.
|
|
18
|
+
* Only required for schemas that can't be compared out of the box,
|
|
19
|
+
* like custom schemas or instanceof schemas.
|
|
20
|
+
*/
|
|
21
|
+
export declare const stackObjectRegistry: z.core.$ZodRegistry<StackObjectMetadata, z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a Zod schema for stack objects that have a stackObjectType property.
|
|
24
|
+
* This is a helper to reduce boilerplate when creating custom stack object schemas.
|
|
25
|
+
* It also ensures the schema is registered in stackObjectRegistry, which enables
|
|
26
|
+
* proper type string generation in stack effects.
|
|
27
|
+
*
|
|
28
|
+
* Use this instead of z.custom() directly for stack objects.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* interface StackEmail {
|
|
33
|
+
* stackObjectType: "email";
|
|
34
|
+
* to: string;
|
|
35
|
+
* subject: string;
|
|
36
|
+
* body: string;
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* const stackEmailSchema = createStackObjectSchema<StackEmail>("email");
|
|
40
|
+
*
|
|
41
|
+
* // Use in stack effect:
|
|
42
|
+
* @ForthicWord(se`(email:${stackEmailSchema} -- sent:${z.boolean()})`, "Send email")
|
|
43
|
+
* async SEND(email: StackEmail): Promise<boolean> { ... }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function createStackObjectSchema<T extends {
|
|
47
|
+
stackObjectType: string;
|
|
48
|
+
}>(stackObjectType: string, errorMessage?: string): z.ZodCustom<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a Zod instanceof schema with automatic metadata registration.
|
|
51
|
+
* This ensures the schema is registered in stackObjectRegistry, which enables
|
|
52
|
+
* proper type string generation in stack effects.
|
|
53
|
+
*
|
|
54
|
+
* Use this instead of z.instanceof() directly.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { Temporal } from "temporal-polyfill";
|
|
59
|
+
*
|
|
60
|
+
* const plainDateSchema = createInstanceOfSchema(Temporal.PlainDate);
|
|
61
|
+
*
|
|
62
|
+
* // Use in stack effect:
|
|
63
|
+
* @ForthicWord(se`(date:${plainDateSchema} -- formatted:${z.string()})`, "Format date")
|
|
64
|
+
* async FORMAT(date: Temporal.PlainDate): Promise<string> { ... }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function createInstanceOfSchema<T extends abstract new (...args: any[]) => any>(ClassToSchematize: T,
|
|
68
|
+
/** If not passed, falls back to class.name */
|
|
69
|
+
className?: string): z.ZodType<InstanceType<T>>;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stackObjectRegistry = void 0;
|
|
4
|
+
exports.createStackObjectSchema = createStackObjectSchema;
|
|
5
|
+
exports.createInstanceOfSchema = createInstanceOfSchema;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
/**
|
|
8
|
+
* Track metadata for schema comparison in tests and documentation.
|
|
9
|
+
* Only required for schemas that can't be compared out of the box,
|
|
10
|
+
* like custom schemas or instanceof schemas.
|
|
11
|
+
*/
|
|
12
|
+
exports.stackObjectRegistry = zod_1.z.registry();
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Zod schema for stack objects that have a stackObjectType property.
|
|
15
|
+
* This is a helper to reduce boilerplate when creating custom stack object schemas.
|
|
16
|
+
* It also ensures the schema is registered in stackObjectRegistry, which enables
|
|
17
|
+
* proper type string generation in stack effects.
|
|
18
|
+
*
|
|
19
|
+
* Use this instead of z.custom() directly for stack objects.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* interface StackEmail {
|
|
24
|
+
* stackObjectType: "email";
|
|
25
|
+
* to: string;
|
|
26
|
+
* subject: string;
|
|
27
|
+
* body: string;
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* const stackEmailSchema = createStackObjectSchema<StackEmail>("email");
|
|
31
|
+
*
|
|
32
|
+
* // Use in stack effect:
|
|
33
|
+
* @ForthicWord(se`(email:${stackEmailSchema} -- sent:${z.boolean()})`, "Send email")
|
|
34
|
+
* async SEND(email: StackEmail): Promise<boolean> { ... }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function createStackObjectSchema(stackObjectType, errorMessage) {
|
|
38
|
+
const schema = zod_1.z.custom((maybeStackObject) => maybeStackObject?.stackObjectType === stackObjectType, errorMessage ?? `expected ${stackObjectType} stackObjectType`);
|
|
39
|
+
// Register schema with metadata
|
|
40
|
+
exports.stackObjectRegistry.add(schema, {
|
|
41
|
+
objectType: "stackObject",
|
|
42
|
+
stackObjectType,
|
|
43
|
+
});
|
|
44
|
+
return schema;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a Zod instanceof schema with automatic metadata registration.
|
|
48
|
+
* This ensures the schema is registered in stackObjectRegistry, which enables
|
|
49
|
+
* proper type string generation in stack effects.
|
|
50
|
+
*
|
|
51
|
+
* Use this instead of z.instanceof() directly.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Temporal } from "temporal-polyfill";
|
|
56
|
+
*
|
|
57
|
+
* const plainDateSchema = createInstanceOfSchema(Temporal.PlainDate);
|
|
58
|
+
*
|
|
59
|
+
* // Use in stack effect:
|
|
60
|
+
* @ForthicWord(se`(date:${plainDateSchema} -- formatted:${z.string()})`, "Format date")
|
|
61
|
+
* async FORMAT(date: Temporal.PlainDate): Promise<string> { ... }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
function createInstanceOfSchema(ClassToSchematize,
|
|
65
|
+
/** If not passed, falls back to class.name */
|
|
66
|
+
className) {
|
|
67
|
+
const schema = zod_1.z.instanceof(ClassToSchematize);
|
|
68
|
+
// Register schema with metadata
|
|
69
|
+
const resolvedClassName = className ?? ClassToSchematize.name;
|
|
70
|
+
exports.stackObjectRegistry.add(schema, {
|
|
71
|
+
objectType: "class",
|
|
72
|
+
OriginalClass: ClassToSchematize,
|
|
73
|
+
className: resolvedClassName,
|
|
74
|
+
});
|
|
75
|
+
return schema;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=schemaUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaUtils.js","sourceRoot":"","sources":["../../../../src/forthic/decorators/schemaUtils.ts"],"names":[],"mappings":";;;AAkDA,0DAgBC;AAoBD,wDAgBC;AAtGD,6BAAwB;AAmBxB;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,OAAC,CAAC,QAAQ,EAAuB,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,uBAAuB,CACrC,eAAuB,EACvB,YAAqB;IAErB,MAAM,MAAM,GAAG,OAAC,CAAC,MAAM,CACrB,CAAC,gBAAgB,EAAE,EAAE,CAAE,gBAAkC,EAAE,eAAe,KAAK,eAAe,EAC9F,YAAY,IAAI,YAAY,eAAe,kBAAkB,CAC9D,CAAC;IAEF,gCAAgC;IAChC,2BAAmB,CAAC,GAAG,CAAC,MAAM,EAAE;QAC9B,UAAU,EAAE,aAAa;QACzB,eAAe;KAChB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,sBAAsB,CACpC,iBAAoB;AACpB,8CAA8C;AAC9C,SAAkB;IAElB,MAAM,MAAM,GAAG,OAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAE/C,gCAAgC;IAChC,MAAM,iBAAiB,GAAG,SAAS,IAAI,iBAAiB,CAAC,IAAI,CAAC;IAC9D,2BAAmB,CAAC,GAAG,CAAC,MAAM,EAAE;QAC9B,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,iBAAiB;QAChC,SAAS,EAAE,iBAAiB;KAC7B,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { util as zodUtil } from "zod/v4/core";
|
|
3
|
+
/**
|
|
4
|
+
* Map the set of Zod types to the strings we use in Forthic stack effects.
|
|
5
|
+
* Uses Zod's internal def.type for comprehensive type detection.
|
|
6
|
+
*/
|
|
7
|
+
export declare const mapZodToStackEffectType: (zodType: z.ZodTypeAny) => string;
|
|
8
|
+
type InferTupleTypes<T extends zodUtil.TupleItems> = {
|
|
9
|
+
[K in keyof T]: T[K] extends z.ZodTypeAny ? z.infer<T[K]> : never;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Represents a type-safe stack effect with Zod schemas for validation.
|
|
13
|
+
*
|
|
14
|
+
* @template Args - Tuple of Zod schemas for input parameters
|
|
15
|
+
* @template Return - Zod schema for the return type
|
|
16
|
+
*/
|
|
17
|
+
export type TaggedStackEffect<Args extends zodUtil.TupleItems, Return extends z.core.$ZodFunctionOut = z.core.$ZodFunctionOut> = {
|
|
18
|
+
/** The human-readable stack effect string (e.g., "( a:number b:string -- result:string )") */
|
|
19
|
+
stackEffect: string;
|
|
20
|
+
/** Zod schemas for runtime validation */
|
|
21
|
+
schema: {
|
|
22
|
+
inputSchemas: z.ZodTypeAny[];
|
|
23
|
+
outputSchema: z.ZodTypeAny;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Phantom property to convey the expected function signature, constructed from the input + output types.
|
|
27
|
+
* DO NOT USE AT RUNTIME - it's only used for type inference.
|
|
28
|
+
*/
|
|
29
|
+
_implType: (...args: InferTupleTypes<Args>) => Promise<z.infer<Return>>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Tagged template literal for stack effects. Use with the @ForthicWord decorator to
|
|
33
|
+
* create a type-safe stack effect.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Type-safe stack effect with Zod validation
|
|
38
|
+
* @ForthicWord(se`(a:${z.number()} b:${z.string()} -- result:${z.string()})`, "Concatenate number and string")
|
|
39
|
+
* async CONCAT(a: number, b: string): Promise<string> {
|
|
40
|
+
* return `${a}${b}`;
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // No parameters, returns string
|
|
47
|
+
* @ForthicWord(se`( -- message:${z.string()})`, "Get greeting")
|
|
48
|
+
* async GREET(): Promise<string> {
|
|
49
|
+
* return "Hello!";
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // Takes string, no return (void)
|
|
56
|
+
* @ForthicWord(se`(input:${z.string()} -- ${z.void()})`, "Log to console")
|
|
57
|
+
* async LOG(input: string): Promise<void> {
|
|
58
|
+
* console.log(input);
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare const se: <Args extends zodUtil.TupleItems, Return extends z.core.$ZodFunctionOut>(template: TemplateStringsArray, ...values: [...Args, Return]) => TaggedStackEffect<Args, Return>;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.se = exports.mapZodToStackEffectType = void 0;
|
|
4
|
+
const schemaUtils_js_1 = require("./schemaUtils.js");
|
|
5
|
+
/**
|
|
6
|
+
* Map the set of Zod types to the strings we use in Forthic stack effects.
|
|
7
|
+
* Uses Zod's internal def.type for comprehensive type detection.
|
|
8
|
+
*/
|
|
9
|
+
const mapZodToStackEffectType = (zodType) => {
|
|
10
|
+
const def = zodType.def;
|
|
11
|
+
switch (def.type) {
|
|
12
|
+
case "string":
|
|
13
|
+
return "string";
|
|
14
|
+
case "int":
|
|
15
|
+
case "bigint":
|
|
16
|
+
return "number";
|
|
17
|
+
case "number":
|
|
18
|
+
return "number";
|
|
19
|
+
case "boolean":
|
|
20
|
+
return "boolean";
|
|
21
|
+
case "null":
|
|
22
|
+
return "null";
|
|
23
|
+
case "undefined":
|
|
24
|
+
case "void":
|
|
25
|
+
return "";
|
|
26
|
+
case "date":
|
|
27
|
+
return "date";
|
|
28
|
+
case "symbol":
|
|
29
|
+
return "symbol";
|
|
30
|
+
case "object": {
|
|
31
|
+
const objectDef = def;
|
|
32
|
+
const objectShape = objectDef.shape;
|
|
33
|
+
// Get all property types
|
|
34
|
+
const properties = Object.entries(objectShape).map(([key, fieldSchema]) => {
|
|
35
|
+
const fieldType = (0, exports.mapZodToStackEffectType)(fieldSchema);
|
|
36
|
+
return `${key}: ${fieldType}`;
|
|
37
|
+
});
|
|
38
|
+
// Return formatted object type
|
|
39
|
+
return properties.length > 0 ? `{ ${properties.join(", ")} }` : "{}";
|
|
40
|
+
}
|
|
41
|
+
case "literal": {
|
|
42
|
+
const literalDef = def;
|
|
43
|
+
const value = literalDef.values[0];
|
|
44
|
+
// Quote string literals
|
|
45
|
+
return typeof value === "string" ? `"${value}"` : String(value);
|
|
46
|
+
}
|
|
47
|
+
case "enum": {
|
|
48
|
+
const enumDef = def;
|
|
49
|
+
const enumEntries = Object.values(enumDef.entries);
|
|
50
|
+
// Return union of quoted values - zod enums are always strings
|
|
51
|
+
return enumEntries.map((entry) => `"${entry}"`).join("|");
|
|
52
|
+
}
|
|
53
|
+
case "optional": {
|
|
54
|
+
const optionalDef = def;
|
|
55
|
+
const innerType = (0, exports.mapZodToStackEffectType)(optionalDef.innerType);
|
|
56
|
+
// Optional is a union with undefined
|
|
57
|
+
return innerType ? `${innerType}|undefined` : "undefined";
|
|
58
|
+
}
|
|
59
|
+
case "nullable": {
|
|
60
|
+
const nullableDef = def;
|
|
61
|
+
const innerType = (0, exports.mapZodToStackEffectType)(nullableDef.innerType);
|
|
62
|
+
// Nullable is a union with null
|
|
63
|
+
return innerType ? `${innerType}|null` : "null";
|
|
64
|
+
}
|
|
65
|
+
case "union": {
|
|
66
|
+
const unionDef = def;
|
|
67
|
+
const unionOptions = unionDef.options;
|
|
68
|
+
// Recursively get types for all union options
|
|
69
|
+
const optionTypes = unionOptions.map((option) => (0, exports.mapZodToStackEffectType)(option));
|
|
70
|
+
// Dedupe
|
|
71
|
+
return [...new Set(optionTypes)].join("|");
|
|
72
|
+
}
|
|
73
|
+
case "tuple": {
|
|
74
|
+
const tupleDef = def;
|
|
75
|
+
const tupleItems = tupleDef.items;
|
|
76
|
+
const elementTypes = tupleItems.map((item) => (0, exports.mapZodToStackEffectType)(item));
|
|
77
|
+
return `[${elementTypes.join(", ")}]`;
|
|
78
|
+
}
|
|
79
|
+
case "array": {
|
|
80
|
+
const arrayDef = def;
|
|
81
|
+
const elementType = (0, exports.mapZodToStackEffectType)(arrayDef.element);
|
|
82
|
+
// If the element is a union (contains "|") but not already an array type (doesn't end with "]"),
|
|
83
|
+
// wrap it in parentheses
|
|
84
|
+
const needsParens = elementType.includes("|") && !elementType.endsWith("]");
|
|
85
|
+
const wrappedType = needsParens ? `(${elementType})` : elementType;
|
|
86
|
+
return `${wrappedType}[]`;
|
|
87
|
+
}
|
|
88
|
+
case "custom": {
|
|
89
|
+
const metadata = schemaUtils_js_1.stackObjectRegistry.get(zodType);
|
|
90
|
+
if (!metadata) {
|
|
91
|
+
throw new Error(`Custom schema found without stack object registry entry. Consider using createStackObjectSchema or createInstanceOfSchema or manually registering the schema.`);
|
|
92
|
+
}
|
|
93
|
+
return metadata.stackObjectType ?? metadata.className ?? "object";
|
|
94
|
+
}
|
|
95
|
+
case "any":
|
|
96
|
+
return "any";
|
|
97
|
+
case "record":
|
|
98
|
+
case "function":
|
|
99
|
+
case "promise":
|
|
100
|
+
case "map":
|
|
101
|
+
case "set":
|
|
102
|
+
case "lazy":
|
|
103
|
+
case "never":
|
|
104
|
+
case "unknown":
|
|
105
|
+
case "file":
|
|
106
|
+
case "nonoptional":
|
|
107
|
+
case "success":
|
|
108
|
+
case "transform":
|
|
109
|
+
case "prefault":
|
|
110
|
+
case "nan":
|
|
111
|
+
case "pipe":
|
|
112
|
+
case "template_literal":
|
|
113
|
+
case "intersection":
|
|
114
|
+
case "catch":
|
|
115
|
+
case "default":
|
|
116
|
+
case "readonly":
|
|
117
|
+
// Unsupported types - throw error to ensure we handle everything
|
|
118
|
+
throw new Error(`Stack effect string generation not supported for type: "${def.type}" - you may either update mapZodToStackEffectType or use a simpler type (e.g. use createStackObjectSchema)`);
|
|
119
|
+
default:
|
|
120
|
+
throw new Error(`Unknown type: "${def.type}". You either need to update mapZodToStackEffectType, or zod is doing something unexpected.`);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
exports.mapZodToStackEffectType = mapZodToStackEffectType;
|
|
124
|
+
/**
|
|
125
|
+
* Tagged template literal for stack effects. Use with the @ForthicWord decorator to
|
|
126
|
+
* create a type-safe stack effect.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* // Type-safe stack effect with Zod validation
|
|
131
|
+
* @ForthicWord(se`(a:${z.number()} b:${z.string()} -- result:${z.string()})`, "Concatenate number and string")
|
|
132
|
+
* async CONCAT(a: number, b: string): Promise<string> {
|
|
133
|
+
* return `${a}${b}`;
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* // No parameters, returns string
|
|
140
|
+
* @ForthicWord(se`( -- message:${z.string()})`, "Get greeting")
|
|
141
|
+
* async GREET(): Promise<string> {
|
|
142
|
+
* return "Hello!";
|
|
143
|
+
* }
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* // Takes string, no return (void)
|
|
149
|
+
* @ForthicWord(se`(input:${z.string()} -- ${z.void()})`, "Log to console")
|
|
150
|
+
* async LOG(input: string): Promise<void> {
|
|
151
|
+
* console.log(input);
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
const se = (template, ...values) => {
|
|
156
|
+
const stackEffectTypes = values.map((value) => (0, exports.mapZodToStackEffectType)(value));
|
|
157
|
+
// Outputs the template string as if it weren't tagged, e.g. "( a:string b:number -- c:number )"
|
|
158
|
+
const parts = [];
|
|
159
|
+
for (let i = 0; i < template.length; i++) {
|
|
160
|
+
parts.push(template[i]);
|
|
161
|
+
if (i < stackEffectTypes.length) {
|
|
162
|
+
parts.push(stackEffectTypes[i]);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const outStr = parts.join("");
|
|
166
|
+
const taggedStackEffect = {
|
|
167
|
+
stackEffect: outStr,
|
|
168
|
+
schema: {
|
|
169
|
+
inputSchemas: values.slice(0, -1),
|
|
170
|
+
outputSchema: values[values.length - 1],
|
|
171
|
+
},
|
|
172
|
+
_implType: async () => {
|
|
173
|
+
throw new Error("This function should not be called at runtime, it's only used for type inference");
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
return taggedStackEffect;
|
|
177
|
+
};
|
|
178
|
+
exports.se = se;
|
|
179
|
+
//# sourceMappingURL=stackEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stackEffect.js","sourceRoot":"","sources":["../../../../src/forthic/decorators/stackEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Token, Tokenizer, CodeLocation } from "./tokenizer.js";
|
|
2
2
|
import { Module, Word } from "./module.js";
|
|
3
3
|
import { LiteralHandler } from "./literals.js";
|
|
4
|
+
import { StackValue } from "../websocket/serializer.js";
|
|
4
5
|
type Timestamp = {
|
|
5
6
|
label: string;
|
|
6
7
|
time_ms: number;
|
|
@@ -55,6 +56,7 @@ export declare class Interpreter {
|
|
|
55
56
|
private is_compiling;
|
|
56
57
|
private is_memo_definition;
|
|
57
58
|
private cur_definition;
|
|
59
|
+
private definition_start_input_pos;
|
|
58
60
|
private string_location?;
|
|
59
61
|
private word_counts;
|
|
60
62
|
private is_profiling;
|
|
@@ -164,6 +166,25 @@ export declare class Interpreter {
|
|
|
164
166
|
endStream(): void;
|
|
165
167
|
}
|
|
166
168
|
export declare function dup_interpreter(interp: Interpreter): Interpreter;
|
|
169
|
+
/**
|
|
170
|
+
* Serializable interpreter state for preserving variables, words, and stack
|
|
171
|
+
* across interpreter instantiations (e.g., multiturn chat sessions).
|
|
172
|
+
*/
|
|
173
|
+
export interface InterpreterState {
|
|
174
|
+
stack: StackValue[];
|
|
175
|
+
variables: Record<string, StackValue>;
|
|
176
|
+
word_definitions: string[];
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Export the app module state and stack from an interpreter as a serializable object.
|
|
180
|
+
* The caller is responsible for persisting the returned state.
|
|
181
|
+
*/
|
|
182
|
+
export declare function export_state(interp: Interpreter): InterpreterState;
|
|
183
|
+
/**
|
|
184
|
+
* Import previously exported state into an interpreter.
|
|
185
|
+
* Replays word definitions, restores variable values, and sets the stack.
|
|
186
|
+
*/
|
|
187
|
+
export declare function import_state(interp: Interpreter, state: InterpreterState): Promise<void>;
|
|
167
188
|
/**
|
|
168
189
|
* Interpreter - Full-featured interpreter with standard library
|
|
169
190
|
*
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StandardInterpreter = exports.Interpreter = exports.Stack = void 0;
|
|
4
4
|
exports.dup_interpreter = dup_interpreter;
|
|
5
|
+
exports.export_state = export_state;
|
|
6
|
+
exports.import_state = import_state;
|
|
5
7
|
const tokenizer_js_1 = require("./tokenizer.js");
|
|
6
8
|
const module_js_1 = require("./module.js");
|
|
7
9
|
const tokenizer_js_2 = require("./tokenizer.js");
|
|
@@ -15,6 +17,7 @@ const math_module_js_1 = require("./modules/standard/math_module.js");
|
|
|
15
17
|
const boolean_module_js_1 = require("./modules/standard/boolean_module.js");
|
|
16
18
|
const json_module_js_1 = require("./modules/standard/json_module.js");
|
|
17
19
|
const datetime_module_js_1 = require("./modules/standard/datetime_module.js");
|
|
20
|
+
const serializer_js_1 = require("../websocket/serializer.js");
|
|
18
21
|
/**
|
|
19
22
|
* StartModuleWord - Handles module creation and switching
|
|
20
23
|
*
|
|
@@ -183,6 +186,7 @@ class Interpreter {
|
|
|
183
186
|
is_compiling;
|
|
184
187
|
is_memo_definition;
|
|
185
188
|
cur_definition;
|
|
189
|
+
definition_start_input_pos;
|
|
186
190
|
string_location;
|
|
187
191
|
word_counts;
|
|
188
192
|
is_profiling;
|
|
@@ -206,6 +210,7 @@ class Interpreter {
|
|
|
206
210
|
this.is_compiling = false;
|
|
207
211
|
this.is_memo_definition = false;
|
|
208
212
|
this.cur_definition = null;
|
|
213
|
+
this.definition_start_input_pos = 0;
|
|
209
214
|
// Debug support
|
|
210
215
|
this.string_location = undefined;
|
|
211
216
|
// Profiling support
|
|
@@ -724,6 +729,8 @@ class Interpreter {
|
|
|
724
729
|
this.cur_definition = new module_js_1.DefinitionWord(token.string);
|
|
725
730
|
this.is_compiling = true;
|
|
726
731
|
this.is_memo_definition = false;
|
|
732
|
+
// Record the position right after the definition name for source capture
|
|
733
|
+
this.definition_start_input_pos = this.get_tokenizer().input_pos;
|
|
727
734
|
}
|
|
728
735
|
handle_start_memo_token(token) {
|
|
729
736
|
if (this.is_compiling) {
|
|
@@ -732,13 +739,22 @@ class Interpreter {
|
|
|
732
739
|
this.cur_definition = new module_js_1.DefinitionWord(token.string);
|
|
733
740
|
this.is_compiling = true;
|
|
734
741
|
this.is_memo_definition = true;
|
|
742
|
+
// Record the position right after the memo name for source capture
|
|
743
|
+
this.definition_start_input_pos = this.get_tokenizer().input_pos;
|
|
735
744
|
}
|
|
736
745
|
handle_end_definition_token(token) {
|
|
737
746
|
if (!this.is_compiling || !this.cur_definition) {
|
|
738
747
|
throw new errors_js_1.ExtraSemicolonError(this.get_top_input_string(), token.location);
|
|
739
748
|
}
|
|
749
|
+
// Construct the source text for serialization
|
|
750
|
+
const tokenizer = this.get_tokenizer();
|
|
751
|
+
const body = tokenizer.input_string.substring(this.definition_start_input_pos, tokenizer.input_pos);
|
|
752
|
+
const prefix = this.is_memo_definition ? "@:" : ":";
|
|
753
|
+
const source = `${prefix} ${this.cur_definition.name} ${body}`;
|
|
754
|
+
this.cur_definition.source = source;
|
|
740
755
|
if (this.is_memo_definition) {
|
|
741
|
-
this.cur_module().add_memo_words(this.cur_definition);
|
|
756
|
+
const memoWord = this.cur_module().add_memo_words(this.cur_definition);
|
|
757
|
+
memoWord.source = source;
|
|
742
758
|
}
|
|
743
759
|
else {
|
|
744
760
|
this.cur_module().add_word(this.cur_definition);
|
|
@@ -860,6 +876,65 @@ function dup_interpreter(interp) {
|
|
|
860
876
|
}
|
|
861
877
|
return result_interp;
|
|
862
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Export the app module state and stack from an interpreter as a serializable object.
|
|
881
|
+
* The caller is responsible for persisting the returned state.
|
|
882
|
+
*/
|
|
883
|
+
function export_state(interp) {
|
|
884
|
+
const internal = interp;
|
|
885
|
+
// Serialize the stack
|
|
886
|
+
const stack = (0, serializer_js_1.serializeStack)(internal.stack.get_items());
|
|
887
|
+
// Serialize variables
|
|
888
|
+
const variables = {};
|
|
889
|
+
const appModule = internal.app_module;
|
|
890
|
+
for (const [name, variable] of Object.entries(appModule.variables)) {
|
|
891
|
+
variables[name] = (0, serializer_js_1.serializeValue)(variable.get_value());
|
|
892
|
+
}
|
|
893
|
+
// Collect source text from user-defined words
|
|
894
|
+
const word_definitions = [];
|
|
895
|
+
const seen = new Set();
|
|
896
|
+
for (const word of appModule.words) {
|
|
897
|
+
if (word instanceof module_js_1.DefinitionWord && word.source) {
|
|
898
|
+
// For DefinitionWords, use the source directly (avoids duplicates from memo bang variants)
|
|
899
|
+
if (!seen.has(word.name)) {
|
|
900
|
+
seen.add(word.name);
|
|
901
|
+
word_definitions.push(word.source);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
else if (word instanceof module_js_1.ModuleMemoWord && word.source) {
|
|
905
|
+
if (!seen.has(word.name)) {
|
|
906
|
+
seen.add(word.name);
|
|
907
|
+
word_definitions.push(word.source);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return { stack, variables, word_definitions };
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Import previously exported state into an interpreter.
|
|
915
|
+
* Replays word definitions, restores variable values, and sets the stack.
|
|
916
|
+
*/
|
|
917
|
+
async function import_state(interp, state) {
|
|
918
|
+
const internal = interp;
|
|
919
|
+
// 1. Replay word definitions (this may also create variables via VARIABLES word)
|
|
920
|
+
for (const def of state.word_definitions) {
|
|
921
|
+
await interp.run(def);
|
|
922
|
+
}
|
|
923
|
+
// 2. Restore variable values (overwriting any defaults from definitions)
|
|
924
|
+
const appModule = internal.app_module;
|
|
925
|
+
for (const [name, serializedValue] of Object.entries(state.variables)) {
|
|
926
|
+
const value = (0, serializer_js_1.deserializeValue)(serializedValue);
|
|
927
|
+
if (appModule.variables[name]) {
|
|
928
|
+
appModule.variables[name].set_value(value);
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
appModule.add_variable(name, value);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
// 3. Restore the stack
|
|
935
|
+
const stackItems = (0, serializer_js_1.deserializeStack)(state.stack);
|
|
936
|
+
internal.stack.set_raw_items(stackItems);
|
|
937
|
+
}
|
|
863
938
|
/**
|
|
864
939
|
* Interpreter - Full-featured interpreter with standard library
|
|
865
940
|
*
|