Bladeren bron

ncd: Implement registration of functions by modules.

Ambroz Bizjak 11 jaren geleden
bovenliggende
commit
3da656da45
5 gewijzigde bestanden met toevoegingen van 202 en 2 verwijderingen
  1. 86 0
      ncd/NCDModule.h
  2. 80 0
      ncd/NCDModuleIndex.c
  3. 22 2
      ncd/NCDModuleIndex.h
  4. 12 0
      ncd/NCDModuleIndex_fhash.h
  5. 2 0
      ncd/NCDModuleIndex_func_vec.h

+ 86 - 0
ncd/NCDModule.h

@@ -37,6 +37,7 @@
 #include <base/BLog.h>
 #include <ncd/NCDObject.h>
 #include <ncd/NCDStringIndex.h>
+#include <ncd/NCDEvaluator.h>
 
 #ifndef BADVPN_NO_PROCESS
 #include <system/BProcess.h>
@@ -59,6 +60,7 @@ struct NCDModuleProcess_s;
 struct NCDModuleGroup;
 struct NCDInterpModule;
 struct NCDInterpModuleGroup;
+struct NCDInterpFunction;
 
 /**
  * Function called to inform the interpeter of state changes of the
@@ -958,6 +960,13 @@ struct NCDModuleGroup {
      * {@link NCDInterpModuleGroup}.
      */
     const char *const*strings;
+    
+    /**
+     * A pointer to an array of global functions implemented by this module
+     * group. The array must be terminated with a structure that has a NULL
+     * func_name member. May be NULL.
+     */
+    struct NCDModuleFunction const *functions;
 };
 
 /**
@@ -1008,4 +1017,81 @@ struct NCDInterpModuleGroup {
     void *group_state;
 };
 
+/**
+ * Contains parameters to {@link NCDModuleFunction_func_eval} that are passed indirectly.
+ */
+struct NCDModuleFunction_eval_params {
+    /**
+     * A pointer to the {@link NCDInterpFunction} structure for the function being called.
+     */
+    struct NCDInterpFunction const *ifunc;
+};
+
+/**
+ * Callback for evaluating a function (defined by an {@link NCDModuleFunction} structure).
+ * 
+ * @param args arguments to evaluate the function with.
+ *             These arguments are provided in a lazy manner - an argument
+ *             must be evaluated to obtain its value.
+ * @param mem an existing value memory object to store the value into
+ * @param out on success, *out should be set to the value reference to
+ *            the evaluated value, residing in the specified memory
+ *            object. It is permitted to return success but store an
+ *            invalid value reference here, which is understood as an
+ *            error.
+ * @param params indirectly passed arguments
+ * @return 1 on success, 0 on error (but see the description of the out parameter).
+ */
+typedef int (*NCDModuleFunction_func_eval) (NCDEvaluatorArgs args, NCDValMem *mem, NCDValRef *out, struct NCDModuleFunction_eval_params const *params);
+
+struct NCDModuleFunction {
+    /**
+     * The name of the function.
+     * NULL to terminate the array of functions.
+     */
+    char const *func_name;
+    
+    /**
+     * Callback for evaluating the function.
+     * 
+     * @param group the group the function belongs to
+     * @param func pointer to this structure. It can be used to implement
+     *             different functions in the same callback, by reading the
+     *             func_name member.
+     * @param args used to access the arguments to the function, in a lazily
+     *             evaluated manner
+     * @param mem an existing value memory object to store the result to
+     * @param out on success, *out should be set to the value reference to
+     *            the evaluated value, residing in the specified memory
+     *            object. It is permitted to return success but store an
+     *            invalid value reference here, which is understood as an
+     *            error.
+     * @return 1 on success, 0 on error (but see above).
+     */
+    NCDModuleFunction_func_eval func_eval;
+};
+
+/**
+ * Represents an {@link NCDModuleFunction} within an interpreter.
+ * This structure is initialized by the interpreter when it loads a module group.
+ */
+struct NCDInterpFunction {
+    /**
+     * A copy of the original NCDModuleFunction structure.
+     */
+    struct NCDModuleFunction function;
+    
+    /**
+     * The string identifier of this functions's name. according to
+     * {@link NCDStringIndex}.
+     */
+    NCD_string_id_t func_name_id;
+    
+    /**
+     * A pointer to the {@link NCDInterpModuleGroup} representing the group
+     * this function belongs to.
+     */
+    struct NCDInterpModuleGroup *group;
+};
+
 #endif

+ 80 - 0
ncd/NCDModuleIndex.c

@@ -45,6 +45,12 @@
 #include "NCDModuleIndex_mhash.h"
 #include <structure/CHash_impl.h>
 
+#include "NCDModuleIndex_func_vec.h"
+#include <structure/Vector_impl.h>
+
+#include "NCDModuleIndex_fhash.h"
+#include <structure/CHash_impl.h>
+
 static int string_pointer_comparator (void *user, void *v1, void *v2)
 {
     const char **s1 = v1;
@@ -132,9 +138,25 @@ int NCDModuleIndex_Init (NCDModuleIndex *o, NCDStringIndex *string_index)
         goto fail1;
     }
     
+    // init functions vector
+    if (!NCDModuleIndex__FuncVec_Init(&o->func_vec, NCDMODULEINDEX_FUNCTIONS_VEC_INITIAL_SIZE)) {
+        BLog(BLOG_ERROR, "NCDModuleIndex__FuncVec_Init failed");
+        goto fail2;
+    }
+    
+    // init functions hash
+    if (!NCDModuleIndex__FuncHash_Init(&o->func_hash, NCDMODULEINDEX_FUNCTIONS_HASH_SIZE)) {
+        BLog(BLOG_ERROR, "NCDModuleIndex__FuncHash_Init failed");
+        goto fail3;
+    }
+    
     DebugObject_Init(&o->d_obj);
     return 1;
     
+fail3:
+    NCDModuleIndex__FuncVec_Free(&o->func_vec);
+fail2:
+    NCDMethodIndex_Free(&o->method_index);
 fail1:
     NCDModuleIndex__MHash_Free(&o->modules_hash);
 fail0:
@@ -167,6 +189,12 @@ void NCDModuleIndex_Free (NCDModuleIndex *o)
     }
 #endif
     
+    // free functions hash
+    NCDModuleIndex__FuncHash_Free(&o->func_hash);
+    
+    // free functions vector
+    NCDModuleIndex__FuncVec_Free(&o->func_vec);
+    
     // free method index
     NCDMethodIndex_Free(&o->method_index);
     
@@ -310,8 +338,48 @@ int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *gro
         goto fail3;
     }
     
+    size_t prev_func_count = NCDModuleIndex__FuncVec_Count(&o->func_vec);
+    
+    if (group->functions) {
+        for (struct NCDModuleFunction const *mfunc = group->functions; mfunc->func_name; mfunc++) {
+            NCD_string_id_t func_name_id = NCDStringIndex_Get(string_index, mfunc->func_name);
+            if (func_name_id < 0) {
+                BLog(BLOG_ERROR, "NCDStringIndex_Get failed");
+                goto fail4;
+            }
+            
+            NCDModuleIndex__FuncHashRef lookup_ref = NCDModuleIndex__FuncHash_Lookup(&o->func_hash, o, func_name_id);
+            if (lookup_ref.link >= 0) {
+                BLog(BLOG_ERROR, "Function already exists: %s", mfunc->func_name);
+                goto fail4;
+            }
+            
+            size_t func_index;
+            struct NCDModuleIndex__Func *func = NCDModuleIndex__FuncVec_Push(&o->func_vec, &func_index);
+            if (!func) {
+                BLog(BLOG_ERROR, "NCDModuleIndex__FuncVec_Push failed");
+                goto fail4;
+            }
+            
+            func->ifunc.function = *mfunc;
+            func->ifunc.func_name_id = func_name_id;
+            func->ifunc.group = &ig->igroup;
+            
+            NCDModuleIndex__FuncHashRef ref = {func, func_index};
+            int res = NCDModuleIndex__FuncHash_Insert(&o->func_hash, o, ref, NULL);
+            ASSERT_EXECUTE(res)
+        }
+    }
+    
     return 1;
     
+fail4:
+    while (NCDModuleIndex__FuncVec_Count(&o->func_vec) > prev_func_count) {
+        size_t func_index;
+        struct NCDModuleIndex__Func *func = NCDModuleIndex__FuncVec_Pop(&o->func_vec, &func_index);
+        NCDModuleIndex__FuncHashRef ref = {func, func_index};
+        NCDModuleIndex__FuncHash_Remove(&o->func_hash, o, ref);
+    }
 fail3:
     while (num_inited_modules-- > 0) {
         struct NCDModuleIndex_module *m = &ig->modules[num_inited_modules];
@@ -370,3 +438,15 @@ const struct NCDInterpModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o
     
     return NCDMethodIndex_GetMethodModule(&o->method_index, obj_type, method_name_id);
 }
+
+const struct NCDInterpFunction * NCDModuleIndex_FindFunction (NCDModuleIndex *o, NCD_string_id_t func_name_id)
+{
+    DebugObject_Access(&o->d_obj);
+    
+    NCDModuleIndex__FuncHashRef lookup_ref = NCDModuleIndex__FuncHash_Lookup(&o->func_hash, o, func_name_id);
+    if (lookup_ref.link < 0) {
+        return NULL;
+    }
+    
+    return &lookup_ref.ptr->ifunc;
+}

+ 22 - 2
ncd/NCDModuleIndex.h

@@ -34,11 +34,15 @@
 #include <structure/BAVL.h>
 #include <structure/CHash.h>
 #include <structure/LinkedList0.h>
+#include <structure/Vector.h>
 #include <base/DebugObject.h>
+#include <ncd/NCDStringIndex.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDMethodIndex.h>
 
 #define NCDMODULEINDEX_MODULES_HASH_SIZE 512
+#define NCDMODULEINDEX_FUNCTIONS_VEC_INITIAL_SIZE 32
+#define NCDMODULEINDEX_FUNCTIONS_HASH_SIZE 64
 
 struct NCDModuleIndex_module {
     struct NCDInterpModule imodule;
@@ -60,21 +64,36 @@ struct NCDModuleIndex_group {
     struct NCDModuleIndex_module modules[];
 };
 
+struct NCDModuleIndex__Func {
+    struct NCDInterpFunction ifunc;
+    int hash_next;
+};
+
 typedef struct NCDModuleIndex_module *NCDModuleIndex__mhash_link;
 typedef const char *NCDModuleIndex__mhash_key;
 
+typedef struct NCDModuleIndex_s NCDModuleIndex;
+
 #include "NCDModuleIndex_mhash.h"
 #include <structure/CHash_decl.h>
 
-typedef struct {
+#include "NCDModuleIndex_func_vec.h"
+#include <structure/Vector_decl.h>
+
+#include "NCDModuleIndex_fhash.h"
+#include <structure/CHash_decl.h>
+
+struct NCDModuleIndex_s {
     NCDModuleIndex__MHash modules_hash;
 #ifndef NDEBUG
     BAVL base_types_tree;
 #endif
     LinkedList0 groups_list;
     NCDMethodIndex method_index;
+    NCDModuleIndex__FuncVec func_vec;
+    NCDModuleIndex__FuncHash func_hash;
     DebugObject d_obj;
-} NCDModuleIndex;
+};
 
 int NCDModuleIndex_Init (NCDModuleIndex *o, NCDStringIndex *string_index) WARN_UNUSED;
 void NCDModuleIndex_Free (NCDModuleIndex *o);
@@ -82,5 +101,6 @@ int NCDModuleIndex_AddGroup (NCDModuleIndex *o, const struct NCDModuleGroup *gro
 const struct NCDInterpModule * NCDModuleIndex_FindModule (NCDModuleIndex *o, const char *type);
 int NCDModuleIndex_GetMethodNameId (NCDModuleIndex *o, const char *method_name);
 const struct NCDInterpModule * NCDModuleIndex_GetMethodModule (NCDModuleIndex *o, NCD_string_id_t obj_type, int method_name_id);
+const struct NCDInterpFunction * NCDModuleIndex_FindFunction (NCDModuleIndex *o, NCD_string_id_t func_name_id);
 
 #endif

+ 12 - 0
ncd/NCDModuleIndex_fhash.h

@@ -0,0 +1,12 @@
+#define CHASH_PARAM_NAME NCDModuleIndex__FuncHash
+#define CHASH_PARAM_ENTRY struct NCDModuleIndex__Func
+#define CHASH_PARAM_LINK int
+#define CHASH_PARAM_KEY NCD_string_id_t
+#define CHASH_PARAM_ARG NCDModuleIndex *
+#define CHASH_PARAM_NULL ((int)-1)
+#define CHASH_PARAM_DEREF(arg, link) (NCDModuleIndex__FuncVec_Get(&(arg)->func_vec, (link)))
+#define CHASH_PARAM_ENTRYHASH(arg, entry) ((size_t)(entry).ptr->ifunc.func_name_id)
+#define CHASH_PARAM_KEYHASH(arg, key) ((size_t)(key))
+#define CHASH_PARAM_COMPARE_ENTRIES(arg, entry1, entry2) ((entry1).ptr->ifunc.func_name_id == (entry2).ptr->ifunc.func_name_id)
+#define CHASH_PARAM_COMPARE_KEY_ENTRY(arg, key1, entry2) ((key1) == (entry2).ptr->ifunc.func_name_id)
+#define CHASH_PARAM_ENTRY_NEXT hash_next

+ 2 - 0
ncd/NCDModuleIndex_func_vec.h

@@ -0,0 +1,2 @@
+#define VECTOR_NAME NCDModuleIndex__FuncVec
+#define VECTOR_ELEM_TYPE struct NCDModuleIndex__Func