diff --git a/.ikc3_history b/.ikc3_history
index dd47013..13d2a34 100644
--- a/.ikc3_history
+++ b/.ikc3_history
@@ -1,11 +1,3 @@
-a <- void
-a
-%KC3.Operator{symbol_value: void}
-%KC3.Operator{symbol_value: 1}
-%KC3.Operator{symbol_value: void}
-1; 2; 3
-1; 2
-1 ; 2
a = 1; 2
a = ?; 2
a
@@ -97,4 +89,11 @@ file.type == :dir
file = %{type: :dir, items = [%{type: file, items: []}]}
file = %{type: :dir, items: [%{type: file, items: []}]}
file = %{type: :dir, items: [%{type: :file, items: []}]}
-
+file = "plop.md"
+Str.starts_with?(file, ".") ||
+(Sw) 4 > 0
+q
+List.sort([1, 2, 3, 4])
+List.sort([4, 3, 2, 1])
+List.sort(["1. a", "2. bc", "3. cde", "4. fghi"])
+List.sort(["1. abcd", "2. efg", "3. hi", "4. j"])
diff --git a/doc/kc3/1. Introduction.en.md b/doc/kc3/1. Introduction.en.md
new file mode 100644
index 0000000..00e45ab
--- /dev/null
+++ b/doc/kc3/1. Introduction.en.md
@@ -0,0 +1,65 @@
+# 1 Introduction
+
+KC3 is currently a programming language project, inspired by C, Elixir
+and Common Lisp. It could be described as C with Elixir modules,
+pattern matching, and a semantic object system. The idea is to plug
+modules, closures, pattern matching, a graph database and
+metaprogramming into C99 with an extremely small set of dependencies.
+
+Supported operating systems (additionnal dependencies) :
+ - BSD
+ - Linux (libbsd, libmd)
+ - MacOS X (libmd)
+ - Windows (MSys2)
+
+Supported architectures :
+ - aarch64 (arm64, Apple M1, Apple M2)
+ - amd64
+ - i386
+ - sparc64
+
+
+## 1.1 Modules
+
+Everything in KC3 is in a module. A module is a namespace,
+and is named with a symbol starting with a uppercase character.
+For instance `Sym` and `Str` are valid module names.
+
+Each module can define a type and a module name can also be a
+type name if the corresponding module defines a type.
+
+The module can also include definitions for functions for
+operating on the module type or other types.
+
+The default module is `KC3`, which is defined as facts (triples)
+in `lib/kc3/0.1/kc3.facts`.
+
+
+## 1.2 Data types
+
+Basic data types in KC3 are :
+ - Strings : `Str`, e.g. `"Hello, world !"`
+ - Symbols : `Sym`, e.g. `:hello` or `Hello`
+ - Booleans : `Bool`, `true` or `false`
+ - Numbers
+ - Integers
+ - Small integers
+ - Signed small integers : `S8`, `S16`, `S32`, `S64`, `Sw`
+ - Unsigned small integers : `U8`, `U16`, `U32`, `U64`, `Uw`
+ - Large integers : `Integer`
+ - Rational numbers (fractions of integers) : `Ratio`, e.g. `-2/3`
+ - Floating point numbers : `F32`, `F64`, `F128`
+ - Complex numbers (i = √(-1)) : `Complex`, e.g. `1 +i 2`
+ - Lists : `List`, e.g. `[1, 2, 3]`
+ - Tuples : `Tuple`, e.g. `{:ok, 123}`
+ - Maps : `Map`, e.g. `%{id: 1, login: "dx"}`
+ - Structs : e.g. `%GL.Sphere{}`
+ - Quoted code : `Quote`, e.g. `quote 1 + 2`
+ - Identifiers : `Ident`, e.g. `quote hello`
+ - Function or operator call : `Call`, e.g. `quote sqrt(1)`, `quote 1 + 2`
+ - Code blocks : `Block`, e.g. `{ 1 + 2; 3 + 4 }`
+ - Function : `Fn`, e.g. `fn (x) { x * 2 }`
+ - C function : `Cfn`, e.g. `cfn Tag "tag_add" (Tag, Tag, Result)`
+ - Unquoted code: `Unquote`, e.g. `quote 1 + unquote(x)`
+ - Variables : `Var`, e.g. `?`
+ - Void : `Void`, e.g. `void`
diff --git a/doc/kc3/1_introduction.en.md b/doc/kc3/1_introduction.en.md
deleted file mode 100644
index c4dcca6..0000000
--- a/doc/kc3/1_introduction.en.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: 1. Introduction
----
-
-# Introduction
-
-KC3 is currently a programming language project, inspired by C, Elixir
-and Common Lisp. It could be described as C with Elixir modules,
-pattern matching, and a semantic object system. The idea is to plug
-modules, closures, pattern matching, a graph database and
-metaprogramming into C99 with an extremely small set of dependencies.
-
-Supported operating systems (additionnal dependencies) :
- - BSD
- - Linux (libbsd, libmd)
- - MacOS X (libmd)
- - Windows (MSys2)
-
-Supported architectures :
- - aarch64 (arm64, Apple M1, Apple M2)
- - amd64
- - i386
- - sparc64
-
-
-## Modules
-
-Everything in KC3 is in a module. A module is a namespace,
-and is named with a symbol starting with a uppercase character.
-For instance `Sym` and `Str` are valid module names.
-
-Each module can define a type and a module name can also be a
-type name if the corresponding module defines a type.
-
-The module can also include definitions for functions for
-operating on the module type or other types.
-
-The default module is `KC3`, which is defined as facts (triples)
-in `lib/kc3/0.1/kc3.facts`.
-
-
-## Data types
-
-Basic data types in KC3 are :
- - Strings : `Str`, e.g. `"Hello, world !"`
- - Symbols : `Sym`, e.g. `:hello` or `Hello`
- - Booleans : `Bool`, `true` or `false`
- - Numbers
- - Integers
- - Small integers
- - Signed small integers : `S8`, `S16`, `S32`, `S64`, `Sw`
- - Unsigned small integers : `U8`, `U16`, `U32`, `U64`, `Uw`
- - Large integers : `Integer`
- - Rational numbers (fractions of integers) : `Ratio`, e.g. `-2/3`
- - Floating point numbers : `F32`, `F64`, `F128`
- - Complex numbers (i = √(-1)) : `Complex`, e.g. `1 +i 2`
- - Lists : `List`, e.g. `[1, 2, 3]`
- - Tuples : `Tuple`, e.g. `{:ok, 123}`
- - Maps : `Map`, e.g. `%{id: 1, login: "dx"}`
- - Structs : e.g. `%GL.Sphere{}`
- - Quoted code : `Quote`, e.g. `quote 1 + 2`
- - Identifiers : `Ident`, e.g. `quote hello`
- - Function or operator call : `Call`, e.g. `quote sqrt(1)`, `quote 1 + 2`
- - Code blocks : `Block`, e.g. `{ 1 + 2; 3 + 4 }`
- - Function : `Fn`, e.g. `fn (x) { x * 2 }`
- - C function : `Cfn`, e.g. `cfn Tag "tag_add" (Tag, Tag, Result)`
- - Unquoted code: `Unquote`, e.g. `quote 1 + unquote(x)`
- - Variables : `Var`, e.g. `?`
- - Void : `Void`, e.g. `void`
diff --git a/doc/kc3/2. Integer.en.md b/doc/kc3/2. Integer.en.md
new file mode 100644
index 0000000..5ec89dc
--- /dev/null
+++ b/doc/kc3/2. Integer.en.md
@@ -0,0 +1,132 @@
+---
+title: 2. Integers
+---
+
+# Integers
+
+## Small integers
+
+IKC3 supports all C integer type sizes from `U8` (matching the C type `uint8_t`)
+to `U64` (matching the C type `uint64_t`) for unsigned integers,
+and from `S8` to `S64` for signed integers.
+
+In addition to these 8 basic integer types there are 2 pointer-sized
+integer types :
+`Uw` for unsigned pointer-sized integers,
+and `Sw` for signed pointer-sized integers.
+
+Small integers take little space, are static, they are passed directly and
+not as a pointer, and for these reasons are fast.
+
+They do not need to be cleaned after use and thus can be used in arrays like
+is usually done in C.
+
+```
+ikc3> type(-1)
+S8
+ikc3> type(-128)
+S16
+ikc3> type(-32768)
+S32
+ikc3> type(-2147483648)
+S64
+ikc3> type(-9223372036854775807)
+S64
+ikc3> type(0)
+U8
+ikc3> type(256)
+U16
+ikc3> type(65536)
+U32
+ikc3> type(4294967296)
+U64
+ikc3> type(18446744073709551615)
+U64
+```
+
+## Large integers
+
+IKC3 supports large integers and they are compatible with small integers.
+Their type is `Integer` and can support numbers as large as memory allows.
+They are slow because they are allocated dynamically on the heap
+using malloc.
+
+```
+ikc3> type(1000000000000000000000000000000)
+Integer
+```
+
+
+## Operations on integers
+
+### Operator `~`
+
+Binary not.
+
+```
+ikc3> ~ 1
+254
+ikc3> ~ -1
+0
+ikc3> ~ 0
+255
+ikc3> ~ 255
+0
+ikc3> ~ (U16) 1
+65534
+ikc3> ~ (S16) 1
+-2
+```
+
+### Operator `+`
+
+Integer addition.
+
+All positive integers can be defined in terms of addition of :
+zero or a positive integer, and one. E.g.
+
+```
+1 = 0 + 1
+2 = 0 + 1 + 1
+3 = 0 + 1 + 1 + 1
+etc.
+```
+
+### Operator `-`
+
+Integer subtraction. Take an integer and remove another integer from it.
+
+### Operator `*`
+
+Integer multiplication. Init result to zero, add an integer `a` and
+repeat `b` times.
+
+### Operator `/`
+
+Integer division. The inverse of multiplication :
+for all integers `a` and `b` there is a couple `q` and `r` that satisfies
+`a = b * q + r`. Integer division returns `q`.
+
+### Operator `mod`
+
+Integer modulo. Returns `r` in the previous equation (see Operator `/`)
+
+### Operator `<<`
+
+Left shift
+
+
+# Examples
+
+```
+ikc3> type(1)
+U8
+ikc3> type(1000000000000000000000000000000)
+Integer
+ikc3> a = 1 + 100000000000000000000000000000000
+100000000000000000000000000000001
+ikc3> a * a
+10000000000000000000000000000000200000000000000000000000000000001
+ikc3> a * a / 1000000000000000000000000000000000000000000000000000
+10000000000000
+```
diff --git a/doc/kc3/3. Map.en.md b/doc/kc3/3. Map.en.md
new file mode 100644
index 0000000..3c17511
--- /dev/null
+++ b/doc/kc3/3. Map.en.md
@@ -0,0 +1,46 @@
+---
+title: 3. Map
+---
+
+# Maps
+
+KC3 maps are like Elixir maps, they are key-values enclosed in `%{}` :
+
+```
+ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
+%{id: 1, title: "My title", message: "Hello, world !"}
+```
+
+Destructuring works with maps to extract values :
+
+```
+ikc3> %{id: id, title: "My title", message: message} = ^ a
+%{id: 1, title: "My title", message: "Hello, world !"}
+ikc3> id
+1
+ikc3> message
+"Hello, world !"
+```
+
+
+You can use the dot syntax to access map values from a `Sym` key :
+
+```
+ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
+%{id: 1, title: "My title", message: "Hello, world !"}
+ikc3> a.id
+1
+ikc3> a.message
+"Hello, world !"
+```
+
+You can also use the `KC3.access` function for the same result :
+
+```
+ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
+%{id: 1, title: "My title", message: "Hello, world !"}
+ikc3> access(a, :id)
+1
+ikc3> access(a, :message)
+"Hello, world !"
+```
diff --git a/doc/kc3/4. Ratio.en.md b/doc/kc3/4. Ratio.en.md
new file mode 100644
index 0000000..39f7c67
--- /dev/null
+++ b/doc/kc3/4. Ratio.en.md
@@ -0,0 +1,21 @@
+---
+title: 4. Ratio
+---
+
+# Ratios
+
+Ratios are made with a couple of large integers : the numerator
+which can be any number, and the denominator which has to be positive.
+They represent fractions of integral numbers.
+They are written with a slash and no space.
+
+```
+ikc3> 1/2 + 2/3
+7/6
+ikc3> 1/2 * 2/3
+1/3
+ikc3> 1/2 / 2/3
+3/4
+ikc3> 1/2 - 2/3
+-1/6
+```
diff --git a/doc/kc3/5. List.en.md b/doc/kc3/5. List.en.md
new file mode 100644
index 0000000..adf816e
--- /dev/null
+++ b/doc/kc3/5. List.en.md
@@ -0,0 +1,27 @@
+# Module List
+
+Regular lists can be :
+ - an element and a list : `[1 | [2]]`
+ - multiple elements : `[1, 2, 3]`
+ - multiple elements and a list : `[1, 2 | [3, 4]]`
+ - the empty list : `[]`
+
+Regular lists end with the empty list : `[1] == [1 | []]`.
+
+You can also contruct dotted lists like in Common Lisp where
+the next list pointer is an arbitrary form. E.g. :
+ - an element and an element : `[1 | 2]`
+ - multiple elements and an element : `[1, 2, 3 | 4]`
+ - the empty list and an element : `[[] | 1]`
+
+All these list formats are supported in pattern matching.
+
+## Functions
+
+```
+List List.map (List, Fn)
+```
+
+```
+List List.reverse (List)
+```
diff --git a/doc/kc3/6. Variable.en.md b/doc/kc3/6. Variable.en.md
new file mode 100644
index 0000000..5d12c8d
--- /dev/null
+++ b/doc/kc3/6. Variable.en.md
@@ -0,0 +1,68 @@
+# Variables
+
+Variables in C3 can be defined using the litteral value for a variable
+which is always `?`. You can cast this litteral value and it will not
+really be casted but it will give you a typed variable litteral value.
+E.g. `(List) ?`.
+The typed variable litteral value will only accept to be set once to
+one value of the variable's type (in this example the type of a linked
+list).
+
+It's actually a syntax so you cannot rename `?` by mistake and
+so is an easy task to do static analysis of variable creation.
+
+The default type for a variable which you can also specify explicitly
+is `Tag` which is an enum-tagged union type of any other C3 types
+currently defined in the environment. So `?` is exactly equivalent to
+`(Tag) ?` and they will both accept to be set once to one value of any
+type.
+
+Actually all variables are allocated as tags and in the end the typing
+is dynamic but it could be made static through JIT compilation of
+functions.
+
+A variable is settable once and cannot be changed afterwards (there is
+an exception if you write C code and link to it but it is not easy nor
+silent).
+
+This way you do not need to lock or trust any behaviour, once your
+variable is set to a value the value of the variable will never change,
+it really is read-only.
+
+
+## Init and C interoperatbility
+
+To set the value of a variable in the end you need to call a C function
+that should accept this C function definition :
+`quote cfn unquote(type) unquote("init_#{variable_type}#{init_suffix}") (Result, ...)`.
+There are many functions for this, here is a quick list :
+ - `tag_init_1` takes a C string as an argument and returns a value of
+ any type currently defined in the C3 environment.
+ - `#{type}_init_1` C functions take a C string as an argument and return
+ a value of type `type`.
+ - `tag_init_copy` takes a tag as an argument and returns a deep copy
+ of it.
+
+You can also use the assignment operator which is `<-` which in turn calls
+`tag_init_copy`. It works like the C assignment operator (`=`).
+
+Examples :
+```
+# Declare a unsigned byte 8 bits variable "x".
+x = (U8) ?
+# Set the variable "x" to zero.
+x <- 0
+# Allocate again for the same binding name "x"
+x = (U8) ?
+# Also set the new variable "x" to zero with just one Unicode symbol
+# that is AltGr+Y on my keyboard.
+x ← 0
+```
+
+
+## So how do I change anything if it is read-only ?
+
+You can always reset an existing binding at will to another variable
+litteral and another variable will be created for the same name and it
+will be in a different memory location, settable once and then
+read-only again so you can use it without locking.
diff --git a/doc/kc3/integer.en.md b/doc/kc3/integer.en.md
deleted file mode 100644
index 5ec89dc..0000000
--- a/doc/kc3/integer.en.md
+++ /dev/null
@@ -1,132 +0,0 @@
----
-title: 2. Integers
----
-
-# Integers
-
-## Small integers
-
-IKC3 supports all C integer type sizes from `U8` (matching the C type `uint8_t`)
-to `U64` (matching the C type `uint64_t`) for unsigned integers,
-and from `S8` to `S64` for signed integers.
-
-In addition to these 8 basic integer types there are 2 pointer-sized
-integer types :
-`Uw` for unsigned pointer-sized integers,
-and `Sw` for signed pointer-sized integers.
-
-Small integers take little space, are static, they are passed directly and
-not as a pointer, and for these reasons are fast.
-
-They do not need to be cleaned after use and thus can be used in arrays like
-is usually done in C.
-
-```
-ikc3> type(-1)
-S8
-ikc3> type(-128)
-S16
-ikc3> type(-32768)
-S32
-ikc3> type(-2147483648)
-S64
-ikc3> type(-9223372036854775807)
-S64
-ikc3> type(0)
-U8
-ikc3> type(256)
-U16
-ikc3> type(65536)
-U32
-ikc3> type(4294967296)
-U64
-ikc3> type(18446744073709551615)
-U64
-```
-
-## Large integers
-
-IKC3 supports large integers and they are compatible with small integers.
-Their type is `Integer` and can support numbers as large as memory allows.
-They are slow because they are allocated dynamically on the heap
-using malloc.
-
-```
-ikc3> type(1000000000000000000000000000000)
-Integer
-```
-
-
-## Operations on integers
-
-### Operator `~`
-
-Binary not.
-
-```
-ikc3> ~ 1
-254
-ikc3> ~ -1
-0
-ikc3> ~ 0
-255
-ikc3> ~ 255
-0
-ikc3> ~ (U16) 1
-65534
-ikc3> ~ (S16) 1
--2
-```
-
-### Operator `+`
-
-Integer addition.
-
-All positive integers can be defined in terms of addition of :
-zero or a positive integer, and one. E.g.
-
-```
-1 = 0 + 1
-2 = 0 + 1 + 1
-3 = 0 + 1 + 1 + 1
-etc.
-```
-
-### Operator `-`
-
-Integer subtraction. Take an integer and remove another integer from it.
-
-### Operator `*`
-
-Integer multiplication. Init result to zero, add an integer `a` and
-repeat `b` times.
-
-### Operator `/`
-
-Integer division. The inverse of multiplication :
-for all integers `a` and `b` there is a couple `q` and `r` that satisfies
-`a = b * q + r`. Integer division returns `q`.
-
-### Operator `mod`
-
-Integer modulo. Returns `r` in the previous equation (see Operator `/`)
-
-### Operator `<<`
-
-Left shift
-
-
-# Examples
-
-```
-ikc3> type(1)
-U8
-ikc3> type(1000000000000000000000000000000)
-Integer
-ikc3> a = 1 + 100000000000000000000000000000000
-100000000000000000000000000000001
-ikc3> a * a
-10000000000000000000000000000000200000000000000000000000000000001
-ikc3> a * a / 1000000000000000000000000000000000000000000000000000
-10000000000000
-```
diff --git a/doc/kc3/list.md b/doc/kc3/list.md
deleted file mode 100644
index adf816e..0000000
--- a/doc/kc3/list.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Module List
-
-Regular lists can be :
- - an element and a list : `[1 | [2]]`
- - multiple elements : `[1, 2, 3]`
- - multiple elements and a list : `[1, 2 | [3, 4]]`
- - the empty list : `[]`
-
-Regular lists end with the empty list : `[1] == [1 | []]`.
-
-You can also contruct dotted lists like in Common Lisp where
-the next list pointer is an arbitrary form. E.g. :
- - an element and an element : `[1 | 2]`
- - multiple elements and an element : `[1, 2, 3 | 4]`
- - the empty list and an element : `[[] | 1]`
-
-All these list formats are supported in pattern matching.
-
-## Functions
-
-```
-List List.map (List, Fn)
-```
-
-```
-List List.reverse (List)
-```
diff --git a/doc/kc3/map.en.md b/doc/kc3/map.en.md
deleted file mode 100644
index 3c17511..0000000
--- a/doc/kc3/map.en.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: 3. Map
----
-
-# Maps
-
-KC3 maps are like Elixir maps, they are key-values enclosed in `%{}` :
-
-```
-ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
-%{id: 1, title: "My title", message: "Hello, world !"}
-```
-
-Destructuring works with maps to extract values :
-
-```
-ikc3> %{id: id, title: "My title", message: message} = ^ a
-%{id: 1, title: "My title", message: "Hello, world !"}
-ikc3> id
-1
-ikc3> message
-"Hello, world !"
-```
-
-
-You can use the dot syntax to access map values from a `Sym` key :
-
-```
-ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
-%{id: 1, title: "My title", message: "Hello, world !"}
-ikc3> a.id
-1
-ikc3> a.message
-"Hello, world !"
-```
-
-You can also use the `KC3.access` function for the same result :
-
-```
-ikc3> a = %{id: 1, title: "My title", message: "Hello, world !"}
-%{id: 1, title: "My title", message: "Hello, world !"}
-ikc3> access(a, :id)
-1
-ikc3> access(a, :message)
-"Hello, world !"
-```
diff --git a/doc/kc3/ratio.en.md b/doc/kc3/ratio.en.md
deleted file mode 100644
index 39f7c67..0000000
--- a/doc/kc3/ratio.en.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: 4. Ratio
----
-
-# Ratios
-
-Ratios are made with a couple of large integers : the numerator
-which can be any number, and the denominator which has to be positive.
-They represent fractions of integral numbers.
-They are written with a slash and no space.
-
-```
-ikc3> 1/2 + 2/3
-7/6
-ikc3> 1/2 * 2/3
-1/3
-ikc3> 1/2 / 2/3
-3/4
-ikc3> 1/2 - 2/3
--1/6
-```
diff --git a/doc/kc3/variable.md b/doc/kc3/variable.md
deleted file mode 100644
index 5d12c8d..0000000
--- a/doc/kc3/variable.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# Variables
-
-Variables in C3 can be defined using the litteral value for a variable
-which is always `?`. You can cast this litteral value and it will not
-really be casted but it will give you a typed variable litteral value.
-E.g. `(List) ?`.
-The typed variable litteral value will only accept to be set once to
-one value of the variable's type (in this example the type of a linked
-list).
-
-It's actually a syntax so you cannot rename `?` by mistake and
-so is an easy task to do static analysis of variable creation.
-
-The default type for a variable which you can also specify explicitly
-is `Tag` which is an enum-tagged union type of any other C3 types
-currently defined in the environment. So `?` is exactly equivalent to
-`(Tag) ?` and they will both accept to be set once to one value of any
-type.
-
-Actually all variables are allocated as tags and in the end the typing
-is dynamic but it could be made static through JIT compilation of
-functions.
-
-A variable is settable once and cannot be changed afterwards (there is
-an exception if you write C code and link to it but it is not easy nor
-silent).
-
-This way you do not need to lock or trust any behaviour, once your
-variable is set to a value the value of the variable will never change,
-it really is read-only.
-
-
-## Init and C interoperatbility
-
-To set the value of a variable in the end you need to call a C function
-that should accept this C function definition :
-`quote cfn unquote(type) unquote("init_#{variable_type}#{init_suffix}") (Result, ...)`.
-There are many functions for this, here is a quick list :
- - `tag_init_1` takes a C string as an argument and returns a value of
- any type currently defined in the C3 environment.
- - `#{type}_init_1` C functions take a C string as an argument and return
- a value of type `type`.
- - `tag_init_copy` takes a tag as an argument and returns a deep copy
- of it.
-
-You can also use the assignment operator which is `<-` which in turn calls
-`tag_init_copy`. It works like the C assignment operator (`=`).
-
-Examples :
-```
-# Declare a unsigned byte 8 bits variable "x".
-x = (U8) ?
-# Set the variable "x" to zero.
-x <- 0
-# Allocate again for the same binding name "x"
-x = (U8) ?
-# Also set the new variable "x" to zero with just one Unicode symbol
-# that is AltGr+Y on my keyboard.
-x ← 0
-```
-
-
-## So how do I change anything if it is read-only ?
-
-You can always reset an existing binding at will to another variable
-litteral and another variable will be created for the same name and it
-will be in a different memory location, settable once and then
-read-only again so you can use it without locking.
diff --git a/lib/kc3/0.1/httpd.kc3 b/lib/kc3/0.1/httpd.kc3
index 26c9977..7570b9d 100644
--- a/lib/kc3/0.1/httpd.kc3
+++ b/lib/kc3/0.1/httpd.kc3
@@ -16,6 +16,27 @@ defmodule HTTPd do
def root_dir = "./static"
+ def load_directory = fn (dir) {
+ if (File.exists?(dir) &&
+ File.is_directory?(dir)) do
+ files = File.list(dir)
+ List.each(files, fn (file) {
+ if (! Str.starts_with?(file, ".")) do
+ load(dir + file)
+ end
+ })
+ end
+ }
+
+ def load_app = fn () {
+ HTTP.mime_type_load("config/mime.types")
+ load_directory("app/views/")
+ load_directory("app/controllers/")
+ if (File.exists?("config/routes.kc3")) do
+ load("config/routes.kc3")
+ end
+ }
+
def http_client = fn (socket, events, client_ev, client) do
if List.has?(events, :read) do
req = HTTP.Request.buf_parse(client.buf_rw.r)
@@ -58,18 +79,6 @@ defmodule HTTPd do
Socket.close(socket)
}
- def load_app = fn () {
- HTTP.mime_type_load("config/mime.types")
- controllers_dir = "app/controllers/"
- controllers = File.list(controllers_dir)
- List.each(controllers, fn (c) {
- load(controllers_dir + c)
- })
- if (File.exists?("config/routes.kc3")) do
- load("config/routes.kc3")
- end
- }
-
def main = fn {
() {
host = getenv("KC3_HTTPD_HOST")
diff --git a/lib/kc3/0.1/list.kc3 b/lib/kc3/0.1/list.kc3
index 303d350..2fad4e0 100644
--- a/lib/kc3/0.1/list.kc3
+++ b/lib/kc3/0.1/list.kc3
@@ -35,4 +35,6 @@ defmodule List do
([a | b], acc) { reverse(b, [a | acc]) }
}
+ def sort = cfn List "list_sort" (List, Result)
+
end
diff --git a/libkc3/compare.c b/libkc3/compare.c
index 530a78a..9cefbe0 100644
--- a/libkc3/compare.c
+++ b/libkc3/compare.c
@@ -472,19 +472,21 @@ s8 compare_s64_u64 (s64 a, u64 b)
s8 compare_str (const s_str *a, const s_str *b)
{
int r;
+ sw size;
assert(a);
assert(b);
if (a == b)
return 0;
- if (a->size < b->size)
- return -1;
- if (a->size > b->size)
- return 1;
- r = memcmp(a->ptr.p, b->ptr.p, a->size);
+ size = a->size < b->size ? a->size : b->size;
+ r = memcmp(a->ptr.p, b->ptr.p, size);
if (r < 0)
return -1;
if (r > 0)
return 1;
+ if (a->size < b->size)
+ return -1;
+ if (a->size > b->size)
+ return 1;
return 0;
}
@@ -845,6 +847,43 @@ s8 compare_tag (const s_tag *a, const s_tag *b) {
break;
}
break;
+ case TAG_SW:
+ switch (b->type) {
+ case TAG_F32: return compare_f32((f32) a->data.sw, b->data.f32);
+ case TAG_F64: return compare_f64((f64) a->data.sw, b->data.f64);
+ case TAG_F128:
+ return compare_f128((f128) a->data.sw, b->data.f128);
+ case TAG_INTEGER:
+ integer_init_s64(&tmp, a->data.sw);
+ r = compare_integer(&tmp, &b->data.integer);
+ integer_clean(&tmp);
+ return r;
+ case TAG_S8: return compare_sw(a->data.sw, (sw) b->data.s8);
+ case TAG_S16: return compare_sw(a->data.sw, (sw) b->data.s16);
+ case TAG_S32: return compare_sw(a->data.sw, (sw) b->data.s32);
+ case TAG_S64: return compare_sw(a->data.sw, (sw) b->data.s64);
+ case TAG_SW: return compare_sw(a->data.sw, b->data.sw);
+ case TAG_U8: return compare_sw(a->data.sw, (sw) b->data.u8);
+ case TAG_U16: return compare_sw(a->data.sw, (sw) b->data.u16);
+ case TAG_U32: return compare_sw(a->data.sw, (sw) b->data.u32);
+ case TAG_U64:
+ integer_init_sw(&tmp, a->data.sw);
+ integer_init_u64(&tmp2, b->data.u64);
+ r = compare_integer(&tmp, &tmp2);
+ integer_clean(&tmp);
+ integer_clean(&tmp2);
+ return r;
+ case TAG_UW:
+ integer_init_sw(&tmp, a->data.sw);
+ integer_init_uw(&tmp2, b->data.uw);
+ r = compare_integer(&tmp, &tmp2);
+ integer_clean(&tmp);
+ integer_clean(&tmp2);
+ return r;
+ default:
+ break;
+ }
+ break;
case TAG_U8:
switch (b->type) {
case TAG_F32: return compare_f32((f32) a->data.u8, b->data.f32);
@@ -860,7 +899,7 @@ s8 compare_tag (const s_tag *a, const s_tag *b) {
case TAG_S16: return compare_s16((s16) a->data.u8, b->data.s16);
case TAG_S32: return compare_s32((s32) a->data.u8, b->data.s32);
case TAG_S64: return compare_s64((s64) a->data.u8, b->data.s64);
- case TAG_SW: return compare_s64((s64) a->data.u8, (s64) b->data.sw);
+ case TAG_SW: return compare_sw((sw) a->data.u8, b->data.sw);
case TAG_U8: return compare_u8(a->data.u8, b->data.u8);
case TAG_U16: return compare_u16((u16) a->data.u8, b->data.u16);
case TAG_U32: return compare_u32((u32) a->data.u8, b->data.u32);
@@ -885,12 +924,12 @@ s8 compare_tag (const s_tag *a, const s_tag *b) {
case TAG_S16: return compare_s16((s16) a->data.u16, b->data.s16);
case TAG_S32: return compare_s32((s32) a->data.u16, b->data.s32);
case TAG_S64: return compare_s64((s64) a->data.u16, b->data.s64);
- case TAG_SW: return compare_s64((s64) a->data.u16, (s64) b->data.sw);
+ case TAG_SW: return compare_sw((sw) a->data.u16, b->data.sw);
case TAG_U8: return compare_u16(a->data.u16, (u16) b->data.u8);
case TAG_U16: return compare_u16(a->data.u16, b->data.u16);
case TAG_U32: return compare_u32((u32) a->data.u16, b->data.u32);
case TAG_U64: return compare_u64((u64) a->data.u16, b->data.u64);
- case TAG_UW: return compare_u64((u64) a->data.u16, (u64) b->data.uw);
+ case TAG_UW: return compare_uw((uw) a->data.u16, b->data.uw);
default:
break;
}
@@ -910,7 +949,7 @@ s8 compare_tag (const s_tag *a, const s_tag *b) {
case TAG_S16: return compare_s64((s64) a->data.u32, (s64) b->data.s16);
case TAG_S32: return compare_s64((s64) a->data.u32, (s64) b->data.s32);
case TAG_S64: return compare_s64((s64) a->data.u32, b->data.s64);
- case TAG_SW: return compare_s64((s64) a->data.u32, (s64) b->data.sw);
+ case TAG_SW: return compare_sw((sw) a->data.u32, b->data.sw);
case TAG_U8: return compare_u32(a->data.u32, (u32) b->data.u8);
case TAG_U16: return compare_u32(a->data.u32, (u32) b->data.u16);
case TAG_U32: return compare_u32((u32) a->data.u32, b->data.u32);
@@ -1063,6 +1102,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_integer_s64(&a->data.integer, b->data.s32);
case TAG_S64:
return compare_integer_s64(&a->data.integer, b->data.s64);
+ case TAG_SW:
+ return compare_integer_s64(&a->data.integer, b->data.sw);
case TAG_U8:
return compare_integer_u64(&a->data.integer, b->data.u8);
case TAG_U16:
@@ -1071,6 +1112,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_integer_u64(&a->data.integer, b->data.u32);
case TAG_U64:
return compare_integer_u64(&a->data.integer, b->data.u64);
+ case TAG_UW:
+ return compare_integer_u64(&a->data.integer, b->data.uw);
default: ;
}
break;
@@ -1086,6 +1129,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s32(a->data.s8, b->data.s32);
case TAG_S64:
return compare_s64(a->data.s8, b->data.s64);
+ case TAG_SW:
+ return compare_s64(a->data.s8, b->data.sw);
case TAG_U8:
return compare_s16(a->data.s8, b->data.u8);
case TAG_U16:
@@ -1094,6 +1139,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.s8, b->data.u32);
case TAG_U64:
return compare_s64_u64(a->data.s8, b->data.u64);
+ case TAG_UW:
+ return compare_s64_u64(a->data.s8, b->data.uw);
default: ;
}
break;
@@ -1109,6 +1156,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s32(a->data.s16, b->data.s32);
case TAG_S64:
return compare_s64(a->data.s16, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.s16, b->data.sw);
case TAG_U8:
return compare_s16(a->data.s16, b->data.u8);
case TAG_U16:
@@ -1117,6 +1166,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.s16, b->data.u32);
case TAG_U64:
return compare_s64_u64(a->data.s16, b->data.u64);
+ case TAG_UW:
+ return compare_s64_u64(a->data.s16, b->data.uw);
default: ;
}
break;
@@ -1132,6 +1183,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s32(a->data.s32, b->data.s32);
case TAG_S64:
return compare_s64(a->data.s32, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.s32, b->data.sw);
case TAG_U8:
return compare_s32(a->data.s32, b->data.u8);
case TAG_U16:
@@ -1140,6 +1193,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.s32, b->data.u32);
case TAG_U64:
return compare_s64_u64(a->data.s32, b->data.u64);
+ case TAG_UW:
+ return compare_s64_u64(a->data.s32, b->data.uw);
default: ;
}
break;
@@ -1155,6 +1210,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.s64, b->data.s32);
case TAG_S64:
return compare_s64(a->data.s64, b->data.s64);
+ case TAG_SW:
+ return compare_s64(a->data.s64, b->data.sw);
case TAG_U8:
return compare_s64(a->data.s64, b->data.u8);
case TAG_U16:
@@ -1163,6 +1220,35 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.s64, b->data.u32);
case TAG_U64:
return compare_s64_u64(a->data.s64, b->data.u64);
+ case TAG_UW:
+ return compare_s64_u64(a->data.s64, b->data.uw);
+ default: ;
+ }
+ break;
+ case TAG_SW:
+ switch (b->type) {
+ case TAG_INTEGER:
+ return -compare_integer_s64(&b->data.integer, a->data.sw);
+ case TAG_S8:
+ return compare_sw(a->data.sw, b->data.s8);
+ case TAG_S16:
+ return compare_sw(a->data.sw, b->data.s16);
+ case TAG_S32:
+ return compare_sw(a->data.sw, b->data.s32);
+ case TAG_S64:
+ return compare_s64(a->data.sw, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.sw, b->data.sw);
+ case TAG_U8:
+ return compare_sw(a->data.sw, b->data.u8);
+ case TAG_U16:
+ return compare_sw(a->data.sw, b->data.u16);
+ case TAG_U32:
+ return compare_sw(a->data.sw, b->data.u32);
+ case TAG_U64:
+ return compare_s64_u64(a->data.sw, b->data.u64);
+ case TAG_UW:
+ return compare_s64_u64(a->data.sw, b->data.uw);
default: ;
}
break;
@@ -1178,6 +1264,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s32(a->data.u8, b->data.s32);
case TAG_S64:
return compare_s64(a->data.u8, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.u8, b->data.sw);
case TAG_U8:
return compare_u8(a->data.u8, b->data.u8);
case TAG_U16:
@@ -1186,6 +1274,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_u32(a->data.u8, b->data.u32);
case TAG_U64:
return compare_u64(a->data.u8, b->data.u64);
+ case TAG_UW:
+ return compare_uw(a->data.u8, b->data.uw);
default: ;
}
break;
@@ -1201,6 +1291,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s32(a->data.u16, b->data.s32);
case TAG_S64:
return compare_s64(a->data.u16, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.u16, b->data.sw);
case TAG_U8:
return compare_u16(a->data.u16, b->data.u8);
case TAG_U16:
@@ -1209,6 +1301,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_u32(a->data.u16, b->data.u32);
case TAG_U64:
return compare_u64(a->data.u16, b->data.u64);
+ case TAG_UW:
+ return compare_uw(a->data.u16, b->data.uw);
default: ;
}
break;
@@ -1224,6 +1318,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_s64(a->data.u32, b->data.s32);
case TAG_S64:
return compare_s64(a->data.u32, b->data.s64);
+ case TAG_SW:
+ return compare_sw(a->data.u32, b->data.sw);
case TAG_U8:
return compare_u32(a->data.u32, b->data.u8);
case TAG_U16:
@@ -1232,6 +1328,8 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return compare_u32(a->data.u32, b->data.u32);
case TAG_U64:
return compare_u64(a->data.u32, b->data.u64);
+ case TAG_UW:
+ return compare_uw(a->data.u32, b->data.uw);
default: ;
}
break;
@@ -1247,14 +1345,45 @@ s8 compare_tag_number (const s_tag *a, const s_tag *b)
return -compare_s64_u64(b->data.s32, a->data.u64);
case TAG_S64:
return -compare_s64_u64(b->data.s64, a->data.u64);
+ case TAG_SW:
+ return -compare_s64_u64(b->data.sw, a->data.u64);
case TAG_U8:
return compare_u64(a->data.u64, b->data.u8);
case TAG_U16:
- return compare_u16(a->data.u64, b->data.u16);
+ return compare_u64(a->data.u64, b->data.u16);
case TAG_U32:
- return compare_u32(a->data.u64, b->data.u32);
+ return compare_u64(a->data.u64, b->data.u32);
case TAG_U64:
return compare_u64(a->data.u64, b->data.u64);
+ case TAG_UW:
+ return compare_u64(a->data.u64, b->data.uw);
+ default: ;
+ }
+ break;
+ case TAG_UW:
+ switch (b->type) {
+ case TAG_INTEGER:
+ return -compare_integer_u64(&b->data.integer, a->data.uw);
+ case TAG_S8:
+ return -compare_s64_u64(b->data.s8, a->data.uw);
+ case TAG_S16:
+ return -compare_s64_u64(b->data.s16, a->data.uw);
+ case TAG_S32:
+ return -compare_s64_u64(b->data.s32, a->data.uw);
+ case TAG_S64:
+ return -compare_s64_u64(b->data.s64, a->data.uw);
+ case TAG_SW:
+ return -compare_s64_u64(b->data.sw, a->data.uw);
+ case TAG_U8:
+ return compare_uw(a->data.uw, b->data.u8);
+ case TAG_U16:
+ return compare_uw(a->data.uw, b->data.u16);
+ case TAG_U32:
+ return compare_uw(a->data.uw, b->data.u32);
+ case TAG_U64:
+ return compare_uw(a->data.uw, b->data.u64);
+ case TAG_UW:
+ return compare_uw(a->data.uw, b->data.uw);
default: ;
}
break;
diff --git a/libkc3/list.c b/libkc3/list.c
index d524d7c..696b503 100644
--- a/libkc3/list.c
+++ b/libkc3/list.c
@@ -305,6 +305,31 @@ s_list ** list_remove_void (s_list **list)
return list;
}
+s_list ** list_sort (const s_list * const *list, s_list **dest)
+{
+ const s_list *l;
+ s_list *new_;
+ s_list *tmp;
+ s_list **t;
+ assert(list);
+ assert(dest);
+ tmp = NULL;
+ l = *list;
+ while (l) {
+ t = &tmp;
+ while (*t && compare_tag(&(*t)->tag, &l->tag) <= 0)
+ t = &(*t)->next.data.list;
+ if (! (new_ = list_new_tag_copy(&l->tag, *t))) {
+ list_delete_all(tmp);
+ return NULL;
+ }
+ *t = new_;
+ l = list_next(l);
+ }
+ *dest = tmp;
+ return dest;
+}
+
s_list ** list_tail (s_list **list)
{
s_list **tail;
diff --git a/libkc3/list.h b/libkc3/list.h
index 9dfc8d6..c7f9757 100644
--- a/libkc3/list.h
+++ b/libkc3/list.h
@@ -56,6 +56,7 @@ bool list_is_alist (const s_list * const *list);
bool list_is_plist (const s_list *list);
sw list_length (const s_list *list);
s_list * list_next (const s_list *list);
+s_list ** list_sort (const s_list * const *list, s_list **dest);
s_list ** list_tail (s_list **list);
s_array * list_to_array (const s_list *list, const s_sym *type,
s_array *dest);
diff --git a/test/httpd/app/controllers/doc_controller.kc3 b/test/httpd/app/controllers/doc_controller.kc3
index 815949b..20a57e3 100644
--- a/test/httpd/app/controllers/doc_controller.kc3
+++ b/test/httpd/app/controllers/doc_controller.kc3
@@ -1,32 +1,51 @@
defmodule DocController do
+ require EKC3
require File
+ require List
+ require Str
def doc_index = fn {
(path, path_md) { doc_index(path, path_md, path, []) }
([], path_md, dir, acc) { List.reverse(acc) }
([file | rest], path_md, dir, acc) {
- if (Str.starts_with?(file, ".")) do
+ if (Str.starts_with?(file, ".") ||
+ (Str.rindex_character(file, '.') > 0 &&
+ ! Str.ends_with?(file, ".md") &&
+ ! Str.ends_with?(file, ".html"))) do
doc_index(rest, path_md, dir, acc)
else
path = dir + file
- end_ = if Str.ends_with?(file, ".md") do -4 else
- if Str.ends_with?(file, ".html") do -6 else
- if Str.ends_with?(file, ".txt") do -5 else -1 end
- end
- end
- url = Str.slice(path, 1, end_)
+ name = ^ file
+ url = Str.slice(path, 1, -1)
if File.is_directory?(path) do
- items = doc_index(File.list(path), path_md, path + "/", [])
+ items = doc_index(List.sort(File.list(path)), path_md,
+ path + "/", [])
item = %{type: :dir,
url: url,
- name: file,
+ name: name,
items: items}
doc_index(rest, path_md, dir, [item | acc])
else
+ end_ = Str.rindex_character(name, '.')
+ if (end_ > 0) do
+ name = Str.slice(name, 0, end_)
+ end_ = Str.rindex_character(name, '.')
+ if (end_ > 0) do
+ name = Str.slice(name, 0, end_)
+ end
+ end
+ end_ = Str.rindex_character(url, '.')
+ if (end_ > 0) do
+ url = Str.slice(url, 0, end_)
+ end_ = Str.rindex_character(url, '.')
+ if (end_ > 0) do
+ url = Str.slice(url, 0, end_)
+ end
+ end
item = %{type: :file,
url: url,
- name: Str.slice(file, 0, end_),
+ name: name,
items: []}
doc_index(rest, path_md, dir, [item | acc])
end
@@ -41,18 +60,30 @@ defmodule DocController do
def route = fn (request) {
if (request.method == :get) do
- path_md = ".#{request.url}.md"
- if File.exists?(path_md) do
- index = doc_index("./doc/", path_md)
+ locale = "en"
+ path_html = ".#{request.url}/index.#{locale}.html"
+ if File.exists?(path_html) do
+ index = doc_index("./doc/", path_html)
menu = EKC3.render_file("app/templates/doc/menu.html.ekc3")
title = "kc3-lang.org"
- md = File.read(path_md)
- html = Markdown.to_html_str(md)
+ html = File.read(path_html)
page = EKC3.render_file("app/templates/doc/show.html.ekc3")
body = EKC3.render_file("app/templates/layout.html.ekc3")
%HTTP.Response{body: body}
else
- HTTPd.error_404_page(request)
+ path_md = ".#{request.url}.#{locale}.md"
+ if File.exists?(path_md) do
+ index = doc_index("./doc/", path_md)
+ menu = EKC3.render_file("app/templates/doc/menu.html.ekc3")
+ title = "kc3-lang.org"
+ md = File.read(path_md)
+ html = Markdown.to_html_str(md)
+ page = EKC3.render_file("app/templates/doc/show.html.ekc3")
+ body = EKC3.render_file("app/templates/layout.html.ekc3")
+ %HTTP.Response{body: body}
+ else
+ HTTPd.error_404_page(request)
+ end
end
else
HTTPd.error_404_page(request)