summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commodity.cc4
-rw-r--r--src/generate.cc3
-rw-r--r--src/parser.cc36
-rw-r--r--src/token.cc23
-rw-r--r--src/token.h3
5 files changed, 66 insertions, 3 deletions
diff --git a/src/commodity.cc b/src/commodity.cc
index 08252cf4..243d2a6c 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -473,8 +473,12 @@ namespace {
return std::strcmp(buf, "and") == 0;
case 'd':
return std::strcmp(buf, "div") == 0;
+ case 'e':
+ return std::strcmp(buf, "else") == 0;
case 'f':
return std::strcmp(buf, "false") == 0;
+ case 'i':
+ return std::strcmp(buf, "if") == 0;
case 'o':
return std::strcmp(buf, "or") == 0;
case 'n':
diff --git a/src/generate.cc b/src/generate.cc
index 725c4a6c..6d1bfb1a 100644
--- a/src/generate.cc
+++ b/src/generate.cc
@@ -171,7 +171,8 @@ void generate_posts_iterator::generate_commodity(std::ostream& out)
}
while (comm == "h" || comm == "m" || comm == "s" ||
comm == "and" || comm == "div" || comm == "false" ||
- comm == "or" || comm == "not" || comm == "true");
+ comm == "or" || comm == "not" || comm == "true" ||
+ comm == "if" || comm == "else");
out << comm;
}
diff --git a/src/parser.cc b/src/parser.cc
index 396d3a64..b3457f08 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -382,7 +382,41 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
_("%1 operator not followed by argument") << tok.symbol);
node->set_right(subnode);
- } else {
+ }
+ else if (tok.kind == token_t::KW_IF) {
+ ptr_op_t if_op(parse_or_expr(in, tflags));
+ if (! if_op)
+ throw_(parse_error, _("'if' keyword not followed by argument"));
+
+ tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ if (tok.kind == token_t::KW_ELSE) {
+ ptr_op_t else_op(parse_or_expr(in, tflags));
+ if (! else_op)
+ throw_(parse_error, _("'else' keyword not followed by argument"));
+
+ ptr_op_t subnode = new op_t(op_t::O_COLON);
+ subnode->set_left(node);
+ subnode->set_right(else_op);
+
+ node = new op_t(op_t::O_QUERY);
+ node->set_left(if_op);
+ node->set_right(subnode);
+ } else {
+ ptr_op_t null_node = new op_t(op_t::VALUE);
+ null_node->set_value(NULL_VALUE);
+
+ ptr_op_t subnode = new op_t(op_t::O_COLON);
+ subnode->set_left(node);
+ subnode->set_right(null_node);
+
+ node = new op_t(op_t::O_QUERY);
+ node->set_left(if_op);
+ node->set_right(subnode);
+
+ push_token(tok);
+ }
+ }
+ else {
push_token(tok);
}
}
diff --git a/src/token.cc b/src/token.cc
index 6935bc7a..0a8fce7e 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -38,7 +38,8 @@ int expr_t::token_t::parse_reserved_word(std::istream& in)
{
char c = static_cast<char>(in.peek());
- if (c == 'a' || c == 'd' || c == 'f' || c == 'o' || c == 'n' || c == 't') {
+ if (c == 'a' || c == 'd' || c == 'e' || c == 'f' ||
+ c == 'i' || c == 'o' || c == 'n' || c == 't') {
length = 0;
char buf[6];
@@ -64,6 +65,16 @@ int expr_t::token_t::parse_reserved_word(std::istream& in)
}
break;
+ case 'e':
+ if (std::strcmp(buf, "else") == 0) {
+ symbol[0] = 'L';
+ symbol[1] = 'S';
+ symbol[2] = '\0';
+ kind = KW_ELSE;
+ return 1;
+ }
+ break;
+
case 'f':
if (std::strcmp(buf, "false") == 0) {
kind = VALUE;
@@ -72,6 +83,16 @@ int expr_t::token_t::parse_reserved_word(std::istream& in)
}
break;
+ case 'i':
+ if (std::strcmp(buf, "if") == 0) {
+ symbol[0] = 'i';
+ symbol[1] = 'f';
+ symbol[2] = '\0';
+ kind = KW_IF;
+ return 1;
+ }
+ break;
+
case 'o':
if (std::strcmp(buf, "or") == 0) {
symbol[0] = '|';
diff --git a/src/token.h b/src/token.h
index d0b65ded..7b5eec11 100644
--- a/src/token.h
+++ b/src/token.h
@@ -88,6 +88,9 @@ struct expr_t::token_t : public noncopyable
KW_OR, // |, ||, or
KW_MOD, // %
+ KW_IF, // if
+ KW_ELSE, // else
+
QUERY, // ?
COLON, // :