Commit b6c2274541f8340ba3ec01503931a46c54583661

Thomas de Grivel 2023-03-14T08:13:59

wip double free

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