]> git.lizzy.rs Git - nothing.git/blobdiff - src/script/expr.c
TODO(#394)
[nothing.git] / src / script / expr.c
index db0fa58d49296b2fae2c14ba18ee4784c2c48679..1ecec674efccfc9a362b050dee8a5d4fd1ba1d82 100644 (file)
@@ -7,25 +7,7 @@
 
 #include "script/expr.h"
 #include "script/gc.h"
-
-static char *string_duplicate(const char *str,
-                              const char *str_end)
-{
-    if (str_end != NULL && str > str_end) {
-        return NULL;
-    }
-
-    const size_t n = str_end == NULL ? strlen(str) : (size_t) (str_end - str);
-    char *dup_str = malloc(sizeof(char) * (n + 1));
-    if (dup_str == NULL) {
-        return NULL;
-    }
-
-    memcpy(dup_str, str, n);
-    dup_str[n] = '\0';
-
-    return dup_str;
-}
+#include "str.h"
 
 struct Expr atom_as_expr(struct Atom *atom)
 {
@@ -72,6 +54,10 @@ void print_atom_as_sexpr(struct Atom *atom)
     case ATOM_STRING:
         printf("\"%s\"", atom->str);
         break;
+
+    case ATOM_NATIVE:
+        printf("<native>");
+        break;
     }
 }
 
@@ -101,7 +87,6 @@ void print_cons_as_sexpr(struct Cons *head)
 
 void print_expr_as_sexpr(struct Expr expr)
 {
-    /* TODO(#296): print_expr_as_sexpr doesn't support lists */
     switch (expr.type) {
     case EXPR_ATOM:
         print_atom_as_sexpr(expr.atom);
@@ -236,6 +221,32 @@ error:
     return NULL;
 }
 
+struct Atom *create_native_atom(Gc *gc, NativeFunction fun, void *param)
+{
+    struct Atom *atom = malloc(sizeof(struct Atom));
+
+    if (atom == NULL) {
+        goto error;
+    }
+
+    atom->type = ATOM_NATIVE;
+    atom->native.fun = fun;
+    atom->native.param = param;
+
+    if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
+        goto error;
+    }
+
+    return atom;
+
+error:
+    if (atom != NULL) {
+        free(atom);
+    }
+
+    return NULL;
+}
+
 void destroy_atom(struct Atom *atom)
 {
     switch (atom->type) {
@@ -244,6 +255,7 @@ void destroy_atom(struct Atom *atom)
         free(atom->str);
     } break;
 
+    case ATOM_NATIVE:
     case ATOM_NUMBER: {
         /* Nothing */
     } break;
@@ -251,3 +263,98 @@ void destroy_atom(struct Atom *atom)
 
     free(atom);
 }
+
+static int atom_as_sexpr(struct Atom *atom, char *output, size_t n)
+{
+    assert(atom);
+    assert(output);
+
+    switch (atom->type) {
+    case ATOM_SYMBOL:
+        return snprintf(output, n, "%s", atom->sym);
+
+    case ATOM_NUMBER:
+        return snprintf(output, n, "%ld", atom->num);
+
+    case ATOM_STRING:
+        return snprintf(output, n, "\"%s\"", atom->str);
+
+    case ATOM_NATIVE:
+        return snprintf(output, n, "<native>");
+    }
+
+    return 0;
+}
+
+static int cons_as_sexpr(struct Cons *head, char *output, size_t n)
+{
+    assert(head);
+    assert(output);
+
+    /* TODO(#378): cons_as_sexpr does not handle encoding errors of snprintf */
+
+    struct Cons *cons = head;
+
+    int m = (int) n;
+
+    int c = snprintf(output, n, "(");
+    if (m - c <= c) {
+        return c;
+    }
+
+    c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
+    if (m - c <= 0) {
+        return c;
+    }
+
+    while (cons->cdr.type == EXPR_CONS) {
+        cons = cons->cdr.cons;
+
+        c += snprintf(output + c, (size_t) (m - c), " ");
+        if (m - c <= 0) {
+            return c;
+        }
+
+        c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
+        if (m - c <= 0) {
+            return c;
+        }
+    }
+
+    if (cons->cdr.atom->type != ATOM_SYMBOL ||
+        strcmp("nil", cons->cdr.atom->sym) != 0) {
+
+        c += snprintf(output + c, (size_t) (m - c), " . ");
+        if (m - c <= 0) {
+            return c;
+        }
+
+        c += expr_as_sexpr(cons->cdr, output + c, (size_t) (m - c));
+        if (m - c <= 0) {
+            return c;
+        }
+    }
+
+    c += snprintf(output + c, (size_t) (m - c), ")");
+    if (m - c <= 0) {
+        return c;
+    }
+
+    return c;
+}
+
+int expr_as_sexpr(struct Expr expr, char *output, size_t n)
+{
+    switch(expr.type) {
+    case EXPR_ATOM:
+        return atom_as_sexpr(expr.atom, output, n);
+
+    case EXPR_CONS:
+        return cons_as_sexpr(expr.cons, output, n);
+
+    case EXPR_VOID:
+        return 0;
+    }
+
+    return 0;
+}