@trebco/treb 32.1.1 → 32.3.3
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/dist/treb-spreadsheet.mjs +15 -15
- package/package.json +1 -1
- package/treb-base-types/src/style.ts +20 -0
- package/treb-calculator/src/calculator.ts +2 -0
- package/treb-calculator/src/descriptors.ts +7 -1
- package/treb-calculator/src/expression-calculator.ts +139 -54
- package/treb-calculator/src/functions/base-functions.ts +1 -0
- package/treb-calculator/src/functions/fp.ts +360 -0
- package/treb-calculator/src/functions/gamma.ts +164 -0
- package/treb-calculator/src/functions/lambda-functions.ts +20 -0
- package/treb-calculator/src/functions/statistics-functions.ts +88 -0
- package/treb-data-model/src/sheet.ts +2 -2
- package/treb-embed/src/embedded-spreadsheet.ts +14 -2
- package/treb-export/src/xml-test.ts +47 -0
- package/treb-grid/src/editors/editor.ts +14 -0
- package/treb-grid/src/types/grid.ts +70 -25
- package/treb-parser/package.json +1 -1
- package/treb-parser/src/parser-types.ts +3 -0
- package/treb-parser/src/parser.ts +33 -7
- package/treb-calculator/tsconfig.json +0 -7
package/package.json
CHANGED
|
@@ -318,6 +318,26 @@ export const Style = {
|
|
|
318
318
|
};
|
|
319
319
|
},
|
|
320
320
|
|
|
321
|
+
Serialize: (style: CellStyle): string => {
|
|
322
|
+
const clone: CellStyle = JSON.parse(JSON.stringify(style));
|
|
323
|
+
|
|
324
|
+
// scrub border colors without widths
|
|
325
|
+
if (clone.border_bottom_fill && !clone.border_bottom) {
|
|
326
|
+
clone.border_bottom_fill = undefined;
|
|
327
|
+
}
|
|
328
|
+
if (clone.border_top_fill && !clone.border_top) {
|
|
329
|
+
clone.border_top_fill = undefined;
|
|
330
|
+
}
|
|
331
|
+
if (clone.border_left_fill && !clone.border_left) {
|
|
332
|
+
clone.border_left_fill = undefined;
|
|
333
|
+
}
|
|
334
|
+
if (clone.border_right_fill && !clone.border_right) {
|
|
335
|
+
clone.border_right_fill = undefined;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return JSON.stringify(clone);
|
|
339
|
+
},
|
|
340
|
+
|
|
321
341
|
/**
|
|
322
342
|
* merge. returns a new object, does not update dest in place.
|
|
323
343
|
* NOTE: if it does not update dest in place, then what would be
|
|
@@ -48,6 +48,7 @@ import { ComplexFunctionLibrary } from './functions/complex-functions';
|
|
|
48
48
|
import { MatrixFunctionLibrary } from './functions/matrix-functions';
|
|
49
49
|
import { RegexFunctionLibrary } from './functions/regex-functions';
|
|
50
50
|
import { LambdaFunctionLibrary } from './functions/lambda-functions';
|
|
51
|
+
import { FPFunctionLibrary } from './functions/fp';
|
|
51
52
|
|
|
52
53
|
import { Variance } from './functions/statistics-functions';
|
|
53
54
|
|
|
@@ -242,6 +243,7 @@ export class Calculator extends Graph {
|
|
|
242
243
|
MatrixFunctionLibrary,
|
|
243
244
|
RegexFunctionLibrary,
|
|
244
245
|
LambdaFunctionLibrary,
|
|
246
|
+
FPFunctionLibrary,
|
|
245
247
|
);
|
|
246
248
|
|
|
247
249
|
// aliases
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { RenderFunction, ClickFunction, UnionValue, ICellAddress, IArea } from 'treb-base-types';
|
|
22
|
+
import type { RenderFunction, ClickFunction, UnionValue, ICellAddress, IArea, FunctionUnion } from 'treb-base-types';
|
|
23
23
|
import type { ExpressionUnit } from 'treb-parser';
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -28,6 +28,9 @@ import type { ExpressionUnit } from 'treb-parser';
|
|
|
28
28
|
export interface FunctionContext {
|
|
29
29
|
address: ICellAddress;
|
|
30
30
|
area?: IArea;
|
|
31
|
+
|
|
32
|
+
/** application function for fp functions */
|
|
33
|
+
apply?: (fn: FunctionUnion, args: UnionValue[]) => UnionValue;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
// FIXME: at least some of this could move to base types
|
|
@@ -235,6 +238,9 @@ export interface CompositeFunctionDescriptor {
|
|
|
235
238
|
descriptors: ArgumentDescriptor[];
|
|
236
239
|
}) => ContextResult | undefined;
|
|
237
240
|
|
|
241
|
+
/** flag indicating this function needs fp support */
|
|
242
|
+
fp?: boolean;
|
|
243
|
+
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
export interface FunctionMap {
|
|
@@ -27,11 +27,13 @@ import type { Cell, ICellAddress,
|
|
|
27
27
|
UndefinedUnion,
|
|
28
28
|
ComplexUnion,
|
|
29
29
|
DimensionedQuantityUnion,
|
|
30
|
-
IArea
|
|
30
|
+
IArea,
|
|
31
|
+
FunctionUnion} from 'treb-base-types';
|
|
31
32
|
import { ValueType, GetValueType, Area } from 'treb-base-types';
|
|
32
33
|
import type { Parser, ExpressionUnit, UnitBinary, UnitIdentifier,
|
|
33
34
|
UnitGroup, UnitUnary, UnitAddress, UnitRange, UnitCall, UnitDimensionedQuantity, UnitStructuredReference,
|
|
34
|
-
UnitImplicitCall
|
|
35
|
+
UnitImplicitCall,
|
|
36
|
+
UnitArray} from 'treb-parser';
|
|
35
37
|
import type { DataModel, MacroFunction, Sheet } from 'treb-data-model';
|
|
36
38
|
import { NameError, ReferenceError, ExpressionError, UnknownError, SpillError, ValueError, ArgumentError } from './function-error';
|
|
37
39
|
|
|
@@ -448,6 +450,133 @@ export class ExpressionCalculator {
|
|
|
448
450
|
|
|
449
451
|
}
|
|
450
452
|
|
|
453
|
+
/**
|
|
454
|
+
* split out from ImplicitCall so we can reuse
|
|
455
|
+
*/
|
|
456
|
+
public ImplicitCallTail(result: FunctionUnion, args: ExpressionUnit[]) {
|
|
457
|
+
|
|
458
|
+
const value = result.value as {
|
|
459
|
+
bindings: ExpressionUnit[];
|
|
460
|
+
func: ExpressionUnit|undefined;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
if (!value.func || !value.bindings) {
|
|
464
|
+
return ExpressionError();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// let frame = value.bindings(expr.args);
|
|
468
|
+
|
|
469
|
+
const frame: BindingFrame = {};
|
|
470
|
+
|
|
471
|
+
for (let i = 0; i < value.bindings.length; i++) {
|
|
472
|
+
const name = value.bindings[i];
|
|
473
|
+
if (name?.type === 'identifier') {
|
|
474
|
+
frame[name.name.toUpperCase()] = args[i] || { type: 'missing' };
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
// should not happen, error
|
|
478
|
+
return ExpressionError();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// frame = this.NormalizeBindings(frame); // inline
|
|
483
|
+
|
|
484
|
+
const munged = JSON.parse(JSON.stringify(value.func));
|
|
485
|
+
|
|
486
|
+
this.parser.Walk2(munged, (unit: ExpressionUnit) => {
|
|
487
|
+
if (unit.type === 'identifier') {
|
|
488
|
+
const upper_case = unit.name.toUpperCase();
|
|
489
|
+
const binding = frame[upper_case];
|
|
490
|
+
if (binding) {
|
|
491
|
+
return JSON.parse(JSON.stringify(binding));
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return true;
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// console.info({frame, func, munged});
|
|
498
|
+
|
|
499
|
+
// const exec_result = this.CalculateExpression(munged as ExtendedExpressionUnit);
|
|
500
|
+
// return exec_result || ExpressionError();
|
|
501
|
+
|
|
502
|
+
return this.CalculateExpression(munged as ExtendedExpressionUnit);
|
|
503
|
+
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* an FP call will need to set bindings and call an expression,
|
|
508
|
+
* possibly multiple times. this is a support function for that.
|
|
509
|
+
*/
|
|
510
|
+
protected Apply(fn: FunctionUnion, args: UnionValue[]) {
|
|
511
|
+
|
|
512
|
+
// kind of going backwards here, converting values to expressions...
|
|
513
|
+
// the reason is that we rewrite lambdas to support recursion
|
|
514
|
+
|
|
515
|
+
const mapped: ExpressionUnit[] = args.map(arg => {
|
|
516
|
+
switch (arg.type) {
|
|
517
|
+
case ValueType.number:
|
|
518
|
+
case ValueType.boolean:
|
|
519
|
+
case ValueType.string:
|
|
520
|
+
return {
|
|
521
|
+
type: 'literal', value: arg.value, id: 0, position: 0,
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
case ValueType.error:
|
|
525
|
+
return {
|
|
526
|
+
type: 'literal', value: '#' + arg.value, id: 0, position: 0,
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
case ValueType.array:
|
|
530
|
+
{
|
|
531
|
+
const values: UnitArray['values'] = [];
|
|
532
|
+
for (let c = 0; c < arg.value.length; c++) {
|
|
533
|
+
const col = arg.value[c];
|
|
534
|
+
const mapped_col: UnitArray['values'][0] = [];
|
|
535
|
+
for (let r = 0; r < col.length; r++ ) {
|
|
536
|
+
const val = col[r];
|
|
537
|
+
switch (val.type) {
|
|
538
|
+
case ValueType.boolean:
|
|
539
|
+
case ValueType.number:
|
|
540
|
+
case ValueType.string:
|
|
541
|
+
mapped_col.push(val.value || undefined);
|
|
542
|
+
break;
|
|
543
|
+
default:
|
|
544
|
+
console.warn('unhandled array value', val);
|
|
545
|
+
mapped_col.push(undefined);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
values.push(mapped_col);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return {
|
|
552
|
+
type: 'array',
|
|
553
|
+
values,
|
|
554
|
+
id: 0, position: 0,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
case ValueType.undefined:
|
|
559
|
+
return {
|
|
560
|
+
type: 'missing', id: 0,
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
default:
|
|
564
|
+
|
|
565
|
+
// this (logging) is a problem in a simulation because
|
|
566
|
+
// it can bog down. we probably should only log once.
|
|
567
|
+
// or perhaps not at all?
|
|
568
|
+
|
|
569
|
+
console.warn('unhandled parameter value', arg);
|
|
570
|
+
|
|
571
|
+
}
|
|
572
|
+
return { type: 'missing', id: 0 };
|
|
573
|
+
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
return this.ImplicitCallTail(fn, mapped);
|
|
577
|
+
|
|
578
|
+
}
|
|
579
|
+
|
|
451
580
|
/**
|
|
452
581
|
* this method can take a `call` type if it looked like a call at
|
|
453
582
|
* the parsing stage, it's a simple translation between the two
|
|
@@ -473,53 +602,7 @@ export class ExpressionCalculator {
|
|
|
473
602
|
const result = this.CalculateExpression(expr.call as ExtendedExpressionUnit);
|
|
474
603
|
|
|
475
604
|
if (result.type === ValueType.function) {
|
|
476
|
-
|
|
477
|
-
const value = result.value as {
|
|
478
|
-
bindings: ExpressionUnit[];
|
|
479
|
-
func: ExpressionUnit|undefined;
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
if (!value.func || !value.bindings) {
|
|
483
|
-
return ExpressionError();
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// let frame = value.bindings(expr.args);
|
|
487
|
-
|
|
488
|
-
const frame: BindingFrame = {};
|
|
489
|
-
|
|
490
|
-
for (let i = 0; i < value.bindings.length; i++) {
|
|
491
|
-
const name = value.bindings[i];
|
|
492
|
-
if (name?.type === 'identifier') {
|
|
493
|
-
frame[name.name.toUpperCase()] = expr.args[i] || { type: 'missing' };
|
|
494
|
-
}
|
|
495
|
-
else {
|
|
496
|
-
// should not happen, error
|
|
497
|
-
return ExpressionError();
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// frame = this.NormalizeBindings(frame); // inline
|
|
502
|
-
|
|
503
|
-
const munged = JSON.parse(JSON.stringify(value.func));
|
|
504
|
-
|
|
505
|
-
this.parser.Walk2(munged, (unit: ExpressionUnit) => {
|
|
506
|
-
if (unit.type === 'identifier') {
|
|
507
|
-
const upper_case = unit.name.toUpperCase();
|
|
508
|
-
const binding = frame[upper_case];
|
|
509
|
-
if (binding) {
|
|
510
|
-
return JSON.parse(JSON.stringify(binding));
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return true;
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
// console.info({frame, func, munged});
|
|
517
|
-
|
|
518
|
-
// const exec_result = this.CalculateExpression(munged as ExtendedExpressionUnit);
|
|
519
|
-
// return exec_result || ExpressionError();
|
|
520
|
-
|
|
521
|
-
return this.CalculateExpression(munged as ExtendedExpressionUnit);
|
|
522
|
-
|
|
605
|
+
return this.ImplicitCallTail(result, expr.args)
|
|
523
606
|
}
|
|
524
607
|
|
|
525
608
|
return ExpressionError();
|
|
@@ -721,11 +804,12 @@ export class ExpressionCalculator {
|
|
|
721
804
|
start: { ...this.context.area.start, },
|
|
722
805
|
end: { ...this.context.area.end, },
|
|
723
806
|
} : undefined,
|
|
807
|
+
apply: func.fp ? this.Apply.bind(this) : undefined,
|
|
724
808
|
};
|
|
725
809
|
|
|
726
|
-
|
|
810
|
+
const result = func.fn.apply(ctx, mapped_args);
|
|
727
811
|
|
|
728
|
-
|
|
812
|
+
if (func.return_type === 'reference') {
|
|
729
813
|
|
|
730
814
|
if (return_reference) {
|
|
731
815
|
return result;
|
|
@@ -744,7 +828,7 @@ export class ExpressionCalculator {
|
|
|
744
828
|
|
|
745
829
|
}
|
|
746
830
|
|
|
747
|
-
return func.fn.apply(ctx, mapped_args);
|
|
831
|
+
return result; // func.fn.apply(ctx, mapped_args);
|
|
748
832
|
|
|
749
833
|
};
|
|
750
834
|
|
|
@@ -1162,11 +1246,11 @@ export class ExpressionCalculator {
|
|
|
1162
1246
|
|
|
1163
1247
|
switch (upper_case){
|
|
1164
1248
|
case 'FALSE':
|
|
1165
|
-
case 'F':
|
|
1249
|
+
// case 'F':
|
|
1166
1250
|
return () => {return {value: false, type: ValueType.boolean}};
|
|
1167
1251
|
|
|
1168
1252
|
case 'TRUE':
|
|
1169
|
-
case 'T':
|
|
1253
|
+
// case 'T':
|
|
1170
1254
|
return () => {return {value: true, type: ValueType.boolean}};
|
|
1171
1255
|
|
|
1172
1256
|
case 'UNDEFINED':
|
|
@@ -1215,6 +1299,7 @@ export class ExpressionCalculator {
|
|
|
1215
1299
|
return value;
|
|
1216
1300
|
}
|
|
1217
1301
|
}
|
|
1302
|
+
|
|
1218
1303
|
return undefined;
|
|
1219
1304
|
}
|
|
1220
1305
|
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of TREB.
|
|
3
|
+
*
|
|
4
|
+
* TREB is free software: you can redistribute it and/or modify it under the
|
|
5
|
+
* terms of the GNU General Public License as published by the Free Software
|
|
6
|
+
* Foundation, either version 3 of the License, or (at your option) any
|
|
7
|
+
* later version.
|
|
8
|
+
*
|
|
9
|
+
* TREB is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
10
|
+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
12
|
+
* details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License along
|
|
15
|
+
* with TREB. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
17
|
+
* Copyright 2022-2024 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { FunctionMap } from '../descriptors';
|
|
23
|
+
import type { FunctionUnion, UnionValue} from 'treb-base-types';
|
|
24
|
+
import { ValueType } from 'treb-base-types';
|
|
25
|
+
import { ArgumentError, ValueError } from '../function-error';
|
|
26
|
+
|
|
27
|
+
export const FPFunctionLibrary: FunctionMap = {
|
|
28
|
+
|
|
29
|
+
MakeArray: {
|
|
30
|
+
description: 'Create an array using a function',
|
|
31
|
+
arguments: [
|
|
32
|
+
{ name: 'rows' },
|
|
33
|
+
{ name: 'columns' },
|
|
34
|
+
{
|
|
35
|
+
name: 'lambda',
|
|
36
|
+
description: 'Function to apply',
|
|
37
|
+
boxed: true,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
fp: true,
|
|
41
|
+
fn: function(rows: number, columns: number, lambda: FunctionUnion) {
|
|
42
|
+
if (rows > 0 && columns > 0 && lambda?.type === ValueType.function) {
|
|
43
|
+
const apply = this?.apply;
|
|
44
|
+
if (!apply) {
|
|
45
|
+
return ValueError();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const value: UnionValue[][] = [];
|
|
49
|
+
for (let c = 0; c < columns; c++) {
|
|
50
|
+
const values_col: UnionValue[] = [];
|
|
51
|
+
for (let r = 0; r < rows; r++) {
|
|
52
|
+
values_col.push(apply(lambda, [
|
|
53
|
+
{ type: ValueType.number, value: r + 1 },
|
|
54
|
+
{ type: ValueType.number, value: c + 1 },
|
|
55
|
+
]));
|
|
56
|
+
}
|
|
57
|
+
value.push(values_col);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
type: ValueType.array,
|
|
62
|
+
value,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
return ArgumentError();
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
Reduce: {
|
|
71
|
+
description: 'Accumulates a value by applying a function to a set of values',
|
|
72
|
+
arguments: [
|
|
73
|
+
{
|
|
74
|
+
name: 'initial value',
|
|
75
|
+
boxed: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'data',
|
|
79
|
+
description: 'Input data',
|
|
80
|
+
boxed: true,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'lambda',
|
|
84
|
+
description: 'Function to apply',
|
|
85
|
+
boxed: true,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
fp: true,
|
|
89
|
+
fn: function(initial: UnionValue, data: UnionValue, lambda: FunctionUnion) {
|
|
90
|
+
|
|
91
|
+
if (!this?.apply) {
|
|
92
|
+
return ValueError();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (lambda.type !== ValueType.function) {
|
|
96
|
+
return ArgumentError();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (data.type !== ValueType.array) {
|
|
100
|
+
data = {
|
|
101
|
+
type: ValueType.array,
|
|
102
|
+
value: [[data]],
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const cols = data.value.length;
|
|
107
|
+
const rows = data.value[0].length;
|
|
108
|
+
|
|
109
|
+
for (let r = 0; r < rows; r++) {
|
|
110
|
+
for (let c = 0; c < cols; c++) {
|
|
111
|
+
const apply_args: UnionValue[] = [initial, data.value[c][r]];
|
|
112
|
+
const result = this.apply(lambda, apply_args)
|
|
113
|
+
initial = result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return initial;
|
|
118
|
+
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
Scan: {
|
|
123
|
+
description: 'Applies a function to a set of values, iteratively',
|
|
124
|
+
arguments: [
|
|
125
|
+
{
|
|
126
|
+
name: 'initial value',
|
|
127
|
+
boxed: true,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'data',
|
|
131
|
+
description: 'Input data',
|
|
132
|
+
boxed: true,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'lambda',
|
|
136
|
+
description: 'Function to apply',
|
|
137
|
+
boxed: true,
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
fp: true,
|
|
141
|
+
fn: function(initial: UnionValue, data: UnionValue, lambda: FunctionUnion) {
|
|
142
|
+
|
|
143
|
+
if (!this?.apply) {
|
|
144
|
+
return ValueError();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (lambda.type !== ValueType.function) {
|
|
148
|
+
return ArgumentError();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (data.type !== ValueType.array) {
|
|
152
|
+
data = {
|
|
153
|
+
type: ValueType.array,
|
|
154
|
+
value: [[data]],
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const results: UnionValue[][] = [];
|
|
159
|
+
const cols = data.value.length;
|
|
160
|
+
const rows = data.value[0].length;
|
|
161
|
+
|
|
162
|
+
for (let i = 0; i < cols; i++) { results.push([])}
|
|
163
|
+
|
|
164
|
+
for (let r = 0; r < rows; r++) {
|
|
165
|
+
for (let c = 0; c < cols; c++) {
|
|
166
|
+
const apply_args: UnionValue[] = [initial, data.value[c][r]];
|
|
167
|
+
const result = this.apply(lambda, apply_args)
|
|
168
|
+
results[c][r] = result;
|
|
169
|
+
initial = result;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
type: ValueType.array,
|
|
175
|
+
value: results,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
ByRow: {
|
|
182
|
+
description: 'Apply a function to each row in an array',
|
|
183
|
+
arguments: [
|
|
184
|
+
{
|
|
185
|
+
name: 'data',
|
|
186
|
+
description: 'Input data',
|
|
187
|
+
repeat: true,
|
|
188
|
+
boxed: true,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'lambda',
|
|
192
|
+
description: 'Function to apply',
|
|
193
|
+
boxed: true,
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
fp: true,
|
|
197
|
+
fn: function(data: UnionValue, lambda: FunctionUnion) {
|
|
198
|
+
if (!this?.apply) { return ValueError(); }
|
|
199
|
+
|
|
200
|
+
if (lambda.type !== ValueType.function) {
|
|
201
|
+
return ArgumentError();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (data.type !== ValueType.array) {
|
|
205
|
+
data = {
|
|
206
|
+
type: ValueType.array,
|
|
207
|
+
value: [[data]],
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const cols = data.value.length;
|
|
212
|
+
const rows = data.value[0].length;
|
|
213
|
+
|
|
214
|
+
const value: UnionValue[][] = [[]];
|
|
215
|
+
for (let r = 0; r < rows; r++) {
|
|
216
|
+
const args: UnionValue[] = [];
|
|
217
|
+
for (let c = 0; c < cols; c++) {
|
|
218
|
+
args.push(data.value[c][r]);
|
|
219
|
+
}
|
|
220
|
+
value[0].push(this.apply(lambda, [{
|
|
221
|
+
type: ValueType.array, value: [args],
|
|
222
|
+
}]));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
type: ValueType.array,
|
|
227
|
+
value,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
ByCol: {
|
|
235
|
+
description: 'Apply a function to each column in an array',
|
|
236
|
+
arguments: [
|
|
237
|
+
{
|
|
238
|
+
name: 'data',
|
|
239
|
+
description: 'Input data',
|
|
240
|
+
repeat: true,
|
|
241
|
+
boxed: true,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: 'lambda',
|
|
245
|
+
description: 'Function to apply',
|
|
246
|
+
boxed: true,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
fp: true,
|
|
250
|
+
fn: function(data: UnionValue, lambda: FunctionUnion) {
|
|
251
|
+
if (!this?.apply) { return ValueError(); }
|
|
252
|
+
|
|
253
|
+
if (lambda.type !== ValueType.function) {
|
|
254
|
+
return ArgumentError();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (data.type !== ValueType.array) {
|
|
258
|
+
data = {
|
|
259
|
+
type: ValueType.array,
|
|
260
|
+
value: [[data]],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const cols = data.value.length;
|
|
265
|
+
const rows = data.value[0].length;
|
|
266
|
+
|
|
267
|
+
const value: UnionValue[][] = [];
|
|
268
|
+
for (let c = 0; c < cols; c++) {
|
|
269
|
+
const args: UnionValue[] = [];
|
|
270
|
+
for (let r = 0; r < rows; r++) {
|
|
271
|
+
args.push(data.value[c][r]);
|
|
272
|
+
}
|
|
273
|
+
value.push([this.apply(lambda, [{
|
|
274
|
+
type: ValueType.array, value: [args],
|
|
275
|
+
}])]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
type: ValueType.array,
|
|
280
|
+
value,
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
Map: {
|
|
287
|
+
description: 'Apply a function to a set of values',
|
|
288
|
+
arguments: [
|
|
289
|
+
{
|
|
290
|
+
name: 'data',
|
|
291
|
+
description: 'Input data',
|
|
292
|
+
repeat: true,
|
|
293
|
+
boxed: true,
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: 'lambda',
|
|
297
|
+
description: 'Function to apply',
|
|
298
|
+
boxed: true,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
|
|
302
|
+
fp: true,
|
|
303
|
+
fn: function(...args: UnionValue[]) {
|
|
304
|
+
|
|
305
|
+
if (args.length < 2) {
|
|
306
|
+
return ArgumentError();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const lambda = args[args.length - 1];
|
|
310
|
+
if (lambda.type !== ValueType.function) {
|
|
311
|
+
return ArgumentError();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const apply = this?.apply;
|
|
315
|
+
if (!apply) {
|
|
316
|
+
return ValueError();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
for (let i = 0; i < args.length - 1; i++) {
|
|
320
|
+
const arg = args[i];
|
|
321
|
+
if (arg.type !== ValueType.array) {
|
|
322
|
+
args[i] = {
|
|
323
|
+
type: ValueType.array,
|
|
324
|
+
value: [[arg]],
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const key = args[0];
|
|
330
|
+
const results: UnionValue[][] = [];
|
|
331
|
+
if (key.type === ValueType.array) {
|
|
332
|
+
for (let r = 0; r < key.value.length; r++) {
|
|
333
|
+
const row = key.value[r];
|
|
334
|
+
const results_row: UnionValue[] = [];
|
|
335
|
+
for (let c = 0; c < row.length; c++) {
|
|
336
|
+
const apply_args: UnionValue[] = [row[c]];
|
|
337
|
+
|
|
338
|
+
for (let i = 1; i < args.length - 1; i++) {
|
|
339
|
+
const arg = args[i];
|
|
340
|
+
if (arg.type === ValueType.array) {
|
|
341
|
+
apply_args.push(arg.value[r][c])
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
results_row.push(apply(lambda, apply_args));
|
|
346
|
+
}
|
|
347
|
+
results.push(results_row);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
type: ValueType.array,
|
|
353
|
+
value: results,
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
};
|