|
@@ -39,9 +39,89 @@
|
|
|
|
|
|
|
|
#include <generated/blog_channel_ncd.h>
|
|
#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 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)
|
|
static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out)
|
|
|
{
|
|
{
|
|
|
switch (NCDValue_Type(value)) {
|
|
switch (NCDValue_Type(value)) {
|
|
@@ -110,31 +190,89 @@ static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem,
|
|
|
} break;
|
|
} break;
|
|
|
|
|
|
|
|
case NCDVALUE_VAR: {
|
|
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");
|
|
BLog(BLOG_ERROR, "failed to grow var array");
|
|
|
|
|
+ BFree(var.varnames);
|
|
|
goto fail;
|
|
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;
|
|
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;
|
|
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;
|
|
} break;
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
|
|
+ default: {
|
|
|
BLog(BLOG_ERROR, "expression type not supported");
|
|
BLog(BLOG_ERROR, "expression type not supported");
|
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
+ } break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
return 1;
|
|
@@ -143,21 +281,44 @@ fail:
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-struct eval_context {
|
|
|
|
|
- NCDEvaluator *eval;
|
|
|
|
|
- NCDEvaluator_EvalFuncs const *funcs;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
|
|
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;
|
|
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)
|
|
int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index)
|
|
@@ -188,39 +349,26 @@ void NCDEvaluator_Free (NCDEvaluator *o)
|
|
|
BFree(o->vars.elems[i].varnames);
|
|
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__CallVec_Free(&o->calls);
|
|
|
NCDEvaluator__VarVec_Free(&o->vars);
|
|
NCDEvaluator__VarVec_Free(&o->vars);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value)
|
|
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)
|
|
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)
|
|
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_newmem)
|
|
|
ASSERT(out_val)
|
|
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.eval = eval;
|
|
|
context.funcs = funcs;
|
|
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;
|
|
goto fail1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- *out_val = NCDVal_FromSafe(out_newmem, o->ref);
|
|
|
|
|
- return 1;
|
|
|
|
|
|
|
+ *out_ref = ref;
|
|
|
|
|
+ res = 1;
|
|
|
|
|
|
|
|
fail1:
|
|
fail1:
|
|
|
- NCDValMem_Free(out_newmem);
|
|
|
|
|
|
|
+ NCDValMem_Free(&temp_mem);
|
|
|
fail0:
|
|
fail0:
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return res;
|
|
|
}
|
|
}
|