mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Add "eval()" built-in function.
This commit is contained in:
@@ -166,7 +166,7 @@
|
||||
(list "_" "abs" "access" "adawn" "adusk" "ampm" "ansicolor" "args" "asc"
|
||||
"baseyr" "catch" "catcherr" "char" "choose" "coerce" "columns" "current" "date"
|
||||
"datepart" "datetime" "dawn" "day" "daysinmon" "defined" "dosubst"
|
||||
"dusk" "easterdate" "escape" "evaltrig" "filedate" "filedatetime"
|
||||
"dusk" "easterdate" "escape" "eval" "evaltrig" "filedate" "filedatetime"
|
||||
"filedir" "filename" "getenv" "hebdate" "hebday" "hebmon" "hebyear"
|
||||
"hour" "htmlescape" "htmlstriptags" "iif" "index" "isany" "isconst" "isdst"
|
||||
"isleap" "isomitted" "language" "localtoutc" "lower" "max" "min"
|
||||
|
||||
@@ -3512,6 +3512,24 @@ If the optional \fIadd_quotes\fR argument is supplied and is non-zero, then
|
||||
the return value from \fBescape\fR will include surrounding double-quotes.
|
||||
.RE
|
||||
.TP
|
||||
.B eval(s_arg)
|
||||
Parses the string \fIarg\fR as an expression and evaluates it, returning
|
||||
the result. Note that any variable names in the parsed expression refer
|
||||
to global variables, not any local variables. For example, consider this:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
SET x 2
|
||||
FSET f(x) x + eval("1 + x")
|
||||
REM MSG F is [f(9)]
|
||||
.fi
|
||||
.PP
|
||||
The result will be "F is 12" because the reference to \fIx\fR inside the
|
||||
\fBeval()\fR argument refers to the \fIglobal\fR variable \fIx\fR and
|
||||
not the function argument.
|
||||
.PP
|
||||
.RE
|
||||
.TP
|
||||
.B evaltrig(s_trigger [,dq_start])
|
||||
Evaluates \fItrigger\fR as if it were a REM or IFTRIG trigger specification
|
||||
and returns the trigger date as a \fBDATE\fR (or as a \fBDATETIME\fR if
|
||||
|
||||
66
src/expr.c
66
src/expr.c
@@ -497,6 +497,7 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||
old function call API by building up a bundle of evaluated
|
||||
arguments */
|
||||
info.nargs = node->num_kids;
|
||||
info.nonconst = 0;
|
||||
|
||||
if (info.nargs) {
|
||||
if (info.nargs <= STACK_ARGS_MAX) {
|
||||
@@ -548,6 +549,11 @@ eval_builtin(expr_node *node, Value *locals, Value *ans, int *nonconst)
|
||||
fprintf(ErrFp, ") => ");
|
||||
}
|
||||
r = f->func(&info);
|
||||
/* Propagate non-constness */
|
||||
if (info.nonconst) {
|
||||
nonconst_debug(*nonconst, tr("Non-constant built-in function `%s' makes expression non-constant"), f->name);
|
||||
*nonconst = 1;
|
||||
}
|
||||
if (r == OK) {
|
||||
/* All went well; copy the result destructively */
|
||||
(*ans) = info.retval;
|
||||
@@ -2589,7 +2595,7 @@ static expr_node *parse_expression_aux(char const **e, int *r, Var *locals, int
|
||||
/* */
|
||||
/* parse_expression - top-level expression-parsing function */
|
||||
/* */
|
||||
/* *e points to string being parsed; *e will be updates */
|
||||
/* *e points to string being parsed; *e will be updated */
|
||||
/* r points to a location for the return code (OK or an error) */
|
||||
/* locals is an array of local function arguments, if any */
|
||||
/* */
|
||||
@@ -2625,36 +2631,38 @@ expr_node *parse_expression(char const **e, int *r, Var *locals)
|
||||
fprintf(ErrFp, " Unparsed: %s\n", *e);
|
||||
}
|
||||
}
|
||||
if (*r == E_EXPECT_COMMA ||
|
||||
*r == E_MISS_RIGHT_PAREN ||
|
||||
*r == E_EXPECTING_EOL ||
|
||||
*r == E_2MANY_ARGS ||
|
||||
*r == E_2FEW_ARGS ||
|
||||
*r == E_PARSE_ERR ||
|
||||
*r == E_EOLN ||
|
||||
*r == E_BAD_NUMBER ||
|
||||
*r == E_BAD_DATE ||
|
||||
*r == E_BAD_TIME ||
|
||||
*r == E_ILLEGAL_CHAR) {
|
||||
end_of_expr = find_end_of_expr(orig);
|
||||
while (**e && isempty(**e)) {
|
||||
(*e)++;
|
||||
}
|
||||
while (*orig && ((orig < end_of_expr) || (orig <= *e))) {
|
||||
if (*orig == '\n') {
|
||||
fprintf(ErrFp, " ");
|
||||
} else {
|
||||
fprintf(ErrFp, "%c", *orig);
|
||||
if (!SuppressErrorOutputInCatch) {
|
||||
if (*r == E_EXPECT_COMMA ||
|
||||
*r == E_MISS_RIGHT_PAREN ||
|
||||
*r == E_EXPECTING_EOL ||
|
||||
*r == E_2MANY_ARGS ||
|
||||
*r == E_2FEW_ARGS ||
|
||||
*r == E_PARSE_ERR ||
|
||||
*r == E_EOLN ||
|
||||
*r == E_BAD_NUMBER ||
|
||||
*r == E_BAD_DATE ||
|
||||
*r == E_BAD_TIME ||
|
||||
*r == E_ILLEGAL_CHAR) {
|
||||
end_of_expr = find_end_of_expr(orig);
|
||||
while (**e && isempty(**e)) {
|
||||
(*e)++;
|
||||
}
|
||||
orig++;
|
||||
while (*orig && ((orig < end_of_expr) || (orig <= *e))) {
|
||||
if (*orig == '\n') {
|
||||
fprintf(ErrFp, " ");
|
||||
} else {
|
||||
fprintf(ErrFp, "%c", *orig);
|
||||
}
|
||||
orig++;
|
||||
}
|
||||
fprintf(ErrFp, "\n");
|
||||
orig = o2;
|
||||
while (*orig && (orig < *e || isspace(*orig))) {
|
||||
orig++;
|
||||
fprintf(ErrFp, " ");
|
||||
}
|
||||
fprintf(ErrFp, "^-- %s\n", tr("here"));
|
||||
}
|
||||
fprintf(ErrFp, "\n");
|
||||
orig = o2;
|
||||
while (*orig && (orig < *e || isspace(*orig))) {
|
||||
orig++;
|
||||
fprintf(ErrFp, " ");
|
||||
}
|
||||
fprintf(ErrFp, "^-- %s\n", tr("here"));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
22
src/funcs.c
22
src/funcs.c
@@ -99,6 +99,7 @@ static int FDosubst (func_info *);
|
||||
static int FDusk (func_info *);
|
||||
static int FEasterdate (func_info *);
|
||||
static int FEscape (func_info *);
|
||||
static int FEval (func_info *);
|
||||
static int FEvalTrig (func_info *);
|
||||
static int FFiledate (func_info *);
|
||||
static int FFiledatetime (func_info *);
|
||||
@@ -268,6 +269,7 @@ BuiltinFunc Func[] = {
|
||||
{ "dusk", 0, 1, 0, FDusk, NULL },
|
||||
{ "easterdate", 0, 1, 0, FEasterdate, NULL },
|
||||
{ "escape", 1, 2, 1, FEscape, NULL },
|
||||
{ "eval", 1, 1, 1, FEval, NULL },
|
||||
{ "evaltrig", 1, 2, 0, FEvalTrig, NULL },
|
||||
{ "filedate", 1, 1, 0, FFiledate, NULL },
|
||||
{ "filedatetime", 1, 1, 0, FFiledatetime, NULL },
|
||||
@@ -3969,6 +3971,26 @@ FWeekno(func_info *info)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
FEval(func_info *info)
|
||||
{
|
||||
expr_node *n;
|
||||
int r;
|
||||
|
||||
ASSERT_TYPE(0, STR_TYPE);
|
||||
char const *e = ARGSTR(0);
|
||||
|
||||
n = parse_expression(&e, &r, NULL);
|
||||
if (r != OK) {
|
||||
info->nonconst = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = evaluate_expr_node(n, NULL, &(info->retval), &(info->nonconst));
|
||||
free_expr_tree(n);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
FEvalTrig(func_info *info)
|
||||
{
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef struct {
|
||||
int nargs;
|
||||
Value *args;
|
||||
Value retval;
|
||||
int nonconst;
|
||||
} func_info;
|
||||
|
||||
/* Forward reference */
|
||||
|
||||
@@ -16471,6 +16471,49 @@ a 1
|
||||
|
||||
DEBUG -n
|
||||
|
||||
# Test eval
|
||||
DEBUG +x
|
||||
set a eval("1 + 2")
|
||||
eval("1 + 2") => 1 + 2 => 3
|
||||
3
|
||||
dump -c a
|
||||
Variable Value
|
||||
|
||||
a 3 <const>
|
||||
set a eval("today() + 1")
|
||||
eval("today() + 1") => today() => 1991-02-16
|
||||
1991-02-16 + 1 => 1991-02-17
|
||||
1991-02-17
|
||||
dump -c a
|
||||
Variable Value
|
||||
|
||||
a 1991-02-17
|
||||
set a eval("1 +")
|
||||
eval("1 +") => ../tests/test.rem(1569): Unexpected end of line
|
||||
1 +
|
||||
^-- here
|
||||
Unexpected end of line
|
||||
set a eval("1/0")
|
||||
eval("1/0") => 1 / 0 => Division by zero
|
||||
../tests/test.rem(1570): `/': Division by zero
|
||||
Division by zero
|
||||
set a eval("1 / / 2")
|
||||
eval("1 / / 2") => ../tests/test.rem(1571): Illegal character `/'
|
||||
1 / / 2
|
||||
^-- here
|
||||
Illegal character
|
||||
set a catch(eval("1 +"), 33)
|
||||
eval("1 +") => Unexpected end of line
|
||||
catch(*Unexpected end of line*, 33) => 33
|
||||
set a catch(eval("1/0"), 34)
|
||||
eval("1/0") => 1 / 0 => Division by zero
|
||||
Division by zero
|
||||
catch(*Division by zero*, 34) => 34
|
||||
set a catch(eval("1 / / 2"), 35)
|
||||
eval("1 / / 2") => Illegal character
|
||||
catch(*Illegal character*, 35) => 35
|
||||
DEBUG -x
|
||||
|
||||
DEBUG -e
|
||||
Variable hash table statistics:
|
||||
Entries: 100143; Buckets: 87719; Non-empty Buckets: 66301
|
||||
@@ -24424,6 +24467,7 @@ dosubst
|
||||
dusk
|
||||
easterdate
|
||||
escape
|
||||
eval
|
||||
evaltrig
|
||||
filedate
|
||||
filedatetime
|
||||
|
||||
@@ -1560,6 +1560,20 @@ dump -c a
|
||||
|
||||
DEBUG -n
|
||||
|
||||
# Test eval
|
||||
DEBUG +x
|
||||
set a eval("1 + 2")
|
||||
dump -c a
|
||||
set a eval("today() + 1")
|
||||
dump -c a
|
||||
set a eval("1 +")
|
||||
set a eval("1/0")
|
||||
set a eval("1 / / 2")
|
||||
set a catch(eval("1 +"), 33)
|
||||
set a catch(eval("1/0"), 34)
|
||||
set a catch(eval("1 / / 2"), 35)
|
||||
DEBUG -x
|
||||
|
||||
DEBUG -e
|
||||
|
||||
# Output expression-node stats
|
||||
|
||||
Reference in New Issue
Block a user