summaryrefslogtreecommitdiff
path: root/src/lang
diff options
context:
space:
mode:
Diffstat (limited to 'src/lang')
-rw-r--r--src/lang/js-lang/builtin/sbuiltin.ts25
-rw-r--r--src/lang/ts-lang/builtin/sbuiltin.ts28
-rw-r--r--src/lang/ts-lang/core/eval.ts3
3 files changed, 56 insertions, 0 deletions
diff --git a/src/lang/js-lang/builtin/sbuiltin.ts b/src/lang/js-lang/builtin/sbuiltin.ts
index 013854c..7d9b851 100644
--- a/src/lang/js-lang/builtin/sbuiltin.ts
+++ b/src/lang/js-lang/builtin/sbuiltin.ts
@@ -40,6 +40,30 @@ export const V_SBUILTIN_Map: SBUILTIN = (node, frame) => {
return values.map((v, i) => callFn(fn, [v, i], frame));
};
+export const V_SBUILTIN_Reduce: SBUILTIN = (node, frame) => {
+ const children = getEvaluatedChildren(node, frame);
+ const fn = children[1] as FnPrim | undefined;
+ const acc = children[2];
+
+ if (!fn?.fn) {
+ throw new Error(
+ `Invalid params for reduce: ${JSON.stringify(children, undefined, 2)}`
+ );
+ }
+
+ const values = children[0];
+
+ if (!Array.isArray(values)) {
+ // add to ts
+ throw new Error(`Can't reduce non-array value: ${values}`);
+ }
+
+ return values.reduce(
+ (acc, cur, idx) => callFn(fn, [acc, cur, idx], frame),
+ acc
+ );
+};
+
export const V_SBUILTIN_IfElse: SBUILTIN = (node, frame) => {
const children = node.children;
@@ -59,5 +83,6 @@ export const V_SBUILTIN_IfElse: SBUILTIN = (node, frame) => {
export const nameToSBUILTIN: Record<string, SBUILTIN> = {
call: V_SBUILTIN_Call,
map: V_SBUILTIN_Map,
+ reduce: V_SBUILTIN_Reduce,
"?": V_SBUILTIN_IfElse,
};
diff --git a/src/lang/ts-lang/builtin/sbuiltin.ts b/src/lang/ts-lang/builtin/sbuiltin.ts
index c92fd6a..38b4256 100644
--- a/src/lang/ts-lang/builtin/sbuiltin.ts
+++ b/src/lang/ts-lang/builtin/sbuiltin.ts
@@ -42,6 +42,34 @@ export type SBUILTIN_Map<
GetEvaluatedChildren<Node, Frame, Callstack>
>}`>;
+type Reduce<
+ Arr extends readonly any[],
+ Fn extends FnPrim,
+ Acc,
+ IdxLen extends readonly any[] = readonly []
+> = Arr extends [infer Head, ...infer Tail]
+ ? Reduce<
+ Tail,
+ Fn,
+ CallFn<Fn, [Acc, Head, IdxLen["length"]]>,
+ [...IdxLen, any]
+ >
+ : Acc;
+
+export type SBUILTIN_Reduce<
+ Node extends ASTNode,
+ Frame extends StackFrame,
+ Callstack extends readonly string[]
+> = GetEvaluatedChildren<Node, Frame, Callstack> extends [
+ infer Arr extends readonly any[],
+ infer Fn extends FnPrim,
+ infer Acc
+]
+ ? Reduce<Arr, Fn, Acc>
+ : EvalError<`Invalid params for reduce: ${ToString<
+ GetEvaluatedChildren<Node, Frame, Callstack>
+ >}`>;
+
export type SBUILTIN_IfElse<
Node extends ASTNode,
Frame extends StackFrame,
diff --git a/src/lang/ts-lang/core/eval.ts b/src/lang/ts-lang/core/eval.ts
index ebc58e7..bef0ef8 100644
--- a/src/lang/ts-lang/core/eval.ts
+++ b/src/lang/ts-lang/core/eval.ts
@@ -8,6 +8,7 @@ import {
SBUILTIN_Call,
SBUILTIN_IfElse,
SBUILTIN_Map,
+ SBUILTIN_Reduce,
} from "../builtin";
import { ToString } from "../util";
import {
@@ -34,6 +35,8 @@ export type MapBuiltins<
? SBUILTIN_Call<Node, Frame, Callstack>
: Node["name"] extends "map"
? SBUILTIN_Map<Node, Frame, Callstack>
+ : Node["name"] extends "reduce"
+ ? SBUILTIN_Reduce<Node, Frame, Callstack>
: Node["name"] extends "?"
? SBUILTIN_IfElse<Node, Frame, Callstack>
: Node["name"] extends "tostring"