aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2024-11-30 11:09:46 +0800
committerRunxi Yu <me@runxiyu.org>2024-11-30 11:09:46 +0800
commit82ba4d44d17e86890da95aeeaae9cc550e3187e6 (patch)
treebd43165634c465ae1a7aca6224e5300908f64cd5 /README.md
parentLICENSE: CC0 (diff)
downloade2-spec-82ba4d44d17e86890da95aeeaae9cc550e3187e6.tar.gz
e2-spec-82ba4d44d17e86890da95aeeaae9cc550e3187e6.tar.zst
e2-spec-82ba4d44d17e86890da95aeeaae9cc550e3187e6.zip
README.md: Initial write-up
Diffstat (limited to 'README.md')
-rw-r--r--README.md73
1 files changed, 73 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..acbc43a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,73 @@
+# e2 language testing space
+
+Many languages attempt to be "memory safe" by processes such as reference
+counting, borrow checking, and mark-and-sweep garbage collection. These, for
+the most part, are guided towards preventing programmer error that causes
+use-after-frees, memory leaks, and similar conditions. We hereby refer to them
+as "conventional memory safety features".
+
+However, in most cases, languages other than assembly (including these allegedly
+memory safe languages) do not handle stack overflows correctly;
+although dynamic allocation failures could be easily handled, correctly-written
+programs could crash when running out of stack space, with no method to detect
+this condition and fail gracefully.
+
+Conventional memory safety features are not our priority, but we may choose to
+include them in the future, likely with reference counting while allowing weak
+pointers to be labelled.
+
+## General idea of how it should work
+
+We haven't decided on general syntax yet. We generally prefer C-like syntax,
+although syntax inspired from other languages are occasionally used when
+appropriate; for example, multiple return values look rather awkward in the C
+syntax, so perhaps we could use Go syntax for that (`func f(param1, return2)
+(return1, return2)`), although we'd prefer naming parameters with `type
+identifier` rather than `identifier type`.
+
+For stack safety: When defining a function, the programmer must specify what to
+do if the function could not be called (for example, if the stack if full). For
+example, `malloc` for allocating dynamic memory would be structured something
+like follows:
+
+```e2
+func malloc(size_t s) (void*) {
+ /* What malloc is supposed to do */
+ return ptr;
+} onfail {
+ return NULL;
+}
+```
+
+If something causes `malloc` to be uncallable, e.g. if there is insufficient
+stack space to hold its local variables, it simply returns NULL as if it failed.
+
+Other functions may have different methods of failure. Some might return an
+error, so it might be natural to set their error return value to something like
+`ESTACK`:
+
+```e2
+func f() (err) {
+ return NIL;
+} onfail {
+ return ESTACK;
+}
+```
+
+The above lets us define how functions should fail due to insufficient stack.
+This pattern is also useful outside of functions as a unit, therefore we
+introduce the following syntax for generic stack failure handling:
+
+```e2
+try {
+ /* Do something */
+} onfail {
+ /* Do something else, perhaps returning errors */
+}
+```
+
+Note that since (almost) arbitrary code could be placed in the `onfail` block
+(both in case of functions and in case of try/onfail), the `onfail` block must
+not fail; therefore, the compiler must begin to fail functions, whenever
+subroutines that those functions call have `onfail` blocks that would be
+impossible to fulfill due to stack size constraints.