feat: add if() conditional operator and update docs (#92)
Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #92
This commit is contained in:
parent
7b794f90b9
commit
5176005bb3
1
NEWS
1
NEWS
@ -19,6 +19,7 @@ o Comparison operators return bool rather than int (Note this can be a breaking
|
|||||||
in a numerical computation.)
|
in a numerical computation.)
|
||||||
o Foreground and background color style attributes for cells.
|
o Foreground and background color style attributes for cells.
|
||||||
o Variable row height for cells.
|
o Variable row height for cells.
|
||||||
|
o Addition of an if() conditional operator.
|
||||||
o Addition of a find() macro to search for a cell satisfying a condition.
|
o Addition of a find() macro to search for a cell satisfying a condition.
|
||||||
o Addition of an is(VALUE, TYPE, TYPE,...) predicate
|
o Addition of an is(VALUE, TYPE, TYPE,...) predicate
|
||||||
o Addition of functions for unit displacements in the six cardinal directions
|
o Addition of functions for unit displacements in the six cardinal directions
|
||||||
|
400
doc/teapot.lyx
400
doc/teapot.lyx
@ -3916,11 +3916,17 @@ underline
|
|||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Subsubsection
|
\begin_layout Subsubsection
|
||||||
|
\begin_inset CommandInset label
|
||||||
|
LatexCommand label
|
||||||
|
name "subsec:Shadowed"
|
||||||
|
|
||||||
|
\end_inset
|
||||||
|
|
||||||
Shadowed
|
Shadowed
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
This attribute is a s simple true-false flag set with shadowed(), defaulting
|
This attribute is a simple true-false flag set with shadowed(), defaulting
|
||||||
to false.
|
to false.
|
||||||
When true, it means that the left neighbour cell will additionally use
|
When true, it means that the left neighbour cell will additionally use
|
||||||
the display room of this cell (and all following shadowed cells to the
|
the display room of this cell (and all following shadowed cells to the
|
||||||
@ -5791,7 +5797,7 @@ or
|
|||||||
|
|
||||||
\series default
|
\series default
|
||||||
\emph default
|
\emph default
|
||||||
y evaluates to the logical disjunction of boolean values
|
y evaluates to the logical disjunction of Boolean values
|
||||||
\emph on
|
\emph on
|
||||||
x
|
x
|
||||||
\emph default
|
\emph default
|
||||||
@ -5820,6 +5826,25 @@ x
|
|||||||
y
|
y
|
||||||
\emph default
|
\emph default
|
||||||
otherwise.
|
otherwise.
|
||||||
|
Note the rules for these Boolean operators means they can also sometimes
|
||||||
|
be used for conditional-like behavior: Suppose you want to use the value
|
||||||
|
of the cell labeled
|
||||||
|
\family sans
|
||||||
|
OPTION
|
||||||
|
\family default
|
||||||
|
if it is non-empty and non-zero, and the value of the cell labeled
|
||||||
|
\family sans
|
||||||
|
DEFAULT
|
||||||
|
\family default
|
||||||
|
otherwise.
|
||||||
|
Since the empty and zero values are considered false, you can achieve this
|
||||||
|
with:
|
||||||
|
\family sans
|
||||||
|
|
||||||
|
\begin_inset Newline newline
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
@(OPTION) or @(DEFAULT)
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -6814,13 +6839,14 @@ $
|
|||||||
\series bold
|
\series bold
|
||||||
X
|
X
|
||||||
\series default
|
\series default
|
||||||
(SRC,REF,1,1,1)
|
(SRC,REF,fix,fix,fix)
|
||||||
\family default
|
\family default
|
||||||
is identical to
|
is identical to
|
||||||
\family sans
|
\family sans
|
||||||
@(SRC)
|
@(SRC)
|
||||||
\family default
|
\family default
|
||||||
, but you should certainly prefer the latter for clarity of expression.
|
, but you should certainly prefer the latter for clarity of expression when
|
||||||
|
that's what you mean.
|
||||||
\begin_inset Newline newline
|
\begin_inset Newline newline
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
@ -8251,6 +8277,102 @@ hexact used as a keyword to the string() function; listed here to record
|
|||||||
that this identifier may not be used as a cell label.
|
that this identifier may not be used as a cell label.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
if
|
||||||
|
\series medium
|
||||||
|
(
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
[,
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
then_expr
|
||||||
|
\emph default
|
||||||
|
[
|
||||||
|
\emph on
|
||||||
|
,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
else_expr
|
||||||
|
\emph default
|
||||||
|
]]) Typical conditional expression.
|
||||||
|
First the
|
||||||
|
\series default
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
is evaluated.
|
||||||
|
If its value is falsy, then the value of the
|
||||||
|
\emph on
|
||||||
|
else_expr
|
||||||
|
\emph default
|
||||||
|
is returned if it is present, or else the empty value is returned.
|
||||||
|
(If you just want to return the value of the
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
when it corresponds to boolean false, use
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
then_expr
|
||||||
|
\emph default
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
instead.) If the value of
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
is truthy, then the value of the
|
||||||
|
\emph on
|
||||||
|
then_expr
|
||||||
|
\emph default
|
||||||
|
is returned if it is present, otherwise the value of the
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
is returned.
|
||||||
|
Note that if() is short-circuiting in the sense that the
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
is always evaluated but at most one of
|
||||||
|
\emph on
|
||||||
|
then_expr
|
||||||
|
\emph default
|
||||||
|
and
|
||||||
|
\emph on
|
||||||
|
else_expr
|
||||||
|
\emph default
|
||||||
|
is (note, if evaluating
|
||||||
|
\emph on
|
||||||
|
condition
|
||||||
|
\emph default
|
||||||
|
results in an error, then this expression produces an error without evaluating
|
||||||
|
either
|
||||||
|
\emph on
|
||||||
|
then_expr
|
||||||
|
\emph default
|
||||||
|
or
|
||||||
|
\emph on
|
||||||
|
else_expr
|
||||||
|
\emph default
|
||||||
|
).
|
||||||
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
@ -8262,7 +8384,7 @@ int
|
|||||||
\series default
|
\series default
|
||||||
int
|
int
|
||||||
\series medium
|
\series medium
|
||||||
[([int|float|string|empty
|
[([int|boolean|float|string|empty
|
||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
@ -8284,14 +8406,14 @@ converts to an
|
|||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\emph default
|
\emph default
|
||||||
integer the given integer, float, string, or empty value
|
integer the given integer, boolean, float, string, or empty value
|
||||||
\emph on
|
\emph on
|
||||||
x.
|
x.
|
||||||
|
|
||||||
\emph default
|
\emph default
|
||||||
(The latter converts to 0.) The optional second argument must be the name
|
(The latter converts to 0, and Boolean true converts to 1 and false to 0.)
|
||||||
of one of the functions that produces a floating point integral value from
|
The optional second argument must be the name of one of the functions that
|
||||||
a float, i.e.,
|
produces a floating point integral value from a float, i.e.,
|
||||||
\family sans
|
\family sans
|
||||||
\series bold
|
\series bold
|
||||||
ceil
|
ceil
|
||||||
@ -10208,13 +10330,26 @@ If your machine uses binary floating point arithmetic, and chances are that
|
|||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Quote
|
\begin_layout Quote
|
||||||
|
|
||||||
|
\family sans
|
||||||
0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1
|
0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
You expect to see 1.0 as result, and indeed that is what you get.
|
You expect to see
|
||||||
Now you compare this result to the constant 1.0, but surprisingly for many
|
\family sans
|
||||||
users, the result is 0.
|
1.0
|
||||||
|
\family default
|
||||||
|
as result, and indeed that is what you get.
|
||||||
|
Now you compare this result to the constant
|
||||||
|
\family sans
|
||||||
|
1.0
|
||||||
|
\family default
|
||||||
|
, but surprisingly for many users, the result is
|
||||||
|
\family sans
|
||||||
|
false
|
||||||
|
\family default
|
||||||
|
.
|
||||||
Appearantly, 1.0 is unequal 1.0 for
|
Appearantly, 1.0 is unequal 1.0 for
|
||||||
\noun on
|
\noun on
|
||||||
teapot
|
teapot
|
||||||
@ -10275,90 +10410,179 @@ teapot
|
|||||||
has no way to hide cells, but you have three dimensions.
|
has no way to hide cells, but you have three dimensions.
|
||||||
Just use one or more layers for such cells and give each cell a label in
|
Just use one or more layers for such cells and give each cell a label in
|
||||||
order to reference and find it easily.
|
order to reference and find it easily.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
If you're really wedded to cells that calculate but don't appear on the
|
||||||
|
display, you can use such hacks as
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
shadowing
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
a cell with computations in it (see subsection
|
||||||
|
\begin_inset CommandInset ref
|
||||||
|
LatexCommand ref
|
||||||
|
reference "subsec:Shadowed"
|
||||||
|
plural "false"
|
||||||
|
caps "false"
|
||||||
|
noprefix "false"
|
||||||
|
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
) or making its foreground and background the same color, etc.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Subsection
|
\begin_layout Subsection
|
||||||
Why is there no conditional evaluation?
|
Can you share a trick for multi-way dispatch?
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
There is no special operator or function for conditional evaluation.
|
By now,
|
||||||
I could add one easily, but then next someone would ask for loops and someone
|
|
||||||
else for user-defined functions, variables and so on.
|
|
||||||
If you need a programming language, you know where to find it.
|
|
||||||
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Standard
|
|
||||||
But don't worry.
|
|
||||||
The answer is, that conditional evaluation comes for free with
|
|
||||||
\noun on
|
\noun on
|
||||||
teapot
|
teapot
|
||||||
\noun default
|
\noun default
|
||||||
's orthogonal cell addressing.
|
has a conventional
|
||||||
As an example, depending on the cell labelled
|
\family sans
|
||||||
\family typewriter
|
if()
|
||||||
X
|
|
||||||
\family default
|
\family default
|
||||||
being negative or not, you want the result to be the string
|
operator for convenience when you want to choose between two alternatives
|
||||||
\family typewriter
|
based on a single Boolean condition.
|
||||||
"BAD
|
However, a methodology used to provide conditional behavior before
|
||||||
|
\family sans
|
||||||
|
if()
|
||||||
\family default
|
\family default
|
||||||
or
|
was implemented is still worth knowing about, because it can actually provide
|
||||||
|
more flexibility and power, particularly in providing for multi-way dispatch.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
For example, suppose that you want to produce one of the strings
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
\family typewriter
|
\family typewriter
|
||||||
"GOOD"
|
NONE
|
||||||
|
\family default
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
,
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\family typewriter
|
||||||
|
ONE
|
||||||
|
\family default
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
, or
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\family typewriter
|
||||||
|
MANY
|
||||||
|
\family default
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
depending on whether the cell labeled
|
||||||
|
\family typewriter
|
||||||
|
INPUT
|
||||||
|
\family default
|
||||||
|
has a value that is zero, one, or greater than one, respectively.
|
||||||
|
Here's one convenient way to arrange that.
|
||||||
|
In some scratch area, create a cell labeled
|
||||||
|
\family typewriter
|
||||||
|
OUTPUT
|
||||||
|
\family default
|
||||||
|
that contains the string
|
||||||
|
\family typewriter
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
NONE
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\family default
|
||||||
|
with the two successive cells to the right containing
|
||||||
|
\family typewriter
|
||||||
|
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
ONE
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\family default
|
||||||
|
and
|
||||||
|
\family typewriter
|
||||||
|
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
MANY
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
\family default
|
\family default
|
||||||
.
|
.
|
||||||
This is a solution:
|
Then the expression
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Quote
|
\begin_layout Quote
|
||||||
eval(BAD + &((@(X)>=0),0,0))
|
|
||||||
|
\family sans
|
||||||
|
@(OUTPUT, min(@(INPUT), 2))
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
Note this is making use of the fact that you can add locations in the natural
|
does the trick: the (optional) second argument of the fetch function
|
||||||
way.
|
\family sans
|
||||||
The cell labelled
|
@()
|
||||||
\family typewriter
|
|
||||||
BAD
|
|
||||||
\family default
|
\family default
|
||||||
contains the string
|
adds to the X-coordinate of the
|
||||||
\family typewriter
|
\family typewriter
|
||||||
"BAD"
|
OUTPUT
|
||||||
\family default
|
\family default
|
||||||
, its right neighbour contains the string
|
location, and the
|
||||||
|
\family sans
|
||||||
|
min()
|
||||||
|
\family default
|
||||||
|
makes sure the amount being added to that coordinate is no more than two.
|
||||||
|
(Note that for this to work exactly as shown assumes that the value in
|
||||||
|
the
|
||||||
\family typewriter
|
\family typewriter
|
||||||
"GOOD"
|
INPUT
|
||||||
|
\family default
|
||||||
|
cell is always a non-negative integer.
|
||||||
|
You should relatively easily be able to enhance the given expression to
|
||||||
|
handle other possibilities for
|
||||||
|
\family typewriter
|
||||||
|
INPUT
|
||||||
|
\family default
|
||||||
|
, for example if it might be negative or have a floating-point value.) If
|
||||||
|
you want to use Boolean conditions on input variables in a similar way,
|
||||||
|
you can convert them to integers with
|
||||||
|
\family sans
|
||||||
|
int()
|
||||||
\family default
|
\family default
|
||||||
.
|
.
|
||||||
If you have nested conditions, you could weight them with 1, 2, 4 and so
|
|
||||||
on to address a bigger range of cells.
|
|
||||||
Alternatively, you could make use of all three dimensions for nested conditions.
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Standard
|
|
||||||
Sometimes you can also get conditional-like behavior using the logical expressio
|
|
||||||
ns.
|
|
||||||
Suppose you want to use the value of the cell labeled
|
|
||||||
\family sans
|
|
||||||
OPTION
|
|
||||||
\family default
|
|
||||||
if it is non-empty and non-zero, and the value of the cell labeled
|
|
||||||
\family sans
|
|
||||||
DEFAULT
|
|
||||||
\family default
|
|
||||||
otherwise.
|
|
||||||
Since the empty and zero values are considered false, but the logical operators
|
|
||||||
short-circuit and preserve the original values of their arguments, you
|
|
||||||
can achieve this with:
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Standard
|
|
||||||
|
|
||||||
\family sans
|
|
||||||
@(OPTION) or @(DEFAULT)
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Subsection
|
\begin_layout Subsection
|
||||||
@ -10399,8 +10623,16 @@ absolute
|
|||||||
\family sans
|
\family sans
|
||||||
R(,-1)+1
|
R(,-1)+1
|
||||||
\family default
|
\family default
|
||||||
or up()+1 to add one to the value of the cell which is one up from the
|
or
|
||||||
current cell (all of these expressions work).
|
\family sans
|
||||||
|
R(up)+1
|
||||||
|
\family default
|
||||||
|
or
|
||||||
|
\family sans
|
||||||
|
up()+1
|
||||||
|
\family default
|
||||||
|
to add one to the value of the cell which is up one position from the current
|
||||||
|
cell (all of these expressions work).
|
||||||
Then you can fill that expression downwards and get your column of consecutive
|
Then you can fill that expression downwards and get your column of consecutive
|
||||||
numbers.
|
numbers.
|
||||||
\end_layout
|
\end_layout
|
||||||
@ -10413,9 +10645,9 @@ But these sorts of relative expressions only keep working if the cells move
|
|||||||
\family sans
|
\family sans
|
||||||
R(,-1)
|
R(,-1)
|
||||||
\family default
|
\family default
|
||||||
) and you insert another row in between them, your references will be all
|
) and you insert another row in between them, your references will all be
|
||||||
messed up.
|
messed up.
|
||||||
There is value to
|
Thus, there is value to
|
||||||
\begin_inset Quotes eld
|
\begin_inset Quotes eld
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
@ -10432,11 +10664,13 @@ referring to what you want.
|
|||||||
\begin_inset Quotes erd
|
\begin_inset Quotes erd
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
|
Note that labeled cells handle some aspects of this desired behavior, because
|
||||||
|
the label goes with the cell when it is moved in the spreadsheet
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
To provide for this need,
|
However, to provide for the cases when just labels by themselves are not
|
||||||
|
enough,
|
||||||
\noun on
|
\noun on
|
||||||
teapot
|
teapot
|
||||||
\noun default
|
\noun default
|
||||||
@ -10541,7 +10775,11 @@ X(SRC,REF,fix,fix,fix)
|
|||||||
\family sans
|
\family sans
|
||||||
@(SRC)
|
@(SRC)
|
||||||
\family default
|
\family default
|
||||||
, but the intent of the latter is much clearer.
|
, although of course if that's all you want, there's no need to use
|
||||||
|
\family sans
|
||||||
|
X()
|
||||||
|
\family default
|
||||||
|
.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
@ -10559,15 +10797,15 @@ do the right thing
|
|||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
as you copy and move either that formula or the referred-to data? The response
|
as you copy and move either that formula or the referred-to data? The response
|
||||||
to this is that in a typical spreadsheet, there are only a small number
|
to this criticism is that in a typical spreadsheet, there are only a small
|
||||||
of fundamental references, and all other references derive from them in
|
number of fundamental references, and all other references derive from
|
||||||
this way.
|
them in a natural way.
|
||||||
So you generally only need a few labels, and by taking just a little extra
|
So you generally only need a few labels, and by taking just a little extra
|
||||||
time to apply those labels and refer to them in initial formulas, you are
|
time to apply those labels and refer to them in initial formulas, you are
|
||||||
making the semantics of your references much clearer and in essence documenting
|
making the semantics of your references much clearer and in essence documenting
|
||||||
them within your spreadsheet.
|
them within your spreadsheet.
|
||||||
This modicum of extra effort will therefore be repaid in an easier-to-use,
|
This modicum of extra effort will be repaid by a spreadsheet that is easier
|
||||||
easier-to-understand, and easier-to-maintain and update spreadsheet.
|
to use, understand, maintain, and update.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\end_body
|
\end_body
|
||||||
|
@ -684,6 +684,39 @@ static Token blop_macro(FunctionIdentifier self, int argc, const Token argv[])
|
|||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
|
/* if_macro -- traditional if-then-else expression */ /*{{{*/
|
||||||
|
static Token if_macro(FunctionIdentifier self, int argc, const Token argv[]) {
|
||||||
|
assert(self == FUNC_IF);
|
||||||
|
if (argc < 1 || argc > 3) {
|
||||||
|
Token error;
|
||||||
|
const char *usage = _("Usage: if(expr[, true_expr[, false_expr]])");
|
||||||
|
return duperror(&error, usage);
|
||||||
|
}
|
||||||
|
Token tcond = evaltoken(argv[0], FULL);
|
||||||
|
Token cond = tbool(tcond);
|
||||||
|
if (cond.type == EEK) return cond;
|
||||||
|
assert(cond.type == BOOL); // Since it's bool no need to worry about freeing
|
||||||
|
if (cond.u.bl) {
|
||||||
|
/* Condition is true. Return value of second argument or of first
|
||||||
|
argument if there is no second argument */
|
||||||
|
if (argc >= 2) {
|
||||||
|
tfree(&tcond);
|
||||||
|
return evaltoken(argv[1], FULL);
|
||||||
|
}
|
||||||
|
return tcond;
|
||||||
|
}
|
||||||
|
/* Condition is false. Return value of third argument or empty if there is
|
||||||
|
none.
|
||||||
|
*/
|
||||||
|
tfree(&tcond);
|
||||||
|
Token result;
|
||||||
|
result.type = EMPTY;
|
||||||
|
if (argc >= 3) {
|
||||||
|
result = evaltoken(argv[2], FULL);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* self function, typically used for keywords */ /*{{{*/
|
/* self function, typically used for keywords */ /*{{{*/
|
||||||
static Token self_func(FunctionIdentifier self, int argc, const Token argv[])
|
static Token self_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
@ -1782,6 +1815,7 @@ Tfunc tfunc[]=
|
|||||||
/* Boolean functions */
|
/* Boolean functions */
|
||||||
[FUNC_AND] = { "and", blop_macro, INFIX_BOOL, MACRO, 0 },
|
[FUNC_AND] = { "and", blop_macro, INFIX_BOOL, MACRO, 0 },
|
||||||
[FUNC_FALSE] = { "false", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_FALSE] = { "false", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
[FUNC_IF] = { "if", if_macro, PREFIX_FUNC, MACRO, 0 },
|
||||||
[FUNC_OR] = { "or", blop_macro, INFIX_BOOL, MACRO, 0 },
|
[FUNC_OR] = { "or", blop_macro, INFIX_BOOL, MACRO, 0 },
|
||||||
[FUNC_TRUE] = { "true", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_TRUE] = { "true", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ typedef enum
|
|||||||
|
|
||||||
FUNC_COUNT,
|
FUNC_COUNT,
|
||||||
|
|
||||||
|
FUNC_IF,
|
||||||
|
|
||||||
N_FUNCTION_IDS
|
N_FUNCTION_IDS
|
||||||
} FunctionIdentifier;
|
} FunctionIdentifier;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user