@lionlang/core 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +324 -6
  2. package/package.json +2 -1
package/README.md CHANGED
@@ -1,15 +1,333 @@
1
- # @lionlang/core
1
+ # Lion
2
2
 
3
- To install dependencies:
3
+ Lion is a JSON-based Lisp. Every Lion program is valid JSON, which makes it easy to serialize, store, inspect, and generate from other systems.
4
+
5
+ Lion evaluates:
6
+
7
+ - JSON primitives directly
8
+ - strings as environment references when a binding exists
9
+ - arrays as special forms or function-call expressions
10
+ - objects by recursively evaluating their values
11
+
12
+ The result is a small homoiconic language that can describe both computation and data interchange without a separate parser.
13
+
14
+ ## Packages
15
+
16
+ ```text
17
+ packages/
18
+ core/ evaluator, special forms, stdlib
19
+ repl/ interactive web REPL
20
+ agent/ real-world Lion program driving an OpenTUI + AI agent
21
+ ```
22
+
23
+ ## Basic Usage
24
+
25
+ ```ts
26
+ import { Effect } from "effect";
27
+ import { run } from "@lionlang/core/evaluation/evaluate";
28
+ import { stdlib } from "@lionlang/core/modules";
29
+
30
+ const result = await Effect.runPromise(
31
+ run(["number/add", 1, 2], stdlib)
32
+ );
33
+
34
+ // => 3
35
+ ```
36
+
37
+ ## Custom Environment
38
+
39
+ Any string can resolve against the evaluation environment. That includes values, objects, classes, and functions.
40
+
41
+ ```ts
42
+ import { Effect } from "effect";
43
+ import { run } from "@lionlang/core/evaluation/evaluate";
44
+ import { stdlib } from "@lionlang/core/modules";
45
+
46
+ const env = {
47
+ ...stdlib,
48
+ price: 100,
49
+ taxRate: 0.08,
50
+ clamp: (min: number, max: number, value: number) =>
51
+ Math.min(max, Math.max(min, value)),
52
+ };
53
+
54
+ await Effect.runPromise(
55
+ run(["number/add", "price", ["number/multiply", "price", "taxRate"]], env)
56
+ );
57
+ // => 108
58
+
59
+ await Effect.runPromise(run(["clamp", 0, 100, 150], env));
60
+ // => 100
61
+ ```
62
+
63
+ ## Expression Model
64
+
65
+ ### Primitives
66
+
67
+ Numbers, booleans, and `null` evaluate to themselves. Strings are treated as references first; if no binding exists, the original string is returned.
68
+
69
+ ```json
70
+ 42
71
+ true
72
+ null
73
+ "x"
74
+ ```
75
+
76
+ With `{ "x": 10 }` in the environment, `"x"` evaluates to `10`. Otherwise it evaluates to `"x"`.
77
+
78
+ ### Arrays
79
+
80
+ Arrays are always treated as executable expressions:
81
+
82
+ 1. special forms such as `["define", "x", 1]`
83
+ 2. function calls when the first element evaluates to a function
84
+
85
+ ```json
86
+ ["number/add", 1, 2]
87
+ ```
88
+
89
+ Evaluates to `3`.
90
+
91
+ ### Objects
92
+
93
+ Objects preserve their keys and evaluate each value.
94
+
95
+ ```json
96
+ {
97
+ "sum": ["number/add", 1, 2],
98
+ "ok": true
99
+ }
100
+ ```
101
+
102
+ Evaluates to `{ "sum": 3, "ok": true }`.
103
+
104
+ ## Special Forms
105
+
106
+ ### `quote`
107
+
108
+ Returns its argument without evaluating it.
109
+
110
+ ```json
111
+ ["quote", ["number/add", 1, 2]]
112
+ ```
113
+
114
+ ### `eval`
115
+
116
+ Evaluates its argument, then evaluates the result.
117
+
118
+ ```json
119
+ ["eval", ["quote", ["number/add", 1, 2]]]
120
+ ```
121
+
122
+ ### `begin`
123
+
124
+ Evaluates expressions in order and returns the last result.
125
+
126
+ ```json
127
+ ["begin", ["define", "x", 1], ["define", "x", 2], "x"]
128
+ ```
129
+
130
+ ### `define`
131
+
132
+ Evaluates a value, stores it in the global environment, and returns the stored value.
133
+
134
+ ```json
135
+ ["define", "answer", 42]
136
+ ```
137
+
138
+ ### `lambda`
139
+
140
+ Creates a Lion function with lexical scope.
141
+
142
+ ```json
143
+ ["lambda", ["x"], ["number/add", "x", 1]]
144
+ ```
145
+
146
+ Lambdas close over surrounding scope, and they observe updated global bindings when invoked later.
147
+
148
+ ### `cond`
149
+
150
+ Evaluates condition/result pairs in order and returns the first matching result. An `else` branch is optional.
151
+
152
+ ```json
153
+ ["cond",
154
+ [["number/greaterThan", "score", 90], "great"],
155
+ [["number/greaterThan", "score", 70], "pass"],
156
+ ["else", "retry"]]
157
+ ```
158
+
159
+ If no branch matches and no `else` is provided, `cond` returns `null`.
160
+
161
+ ### `match`
162
+
163
+ Pattern matches a value against predicate/function pairs, then applies the first matching branch. The last argument is a fallback function.
164
+
165
+ ```json
166
+ ["match",
167
+ "value",
168
+ ["value/number?", ["lambda", ["x"], ["number/add", "x", 1]]],
169
+ ["value/string?", ["lambda", ["x"], ["string/concat", "x", "!"]]],
170
+ ["lambda", ["x"], "x"]]
171
+ ```
172
+
173
+ `match` also supports structural predicates:
174
+
175
+ ```json
176
+ ["match",
177
+ { "type": "user", "profile": { "name": "Ada" } },
178
+ [
179
+ {
180
+ "type": ["func/partial", "string/equals?", "user"],
181
+ "profile": { "name": "value/string?" }
182
+ },
183
+ "value/identity"
184
+ ],
185
+ ["lambda", ["x"], null]]
186
+ ```
187
+
188
+ ## Standard Library
189
+
190
+ The default environment exported as `stdlib` namespaces entries as `<module>/<name>`.
191
+
192
+ ### `number`
193
+
194
+ ```json
195
+ ["number/add", 1, 2]
196
+ ["number/subtract", 10, 3]
197
+ ["number/multiply", 5, 4]
198
+ ["number/divide", 20, 4]
199
+ ["number/equals?", 5, 5]
200
+ ["number/lessThan", 3, 5]
201
+ ["number/greaterThan", 5, 3]
202
+ ["number/lessThanOrEqualTo", 3, 5]
203
+ ["number/greaterThanOrEqualTo", 5, 5]
204
+ ```
205
+
206
+ ### `boolean`
207
+
208
+ ```json
209
+ ["boolean/not", true]
210
+ ["boolean/and", true, false]
211
+ ["boolean/or", false, true]
212
+ ["boolean/xor", true, false]
213
+ ["boolean/nand", true, true]
214
+ ["boolean/nor", false, false]
215
+ ["boolean/equals?", true, true]
216
+ ```
217
+
218
+ ### `array`
219
+
220
+ ```json
221
+ ["array/make", 1, 2, 3]
222
+ ["array/head", ["array/make", 1, 2, 3]]
223
+ ["array/tail", ["array/make", 1, 2, 3]]
224
+ ["array/length", ["array/make", 1, 2, 3]]
225
+ ["array/concat", ["array/make", 1, 2], ["array/make", 3, 4]]
226
+ ["array/includes?", ["array/make", 1, 2, 3], 2]
227
+ ["array/map", ["array/make", 1, 2, 3], ["lambda", ["x"], ["number/add", "x", 1]]]
228
+ ["array/flat-map", ["array/make", 1, 2], ["lambda", ["x"], ["array/make", "x", "x"]]]
229
+ ["array/reduce", ["array/make", 1, 2, 3], 0, ["lambda", ["acc", "x"], ["number/add", "acc", "x"]]]
230
+ ```
231
+
232
+ ### `string`
233
+
234
+ ```json
235
+ ["string/equals?", "a", "a"]
236
+ ["string/length", "lion"]
237
+ ["string/concat", "lion", "ized"]
238
+ ["string/startsWith", "lion", "li"]
239
+ ["string/endsWith", "lion", "on"]
240
+ ["string/includes", "lion", "io"]
241
+ ["string/indexOf", "lion", "o"]
242
+ ```
243
+
244
+ ### `object`
245
+
246
+ ```json
247
+ ["object/get", {"a": 1}, "a"]
248
+ ["object/get-path", {"a": {"b": {"c": 42}}}, "a.b.c"]
249
+ ["object/keys", {"a": 1, "b": 2}]
250
+ ["object/values", {"a": 1, "b": 2}]
251
+ ["object/json-stringify", {"a": 1}, null, 2]
252
+ ["object/get-method", "obj", "methodName"]
253
+ ["object/call-method", "obj", "methodName", 1, 2]
254
+ ["object/get-method-path", "obj", "nested.methodName"]
255
+ ["object/call-method-path", "obj", "nested.methodName", 1, 2]
256
+ ["object/new", "SomeClass", "arg1", "arg2"]
257
+ ```
258
+
259
+ `object/get-path` understands dot paths and numeric array segments such as `"users.1.name"`.
260
+
261
+ ### `func`
262
+
263
+ ```json
264
+ ["func/bind", "fn", "obj"]
265
+ ["func/apply", "fn", "obj", 1, 2]
266
+ ["func/callback", ["lambda", ["x"], ["number/add", "x", 1]]]
267
+ ["func/partial", "fn", 1, 2]
268
+ ```
269
+
270
+ `func/callback` is especially useful for turning Lion lambdas into JavaScript callbacks while preserving access to the Lion environment.
271
+
272
+ ### `value`
273
+
274
+ ```json
275
+ ["value/function?", "x"]
276
+ ["value/number?", 1]
277
+ ["value/string?", "lion"]
278
+ ["value/boolean?", true]
279
+ ["value/object?", {"a": 1}]
280
+ ["value/array?", ["array/make", 1, 2]]
281
+ ["value/null?", null]
282
+ ["value/identity", 42]
283
+ ```
284
+
285
+ `value/undefined?` and `value/symbol?` are mainly useful when Lion is evaluating host values supplied through the environment.
286
+
287
+ ### `console`
288
+
289
+ ```json
290
+ ["console/log", "hello"]
291
+ ["console/log-json", {"hello": "world"}]
292
+ ```
293
+
294
+ ## Host Interop
295
+
296
+ Lion works well as a configuration and orchestration layer over ordinary JavaScript objects and functions.
297
+
298
+ The `packages/agent` package is the clearest example. It injects:
299
+
300
+ - `OpenTUI` classes and enums
301
+ - AI SDK helpers
302
+ - a model instance
303
+ - Node `fs`
304
+ - Zod constructors
305
+ - a renderer instance
306
+
307
+ Then Lion code in [`packages/agent/src/agent.json`](/Users/andrueanderson/Workspace/TypeScript/lion/packages/agent/src/agent.json) uses:
308
+
309
+ - `object/get-path` to traverse host APIs
310
+ - `object/new` to construct classes
311
+ - `object/call-method` via aliases such as `"()"`
312
+ - `func/callback` to hand Lion lambdas to promise and event APIs
313
+ - `match`, `cond`, `begin`, and `define` to orchestrate application flow
314
+
315
+ That lets Lion drive a non-trivial terminal UI agent entirely from JSON.
316
+
317
+ ## Development
318
+
319
+ From the repo root:
4
320
 
5
321
  ```bash
6
322
  bun install
323
+ bun run prepare
324
+ bun test
325
+ bun run build
7
326
  ```
8
327
 
9
- To run:
328
+ To work on a specific package:
10
329
 
11
330
  ```bash
12
- bun run index.ts
331
+ turbo test --filter=@lionlang/core
332
+ turbo dev --filter=@lionlang/repl
13
333
  ```
14
-
15
- This project was created using `bun init` in bun v1.3.1. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@lionlang/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Lion is a JSON-based Lisp.",
6
6
  "license": "MIT",
7
7
  "author": "Andrue Anderson <andrue.anderson.cs@gmail.com>",
8
+ "homepage": "https://lionlang.dev",
8
9
  "repository": {
9
10
  "type": "git",
10
11
  "url": "git+https://github.com/andrueandersoncs/lion.git",