Skip to content

Commit f099fa9

Browse files
committed
add ternary operator
1 parent 122c203 commit f099fa9

5 files changed

Lines changed: 44 additions & 2 deletions

File tree

docs/src/math.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ Asar supports the 6 usual comparison operators:
7777
| --- | --- |
7878
| <code>a \|\| b</code> | Returns 1 if at least one of `a` and `b` evaluates to true |
7979
| `a && b` | Returns 1 if both of `a` and `b` evaluate to true |
80+
| `?(a, b, c)` | Returns `b` if `a` is true, or `c` if `a` is false |
8081

81-
These operators are lazy: they will not evaluate the right-hand argument if the result is already determined by the left-hand argument. (Specifically, `1 || anything` immediately returns `1` and doesn't evaluate `anything`, and similarly, `0 && anything` immediately returns `0`.)
82+
These operators are lazy: they will not evaluate the right-hand argument if the result is already determined by the left-hand argument. More specifically, `1 || anything` immediately returns `1` and doesn't evaluate `anything`; `0 && anything` immediately returns `0`; and `?(1, x, anything)` returns `x` without evaluating `anything`.
8283

8384
## Operator precedence
8485

src/asar/math_ast.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ class math_ast_unop : public math_ast_node {
6161
int get_len(bool could_be_bank_ex) const;
6262
};
6363

64+
class math_ast_ternary_cond : public math_ast_node {
65+
owned_node m_cond, m_true, m_false;
66+
public:
67+
math_ast_ternary_cond(owned_node cond_in, owned_node true_in, owned_node false_in)
68+
: m_cond(std::move(cond_in)), m_true(std::move(true_in)), m_false(std::move(false_in)) {}
69+
70+
math_val evaluate(const eval_context& ctx) const;
71+
int has_label() const;
72+
int get_len(bool could_be_bank_ex) const;
73+
};
74+
6475
class math_ast_literal : public math_ast_node {
6576
math_val m_value;
6677
int m_len;

src/asar/math_eval.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,22 @@ int math_ast_unop::get_len(bool could_be_bank_ex) const {
231231
return m_arg->get_len(false);
232232
}
233233

234+
math_val math_ast_ternary_cond::evaluate(const eval_context& ctx) const {
235+
if(m_cond->evaluate(ctx).get_bool()) {
236+
return m_true->evaluate(ctx);
237+
} else {
238+
return m_false->evaluate(ctx);
239+
}
240+
}
241+
242+
int math_ast_ternary_cond::has_label() const {
243+
return m_cond->has_label() | m_true->has_label() | m_false->has_label();
244+
}
245+
246+
int math_ast_ternary_cond::get_len(bool could_be_bank_ex) const {
247+
return std::max(m_true->get_len(false), m_false->get_len(false));
248+
}
249+
234250
math_val math_ast_label::evaluate(const eval_context &ctx) const {
235251
if (m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
236252
return math_val::make_identifier(m_cur_ns + m_labelname);

src/asar/math_parse.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ owned_node parse_context::parse_atom() {
6464
}
6565
if (is_ualpha(*str) || *str=='.' || *str=='?') {
6666
const char * start=str;
67-
while (is_ualnum(*str) || *str == '.') str++;
67+
while (is_ualnum(*str) || *str == '.' || *str == '?') str++;
6868
int len=(int)(str-start);
6969
while (*str==' ') str++;
7070
if (*str=='(') {
@@ -80,6 +80,16 @@ owned_node parse_context::parse_atom() {
8080
if(*str == ',') str++;
8181
}
8282
str++;
83+
// ternary is basically just a function called "?"
84+
if(func_name == "?") {
85+
if(arguments.size() != 3) {
86+
throw_err_block(2, err_argument_count, 3, (int)arguments.size());
87+
}
88+
return std::make_unique<math_ast_ternary_cond>(
89+
std::move(arguments[0]),
90+
std::move(arguments[1]),
91+
std::move(arguments[2]));
92+
}
8393
return std::make_unique<math_ast_function_call>(std::move(arguments), std::move(func_name));
8494
} else {
8595
string name_part(start, len);

tests/ternary.asm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
assert ?(1, "a", "b") == "a"
2+
assert ?(0, "a", "b") == "b"
3+
assert ?(1, 1, 1/0) == 1 ; short-circuiting
4+
assert ?(1, "a", 0) == "a" ; mixed types

0 commit comments

Comments
 (0)