Kaynağa Gözat

ncd: Refactoring to support upcoming function calls.

Ambroz Bizjak 11 yıl önce
ebeveyn
işleme
4138b04639

+ 1 - 1
ncd/CMakeLists.txt

@@ -96,7 +96,7 @@ set(NCDINTERPRETER_SOURCES
     NCDModuleIndex.c
     NCDInterpProcess.c
     NCDInterpProg.c
-    NCDPlaceholderDb.c
+    NCDEvaluator.c
     NCDMethodIndex.c
     extra/BEventLock.c
     extra/NCDBuf.c

+ 271 - 0
ncd/NCDEvaluator.c

@@ -0,0 +1,271 @@
+/**
+ * @file NCDEvaluator.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <limits.h>
+
+#include <base/BLog.h>
+#include <ncd/make_name_indices.h>
+
+#include "NCDEvaluator.h"
+
+#include <generated/blog_channel_ncd.h>
+
+struct NCDEvaluator__var {
+    NCD_string_id_t *varnames;
+    size_t num_names;
+};
+
+struct NCDEvaluator__call {
+    int y;
+};
+
+#define GROWARRAY_NAME VarArray
+#define GROWARRAY_OBJECT_TYPE NCDEvaluator
+#define GROWARRAY_ARRAY_MEMBER vars
+#define GROWARRAY_CAPACITY_MEMBER vars_capacity
+#define GROWARRAY_MAX_CAPACITY INT_MAX
+#include <misc/grow_array.h>
+
+#define GROWARRAY_NAME CallArray
+#define GROWARRAY_OBJECT_TYPE NCDEvaluator
+#define GROWARRAY_ARRAY_MEMBER calls
+#define GROWARRAY_CAPACITY_MEMBER calls_capacity
+#define GROWARRAY_MAX_CAPACITY INT_MAX
+#include <misc/grow_array.h>
+
+static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out)
+{
+    ASSERT((NCDValue_Type(value), 1))
+    
+    switch (NCDValue_Type(value)) {
+        case NCDVALUE_STRING: {
+            const char *str = NCDValue_StringValue(value);
+            size_t len = NCDValue_StringLength(value);
+            
+            NCD_string_id_t string_id = NCDStringIndex_GetBin(o->string_index, str, len);
+            if (string_id < 0) {
+                BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
+                goto fail;
+            }
+            
+            *out = NCDVal_NewIdString(mem, string_id, o->string_index);
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+        } break;
+        
+        case NCDVALUE_LIST: {
+            *out = NCDVal_NewList(mem, NCDValue_ListCount(value));
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+            
+            for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
+                NCDValRef vval;
+                if (!add_expr_recurser(o, e, mem, &vval)) {
+                    goto fail;
+                }
+                
+                if (!NCDVal_ListAppend(*out, vval)) {
+                    BLog(BLOG_ERROR, "depth limit exceeded");
+                    goto fail;
+                }
+            }
+        } break;
+        
+        case NCDVALUE_MAP: {
+            *out = NCDVal_NewMap(mem, NCDValue_MapCount(value));
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+            
+            for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
+                NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
+                
+                NCDValRef vkey;
+                NCDValRef vval;
+                if (!add_expr_recurser(o, ekey, mem, &vkey) ||
+                    !add_expr_recurser(o, eval, mem, &vval)
+                ) {
+                    goto fail;
+                }
+                
+                int inserted;
+                if (!NCDVal_MapInsert(*out, vkey, vval, &inserted)) {
+                    BLog(BLOG_ERROR, "depth limit exceeded");
+                    goto fail;
+                }
+                if (!inserted) {
+                    BLog(BLOG_ERROR, "duplicate key in map");
+                    goto fail;
+                }
+            }
+        } break;
+        
+        case NCDVALUE_VAR: {
+            if (o->num_vars == o->vars_capacity && !VarArray_DoubleUp(o)) {
+                BLog(BLOG_ERROR, "failed to grow var array");
+                goto fail;
+            }
+            
+            struct NCDEvaluator__var *var = &o->vars[o->num_vars];
+            
+            int plid = o->num_vars;
+            if (plid >= NCDVAL_TOPPLID) {
+                BLog(BLOG_ERROR, "too many placeholders");
+                goto fail;
+            }
+            
+            if (!ncd_make_name_indices(o->string_index, NCDValue_VarName(value), &var->varnames, &var->num_names)) {
+                BLog(BLOG_ERROR, "ncd_make_name_indices failed");
+                goto fail;
+            }
+            
+            o->num_vars++;
+            
+            *out = NCDVal_NewPlaceholder(mem, plid);
+        } break;
+        
+        default:
+            BLog(BLOG_ERROR, "expression type not supported");
+            goto fail;
+    }
+    
+    return 1;
+    
+fail:
+    return 0;
+}
+
+struct eval_context {
+    NCDEvaluator *eval;
+    NCDEvaluator_EvalFuncs const *funcs;
+};
+
+static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
+{
+    struct eval_context const *context = arg;
+    NCDEvaluator *o = context->eval;
+    ASSERT(plid >= 0)
+    ASSERT(plid < o->num_vars)
+    
+    struct NCDEvaluator__var *var = &o->vars[plid];
+    
+    return context->funcs->func_eval_var(context->funcs->user, var->varnames, var->num_names, mem, out);
+}
+
+int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index)
+{
+    o->string_index = string_index;
+    
+    if (!VarArray_Init(o, 16)) {
+        BLog(BLOG_ERROR, "NamesArray_Init failed");
+        goto fail0;
+    }
+    
+    if (!CallArray_Init(o, 16)) {
+        BLog(BLOG_ERROR, "EntriesArray_Init failed");
+        goto fail1;
+    }
+    
+    o->num_vars = 0;
+    o->num_calls = 0;
+    
+    return 1;
+    
+fail1:
+    VarArray_Free(o);
+fail0:
+    return 0;
+}
+
+void NCDEvaluator_Free (NCDEvaluator *o)
+{
+    for (int i = 0; i < o->num_vars; i++) {
+        BFree(o->vars[i].varnames);
+    }
+    
+    CallArray_Free(o);
+    VarArray_Free(o);
+}
+
+int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value)
+{
+    NCDValMem_Init(&o->mem);
+    
+    NCDValRef ref;
+    if (!add_expr_recurser(eval, value, &o->mem, &ref)) {
+        goto fail1;
+    }
+    
+    o->ref = NCDVal_ToSafe(ref);
+    
+    if (!NCDValReplaceProg_Init(&o->prog, ref)) {
+        BLog(BLOG_ERROR, "NCDValReplaceProg_Init failed");
+        goto fail1;
+    }
+    
+    return 1;
+    
+fail1:
+    NCDValMem_Free(&o->mem);
+    return 0;
+}
+
+void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o)
+{
+    NCDValReplaceProg_Free(&o->prog);
+    NCDValMem_Free(&o->mem);
+}
+
+int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val)
+{
+    if (!NCDValMem_InitCopy(out_newmem, &o->mem)) {
+        BLog(BLOG_ERROR, "NCDValMem_InitCopy failed");
+        goto fail0;
+    }
+    
+    struct eval_context context;
+    context.eval = eval;
+    context.funcs = funcs;
+    
+    if (!NCDValReplaceProg_Execute(o->prog, out_newmem, replace_placeholders_callback, &context)) {
+        BLog(BLOG_ERROR, "NCDValReplaceProg_Execute failed");
+        goto fail1;
+    }
+    
+    *out_val = NCDVal_FromSafe(out_newmem, o->ref);
+    return 1;
+    
+fail1:
+    NCDValMem_Free(out_newmem);
+fail0:
+    return 0;
+}

+ 70 - 0
ncd/NCDEvaluator.h

@@ -0,0 +1,70 @@
+/**
+ * @file NCDEvaluator.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_NCDEVALUATOR_H
+#define BADVPN_NCDEVALUATOR_H
+
+#include <stddef.h>
+
+#include <misc/debug.h>
+#include <ncd/NCDAst.h>
+#include <ncd/NCDStringIndex.h>
+#include <ncd/NCDVal.h>
+
+struct NCDEvaluator__var;
+struct NCDEvaluator__call;
+
+typedef struct {
+    NCDStringIndex *string_index;
+    struct NCDEvaluator__var *vars;
+    struct NCDEvaluator__call *calls;
+    int vars_capacity;
+    int calls_capacity;
+    int num_vars;
+    int num_calls;
+} NCDEvaluator;
+
+typedef struct {
+    NCDValMem mem;
+    NCDValSafeRef ref;
+    NCDValReplaceProg prog;
+} NCDEvaluatorExpr;
+
+typedef struct {
+    void *user;
+    int (*func_eval_var) (void *user, NCD_string_id_t const *varnames, size_t num_names, NCDValMem *mem, NCDValRef *out);
+} NCDEvaluator_EvalFuncs;
+
+int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index) WARN_UNUSED;
+void NCDEvaluator_Free (NCDEvaluator *o);
+int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value) WARN_UNUSED;
+void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o);
+int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val) WARN_UNUSED;
+
+#endif

+ 14 - 136
ncd/NCDInterpProcess.c

@@ -51,9 +51,7 @@ struct NCDInterpProcess__stmt {
         const struct NCDInterpModule *simple_module;
         int method_name_id;
     } binding;
-    NCDValMem arg_mem;
-    NCDValSafeRef arg_ref;
-    NCDValReplaceProg arg_prog;
+    NCDEvaluatorExpr arg_expr;
     int alloc_size;
     int prealloc_offset;
     int hash_next;
@@ -82,108 +80,11 @@ static int compute_prealloc (NCDInterpProcess *o)
     return 1;
 }
 
-static int convert_value_recurser (NCDPlaceholderDb *pdb, NCDStringIndex *string_index, NCDValue *value, NCDValMem *mem, NCDValRef *out)
-{
-    ASSERT(pdb)
-    ASSERT(string_index)
-    ASSERT((NCDValue_Type(value), 1))
-    ASSERT(mem)
-    ASSERT(out)
-    
-    switch (NCDValue_Type(value)) {
-        case NCDVALUE_STRING: {
-            const char *str = NCDValue_StringValue(value);
-            size_t len = NCDValue_StringLength(value);
-            
-            NCD_string_id_t string_id = NCDStringIndex_GetBin(string_index, str, len);
-            if (string_id < 0) {
-                BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
-                goto fail;
-            }
-            
-            *out = NCDVal_NewIdString(mem, string_id, string_index);
-            if (NCDVal_IsInvalid(*out)) {
-                goto fail;
-            }
-        } break;
-        
-        case NCDVALUE_LIST: {
-            *out = NCDVal_NewList(mem, NCDValue_ListCount(value));
-            if (NCDVal_IsInvalid(*out)) {
-                goto fail;
-            }
-            
-            for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
-                NCDValRef vval;
-                if (!convert_value_recurser(pdb, string_index, e, mem, &vval)) {
-                    goto fail;
-                }
-                
-                if (!NCDVal_ListAppend(*out, vval)) {
-                    BLog(BLOG_ERROR, "depth limit exceeded");
-                    goto fail;
-                }
-            }
-        } break;
-        
-        case NCDVALUE_MAP: {
-            *out = NCDVal_NewMap(mem, NCDValue_MapCount(value));
-            if (NCDVal_IsInvalid(*out)) {
-                goto fail;
-            }
-            
-            for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
-                NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
-                
-                NCDValRef vkey;
-                NCDValRef vval;
-                if (!convert_value_recurser(pdb, string_index, ekey, mem, &vkey) ||
-                    !convert_value_recurser(pdb, string_index, eval, mem, &vval)
-                ) {
-                    goto fail;
-                }
-                
-                int inserted;
-                if (!NCDVal_MapInsert(*out, vkey, vval, &inserted)) {
-                    BLog(BLOG_ERROR, "depth limit exceeded");
-                    goto fail;
-                }
-                if (!inserted) {
-                    BLog(BLOG_ERROR, "duplicate key in map");
-                    goto fail;
-                }
-            }
-        } break;
-        
-        case NCDVALUE_VAR: {
-            int plid;
-            if (!NCDPlaceholderDb_AddVariable(pdb, NCDValue_VarName(value), &plid)) {
-                goto fail;
-            }
-            
-            if (NCDVAL_MINIDX + plid >= -1) {
-                goto fail;
-            }
-            
-            *out = NCDVal_NewPlaceholder(mem, plid);
-        } break;
-        
-        default:
-            BLog(BLOG_ERROR, "expression type not supported");
-            goto fail;
-    }
-    
-    return 1;
-    
-fail:
-    return 0;
-}
-
-int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIndex *string_index, NCDPlaceholderDb *pdb, NCDModuleIndex *module_index)
+int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIndex *string_index, NCDEvaluator *eval, NCDModuleIndex *module_index)
 {
     ASSERT(process)
     ASSERT(string_index)
-    ASSERT(pdb)
+    ASSERT(eval)
     ASSERT(module_index)
     
     NCDBlock *block = NCDProcess_Block(process);
@@ -243,31 +144,21 @@ int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIn
             goto loop_fail0;
         }
         
-        NCDValMem_Init(&e->arg_mem);
-        
-        NCDValRef val;
-        if (!convert_value_recurser(pdb, string_index, NCDStatement_RegArgs(s), &e->arg_mem, &val)) {
-            BLog(BLOG_ERROR, "convert_value_recurser failed");
-            goto loop_fail1;
-        }
-        
-        e->arg_ref = NCDVal_ToSafe(val);
-        
-        if (!NCDValReplaceProg_Init(&e->arg_prog, val)) {
-            BLog(BLOG_ERROR, "NCDValReplaceProg_Init failed");
-            goto loop_fail1;
+        if (!NCDEvaluatorExpr_Init(&e->arg_expr, eval, NCDStatement_RegArgs(s))) {
+            BLog(BLOG_ERROR, "NCDEvaluatorExpr_Init failed");
+            goto loop_fail0;
         }
         
         if (NCDStatement_RegObjName(s)) {
             if (!ncd_make_name_indices(string_index, NCDStatement_RegObjName(s), &e->objnames, &e->num_objnames)) {
                 BLog(BLOG_ERROR, "ncd_make_name_indices failed");
-                goto loop_fail2;
+                goto loop_fail1;
             }
             
             e->binding.method_name_id = NCDModuleIndex_GetMethodNameId(module_index, NCDStatement_RegCmdName(s));
             if (e->binding.method_name_id == -1) {
                 BLog(BLOG_ERROR, "NCDModuleIndex_GetMethodNameId failed");
-                goto loop_fail3;
+                goto loop_fail2;
             }
         } else {
             e->binding.simple_module = NCDModuleIndex_FindModule(module_index, NCDStatement_RegCmdName(s));
@@ -282,12 +173,10 @@ int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIn
         o->num_stmts++;
         continue;
         
-    loop_fail3:
-        BFree(e->objnames);
     loop_fail2:
-        NCDValReplaceProg_Free(&e->arg_prog);
+        BFree(e->objnames);
     loop_fail1:
-        NCDValMem_Free(&e->arg_mem);
+        NCDEvaluatorExpr_Free(&e->arg_expr);
     loop_fail0:
         goto fail3;
     }
@@ -301,8 +190,7 @@ fail3:
     while (o->num_stmts-- > 0) {
         struct NCDInterpProcess__stmt *e = &o->stmts[o->num_stmts];
         BFree(e->objnames);
-        NCDValReplaceProg_Free(&e->arg_prog);
-        NCDValMem_Free(&e->arg_mem);
+        NCDEvaluatorExpr_Free(&e->arg_expr);
     }
     free(o->name);
 fail2:
@@ -320,8 +208,7 @@ void NCDInterpProcess_Free (NCDInterpProcess *o)
     while (o->num_stmts-- > 0) {
         struct NCDInterpProcess__stmt *e = &o->stmts[o->num_stmts];
         BFree(e->objnames);
-        NCDValReplaceProg_Free(&e->arg_prog);
-        NCDValMem_Free(&e->arg_mem);
+        NCDEvaluatorExpr_Free(&e->arg_expr);
     }
     
     free(o->name);
@@ -404,24 +291,15 @@ const struct NCDInterpModule * NCDInterpProcess_StatementGetMethodModule (NCDInt
     return NCDModuleIndex_GetMethodModule(module_index, obj_type, o->stmts[i].binding.method_name_id);
 }
 
-int NCDInterpProcess_CopyStatementArgs (NCDInterpProcess *o, int i, NCDValMem *out_valmem, NCDValRef *out_val, NCDValReplaceProg *out_prog)
+NCDEvaluatorExpr * NCDInterpProcess_GetStatementArgsExpr (NCDInterpProcess *o, int i)
 {
     DebugObject_Access(&o->d_obj);
     ASSERT(i >= 0)
     ASSERT(i < o->num_stmts)
-    ASSERT(out_valmem)
-    ASSERT(out_val)
-    ASSERT(out_prog)
     
     struct NCDInterpProcess__stmt *e = &o->stmts[i];
     
-    if (!NCDValMem_InitCopy(out_valmem, &e->arg_mem)) {
-        return 0;
-    }
-    
-    *out_val = NCDVal_FromSafe(out_valmem, e->arg_ref);
-    *out_prog = e->arg_prog;
-    return 1;
+    return &e->arg_expr;
 }
 
 void NCDInterpProcess_StatementBumpAllocSize (NCDInterpProcess *o, int i, int alloc_size)

+ 3 - 3
ncd/NCDInterpProcess.h

@@ -36,7 +36,7 @@
 #include <base/DebugObject.h>
 #include <ncd/NCDAst.h>
 #include <ncd/NCDVal.h>
-#include <ncd/NCDPlaceholderDb.h>
+#include <ncd/NCDEvaluator.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDModuleIndex.h>
 #include <ncd/NCDStringIndex.h>
@@ -64,14 +64,14 @@ typedef struct {
     DebugObject d_obj;
 } NCDInterpProcess;
 
-int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIndex *string_index, NCDPlaceholderDb *pdb, NCDModuleIndex *module_index) WARN_UNUSED;
+int NCDInterpProcess_Init (NCDInterpProcess *o, NCDProcess *process, NCDStringIndex *string_index, NCDEvaluator *eval, NCDModuleIndex *module_index) WARN_UNUSED;
 void NCDInterpProcess_Free (NCDInterpProcess *o);
 int NCDInterpProcess_FindStatement (NCDInterpProcess *o, int from_index, NCD_string_id_t name);
 const char * NCDInterpProcess_StatementCmdName (NCDInterpProcess *o, int i, NCDStringIndex *string_index);
 void NCDInterpProcess_StatementObjNames (NCDInterpProcess *o, int i, const NCD_string_id_t **out_objnames, size_t *out_num_objnames);
 const struct NCDInterpModule * NCDInterpProcess_StatementGetSimpleModule (NCDInterpProcess *o, int i, NCDStringIndex *string_index, NCDModuleIndex *module_index);
 const struct NCDInterpModule * NCDInterpProcess_StatementGetMethodModule (NCDInterpProcess *o, int i, NCD_string_id_t obj_type, NCDModuleIndex *module_index);
-int NCDInterpProcess_CopyStatementArgs (NCDInterpProcess *o, int i, NCDValMem *out_valmem, NCDValRef *out_val, NCDValReplaceProg *out_prog) WARN_UNUSED;
+NCDEvaluatorExpr * NCDInterpProcess_GetStatementArgsExpr (NCDInterpProcess *o, int i);
 void NCDInterpProcess_StatementBumpAllocSize (NCDInterpProcess *o, int i, int alloc_size);
 int NCDInterpProcess_PreallocSize (NCDInterpProcess *o);
 int NCDInterpProcess_StatementPreallocSize (NCDInterpProcess *o, int i);

+ 3 - 3
ncd/NCDInterpProg.c

@@ -41,13 +41,13 @@
 #include "NCDInterpProg_hash.h"
 #include <structure/CHash_impl.h>
 
-int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *string_index, NCDPlaceholderDb *pdb, NCDModuleIndex *module_index)
+int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *string_index, NCDEvaluator *eval, NCDModuleIndex *module_index)
 {
     ASSERT(prog)
     ASSERT(!NCDProgram_ContainsElemType(prog, NCDPROGRAMELEM_INCLUDE))
     ASSERT(!NCDProgram_ContainsElemType(prog, NCDPROGRAMELEM_INCLUDE_GUARD))
     ASSERT(string_index)
-    ASSERT(pdb)
+    ASSERT(eval)
     ASSERT(module_index)
     
     if (NCDProgram_NumElems(prog) > INT_MAX) {
@@ -80,7 +80,7 @@ int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *stri
             goto fail2;
         }
         
-        if (!NCDInterpProcess_Init(&e->iprocess, p, string_index, pdb, module_index)) {
+        if (!NCDInterpProcess_Init(&e->iprocess, p, string_index, eval, module_index)) {
             BLog(BLOG_ERROR, "NCDInterpProcess_Init failed");
             goto fail2;
         }

+ 1 - 1
ncd/NCDInterpProg.h

@@ -56,7 +56,7 @@ typedef struct {
     DebugObject d_obj;
 } NCDInterpProg;
 
-int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *string_index, NCDPlaceholderDb *pdb, NCDModuleIndex *module_index) WARN_UNUSED;
+int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *string_index, NCDEvaluator *eval, NCDModuleIndex *module_index) WARN_UNUSED;
 void NCDInterpProg_Free (NCDInterpProg *o);
 NCDInterpProcess * NCDInterpProg_FindProcess (NCDInterpProg *o, NCD_string_id_t name);
 

+ 18 - 24
ncd/NCDInterpreter.c

@@ -98,7 +98,7 @@ static void process_work_job_handler_working (struct process *p);
 static void process_work_job_handler_up (struct process *p);
 static void process_work_job_handler_waiting (struct process *p);
 static void process_work_job_handler_terminating (struct process *p);
-static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out);
+static int eval_func_eval_var (void *user, NCD_string_id_t const *varnames, size_t num_names, NCDValMem *mem, NCDValRef *out);
 static void process_advance (struct process *p);
 static void process_wait_timer_handler (BSmallTimer *timer);
 static int process_find_object (struct process *p, int pos, NCD_string_id_t name, NCDObject *out_object);
@@ -190,14 +190,14 @@ int NCDInterpreter_Init (NCDInterpreter *o, NCDProgram program, struct NCDInterp
         goto fail3;
     }
     
-    // init placeholder database
-    if (!NCDPlaceholderDb_Init(&o->placeholder_db, &o->string_index)) {
-        BLog(BLOG_ERROR, "NCDPlaceholderDb_Init failed");
+    // init expression evaluator
+    if (!NCDEvaluator_Init(&o->evaluator, &o->string_index)) {
+        BLog(BLOG_ERROR, "NCDEvaluator_Init failed");
         goto fail3;
     }
     
     // init interp program
-    if (!NCDInterpProg_Init(&o->iprogram, &o->program, &o->string_index, &o->placeholder_db, &o->mindex)) {
+    if (!NCDInterpProg_Init(&o->iprogram, &o->program, &o->string_index, &o->evaluator, &o->mindex)) {
         BLog(BLOG_ERROR, "NCDInterpProg_Init failed");
         goto fail5;
     }
@@ -259,7 +259,7 @@ fail7:;
     NCDInterpProg_Free(&o->iprogram);
 fail5:
     // free placeholder database
-    NCDPlaceholderDb_Free(&o->placeholder_db);
+    NCDEvaluator_Free(&o->evaluator);
 fail3:
     // free module index
     NCDModuleIndex_Free(&o->mindex);
@@ -294,7 +294,7 @@ void NCDInterpreter_Free (NCDInterpreter *o)
     NCDInterpProg_Free(&o->iprogram);
     
     // free placeholder database
-    NCDPlaceholderDb_Free(&o->placeholder_db);
+    NCDEvaluator_Free(&o->evaluator);
     
     // free module index
     NCDModuleIndex_Free(&o->mindex);
@@ -812,17 +812,14 @@ again:
     return;
 }
 
-int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
+int eval_func_eval_var (void *user, NCD_string_id_t const *varnames, size_t num_names, NCDValMem *mem, NCDValRef *out)
 {
-    struct process *p = arg;
-    ASSERT(plid >= 0)
+    struct process *p = user;
+    ASSERT(varnames)
+    ASSERT(num_names > 0)
     ASSERT(mem)
     ASSERT(out)
     
-    const NCD_string_id_t *varnames;
-    size_t num_names;
-    NCDPlaceholderDb_GetVariable(&p->interp->placeholder_db, plid, &varnames, &num_names);
-    
     return process_resolve_variable_expr(p, p->ap, varnames, num_names, mem, out);
 }
 
@@ -888,20 +885,17 @@ void process_advance (struct process *p)
         }
     }
     
-    // copy arguments
+    // get evaluator expression for the arguments
+    NCDEvaluatorExpr *expr = NCDInterpProcess_GetStatementArgsExpr(p->iprocess, ps->i);
+    
+    // evaluate arguments
     NCDValRef args;
-    NCDValReplaceProg prog;
-    if (!NCDInterpProcess_CopyStatementArgs(p->iprocess, ps->i, &ps->args_mem, &args, &prog)) {
-        STATEMENT_LOG(ps, BLOG_ERROR, "NCDInterpProcess_CopyStatementArgs failed");
+    NCDEvaluator_EvalFuncs funcs = {p, eval_func_eval_var};
+    if (!NCDEvaluatorExpr_Eval(expr, &p->interp->evaluator, &funcs, &ps->args_mem, &args)) {
+        STATEMENT_LOG(ps, BLOG_ERROR, "failed to evaluate arguments");
         goto fail0;
     }
     
-    // replace placeholders with values of variables
-    if (!NCDValReplaceProg_Execute(prog, &ps->args_mem, replace_placeholders_callback, p)) {
-        STATEMENT_LOG(ps, BLOG_ERROR, "failed to replace variables in arguments with values");
-        goto fail1;
-    }
-    
     // convert non-continuous strings unless the module can handle them
     if (!(module->module.flags & NCDMODULE_FLAG_ACCEPT_NON_CONTINUOUS_STRINGS)) {
         if (!NCDValMem_ConvertNonContinuousStrings(&ps->args_mem, &args)) {

+ 3 - 3
ncd/NCDInterpreter.h

@@ -39,7 +39,7 @@
 #include <ncd/NCDStringIndex.h>
 #include <ncd/NCDModuleIndex.h>
 #include <ncd/NCDAst.h>
-#include <ncd/NCDPlaceholderDb.h>
+#include <ncd/NCDEvaluator.h>
 #include <ncd/NCDInterpProg.h>
 #include <ncd/NCDModule.h>
 #include <structure/LinkedList1.h>
@@ -103,8 +103,8 @@ typedef struct {
     // program AST
     NCDProgram program;
 
-    // placeholder database
-    NCDPlaceholderDb placeholder_db;
+    // expression evaluator
+    NCDEvaluator evaluator;
 
     // structure for efficient interpretation
     NCDInterpProg iprogram;

+ 0 - 127
ncd/NCDPlaceholderDb.c

@@ -1,127 +0,0 @@
-/**
- * @file NCDPlaceholderDb.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#include <misc/balloc.h>
-#include <misc/strdup.h>
-#include <base/BLog.h>
-#include <ncd/make_name_indices.h>
-
-#include "NCDPlaceholderDb.h"
-
-#include <generated/blog_channel_NCDPlaceholderDb.h>
-
-int NCDPlaceholderDb_Init (NCDPlaceholderDb *o, NCDStringIndex *string_index)
-{
-    ASSERT(string_index)
-    
-    o->count = 0;
-    o->capacity = 1;
-    o->string_index = string_index;
-    
-    if (!(o->arr = BAllocArray(o->capacity, sizeof(o->arr[0])))) {
-        BLog(BLOG_ERROR, "NCDPlaceholderDb_Init failed");
-        return 0;
-    }
-    
-    return 1;
-}
-
-void NCDPlaceholderDb_Free (NCDPlaceholderDb *o)
-{
-    for (size_t i = 0; i < o->count; i++) {
-        BFree(o->arr[i].varnames);
-    }
-    
-    BFree(o->arr);
-}
-
-int NCDPlaceholderDb_AddVariable (NCDPlaceholderDb *o, const char *varname, int *out_plid)
-{
-    ASSERT(varname)
-    ASSERT(out_plid)
-    ASSERT(o->count <= o->capacity)
-    ASSERT(o->capacity > 0)
-    
-    if (o->count == o->capacity) {
-        if (o->capacity > SIZE_MAX / 2) {
-            BLog(BLOG_ERROR, "too many placeholder entries (cannot resize)");
-            return 0;
-        }
-        size_t newcap = 2 * o->capacity;
-        
-        struct NCDPlaceholderDb__entry *newarr = BAllocArray(newcap, sizeof(newarr[0]));
-        if (!newarr) {
-            BLog(BLOG_ERROR, "BAllocArray failed");
-            return 0;
-        }
-        
-        memcpy(newarr, o->arr, o->count * sizeof(newarr[0]));
-        BFree(o->arr);
-        
-        o->arr = newarr;
-        o->capacity = newcap;
-    }
-    
-    ASSERT(o->count < o->capacity)
-    
-    if (o->count > INT_MAX) {
-        BLog(BLOG_ERROR, "too many placeholder entries (cannot fit integer)");
-        return 0;
-    }
-    
-    NCD_string_id_t *varnames;
-    size_t num_names;
-    if (!ncd_make_name_indices(o->string_index, varname, &varnames, &num_names)) {
-        BLog(BLOG_ERROR, "ncd_make_name_indices failed");
-        return 0;
-    }
-    
-    *out_plid = o->count;
-    
-    o->arr[o->count].varnames = varnames;
-    o->arr[o->count].num_names = num_names;
-    o->count++;
-    
-    return 1;
-}
-
-void NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid, const NCD_string_id_t **out_varnames, size_t *out_num_names)
-{
-    ASSERT(plid >= 0)
-    ASSERT(plid < o->count)
-    ASSERT(out_varnames)
-    ASSERT(out_num_names)
-    
-    *out_varnames = o->arr[plid].varnames;
-    *out_num_names = o->arr[plid].num_names;
-}

+ 0 - 95
ncd/NCDPlaceholderDb.h

@@ -1,95 +0,0 @@
-/**
- * @file NCDPlaceholderDb.h
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_NCDPLACEHOLDERDB_H
-#define BADVPN_NCDPLACEHOLDERDB_H
-
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <ncd/NCDStringIndex.h>
-
-struct NCDPlaceholderDb__entry {
-    NCD_string_id_t *varnames;
-    size_t num_names;
-};
-
-/**
- * Associates variable placeholder numbers to variable names.
- * This is populated by {@link NCDInterpProcess_Init} when converting the {@link NCDValue}
- * objects in the AST to compact representations in {@link NCDValMem}. Variables are
- * replaced with placeholder identifiers (integers), which this object associates
- * with their names.
- * During interpretation, when a statement is being initialized, the compact form held
- * by {@link NCDInterpProcess} is byte-copied, and placeholders are replaced with the
- * values of corresponding variables using {@link NCDVal_ReplacePlaceholders}.
- */
-typedef struct {
-    struct NCDPlaceholderDb__entry *arr;
-    size_t count;
-    size_t capacity;
-    NCDStringIndex *string_index;
-} NCDPlaceholderDb;
-
-/**
- * Initializes the placeholder database.
- * Returns 1 on success, and 0 on failure.
- */
-int NCDPlaceholderDb_Init (NCDPlaceholderDb *o, NCDStringIndex *string_index) WARN_UNUSED;
-
-/**
- * Frees the placeholder database.
- */
-void NCDPlaceholderDb_Free (NCDPlaceholderDb *o);
-
-/**
- * Adds a variable to the database.
- * 
- * @param varname name of the variable (text, including dots). Must not be NULL.
- * @param out_plid on success, the placeholder identifier will be returned here. Must
- *                 not be NULL.
- * @return 1 on success, 0 on failure
- */
-int NCDPlaceholderDb_AddVariable (NCDPlaceholderDb *o, const char *varname, int *out_plid) WARN_UNUSED;
-
-/**
- * Retrieves the name of the variable associated with a placeholder identifier.
- * 
- * @param plid placeholder identifier; must have been previously provided by
- *             {@link NCDPlaceholderDb_AddVariable}.
- * @return name of the variable, split by dots. The returned value points to
- *         an array of pointers to strings, which is terminated by a NULL
- *         pointer. These all point to internal data in the placeholder
- *         database; they must not be modified, and remain valid until the
- *         database is freed.
- *         Note that there will always be at least one string in the result.
- */
-void NCDPlaceholderDb_GetVariable (NCDPlaceholderDb *o, int plid, const NCD_string_id_t **out_varnames, size_t *out_num_names);
-
-#endif

+ 1 - 1
ncd/NCDVal.c

@@ -626,7 +626,7 @@ NCDValRef NCDVal_NewPlaceholder (NCDValMem *mem, int plid)
 {
     NCDVal__AssertMem(mem);
     ASSERT(plid >= 0)
-    ASSERT(NCDVAL_MINIDX + plid < -1)
+    ASSERT(plid < NCDVAL_TOPPLID)
     
     NCDValRef ref = {mem, NCDVAL_MINIDX + plid};
     return ref;

+ 4 - 3
ncd/NCDVal.h

@@ -45,6 +45,7 @@
 
 #define NCDVAL_MAXIDX INT_MAX
 #define NCDVAL_MINIDX INT_MIN
+#define NCDVAL_TOPPLID (-1 - NCDVAL_MINIDX)
 
 typedef int NCDVal__idx;
 
@@ -187,11 +188,11 @@ NCDValRef NCDVal_NewInvalid (void);
 /**
  * Returns a new placeholder value reference. A placeholder value is a valid value
  * containing an integer placeholder identifier.
- * This always succeeds; however, the caller must ensure the identifier is
- * non-negative and satisfies (NCDVAL_MINIDX + plid < -1).
+ * This always succeeds; however, the caller must ensure the identifier is in the
+ * range [0, NCDVAL_TOPPLID).
  * 
  * The placeholder type is only used internally in the interpreter for argument
- * resolution, and is never seen by modules. Also see {@link NCDPlaceholderDb}.
+ * resolution, and is never seen by modules.
  */
 NCDValRef NCDVal_NewPlaceholder (NCDValMem *mem, int plid);