feat: Allow expressions in region functions and add count() accumulator (#86)
Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #86
This commit is contained in:
parent
eb5d576349
commit
7f005f171e
714
doc/teapot.lyx
714
doc/teapot.lyx
@ -6169,9 +6169,8 @@ Functions
|
|||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
This section documents all available functions in alphabetical order (except
|
This section documents all available functions.
|
||||||
for the short addressing/value fetching functions, which are listed together
|
Functions are listed within each section in alphabetical order.
|
||||||
at the beginning).
|
|
||||||
The functions are described in a C-like notation; you don't have to write
|
The functions are described in a C-like notation; you don't have to write
|
||||||
the types when you use the function in a formula.
|
the types when you use the function in a formula.
|
||||||
For example, use
|
For example, use
|
||||||
@ -6186,7 +6185,38 @@ This section documents all available functions in alphabetical order (except
|
|||||||
If no type is given for the result of a function, it means the result type
|
If no type is given for the result of a function, it means the result type
|
||||||
depends on the arguments.
|
depends on the arguments.
|
||||||
Brackets mark optional arguments.
|
Brackets mark optional arguments.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Subsubsection
|
||||||
|
Addressing/value fetching functions
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
All of these functions come in pairs, an
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
addressing
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
one whose value is a
|
||||||
|
\emph on
|
||||||
|
location
|
||||||
|
\emph default
|
||||||
|
, and a corresponding
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
fetching
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
one that produces the
|
||||||
|
\emph on
|
||||||
|
value
|
||||||
|
\emph default
|
||||||
|
of the cell at the corresponding location.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -6665,15 +6695,310 @@ X&
|
|||||||
\series default
|
\series default
|
||||||
()
|
()
|
||||||
\family default
|
\family default
|
||||||
as well, which takes exactly the same arguments with the same meanings,
|
as well, which takes exactly the same arguments with the same meanings
|
||||||
but it is rarely needed.
|
and returns the corresponding location, rather than the value there, but
|
||||||
It is provided for completeness.
|
it is rarely needed.
|
||||||
|
It is provided for completeness of the pairing described in the introduction
|
||||||
|
to this section.
|
||||||
\begin_inset Newline newline
|
\begin_inset Newline newline
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
See the FAQ below for further discussion of cell references.
|
See the FAQ below for further discussion of cell references.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Subsubsection
|
||||||
|
Accumulation functions
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
All of these functions accumulate an entire array of values in some way.
|
||||||
|
They differ only in how the values are accumulated, and otherwise have
|
||||||
|
exactly the same behavior/signature, namely:
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
|
||||||
|
\series bold
|
||||||
|
\emph on
|
||||||
|
accumulator
|
||||||
|
\family sans
|
||||||
|
\series default
|
||||||
|
\emph default
|
||||||
|
(
|
||||||
|
\family default
|
||||||
|
\series medium
|
||||||
|
[location
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
[,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
location
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
[,
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
expr
|
||||||
|
\emph default
|
||||||
|
]]])
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
|
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\series bold
|
||||||
|
accumulator
|
||||||
|
\series medium
|
||||||
|
\emph default
|
||||||
|
(
|
||||||
|
\emph on
|
||||||
|
v1
|
||||||
|
\family roman
|
||||||
|
,
|
||||||
|
\family default
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
v2,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
...
|
||||||
|
\emph default
|
||||||
|
)
|
||||||
|
\series default
|
||||||
|
The first form evaluates to the accumulation of
|
||||||
|
\emph on
|
||||||
|
expr
|
||||||
|
\emph default
|
||||||
|
computed for each location in the block defined by corner locations
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
.
|
||||||
|
(Note that negative coordinates in the block corners are simply interpreted
|
||||||
|
as zero.) The expression
|
||||||
|
\emph on
|
||||||
|
expr
|
||||||
|
\emph default
|
||||||
|
defaults to
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\series bold
|
||||||
|
@
|
||||||
|
\series default
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
– in other words, it accumulates the values in that block.
|
||||||
|
The location
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
defaults to
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
, corresponding to a one-cell block, and
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
in turn defaults to the current location.
|
||||||
|
The second form simply accumulates all of the argument values.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
The available accumulators are:
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
|
||||||
|
\series medium
|
||||||
|
int
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\series default
|
||||||
|
count Returns the number of accumulated values that are true when converted
|
||||||
|
to a boolean value.
|
||||||
|
For a block defined by corner locations
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
,
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
count(
|
||||||
|
\emph on
|
||||||
|
l1,l2
|
||||||
|
\emph default
|
||||||
|
)
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
is essentially a shorthand for
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
sum(
|
||||||
|
\emph on
|
||||||
|
l1, l2,
|
||||||
|
\emph default
|
||||||
|
int(bool()))
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
max In the first form, returns the
|
||||||
|
\emph on
|
||||||
|
location
|
||||||
|
\emph default
|
||||||
|
within the block of the maximum value being accumulated; to get the maximum
|
||||||
|
value occurring in the block with corners
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
, use
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
@(max(
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
,
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
))
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
instead.
|
||||||
|
In the second form, simply returns the maximum of the argument values.
|
||||||
|
Recall that in comparisons with the corresponding types, an empty cell
|
||||||
|
corresponds to 0, 0.0, or
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
, as needed.
|
||||||
|
This accumulator returns an error if it encounters values that are not
|
||||||
|
comparable (like a string and an integer).
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
min Just like
|
||||||
|
\family sans
|
||||||
|
max
|
||||||
|
\family default
|
||||||
|
but for the minimum of the accumulated values.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
|
||||||
|
\series medium
|
||||||
|
int
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\series default
|
||||||
|
n Returns the number of accumulated values that are not empty.
|
||||||
|
For a block defined by corner locations
|
||||||
|
\emph on
|
||||||
|
l1
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
l2
|
||||||
|
\emph default
|
||||||
|
,
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
n(
|
||||||
|
\emph on
|
||||||
|
l1,l2
|
||||||
|
\emph default
|
||||||
|
)
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
is essentially a shorthand for
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
sum(
|
||||||
|
\emph on
|
||||||
|
l1, l2,
|
||||||
|
\emph default
|
||||||
|
int(-is(@,empty)))
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
sum Returns the sum of the accumulated values (recall for strings this is
|
||||||
|
the concatenation).
|
||||||
|
This accumulator returns an error if encounters values that cannot be added
|
||||||
|
(like a string and an integer).
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Subsubsection
|
||||||
|
All other functions
|
||||||
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
@ -8177,302 +8502,6 @@ is
|
|||||||
to convert three integers to a location.
|
to convert three integers to a location.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
|
||||||
|
|
||||||
\series medium
|
|
||||||
location
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
max
|
|
||||||
\series medium
|
|
||||||
(location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
|
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
\emph default
|
|
||||||
max
|
|
||||||
\series medium
|
|
||||||
(
|
|
||||||
\emph on
|
|
||||||
v1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph on
|
|
||||||
v2
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
...)
|
|
||||||
\series default
|
|
||||||
evaluates to the maximum in the same way min does for the minimum.
|
|
||||||
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Description
|
|
||||||
|
|
||||||
\series medium
|
|
||||||
location
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
min
|
|
||||||
\series medium
|
|
||||||
(location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
|
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
\emph default
|
|
||||||
min
|
|
||||||
\series medium
|
|
||||||
(
|
|
||||||
\emph on
|
|
||||||
v1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph on
|
|
||||||
v2
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
...)
|
|
||||||
\series default
|
|
||||||
The first form evaluates to the location of the minimum of all values in
|
|
||||||
the block marked by the corners pointed to by
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
and
|
|
||||||
\emph on
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
.
|
|
||||||
Note that the empty cell is equal to 0, 0.0 and "", so if the first minimum
|
|
||||||
is an empty cell, the result will be a pointer to this cell, too.
|
|
||||||
If you are not interested in the location of the minimum but the value
|
|
||||||
itself, use @(min(
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\emph on
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
)).
|
|
||||||
The second form simply returns the smallest of the specified values, returning
|
|
||||||
an error if it encounters two that are not comparable (like a string and
|
|
||||||
an integer).
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Description
|
|
||||||
|
|
||||||
\series medium
|
|
||||||
int
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
n
|
|
||||||
\series medium
|
|
||||||
([location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
[,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
])
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
|
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
\emph default
|
|
||||||
n
|
|
||||||
\series medium
|
|
||||||
(
|
|
||||||
\family roman
|
|
||||||
\emph on
|
|
||||||
v1,
|
|
||||||
\family default
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
v2,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
...
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\series default
|
|
||||||
The first form evaluates to the number of non-empty cells in the block
|
|
||||||
with corners at location
|
|
||||||
\emph on
|
|
||||||
s l1
|
|
||||||
\emph default
|
|
||||||
and
|
|
||||||
\emph on
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
.
|
|
||||||
Location
|
|
||||||
\emph on
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
defaults to
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
; i.e., with a single location argument
|
|
||||||
\family sans
|
|
||||||
\series bold
|
|
||||||
n
|
|
||||||
\family default
|
|
||||||
\series medium
|
|
||||||
(
|
|
||||||
\family sans
|
|
||||||
\series default
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\family default
|
|
||||||
\series medium
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\series default
|
|
||||||
just tests whether the cell at
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
is empty.
|
|
||||||
Location
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
defaults to the current location.
|
|
||||||
If any dimension of either location is negative, that component is simply
|
|
||||||
taken as 0.
|
|
||||||
In other words, locations off the sheet are considered empty, but it is
|
|
||||||
not an error to access them.
|
|
||||||
\begin_inset Newline newline
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
The second form simply returns the number of its arguments which are nonempty.
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
number
|
number
|
||||||
\series medium
|
\series medium
|
||||||
@ -9117,87 +9146,6 @@ y
|
|||||||
If is omitted, the substring proceeds to the end of the string.
|
If is omitted, the substring proceeds to the end of the string.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
|
||||||
sum
|
|
||||||
\series medium
|
|
||||||
(location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
,
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
location
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\emph default
|
|
||||||
|
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\series default
|
|
||||||
\emph default
|
|
||||||
sum
|
|
||||||
\series medium
|
|
||||||
(
|
|
||||||
\family roman
|
|
||||||
\emph on
|
|
||||||
v1,
|
|
||||||
\family default
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\family roman
|
|
||||||
v2,
|
|
||||||
\family default
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\family roman
|
|
||||||
...
|
|
||||||
\emph default
|
|
||||||
)
|
|
||||||
\family default
|
|
||||||
|
|
||||||
\series default
|
|
||||||
The first form evaluates to the sum of all values in the block with corners
|
|
||||||
at locations
|
|
||||||
\emph on
|
|
||||||
l1
|
|
||||||
\emph default
|
|
||||||
and
|
|
||||||
\emph on
|
|
||||||
l2
|
|
||||||
\emph default
|
|
||||||
.
|
|
||||||
The second form simply adds all of its arguments.
|
|
||||||
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
|
@ -1175,24 +1175,59 @@ typedef void (*RegFuncUpdt)(FunctionIdentifier id, Location *loc, Token *tok,
|
|||||||
const Location *newloc, const Token* newtok);
|
const Location *newloc, const Token* newtok);
|
||||||
typedef void (*RegFuncFinl)(FunctionIdentifier id, Location *loc, Token *tok);
|
typedef void (*RegFuncFinl)(FunctionIdentifier id, Location *loc, Token *tok);
|
||||||
|
|
||||||
/* region_func -- apply an operation over a whole region */
|
/* region_macro -- apply an operation over an expression evaluated at
|
||||||
static Token region_func(RegFuncInit init, RegFuncUpdt updt, RegFuncFinl finl,
|
every location in a whole region, or every value in the region, or the
|
||||||
|
evaluated value of every argument to the macro. */
|
||||||
|
static Token region_macro(RegFuncInit init, RegFuncUpdt updt, RegFuncFinl finl,
|
||||||
FunctionIdentifier id, int argc, const Token argv[])
|
FunctionIdentifier id, int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
if (argc == 2 && argv[0].type == LOCATION && argv[1].type == LOCATION)
|
Location l1; LOCATION_GETS(l1, upd_l);
|
||||||
{
|
Location l2; LOCATION_GETS(l2, upd_l);
|
||||||
int x1 = argv[0].u.location[X];
|
bool block = argc > 0 && argc < 4; // could be a block with 1, 2, or 3 args
|
||||||
int x2 = argv[1].u.location[X];
|
if (block) {
|
||||||
posorder(&x1, &x2);
|
Token first = evaltoken(argv[0], FULL);
|
||||||
int y1 = argv[0].u.location[Y];
|
if (first.type == LOCATION) {
|
||||||
int y2 = argv[1].u.location[Y];
|
LOCATION_GETS(l1, first.u.location);
|
||||||
posorder(&y1, &y2);
|
LOCATION_GETS(l2, l1);
|
||||||
int z1 = argv[0].u.location[Z];
|
} else {
|
||||||
int z2 = argv[1].u.location[Z];
|
block = false;
|
||||||
posorder(&z1,&z2);
|
}
|
||||||
|
tfree_protected(&first, argv[0]);
|
||||||
|
if (block && argc > 1) {
|
||||||
|
Token second = evaltoken(argv[1], FULL);
|
||||||
|
if (second.type == LOCATION) {
|
||||||
|
LOCATION_GETS(l2, second.u.location);
|
||||||
|
} else {
|
||||||
|
block = false;
|
||||||
|
}
|
||||||
|
tfree_protected(&second, argv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!block) { // accumulate over all (evaluated) arguments
|
||||||
|
Location l; OLOCATION(l);
|
||||||
|
Token t = evaltoken(argv[0], FULL);
|
||||||
|
if (init != (RegFuncInit)0) init(id, &l, &t);
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
Location fake; OLOCATION(fake); fake[X] = i;
|
||||||
|
Token u = evaltoken(argv[i], FULL);
|
||||||
|
updt(id, &l, &t, &fake, &u);
|
||||||
|
tfree_protected(&u, t);
|
||||||
|
if (t.type == EEK) return t;
|
||||||
|
}
|
||||||
|
/* don't call finalize in this case because the region is fake */
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
// Evaluate over all cells in block defined by locations l1 and l2
|
||||||
|
int x1 = l1[X], x2 = l2[X]; posorder(&x1, &x2);
|
||||||
|
int y1 = l1[Y], y2 = l2[Y]; posorder(&y1, &y2);
|
||||||
|
int z1 = l1[Y], z2 = l2[Z]; posorder(&z1, &z2);
|
||||||
Location l; l[X] = x1; l[Y] = y1; l[Z] = z1;
|
Location l; l[X] = x1; l[Y] = y1; l[Z] = z1;
|
||||||
Token t = recompvalue(upd_sheet, l);
|
Token t;
|
||||||
|
if (argc == 3) {
|
||||||
|
t = evaluate_at(argv[2], upd_sheet, l);
|
||||||
|
} else {
|
||||||
|
t = recompvalue(upd_sheet, l);
|
||||||
|
}
|
||||||
if (init != (RegFuncInit)0) init(id, &l, &t);
|
if (init != (RegFuncInit)0) init(id, &l, &t);
|
||||||
if (t.type == EEK) return t;
|
if (t.type == EEK) return t;
|
||||||
|
|
||||||
@ -1201,7 +1236,12 @@ static Token region_func(RegFuncInit init, RegFuncUpdt updt, RegFuncFinl finl,
|
|||||||
for (w[Y]=y1; w[Y]<=y2; ++(w[Y]))
|
for (w[Y]=y1; w[Y]<=y2; ++(w[Y]))
|
||||||
for (w[Z]=z1; w[Z]<=z2; ++(w[Z]))
|
for (w[Z]=z1; w[Z]<=z2; ++(w[Z]))
|
||||||
{
|
{
|
||||||
Token tmp = recompvalue(upd_sheet, w);
|
Token tmp;
|
||||||
|
if (argc == 3) {
|
||||||
|
tmp = evaluate_at(argv[2], upd_sheet, w);
|
||||||
|
} else {
|
||||||
|
tmp = recompvalue(upd_sheet, w);
|
||||||
|
}
|
||||||
updt(id, &l, &t, &w, &tmp);
|
updt(id, &l, &t, &w, &tmp);
|
||||||
tfree_protected(&tmp, t);
|
tfree_protected(&tmp, t);
|
||||||
if (t.type == EEK) {
|
if (t.type == EEK) {
|
||||||
@ -1218,26 +1258,6 @@ static Token region_func(RegFuncInit init, RegFuncUpdt updt, RegFuncFinl finl,
|
|||||||
if (finl != (RegFuncFinl)0) finl(id, &l, &t);
|
if (finl != (RegFuncFinl)0) finl(id, &l, &t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
if (argc > 0) /* try to accumulate over all arguments */
|
|
||||||
{
|
|
||||||
Location l; OLOCATION(l);
|
|
||||||
Token t = argv[0];
|
|
||||||
if (init != (RegFuncInit)0) init(id, &l, &t);
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
|
||||||
Location fake; OLOCATION(fake); fake[X] = i;
|
|
||||||
updt(id, &l, &t, &fake, argv + i);
|
|
||||||
if (t.type == EEK) return t;
|
|
||||||
}
|
|
||||||
/* don't call finalize in this case because the region is fake */
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
const char* templ = _("Usage:%s(loc_start,loc_end)|%s(val2,val2,...)");
|
|
||||||
Token err;
|
|
||||||
err.type = EEK;
|
|
||||||
err.u.err = malloc(strlen(templ) + 2*MAX_FUNC_NAME_LENGTH + 1);
|
|
||||||
sprintf(err.u.err, templ, tfunc[id].name, tfunc[id].name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sum_init(FunctionIdentifier id, Location *loc, Token *tok)
|
static void sum_init(FunctionIdentifier id, Location *loc, Token *tok)
|
||||||
{
|
{
|
||||||
@ -1280,11 +1300,9 @@ static void minmax_finl(FunctionIdentifier id, Location *loc, Token *tok)
|
|||||||
LOCATION_GETS(tok->u.location, *loc);
|
LOCATION_GETS(tok->u.location, *loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void n_init(FunctionIdentifier id, Location *loc, Token *tok)
|
static void init_zero(FunctionIdentifier id, Location *loc, Token *tok)
|
||||||
{
|
{
|
||||||
assert(id == FUNC_N);
|
|
||||||
tfree(tok);
|
tfree(tok);
|
||||||
tok->type = EMPTY;
|
|
||||||
tok->type = INT;
|
tok->type = INT;
|
||||||
tok->u.integer = 0;
|
tok->u.integer = 0;
|
||||||
}
|
}
|
||||||
@ -1296,6 +1314,20 @@ static void n_updt(FunctionIdentifier id, Location *loc, Token *tok,
|
|||||||
tok->u.integer += (newtok->type != EMPTY);
|
tok->u.integer += (newtok->type != EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void count_updt(FunctionIdentifier id, Location *loc, Token *tok,
|
||||||
|
const Location* newloc, const Token *newtok)
|
||||||
|
{
|
||||||
|
assert(id == FUNC_COUNT);
|
||||||
|
Token countit = tbool(*newtok);
|
||||||
|
if (countit.type == EEK) {
|
||||||
|
tfree_protected(tok, countit);
|
||||||
|
*tok = countit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(countit.type == BOOL);
|
||||||
|
tok->u.integer += countit.u.bl;
|
||||||
|
}
|
||||||
|
|
||||||
static Token reg_disp(FunctionIdentifier self, int argc, const Token argv[])
|
static Token reg_disp(FunctionIdentifier self, int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
RegFuncInit i = 0;
|
RegFuncInit i = 0;
|
||||||
@ -1308,10 +1340,12 @@ static Token reg_disp(FunctionIdentifier self, int argc, const Token argv[])
|
|||||||
case FUNC_MAX:
|
case FUNC_MAX:
|
||||||
u = minmax_updt; f = minmax_finl; break;
|
u = minmax_updt; f = minmax_finl; break;
|
||||||
case FUNC_N:
|
case FUNC_N:
|
||||||
i = n_init; u = n_updt; break;
|
i = init_zero; u = n_updt; break;
|
||||||
|
case FUNC_COUNT:
|
||||||
|
i = init_zero; u = count_updt; break;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
return region_func(i, u, f, self, argc, argv);
|
return region_macro(i, u, f, self, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* binop_func -- common implementation of all binary operations
|
/* binop_func -- common implementation of all binary operations
|
||||||
@ -1702,8 +1736,8 @@ static Token negate_func(FunctionIdentifier self, int argc, const Token argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* table of functions */ /*{{{*/
|
/* table of functions */ /*{{{*/
|
||||||
/* The order of these entries has no influence on performance, but to stay
|
/* The order of these entries is irrelevant because they just depend on the
|
||||||
compatible, new entries should be appended. */
|
values of the FUNC_XXX enum values. */
|
||||||
Tfunc tfunc[]=
|
Tfunc tfunc[]=
|
||||||
{
|
{
|
||||||
/* Operators in order of increasing precedence */
|
/* Operators in order of increasing precedence */
|
||||||
@ -1782,10 +1816,11 @@ Tfunc tfunc[]=
|
|||||||
[FUNC_CENTER] = { "center", self_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_CENTER] = { "center", self_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
|
||||||
/* Block operations */
|
/* Block operations */
|
||||||
[FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_COUNT] = { "count", reg_disp, PREFIX_FUNC, MACRO, 0 },
|
||||||
[FUNC_MIN] = { "min", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, MACRO, 0 },
|
||||||
[FUNC_N] = { "n", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_MIN] = { "min", reg_disp, PREFIX_FUNC, MACRO, 0 },
|
||||||
[FUNC_SUM] = { "sum", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_N] = { "n", reg_disp, PREFIX_FUNC, MACRO, 0 },
|
||||||
|
[FUNC_SUM] = { "sum", reg_disp, PREFIX_FUNC, MACRO, 0 },
|
||||||
|
|
||||||
/* String functions */
|
/* String functions */
|
||||||
[FUNC_LEN] = { "len", len_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_LEN] = { "len", len_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
@ -51,6 +51,8 @@ typedef enum
|
|||||||
|
|
||||||
FUNC_DIM, FUNC_ITALIC,
|
FUNC_DIM, FUNC_ITALIC,
|
||||||
|
|
||||||
|
FUNC_COUNT,
|
||||||
|
|
||||||
N_FUNCTION_IDS
|
N_FUNCTION_IDS
|
||||||
} FunctionIdentifier;
|
} FunctionIdentifier;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user