From 9dede7f317f066245f503cffd86ab1dcbdb9f57b Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Mon, 4 Sep 2023 12:01:26 +0200 Subject: [PATCH] docs(sexpr): update readme (code example) --- packages/sexpr/README.md | 29 ++++++++++++++++------------- packages/sexpr/tpl.readme.md | 32 +++++++++++++++++--------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/packages/sexpr/README.md b/packages/sexpr/README.md index 7b97cf3005..673ec4de61 100644 --- a/packages/sexpr/README.md +++ b/packages/sexpr/README.md @@ -171,14 +171,9 @@ parse(`(* (+ 3 5) 10)`); ```ts tangle:export/readme.ts import type { Fn, Fn2 } from "@thi.ng/api"; import { DEFAULT, defmulti, type MultiFn3 } from "@thi.ng/defmulti"; -import { assert } from "@thi.ng/errors"; import { - parse, - runtime, - type ASTNode, - type Expression, - type Implementations, - type Sym, + parse, runtime, + type ASTNode, type Expression, type Implementations, type Sym } from "@thi.ng/sexpr"; // evaluator: parses given source string into an abstract syntax tree (AST) and @@ -195,8 +190,10 @@ const interpret = runtime, any, any>({ // for expression nodes (aka function calls) delegate to builtins // (implementations are defined further below) expr: (x, env) => builtins(x.children[0], x.children, env), + // lookup symbol's value (via its name) in environment sym: (x, env) => env[x.value], + // strings and numbers evaluate verbatim str: (x) => x.value, num: (x) => x.value, @@ -235,17 +232,19 @@ builtins.addAll({ "*": mathOp((acc, x) => acc * x, (x) => x), "-": mathOp((acc, x) => acc - x, (x) => -x), "/": mathOp((acc, x) => acc / x, (x) => 1 / x), + // count returns the length of first argument (presumably a string) // (e.g. `(count "abc")` => 3) count: (_, [__, arg], env) => interpret(arg, env).length, + // concatenates all args into a space-separated string and prints it // returns undefined - print: (_, [__, ...args], env) => - console.log(evalArgs(args, env).join(" ")), + print: (_, [__, ...args], env) => console.log(evalArgs(args, env).join(" ")), + // defines as new symbol with given value, stores it in the environment and // then returns the value, e.g. `(def magic 42)` - def: (_, [__, name, value], env) => - (env[(name).value] = interpret(value, env)), + def: (_, [__, name, value], env) => (env[(name).value] = interpret(value, env)), + // defines a new function with given name, args and body, stores it in the // environment and returns it, e.g. `(defn madd (a b c) (+ (* a b) c))` defn: (_, [__, name, args, ...body], env) => { @@ -261,15 +260,19 @@ builtins.addAll({ return body.reduce((_, x) => interpret(x, $env), undefined); }); }, + // add default/fallback implementation to allow calling functions defined in // the environment (either externally or via `defn`) [DEFAULT]: (x: ASTNode, [_, ...args]: ASTNode[], env: any) => { - const f = env[(x).value]; - assert(!!f, "missing impl"); + const name = (x).value; + const f = env[name]; + if (!f) throw new Error(`missing impl for: ${name}`); return f.apply(null, evalArgs(args, env)); }, }); +// testing our toy Lisp DSL... + // define symbol and use in another expression $eval(`(def chars "abc") (print (count chars) "characters")`); // 3 characters diff --git a/packages/sexpr/tpl.readme.md b/packages/sexpr/tpl.readme.md index 4973ae4c34..08f6d7b6fd 100644 --- a/packages/sexpr/tpl.readme.md +++ b/packages/sexpr/tpl.readme.md @@ -119,14 +119,9 @@ parse(`(* (+ 3 5) 10)`); ```ts tangle:export/readme.ts import type { Fn, Fn2 } from "@thi.ng/api"; import { DEFAULT, defmulti, type MultiFn3 } from "@thi.ng/defmulti"; -import { assert } from "@thi.ng/errors"; import { - parse, - runtime, - type ASTNode, - type Expression, - type Implementations, - type Sym, + parse, runtime, + type ASTNode, type Expression, type Implementations, type Sym } from "@thi.ng/sexpr"; // evaluator: parses given source string into an abstract syntax tree (AST) and @@ -143,9 +138,11 @@ const interpret = runtime, any, any>({ // for expression nodes (aka function calls) delegate to builtins // (implementations are defined further below) expr: (x, env) => builtins(x.children[0], x.children, env), + // lookup symbol's value (via its name) in environment sym: (x, env) => env[x.value], - // strings and numbers evaluate verbatim + + // strings and numbers evaluate verbatim str: (x) => x.value, num: (x) => x.value, }); @@ -183,17 +180,19 @@ builtins.addAll({ "*": mathOp((acc, x) => acc * x, (x) => x), "-": mathOp((acc, x) => acc - x, (x) => -x), "/": mathOp((acc, x) => acc / x, (x) => 1 / x), + // count returns the length of first argument (presumably a string) // (e.g. `(count "abc")` => 3) count: (_, [__, arg], env) => interpret(arg, env).length, + // concatenates all args into a space-separated string and prints it // returns undefined - print: (_, [__, ...args], env) => - console.log(evalArgs(args, env).join(" ")), + print: (_, [__, ...args], env) => console.log(evalArgs(args, env).join(" ")), + // defines as new symbol with given value, stores it in the environment and // then returns the value, e.g. `(def magic 42)` - def: (_, [__, name, value], env) => - (env[(name).value] = interpret(value, env)), + def: (_, [__, name, value], env) => (env[(name).value] = interpret(value, env)), + // defines a new function with given name, args and body, stores it in the // environment and returns it, e.g. `(defn madd (a b c) (+ (* a b) c))` defn: (_, [__, name, args, ...body], env) => { @@ -209,15 +208,19 @@ builtins.addAll({ return body.reduce((_, x) => interpret(x, $env), undefined); }); }, + // add default/fallback implementation to allow calling functions defined in // the environment (either externally or via `defn`) [DEFAULT]: (x: ASTNode, [_, ...args]: ASTNode[], env: any) => { - const f = env[(x).value]; - assert(!!f, "missing impl"); + const name = (x).value; + const f = env[name]; + if (!f) throw new Error(`missing impl for: ${name}`); return f.apply(null, evalArgs(args, env)); }, }); +// testing our toy Lisp DSL... + // define symbol and use in another expression $eval(`(def chars "abc") (print (count chars) "characters")`); // 3 characters @@ -226,7 +229,6 @@ $eval(`(def chars "abc") (print (count chars) "characters")`); $eval(`(defn madd (a b c) (+ (* a b) c)) (print (madd 3 5 (* 5 2)))`); // 25 -// pre-define a function in the environment and then use it $eval(`(print (join " | " (+ 1 2) (* 3 4) (- 5 6) (/ 7 8)))`, { join: (sep: string, ...xs: any[]) => xs.join(sep), });