Skip to content

Commit

Permalink
docs(sexpr): update readme (code example)
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Sep 4, 2023
1 parent 567fc85 commit 9dede7f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 28 deletions.
29 changes: 16 additions & 13 deletions packages/sexpr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -195,8 +190,10 @@ const interpret = runtime<Implementations<any, any>, any, any>({
// for expression nodes (aka function calls) delegate to builtins
// (implementations are defined further below)
expr: (x, env) => builtins(<Sym>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,
Expand Down Expand Up @@ -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[(<Sym>name).value] = interpret(value, env)),
def: (_, [__, name, value], env) => (env[(<Sym>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) => {
Expand All @@ -261,15 +260,19 @@ builtins.addAll({
return body.reduce((_, x) => interpret(x, $env), <any>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[(<Sym>x).value];
assert(!!f, "missing impl");
const name = (<Sym>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
Expand Down
32 changes: 17 additions & 15 deletions packages/sexpr/tpl.readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -143,9 +138,11 @@ const interpret = runtime<Implementations<any, any>, any, any>({
// for expression nodes (aka function calls) delegate to builtins
// (implementations are defined further below)
expr: (x, env) => builtins(<Sym>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,
});
Expand Down Expand Up @@ -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[(<Sym>name).value] = interpret(value, env)),
def: (_, [__, name, value], env) => (env[(<Sym>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) => {
Expand All @@ -209,15 +208,19 @@ builtins.addAll({
return body.reduce((_, x) => interpret(x, $env), <any>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[(<Sym>x).value];
assert(!!f, "missing impl");
const name = (<Sym>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
Expand All @@ -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),
});
Expand Down

0 comments on commit 9dede7f

Please sign in to comment.