@trebco/treb 23.6.5 → 25.0.0-rc2
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/.eslintignore +8 -0
- package/.eslintrc.js +164 -0
- package/README-shadow-DOM.md +88 -0
- package/README.md +37 -130
- package/api-config.json +29 -0
- package/api-generator/api-generator-types.ts +82 -0
- package/api-generator/api-generator.ts +1172 -0
- package/api-generator/package.json +3 -0
- package/build/treb-spreadsheet.mjs +14 -0
- package/{treb.d.ts → build/treb.d.ts} +323 -271
- package/esbuild-custom-element.mjs +336 -0
- package/esbuild.js +305 -0
- package/package.json +49 -14
- package/treb-base-types/package.json +5 -0
- package/treb-base-types/src/api_types.ts +36 -0
- package/treb-base-types/src/area.ts +583 -0
- package/treb-base-types/src/basic_types.ts +45 -0
- package/treb-base-types/src/cell.ts +612 -0
- package/treb-base-types/src/cells.ts +1066 -0
- package/treb-base-types/src/color.ts +124 -0
- package/treb-base-types/src/import.ts +71 -0
- package/treb-base-types/src/index-standalone.ts +29 -0
- package/treb-base-types/src/index.ts +42 -0
- package/treb-base-types/src/layout.ts +47 -0
- package/treb-base-types/src/localization.ts +187 -0
- package/treb-base-types/src/rectangle.ts +145 -0
- package/treb-base-types/src/render_text.ts +72 -0
- package/treb-base-types/src/style.ts +545 -0
- package/treb-base-types/src/table.ts +109 -0
- package/treb-base-types/src/text_part.ts +54 -0
- package/treb-base-types/src/theme.ts +608 -0
- package/treb-base-types/src/union.ts +152 -0
- package/treb-base-types/src/value-type.ts +164 -0
- package/treb-base-types/style/resizable.css +59 -0
- package/treb-calculator/modern.tsconfig.json +11 -0
- package/treb-calculator/package.json +5 -0
- package/treb-calculator/src/calculator.ts +2546 -0
- package/treb-calculator/src/complex-math.ts +558 -0
- package/treb-calculator/src/dag/array-vertex.ts +198 -0
- package/treb-calculator/src/dag/graph.ts +951 -0
- package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
- package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
- package/treb-calculator/src/dag/vertex.ts +352 -0
- package/treb-calculator/src/descriptors.ts +162 -0
- package/treb-calculator/src/expression-calculator.ts +1069 -0
- package/treb-calculator/src/function-error.ts +103 -0
- package/treb-calculator/src/function-library.ts +103 -0
- package/treb-calculator/src/functions/base-functions.ts +1214 -0
- package/treb-calculator/src/functions/checkbox.ts +164 -0
- package/treb-calculator/src/functions/complex-functions.ts +253 -0
- package/treb-calculator/src/functions/finance-functions.ts +399 -0
- package/treb-calculator/src/functions/information-functions.ts +102 -0
- package/treb-calculator/src/functions/matrix-functions.ts +182 -0
- package/treb-calculator/src/functions/sparkline.ts +335 -0
- package/treb-calculator/src/functions/statistics-functions.ts +350 -0
- package/treb-calculator/src/functions/text-functions.ts +298 -0
- package/treb-calculator/src/index.ts +27 -0
- package/treb-calculator/src/notifier-types.ts +59 -0
- package/treb-calculator/src/primitives.ts +428 -0
- package/treb-calculator/src/utilities.ts +305 -0
- package/treb-charts/package.json +5 -0
- package/treb-charts/src/chart-functions.ts +156 -0
- package/treb-charts/src/chart-types.ts +230 -0
- package/treb-charts/src/chart.ts +1288 -0
- package/treb-charts/src/index.ts +24 -0
- package/treb-charts/src/main.ts +37 -0
- package/treb-charts/src/rectangle.ts +52 -0
- package/treb-charts/src/renderer.ts +1841 -0
- package/treb-charts/src/util.ts +122 -0
- package/treb-charts/style/charts.scss +221 -0
- package/treb-charts/style/old-charts.scss +250 -0
- package/treb-embed/markup/layout.html +137 -0
- package/treb-embed/markup/toolbar.html +175 -0
- package/treb-embed/modern.tsconfig.json +25 -0
- package/treb-embed/src/custom-element/content-types.d.ts +18 -0
- package/treb-embed/src/custom-element/global.d.ts +11 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1228 -0
- package/treb-embed/src/custom-element/treb-global.ts +44 -0
- package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
- package/treb-embed/src/embedded-spreadsheet.ts +5358 -0
- package/treb-embed/src/index.ts +16 -0
- package/treb-embed/src/language-model.ts +41 -0
- package/treb-embed/src/options.ts +298 -0
- package/treb-embed/src/progress-dialog.ts +228 -0
- package/treb-embed/src/selection-state.ts +16 -0
- package/treb-embed/src/spinner.ts +42 -0
- package/treb-embed/src/toolbar-message.ts +96 -0
- package/treb-embed/src/types.ts +167 -0
- package/treb-embed/style/autocomplete.scss +103 -0
- package/treb-embed/style/dark-theme.scss +114 -0
- package/treb-embed/style/defaults.scss +36 -0
- package/treb-embed/style/dialog.scss +181 -0
- package/treb-embed/style/dropdown-select.scss +101 -0
- package/treb-embed/style/formula-bar.scss +193 -0
- package/treb-embed/style/grid.scss +374 -0
- package/treb-embed/style/layout.scss +424 -0
- package/treb-embed/style/mouse-mask.scss +67 -0
- package/treb-embed/style/note.scss +92 -0
- package/treb-embed/style/overlay-editor.scss +102 -0
- package/treb-embed/style/spinner.scss +92 -0
- package/treb-embed/style/tab-bar.scss +228 -0
- package/treb-embed/style/table.scss +80 -0
- package/treb-embed/style/theme-defaults.scss +444 -0
- package/treb-embed/style/toolbar.scss +416 -0
- package/treb-embed/style/tooltip.scss +68 -0
- package/treb-embed/style/treb-icons.scss +130 -0
- package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
- package/treb-embed/style/z-index.scss +43 -0
- package/treb-export/docs/charts.md +68 -0
- package/treb-export/modern.tsconfig.json +19 -0
- package/treb-export/package.json +4 -0
- package/treb-export/src/address-type.ts +77 -0
- package/treb-export/src/base-template.ts +22 -0
- package/treb-export/src/column-width.ts +85 -0
- package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
- package/treb-export/src/drawing2/chart2.ts +282 -0
- package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
- package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
- package/treb-export/src/drawing2/drawing2.ts +355 -0
- package/treb-export/src/drawing2/embedded-image.ts +71 -0
- package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
- package/treb-export/src/export-worker/export-worker.ts +99 -0
- package/treb-export/src/export-worker/index-modern.ts +22 -0
- package/treb-export/src/export2.ts +2204 -0
- package/treb-export/src/import2.ts +882 -0
- package/treb-export/src/relationship.ts +36 -0
- package/treb-export/src/shared-strings2.ts +128 -0
- package/treb-export/src/template-2.ts +22 -0
- package/treb-export/src/unescape_xml.ts +47 -0
- package/treb-export/src/workbook-sheet2.ts +182 -0
- package/treb-export/src/workbook-style2.ts +1285 -0
- package/treb-export/src/workbook-theme2.ts +88 -0
- package/treb-export/src/workbook2.ts +491 -0
- package/treb-export/src/xml-utils.ts +201 -0
- package/treb-export/template/base/[Content_Types].xml +2 -0
- package/treb-export/template/base/_rels/.rels +2 -0
- package/treb-export/template/base/docProps/app.xml +2 -0
- package/treb-export/template/base/docProps/core.xml +12 -0
- package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
- package/treb-export/template/base/xl/sharedStrings.xml +2 -0
- package/treb-export/template/base/xl/styles.xml +2 -0
- package/treb-export/template/base/xl/theme/theme1.xml +2 -0
- package/treb-export/template/base/xl/workbook.xml +2 -0
- package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
- package/treb-export/template/base.xlsx +0 -0
- package/treb-format/package.json +8 -0
- package/treb-format/src/format.test.ts +213 -0
- package/treb-format/src/format.ts +942 -0
- package/treb-format/src/format_cache.ts +199 -0
- package/treb-format/src/format_parser.ts +723 -0
- package/treb-format/src/index.ts +25 -0
- package/treb-format/src/number_format_section.ts +100 -0
- package/treb-format/src/value_parser.ts +337 -0
- package/treb-grid/package.json +5 -0
- package/treb-grid/src/editors/autocomplete.ts +394 -0
- package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
- package/treb-grid/src/editors/formula_bar.ts +473 -0
- package/treb-grid/src/editors/formula_editor_base.ts +910 -0
- package/treb-grid/src/editors/overlay_editor.ts +511 -0
- package/treb-grid/src/index.ts +37 -0
- package/treb-grid/src/layout/base_layout.ts +2618 -0
- package/treb-grid/src/layout/grid_layout.ts +299 -0
- package/treb-grid/src/layout/rectangle_cache.ts +86 -0
- package/treb-grid/src/render/selection-renderer.ts +414 -0
- package/treb-grid/src/render/svg_header_overlay.ts +93 -0
- package/treb-grid/src/render/svg_selection_block.ts +187 -0
- package/treb-grid/src/render/tile_renderer.ts +2122 -0
- package/treb-grid/src/types/annotation.ts +216 -0
- package/treb-grid/src/types/border_constants.ts +34 -0
- package/treb-grid/src/types/clipboard_data.ts +31 -0
- package/treb-grid/src/types/data_model.ts +334 -0
- package/treb-grid/src/types/drag_mask.ts +81 -0
- package/treb-grid/src/types/grid.ts +7743 -0
- package/treb-grid/src/types/grid_base.ts +3644 -0
- package/treb-grid/src/types/grid_command.ts +470 -0
- package/treb-grid/src/types/grid_events.ts +124 -0
- package/treb-grid/src/types/grid_options.ts +97 -0
- package/treb-grid/src/types/grid_selection.ts +60 -0
- package/treb-grid/src/types/named_range.ts +369 -0
- package/treb-grid/src/types/scale-control.ts +202 -0
- package/treb-grid/src/types/serialize_options.ts +72 -0
- package/treb-grid/src/types/set_range_options.ts +52 -0
- package/treb-grid/src/types/sheet.ts +3099 -0
- package/treb-grid/src/types/sheet_types.ts +95 -0
- package/treb-grid/src/types/tab_bar.ts +464 -0
- package/treb-grid/src/types/tile.ts +59 -0
- package/treb-grid/src/types/update_flags.ts +75 -0
- package/treb-grid/src/util/dom_utilities.ts +44 -0
- package/treb-grid/src/util/fontmetrics2.ts +179 -0
- package/treb-grid/src/util/ua.ts +104 -0
- package/treb-logo.svg +18 -0
- package/treb-parser/package.json +5 -0
- package/treb-parser/src/csv-parser.ts +122 -0
- package/treb-parser/src/index.ts +25 -0
- package/treb-parser/src/md-parser.ts +526 -0
- package/treb-parser/src/parser-types.ts +397 -0
- package/treb-parser/src/parser.test.ts +298 -0
- package/treb-parser/src/parser.ts +2673 -0
- package/treb-utils/package.json +5 -0
- package/treb-utils/src/dispatch.ts +57 -0
- package/treb-utils/src/event_source.ts +147 -0
- package/treb-utils/src/ievent_source.ts +33 -0
- package/treb-utils/src/index.ts +31 -0
- package/treb-utils/src/measurement.ts +174 -0
- package/treb-utils/src/resizable.ts +160 -0
- package/treb-utils/src/scale.ts +137 -0
- package/treb-utils/src/serialize_html.ts +124 -0
- package/treb-utils/src/template.ts +70 -0
- package/treb-utils/src/validate_uri.ts +61 -0
- package/tsconfig.json +10 -0
- package/tsproject.json +30 -0
- package/util/license-plugin-esbuild.js +86 -0
- package/util/list-css-vars.sh +46 -0
- package/README-esm.md +0 -37
- package/treb-bundle.css +0 -2
- package/treb-bundle.mjs +0 -15
|
@@ -0,0 +1,428 @@
|
|
|
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-2023 trebco, llc.
|
|
18
|
+
* info@treb.app
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Complex, IsComplex, UnionValue, ValueType } from 'treb-base-types';
|
|
23
|
+
import { DivideByZeroError, ValueError } from './function-error';
|
|
24
|
+
|
|
25
|
+
import * as ComplexLib from './complex-math';
|
|
26
|
+
|
|
27
|
+
// import { PolarToRectangular, RectangularToPolar,
|
|
28
|
+
// MultiplyComplex, DivideComplex, PowerComplex } from './complex-math';
|
|
29
|
+
|
|
30
|
+
export type PrimitiveBinaryExpression = (a: UnionValue, b: UnionValue) => UnionValue;
|
|
31
|
+
|
|
32
|
+
type NumericTuple = [number, number, UnionValue?, UnionValue?, UnionValue?];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* a is either a complex union value or undefined. if it's defined,
|
|
36
|
+
* return it. if it's undefined, return a complex number with the given
|
|
37
|
+
* real value.
|
|
38
|
+
*/
|
|
39
|
+
const EnsureComplex = (a?: UnionValue, real = 0): { type: ValueType.complex, value: {real: number, imaginary: number}} => {
|
|
40
|
+
|
|
41
|
+
if (a && a.type === ValueType.complex) {
|
|
42
|
+
return a as {type: ValueType.complex, value: {real: number, imaginary: number}};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
type: ValueType.complex,
|
|
47
|
+
value: {
|
|
48
|
+
real,
|
|
49
|
+
imaginary: 0,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* return a complex number or, if there's no imaginary component, reduce it to a real
|
|
57
|
+
*/
|
|
58
|
+
const BoxComplex = (value: Complex): UnionValue => {
|
|
59
|
+
return value.imaginary ?
|
|
60
|
+
{ type: ValueType.complex, value } :
|
|
61
|
+
{ type: ValueType.number, value: value.real };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const NumericTypes = (a: UnionValue, b: UnionValue): NumericTuple => {
|
|
65
|
+
|
|
66
|
+
if (a.type === ValueType.error) { return [0, 0, a]; }
|
|
67
|
+
if (b.type === ValueType.error) { return [0, 0, b]; }
|
|
68
|
+
|
|
69
|
+
const result: NumericTuple = [0, 0];
|
|
70
|
+
|
|
71
|
+
// FIXME: what about empty string? should === 0?
|
|
72
|
+
|
|
73
|
+
switch (a.type) {
|
|
74
|
+
case ValueType.number:
|
|
75
|
+
result[0] = a.value as number;
|
|
76
|
+
break;
|
|
77
|
+
|
|
78
|
+
case ValueType.boolean:
|
|
79
|
+
result[0] = a.value ? 1 : 0;
|
|
80
|
+
break;
|
|
81
|
+
|
|
82
|
+
case ValueType.undefined:
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case ValueType.complex:
|
|
86
|
+
result[3] = a;
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
default:
|
|
90
|
+
return [0, 0, ValueError()]; // FIXME
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
switch (b.type) {
|
|
94
|
+
case ValueType.number:
|
|
95
|
+
result[1] = b.value as number;
|
|
96
|
+
break;
|
|
97
|
+
|
|
98
|
+
case ValueType.boolean:
|
|
99
|
+
result[1] = b.value ? 1 : 0;
|
|
100
|
+
break;
|
|
101
|
+
|
|
102
|
+
case ValueType.undefined:
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case ValueType.complex:
|
|
106
|
+
result[4] = b;
|
|
107
|
+
break;
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
return [0, 0, ValueError()]; // FIXME
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// if we have one complex value, ensure we have two, so
|
|
114
|
+
// we don't have to test again.
|
|
115
|
+
|
|
116
|
+
if (result[3] || result[4]) {
|
|
117
|
+
result[3] = EnsureComplex(result[3], result[0]);
|
|
118
|
+
result[4] = EnsureComplex(result[4], result[1]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const Add = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
125
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
126
|
+
|
|
127
|
+
if (z) { return z; }
|
|
128
|
+
|
|
129
|
+
if (c1 && c2) {
|
|
130
|
+
return BoxComplex({
|
|
131
|
+
real: c1.value.real + c2.value.real,
|
|
132
|
+
imaginary: c1.value.imaginary + c2.value.imaginary,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return { value: x + y, type: ValueType.number };
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const Subtract = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
140
|
+
|
|
141
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
142
|
+
|
|
143
|
+
if (z) { return z; }
|
|
144
|
+
|
|
145
|
+
if (c1 && c2) {
|
|
146
|
+
return BoxComplex({
|
|
147
|
+
real: c1.value.real - c2.value.real,
|
|
148
|
+
imaginary: c1.value.imaginary - c2.value.imaginary,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { value: x - y, type: ValueType.number };
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* power function that only uses complex numbers if one of
|
|
157
|
+
* the arguments is complex. this is intended to prevent complex
|
|
158
|
+
* numbers from leaking in to spreadsheets.
|
|
159
|
+
*/
|
|
160
|
+
const PowerGated = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
161
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
162
|
+
if (z) { return z; }
|
|
163
|
+
|
|
164
|
+
if (c1 && c2) {
|
|
165
|
+
return BoxComplex(ComplexLib.Power(c1.value, c2.value));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const value = Math.pow(x, y);
|
|
169
|
+
if (isNaN(value)) { return ValueError(); }
|
|
170
|
+
|
|
171
|
+
return { type: ValueType.number, value };
|
|
172
|
+
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* power function that uses complex exponentiation if one of the arguments
|
|
177
|
+
* is complex, or if the exponent is < 1.
|
|
178
|
+
*/
|
|
179
|
+
const PowerComplex = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
180
|
+
|
|
181
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
182
|
+
if (z) { return z; }
|
|
183
|
+
|
|
184
|
+
// if one argument is complex, we will always get both as complex.
|
|
185
|
+
// so we don't need to re-test. for the same reason if exponent
|
|
186
|
+
// is < 1 we will have to convert both.
|
|
187
|
+
|
|
188
|
+
if (c1 && c2) {
|
|
189
|
+
return BoxComplex(ComplexLib.Power(c1.value, c2.value));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (x < 0 && y !== 0 && Math.abs(y) < 1) {
|
|
193
|
+
return BoxComplex(ComplexLib.Power(
|
|
194
|
+
{ real: x, imaginary: 0}, { real: y, imaginary: 0 }));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const value = Math.pow(x, y);
|
|
198
|
+
if (isNaN(value)) { return ValueError(); }
|
|
199
|
+
|
|
200
|
+
return { type: ValueType.number, value };
|
|
201
|
+
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
export const Power = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
206
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
207
|
+
if (z) { return z; }
|
|
208
|
+
|
|
209
|
+
if (c1 && c2) {
|
|
210
|
+
return BoxComplex(ComplexLib.Power(c1.value, c2.value));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const value = Math.pow(x, y);
|
|
214
|
+
if (isNaN(value)) { return ValueError(); }
|
|
215
|
+
|
|
216
|
+
return { type: ValueType.number, value };
|
|
217
|
+
|
|
218
|
+
};
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
let Power = PowerGated;
|
|
222
|
+
|
|
223
|
+
export const Multiply = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
224
|
+
|
|
225
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
226
|
+
|
|
227
|
+
if (z) { return z; }
|
|
228
|
+
|
|
229
|
+
if (c1 && c2) {
|
|
230
|
+
return BoxComplex(ComplexLib.Multiply(c1.value, c2.value));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return { value: x * y, type: ValueType.number };
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export const Divide = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
237
|
+
const [x, y, z, c1, c2] = NumericTypes(a, b);
|
|
238
|
+
if (z) { return z; }
|
|
239
|
+
|
|
240
|
+
if (c1 && c2) {
|
|
241
|
+
if (c2.value.real === 0 && c2.value.imaginary === 0) {
|
|
242
|
+
return DivideByZeroError();
|
|
243
|
+
}
|
|
244
|
+
return BoxComplex(ComplexLib.Divide(c1.value, c2.value));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (y === 0) {
|
|
248
|
+
return DivideByZeroError();
|
|
249
|
+
}
|
|
250
|
+
return { value: x / y, type: ValueType.number };
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
export const Modulo = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
254
|
+
const [x, y, z] = NumericTypes(a, b);
|
|
255
|
+
if (z) { return z; }
|
|
256
|
+
if (y === 0) {
|
|
257
|
+
return DivideByZeroError();
|
|
258
|
+
}
|
|
259
|
+
return { value: x % y, type: ValueType.number };
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export const Concatenate = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
263
|
+
if (a.type === ValueType.error) { return a; }
|
|
264
|
+
if (b.type === ValueType.error) { return b; }
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
type: ValueType.string,
|
|
268
|
+
value: `${a.type === ValueType.undefined ? '' : a.value}${b.type === ValueType.undefined ? '' : b.value}`,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export const Equals = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
274
|
+
if (a.type === ValueType.error) { return a; }
|
|
275
|
+
if (b.type === ValueType.error) { return b; }
|
|
276
|
+
|
|
277
|
+
// empty cells equal 0 (real or complex) and ""
|
|
278
|
+
|
|
279
|
+
if ((a.type === ValueType.undefined && (b.value === '' || b.value === 0 || (b.type === ValueType.complex && b.value.real === 0 && b.value.imaginary === 0)))
|
|
280
|
+
|| (b.type === ValueType.undefined && (a.value === '' || a.value === 0 || (a.type === ValueType.complex && a.value.real === 0 && a.value.imaginary === 0)))) {
|
|
281
|
+
return { type: ValueType.boolean, value: true, };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
285
|
+
|
|
286
|
+
// complex can equal real or complex
|
|
287
|
+
|
|
288
|
+
let equals = false;
|
|
289
|
+
|
|
290
|
+
if (a.type === b.type) {
|
|
291
|
+
equals =
|
|
292
|
+
a.value.real == b.value.real && // == ?
|
|
293
|
+
a.value.imaginary == b.value.imaginary // == ?
|
|
294
|
+
;
|
|
295
|
+
}
|
|
296
|
+
else if (a.type === ValueType.number) {
|
|
297
|
+
equals =
|
|
298
|
+
b.value.real == a.value &&
|
|
299
|
+
!b.value.imaginary;
|
|
300
|
+
}
|
|
301
|
+
else if (b.type === ValueType.number) {
|
|
302
|
+
equals =
|
|
303
|
+
a.value.real == b.value &&
|
|
304
|
+
!a.value.imaginary;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return { type: ValueType.boolean, value: equals };
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return { type: ValueType.boolean, value: a.value == b.value }; // note ==
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
export const NotEquals = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
315
|
+
const result = Equals(a, b);
|
|
316
|
+
if (result.type === ValueType.error) {
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
type: ValueType.boolean,
|
|
321
|
+
value: !result.value,
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/* *
|
|
326
|
+
* this is duplicative, but it seems better than another function call.
|
|
327
|
+
* not sure if that is over-optimization (it is).
|
|
328
|
+
* /
|
|
329
|
+
export const NotEquals = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
330
|
+
if (a.type === ValueType.error) { return a; }
|
|
331
|
+
if (b.type === ValueType.error) { return b; }
|
|
332
|
+
|
|
333
|
+
// empty cells equal 0 and ""
|
|
334
|
+
// FIXME: should also equal a complex with 0+0i
|
|
335
|
+
|
|
336
|
+
if ((a.type === ValueType.undefined && (b.value === '' || b.value === 0))
|
|
337
|
+
|| (b.type === ValueType.undefined && (a.value === '' || a.value === 0))) {
|
|
338
|
+
|
|
339
|
+
return { type: ValueType.boolean, value: false, };
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
343
|
+
return {
|
|
344
|
+
type: ValueType.boolean,
|
|
345
|
+
value: !((a.type === b.type) &&
|
|
346
|
+
a.value.real == b.value.real && // ==
|
|
347
|
+
a.value.imaginary == b.value.imaginary) // ==
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return { type: ValueType.boolean, value: a.value != b.value }; // note ==
|
|
353
|
+
};
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
// NOTE: our comparisons don't match Excel with different types -- we could
|
|
357
|
+
// probably figure out what Excel is doing, but I'm not sure it's useful or
|
|
358
|
+
// worthwhile
|
|
359
|
+
|
|
360
|
+
export const GreaterThan = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
361
|
+
if (a.type === ValueType.error) { return a; }
|
|
362
|
+
if (b.type === ValueType.error) { return b; }
|
|
363
|
+
|
|
364
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
365
|
+
return ValueError();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return { type: ValueType.boolean, value: (a.value||0) > (b.value||0) };
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export const GreaterThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
372
|
+
if (a.type === ValueType.error) { return a; }
|
|
373
|
+
if (b.type === ValueType.error) { return b; }
|
|
374
|
+
|
|
375
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
376
|
+
return ValueError();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return { type: ValueType.boolean, value: a.value >= b.value };
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
export const LessThan = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
383
|
+
if (a.type === ValueType.error) { return a; }
|
|
384
|
+
if (b.type === ValueType.error) { return b; }
|
|
385
|
+
|
|
386
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
387
|
+
return ValueError();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return { type: ValueType.boolean, value: a.value < b.value };
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
export const LessThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
394
|
+
if (a.type === ValueType.error) { return a; }
|
|
395
|
+
if (b.type === ValueType.error) { return b; }
|
|
396
|
+
|
|
397
|
+
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
398
|
+
return ValueError();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return { type: ValueType.boolean, value: a.value <= b.value };
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export const UseComplex = () => {
|
|
405
|
+
Power = PowerComplex;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export const MapOperator = (operator: string) => {
|
|
409
|
+
switch(operator) {
|
|
410
|
+
case '&': return Concatenate;
|
|
411
|
+
case '+': return Add;
|
|
412
|
+
case '-': return Subtract;
|
|
413
|
+
case '*': return Multiply;
|
|
414
|
+
case '/': return Divide;
|
|
415
|
+
case '^': return Power;
|
|
416
|
+
case '**': return Power;
|
|
417
|
+
case '%': return Modulo; // NOTE: not an excel operator
|
|
418
|
+
case '=': return Equals;
|
|
419
|
+
case '==': return Equals;
|
|
420
|
+
case '!=': return NotEquals;
|
|
421
|
+
case '<>': return NotEquals;
|
|
422
|
+
case '>': return GreaterThan;
|
|
423
|
+
case '>=': return GreaterThanEqual;
|
|
424
|
+
case '<': return LessThan;
|
|
425
|
+
case '<=': return LessThanEqual;
|
|
426
|
+
}
|
|
427
|
+
return undefined;
|
|
428
|
+
};
|