[script] Add support for logical AND and OR

Allows the use of "&&" and "||". These are evaluated lazily and return the
evaluated sub-value which completed the operation rather than a bool. It allows
things like:

reply = cache_lookup(index) || slow_lookup(index);

If cache_lookup returns a false value (NULL, or 0) then slow_lookup is executed
and its result is placed in reply. Otherwise the result from cache_lookup is
used.
This commit is contained in:
Charlie Brej 2009-06-18 17:27:32 +01:00 committed by Ray Strode
parent 02e878a728
commit cf8c99c38f
3 changed files with 83 additions and 7 deletions

View file

@ -553,6 +553,18 @@ static script_obj* script_evaluate_cmp (script_state* state, script_exp* exp)
return script_obj_new_int (reply);
}
static script_obj* script_evaluate_logic (script_state* state, script_exp* exp)
{
script_obj* obj = script_evaluate (state, exp->data.dual.sub_a);
if (exp->type == SCRIPT_EXP_TYPE_AND && !script_obj_as_bool(obj))
return obj;
else if (exp->type == SCRIPT_EXP_TYPE_OR &&script_obj_as_bool(obj))
return obj;
script_obj_unref (obj);
obj = script_evaluate (state, exp->data.dual.sub_b);
return obj;
}
static script_obj* script_evaluate_func (script_state* state, script_exp* exp)
{
script_state localstate;
@ -647,6 +659,11 @@ static script_obj* script_evaluate (script_state* state, script_exp* exp)
{
return script_evaluate_cmp (state, exp);
}
case SCRIPT_EXP_TYPE_AND:
case SCRIPT_EXP_TYPE_OR:
{
return script_evaluate_logic (state, exp);
}
case SCRIPT_EXP_TYPE_TERM_INT:
{
return script_obj_new_int (exp->data.integer);

View file

@ -24,9 +24,11 @@
int var (exp) tm = ! ++ --
f() f[] f.a pi =
* / % md =
+ - pm = && ||
+ - pm =
< <= > >= gt =
== != eq =
&& an
|| or
= as = += -= *= %=
*/
@ -250,9 +252,9 @@ static script_exp* script_parse_exp_eq (ply_scan_t* scan)
{
script_exp* sub_a = script_parse_exp_gt (scan);
if (!sub_a) return NULL;
ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
while (1){
ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
if (peektoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
@ -269,22 +271,75 @@ static script_exp* script_parse_exp_eq (ply_scan_t* scan)
exp->data.dual.sub_b = script_parse_exp_gt (scan);
assert(exp->data.dual.sub_b); //FIXME syntax error
sub_a = exp;
curtoken = ply_scan_get_current_token(scan);
peektoken = ply_scan_peek_next_token(scan);
}
return sub_a;
}
static script_exp* script_parse_exp_an (ply_scan_t* scan)
{
script_exp* sub_a = script_parse_exp_eq (scan);
if (!sub_a) return NULL;
while (1){
ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
if (peektoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
if (curtoken->data.symbol != '&') break;
if (peektoken->data.symbol != '&') break;
ply_scan_get_next_token(scan);
ply_scan_get_next_token(scan);
script_exp* exp = malloc(sizeof(script_exp));
exp->type = SCRIPT_EXP_TYPE_AND;
exp->data.dual.sub_a = sub_a;
exp->data.dual.sub_b = script_parse_exp_eq (scan);
assert(exp->data.dual.sub_b); //FIXME syntax error
sub_a = exp;
}
return sub_a;
}
static script_exp* script_parse_exp_or (ply_scan_t* scan)
{
script_exp* sub_a = script_parse_exp_an (scan);
if (!sub_a) return NULL;
while (1){
ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
if (peektoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
if (peektoken->data.symbol != '|') break;
if (curtoken->data.symbol != '|') break;
ply_scan_get_next_token(scan);
ply_scan_get_next_token(scan);
script_exp* exp = malloc(sizeof(script_exp));
exp->type = SCRIPT_EXP_TYPE_OR;
exp->data.dual.sub_a = sub_a;
exp->data.dual.sub_b = script_parse_exp_an (scan);
assert(exp->data.dual.sub_b); //FIXME syntax error
sub_a = exp;
}
return sub_a;
}
static script_exp* script_parse_exp_as (ply_scan_t* scan)
{
script_exp* lhs = script_parse_exp_eq (scan);
script_exp* lhs = script_parse_exp_or (scan);
if (!lhs) return NULL;
ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == '=' ){
ply_scan_get_next_token(scan);
script_exp* rhs = script_parse_exp_eq(scan);
script_exp* rhs = script_parse_exp_or(scan);
assert(rhs); //FIXME syntax error
script_exp* exp = malloc(sizeof(script_exp));
exp->type = SCRIPT_EXP_TYPE_ASSIGN;
@ -514,6 +569,8 @@ static void script_parse_exp_free (script_exp* exp)
case SCRIPT_EXP_TYPE_GE:
case SCRIPT_EXP_TYPE_LT:
case SCRIPT_EXP_TYPE_LE:
case SCRIPT_EXP_TYPE_AND:
case SCRIPT_EXP_TYPE_OR:
case SCRIPT_EXP_TYPE_ASSIGN:
case SCRIPT_EXP_TYPE_HASH:
script_parse_exp_free (exp->data.dual.sub_a);

View file

@ -118,6 +118,8 @@ typedef enum
SCRIPT_EXP_TYPE_LE,
SCRIPT_EXP_TYPE_EQ,
SCRIPT_EXP_TYPE_NE,
SCRIPT_EXP_TYPE_AND,
SCRIPT_EXP_TYPE_OR,
SCRIPT_EXP_TYPE_HASH,
SCRIPT_EXP_TYPE_FUNCTION,
SCRIPT_EXP_TYPE_ASSIGN,