diff options
Diffstat (limited to 'js/baba-yaga/scratch/baba/with.baba')
-rw-r--r-- | js/baba-yaga/scratch/baba/with.baba | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/js/baba-yaga/scratch/baba/with.baba b/js/baba-yaga/scratch/baba/with.baba new file mode 100644 index 0000000..05de150 --- /dev/null +++ b/js/baba-yaga/scratch/baba/with.baba @@ -0,0 +1,217 @@ +// with.baba — Dev playground and implementation plan for header `with` locals +// +// This file documents the proposed `with` and `with rec` header clauses for +// local bindings inside function bodies. It contains: +// - Syntax and semantics +// - Typing rules (locals treated like globals) +// - Semicolon policy +// - Examples (untyped, typed, shadowing, with `when`, mutual recursion) +// - Error cases +// - Implementation plan (lexer, parser, interpreter, tests) +// +// NOTE: All examples are commented out so this file remains parseable until the +// feature is implemented. + +// ----------------------------------------------------------------------------- +// Syntax +// +// Function declaration (untyped params): +// name : params -> with ( headerEntries ) -> body; +// +// Function declaration (typed params + return type): +// name : (x: T, y: U) -> R -> with ( headerEntries ) -> body; +// +// Header entries inside `with ( ... )` are separated by semicolons `;` and may +// end with an optional trailing semicolon. +// Each entry is either: +// - Type declaration (same style as global): +// ident Type; +// - Assignment (value): +// ident : expression; +// +// Mutually recursive locals use `with rec` (or `with recursion`) to pre-bind: +// name : args -> ... +// with rec ( +// f : a -> ... g ...; +// g : b -> ... f ...; +// ) -> +// body; +// +// Soft keywords: +// - `with` and `rec` are recognized only in the function-header position +// (immediately after an arrow). Elsewhere they remain plain identifiers. + +// ----------------------------------------------------------------------------- +// Semantics +// +// with (non-rec): +// - Create an inner scope layered over the function call scope. +// - Process header entries left-to-right: +// - Type decl: record `name -> Type` in the with-scope types map. +// - Assignment: evaluate expression in the current with-scope, then +// if a type was declared for `name`, validate using the existing runtime +// type lattice (Int ⊂ Float ⊂ Number). Bind `name` to the result. +// - Evaluate `body` in that inner scope; discard the scope after. +// - No forward references among assignments. +// - Shadowing permitted (locals shadow params/globals). +// +// with rec (mutual recursion): +// - Pre-bind all names in the header to placeholders in the with-scope. +// - Evaluate each RHS in order and assign into the same with-scope. +// - Restrict RHS to functions (to avoid non-lazy cycles). If non-function is +// assigned under `rec`, throw a clear error. +// - Body executes after all bindings are assigned. + +// ----------------------------------------------------------------------------- +// Semicolons +// - Inside `with ( ... )`: semicolons separate entries; trailing `;` allowed. +// - Between header and body: only the arrow `->`. +// - After `body`: same as today at top-level (semicolon optional/tolerated). + +// ----------------------------------------------------------------------------- +// Executable Examples + +// 1) Basic locals (untyped) +addMul : x y -> + with (inc : x + 1; prod : inc * y;) -> + inc + prod; +addMulResult : addMul 2 5; + +// 2) Quadratic roots (untyped) +quadraticRoots : a b c -> + with ( + disc : b * b - 4 * a * c; + sqrtDisc : math.sqrt disc; + denom : 2 * a; + ) -> + { r1: (-b + sqrtDisc) / denom, r2: (-b - sqrtDisc) / denom }; +roots : quadraticRoots 1 -3 2; + +// 3) Typed params + typed locals (global-like declarations inside header) +sumNext : (x: Int, y: Int) -> Int -> + with ( + nextX Int; nextY Int; + nextX : x + 1; + nextY : y + 1; + ) -> + nextX + nextY; +sumNextResult : sumNext 2 3; + +// 4) Shadowing and ordering +shadow : x -> + with (x : x + 1; y : x * 2) -> + x + y; +shadowResult : shadow 3; + +// 5) With + when +classify : n -> + with ( + lo Int; hi Int; + lo : 10; hi : 100; + ) -> + when n is + 0 then "zero" + _ then when (n > hi) is + true then "large" + _ then when (n > lo) is + true then "medium" + _ then "small"; +classify0 : classify 0; +classify50 : classify 50; +classify200 : classify 200; + +// Multi-discriminant with local +bucket : x y -> + with (t : x + y) -> + when x t is + 0 0 then "origin" + _ _ then "other"; +bucketResult : bucket 0 0; + +// 6) Result + with + when +safeDivide : x y -> + with (zero : 0) -> + when y is + 0 then Err "Division by zero" + _ then Ok (x / y); + +useDivide : a b -> + with (fallback Int; fallback : 0) -> + when (safeDivide a b) is + Ok v then v + Err _ then fallback; +divOk : useDivide 10 2; +divErr : useDivide 10 0; + +// 7) with rec — mutual recursion among locals +isEvenOdd : z -> + with rec ( + isEven : n -> + when n is + 0 then true + _ then isOdd (n - 1); + isOdd : n -> + when n is + 0 then false + _ then isEven (n - 1); + ) -> + { even: isEven 10, odd: isOdd 7 }; +rEvenOdd : isEvenOdd 0; + +// Sample I/O to visualize outputs when running this file directly +io.out addMulResult; +io.out roots; +io.out sumNextResult; +io.out shadowResult; +io.out classify0 classify50 classify200; +io.out bucketResult; +io.out divOk divErr; +io.out rEvenOdd; + +// ----------------------------------------------------------------------------- +// Error cases (intended) +// - Non-rec forward reference among assignments in `with`: error. +// - In `with rec`, assignment RHS must evaluate to a function: error otherwise. +// - Type mismatch for a typed local: reuse existing error messaging similar to +// function parameter/return mismatches. + +// ----------------------------------------------------------------------------- +// Implementation plan +// 1) Lexer (none/minimal): +// - Keep `with` / `rec` as IDENTIFIER tokens; treat as soft keywords in parser. +// +// 2) Parser (parser.js): +// - After params and optional return type, detect: IDENT('with') [IDENT('rec'|'recursion')] LPAREN ... RPAREN ARROW +// - Parse header entries list: +// entry := IDENT TYPE ';' | IDENT ':' expression ';' +// allow repeated entries and optional trailing ';' +// - AST: augment FunctionDeclaration/CurriedFunctionDeclaration body with optional +// WithHeader { recursive: boolean, entries: Array< TypeDecl | Assign > } +// where TypeDecl { name, typeAnnotation }, Assign { name, expr } +// - Ensure support both in top-level function and nested curried bodies. +// +// 3) Interpreter (interpreter.js): +// - When invoking a function with WithHeader: +// - Create with-scope Map layered over call-scope; maintain withTypes Map. +// - If recursive: +// - Pre-bind all names to undefined in with-scope. +// - Evaluate each Assign RHS with with-scope in effect; verify RHS is Function; set binding. +// Else: +// - Process entries left-to-right: on TypeDecl store in withTypes; on Assign evaluate and bind. +// - On each Assign, if a type exists in withTypes, validate via existing lattice. +// - Evaluate body in with-scope; finally restore original scope. +// +// 4) Tests (tests/*.test.js): +// - parser-with-header.test.js (new): parsing of with/with rec, typed locals, trailing semicolon, shadowing, disallow forward refs. +// - interpreter-with-header.test.js (new): +// * Basic untyped locals +// * Typed locals pass and fail +// * With + when interactions +// * Shadowing behavior +// * with rec mutual recursion (success), non-function RHS (error) +// - Back-compat pass: ensure existing tests still green. +// +// 5) Docs: +// - Update README and ref.txt with the new form, semicolon policy, and examples. + + |