diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index ebeb449..3cf9d56 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -312,6 +312,9 @@ sw buf_inspect_call (s_buf *buf, const s_call *call)
s8 op_precedence;
sw r;
sw result = 0;
+ if (call->ident.module == &g_sym_C3 &&
+ call->ident.sym == &g_sym_if_then_else)
+ return buf_inspect_call_if_then_else(buf, call);
if (operator_find(&call->ident) &&
operator_symbol(&call->ident) == &g_sym__brackets)
return buf_inspect_call_brackets(buf, call);
@@ -329,7 +332,7 @@ sw buf_inspect_call (s_buf *buf, const s_call *call)
result += r;
if ((r = buf_inspect_call_args(buf, call->arguments)) < 0)
return r;
- result += r;
+ result += r;
return result;
}
@@ -410,6 +413,70 @@ sw buf_inspect_call_brackets (s_buf *buf, const s_call *call)
return result;
}
+sw buf_inspect_call_if_then_else (s_buf *buf, const s_call *call)
+{
+ s_list *else_;
+ sw r;
+ sw result = 0;
+ s_list *then;
+ if (call->ident.module != &g_sym_C3 ||
+ call->ident.sym != &g_sym_if_then_else ||
+ ! call->arguments ||
+ ! (then = list_next(call->arguments)) ||
+ ! (else_ = list_next(then)))
+ return -2;
+ if ((r = buf_write_1(buf, "if ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_tag(buf, &call->arguments->tag)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_tag(buf, &then->tag)) < 0)
+ return r;
+ result += r;
+ if (else_->tag.type != TAG_VOID) {
+ if ((r = buf_write_1(buf, "\nelse ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_tag(buf, &else_->tag)) < 0)
+ return r;
+ result += r;
+ }
+ return result;
+}
+
+sw buf_inspect_call_if_then_else_size (const s_call *call)
+{
+ s_list *else_;
+ sw r;
+ sw result = 0;
+ s_list *then;
+ if (call->ident.module != &g_sym_C3 ||
+ call->ident.sym != &g_sym_if_then_else ||
+ ! call->arguments ||
+ ! (then = list_next(call->arguments)) ||
+ ! (else_ = list_next(then)))
+ return -2;
+ result += strlen("if ");
+ if ((r = buf_inspect_tag_size(&call->arguments->tag)) < 0)
+ return r;
+ result += r;
+ result += strlen(" ");
+ if ((r = buf_inspect_tag_size(&then->tag)) < 0)
+ return r;
+ result += r;
+ if (else_->tag.type != TAG_VOID) {
+ result += strlen("\nelse ");
+ if ((r = buf_inspect_tag_size(&else_->tag)) < 0)
+ return r;
+ result += r;
+ }
+ return result;
+}
+
sw buf_inspect_call_op (s_buf *buf, const s_call *call, s8 op_precedence)
{
s_ident ident;
@@ -533,6 +600,9 @@ sw buf_inspect_call_size (const s_call *call)
s8 op_precedence;
sw r;
sw result = 0;
+ if (call->ident.module == &g_sym_C3 &&
+ call->ident.sym == &g_sym_if_then_else)
+ return buf_inspect_call_if_then_else_size(call);
if (operator_find(&call->ident) &&
operator_arity(&call->ident) == 1)
return buf_inspect_call_op_unary_size(call);
diff --git a/libc3/buf_inspect.h b/libc3/buf_inspect.h
index 7212f04..dfed10a 100644
--- a/libc3/buf_inspect.h
+++ b/libc3/buf_inspect.h
@@ -62,6 +62,8 @@ sw buf_inspect_bool_size (const bool *b);
sw buf_inspect_call (s_buf *buf, const s_call *call);
sw buf_inspect_call_args (s_buf *buf, const s_list *args);
sw buf_inspect_call_brackets (s_buf *buf, const s_call *call);
+sw buf_inspect_call_if_then_else (s_buf *buf, const s_call *call);
+sw buf_inspect_call_if_then_else_size (const s_call *call);
sw buf_inspect_call_op (s_buf *buf, const s_call *call,
s8 op_precedence);
sw buf_inspect_call_op_size (const s_call *call, s8 op_precedence);
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 74aa3f3..7dfe408 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -734,7 +734,7 @@ sw buf_parse_call_op (s_buf *buf, s_call *dest)
if ((r = buf_ignore_spaces_but_newline(buf)) < 0)
goto restore;
result += r;
- if ((r = buf_parse_ident_peek(buf, &next_op)) <= 0)
+ if ((r = buf_peek_ident(buf, &next_op)) <= 0)
goto restore;
if (! operator_resolve(&next_op, 2, &next_op) ||
operator_precedence(&next_op) < 0) {
@@ -778,7 +778,7 @@ sw buf_parse_call_op_rec (s_buf *buf, s_call *dest, u8 min_precedence)
left = &tmp.arguments->tag;
right = &list_next(tmp.arguments)->tag;
tag_init_copy(left, &dest->arguments->tag);
- if ((r = buf_parse_ident_peek(buf, &next_op)) <= 0)
+ if ((r = buf_peek_ident(buf, &next_op)) <= 0)
goto restore;
if (! operator_resolve(&next_op, 2, &next_op) ||
(op_precedence = operator_precedence(&next_op)) < 0) {
@@ -806,7 +806,7 @@ sw buf_parse_call_op_rec (s_buf *buf, s_call *dest, u8 min_precedence)
break;
if (r > 0 && c == '\n')
break;
- r = buf_parse_ident_peek(buf, &next_op);
+ r = buf_peek_ident(buf, &next_op);
if (r <= 0)
break;
if (! operator_resolve(&next_op, 2, &next_op) &&
@@ -839,7 +839,7 @@ sw buf_parse_call_op_rec (s_buf *buf, s_call *dest, u8 min_precedence)
r = -1;
break;
}
- r = buf_parse_ident_peek(buf, &next_op);
+ r = buf_peek_ident(buf, &next_op);
if (r > 0 &&
(! operator_resolve(&next_op, 2, &next_op) ||
(next_op_precedence = operator_precedence(&next_op)) < 0)) {
@@ -1660,13 +1660,128 @@ sw buf_parse_ident (s_buf *buf, s_ident *dest)
return r;
}
-sw buf_parse_ident_peek (s_buf *buf, s_ident *dest)
+sw buf_parse_if (s_buf *buf, s_call *dest)
{
sw r;
+ if ((r = buf_parse_if_then_else(buf, dest)))
+ return r;
+ return buf_parse_if_then(buf, dest);
+}
+
+sw buf_parse_if_then (s_buf *buf, s_call *dest)
+{
+ s_list **a;
+ sw r;
+ sw result = 0;
+ s_call tmp = {0};
s_buf_save save;
+ assert(buf);
+ assert(dest);
buf_save_init(buf, &save);
- r = buf_parse_ident(buf, dest);
+ if ((r = buf_read_1(buf, "if")) <= 0)
+ goto clean;
+ result += r;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ tmp.ident.module = &g_sym_C3;
+ tmp.ident.sym = &g_sym_if_then_else;
+ a = &tmp.arguments;
+ *a = list_new(NULL);
+ if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ goto restore;
+ result += r;
+ a = &(*a)->next.data.list;
+ *a = list_new(NULL);
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ goto restore;
+ result += r;
+ a = &(*a)->next.data.list;
+ *a = list_new(NULL);
+ *dest = tmp;
+ r = result;
+ goto clean;
+ restore:
+ call_clean(&tmp);
buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
+sw buf_parse_if_then_else (s_buf *buf, s_call *dest)
+{
+ s_list **a;
+ sw r;
+ sw result = 0;
+ s_call tmp = {0};
+ s_buf_save save;
+ assert(buf);
+ assert(dest);
+ buf_save_init(buf, &save);
+ if ((r = buf_read_1(buf, "if")) <= 0)
+ goto clean;
+ result += r;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ tmp.ident.module = &g_sym_C3;
+ tmp.ident.sym = &g_sym_if_then_else;
+ a = &tmp.arguments;
+ *a = list_new(NULL);
+ if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ goto restore;
+ result += r;
+ a = &(*a)->next.data.list;
+ *a = list_new(NULL);
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ goto restore;
+ result += r;
+ a = &(*a)->next.data.list;
+ *a = list_new(NULL);
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_read_1(buf, "else")) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ goto restore;
+ result += r;
+ *dest = tmp;
+ r = result;
+ goto clean;
+ restore:
+ call_clean(&tmp);
+ buf_save_restore_rpos(buf, &save);
+ clean:
buf_save_clean(buf, &save);
return r;
}
@@ -3170,6 +3285,16 @@ sw buf_parse_tag_ident (s_buf *buf, s_tag *dest)
return r;
}
+sw buf_parse_tag_if (s_buf *buf, s_tag *dest)
+{
+ sw r;
+ assert(buf);
+ assert(dest);
+ if ((r = buf_parse_if(buf, &dest->data.call)) > 0)
+ dest->type = TAG_CALL;
+ return r;
+}
+
sw buf_parse_tag_integer (s_buf *buf, s_tag *dest)
{
sw r;
@@ -3250,6 +3375,7 @@ sw buf_parse_tag_primary (s_buf *buf, s_tag *dest)
(r = buf_parse_tag_array(buf, dest)) != 0 ||
(r = buf_parse_tag_cast(buf, dest)) != 0 ||
(r = buf_parse_tag_unquote(buf, dest)) != 0 ||
+ (r = buf_parse_tag_if(buf, dest)) != 0 ||
(r = buf_parse_tag_call(buf, dest)) != 0 ||
(r = buf_parse_tag_call_paren(buf, dest)) != 0 ||
(r = buf_parse_tag_call_op_unary(buf, dest)) != 0 ||
@@ -3598,3 +3724,16 @@ sw buf_peek_array_dimensions (s_buf *buf, s_array *dest)
buf_save_clean(buf, &save);
return r;
}
+
+sw buf_peek_ident (s_buf *buf, s_ident *dest)
+{
+ sw r;
+ s_buf_save save;
+ assert(buf);
+ assert(dest);
+ buf_save_init(buf, &save);
+ r = buf_parse_ident(buf, dest);
+ buf_save_restore_rpos(buf, &save);
+ buf_save_clean(buf, &save);
+ return r;
+}
diff --git a/libc3/buf_parse.h b/libc3/buf_parse.h
index 3e55b99..ad9120e 100644
--- a/libc3/buf_parse.h
+++ b/libc3/buf_parse.h
@@ -75,7 +75,9 @@ sw buf_parse_integer_unsigned_dec (s_buf *buf, s_integer *dest);
sw buf_parse_integer_unsigned_hex (s_buf *buf, s_integer *dest);
sw buf_parse_integer_unsigned_oct (s_buf *buf, s_integer *dest);
sw buf_parse_ident (s_buf *buf, s_ident *dest);
-sw buf_parse_ident_peek (s_buf *buf, s_ident *dest);
+sw buf_parse_if (s_buf *buf, s_call *dest);
+sw buf_parse_if_then (s_buf *buf, s_call *dest);
+sw buf_parse_if_then_else (s_buf *buf, s_call *dest);
sw buf_parse_integer (s_buf *buf, s_integer *dest);
sw buf_parse_list (s_buf *buf, s_list **dest);
sw buf_parse_list_paren (s_buf *buf, s_list **dest);
@@ -113,6 +115,7 @@ sw buf_parse_tag_f32 (s_buf *buf, s_tag *dest);
sw buf_parse_tag_f64 (s_buf *buf, s_tag *dest);
sw buf_parse_tag_fn (s_buf *buf, s_tag *dest);
sw buf_parse_tag_ident (s_buf *buf, s_tag *dest);
+sw buf_parse_tag_if (s_buf *buf, s_tag *dest);
sw buf_parse_tag_integer (s_buf *buf, s_tag *dest);
sw buf_parse_tag_list (s_buf *buf, s_tag *dest);
sw buf_parse_tag_map (s_buf *buf, s_tag *map);
@@ -134,5 +137,6 @@ sw buf_parse_var (s_buf *buf, void *dest);
sw buf_parse_void (s_buf *buf, void *dest);
sw buf_peek_array_dimensions (s_buf *buf, s_array *dest);
+sw buf_peek_ident (s_buf *buf, s_ident *dest);
#endif /* LIBC3_BUF_PARSE_H */
diff --git a/libc3/sym.c b/libc3/sym.c
index 4ea3a17..75acc68 100644
--- a/libc3/sym.c
+++ b/libc3/sym.c
@@ -63,6 +63,7 @@ const s_sym g_sym_cast = {{{NULL}, 4, {"cast"}}};
const s_sym g_sym_defstruct = {{{NULL}, 9, {"defstruct"}}};
const s_sym g_sym_do = {{{NULL}, 2, {"do"}}};
const s_sym g_sym_end = {{{NULL}, 3, {"end"}}};
+const s_sym g_sym_if_then_else = {{{NULL}, 12, {"if_then_else"}}};
const s_sym g_sym_is_a = {{{NULL}, 4, {"is_a"}}};
const s_sym g_sym_load_time = {{{NULL}, 9, {"load_time"}}};
const s_sym g_sym_operator_pin = {{{NULL}, 12, {"operator_pin"}}};
@@ -303,6 +304,7 @@ void sym_init_g_sym (void)
sym_intern(&g_sym_defstruct, NULL);
sym_intern(&g_sym_do, NULL);
sym_intern(&g_sym_end, NULL);
+ sym_intern(&g_sym_if_then_else, NULL);
sym_intern(&g_sym_is_a, NULL);
sym_intern(&g_sym_load_time, NULL);
sym_intern(&g_sym_operator_pin, NULL);
diff --git a/libc3/sym.h b/libc3/sym.h
index d05724c..623ac6e 100644
--- a/libc3/sym.h
+++ b/libc3/sym.h
@@ -75,6 +75,7 @@ extern const s_sym g_sym_cast;
extern const s_sym g_sym_defstruct;
extern const s_sym g_sym_do;
extern const s_sym g_sym_end;
+extern const s_sym g_sym_if_then_else;
extern const s_sym g_sym_is_a;
extern const s_sym g_sym_load_time;
extern const s_sym g_sym_operator_pin;
diff --git a/test/ic3/if.in b/test/ic3/if.in
new file mode 100644
index 0000000..27ea476
--- /dev/null
+++ b/test/ic3/if.in
@@ -0,0 +1,12 @@
+quote if true 1 else 2
+if true 1 else 2
+quote if true 1 else void
+if true 1 else void
+quote if true 1
+if true 1
+quote if false 1 else 2
+if false 1 else 2
+quote if false 1 else void
+if false 1 else void
+quote if false 1
+if false 1
diff --git a/test/ic3/if.out.expected b/test/ic3/if.out.expected
new file mode 100644
index 0000000..70e8ba6
--- /dev/null
+++ b/test/ic3/if.out.expected
@@ -0,0 +1,14 @@
+if true 1
+else 2
+1
+if true 1
+1
+if true 1
+1
+if false 1
+else 2
+2
+if false 1
+void
+if false 1
+void
diff --git a/test/ic3/if.ret.expected b/test/ic3/if.ret.expected
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/test/ic3/if.ret.expected
@@ -0,0 +1 @@
+0