diff options
Diffstat (limited to 'js/scripting-lang/design/IDEAS.md')
-rw-r--r-- | js/scripting-lang/design/IDEAS.md | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/js/scripting-lang/design/IDEAS.md b/js/scripting-lang/design/IDEAS.md new file mode 100644 index 0000000..f11b9da --- /dev/null +++ b/js/scripting-lang/design/IDEAS.md @@ -0,0 +1,375 @@ +# Ideas for future enhancements + +## io architecture ideas + +### ..listen and ..emit for external process interface +- ..listen: receives well-defined state object from JS harness +- ..emit: sends state/commands back to JS harness +- pattern similar to Elm's TEA (The Elm Architecture) + +### js harness application: +- holds the scripting language interpreter +- manages state flow: input -> script -> output +- provides well-known interface for data exchange +- handles error recovery and safety + +### safety considerations: +- sandboxed execution environment +- timeouts for script execution +- memory limits +- input validation/sanitization +- error boundaries around script execution +- fallback state if script fails + +### error tolerance: +- graceful degradation when scripts fail +- default/fallback responses +- retry mechanisms with backoff +- circuit breaker pattern for repeated failures +- logging and monitoring of script execution + +### architectural patterns this resembles: +- actor model (isolated state, message passing) +- event sourcing (state changes as events) +- command pattern (emit commands, not direct state mutations) +- microservices communication patterns +- reactive programming (data flow, state updates) + +### js harness interface ideas: +- onStateUpdate(callback) - register for state changes +- sendState(state) - send state to script +- onError(callback) - handle script errors +- setConfig(options) - configure timeouts, limits, etc. + +### example flow: +1. external system sends state to js harness +2. harness calls script with ..listen state +3. script processes state, emits new state/commands +4. harness receives emit, updates external system +5. cycle repeats + +### questions: +- should scripts be stateless or maintain internal state? +- how to handle async operations in scripts? +- what format for state objects? (json, structured data?) +- how to version state schemas? +- should emit be synchronous or allow batching? + +--- + +## js harness pseudo code + +### basic harness structure +```javascript +class ScriptHarness { + constructor(config) { + this.interpreter = new ScriptInterpreter(); + this.stateHistory = []; + this.config = { + timeout: 5000, + memoryLimit: '10MB', + maxRetries: 3, + ...config + }; + } + + // main entry point + async processState(newState) { + try { + // validate and version state + const validatedState = this.validateState(newState); + + // add to history + this.stateHistory.push({ + version: validatedState.version, + timestamp: Date.now(), + data: validatedState + }); + + // run script with state + const result = await this.runScript(validatedState); + + // emit result to external system + await this.emitResult(result); + + } catch (error) { + await this.handleError(error); + } + } + + // run script with timeout and error handling + async runScript(state) { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('Script execution timeout')); + }, this.config.timeout); + + try { + // translate JS state to script format + const scriptState = this.translateToScript(state); + + // run script with ..listen and capture ..emit + const result = this.interpreter.run(scriptState); + + clearTimeout(timeout); + resolve(result); + } catch (error) { + clearTimeout(timeout); + reject(error); + } + }); + } + + // state translation layer + translateToScript(jsState) { + // convert JS objects to script tables + // handle null/undefined + // add version info + // validate schema + return { + data: this.convertToTable(jsState), + version: jsState.version || '1.0.0', + timestamp: Date.now() + }; + } + + translateFromScript(scriptResult) { + // convert script tables back to JS objects + // validate output schema + // handle errors + return this.convertFromTable(scriptResult); + } + + // state history management + rewindToVersion(targetVersion) { + // find state at target version + // replay state changes up to that point + // return state at that version + } + + stepForward() { + // move one state forward in history + } + + stepBackward() { + // move one state backward in history + } + + // error handling + async handleError(error) { + // log error + // apply fallback state + // notify external system + // implement circuit breaker if needed + } +} +``` + +### external system integration +```javascript +// example usage +const harness = new ScriptHarness({ + timeout: 3000, + maxRetries: 2 +}); + +// register callbacks +harness.onStateUpdate((newState) => { + // send to external system + externalSystem.update(newState); +}); + +harness.onError((error) => { + // handle script errors + console.error('Script error:', error); + externalSystem.handleError(error); +}); + +// process incoming state +await harness.processState({ + user: { name: "Alice", age: 30 }, + action: "login", + version: "1.0.0" +}); +``` + +### script execution flow +```javascript +// script gets state via ..listen +// script processes state +// script emits result via ..emit +// harness captures emit and translates back to JS + +// example script: +/* +current_state : ..listen; +processed : when current_state.action is + "login" then { user: current_state.user, status: "logged_in" } + "logout" then { user: null, status: "logged_out" } + _ then current_state; +..emit processed; +*/ +``` + +--- + +## script design decisions + +### stateless scripts (agreed - most functional approach) +- scripts are pure functions: state in -> state out +- no internal state, no side effects between calls +- each ..listen call starts fresh +- enables easy testing, debugging, replay +- matches functional programming principles + +### async operations ideas: +- ..wait ms - pause script execution for milliseconds +- ..promise value - create a promise-like construct +- ..yield - yield control back to harness, resume later +- ..spawn script - run another script asynchronously +- ..join handle - wait for spawned script to complete +- or: keep scripts synchronous, handle async in JS harness + +### state format translation layer: +- js objects -> script tables conversion +- script tables -> js objects conversion +- schema validation on both sides +- type coercion (numbers, strings, booleans) +- nested object/table translation +- array/table translation (1-based indexing) +- null/undefined handling + +### known architectural approaches: +- adapter pattern (translate between formats) +- facade pattern (simplify complex interfaces) +- data transfer objects (DTOs) +- serialization/deserialization layers +- schema-first design (define format first) + +### schema versioning for state history: +- version field in state objects +- migration functions for old -> new schemas +- state history as array of versioned states +- rollback capability to previous versions +- forward compatibility (new code handles old state) +- backward compatibility (old code handles new state) + +### versioning approaches: +- semantic versioning (major.minor.patch) +- timestamp-based versioning +- hash-based versioning (content-addressable) +- incremental versioning (v1, v2, v3) + +### state history implementation: +- append-only log of state changes +- each state includes version and timestamp +- rewind: replay state changes up to target version +- step: move forward/backward one state at a time +- snapshot: save current state for quick restore + +### emit behavior: +- synchronous by default (simpler to reason about) +- single emit per script execution +- multiple emits could be batched by harness +- or: allow multiple emits, harness decides how to handle +- error if script doesn't emit anything + +--- + +## type checking ideas + +### type checker functions +- add to standard library: is_number, is_string, is_boolean, is_function, is_table, is_null, is_undefined +- use with @ syntax in when expressions +- no parser changes needed +- composable with existing operators + +### example +``` +is_number : x -> equals(typeof x, "number"); +classify : x -> when x is + @is_number then "number" + @is_string then "string" + @is_table then "table" + _ then "unknown"; +``` + +### advantages: +- uses existing features +- composable (can combine with and/or) +- extensible +- consistent with functional patterns +- immediate implementation possible + +### advanced type checking ideas + +#### error type support +- add is_error to standard library +- error objects could have structure: { type: "error", message: "string", code: "number" } +- or simpler: just check if object has error-like properties + +```javascript +// basic error checking using existing patterns +is_error : x -> @is_table and not @equals(x.error, undefined); + +// more sophisticated error checking +is_error : x -> @is_table and + (@logicalOr + (@not @equals(x.error, undefined)) + (@logicalOr + (@not @equals(x.message, undefined)) + (@not @equals(x.code, undefined)) + ) + ); + +// alternative: use table access with error handling +is_error : x -> @is_table and + (@logicalOr + (@not @equals(x["error"], undefined)) + (@logicalOr + (@not @equals(x["message"], undefined)) + (@not @equals(x["code"], undefined)) + ) + ); + +// usage in when expressions +handle_result : x -> when x is + @is_error then "error occurred" + @is_number then "success" + _ then "unknown"; +``` + +#### tagged unions / discriminated unions +- could represent different states: success/error, loading/loaded/error, etc. +- structure: { tag: "success", data: value } or { tag: "error", error: message } + +```javascript +// type checkers for tagged unions +has_tag : tag -> obj -> @is_table and equals(obj.tag, tag); + +is_success : x -> has_tag "success" x; +is_error_result : x -> has_tag "error" x; + +// usage +process_result : x -> when x is + @is_success then x.data + @is_error_result then "error: " + x.error + _ then "unknown result"; +``` + +#### questions about error types: +- do we need a special error type or just error-like objects? +- should errors be first-class or just table properties? +- how do errors propagate through function composition? +- should we have error handling combinators (map_error, catch_error)? + +#### questions about tagged unions: +- are they worth the complexity for this language? +- do they add enough value over simple when expressions? +- would they make scripts harder to read/write? +- are they more useful in the JS harness than in scripts? + +#### simpler alternatives: +- just use when expressions with property checking +- error handling in JS harness, keep scripts simple +- use standard library functions for common error patterns \ No newline at end of file |