@trebco/treb 31.9.1 → 32.3.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.
- package/dist/treb-spreadsheet.mjs +15 -15
- package/i18n/languages/treb-i18n-da.mjs +1 -0
- package/i18n/languages/treb-i18n-de.mjs +1 -0
- package/i18n/languages/treb-i18n-es.mjs +1 -0
- package/i18n/languages/treb-i18n-fr.mjs +1 -0
- package/i18n/languages/treb-i18n-it.mjs +1 -0
- package/i18n/languages/treb-i18n-nl.mjs +1 -0
- package/i18n/languages/treb-i18n-no.mjs +1 -0
- package/i18n/languages/treb-i18n-pl.mjs +1 -0
- package/i18n/languages/treb-i18n-pt.mjs +1 -0
- package/i18n/languages/treb-i18n-sv.mjs +1 -0
- package/package.json +1 -1
- package/treb-base-types/src/style.ts +20 -0
- package/treb-base-types/src/union.ts +6 -0
- package/treb-base-types/src/value-type.ts +13 -0
- package/treb-calculator/src/calculator.ts +20 -1
- package/treb-calculator/src/descriptors.ts +49 -4
- package/treb-calculator/src/expression-calculator.ts +263 -12
- package/treb-calculator/src/functions/base-functions.ts +49 -0
- package/treb-calculator/src/functions/fp.ts +339 -0
- package/treb-calculator/src/functions/gamma.ts +143 -0
- package/treb-calculator/src/functions/lambda-functions.ts +96 -0
- package/treb-calculator/src/functions/statistics-functions.ts +88 -0
- package/treb-data-model/src/data_model.ts +28 -13
- package/treb-data-model/src/named.ts +7 -0
- package/treb-data-model/src/sheet.ts +19 -2
- package/treb-embed/src/embedded-spreadsheet.ts +22 -5
- package/treb-embed/style/theme-defaults.scss +0 -22
- package/treb-grid/src/editors/editor.ts +14 -0
- package/treb-grid/src/types/grid.ts +74 -28
- package/treb-parser/src/parser-types.ts +24 -0
- package/treb-parser/src/parser.ts +157 -223
- package/dist/treb-export-worker.mjs +0 -2
- package/dist/treb.d.ts +0 -2235
- package/treb-calculator/tsconfig.json +0 -7
|
@@ -411,6 +411,13 @@ export class Parser {
|
|
|
411
411
|
}
|
|
412
412
|
break;
|
|
413
413
|
|
|
414
|
+
case 'implicit-call':
|
|
415
|
+
if (func(unit)) {
|
|
416
|
+
unit.call = this.Walk2(unit.call, func);
|
|
417
|
+
unit.args = unit.args.map(source => this.Walk2(source, func));
|
|
418
|
+
}
|
|
419
|
+
break;
|
|
420
|
+
|
|
414
421
|
case 'call':
|
|
415
422
|
if (func(unit)) {
|
|
416
423
|
unit.args = unit.args.map(source => this.Walk2(source, func));
|
|
@@ -477,6 +484,15 @@ export class Parser {
|
|
|
477
484
|
}
|
|
478
485
|
return;
|
|
479
486
|
|
|
487
|
+
case 'implicit-call':
|
|
488
|
+
if (func(unit)) {
|
|
489
|
+
this.Walk(unit.call, func);
|
|
490
|
+
for (const arg of unit.args) {
|
|
491
|
+
this.Walk(arg, func);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return;
|
|
495
|
+
|
|
480
496
|
case 'call':
|
|
481
497
|
if (func(unit)) {
|
|
482
498
|
for (const arg of unit.args) {
|
|
@@ -586,14 +602,15 @@ export class Parser {
|
|
|
586
602
|
if (options.pass_through_addresses) {
|
|
587
603
|
return unit.label;
|
|
588
604
|
}
|
|
589
|
-
return options.r1c1 ? this.R1C1Label(unit, options.r1c1_base) : this.AddressLabel(unit, offset);
|
|
605
|
+
return options.r1c1 ? this.R1C1Label(unit, options.r1c1_base, options.r1c1_force_relative) : this.AddressLabel(unit, offset);
|
|
590
606
|
|
|
591
607
|
case 'range':
|
|
592
608
|
if (options.pass_through_addresses) {
|
|
593
609
|
return unit.label;
|
|
594
610
|
}
|
|
595
611
|
return options.r1c1 ?
|
|
596
|
-
this.R1C1Label(unit.start, options.r1c1_base) + ':' +
|
|
612
|
+
this.R1C1Label(unit.start, options.r1c1_base, options.r1c1_force_relative) + ':' +
|
|
613
|
+
this.R1C1Label(unit.end, options.r1c1_base, options.r1c1_force_relative) :
|
|
597
614
|
this.AddressLabel(unit.start, offset) + ':' + this.AddressLabel(unit.end, offset);
|
|
598
615
|
|
|
599
616
|
case 'missing':
|
|
@@ -755,6 +772,10 @@ export class Parser {
|
|
|
755
772
|
.map((x) => this.Render(x, options)).join(separator);
|
|
756
773
|
}
|
|
757
774
|
|
|
775
|
+
case 'implicit-call':
|
|
776
|
+
return this.Render(unit.call, options) +
|
|
777
|
+
'(' + unit.args.map(element => this.Render(element, options)).join(separator) + ')';
|
|
778
|
+
|
|
758
779
|
case 'call':
|
|
759
780
|
return (
|
|
760
781
|
unit.name +
|
|
@@ -935,10 +956,14 @@ export class Parser {
|
|
|
935
956
|
|
|
936
957
|
/**
|
|
937
958
|
* generates absolute or relative R1C1 address
|
|
959
|
+
*
|
|
960
|
+
* FIXME: not supporting relative (offset) addresses atm? I'd like to
|
|
961
|
+
* change this but I don't want to break anything...
|
|
938
962
|
*/
|
|
939
963
|
protected R1C1Label(
|
|
940
964
|
address: UnitAddress,
|
|
941
965
|
base?: UnitAddress,
|
|
966
|
+
force_relative = false,
|
|
942
967
|
): string {
|
|
943
968
|
|
|
944
969
|
let label = '';
|
|
@@ -948,8 +973,30 @@ export class Parser {
|
|
|
948
973
|
'\'' + address.sheet + '\'' : address.sheet) + '!';
|
|
949
974
|
}
|
|
950
975
|
|
|
976
|
+
let row = '';
|
|
977
|
+
let column = '';
|
|
978
|
+
|
|
979
|
+
if (force_relative && base) {
|
|
980
|
+
const delta_row = address.row - base.row;
|
|
981
|
+
const delta_column = address.column - base.column;
|
|
982
|
+
|
|
983
|
+
if (delta_row) {
|
|
984
|
+
row = `[${delta_row}]`;
|
|
985
|
+
}
|
|
986
|
+
if (delta_column) {
|
|
987
|
+
column = `[${delta_column}]`;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
else {
|
|
992
|
+
row = address.offset_row ? `[${address.row}]` : (address.row + 1).toString();
|
|
993
|
+
column = address.offset_column ? `[${address.column}]` : (address.column + 1).toString();
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/*
|
|
951
997
|
const row = (address.absolute_row || !base) ? (address.row + 1).toString() : `[${address.row - base.row}]`;
|
|
952
998
|
const column = (address.absolute_column || !base) ? (address.column + 1).toString() : `[${address.column - base.column}]`;
|
|
999
|
+
*/
|
|
953
1000
|
|
|
954
1001
|
label += `R${row}C${column}`;
|
|
955
1002
|
|
|
@@ -1009,11 +1056,12 @@ export class Parser {
|
|
|
1009
1056
|
*
|
|
1010
1057
|
* @param exit exit on specific characters
|
|
1011
1058
|
*/
|
|
1012
|
-
protected ParseGeneric(exit: number[] = [0]): ExpressionUnit | null {
|
|
1059
|
+
protected ParseGeneric(exit: number[] = [0], explicit_group = false): ExpressionUnit | null {
|
|
1013
1060
|
let stream: ExpressionUnit[] = [];
|
|
1014
1061
|
|
|
1015
1062
|
for (; this.index < this.length;) {
|
|
1016
1063
|
const unit = this.ParseNext(stream.length === 0);
|
|
1064
|
+
|
|
1017
1065
|
if (typeof unit === 'number') {
|
|
1018
1066
|
|
|
1019
1067
|
if (exit.some((test) => unit === test)) {
|
|
@@ -1025,8 +1073,11 @@ export class Parser {
|
|
|
1025
1073
|
// so we only have to worry about grouping. parse
|
|
1026
1074
|
// up to the closing paren...
|
|
1027
1075
|
|
|
1076
|
+
// actually now we have implicit calls, so we need
|
|
1077
|
+
// to manage that here.
|
|
1078
|
+
|
|
1028
1079
|
this.index++; // open paren
|
|
1029
|
-
const group = this.ParseGeneric([CLOSE_PAREN]);
|
|
1080
|
+
const group = this.ParseGeneric([CLOSE_PAREN], true);
|
|
1030
1081
|
this.index++; // close paren
|
|
1031
1082
|
|
|
1032
1083
|
// and wrap up in a group element to prevent reordering.
|
|
@@ -1034,14 +1085,18 @@ export class Parser {
|
|
|
1034
1085
|
|
|
1035
1086
|
// skip nulls
|
|
1036
1087
|
|
|
1037
|
-
|
|
1088
|
+
// ...don't skip nulls? don't know what the rationale was
|
|
1089
|
+
// but for implicit calls we will need to support empty arguments
|
|
1090
|
+
|
|
1091
|
+
// if (group) {
|
|
1038
1092
|
stream.push({
|
|
1039
1093
|
type: 'group',
|
|
1040
1094
|
id: this.id_counter++,
|
|
1041
|
-
elements: [group],
|
|
1095
|
+
elements: group? [group] : [],
|
|
1042
1096
|
explicit: true,
|
|
1043
1097
|
});
|
|
1044
|
-
}
|
|
1098
|
+
//}
|
|
1099
|
+
|
|
1045
1100
|
}
|
|
1046
1101
|
else {
|
|
1047
1102
|
// this can probably move to PNext? except for the test
|
|
@@ -1051,6 +1106,21 @@ export class Parser {
|
|
|
1051
1106
|
if (operator) {
|
|
1052
1107
|
stream.push(operator);
|
|
1053
1108
|
}
|
|
1109
|
+
else if (explicit_group && unit === this.argument_separator_char) {
|
|
1110
|
+
|
|
1111
|
+
// adding a new unit type here to explicitly show we're in
|
|
1112
|
+
// a group; prevents later passes from treating arguments as
|
|
1113
|
+
// fractions or something else. we just need to remove these
|
|
1114
|
+
// later
|
|
1115
|
+
|
|
1116
|
+
stream.push({
|
|
1117
|
+
type: 'group-separator',
|
|
1118
|
+
position: this.index,
|
|
1119
|
+
id: this.id_counter++,
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
this.index++;
|
|
1123
|
+
}
|
|
1054
1124
|
else {
|
|
1055
1125
|
this.error = `unexpected character [1]: ${String.fromCharCode(unit)}, 0x${unit.toString(16)}`;
|
|
1056
1126
|
this.valid = false;
|
|
@@ -1231,13 +1301,6 @@ export class Parser {
|
|
|
1231
1301
|
// fix ordering of binary operations based on precedence; also
|
|
1232
1302
|
// convert and validate ranges
|
|
1233
1303
|
|
|
1234
|
-
// return this.BinaryToRange(this.ArrangeUnits(stream));
|
|
1235
|
-
// return this.ArrangeUnits(stream);
|
|
1236
|
-
|
|
1237
|
-
// const arranged = this.ArrangeUnits(stream);
|
|
1238
|
-
// const result = this.BinaryToComplex(arranged);
|
|
1239
|
-
// return result;
|
|
1240
|
-
|
|
1241
1304
|
return this.BinaryToComplex(this.ArrangeUnits(stream));
|
|
1242
1305
|
|
|
1243
1306
|
}
|
|
@@ -1612,206 +1675,13 @@ export class Parser {
|
|
|
1612
1675
|
|
|
1613
1676
|
|
|
1614
1677
|
/**
|
|
1615
|
-
*
|
|
1616
|
-
* validates that there are no colon operations with non-address operands
|
|
1617
|
-
* (which is why it's called after precendence reordering; colon has the
|
|
1618
|
-
* highest preference). recursive only over binary ops AND unary ops.
|
|
1619
|
-
*
|
|
1620
|
-
* NOTE: there are other legal arguments to a colon operator. specifically:
|
|
1621
|
-
*
|
|
1622
|
-
* (1) two numbers, in either order
|
|
1623
|
-
*
|
|
1624
|
-
* 15:16
|
|
1625
|
-
* 16:16
|
|
1626
|
-
* 16:15
|
|
1627
|
-
*
|
|
1628
|
-
* (2) with one or both optionally having a $
|
|
1629
|
-
*
|
|
1630
|
-
* 15:$16
|
|
1631
|
-
* $16:$16
|
|
1632
|
-
*
|
|
1633
|
-
* (3) two column identifiers, in either order
|
|
1634
|
-
*
|
|
1635
|
-
* A:F
|
|
1636
|
-
* B:A
|
|
1637
|
-
*
|
|
1638
|
-
* (4) and the same with $
|
|
1639
|
-
*
|
|
1640
|
-
* $A:F
|
|
1641
|
-
* $A:$F
|
|
1678
|
+
* reorders operations for precendence
|
|
1642
1679
|
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1680
|
+
* this method was written with the assumption that groups were
|
|
1681
|
+
* always an error. that's no longer true, with implicit calls.
|
|
1682
|
+
* we should still error if it's not an _explicit_ group, i.e. there's
|
|
1683
|
+
* just a bunch of naked tokens.
|
|
1647
1684
|
*
|
|
1648
|
-
* FIXME: will need some updated to rendering these, we don't have any
|
|
1649
|
-
* handler for rendering infinity
|
|
1650
|
-
*/
|
|
1651
|
-
protected BinaryToRangeX(unit: ExpressionUnit): ExpressionUnit {
|
|
1652
|
-
if (unit.type === 'binary') {
|
|
1653
|
-
if (unit.operator === ':') {
|
|
1654
|
-
|
|
1655
|
-
let range: UnitRange|undefined;
|
|
1656
|
-
let label = '';
|
|
1657
|
-
|
|
1658
|
-
if (unit.left.type === 'address' && unit.right.type === 'address') {
|
|
1659
|
-
// construct a label using the full text. there's a possibility,
|
|
1660
|
-
// I suppose, that there are spaces (this should probably not be
|
|
1661
|
-
// legal). this is a canonical label, though (generated)
|
|
1662
|
-
|
|
1663
|
-
// it might be better to let this slip, or treat it as an error
|
|
1664
|
-
// and force a correction... not sure (TODO/FIXME)
|
|
1665
|
-
|
|
1666
|
-
const start_index = unit.left.position + unit.left.label.length;
|
|
1667
|
-
const end_index = unit.right.position;
|
|
1668
|
-
|
|
1669
|
-
range = {
|
|
1670
|
-
type: 'range',
|
|
1671
|
-
id: this.id_counter++,
|
|
1672
|
-
position: unit.left.position,
|
|
1673
|
-
start: unit.left,
|
|
1674
|
-
end: unit.right,
|
|
1675
|
-
label:
|
|
1676
|
-
unit.left.label +
|
|
1677
|
-
this.expression.substring(start_index, end_index) +
|
|
1678
|
-
unit.right.label,
|
|
1679
|
-
};
|
|
1680
|
-
|
|
1681
|
-
label = range.start.label + ':' + range.end.label;
|
|
1682
|
-
|
|
1683
|
-
this.address_refcount[range.start.label]--;
|
|
1684
|
-
this.address_refcount[range.end.label]--;
|
|
1685
|
-
|
|
1686
|
-
// remove entries from the list for start, stop
|
|
1687
|
-
const positions = [unit.left.position, unit.right.position];
|
|
1688
|
-
this.full_reference_list = this.full_reference_list.filter((test) => {
|
|
1689
|
-
return (
|
|
1690
|
-
test.position !== positions[0] && test.position !== positions[1]
|
|
1691
|
-
);
|
|
1692
|
-
});
|
|
1693
|
-
|
|
1694
|
-
}
|
|
1695
|
-
else if ((unit.left.type === 'literal' || unit.left.type === 'identifier')
|
|
1696
|
-
&& (unit.right.type === 'literal' || unit.right.type === 'identifier')) {
|
|
1697
|
-
|
|
1698
|
-
// see if we can plausibly interpret both of these as rows or columns
|
|
1699
|
-
|
|
1700
|
-
const left = this.UnitToAddress(unit.left);
|
|
1701
|
-
const right = this.UnitToAddress(unit.right);
|
|
1702
|
-
|
|
1703
|
-
// and they need to match
|
|
1704
|
-
|
|
1705
|
-
if (left && right
|
|
1706
|
-
&& ((left.column === Infinity && right.column === Infinity)
|
|
1707
|
-
|| (left.row === Infinity && right.row === Infinity))) {
|
|
1708
|
-
|
|
1709
|
-
label = left.label + ':' + right.label;
|
|
1710
|
-
|
|
1711
|
-
// we don't support out-of-order ranges, so we should correct.
|
|
1712
|
-
// they just won't work otherwise. (TODO/FIXME)
|
|
1713
|
-
|
|
1714
|
-
range = {
|
|
1715
|
-
type: 'range',
|
|
1716
|
-
id: this.id_counter++,
|
|
1717
|
-
position: unit.left.position,
|
|
1718
|
-
start: left,
|
|
1719
|
-
end: right,
|
|
1720
|
-
label,
|
|
1721
|
-
};
|
|
1722
|
-
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
/*
|
|
1728
|
-
else if ( unit.left.type === 'literal'
|
|
1729
|
-
&& unit.right.type === 'literal'
|
|
1730
|
-
&& typeof unit.left.value === 'number'
|
|
1731
|
-
&& typeof unit.right.value === 'number') {
|
|
1732
|
-
|
|
1733
|
-
// technically we don't want to support any number that has
|
|
1734
|
-
// a decimal place, but I'm not sure we have a useful way of
|
|
1735
|
-
// measuring that... could look at the original text?
|
|
1736
|
-
|
|
1737
|
-
if (unit.left.value > 0
|
|
1738
|
-
&& unit.right.value > 0
|
|
1739
|
-
&& !/\./.test(unit.left.text||'')
|
|
1740
|
-
&& !/\./.test(unit.right.text||'')
|
|
1741
|
-
) {
|
|
1742
|
-
|
|
1743
|
-
label = unit.left.value.toString() + ':' + unit.right.value.toString();
|
|
1744
|
-
|
|
1745
|
-
console.info('m2:', label);
|
|
1746
|
-
|
|
1747
|
-
const left: UnitAddress = {
|
|
1748
|
-
type: 'address',
|
|
1749
|
-
position: unit.left.position,
|
|
1750
|
-
label: unit.left.value.toString(),
|
|
1751
|
-
row: unit.left.value - 1,
|
|
1752
|
-
id: this.id_counter++,
|
|
1753
|
-
column: Infinity,
|
|
1754
|
-
};
|
|
1755
|
-
|
|
1756
|
-
const right: UnitAddress = {
|
|
1757
|
-
type: 'address',
|
|
1758
|
-
position: unit.right.position,
|
|
1759
|
-
label: unit.right.value.toString(),
|
|
1760
|
-
row: unit.right.value - 1,
|
|
1761
|
-
id: this.id_counter++,
|
|
1762
|
-
column: Infinity,
|
|
1763
|
-
};
|
|
1764
|
-
|
|
1765
|
-
range = {
|
|
1766
|
-
type: 'range',
|
|
1767
|
-
id: this.id_counter++,
|
|
1768
|
-
position: unit.left.position,
|
|
1769
|
-
start: left,
|
|
1770
|
-
end: right,
|
|
1771
|
-
label,
|
|
1772
|
-
};
|
|
1773
|
-
|
|
1774
|
-
}
|
|
1775
|
-
|
|
1776
|
-
}
|
|
1777
|
-
*/
|
|
1778
|
-
|
|
1779
|
-
if (range) {
|
|
1780
|
-
|
|
1781
|
-
this.dependencies.ranges[label] = range;
|
|
1782
|
-
|
|
1783
|
-
// and add the range
|
|
1784
|
-
this.full_reference_list.push(range);
|
|
1785
|
-
|
|
1786
|
-
return range;
|
|
1787
|
-
|
|
1788
|
-
}
|
|
1789
|
-
else {
|
|
1790
|
-
this.error = `unexpected character: :`;
|
|
1791
|
-
this.valid = false;
|
|
1792
|
-
// console.info('xx', unit);
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
// recurse
|
|
1798
|
-
|
|
1799
|
-
unit.left = this.BinaryToRangeX(unit.left);
|
|
1800
|
-
unit.right = this.BinaryToRangeX(unit.right);
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
// this should no longer be required, because we explicitly check
|
|
1804
|
-
// when we construct the unary operations...
|
|
1805
|
-
|
|
1806
|
-
// else if (unit.type === 'unary') {
|
|
1807
|
-
// unit.operand = this.BinaryToRange(unit.operand);
|
|
1808
|
-
// }
|
|
1809
|
-
|
|
1810
|
-
return unit;
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
|
-
/**
|
|
1814
|
-
* reorders operations for precendence
|
|
1815
1685
|
*/
|
|
1816
1686
|
protected ArrangeUnits(stream: ExpressionUnit[]): ExpressionUnit {
|
|
1817
1687
|
|
|
@@ -1838,6 +1708,10 @@ export class Parser {
|
|
|
1838
1708
|
for (let index = 0; index < stream.length; index++) {
|
|
1839
1709
|
let element = stream[index];
|
|
1840
1710
|
|
|
1711
|
+
if (element.type === 'group-separator') {
|
|
1712
|
+
continue; // drop
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1841
1715
|
// given that we need to support unary operators, the logic needs
|
|
1842
1716
|
// to be a little different. operators are OK at any position, provided
|
|
1843
1717
|
// we can construct either a unary or binary operation.
|
|
@@ -1848,14 +1722,7 @@ export class Parser {
|
|
|
1848
1722
|
// in this case we do it with recursion.
|
|
1849
1723
|
|
|
1850
1724
|
if (unary_operators[element.operator]) {
|
|
1851
|
-
|
|
1852
|
-
// MARK X
|
|
1853
|
-
|
|
1854
|
-
// const right = this.BinaryToRange(
|
|
1855
|
-
// this.ArrangeUnits(stream.slice(index + 1)),
|
|
1856
|
-
//);
|
|
1857
|
-
|
|
1858
|
-
// const right = this.ArrangeUnits(stream.slice(index + 1));
|
|
1725
|
+
|
|
1859
1726
|
const right = this.BinaryToComplex(this.ArrangeUnits(stream.slice(index + 1)));
|
|
1860
1727
|
|
|
1861
1728
|
// this ensures we return the highest-level group, even if we recurse
|
|
@@ -1932,7 +1799,35 @@ export class Parser {
|
|
|
1932
1799
|
if (stack.length === 1) {
|
|
1933
1800
|
const a = stack[0].type;
|
|
1934
1801
|
|
|
1935
|
-
|
|
1802
|
+
// support for lambdas
|
|
1803
|
+
|
|
1804
|
+
if (element.type === 'group' && element.explicit) {
|
|
1805
|
+
if (a === 'address' || a === 'call' || a === 'identifier' || a === 'implicit-call') {
|
|
1806
|
+
|
|
1807
|
+
// our parser seems to create implicit groups from these
|
|
1808
|
+
// values in parens. we should fix that, but we can unpack it.
|
|
1809
|
+
|
|
1810
|
+
let args = element.elements;
|
|
1811
|
+
if (args.length === 1 && args[0].type === 'group' && !args[0].explicit) {
|
|
1812
|
+
args = args[0].elements;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// create an implicit call. replace on the stack.
|
|
1816
|
+
|
|
1817
|
+
stack[0] = {
|
|
1818
|
+
type: 'implicit-call',
|
|
1819
|
+
call: stack[0],
|
|
1820
|
+
args,
|
|
1821
|
+
id: this.id_counter++,
|
|
1822
|
+
position: stack[0].position,
|
|
1823
|
+
};
|
|
1824
|
+
|
|
1825
|
+
continue;
|
|
1826
|
+
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
/*
|
|
1830
|
+
else if (a !== 'operator') {
|
|
1936
1831
|
|
|
1937
1832
|
// console.warn("unexpected element", stack[0], element);
|
|
1938
1833
|
|
|
@@ -1947,6 +1842,7 @@ export class Parser {
|
|
|
1947
1842
|
};
|
|
1948
1843
|
|
|
1949
1844
|
}
|
|
1845
|
+
*/
|
|
1950
1846
|
|
|
1951
1847
|
}
|
|
1952
1848
|
|
|
@@ -1996,6 +1892,8 @@ export class Parser {
|
|
|
1996
1892
|
stack.splice(-2, 2, operation);
|
|
1997
1893
|
}
|
|
1998
1894
|
else {
|
|
1895
|
+
|
|
1896
|
+
/*
|
|
1999
1897
|
this.error = `multiple expressions`;
|
|
2000
1898
|
this.error_position = (element as {position?: number}).position;
|
|
2001
1899
|
this.valid = false;
|
|
@@ -2005,9 +1903,22 @@ export class Parser {
|
|
|
2005
1903
|
elements: stream,
|
|
2006
1904
|
explicit: false,
|
|
2007
1905
|
};
|
|
1906
|
+
*/
|
|
1907
|
+
|
|
1908
|
+
stack.push(element);
|
|
1909
|
+
|
|
2008
1910
|
}
|
|
2009
1911
|
}
|
|
2010
1912
|
|
|
1913
|
+
if (stack.length > 1) {
|
|
1914
|
+
return {
|
|
1915
|
+
type: 'group',
|
|
1916
|
+
id: this.id_counter++,
|
|
1917
|
+
elements: stack,
|
|
1918
|
+
explicit: false,
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
|
|
2011
1922
|
return stack[0];
|
|
2012
1923
|
}
|
|
2013
1924
|
|
|
@@ -2385,6 +2296,20 @@ export class Parser {
|
|
|
2385
2296
|
|
|
2386
2297
|
this.ConsumeWhiteSpace();
|
|
2387
2298
|
|
|
2299
|
+
// UPDATE: UNLESS the token is an address, because that's not
|
|
2300
|
+
// a legal function name. so change that precedence rule, address
|
|
2301
|
+
// comes first.
|
|
2302
|
+
|
|
2303
|
+
// erm -- that's not 100% correct. LOG10 is a valid cell address
|
|
2304
|
+
// and a valid function name. there might be others as well.
|
|
2305
|
+
|
|
2306
|
+
if (this.flags.spreadsheet_semantics) {
|
|
2307
|
+
const address = this.ConsumeAddress(str, position);
|
|
2308
|
+
if (address) return address;
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
// [FIXME: what about braces? (...)]
|
|
2312
|
+
|
|
2388
2313
|
const next_char = this.data[this.index];
|
|
2389
2314
|
if (next_char === OPEN_PAREN) {
|
|
2390
2315
|
const args = this.ConsumeArguments();
|
|
@@ -2404,8 +2329,9 @@ export class Parser {
|
|
|
2404
2329
|
// range operator, and a second address. that will be turned into a range
|
|
2405
2330
|
// later.
|
|
2406
2331
|
|
|
2407
|
-
|
|
2408
|
-
|
|
2332
|
+
// moved up
|
|
2333
|
+
// const address = this.ConsumeAddress(str, position);
|
|
2334
|
+
// if (address) return address;
|
|
2409
2335
|
|
|
2410
2336
|
// check for structured reference, if we had square brackets
|
|
2411
2337
|
|
|
@@ -2638,6 +2564,14 @@ export class Parser {
|
|
|
2638
2564
|
if (!r) return null;
|
|
2639
2565
|
position = r.position;
|
|
2640
2566
|
|
|
2567
|
+
// special hack for LOG10. ugh. can't find any other functions with
|
|
2568
|
+
// this problem, in english at least. btw what's the translation for
|
|
2569
|
+
// log10?
|
|
2570
|
+
|
|
2571
|
+
if (c.column === 8508 && r.row === 9) {
|
|
2572
|
+
return null;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2641
2575
|
const label = sheet ?
|
|
2642
2576
|
sheet + token.substr(sheet.length, position - index).toUpperCase() :
|
|
2643
2577
|
token.substr(0, position - index).toUpperCase();
|