Commit a667bc34c87451a2c6eb481a62185503978c2d41

Thomas de Grivel 2024-02-18T13:34:40

wip unquote

diff --git a/.ic3_history b/.ic3_history
index f3633f8..4141c44 100644
--- a/.ic3_history
+++ b/.ic3_history
@@ -1,8 +1,3 @@
-m("123")
-m = macro (name) { quote "Hello, " + name + " !" }
-m("123")
-m = macro (name) { quote "Hello, " + name + " !" }
-m("123")
 if(true, 1, 2)
 if(false, 1, 2)
 if(false, 1 + 1, 2 + 2)
@@ -97,3 +92,8 @@ name = quote n; quote "Hello, " + (unquote name) + " !"
 name = quote n ; quote "Hello, " + (unquote name) + " !"
 name = quote n
 quote "Hello, " + (unquote name) + " !"
+m = macro (name) { quote "Hello, " + (unquote name) + " !" }
+n = "123"
+m(n)
+m = macro (name) { quote "Hello, " + (unquote name) + " !" }
+m("Quentin")
diff --git a/README.md b/README.md
index 66092e9..1e18a26 100644
--- a/README.md
+++ b/README.md
@@ -261,11 +261,10 @@ ic3>
 
 #### Lists
 
-
 Lists are marked with brackets `[]`.
 
 Regular lists can be :
- - an element and a list : `[1 | [2]]` → `[1, 2]`
+ - an element and a list : `[1 | []]` → `[1]`
  - multiple elements : `[1, 2, 3]`
  - multiple elements and a list : `[1, 2 | [3, 4]]` → `[1, 2, 3, 4]`
  - the empty list : `[]`
@@ -281,6 +280,58 @@ the next list pointer is an arbitrary form. E.g. :
 All these list formats are supported in pattern matching.
 
 
+#### Pattern matching and destructuring
+
+All tag data structures in C3 can be pattern matched using the equal
+sign (`=`) against litteral values containing identifiers. All
+identifiers are supposed to be new bindings when using pattern matching
+in C3. If you want to use an identifier's value in pattern matching you
+must use the _pin operator_ (`^`). Variables can be assigned a new value
+from either side of the equal sign and from inside a tag data structure,
+which is called _destructuring_.
+
+
+Examples :
+```
+ic3> a = 1
+1
+ic3> a = 2
+2
+ic3> a
+2
+ic3> ^ a = 1
+void
+ic3> ^ a = 2
+2
+ic3> ^ a = b
+2
+ic3> b
+2
+```
+
+To use destructuring just type the litteral value you want to match and
+put identifiers (variable names) where you want a variable matching the
+value on the other side of the equal sign. This is the most visual
+approach possible to text-based value matching : the data is constantly
+matched to litterals that show their type to the programmer. This is
+really helpful when writing large programs that need to scale in the way
+of abstractions. Let the data flow in the code through visual types.
+
+
+
+#### Macros
+
+Macros are like functions but start with `macro` instead of `fn` and
+their arguments do not get evaluated. However they get pattern matched
+and the full power of the pattern matcher is available for arguments
+destructuring. Use a map if you want named arguments. Use a list if you
+want &rest or &body arguments.
+
+When evaluated, a macro call returns a tag which is in turn evaluated
+in the calling site lexical environment. This allows for DSLs and custom
+control structures to be defined in C3.
+
+
 ### c3s
 
 Script interpreter. Works the same as ic3 but is not interactive.
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index 0ec4d4f..ebeb449 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -2292,11 +2292,15 @@ sw buf_inspect_unquote (s_buf *buf, const s_unquote *unquote)
   sw result = 0;
   s_buf_save save;
   buf_save_init(buf, &save);
-  if ((r = buf_write_1(buf, "unquote ")) < 0)
+  if ((r = buf_write_1(buf, "unquote(")) < 0)
     goto clean;
   result += r;
   if ((r = buf_inspect_tag(buf, unquote->tag)) < 0)
     goto restore;
+  result += r;
+  if ((r = buf_write_1(buf, ")")) < 0)
+    goto clean;
+  result += r;
   r = result;
   goto clean;
  restore:
@@ -2310,10 +2314,11 @@ sw buf_inspect_unquote_size (const s_unquote *unquote)
 {
   sw r;
   sw result = 0;
-  result += strlen("unquote ");
+  result += strlen("unquote(");
   if ((r = buf_inspect_tag_size(unquote->tag)) < 0)
     return r;
   result += r;
+  result += strlen(")");
   return result;
 }
 
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index b4a812f..770f9de 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -3198,6 +3198,7 @@ sw buf_parse_tag_primary (s_buf *buf, s_tag *dest)
       (r = buf_parse_tag_number(buf, dest)) != 0 ||
       (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_call(buf, dest)) != 0 ||
       (r = buf_parse_tag_call_paren(buf, dest)) != 0 ||
       (r = buf_parse_tag_call_op_unary(buf, dest)) != 0 ||
@@ -3208,7 +3209,6 @@ sw buf_parse_tag_primary (s_buf *buf, s_tag *dest)
       (r = buf_parse_tag_tuple(buf, dest)) != 0 ||
       (r = buf_parse_tag_block(buf, dest)) != 0 ||
       (r = buf_parse_tag_quote(buf, dest)) != 0 ||
-      (r = buf_parse_tag_unquote(buf, dest)) != 0 ||
       (r = buf_parse_tag_cfn(buf, dest)) != 0 ||
       (r = buf_parse_tag_fn(buf, dest)) != 0 ||
       (r = buf_parse_tag_struct(buf, dest)) != 0 ||
@@ -3430,9 +3430,12 @@ sw buf_parse_unquote (s_buf *buf, s_unquote *dest)
   sw result = 0;
   s_buf_save save;
   buf_save_init(buf, &save);
-  if ((r = buf_read_1(buf, "unquote")) <= 0)
+  if ((r = buf_read_1(buf, "unquote(")) <= 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;
@@ -3446,6 +3449,15 @@ sw buf_parse_unquote (s_buf *buf, s_unquote *dest)
     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_1(buf, ")")) <= 0)
+    goto clean;
+  result += r;
   *dest = unquote;
   r = result;
   goto clean;
diff --git a/test/ic3/block.in b/test/ic3/block.in
index ef55ff0..cfbc0a5 100644
--- a/test/ic3/block.in
+++ b/test/ic3/block.in
@@ -40,6 +40,6 @@ do
 end
 quote do
   1 + 1
-  2 + unquote 1 + 1
-  unquote 3 + 3
+  2 + unquote(1 + 1)
+  unquote(3 + 3)
 end
diff --git a/test/ic3/macro.in b/test/ic3/macro.in
index 1cb643a..cdb8c74 100644
--- a/test/ic3/macro.in
+++ b/test/ic3/macro.in
@@ -1,5 +1,5 @@
-quote m = macro (name) { quote "Hello, " + (unquote name) + " !" }
-m = macro (name) { quote "Hello, " + (unquote name) + " !" }
+quote m = macro (name) { quote "Hello, " + unquote(name) + " !" }
+m = macro (name) { quote "Hello, " + unquote(name) + " !" }
 quote m("Terrence")
 m("Terrence")
 quote n = "Phillip"
diff --git a/test/ic3/quote.in b/test/ic3/quote.in
index 4af054b..477ef1b 100644
--- a/test/ic3/quote.in
+++ b/test/ic3/quote.in
@@ -15,21 +15,21 @@ quote quote %{1 => 1}
 quote quote %{1 + 1 => 1}
 quote quote %{1 => 1 + 1}
 quote quote 1
-quote quote unquote a = 1 + 1
-quote quote unquote a + a
-quote quote %{a: unquote 1}
-quote quote %{unquote "a" => unquote 1}
-quote quote %{unquote 1 => unquote 1}
-quote quote %{unquote 1 => 1}
-quote quote %{unquote 1 + 1 => 1}
-quote quote %{1 => unquote 1 + 1}
-quote quote %{unquote unquote 1 + 1 => 1}
-quote quote %{1 => unquote unquote 1 + 1}
-quote unquote 1
-quote unquote a = 1 + 1
-quote unquote a + a
-quote unquote %{a: 1}
-quote unquote %{"a" => 1}
-quote unquote %{1 => 1}
-quote unquote %{1 + 1 => 1}
-quote unquote %{1 => 1 + 1}
+quote quote unquote(a = 1 + 1)
+quote quote unquote(a + a)
+quote quote %{a: unquote(1)}
+quote quote %{unquote("a") => unquote(1)}
+quote quote %{unquote(1) => unquote(1)}
+quote quote %{unquote(1) => 1}
+quote quote %{unquote(1 + 1) => 1}
+quote quote %{1 => unquote(1 + 1)}
+quote quote %{unquote(unquote(1 + 1)) => 1}
+quote quote %{1 => unquote(unquote(1 + 1))}
+quote unquote(1)
+quote unquote(a = 1 + 1)
+quote unquote(a + a)
+quote unquote(%{a: 1})
+quote unquote(%{"a" => 1})
+quote unquote(%{1 => 1})
+quote unquote(%{1 + 1 => 1})
+quote unquote(%{1 => 1 + 1})