Procházet zdrojové kódy

ncd: Implement function calls in NCDEvaluator.
Actual functions TBD.

Ambroz Bizjak před 11 roky
rodič
revize
c2b3151f81
3 změnil soubory, kde provedl 259 přidání a 61 odebrání
  1. 227 56
      ncd/NCDEvaluator.c
  2. 21 4
      ncd/NCDEvaluator.h
  3. 11 1
      ncd/NCDInterpreter.c

+ 227 - 56
ncd/NCDEvaluator.c

@@ -39,9 +39,89 @@
 
 #include <generated/blog_channel_ncd.h>
 
-#define NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY 16
+#define NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY 64
 #define NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY 16
 
+#define MAX_LOCAL_IDS (NCDVAL_TOPPLID / 2)
+
+struct NCDEvaluator__eval_context {
+    NCDEvaluator *eval;
+    NCDEvaluator_EvalFuncs const *funcs;
+};
+
+static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value);
+static void expr_free (struct NCDEvaluator__Expr *o);
+static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val);
+static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out);
+static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out);
+
+static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value)
+{
+    ASSERT((NCDValue_Type(value), 1))
+    
+    NCDValMem_Init(&o->mem);
+    
+    NCDValRef ref;
+    if (!add_expr_recurser(eval, value, &o->mem, &ref)) {
+        goto fail1;
+    }
+    
+    o->ref = NCDVal_ToSafe(ref);
+    
+    if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
+        if (!NCDValReplaceProg_Init(&o->prog, ref)) {
+            BLog(BLOG_ERROR, "NCDValReplaceProg_Init failed");
+            goto fail1;
+        }
+    }
+    
+    return 1;
+    
+fail1:
+    NCDValMem_Free(&o->mem);
+    return 0;
+}
+
+static void expr_free (struct NCDEvaluator__Expr *o)
+{
+    if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
+        NCDValReplaceProg_Free(&o->prog);
+    }
+    NCDValMem_Free(&o->mem);
+}
+
+static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val)
+{
+    if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
+        if (!NCDValMem_InitCopy(out_newmem, &o->mem)) {
+            BLog(BLOG_ERROR, "NCDValMem_InitCopy failed");
+            goto fail0;
+        }
+        
+        if (!NCDValReplaceProg_Execute(o->prog, out_newmem, replace_placeholders_callback, (void *)context)) {
+            goto fail_free;
+        }
+        
+        *out_val = NCDVal_FromSafe(out_newmem, o->ref);
+    } else {
+        NCDValMem_Init(out_newmem);
+        
+        NCDValRef ref;
+        if (!replace_placeholders_callback((void *)context, NCDVal_GetSafeRefPlaceholderId(o->ref), out_newmem, &ref) || NCDVal_IsInvalid(ref)) {
+            goto fail_free;
+        }
+        
+        *out_val = ref;
+    }
+    
+    return 1;
+    
+fail_free:
+    NCDValMem_Free(out_newmem);
+fail0:
+    return 0;
+}
+
 static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out)
 {
     switch (NCDValue_Type(value)) {
@@ -110,31 +190,89 @@ static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem,
         } break;
         
         case NCDVALUE_VAR: {
-            struct NCDEvaluator__Var *var;
-            if (!NCDEvaluator__VarVec_AllocAppend(&o->vars, 1, &var)) {
+            struct NCDEvaluator__Var var;
+            
+            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;
+            }
+            
+            size_t index;
+            if (!NCDEvaluator__VarVec_AppendValue(&o->vars, var, &index)) {
                 BLog(BLOG_ERROR, "failed to grow var array");
+                BFree(var.varnames);
                 goto fail;
             }
             
-            int plid = o->vars.count;
-            if (plid >= NCDVAL_TOPPLID) {
-                BLog(BLOG_ERROR, "too many placeholders");
+            if (index >= MAX_LOCAL_IDS) {
+                BLog(BLOG_ERROR, "too many variables");
                 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");
+            *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 0);
+        } break;
+        
+        case NCDVALUE_INVOC: {
+            struct NCDEvaluator__Call call;
+            
+            NCDValue *func = NCDValue_InvocFunc(value);
+            if (NCDValue_Type(func) != NCDVALUE_STRING) {
+                BLog(BLOG_ERROR, "call function is not a string");
+                goto fail_invoc0;
+            }
+            
+            call.func_name_id = NCDStringIndex_GetBin(o->string_index, NCDValue_StringValue(func), NCDValue_StringLength(func));
+            if (call.func_name_id < 0) {
+                BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
+                goto fail_invoc0;
+            }
+            
+            NCDValue *arg = NCDValue_InvocArg(value);
+            if (NCDValue_Type(arg) != NCDVALUE_LIST) {
+                BLog(BLOG_ERROR, "call argument is not a list literal!?");
+                goto fail_invoc0;
+            }
+            
+            if (!(call.args = BAllocArray(NCDValue_ListCount(arg), sizeof(call.args[0])))) {
+                BLog(BLOG_ERROR, "BAllocArray failed");
+                goto fail_invoc0;
+            }
+            call.num_args = 0;
+            
+            for (NCDValue *e = NCDValue_ListFirst(arg); e; e = NCDValue_ListNext(arg, e)) {
+                if (!expr_init(&call.args[call.num_args], o, e)) {
+                    goto fail_invoc1;
+                }
+                call.num_args++;
+            }
+            
+            size_t index;
+            if (!NCDEvaluator__CallVec_AppendValue(&o->calls, call, &index)) {
+                BLog(BLOG_ERROR, "failed to grow call array");
+                goto fail_invoc1;
+            }
+            
+            if (index >= MAX_LOCAL_IDS) {
+                BLog(BLOG_ERROR, "too many variables");
                 goto fail;
             }
             
-            NCDEvaluator__VarVec_DoAppend(&o->vars, 1);
+            *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 1);
+            break;
             
-            *out = NCDVal_NewPlaceholder(mem, plid);
+        fail_invoc1:
+            while (call.num_args-- > 0) {
+                expr_free(&call.args[call.num_args]);
+            }
+            BFree(call.args);
+        fail_invoc0:
+            goto fail;
         } break;
         
-        default:
+        default: {
             BLog(BLOG_ERROR, "expression type not supported");
             goto fail;
+        } break;
     }
     
     return 1;
@@ -143,21 +281,44 @@ 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;
+    struct NCDEvaluator__eval_context const *context = arg;
     NCDEvaluator *o = context->eval;
-    ASSERT(plid >= 0)
-    ASSERT(plid < o->vars.count)
     
-    struct NCDEvaluator__Var *var = &o->vars.elems[plid];
+    int type = plid & 1;
+    int index = plid >> 1;
+    
+    ASSERT(index >= 0)
+    ASSERT(index < MAX_LOCAL_IDS)
     
-    return context->funcs->func_eval_var(context->funcs->user, var->varnames, var->num_names, mem, out);
+    int res;
+    
+    switch (type) {
+        case 0: {
+            struct NCDEvaluator__Var *var = NCDEvaluator__VarVec_Get(&o->vars, index);
+            
+            res = context->funcs->func_eval_var(context->funcs->user, var->varnames, var->num_names, mem, out);
+        } break;
+        
+        case 1: {
+            struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, index);
+            
+            NCDEvaluatorArgs args;
+            args.context = context;
+            args.call_index = index;
+            
+            res = context->funcs->func_eval_call(context->funcs->user, call->func_name_id, args, mem, out);
+        } break;
+        
+        default: {
+            ASSERT(0)
+            res = 0;
+        } break;
+    }
+    
+    ASSERT(res == 0 || res == 1)
+    return res;
 }
 
 int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index)
@@ -188,39 +349,26 @@ void NCDEvaluator_Free (NCDEvaluator *o)
         BFree(o->vars.elems[i].varnames);
     }
     
+    for (size_t i = 0; i < o->calls.count; i++) {
+        struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, i);
+        while (call->num_args-- > 0) {
+            expr_free(&call->args[call->num_args]);
+        }
+        BFree(call->args);
+    }
+    
     NCDEvaluator__CallVec_Free(&o->calls);
     NCDEvaluator__VarVec_Free(&o->vars);
 }
 
 int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value)
 {
-    ASSERT((NCDValue_Type(value), 1))
-    
-    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;
+    return expr_init(&o->expr, eval, value);
 }
 
 void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o)
 {
-    NCDValReplaceProg_Free(&o->prog);
-    NCDValMem_Free(&o->mem);
+    expr_free(&o->expr);
 }
 
 int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val)
@@ -229,25 +377,48 @@ int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator
     ASSERT(out_newmem)
     ASSERT(out_val)
     
-    if (!NCDValMem_InitCopy(out_newmem, &o->mem)) {
-        BLog(BLOG_ERROR, "NCDValMem_InitCopy failed");
-        goto fail0;
-    }
-    
-    struct eval_context context;
+    struct NCDEvaluator__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");
+    return expr_eval(&o->expr, &context, out_newmem, out_val);
+}
+
+size_t NCDEvaluatorArgs_Count (NCDEvaluatorArgs *o)
+{
+    struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
+    
+    return call->num_args;
+}
+
+int NCDEvaluatorArgs_EvalArgNewMem (NCDEvaluatorArgs *o, size_t index, NCDValMem *out_newmem, NCDValRef *out_ref)
+{
+    struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
+    ASSERT(index < call->num_args)
+    
+    return expr_eval(&call->args[index], o->context, out_newmem, out_ref);
+}
+
+int NCDEvaluatorArgs_EvalArg (NCDEvaluatorArgs *o, size_t index, NCDValMem *mem, NCDValRef *out_ref)
+{
+    int res = 0;
+    
+    NCDValMem temp_mem;
+    NCDValRef temp_ref;
+    if (!NCDEvaluatorArgs_EvalArgNewMem(o, index, &temp_mem, &temp_ref)) {
+        goto fail0;
+    }
+    
+    NCDValRef ref = NCDVal_NewCopy(mem, temp_ref);
+    if (NCDVal_IsInvalid(ref)) {
         goto fail1;
     }
     
-    *out_val = NCDVal_FromSafe(out_newmem, o->ref);
-    return 1;
+    *out_ref = ref;
+    res = 1;
     
 fail1:
-    NCDValMem_Free(out_newmem);
+    NCDValMem_Free(&temp_mem);
 fail0:
-    return 0;
+    return res;
 }

+ 21 - 4
ncd/NCDEvaluator.h

@@ -37,6 +37,12 @@
 #include <ncd/NCDStringIndex.h>
 #include <ncd/NCDVal.h>
 
+struct NCDEvaluator__Expr {
+    NCDValMem mem;
+    NCDValSafeRef ref;
+    NCDValReplaceProg prog;
+};
+
 struct NCDEvaluator__Var {
     NCD_string_id_t *varnames;
     size_t num_names;
@@ -47,13 +53,17 @@ struct NCDEvaluator__Var {
 #include <structure/Vector.h>
 
 struct NCDEvaluator__Call {
-    int tbd;
+    NCD_string_id_t func_name_id;
+    struct NCDEvaluator__Expr *args;
+    size_t num_args;
 };
 
 #define VECTOR_NAME NCDEvaluator__CallVec
 #define VECTOR_ELEM_TYPE struct NCDEvaluator__Call
 #include <structure/Vector.h>
 
+struct NCDEvaluator__eval_context;
+
 typedef struct {
     NCDStringIndex *string_index;
     NCDEvaluator__VarVec vars;
@@ -61,14 +71,18 @@ typedef struct {
 } NCDEvaluator;
 
 typedef struct {
-    NCDValMem mem;
-    NCDValSafeRef ref;
-    NCDValReplaceProg prog;
+    struct NCDEvaluator__Expr expr;
 } NCDEvaluatorExpr;
 
+typedef struct {
+    struct NCDEvaluator__eval_context const *context;
+    int call_index;
+} NCDEvaluatorArgs;
+
 typedef struct {
     void *user;
     int (*func_eval_var) (void *user, NCD_string_id_t const *varnames, size_t num_names, NCDValMem *mem, NCDValRef *out);
+    int (*func_eval_call) (void *user, NCD_string_id_t func_name_id, NCDEvaluatorArgs args, NCDValMem *mem, NCDValRef *out);
 } NCDEvaluator_EvalFuncs;
 
 int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index) WARN_UNUSED;
@@ -76,5 +90,8 @@ 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;
+size_t NCDEvaluatorArgs_Count (NCDEvaluatorArgs *o);
+int NCDEvaluatorArgs_EvalArg (NCDEvaluatorArgs *o, size_t index, NCDValMem *mem, NCDValRef *out_ref) WARN_UNUSED;
+int NCDEvaluatorArgs_EvalArgNewMem (NCDEvaluatorArgs *o, size_t index, NCDValMem *out_newmem, NCDValRef *out_ref) WARN_UNUSED;
 
 #endif

+ 11 - 1
ncd/NCDInterpreter.c

@@ -99,6 +99,7 @@ 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 eval_func_eval_var (void *user, NCD_string_id_t const *varnames, size_t num_names, NCDValMem *mem, NCDValRef *out);
+static int eval_func_eval_call (void *user, NCD_string_id_t func_name_id, NCDEvaluatorArgs args, 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);
@@ -823,6 +824,15 @@ int eval_func_eval_var (void *user, NCD_string_id_t const *varnames, size_t num_
     return process_resolve_variable_expr(p, p->ap, varnames, num_names, mem, out);
 }
 
+static int eval_func_eval_call (void *user, NCD_string_id_t func_name_id, NCDEvaluatorArgs args, NCDValMem *mem, NCDValRef *out)
+{
+    struct process *p = user;
+    struct statement *ps = &p->statements[p->ap];
+    
+    STATEMENT_LOG(ps, BLOG_ERROR, "unknown function");
+    return 0;
+}
+
 void process_advance (struct process *p)
 {
     process_assert_pointers(p);
@@ -890,7 +900,7 @@ void process_advance (struct process *p)
     
     // evaluate arguments
     NCDValRef args;
-    NCDEvaluator_EvalFuncs funcs = {p, eval_func_eval_var};
+    NCDEvaluator_EvalFuncs funcs = {p, eval_func_eval_var, eval_func_eval_call};
     if (!NCDEvaluatorExpr_Eval(expr, &p->interp->evaluator, &funcs, &ps->args_mem, &args)) {
         STATEMENT_LOG(ps, BLOG_ERROR, "failed to evaluate arguments");
         goto fail0;