seval.js 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/evaluator.d.ts +31 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +297 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +40 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +152 -0
- package/dist/parser.js.map +1 -0
- package/dist/primitives/arithmetic.d.ts +6 -0
- package/dist/primitives/arithmetic.d.ts.map +1 -0
- package/dist/primitives/arithmetic.js +13 -0
- package/dist/primitives/arithmetic.js.map +1 -0
- package/dist/primitives/array.d.ts +6 -0
- package/dist/primitives/array.d.ts.map +1 -0
- package/dist/primitives/array.js +33 -0
- package/dist/primitives/array.js.map +1 -0
- package/dist/primitives/comparison.d.ts +6 -0
- package/dist/primitives/comparison.d.ts.map +1 -0
- package/dist/primitives/comparison.js +12 -0
- package/dist/primitives/comparison.js.map +1 -0
- package/dist/primitives/index.d.ts +19 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +45 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/primitives/logical.d.ts +6 -0
- package/dist/primitives/logical.d.ts.map +1 -0
- package/dist/primitives/logical.js +9 -0
- package/dist/primitives/logical.js.map +1 -0
- package/dist/primitives/math.d.ts +6 -0
- package/dist/primitives/math.d.ts.map +1 -0
- package/dist/primitives/math.js +21 -0
- package/dist/primitives/math.js.map +1 -0
- package/dist/primitives/object.d.ts +6 -0
- package/dist/primitives/object.d.ts.map +1 -0
- package/dist/primitives/object.js +42 -0
- package/dist/primitives/object.js.map +1 -0
- package/dist/primitives/string.d.ts +6 -0
- package/dist/primitives/string.d.ts.map +1 -0
- package/dist/primitives/string.js +21 -0
- package/dist/primitives/string.js.map +1 -0
- package/dist/primitives/type.d.ts +6 -0
- package/dist/primitives/type.d.ts.map +1 -0
- package/dist/primitives/type.js +12 -0
- package/dist/primitives/type.js.map +1 -0
- package/dist/tokenizer.d.ts +31 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/tokenizer.js +154 -0
- package/dist/tokenizer.js.map +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 cpunion
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# seval.js
|
|
2
|
+
|
|
3
|
+
> S-expression evaluator for TypeScript/JavaScript
|
|
4
|
+
|
|
5
|
+
[](https://github.com/cpunion/seval.js/actions/workflows/ci.yml)
|
|
6
|
+
[](https://codecov.io/gh/cpunion/seval.js)
|
|
7
|
+
[](https://www.npmjs.com/package/seval.js)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
`seval.js` is a safe, sandboxed S-expression parser and evaluator. It's designed to be easily extensible and embeddable in JavaScript/TypeScript applications.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install seval.js
|
|
16
|
+
# or
|
|
17
|
+
bun add seval.js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { evalString, createEvaluator } from 'seval.js'
|
|
24
|
+
|
|
25
|
+
// Simple evaluation
|
|
26
|
+
evalString('(+ 1 2 3)') // 6
|
|
27
|
+
evalString('(* 2 (+ 3 4))') // 14
|
|
28
|
+
|
|
29
|
+
// Conditional and logic
|
|
30
|
+
evalString('(if (> 5 3) "yes" "no")') // "yes"
|
|
31
|
+
evalString('(and true (not false))') // true
|
|
32
|
+
|
|
33
|
+
// Lambda and closures
|
|
34
|
+
evalString('((lambda (x) (* x x)) 5)') // 25
|
|
35
|
+
|
|
36
|
+
// Custom primitives
|
|
37
|
+
const evaluator = createEvaluator({
|
|
38
|
+
primitives: {
|
|
39
|
+
uuid: () => crypto.randomUUID(),
|
|
40
|
+
greet: (args) => `Hello, ${args[0]}!`,
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
evaluator.evalString('(greet "World")') // "Hello, World!"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- **Safe sandboxed evaluation** - No access to global scope or dangerous APIs
|
|
49
|
+
- **Rich primitive library** - 60+ built-in functions for math, strings, arrays, objects
|
|
50
|
+
- **Lambda and closures** - First-class functions with lexical scoping
|
|
51
|
+
- **Customizable** - Add or override primitives easily
|
|
52
|
+
- **TypeScript support** - Full type definitions included
|
|
53
|
+
|
|
54
|
+
## Built-in Primitives
|
|
55
|
+
|
|
56
|
+
### Arithmetic
|
|
57
|
+
`+`, `-`, `*`, `/`, `%`
|
|
58
|
+
|
|
59
|
+
### Comparison
|
|
60
|
+
`=`, `!=`, `<`, `>`, `<=`, `>=`
|
|
61
|
+
|
|
62
|
+
### Logical
|
|
63
|
+
`and`, `or`, `not`
|
|
64
|
+
|
|
65
|
+
### Math
|
|
66
|
+
`abs`, `min`, `max`, `floor`, `ceil`, `round`, `sqrt`, `pow`, `clamp`, `sin`, `cos`, `tan`, `log`, `exp`, `random`
|
|
67
|
+
|
|
68
|
+
### Strings
|
|
69
|
+
`concat`, `str`, `strlen`, `substr`, `str-starts-with`, `str-ends-with`, `str-contains`, `str-replace`, `str-split`, `str-join`, `str-trim`, `str-upper`, `str-lower`, `parse-num`, `parse-int`
|
|
70
|
+
|
|
71
|
+
### Arrays
|
|
72
|
+
`list`, `length`, `first`, `rest`, `last`, `nth`, `append`, `prepend`, `concat-lists`, `slice`, `reverse`, `range`, `empty?`, `contains`, `index-of`
|
|
73
|
+
|
|
74
|
+
### Objects
|
|
75
|
+
`obj`, `get`, `set`, `keys`, `values`, `has-key`, `update-at`, `merge`
|
|
76
|
+
|
|
77
|
+
### Type checks
|
|
78
|
+
`null?`, `number?`, `string?`, `bool?`, `list?`, `object?`
|
|
79
|
+
|
|
80
|
+
## Special Forms
|
|
81
|
+
|
|
82
|
+
```lisp
|
|
83
|
+
; Conditionals
|
|
84
|
+
(if condition then-expr else-expr)
|
|
85
|
+
(cond (test1 expr1) (test2 expr2) (else exprN))
|
|
86
|
+
|
|
87
|
+
; Variable bindings
|
|
88
|
+
(let ((x 1) (y 2)) (+ x y))
|
|
89
|
+
|
|
90
|
+
; Functions
|
|
91
|
+
(lambda (x y) (+ x y))
|
|
92
|
+
(define (square x) (* x x))
|
|
93
|
+
(define pi 3.14159)
|
|
94
|
+
|
|
95
|
+
; Sequences
|
|
96
|
+
(begin expr1 expr2 ...)
|
|
97
|
+
(progn expr1 expr2 ...)
|
|
98
|
+
|
|
99
|
+
; Higher-order functions
|
|
100
|
+
(map (lambda (x) (* x 2)) (list 1 2 3)) ; (2 4 6)
|
|
101
|
+
(filter (lambda (x) (> x 2)) (list 1 2 3 4)) ; (3 4)
|
|
102
|
+
(reduce (list 1 2 3) 0 (acc x) (+ acc x)) ; 6
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## API
|
|
106
|
+
|
|
107
|
+
### `evalString(code: string): Value`
|
|
108
|
+
Parse and evaluate an S-expression string.
|
|
109
|
+
|
|
110
|
+
### `evaluate(expr: SExpr, env?: Environment): Value`
|
|
111
|
+
Evaluate a parsed S-expression AST.
|
|
112
|
+
|
|
113
|
+
### `parse(code: string): SExpr`
|
|
114
|
+
Parse an S-expression string into an AST.
|
|
115
|
+
|
|
116
|
+
### `stringify(expr: SExpr): string`
|
|
117
|
+
Convert an AST back to string.
|
|
118
|
+
|
|
119
|
+
### `createEvaluator(options?: EvaluatorOptions)`
|
|
120
|
+
Create a custom evaluator with additional primitives.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
interface EvaluatorOptions {
|
|
124
|
+
primitives?: Record<string, PrimitiveFunction>
|
|
125
|
+
maxDepth?: number // default: 100
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-Expression Evaluator
|
|
3
|
+
*
|
|
4
|
+
* Safe, sandboxed evaluation of S-expressions with customizable primitives.
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Symbols (typeof === 'symbol') are variable references, looked up in env
|
|
8
|
+
* - Strings (typeof === 'string') are string literals, returned as-is
|
|
9
|
+
*/
|
|
10
|
+
import { type SExpr } from './parser';
|
|
11
|
+
import type { Environment, EvaluatorOptions, Value } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Create a new evaluator instance with optional custom primitives
|
|
14
|
+
*/
|
|
15
|
+
export declare function createEvaluator(options?: EvaluatorOptions): {
|
|
16
|
+
evaluate: (expr: SExpr, env?: Environment) => Value;
|
|
17
|
+
evalString: (code: string, env?: Environment) => Value;
|
|
18
|
+
};
|
|
19
|
+
export declare const defaultEvaluator: {
|
|
20
|
+
evaluate: (expr: SExpr, env?: Environment) => Value;
|
|
21
|
+
evalString: (code: string, env?: Environment) => Value;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Evaluate an S-expression AST
|
|
25
|
+
*/
|
|
26
|
+
export declare const evaluate: (expr: SExpr, env?: Environment) => Value;
|
|
27
|
+
/**
|
|
28
|
+
* Parse and evaluate an S-expression string
|
|
29
|
+
*/
|
|
30
|
+
export declare const evalString: (code: string, env?: Environment) => Value;
|
|
31
|
+
//# sourceMappingURL=evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../src/evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAiC,MAAM,UAAU,CAAA;AAEpE,OAAO,KAAK,EACR,WAAW,EAEX,gBAAgB,EAGhB,KAAK,EACR,MAAM,SAAS,CAAA;AAGhB;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB;qBAmSrC,KAAK,QAAO,WAAW;uBACrB,MAAM,QAAO,WAAW;EAElD;AAGD,eAAO,MAAM,gBAAgB;qBANJ,KAAK,QAAO,WAAW;uBACrB,MAAM,QAAO,WAAW;CAKF,CAAA;AAEjD;;GAEG;AACH,eAAO,MAAM,QAAQ,SAXI,KAAK,QAAO,WAAW,UAWC,CAAA;AAEjD;;GAEG;AACH,eAAO,MAAM,UAAU,SAfI,MAAM,QAAO,WAAW,UAeE,CAAA"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-Expression Evaluator
|
|
3
|
+
*
|
|
4
|
+
* Safe, sandboxed evaluation of S-expressions with customizable primitives.
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Symbols (typeof === 'symbol') are variable references, looked up in env
|
|
8
|
+
* - Strings (typeof === 'string') are string literals, returned as-is
|
|
9
|
+
*/
|
|
10
|
+
import { isSymbol, parse, symName } from './parser';
|
|
11
|
+
import { defaultPrimitives } from './primitives';
|
|
12
|
+
import { isLambda } from './types';
|
|
13
|
+
/**
|
|
14
|
+
* Create a new evaluator instance with optional custom primitives
|
|
15
|
+
*/
|
|
16
|
+
export function createEvaluator(options = {}) {
|
|
17
|
+
const primitives = {
|
|
18
|
+
...defaultPrimitives,
|
|
19
|
+
...options.primitives,
|
|
20
|
+
};
|
|
21
|
+
const maxDepth = options.maxDepth ?? 100;
|
|
22
|
+
function evaluate(expr, env, depth = 0) {
|
|
23
|
+
if (depth > maxDepth) {
|
|
24
|
+
throw new Error('Maximum evaluation depth exceeded');
|
|
25
|
+
}
|
|
26
|
+
// Null
|
|
27
|
+
if (expr === null)
|
|
28
|
+
return null;
|
|
29
|
+
// Literal values
|
|
30
|
+
if (typeof expr === 'number')
|
|
31
|
+
return expr;
|
|
32
|
+
if (typeof expr === 'boolean')
|
|
33
|
+
return expr;
|
|
34
|
+
// String literal - return as-is
|
|
35
|
+
if (typeof expr === 'string')
|
|
36
|
+
return expr;
|
|
37
|
+
// Symbol - look up in environment
|
|
38
|
+
if (isSymbol(expr)) {
|
|
39
|
+
const name = symName(expr);
|
|
40
|
+
if (name in env) {
|
|
41
|
+
return env[name];
|
|
42
|
+
}
|
|
43
|
+
// Symbol not found - return the name as string (might be a primitive name)
|
|
44
|
+
return name;
|
|
45
|
+
}
|
|
46
|
+
// List (function application)
|
|
47
|
+
if (Array.isArray(expr)) {
|
|
48
|
+
if (expr.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
const [op, ...args] = expr;
|
|
51
|
+
const opName = isSymbol(op) ? symName(op) : null;
|
|
52
|
+
// Special forms (check by symbol name)
|
|
53
|
+
if (opName === 'if') {
|
|
54
|
+
const [cond, thenExpr, elseExpr] = args;
|
|
55
|
+
const condResult = evaluate(cond, env, depth + 1);
|
|
56
|
+
return condResult
|
|
57
|
+
? evaluate(thenExpr, env, depth + 1)
|
|
58
|
+
: evaluate(elseExpr, env, depth + 1);
|
|
59
|
+
}
|
|
60
|
+
if (opName === 'let') {
|
|
61
|
+
// (let ((x 1) (y 2)) body)
|
|
62
|
+
const [bindings, body] = args;
|
|
63
|
+
const newEnv = { ...env };
|
|
64
|
+
for (const binding of bindings) {
|
|
65
|
+
const [nameExpr, value] = binding;
|
|
66
|
+
const name = isSymbol(nameExpr) ? symName(nameExpr) : String(nameExpr);
|
|
67
|
+
newEnv[name] = evaluate(value, newEnv, depth + 1);
|
|
68
|
+
}
|
|
69
|
+
return evaluate(body, newEnv, depth + 1);
|
|
70
|
+
}
|
|
71
|
+
if (opName === 'cond') {
|
|
72
|
+
// (cond (test1 expr1) (test2 expr2) (else exprN))
|
|
73
|
+
for (const clause of args) {
|
|
74
|
+
const [test, result] = clause;
|
|
75
|
+
const isElse = isSymbol(test) && symName(test) === 'else';
|
|
76
|
+
if (isElse || evaluate(test, env, depth + 1)) {
|
|
77
|
+
return evaluate(result, env, depth + 1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (opName === 'begin' || opName === 'progn' || opName === 'do') {
|
|
83
|
+
let result = null;
|
|
84
|
+
for (const subExpr of args) {
|
|
85
|
+
result = evaluate(subExpr, env, depth + 1);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
if (opName === 'quote') {
|
|
90
|
+
const val = args[0];
|
|
91
|
+
// For symbols, return the name as string
|
|
92
|
+
if (isSymbol(val)) {
|
|
93
|
+
return symName(val);
|
|
94
|
+
}
|
|
95
|
+
return val;
|
|
96
|
+
}
|
|
97
|
+
// Lambda: (lambda (x y) (+ x y)) or (fn (x y) (+ x y))
|
|
98
|
+
if (opName === 'lambda' || opName === 'fn') {
|
|
99
|
+
const [params, body] = args;
|
|
100
|
+
return {
|
|
101
|
+
__lambda: true,
|
|
102
|
+
params: params.map((p) => (isSymbol(p) ? symName(p) : String(p))),
|
|
103
|
+
body: body,
|
|
104
|
+
closure: env,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// Define: (define name value) or (define (name args...) body)
|
|
108
|
+
if (opName === 'define' || opName === 'defun') {
|
|
109
|
+
const first = args[0];
|
|
110
|
+
if (Array.isArray(first)) {
|
|
111
|
+
// (define (name args...) body) - function definition shorthand
|
|
112
|
+
const [nameExpr, ...paramExprs] = first;
|
|
113
|
+
const name = isSymbol(nameExpr) ? symName(nameExpr) : String(nameExpr);
|
|
114
|
+
const params = paramExprs.map((p) => (isSymbol(p) ? symName(p) : String(p)));
|
|
115
|
+
const body = args[1];
|
|
116
|
+
const fn = {
|
|
117
|
+
__lambda: true,
|
|
118
|
+
params,
|
|
119
|
+
body: body,
|
|
120
|
+
closure: env,
|
|
121
|
+
};
|
|
122
|
+
env[name] = fn;
|
|
123
|
+
return fn;
|
|
124
|
+
}
|
|
125
|
+
// (define name value)
|
|
126
|
+
const name = isSymbol(first) ? symName(first) : String(first);
|
|
127
|
+
const value = evaluate(args[1], env, depth + 1);
|
|
128
|
+
env[name] = value;
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
// Apply: (apply fn list-of-args)
|
|
132
|
+
if (opName === 'apply') {
|
|
133
|
+
const fn = evaluate(args[0], env, depth + 1);
|
|
134
|
+
const fnArgs = evaluate(args[1], env, depth + 1);
|
|
135
|
+
if (isLambda(fn)) {
|
|
136
|
+
const callEnv = { ...fn.closure };
|
|
137
|
+
fn.params.forEach((param, i) => {
|
|
138
|
+
callEnv[param] = fnArgs[i];
|
|
139
|
+
});
|
|
140
|
+
return evaluate(fn.body, callEnv, depth + 1);
|
|
141
|
+
}
|
|
142
|
+
throw new Error(`Cannot apply non-function: ${fn}`);
|
|
143
|
+
}
|
|
144
|
+
// Higher-order functions with inline predicates or lambda
|
|
145
|
+
if (opName === 'filter') {
|
|
146
|
+
const [predExpr, listExpr] = args;
|
|
147
|
+
const pred = evaluate(predExpr, env, depth + 1);
|
|
148
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
149
|
+
if (isLambda(pred)) {
|
|
150
|
+
return list.filter((item) => {
|
|
151
|
+
const callEnv = { ...pred.closure };
|
|
152
|
+
callEnv[pred.params[0]] = item;
|
|
153
|
+
return evaluate(pred.body, callEnv, depth + 1);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// Inline expression form
|
|
157
|
+
return list.filter((item) => {
|
|
158
|
+
const itemEnv = { ...env, '@': item, it: item };
|
|
159
|
+
return evaluate(predExpr, itemEnv, depth + 1);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (opName === 'map') {
|
|
163
|
+
const [mapExpr, listExpr] = args;
|
|
164
|
+
const mapper = evaluate(mapExpr, env, depth + 1);
|
|
165
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
166
|
+
if (isLambda(mapper)) {
|
|
167
|
+
return list.map((item) => {
|
|
168
|
+
const callEnv = { ...mapper.closure };
|
|
169
|
+
callEnv[mapper.params[0]] = item;
|
|
170
|
+
return evaluate(mapper.body, callEnv, depth + 1);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Inline expression form
|
|
174
|
+
return list.map((item) => {
|
|
175
|
+
const itemEnv = { ...env, '@': item, it: item };
|
|
176
|
+
return evaluate(mapExpr, itemEnv, depth + 1);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (opName === 'find') {
|
|
180
|
+
const [listExpr, predExpr] = args;
|
|
181
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
182
|
+
return (list.find((item) => {
|
|
183
|
+
const itemEnv = { ...env, '@': item, it: item };
|
|
184
|
+
return evaluate(predExpr, itemEnv, depth + 1);
|
|
185
|
+
}) ?? null);
|
|
186
|
+
}
|
|
187
|
+
if (opName === 'find-index') {
|
|
188
|
+
const [listExpr, predExpr] = args;
|
|
189
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
190
|
+
return list.findIndex((item) => {
|
|
191
|
+
const itemEnv = { ...env, '@': item, it: item };
|
|
192
|
+
return evaluate(predExpr, itemEnv, depth + 1);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (opName === 'sort-by') {
|
|
196
|
+
const [listExpr, keyExpr] = args;
|
|
197
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
198
|
+
return [...list].sort((a, b) => {
|
|
199
|
+
const aKey = evaluate(keyExpr, { ...env, '@': a, it: a }, depth + 1);
|
|
200
|
+
const bKey = evaluate(keyExpr, { ...env, '@': b, it: b }, depth + 1);
|
|
201
|
+
return aKey - bKey;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (opName === 'count') {
|
|
205
|
+
const [listExpr, predExpr] = args;
|
|
206
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
207
|
+
if (!predExpr)
|
|
208
|
+
return list.length;
|
|
209
|
+
return list.filter((item) => {
|
|
210
|
+
const itemEnv = { ...env, '@': item, it: item };
|
|
211
|
+
return evaluate(predExpr, itemEnv, depth + 1);
|
|
212
|
+
}).length;
|
|
213
|
+
}
|
|
214
|
+
// Reduce: (reduce list init-value (acc item) body) or (reduce list init-value fn)
|
|
215
|
+
if (opName === 'reduce' || opName === 'fold') {
|
|
216
|
+
const [listExpr, initExpr, ...rest] = args;
|
|
217
|
+
const list = evaluate(listExpr, env, depth + 1);
|
|
218
|
+
let acc = evaluate(initExpr, env, depth + 1);
|
|
219
|
+
if (rest.length === 2) {
|
|
220
|
+
// Inline form: (reduce list init (acc item) body)
|
|
221
|
+
const [params, body] = rest;
|
|
222
|
+
const [accExpr, itemExpr] = params;
|
|
223
|
+
const accName = isSymbol(accExpr) ? symName(accExpr) : String(accExpr);
|
|
224
|
+
const itemName = isSymbol(itemExpr) ? symName(itemExpr) : String(itemExpr);
|
|
225
|
+
for (const item of list) {
|
|
226
|
+
const reduceEnv = { ...env, [accName]: acc, [itemName]: item };
|
|
227
|
+
acc = evaluate(body, reduceEnv, depth + 1);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Function form: (reduce list init fn)
|
|
232
|
+
const fn = evaluate(rest[0], env, depth + 1);
|
|
233
|
+
if (isLambda(fn)) {
|
|
234
|
+
for (const item of list) {
|
|
235
|
+
const callEnv = { ...fn.closure };
|
|
236
|
+
callEnv[fn.params[0]] = acc;
|
|
237
|
+
callEnv[fn.params[1]] = item;
|
|
238
|
+
acc = evaluate(fn.body, callEnv, depth + 1);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
throw new Error('reduce requires a function');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return acc;
|
|
246
|
+
}
|
|
247
|
+
// Regular function call or lambda invocation
|
|
248
|
+
// First check if op is a symbol that resolves to a lambda
|
|
249
|
+
const opValue = opName && opName in env ? env[opName] : null;
|
|
250
|
+
if (isLambda(opValue)) {
|
|
251
|
+
// Call user-defined function
|
|
252
|
+
const evaluatedArgs = args.map((arg) => evaluate(arg, env, depth + 1));
|
|
253
|
+
const callEnv = { ...opValue.closure };
|
|
254
|
+
opValue.params.forEach((param, i) => {
|
|
255
|
+
callEnv[param] = evaluatedArgs[i];
|
|
256
|
+
});
|
|
257
|
+
return evaluate(opValue.body, callEnv, depth + 1);
|
|
258
|
+
}
|
|
259
|
+
// Check if it's a primitive function (by symbol name)
|
|
260
|
+
if (opName) {
|
|
261
|
+
const fn = primitives[opName];
|
|
262
|
+
if (fn) {
|
|
263
|
+
const evaluatedArgs = args.map((arg) => evaluate(arg, env, depth + 1));
|
|
264
|
+
const evalFn = (e, newEnv) => evaluate(e, newEnv, depth + 1);
|
|
265
|
+
return fn(evaluatedArgs, env, evalFn);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Maybe op itself is a lambda expression (not a symbol)
|
|
269
|
+
const evaluatedOp = evaluate(op, env, depth + 1);
|
|
270
|
+
if (isLambda(evaluatedOp)) {
|
|
271
|
+
const evaluatedArgs = args.map((arg) => evaluate(arg, env, depth + 1));
|
|
272
|
+
const callEnv = { ...evaluatedOp.closure };
|
|
273
|
+
evaluatedOp.params.forEach((param, i) => {
|
|
274
|
+
callEnv[param] = evaluatedArgs[i];
|
|
275
|
+
});
|
|
276
|
+
return evaluate(evaluatedOp.body, callEnv, depth + 1);
|
|
277
|
+
}
|
|
278
|
+
throw new Error(`Unknown function: ${opName ?? String(op)}`);
|
|
279
|
+
}
|
|
280
|
+
throw new Error(`Cannot evaluate: ${JSON.stringify(expr)}`);
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
evaluate: (expr, env = {}) => evaluate(expr, env),
|
|
284
|
+
evalString: (code, env = {}) => evaluate(parse(code), env),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// Default evaluator instance
|
|
288
|
+
export const defaultEvaluator = createEvaluator();
|
|
289
|
+
/**
|
|
290
|
+
* Evaluate an S-expression AST
|
|
291
|
+
*/
|
|
292
|
+
export const evaluate = defaultEvaluator.evaluate;
|
|
293
|
+
/**
|
|
294
|
+
* Parse and evaluate an S-expression string
|
|
295
|
+
*/
|
|
296
|
+
export const evalString = defaultEvaluator.evalString;
|
|
297
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../src/evaluator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* seval - S-Expression Evaluator
|
|
3
|
+
*
|
|
4
|
+
* A safe, sandboxed S-expression parser and evaluator for TypeScript/JavaScript.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { evalString, createEvaluator } from 'seval'
|
|
9
|
+
*
|
|
10
|
+
* // Simple usage
|
|
11
|
+
* const result = evalString('(+ 1 2 3)') // 6
|
|
12
|
+
*
|
|
13
|
+
* // Custom primitives
|
|
14
|
+
* const evaluator = createEvaluator({
|
|
15
|
+
* primitives: {
|
|
16
|
+
* uuid: () => crypto.randomUUID(),
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
* evaluator.evalString('(uuid)') // "550e8400-e29b-41d4-a716-446655440000"
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export { parse, stringify, isSymbol, sym, symName, type SExpr } from './parser';
|
|
23
|
+
export { tokenize, TokenType, type Token } from './tokenizer';
|
|
24
|
+
export { createEvaluator, evaluate, evalString, defaultEvaluator } from './evaluator';
|
|
25
|
+
export { isLambda, type Value, type Environment, type PrimitiveFunction, type EvaluatorOptions, type LambdaFunction, type EvaluateFn, type ValueArray, type ValueObject, } from './types';
|
|
26
|
+
export { defaultPrimitives, arithmeticPrimitives, comparisonPrimitives, logicalPrimitives, stringPrimitives, arrayPrimitives, objectPrimitives, mathPrimitives, typePrimitives, } from './primitives';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAA;AAG/E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAA;AAG7D,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGrF,OAAO,EACH,QAAQ,EACR,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,WAAW,GACnB,MAAM,SAAS,CAAA;AAGhB,OAAO,EACH,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,GACjB,MAAM,cAAc,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* seval - S-Expression Evaluator
|
|
3
|
+
*
|
|
4
|
+
* A safe, sandboxed S-expression parser and evaluator for TypeScript/JavaScript.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { evalString, createEvaluator } from 'seval'
|
|
9
|
+
*
|
|
10
|
+
* // Simple usage
|
|
11
|
+
* const result = evalString('(+ 1 2 3)') // 6
|
|
12
|
+
*
|
|
13
|
+
* // Custom primitives
|
|
14
|
+
* const evaluator = createEvaluator({
|
|
15
|
+
* primitives: {
|
|
16
|
+
* uuid: () => crypto.randomUUID(),
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
* evaluator.evalString('(uuid)') // "550e8400-e29b-41d4-a716-446655440000"
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
// Parser exports
|
|
23
|
+
export { parse, stringify, isSymbol, sym, symName } from './parser';
|
|
24
|
+
// Tokenizer exports
|
|
25
|
+
export { tokenize, TokenType } from './tokenizer';
|
|
26
|
+
// Evaluator exports
|
|
27
|
+
export { createEvaluator, evaluate, evalString, defaultEvaluator } from './evaluator';
|
|
28
|
+
// Type exports
|
|
29
|
+
export { isLambda, } from './types';
|
|
30
|
+
// Primitives exports
|
|
31
|
+
export { defaultPrimitives, arithmeticPrimitives, comparisonPrimitives, logicalPrimitives, stringPrimitives, arrayPrimitives, objectPrimitives, mathPrimitives, typePrimitives, } from './primitives';
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,iBAAiB;AACjB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAc,MAAM,UAAU,CAAA;AAE/E,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAc,MAAM,aAAa,CAAA;AAE7D,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAErF,eAAe;AACf,OAAO,EACH,QAAQ,GASX,MAAM,SAAS,CAAA;AAEhB,qBAAqB;AACrB,OAAO,EACH,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,GACjB,MAAM,cAAc,CAAA"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-Expression Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses strings like "(+ 1 2)" into nested arrays [Symbol.for('+'), 1, 2]
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Symbols (identifiers) are represented as JS Symbol via Symbol.for(name)
|
|
8
|
+
* - Strings are plain JS strings
|
|
9
|
+
* - This cleanly distinguishes variable references from string literals
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* S-Expression AST type
|
|
13
|
+
* - symbol: variable reference (looked up in environment)
|
|
14
|
+
* - string: string literal (used as-is)
|
|
15
|
+
* - number/boolean: primitive values
|
|
16
|
+
* - array: list/function call
|
|
17
|
+
*/
|
|
18
|
+
export type SExpr = symbol | string | number | boolean | null | SExpr[];
|
|
19
|
+
/**
|
|
20
|
+
* Check if a value is a symbol (variable reference)
|
|
21
|
+
*/
|
|
22
|
+
export declare function isSymbol(value: unknown): value is symbol;
|
|
23
|
+
/**
|
|
24
|
+
* Create a symbol from a name
|
|
25
|
+
*/
|
|
26
|
+
export declare function sym(name: string): symbol;
|
|
27
|
+
/**
|
|
28
|
+
* Get the name from a symbol
|
|
29
|
+
*/
|
|
30
|
+
export declare function symName(s: symbol): string;
|
|
31
|
+
/**
|
|
32
|
+
* Parse S-expression string into AST
|
|
33
|
+
*/
|
|
34
|
+
export declare function parse(input: string): SExpr;
|
|
35
|
+
/**
|
|
36
|
+
* Convert S-expression AST back to string
|
|
37
|
+
*/
|
|
38
|
+
export declare function stringify(expr: SExpr): string;
|
|
39
|
+
export declare const STRING_LITERAL_PREFIX = "\0STR:";
|
|
40
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,EAAE,CAAA;AAEvE;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExC;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAiG1C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAgB7C;AAGD,eAAO,MAAM,qBAAqB,WAAW,CAAA"}
|