NCDEvaluator.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /**
  2. * @file NCDEvaluator.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <stddef.h>
  30. #include <limits.h>
  31. #include <misc/debug.h>
  32. #include <misc/balloc.h>
  33. #include <base/BLog.h>
  34. #include <ncd/make_name_indices.h>
  35. #include "NCDEvaluator.h"
  36. #include <generated/blog_channel_ncd.h>
  37. #define NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY 64
  38. #define NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY 16
  39. #define MAX_LOCAL_IDS (NCDVAL_TOPPLID / 2)
  40. #include "NCDEvaluator_var_vec.h"
  41. #include <structure/Vector_impl.h>
  42. #include "NCDEvaluator_call_vec.h"
  43. #include <structure/Vector_impl.h>
  44. struct NCDEvaluator__eval_context {
  45. NCDEvaluator *eval;
  46. NCDEvaluator_EvalFuncs const *funcs;
  47. };
  48. static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value);
  49. static void expr_free (struct NCDEvaluator__Expr *o);
  50. static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val);
  51. static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out);
  52. static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out);
  53. static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value)
  54. {
  55. ASSERT((NCDValue_Type(value), 1))
  56. NCDValMem_Init(&o->mem);
  57. NCDValRef ref;
  58. if (!add_expr_recurser(eval, value, &o->mem, &ref)) {
  59. goto fail1;
  60. }
  61. o->ref = NCDVal_ToSafe(ref);
  62. if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
  63. if (!NCDValReplaceProg_Init(&o->prog, ref)) {
  64. BLog(BLOG_ERROR, "NCDValReplaceProg_Init failed");
  65. goto fail1;
  66. }
  67. }
  68. return 1;
  69. fail1:
  70. NCDValMem_Free(&o->mem);
  71. return 0;
  72. }
  73. static void expr_free (struct NCDEvaluator__Expr *o)
  74. {
  75. if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
  76. NCDValReplaceProg_Free(&o->prog);
  77. }
  78. NCDValMem_Free(&o->mem);
  79. }
  80. static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val)
  81. {
  82. if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
  83. if (!NCDValMem_InitCopy(out_newmem, &o->mem)) {
  84. BLog(BLOG_ERROR, "NCDValMem_InitCopy failed");
  85. goto fail0;
  86. }
  87. if (!NCDValReplaceProg_Execute(o->prog, out_newmem, replace_placeholders_callback, (void *)context)) {
  88. goto fail_free;
  89. }
  90. *out_val = NCDVal_FromSafe(out_newmem, o->ref);
  91. } else {
  92. NCDValMem_Init(out_newmem);
  93. NCDValRef ref;
  94. if (!replace_placeholders_callback((void *)context, NCDVal_GetSafeRefPlaceholderId(o->ref), out_newmem, &ref) || NCDVal_IsInvalid(ref)) {
  95. goto fail_free;
  96. }
  97. *out_val = ref;
  98. }
  99. return 1;
  100. fail_free:
  101. NCDValMem_Free(out_newmem);
  102. fail0:
  103. return 0;
  104. }
  105. static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out)
  106. {
  107. switch (NCDValue_Type(value)) {
  108. case NCDVALUE_STRING: {
  109. const char *str = NCDValue_StringValue(value);
  110. size_t len = NCDValue_StringLength(value);
  111. NCD_string_id_t string_id = NCDStringIndex_GetBin(o->string_index, str, len);
  112. if (string_id < 0) {
  113. BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
  114. goto fail;
  115. }
  116. *out = NCDVal_NewIdString(mem, string_id, o->string_index);
  117. if (NCDVal_IsInvalid(*out)) {
  118. goto fail;
  119. }
  120. } break;
  121. case NCDVALUE_LIST: {
  122. *out = NCDVal_NewList(mem, NCDValue_ListCount(value));
  123. if (NCDVal_IsInvalid(*out)) {
  124. goto fail;
  125. }
  126. for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
  127. NCDValRef vval;
  128. if (!add_expr_recurser(o, e, mem, &vval)) {
  129. goto fail;
  130. }
  131. if (!NCDVal_ListAppend(*out, vval)) {
  132. BLog(BLOG_ERROR, "depth limit exceeded");
  133. goto fail;
  134. }
  135. }
  136. } break;
  137. case NCDVALUE_MAP: {
  138. *out = NCDVal_NewMap(mem, NCDValue_MapCount(value));
  139. if (NCDVal_IsInvalid(*out)) {
  140. goto fail;
  141. }
  142. for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
  143. NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
  144. NCDValRef vkey;
  145. NCDValRef vval;
  146. if (!add_expr_recurser(o, ekey, mem, &vkey) ||
  147. !add_expr_recurser(o, eval, mem, &vval)
  148. ) {
  149. goto fail;
  150. }
  151. int inserted;
  152. if (!NCDVal_MapInsert(*out, vkey, vval, &inserted)) {
  153. BLog(BLOG_ERROR, "depth limit exceeded");
  154. goto fail;
  155. }
  156. if (!inserted) {
  157. BLog(BLOG_ERROR, "duplicate key in map");
  158. goto fail;
  159. }
  160. }
  161. } break;
  162. case NCDVALUE_VAR: {
  163. struct NCDEvaluator__Var var;
  164. if (!ncd_make_name_indices(o->string_index, NCDValue_VarName(value), &var.varnames, &var.num_names)) {
  165. BLog(BLOG_ERROR, "ncd_make_name_indices failed");
  166. goto fail_var0;
  167. }
  168. size_t index;
  169. struct NCDEvaluator__Var *varptr = NCDEvaluator__VarVec_Push(&o->vars, &index);
  170. if (!varptr) {
  171. BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Push failed");
  172. goto fail_var1;
  173. }
  174. if (index >= MAX_LOCAL_IDS) {
  175. BLog(BLOG_ERROR, "too many variables");
  176. goto fail_var2;
  177. }
  178. *varptr = var;
  179. *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 0);
  180. break;
  181. fail_var2:
  182. NCDEvaluator__VarVec_Pop(&o->vars, NULL);
  183. fail_var1:
  184. BFree(var.varnames);
  185. fail_var0:
  186. goto fail;
  187. } break;
  188. case NCDVALUE_INVOC: {
  189. struct NCDEvaluator__Call call;
  190. NCDValue *func = NCDValue_InvocFunc(value);
  191. if (NCDValue_Type(func) != NCDVALUE_STRING) {
  192. BLog(BLOG_ERROR, "call function is not a string");
  193. goto fail_invoc0;
  194. }
  195. call.func_name_id = NCDStringIndex_GetBin(o->string_index, NCDValue_StringValue(func), NCDValue_StringLength(func));
  196. if (call.func_name_id < 0) {
  197. BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
  198. goto fail_invoc0;
  199. }
  200. NCDValue *arg = NCDValue_InvocArg(value);
  201. if (NCDValue_Type(arg) != NCDVALUE_LIST) {
  202. BLog(BLOG_ERROR, "call argument is not a list literal!?");
  203. goto fail_invoc0;
  204. }
  205. if (!(call.args = BAllocArray(NCDValue_ListCount(arg), sizeof(call.args[0])))) {
  206. BLog(BLOG_ERROR, "BAllocArray failed");
  207. goto fail_invoc0;
  208. }
  209. call.num_args = 0;
  210. for (NCDValue *e = NCDValue_ListFirst(arg); e; e = NCDValue_ListNext(arg, e)) {
  211. if (!expr_init(&call.args[call.num_args], o, e)) {
  212. goto fail_invoc1;
  213. }
  214. call.num_args++;
  215. }
  216. size_t index;
  217. struct NCDEvaluator__Call *callptr = NCDEvaluator__CallVec_Push(&o->calls, &index);
  218. if (!callptr) {
  219. BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Push failed");
  220. goto fail_invoc1;
  221. }
  222. if (index >= MAX_LOCAL_IDS) {
  223. BLog(BLOG_ERROR, "too many variables");
  224. goto fail_invoc2;
  225. }
  226. *callptr = call;
  227. *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 1);
  228. break;
  229. fail_invoc2:
  230. NCDEvaluator__CallVec_Pop(&o->calls, NULL);
  231. fail_invoc1:
  232. while (call.num_args-- > 0) {
  233. expr_free(&call.args[call.num_args]);
  234. }
  235. BFree(call.args);
  236. fail_invoc0:
  237. goto fail;
  238. } break;
  239. default: {
  240. BLog(BLOG_ERROR, "expression type not supported");
  241. goto fail;
  242. } break;
  243. }
  244. return 1;
  245. fail:
  246. return 0;
  247. }
  248. static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
  249. {
  250. struct NCDEvaluator__eval_context const *context = arg;
  251. NCDEvaluator *o = context->eval;
  252. int type = plid & 1;
  253. int index = plid >> 1;
  254. ASSERT(index >= 0)
  255. ASSERT(index < MAX_LOCAL_IDS)
  256. int res;
  257. switch (type) {
  258. case 0: {
  259. struct NCDEvaluator__Var *var = NCDEvaluator__VarVec_Get(&o->vars, index);
  260. res = context->funcs->func_eval_var(context->funcs->user, var->varnames, var->num_names, mem, out);
  261. } break;
  262. case 1: {
  263. struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, index);
  264. NCDEvaluatorArgs args;
  265. args.context = context;
  266. args.call_index = index;
  267. res = context->funcs->func_eval_call(context->funcs->user, call->func_name_id, args, mem, out);
  268. } break;
  269. default: {
  270. ASSERT(0)
  271. res = 0;
  272. } break;
  273. }
  274. ASSERT(res == 0 || res == 1)
  275. return res;
  276. }
  277. int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index)
  278. {
  279. o->string_index = string_index;
  280. if (!NCDEvaluator__VarVec_Init(&o->vars, NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY)) {
  281. BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Init failed");
  282. goto fail0;
  283. }
  284. if (!NCDEvaluator__CallVec_Init(&o->calls, NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY)) {
  285. BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Init failed");
  286. goto fail1;
  287. }
  288. return 1;
  289. fail1:
  290. NCDEvaluator__VarVec_Free(&o->vars);
  291. fail0:
  292. return 0;
  293. }
  294. void NCDEvaluator_Free (NCDEvaluator *o)
  295. {
  296. for (size_t i = 0; i < o->vars.count; i++) {
  297. BFree(o->vars.elems[i].varnames);
  298. }
  299. for (size_t i = 0; i < o->calls.count; i++) {
  300. struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, i);
  301. while (call->num_args-- > 0) {
  302. expr_free(&call->args[call->num_args]);
  303. }
  304. BFree(call->args);
  305. }
  306. NCDEvaluator__CallVec_Free(&o->calls);
  307. NCDEvaluator__VarVec_Free(&o->vars);
  308. }
  309. int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value)
  310. {
  311. return expr_init(&o->expr, eval, value);
  312. }
  313. void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o)
  314. {
  315. expr_free(&o->expr);
  316. }
  317. int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val)
  318. {
  319. ASSERT(funcs)
  320. ASSERT(out_newmem)
  321. ASSERT(out_val)
  322. struct NCDEvaluator__eval_context context;
  323. context.eval = eval;
  324. context.funcs = funcs;
  325. return expr_eval(&o->expr, &context, out_newmem, out_val);
  326. }
  327. size_t NCDEvaluatorArgs_Count (NCDEvaluatorArgs *o)
  328. {
  329. struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
  330. return call->num_args;
  331. }
  332. int NCDEvaluatorArgs_EvalArgNewMem (NCDEvaluatorArgs *o, size_t index, NCDValMem *out_newmem, NCDValRef *out_ref)
  333. {
  334. struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
  335. ASSERT(index < call->num_args)
  336. return expr_eval(&call->args[index], o->context, out_newmem, out_ref);
  337. }
  338. int NCDEvaluatorArgs_EvalArg (NCDEvaluatorArgs *o, size_t index, NCDValMem *mem, NCDValRef *out_ref)
  339. {
  340. int res = 0;
  341. NCDValMem temp_mem;
  342. NCDValRef temp_ref;
  343. if (!NCDEvaluatorArgs_EvalArgNewMem(o, index, &temp_mem, &temp_ref)) {
  344. goto fail0;
  345. }
  346. NCDValRef ref = NCDVal_NewCopy(mem, temp_ref);
  347. if (NCDVal_IsInvalid(ref)) {
  348. goto fail1;
  349. }
  350. *out_ref = ref;
  351. res = 1;
  352. fail1:
  353. NCDValMem_Free(&temp_mem);
  354. fail0:
  355. return res;
  356. }