| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /**
- * @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 <misc/debug.h>
- #include <misc/balloc.h>
- #include <base/BLog.h>
- #include <ncd/make_name_indices.h>
- #include "NCDEvaluator.h"
- #include <generated/blog_channel_ncd.h>
- #define NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY 64
- #define NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY 16
- #define MAX_LOCAL_IDS (NCDVAL_TOPPLID / 2)
- #include "NCDEvaluator_var_vec.h"
- #include <structure/Vector_impl.h>
- #include "NCDEvaluator_call_vec.h"
- #include <structure/Vector_impl.h>
- 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)) {
- 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: {
- 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_var0;
- }
-
- size_t index;
- struct NCDEvaluator__Var *varptr = NCDEvaluator__VarVec_Push(&o->vars, &index);
- if (!varptr) {
- BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Push failed");
- goto fail_var1;
- }
-
- if (index >= MAX_LOCAL_IDS) {
- BLog(BLOG_ERROR, "too many variables");
- goto fail_var2;
- }
-
- *varptr = var;
-
- *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 0);
- break;
-
- fail_var2:
- NCDEvaluator__VarVec_Pop(&o->vars, NULL);
- fail_var1:
- BFree(var.varnames);
- fail_var0:
- goto fail;
- } 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;
- struct NCDEvaluator__Call *callptr = NCDEvaluator__CallVec_Push(&o->calls, &index);
- if (!callptr) {
- BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Push failed");
- goto fail_invoc1;
- }
-
- if (index >= MAX_LOCAL_IDS) {
- BLog(BLOG_ERROR, "too many variables");
- goto fail_invoc2;
- }
-
- *callptr = call;
-
- *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 1);
- break;
-
- fail_invoc2:
- NCDEvaluator__CallVec_Pop(&o->calls, NULL);
- fail_invoc1:
- while (call.num_args-- > 0) {
- expr_free(&call.args[call.num_args]);
- }
- BFree(call.args);
- fail_invoc0:
- goto fail;
- } break;
-
- default: {
- BLog(BLOG_ERROR, "expression type not supported");
- goto fail;
- } break;
- }
-
- return 1;
-
- fail:
- return 0;
- }
- static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
- {
- struct NCDEvaluator__eval_context const *context = arg;
- NCDEvaluator *o = context->eval;
-
- int type = plid & 1;
- int index = plid >> 1;
-
- ASSERT(index >= 0)
- ASSERT(index < MAX_LOCAL_IDS)
-
- 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)
- {
- o->string_index = string_index;
-
- if (!NCDEvaluator__VarVec_Init(&o->vars, NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY)) {
- BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Init failed");
- goto fail0;
- }
-
- if (!NCDEvaluator__CallVec_Init(&o->calls, NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY)) {
- BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Init failed");
- goto fail1;
- }
-
- return 1;
-
- fail1:
- NCDEvaluator__VarVec_Free(&o->vars);
- fail0:
- return 0;
- }
- void NCDEvaluator_Free (NCDEvaluator *o)
- {
- for (size_t i = 0; i < o->vars.count; i++) {
- 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)
- {
- return expr_init(&o->expr, eval, value);
- }
- void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o)
- {
- expr_free(&o->expr);
- }
- int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val)
- {
- ASSERT(funcs)
- ASSERT(out_newmem)
- ASSERT(out_val)
-
- struct NCDEvaluator__eval_context context;
- context.eval = eval;
- context.funcs = funcs;
-
- 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_ref = ref;
- res = 1;
-
- fail1:
- NCDValMem_Free(&temp_mem);
- fail0:
- return res;
- }
|