diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 67eb7e1..956093e 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -41,8 +41,11 @@ sw buf_inspect_bool_size (e_bool x)
sw buf_inspect_call (s_buf *buf, const s_call *call)
{
+ s8 op_precedence;
sw r;
sw result = 0;
+ if ((op_precedence = operator_precedence(&call->ident)) > 0)
+ return buf_inspect_call_op(buf, call, op_precedence);
if ((r = buf_inspect_ident(buf, &call->ident)) < 0)
return r;
result += r;
@@ -52,6 +55,64 @@ sw buf_inspect_call (s_buf *buf, const s_call *call)
return result;
}
+sw buf_inspect_call_op (s_buf *buf, const s_call *call, s8 op_precedence)
+{
+ s_tag *left;
+ bool paren;
+ s8 precedence;
+ sw r;
+ sw result = 0;
+ s_tag *right;
+ left = &call->arguments->tag;
+ right = &list_next(call->arguments)->tag;
+ if (left->type.type == TAG_CALL &&
+ (precedence = operator_precedence(&left->data.call.ident))
+ < op_precedence) {
+ paren = true;
+ if ((r = buf_write_1(buf, "(")) < 0)
+ return r;
+ result += r;
+ }
+ else
+ paren = false;
+ if ((r = buf_inspect_tag(buf, left)) < 0)
+ return r;
+ result += r;
+ if (paren) {
+ if ((r = buf_write_1(buf, ")")) < 0)
+ return r;
+ result += r;
+ }
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ if ((r = buf_inspect_ident(buf, &call->ident)) < 0)
+ return r;
+ result += r;
+ if ((r = buf_write_1(buf, " ")) < 0)
+ return r;
+ result += r;
+ if (right->type.type == TAG_CALL &&
+ (precedence = operator_precedence(&right->data.call.ident))
+ < op_precedence) {
+ paren = true;
+ if ((r = buf_write_1(buf, "(")) < 0)
+ return r;
+ result += r;
+ }
+ else
+ paren = false;
+ if ((r = buf_inspect_tag(buf, right)) < 0)
+ return r;
+ result += r;
+ if (paren) {
+ if ((r = buf_write_1(buf, ")")) < 0)
+ return r;
+ result += r;
+ }
+ return result;
+}
+
sw buf_inspect_call_args (s_buf *buf, const s_list *args)
{
sw r;
diff --git a/libc3/buf_inspect.h b/libc3/buf_inspect.h
index 5d6ecec..9a036a5 100644
--- a/libc3/buf_inspect.h
+++ b/libc3/buf_inspect.h
@@ -30,6 +30,8 @@ sw buf_inspect_bool (s_buf *buf, e_bool b);
sw buf_inspect_bool_size (e_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_op (s_buf *buf, const s_call *call,
+ s8 op_precedence);
sw buf_inspect_call_size (const s_call *call);
sw buf_inspect_cfn (s_buf *buf, const s_cfn *cfn);
sw buf_inspect_cfn_size (const s_cfn *cfn);
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 2212d20..d87b809 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -253,19 +253,19 @@ sw buf_parse_call_op_rec (s_buf *buf, s_call *dest, u8 min_precedence)
call_init_op(&tmp2);
tmp2.arguments->tag = *right;
if ((r = buf_parse_call_op_rec(buf, &tmp2, (next_op_precedence > op_precedence) ? op_precedence + 1 : op_precedence)) <= 0)
- goto restore;
+ break;
bzero(right, sizeof(s_tag));
right->type.type = TAG_CALL;
right->data.call = tmp2;
result += r;
if ((r = buf_ignore_spaces(buf)) < 0)
- goto restore;
+ break;
result += r;
r = buf_parse_ident_peek(buf, &next_op);
if (r > 0)
next_op_precedence = operator_precedence(&next_op);
}
- if ((op_precedence = next_op_precedence) < 0)
+ if (r <= 0 || (op_precedence = next_op_precedence) < min_precedence)
break;
call_init_op(&tmp2);
tmp2.ident = op;
@@ -278,6 +278,7 @@ sw buf_parse_call_op_rec (s_buf *buf, s_call *dest, u8 min_precedence)
goto clean;
restore:
buf_save_restore_rpos(buf, &save);
+ call_clean(&tmp);
clean:
buf_save_clean(buf, &save);
return r;
diff --git a/libc3/env.c b/libc3/env.c
index 7d6ddd0..00d0600 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -488,17 +488,19 @@ s_module * env_module_load (s_env *env, s_module *module,
return module;
}
-bool env_operator_is_right_associative (const s_env *env, s_ident *op)
+bool env_operator_is_right_associative (const s_env *env, const s_ident *op)
{
s_facts_with_cursor cursor;
s8 r;
s_tag tag_ident;
s_tag tag_operator_assoc;
s_tag tag_right;
+ s_ident tmp;
assert(env);
assert(op);
- ident_resolve_module(op, env);
- tag_init_ident(&tag_ident, op);
+ tmp = *op;
+ ident_resolve_module(&tmp, env);
+ tag_init_ident(&tag_ident, &tmp);
tag_init_1( &tag_operator_assoc, ":operator_associativity");
tag_init_1( &tag_right, ":right");
facts_with(&env->facts, &cursor, (t_facts_spec) {
@@ -509,16 +511,18 @@ bool env_operator_is_right_associative (const s_env *env, s_ident *op)
return r;
}
-s8 env_operator_precedence (const s_env *env, s_ident *op)
+s8 env_operator_precedence (const s_env *env, const s_ident *op)
{
s_facts_with_cursor cursor;
s_tag tag_ident;
s_tag tag_operator_precedence;
s_tag tag_var;
+ s_ident tmp;
assert(env);
assert(op);
- ident_resolve_module(op, env);
- tag_init_ident(&tag_ident, op);
+ tmp = *op;
+ ident_resolve_module(&tmp, env);
+ tag_init_ident(&tag_ident, &tmp);
tag_init_1( &tag_operator_precedence, ":operator_precedence");
tag_init_var( &tag_var);
facts_with(&env->facts, &cursor, (t_facts_spec) {
@@ -528,8 +532,8 @@ s8 env_operator_precedence (const s_env *env, s_ident *op)
goto ko;
if (tag_var.type.type != TAG_U8) {
warnx("%s.%s: invalid operator_precedence type",
- op->module_name->str.ptr.ps8,
- op->sym->str.ptr.ps8);
+ tmp.module_name->str.ptr.ps8,
+ tmp.sym->str.ptr.ps8);
goto ko;
}
facts_with_cursor_clean(&cursor);
diff --git a/libc3/env.h b/libc3/env.h
index 43ce7ef..029cdd8 100644
--- a/libc3/env.h
+++ b/libc3/env.h
@@ -46,9 +46,9 @@ bool env_eval_tag (s_env *env, const s_tag *tag, s_tag *dest);
s_module * env_module_load (s_env *env, s_module *module,
const s_sym *name, s_facts *facts);
bool env_operator_is_right_associative (const s_env *env,
- s_ident *op);
+ const s_ident *op);
s8 env_operator_precedence (const s_env *env,
- s_ident *op);
+ const s_ident *op);
/* control structures */
void env_error_f (s_env *env, const char *fmt, ...);
diff --git a/libc3/operator.c b/libc3/operator.c
index 739f6cb..f4bc2b4 100644
--- a/libc3/operator.c
+++ b/libc3/operator.c
@@ -14,12 +14,12 @@
#include <assert.h>
#include "c3.h"
-bool operator_is_right_associative (s_ident *op)
+bool operator_is_right_associative (const s_ident *op)
{
return env_operator_is_right_associative(&g_c3_env, op);
}
-s8 operator_precedence (s_ident *op)
+s8 operator_precedence (const s_ident *op)
{
return env_operator_precedence(&g_c3_env, op);
}
diff --git a/libc3/operator.h b/libc3/operator.h
index 8167efd..afe3ae7 100644
--- a/libc3/operator.h
+++ b/libc3/operator.h
@@ -17,7 +17,7 @@
#include "types.h"
/* Observers */
-bool operator_is_right_associative (s_ident *op);
-s8 operator_precedence (s_ident *op);
+bool operator_is_right_associative (const s_ident *op);
+s8 operator_precedence (const s_ident *op);
#endif /* OPERATOR_H */
diff --git a/test/ic3/add.in b/test/ic3/add.in
index 4268d50..ef1e503 100644
--- a/test/ic3/add.in
+++ b/test/ic3/add.in
@@ -1,3 +1,5 @@
quote 1 + 2
-quote 1 + 2
-quote 1 + 2
+quote 1 + 2 / 3
+quote 1 + 2 / 3 * 4
+quote 1 + 2 / 3 * 4 - 5
+quote 1 + 2 / 3 * 4 - 5