diff --git a/README.md b/README.md
index 2ab8473..35d38e7 100644
--- a/README.md
+++ b/README.md
@@ -349,16 +349,29 @@ Script interpreter. Works the same as ic3 but is not interactive.
- collect_idents
- DONE pin operator (for pattern matching)
- DONE macros
- - special operators
+ - DONE special operators
- their arguments do not get evaluated
- they return a value
- parsed without syntax
+ Ideally it would look like this :
```
- ic3> Facts.add(C3.env.facts, {C3.op, :is_a, :special_operator})
- {C3.op, :is_a, :special_operator}
- ic3> op = fn (a, b, c) { true }
- ic3> op a b c
+ ic3> defspecial_operator op (a, b, c) { true }
+ special_operator (a, b, c) { true }
+ ic3> op 1 2 3
+ true
```
+ - if
+ - if cond1
+ then1
+ then2
+ end
+ - if cond1
+ then1
+ then2
+ else
+ else1
+ else2
+ end
- modules
- defmodule
- def
diff --git a/ic3/.ic3_history b/ic3/.ic3_history
index be4a069..0e17807 100644
--- a/ic3/.ic3_history
+++ b/ic3/.ic3_history
@@ -1,7 +1,3 @@
-getenv("HOME")
-getenv("USER")
-"a" + "b"
-"ab" + "cd"
"ab" + "cd" + "ef"
"Bonjour " + name + " !"
hello = fn (name) { "Hello, " + name + " !" }
@@ -97,3 +93,7 @@ m(n)
n = "Plop"
m = macro (name) { quote "Hello, " + (unquote name) + " !" }
m(n)
+if true 1 else 2 end
+quote if true 1 else 2 end
+quote if false 1 else 2 end
+if false 1 else 2 end
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 3cf9d56..78eab17 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -274,6 +274,43 @@ sw buf_inspect_block (s_buf *buf, const s_block *block)
return result;
}
+sw buf_inspect_block_inner (s_buf *buf, const s_block *block)
+{
+ u64 i = 0;
+ sw r;
+ sw result = 0;
+ if (! block->count)
+ return 0;
+ if (block->short_form) {
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ }
+ else {
+ if ((r = buf_write_1(buf, "\n ")) < 0)
+ return r;
+ }
+ result += r;
+ while (i < block->count - 1) {
+ if ((r = buf_inspect_tag(buf, block->tag + i)) < 0)
+ return r;
+ result += r;
+ if (block->short_form) {
+ if ((r = buf_write_1(buf, "; ")) < 0)
+ return r;
+ }
+ else {
+ if ((r = buf_write_1(buf, "\n ")) < 0)
+ return r;
+ }
+ result += r;
+ i++;
+ }
+ if ((r = buf_inspect_tag(buf, block->tag + i)) < 0)
+ return r;
+ result += r;
+ return result;
+}
+
sw buf_inspect_block_size (const s_block *block)
{
u64 i = 0;
@@ -415,66 +452,55 @@ 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)
{
- s_list *else_;
+ s_tag *condition;
+ s_tag *else_;
sw r;
sw result = 0;
- s_list *then;
+ s_tag *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)))
+ list_length(call->arguments) != 3)
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)
+ condition = &call->arguments->tag;
+ if ((r = buf_inspect_tag(buf, condition)) < 0)
return r;
result += r;
- if ((r = buf_inspect_tag(buf, &then->tag)) < 0)
- return r;
+ then = &list_next(call->arguments)->tag;
+ if (then->type == TAG_BLOCK) {
+ if ((r = buf_inspect_block_inner(buf, &then->data.block)) < 0)
+ return r;
+ }
+ else
+ if ((r = buf_inspect_tag(buf, then)) < 0)
+ return r;
result += r;
- if (else_->tag.type != TAG_VOID) {
- if ((r = buf_write_1(buf, "\nelse ")) < 0)
+ else_ = &list_next(list_next(call->arguments))->tag;
+ if (else_->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;
+ if (then->type == TAG_BLOCK) {
+ if ((r = buf_inspect_block_inner(buf, &else_->data.block)) < 0)
+ return r;
+ }
+ else
+ if ((r = buf_inspect_tag(buf, else_)) < 0)
+ return r;
result += r;
}
+ if ((r = buf_write_1(buf, "\nend")) < 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;
+ (void) call;
+ return -1;
}
sw buf_inspect_call_op (s_buf *buf, const s_call *call, s8 op_precedence)
diff --git a/libc3/buf_inspect.h b/libc3/buf_inspect.h
index dfed10a..89ac4c7 100644
--- a/libc3/buf_inspect.h
+++ b/libc3/buf_inspect.h
@@ -56,6 +56,8 @@
sw buf_inspect_array (s_buf *buf, const s_array *a);
sw buf_inspect_array_size (const s_array *a);
sw buf_inspect_block (s_buf *buf, const s_block *b);
+sw buf_inspect_block_inner (s_buf *buf, const s_block *b);
+sw buf_inspect_block_inner_size (const s_block *b);
sw buf_inspect_block_size (const s_block *b);
sw buf_inspect_bool (s_buf *buf, const bool *b);
sw buf_inspect_bool_size (const bool *b);
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 7dfe408..ed7f2a0 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -402,16 +402,10 @@ sw buf_parse_array_dimensions_rec (s_buf *buf, s_array *dest,
sw buf_parse_block (s_buf *buf, s_block *block)
{
- s_list **i;
- sw j;
- s_list *k;
- sw l;
- s_list *list = 0;
sw r;
sw result = 0;
s_buf_save save;
bool short_form = false;
- s_block tmp;
assert(buf);
assert(block);
buf_save_init(buf, &save);
@@ -423,6 +417,30 @@ sw buf_parse_block (s_buf *buf, s_block *block)
goto clean;
}
result += r;
+ if ((r = buf_parse_block_inner(buf, short_form, block)) <= 0)
+ goto restore;
+ result += r;
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
+sw buf_parse_block_inner (s_buf *buf, bool short_form, s_block *block)
+{
+ s_list **i;
+ sw j;
+ s_list *k;
+ sw l;
+ s_list *list = 0;
+ sw r;
+ sw result = 0;
+ s_buf_save save;
+ s_block tmp;
+ buf_save_init(buf, &save);
i = &list;
*i = NULL;
while (1) {
@@ -1662,17 +1680,13 @@ sw buf_parse_ident (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;
+ s_list **args_last;
+ s_tag *condition;
+ s_tag *else_;
+ bool has_else;
sw r;
sw result = 0;
+ s_tag *then;
s_call tmp = {0};
s_buf_save save;
assert(buf);
@@ -1689,24 +1703,33 @@ sw buf_parse_if_then (s_buf *buf, s_call *dest)
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)
+ args_last = &tmp.arguments;
+ *args_last = list_new(NULL);
+ condition = &(*args_last)->tag;
+ if ((r = buf_parse_tag(buf, condition)) <= 0)
goto restore;
result += r;
- if ((r = buf_parse_tag(buf, &(*a)->tag)) <= 0)
+ args_last = &(*args_last)->next.data.list;
+ *args_last = list_new(NULL);
+ then = &(*args_last)->tag;
+ if ((r = buf_parse_if_then(buf, then, &has_else)) < 0)
goto restore;
result += r;
- a = &(*a)->next.data.list;
- *a = list_new(NULL);
+ args_last = &(*args_last)->next.data.list;
+ *args_last = list_new(NULL);
+ else_ = &(*args_last)->tag;
+ if (has_else) {
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) <= 0)
+ goto restore;
+ result += r;
+ else_->type = TAG_BLOCK;
+ if ((r = buf_parse_block_inner(buf, false, &else_->data.block)) <= 0)
+ goto restore;
+ result += r;
+ }
*dest = tmp;
r = result;
goto clean;
@@ -1718,72 +1741,105 @@ sw buf_parse_if_then (s_buf *buf, s_call *dest)
return r;
}
-sw buf_parse_if_then_else (s_buf *buf, s_call *dest)
+sw buf_parse_if_then (s_buf *buf, s_tag *dest, bool *has_else)
{
- s_list **a;
+ s_list **i;
+ sw j;
+ s_list *k;
+ sw l;
+ s_list *list = 0;
sw r;
sw result = 0;
- s_call tmp = {0};
s_buf_save save;
- assert(buf);
- assert(dest);
+ s_block tmp;
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;
+ i = &list;
+ *i = NULL;
+ while (1) {
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces(buf)) < 0)
+ goto restore;
+ result += r;
+ *i = list_new(NULL);
+ if ((r = buf_parse_tag(buf, &(*i)->tag)) <= 0)
+ goto restore;
+ result += r;
+ if ((r = buf_parse_comments(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_ignore_spaces_but_newline(buf)) < 0)
+ goto restore;
+ result += r;
+ if ((r = buf_read_sym(buf, &g_sym_end)) < 0)
+ goto restore;
+ if (! r && (r = buf_read_1(buf, "}")) < 0)
+ goto restore;
+ if (r > 0) {
+ *has_else = false;
+ goto ok;
+ }
+ if ((r = buf_read_sym(buf, &g_sym_else)) < 0)
+ goto restore;
+ if (r > 0) {
+ *has_else = true;
+ goto ok;
+ }
+ if ((r = buf_read_1(buf, "\n")) < 0 ||
+ (! r && (r = buf_read_1(buf, ";")) <= 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_read_sym(buf, &g_sym_end)) < 0)
+ goto restore;
+ if (! r && (r = buf_read_1(buf, "}")) < 0)
+ goto restore;
+ if (r > 0) {
+ *has_else = false;
+ goto ok;
+ }
+ if ((r = buf_read_sym(buf, &g_sym_else)) < 0)
+ goto restore;
+ if (r > 0) {
+ *has_else = true;
+ goto ok;
+ }
+ i = &(*i)->next.data.list;
+ }
+ r = 0;
restore:
- call_clean(&tmp);
buf_save_restore_rpos(buf, &save);
clean:
buf_save_clean(buf, &save);
+ if (list)
+ list_delete_all(list);
return r;
+ ok:
+ result += r;
+ j = list_length(list);
+ if (! block_init(&tmp, j)) {
+ r = -2;
+ goto restore;
+ }
+ k = list;
+ l = 0;
+ while (l < j) {
+ tmp.tag[l] = k->tag;
+ tag_init_void(&k->tag);
+ k = list_next(k);
+ l++;
+ }
+ dest->type = TAG_BLOCK;
+ dest->data.block = tmp;
+ r = result;
+ goto clean;
+
}
sw buf_parse_integer (s_buf *buf, s_integer *dest)
diff --git a/libc3/buf_parse.h b/libc3/buf_parse.h
index ad9120e..941015e 100644
--- a/libc3/buf_parse.h
+++ b/libc3/buf_parse.h
@@ -46,6 +46,7 @@ sw buf_parse_array_data (s_buf *buf, s_array *dest);
sw buf_parse_array_dimension_count (s_buf *buf, s_array *dest);
sw buf_parse_array_dimensions (s_buf *buf, s_array *dest);
sw buf_parse_block (s_buf *buf, s_block *dest);
+sw buf_parse_block_inner (s_buf *buf, bool short_form, s_block *block);
sw buf_parse_bool (s_buf *buf, bool *dest);
sw buf_parse_brackets (s_buf *buf, s_call *dest);
sw buf_parse_call (s_buf *buf, s_call *dest);
@@ -76,8 +77,7 @@ 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_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_if_then (s_buf *buf, s_tag *dest, bool *has_else);
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);
diff --git a/libc3/sym.c b/libc3/sym.c
index 75acc68..8efdad1 100644
--- a/libc3/sym.c
+++ b/libc3/sym.c
@@ -62,6 +62,7 @@ const s_sym g_sym_Void = {{{NULL}, 4, {"Void"}}};
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_else = {{{NULL}, 4, {"else"}}};
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"}}};
@@ -303,6 +304,7 @@ void sym_init_g_sym (void)
sym_intern(&g_sym_cast, NULL);
sym_intern(&g_sym_defstruct, NULL);
sym_intern(&g_sym_do, NULL);
+ sym_intern(&g_sym_else, NULL);
sym_intern(&g_sym_end, NULL);
sym_intern(&g_sym_if_then_else, NULL);
sym_intern(&g_sym_is_a, NULL);
diff --git a/libc3/sym.h b/libc3/sym.h
index 623ac6e..c88e886 100644
--- a/libc3/sym.h
+++ b/libc3/sym.h
@@ -74,6 +74,7 @@ extern const s_sym g_sym_Void;
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_else;
extern const s_sym g_sym_end;
extern const s_sym g_sym_if_then_else;
extern const s_sym g_sym_is_a;
diff --git a/test/ic3/if.in b/test/ic3/if.in
index 27ea476..ccbb8d4 100644
--- a/test/ic3/if.in
+++ b/test/ic3/if.in
@@ -1,12 +1,60 @@
-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
+quote if true
+ 1
+else
+ 2
+end
+if true
+ 1
+else
+ 2
+end
+quote if true
+ 1
+end
+if true
+ 1
+end
+quote if false
+ 1
+else
+ 2
+end
+if false
+ 1
+else
+ 2
+end
+quote if false
+ 1
+end
+if false
+ 1
+end
+quote if true && true
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
+if true && true
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
+quote if true && false
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
+if true && false
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
diff --git a/test/ic3/if.out.expected b/test/ic3/if.out.expected
index 70e8ba6..371e170 100644
--- a/test/ic3/if.out.expected
+++ b/test/ic3/if.out.expected
@@ -1,14 +1,36 @@
-if true 1
-else 2
+if true
+ 1
+else
+ 2
+end
1
-if true 1
+if true
+ 1
+end
1
-if true 1
-1
-if false 1
-else 2
+if false
+ 1
+else
+ 2
+end
2
-if false 1
-void
-if false 1
+if false
+ 1
+end
void
+if true && true
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
+4
+if true && false
+ 1 + 1
+ 2 + 2
+else
+ 3 + 3
+ 4 + 4
+end
+8