diff --git a/tsds/tsds.mts b/tsds/tsds.mts index a377561..8a3e690 100644 --- a/tsds/tsds.mts +++ b/tsds/tsds.mts @@ -1,3 +1,8 @@ +/** + * TypeScript wrapper for a deductive system implemented in WebAssembly. + * Provides classes and functions for working with logical terms, rules, and inference. + */ + import create_ds from "./ds.mjs"; import type * as dst from "./ds.d.mts"; @@ -5,6 +10,19 @@ const ds: dst.EmbindModule = await create_ds(); let _buffer_size: number = 1024; +/** + * Gets the current buffer size, or sets a new buffer size and returns the previous value. + * The buffer size is used for internal operations like conversions and transformations. + * + * @param size - The new buffer size to set. If 0 (default), the current size is returned without modification. + * @returns The previous buffer size value. + * + * @example + * ```typescript + * const currentSize = buffer_size(); // Get current size + * const oldSize = buffer_size(2048); // Set new size, returns old size + * ``` + */ export function buffer_size(size: number = 0): number { const old_size = _buffer_size; if (size !== 0) { @@ -13,11 +31,19 @@ export function buffer_size(size: number = 0): number { return old_size; } +/** + * Common interface for all deductive system types. + * @internal + */ interface Common { clone(): Common; data_size(): number; } +/** + * Static methods interface for deductive system types. + * @internal + */ interface StaticCommon { from_binary(buffer: dst.Buffer): T; to_binary(value: T): dst.Buffer; @@ -25,13 +51,30 @@ interface StaticCommon { to_string(value: T, size: number): string; } +/** + * Valid initialization arguments for deductive system types. + * @internal + */ type InitialArgument = _common_t | T | string | dst.Buffer | null; +/** + * Base class for all deductive system wrapper types. + * Handles initialization, serialization, and common operations. + * @internal + */ class _common_t { type: StaticCommon; value: T; capacity: number; + /** + * Creates a new instance. + * + * @param type - The static type interface for this common type. + * @param value - Initial value (can be another instance, base value, string, or buffer). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails or invalid arguments are provided. + */ constructor(type: StaticCommon, value: InitialArgument, size: number = 0) { this.type = type; if (value instanceof _common_t) { @@ -60,6 +103,12 @@ class _common_t { } } + /** + * Convert the value to a string representation. + * + * @returns The string representation. + * @throws {Error} If conversion fails. + */ toString(): string { const result = this.type.to_string(this.value, buffer_size()); if (result === "") { @@ -68,69 +117,204 @@ class _common_t { return result; } + /** + * Get the binary representation of the value. + * + * @returns The binary data as a Buffer. + */ data(): dst.Buffer { return this.type.to_binary(this.value); } + /** + * Get the size of the data in bytes. + * + * @returns The data size. + */ size(): number { return this.value.data_size(); } + /** + * Create a deep copy of this instance. + * + * @returns A new instance with cloned value. + */ copy(): this { const this_constructor = this.constructor as new (value: T, size: number) => this; return new this_constructor(this.value.clone() as T, this.size()); } + /** + * Get a key representation for this value. + * The key equality is consistent with object equality. + * + * @returns The string key. + */ key(): string { return this.toString(); } } +/** + * Wrapper class for deductive system strings. + * Supports initialization from strings, buffers, or other instances. + * + * @example + * ```typescript + * const str1 = new string_t("hello"); + * const str2 = new string_t(str1.data()); // From binary + * console.log(str1.toString()); // "hello" + * ``` + */ export class string_t extends _common_t { + /** + * Creates a new string instance. + * + * @param value - Initial value (string, buffer, or another string_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.String, value, size); } } +/** + * Wrapper class for logical variables in the deductive system. + * Variables are used in logical terms and can be unified. + * + * @example + * ```typescript + * const var1 = new variable_t("`X"); + * console.log(var1.name().toString()); // "X" + * ``` + */ export class variable_t extends _common_t { + /** + * Creates a new variable instance. + * + * @param value - Initial value (string, buffer, or another variable_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.Variable, value, size); } + /** + * Get the name of this variable. + * + * @returns The variable name as a string_t. + */ name(): string_t { return new string_t(this.value.name()); } } +/** + * Wrapper class for items in the deductive system. + * Items represent constants or functors in logical terms. + * + * @example + * ```typescript + * const item = new item_t("atom"); + * console.log(item.name().toString()); // "atom" + * ``` + */ export class item_t extends _common_t { + /** + * Creates a new item instance. + * + * @param value - Initial value (string, buffer, or another item_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.Item, value, size); } + /** + * Get the name of this item. + * + * @returns The item name as a string_t. + */ name(): string_t { return new string_t(this.value.name()); } } +/** + * Wrapper class for lists in the deductive system. + * Lists contain ordered sequences of terms. + * + * @example + * ```typescript + * const list = new list_t("(a b c)"); + * console.log(list.length()); // 3 + * console.log(list.getitem(0).toString()); // "a" + * ``` + */ export class list_t extends _common_t { + /** + * Creates a new list instance. + * + * @param value - Initial value (string, buffer, or another list_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.List, value, size); } + /** + * Get the number of elements in the list. + * + * @returns The list length. + */ length(): number { return this.value.length(); } + /** + * Get an element from the list by index. + * + * @param index - The zero-based index of the element. + * @returns The term at the specified index. + */ getitem(index: number): term_t { return new term_t(this.value.getitem(index)); } } +/** + * Wrapper class for logical terms in the deductive system. + * A term can be a variable, item, or list. + * + * @example + * ```typescript + * const term = new term_t("(f `x a)"); + * const innerTerm = term.term(); // Get the underlying term type + * ``` + */ export class term_t extends _common_t { + /** + * Creates a new term instance. + * + * @param value - Initial value (string, buffer, or another term_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.Term, value, size); } + /** + * Extracts the underlying term and returns it as its concrete type (variable_t, item_t, or list_t). + * + * @returns The term as a variable_t, item_t, or list_t. + * @throws {Error} If the term type is unexpected. + */ term(): variable_t | item_t | list_t { const term_type: dst.TermType = this.value.get_type(); if (term_type === ds.TermType.Variable) { @@ -144,6 +328,26 @@ export class term_t extends _common_t { } } + /** + * Ground this term using a dictionary to substitute variables with values. + * + * @param other - A term representing a dictionary (list of pairs). Each pair contains a variable and its substitution value. + * Example: "((`a b))" means substitute variable `a with value b. + * @param scope - Optional scope string for variable scoping. + * @returns The grounded term, or null if grounding fails. + * + * @example + * ```typescript + * const a = new term_t("`a"); + * const b = new term_t("((`a b))"); + * console.log(a.ground(b).toString()); // "b" + * + * // With scope + * const c = new term_t("`a"); + * const d = new term_t("((x y `a `b) (y x `b `c))"); + * console.log(c.ground(d, "x").toString()); // "`c" + * ``` + */ ground(other: term_t, scope: string = ""): term_t | null { const capacity = buffer_size(); const term = ds.Term.ground(this.value, other.value, scope, capacity); @@ -154,23 +358,77 @@ export class term_t extends _common_t { } } +/** + * Wrapper class for logical rules in the deductive system. + * A rule consists of zero or more premises (above the line) and a conclusion (below the line). + * + * @example + * ```typescript + * const rule = new rule_t("(father `X `Y)\n----------\n(parent `X `Y)\n"); + * console.log(rule.conclusion().toString()); // "(parent `X `Y)" + * console.log(rule.length()); // 1 (number of premises) + * ``` + */ export class rule_t extends _common_t { + /** + * Creates a new rule instance. + * + * @param value - Initial value (string, buffer, or another rule_t). + * @param size - Optional buffer capacity for the internal storage. + * @throws {Error} If initialization fails. + */ constructor(value: InitialArgument, size: number = 0) { super(ds.Rule, value, size); } + /** + * Get the number of premises in the rule. + * + * @returns The number of premises. + */ length(): number { return this.value.length(); } + /** + * Get a premise term by index. + * + * @param index - The zero-based index of the premise. + * @returns The premise term at the specified index. + */ getitem(index: number): term_t { return new term_t(this.value.getitem(index)); } + /** + * Get the conclusion of the rule. + * + * @returns The conclusion term. + */ conclusion(): term_t { return new term_t(this.value.conclusion()); } + /** + * Ground this rule using a dictionary to substitute variables with values. + * + * @param other - A rule representing a dictionary (list of pairs). Each pair contains a variable and its substitution value. + * Example: new rule_t("((`a b))") means substitute variable `a with value b. + * @param scope - Optional scope string for variable scoping. + * @returns The grounded rule, or null if grounding fails. + * + * @example + * ```typescript + * const a = new rule_t("`a"); + * const b = new rule_t("((`a b))"); + * console.log(a.ground(b).toString()); // "----\nb\n" + * + * // With scope + * const c = new rule_t("`a"); + * const d = new rule_t("((x y `a `b) (y x `b `c))"); + * console.log(c.ground(d, "x").toString()); // "----\n`c\n" + * ``` + */ ground(other: rule_t, scope: string = ""): rule_t | null { const capacity = buffer_size(); const rule = ds.Rule.ground(this.value, other.value, scope, capacity); @@ -180,6 +438,21 @@ export class rule_t extends _common_t { return new rule_t(rule, capacity); } + /** + * Match this rule with another rule using unification. + * This unifies the first premise of this rule with the other rule. + * The other rule must be a fact (a rule without premises). + * + * @param other - The rule to match against (must be a fact without premises). + * @returns The matched rule, or null if matching fails. + * + * @example + * ```typescript + * const mp = new rule_t("(`p -> `q)\n`p\n`q\n"); + * const pq = new rule_t("((! (! `x)) -> `x)"); + * console.log(mp.match(pq).toString()); // "(! (! `x))\n----------\n`x\n" + * ``` + */ match(other: rule_t): rule_t | null { const capacity = buffer_size(); const rule = ds.Rule.match(this.value, other.value, capacity); @@ -190,29 +463,75 @@ export class rule_t extends _common_t { } } +/** + * Search engine for the deductive system. + * Manages a knowledge base of rules and performs logical inference. + * + * @example + * ```typescript + * const search = new search_t(); + * search.add("(parent john mary)"); + * search.add("(father `X `Y)\n----------\n(parent `X `Y)\n"); + * search.execute((rule) => { + * console.log(rule.toString()); + * return false; // Return false to continue, true to stop + * }); + * ``` + */ export class search_t { _search: dst.Search; + /** + * Creates a new search engine instance. + * + * @param limit_size - Size of the buffer for storing the final objects (rules/facts) in the knowledge base (default: 1000). + * @param buffer_size - Size of the buffer for internal operations like conversions and transformations (default: 10000). + */ constructor(limit_size: number = 1000, buffer_size: number = 10000) { this._search = new ds.Search(limit_size, buffer_size); } + /** + * Set the size of the buffer for storing final objects. + * + * @param limit_size - The new limit size for storing rules/facts. + */ set_limit_size(limit_size: number): void { this._search.set_limit_size(limit_size); } + /** + * Set the buffer size for internal operations. + * + * @param buffer_size - The new buffer size. + */ set_buffer_size(buffer_size: number): void { this._search.set_buffer_size(buffer_size); } + /** + * Reset the search engine, clearing all rules and facts. + */ reset(): void { this._search.reset(); } + /** + * Add a rule or fact to the knowledge base. + * + * @param text - The rule or fact as a string. + * @returns True if successfully added, false otherwise. + */ add(text: string): boolean { return this._search.add(text); } + /** + * Execute the search engine with a callback for each inferred rule. + * + * @param callback - Function called for each candidate rule. Return false to continue, true to stop. + * @returns The number of rules processed. + */ execute(callback: (candidate: rule_t) => boolean): number { return this._search.execute((candidate: dst.Rule): boolean => { return callback(new rule_t(candidate).copy());