changeset 60:2144052c96b4

expr, value: Move interdependent types into dedicated header file
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 24 Aug 2019 21:25:59 +0200
parents f05f6a7896a3
children 81b4668981e6
files src/expr.c src/expr.h src/types.h src/value.c src/value.h
diffstat 5 files changed, 236 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/src/expr.c	Sat Aug 24 21:24:37 2019 +0200
+++ b/src/expr.c	Sat Aug 24 21:25:59 2019 +0200
@@ -1,66 +1,14 @@
 #include "expr.h"
 
+#include <src/value.h>
+#include <src/built-ins.h>
+
 #include <src/base/str.h>
 #include <src/base/vec.h>
 
 #include <assert.h>
 #include <stdio.h>
 
-static const yvalue_id_t YVALUE_ID_MARKER = 0xff00000000000000;
-
-bool yvalue_is_valid(yvalue_id_t id) {
-    return (id & YVALUE_ID_MARKER) == YVALUE_ID_MARKER;
-}
-
-YREF_TYPE yref_type(yref_t* ref) {
-    if ((ref->ref.id & YVALUE_ID_MARKER) == YVALUE_ID_MARKER) {
-        return YREF_ID;
-    }
-    return YREF_SYM;
-}
-
-yvalue_id_t yvalue_create(void);
-
-yref_t yref_new(void) {
-    yref_t ref = {.ref.id = yvalue_create() };
-    return ref;
-}
-
-yref_t yref_new_id(yvalue_id_t id) {
-    assert(yvalue_is_valid(id));
-    yref_t ref = {.ref.id = id};
-    return ref;
-}
-
-yref_t yref_new_str(ystr_t* sym) {
-    yref_t ref = {.ref.sym = *sym};
-    return ref;
-}
-
-yref_t yref_new_c(const char* sym) {
-    yref_t ref = {.ref.sym = ystr_new(sym)};
-    return ref;
-}
-
-ystr_t yref_debug(yref_t* ref) {
-    YREF_TYPE typ = yref_type(ref);
-    if (typ == YREF_ID) {
-        ystr_t s = ystr_new(NULL);
-        ystr_build(&s, "id:<%llu>", ref->ref.id);
-        return s;
-    } else if (typ == YREF_SYM) {
-        ystr_t s = ystr_new(NULL);
-        ystr_build(&s, "id:<\"%s\">", ystr_str(&ref->ref.sym));
-        return s;
-    }
-    return ystr_new("id:INVALID");
-}
-
-void yref_destroy(yref_t* ref) {
-    if (ref == NULL) return;
-    if (yref_type(ref) == YREF_SYM) ystr_destroy(&ref->ref.sym);
-}
-
 void yexpr_init(yexpr_t* v) {
     v->typ = YEXPR_UNDEF;
     memset(&v->value, 0, sizeof(v->value));
@@ -75,10 +23,13 @@
 void yexpr_destroy(yexpr_t* v) {
     if (v == NULL) return;
     switch (v->typ) {
+        // Cases where the value is internal to the yexpr_t value:
         case YEXPR_UNDEF:
         case YEXPR_NUMBER:
         case YEXPR_ATOM:
+        case YEXPR_BUILTIN:
             break;
+        // External values:
         case YEXPR_STRING:
             ystr_destroy(&v->value.str);
             break;
@@ -107,6 +58,12 @@
     v->value.n = n;
 }
 
+void yexpr_set_builtin(yexpr_t* v, YBUILTIN_TYPE b) {
+    yexpr_destroy(v);
+    v->typ = YEXPR_BUILTIN;
+    v->value.builtin = b;
+}
+
 void yexpr_set_str(yexpr_t* v, ystr_t str) {
     yexpr_destroy(v);
     v->typ = YEXPR_STRING;
@@ -181,6 +138,9 @@
             fprintf(stderr, "%s", ystr_str(&tmp));
             ystr_destroy(&tmp);
             break;
+        case YEXPR_BUILTIN:
+            fprintf(stderr, "%s", ybuiltin_name(expr->value.builtin));
+            break;
         case YEXPR_LIST:
             fprintf(stderr, "(");
             yexpr_t* var = YVEC_AT(&expr->value.list, 0, yexpr_t);
@@ -191,5 +151,7 @@
             }
             fprintf(stderr, ")");
             break;
+        default:
+            assert(false /* Unhandled YEXPR_TYPE */);
     }
 }
--- a/src/expr.h	Sat Aug 24 21:24:37 2019 +0200
+++ b/src/expr.h	Sat Aug 24 21:25:59 2019 +0200
@@ -1,133 +1,18 @@
 #ifndef src_expr_h
 #define src_expr_h
 
-#include <src/atom.h>
+#include <src/types.h>
 
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 
-#include <src/base/str.h>
-#include <src/base/vec.h>
-
 /**
  * @file expr.h
  * @addtogroup language
  * @{
  */
 
-/// @brief Numeric reference to a stored value or function (see value.h). Must
-/// have a MSB that is 0xff.
-typedef uint64_t yvalue_id_t;
-
-/**
- * @brief Checks if the id is a valid ID.
- */
-bool yvalue_is_valid(yvalue_id_t id);
-
-typedef enum {
-    YREF_UNDEF = 0,
-    YREF_ID = 1,
-    YREF_SYM = 2,
-} YREF_TYPE;
-
-/**
- * @brief A reference to a stored function or value. To be used as value (not
- * pointer).
- */
-typedef struct {
-    union {
-        ystr_t sym;
-        yvalue_id_t id;
-    } ref;
-} yref_t;
-
-/**
- * @brief Return type of a reference.
- */
-YREF_TYPE yref_type(yref_t* ref);
-
-/**
- * Create a new unnamed reference.
- */
-yref_t yref_new(void);
-
-/**
- * Create a new reference with the given ID.
- */
-yref_t yref_new_id(yvalue_id_t id);
-
-/**
- * Create a new reference to the given symbol. Takes ownership of `sym`, it must
- * not be freed afterwards.
- */
-yref_t yref_new_str(ystr_t* sym);
-
-/**
- * Create a new reference to the given symbol.
- */
-yref_t yref_new_c(const char* sym);
-
-/**
- * Create a debug description of ref.
- */
-ystr_t yref_debug(yref_t* ref);
-
-/**
- * @brief Deallocate memory used by the reference itself.
- */
-void yref_destroy(yref_t* ref);
-
-/**
- * @brief A yexpr_t can be a builtin (which looks like an ID), described by the
- * `builtin` field.
- */
-typedef enum {
-    YBUILTIN_UNDEF = 0,
-    YBUILTIN_FOR = 1,
-    YBUILTIN_LET = 2,
-    YBUILTIN_DEFN = 3,
-} YBUILTIN_TYPE;
-
-/**
- * @brief Type of an yexpr_t value.
- *
- * Each enum value corresponds to a union field being set.
- */
-typedef enum {
-    YEXPR_UNDEF = 0,
-    YEXPR_NUMBER = 1,
-    YEXPR_STRING = 2,
-    YEXPR_ATOM = 3,
-    YEXPR_LIST = 4,
-    YEXPR_REF = 5,
-    YEXPR_BUILTIN = 6,
-} YEXPR_TYPE;
-
-/**
- * A value. Can be either a fundamental value (number, string, atom) or a list
- * of values.
- */
-struct yexpr_t {
-    union {
-        /// A number.
-        long long n;
-        /// A literal string.
-        ystr_t str;
-        /// An atom.
-        yatom_t atom;
-        /// A list of yexpr_t.
-        yvec_t list;
-        /// A named reference (to a value or function described by yvalue_t).
-        yref_t ref;
-        /// A builtin such as `for`, `let`, ...
-        YBUILTIN_TYPE builtin;
-    } value;
-    YEXPR_TYPE typ;
-};
-
-typedef struct yexpr_t yexpr_t;
-
 /**
  * Initialize a yexpr_t to the undefined value.
  */
@@ -156,6 +41,11 @@
 void yexpr_set_str(yexpr_t* v, ystr_t str);
 
 /**
+ * Initialize a yexpr_t value with a builtin.
+ */
+void yexpr_set_builtin(yexpr_t* v, YBUILTIN_TYPE b);
+
+/**
  * Initialize a yexpr_t with an atom.
  */
 void yexpr_set_atom(yexpr_t* v, yatom_t atom);
@@ -193,6 +83,8 @@
  * If `expr` is uninitialized or a list: append `arg` to it. If it is a value:
  * Append value to a new list, append `arg` to the list, and assign the list to
  * `expr`.
+ *
+ * Ownership of arg goes to `expr`; do not explicitly destroy `arg`.
  */
 void yexpr_init_or_extend(yexpr_t* expr, yexpr_t arg);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/types.h	Sat Aug 24 21:25:59 2019 +0200
@@ -0,0 +1,112 @@
+#ifndef src_types_h
+#define src_types_h
+
+/**
+ * @file types.h
+ * @brief Collection of inter-dependent types used by the core implementation.
+ * @addtogroup language
+ * @{
+ */
+
+#include <src/atom.h>
+#include <src/base/str.h>
+#include <src/base/vec.h>
+
+/// @brief Numeric reference to a stored value or function (see value.h). Must
+/// have a MSB that is 0xff.
+typedef uint64_t yvalue_id_t;
+
+/**
+ * @brief Type of a reference: Symbolic or numeric.
+ *
+ * Symbolic references can be resolved to a numeric one, creating a "value slot" (see `value.h`).
+ */
+typedef enum {
+    YREF_UNDEF = 0,
+    YREF_ID = 1,
+    YREF_SYM = 2,
+} YREF_TYPE;
+
+/**
+ * @brief A reference to a stored function or value. To be used as value (not
+ * pointer).
+ */
+typedef struct {
+    union {
+        ystr_t sym;
+        yvalue_id_t id;
+    } ref;
+} yref_t;
+
+/**
+ * @brief A yexpr_t can be a builtin (which looks like an ID), described by the
+ * `builtin` field.
+ *
+ * NOTE: Don't forget updating YBUILTIN_ENUM_STR when adding types here.
+ */
+typedef enum {
+    YBUILTIN_UNDEF = 0,
+    YBUILTIN_FOR = 1,
+    YBUILTIN_LET = 2,
+    YBUILTIN_DEFN = 3,
+
+    YBUILTIN_PLUS = 4,
+    YBUILTIN_MINUS = 5,
+    YBUILTIN_MULT = 6,
+    YBUILTIN_DIV = 7,
+
+    YBUILTIN_IF = 8,
+    YBUILTIN_SEQ = 9,
+} YBUILTIN_TYPE;
+
+/**
+ * @brief Type of an yexpr_t value.
+ *
+ * Each enum value corresponds to a union field being set.
+ */
+typedef enum {
+    YEXPR_UNDEF = 0,
+    YEXPR_NUMBER = 1,
+    YEXPR_STRING = 2,
+    YEXPR_ATOM = 3,
+    YEXPR_LIST = 4,
+    YEXPR_REF = 5,
+    YEXPR_BUILTIN = 6,
+} YEXPR_TYPE;
+
+/**
+ * A value. Can be either a fundamental value (number, string, atom) or a list
+ * of values.
+ */
+struct yexpr_t {
+    union {
+        /// A number.
+        long long n;
+        /// A literal string.
+        ystr_t str;
+        /// An atom.
+        yatom_t atom;
+        /// A list of yexpr_t.
+        yvec_t list;
+        /// A named reference (to a value or function described by yvalue_t).
+        yref_t ref;
+        /// A builtin such as `for`, `let`, ...
+        YBUILTIN_TYPE builtin;
+    } value;
+    YEXPR_TYPE typ;
+};
+
+typedef struct yexpr_t yexpr_t;
+
+/**
+ * @brief Type of a built-in function called during execution.
+ *
+ * The functions return a yexpr_t of which the caller assumes ownership.
+ */
+typedef yexpr_t (*ybuiltin_fn)(yvec_t* call_stack);
+
+
+/**
+ * @}
+ */
+#endif
--- a/src/value.c	Sat Aug 24 21:24:37 2019 +0200
+++ b/src/value.c	Sat Aug 24 21:25:59 2019 +0200
@@ -36,6 +36,8 @@
 // reference-counting in different table)
 static yvalue_id_t yvalue_counter = YVALUE_COUNTER_OFFSET;
 
+static const yvalue_id_t YVALUE_ID_MARKER = 0xff00000000000000;
+
 static inline void yvalue_init_tables(void) {
     if (yvalue_table_initialized) return;
     yvalue_table_initialized = true;
@@ -43,6 +45,60 @@
     YVEC_INIT(&yvalue_table, YVALUE_INITIAL_VALUES, yvalue_t);
 }
 
+bool yvalue_is_valid(yvalue_id_t id) {
+    return (id & YVALUE_ID_MARKER) == YVALUE_ID_MARKER;
+}
+
+YREF_TYPE yref_type(yref_t* ref) {
+    if ((ref->ref.id & YVALUE_ID_MARKER) == YVALUE_ID_MARKER) {
+        return YREF_ID;
+    }
+    return YREF_SYM;
+}
+
+yvalue_id_t yvalue_create(void);
+
+yref_t yref_new(void) {
+    yref_t ref = {.ref.id = yvalue_create() };
+    return ref;
+}
+
+yref_t yref_new_id(yvalue_id_t id) {
+    assert(yvalue_is_valid(id));
+    yref_t ref = {.ref.id = id};
+    return ref;
+}
+
+yref_t yref_new_str(ystr_t* sym) {
+    yref_t ref = {.ref.sym = *sym};
+    return ref;
+}
+
+yref_t yref_new_c(const char* sym) {
+    yref_t ref = {.ref.sym = ystr_new(sym)};
+    return ref;
+}
+
+ystr_t yref_debug(yref_t* ref) {
+    YREF_TYPE typ = yref_type(ref);
+    if (typ == YREF_ID) {
+        ystr_t s = ystr_new(NULL);
+        ystr_build(&s, "id:<%llu>", ref->ref.id);
+        return s;
+    } else if (typ == YREF_SYM) {
+        ystr_t s = ystr_new(NULL);
+        ystr_build(&s, "id:<\"%s\">", ystr_str(&ref->ref.sym));
+        return s;
+    }
+    return ystr_new("id:INVALID");
+}
+
+void yref_destroy(yref_t* ref) {
+    if (ref == NULL) return;
+    if (yref_type(ref) == YREF_SYM) ystr_destroy(&ref->ref.sym);
+}
+
+
 void yvalue_destroy(yvalue_t* val) {
     switch (val->typ) {
         case YVALUE_EXPR:
--- a/src/value.h	Sat Aug 24 21:24:37 2019 +0200
+++ b/src/value.h	Sat Aug 24 21:25:59 2019 +0200
@@ -8,6 +8,7 @@
 
 #include <src/expr.h>
 #include <src/func.h>
+#include <src/types.h>
 
 #include <src/base/str.h>
 #include <src/base/vec.h>
@@ -34,6 +35,48 @@
 };
 
 /**
+ * @brief Checks if the id is a valid ID.
+ */
+bool yvalue_is_valid(yvalue_id_t id);
+
+/**
+ * @brief Return type of a reference.
+ */
+YREF_TYPE yref_type(yref_t* ref);
+
+/**
+ * Create a new unnamed reference.
+ */
+yref_t yref_new(void);
+
+/**
+ * Create a new reference with the given ID.
+ */
+yref_t yref_new_id(yvalue_id_t id);
+
+/**
+ * Create a new reference to the given symbol. Takes ownership of `sym`, it must
+ * not be freed afterwards.
+ */
+yref_t yref_new_str(ystr_t* sym);
+
+/**
+ * Create a new reference to the given symbol.
+ */
+yref_t yref_new_c(const char* sym);
+
+/**
+ * Create a debug description of ref.
+ */
+ystr_t yref_debug(yref_t* ref);
+
+/**
+ * @brief Deallocate memory used by the reference itself.
+ */
+void yref_destroy(yref_t* ref);
+
+
+/**
  * @brief A value with a name, stored in the global value table to be referenced
  * by name or ID. To be used as pointer (not value).
  *