2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <murphy/common/macros.h>
37 #include <murphy/common/debug.h>
38 #include <murphy/common/mm.h>
39 #include <murphy/common/list.h>
40 #include <murphy/common/hashtbl.h>
41 #include <murphy/common/utils.h>
43 #include <murphy/core/scripting.h>
45 static MRP_LIST_HOOK(interpreters); /* registered interpreters */
46 static const char *default_interpreter = "simple"; /* the default interpreter */
54 const char *name; /* variable name */
55 mrp_script_type_t type; /* type if declared */
56 int id; /* variable id */
61 * a context frame (a set of context variable values)
64 typedef struct context_value_s context_value_t;
65 struct context_value_s {
66 int id; /* variable id */
67 mrp_script_value_t value; /* value for this variable */
68 context_value_t *next; /* next value in this frame */
71 typedef struct context_frame_s context_frame_t;
72 struct context_frame_s {
73 context_value_t *values; /* hook to more value */
74 context_frame_t *prev; /* previous frame */
79 * table of context variables and context frames
82 struct mrp_context_tbl_s {
83 context_var_t *variables; /* known/declared context variables */
84 int nvariable; /* number of variables */
85 mrp_htbl_t *names; /* variable name to id mapping */
86 context_frame_t *frame; /* active frame */
91 int mrp_register_interpreter(mrp_interpreter_t *i)
93 MRP_UNUSED(default_interpreter);
95 mrp_list_init(&i->hook);
96 mrp_list_append(&interpreters, &i->hook);
102 static void unregister_interpreter(mrp_interpreter_t *i)
104 mrp_list_delete(&i->hook);
105 mrp_list_init(&i->hook);
109 int mrp_unregister_interpreter(const char *name)
111 mrp_interpreter_t *i;
113 i = mrp_lookup_interpreter(name);
116 unregister_interpreter(i);
126 mrp_interpreter_t *mrp_lookup_interpreter(const char *name)
128 mrp_list_hook_t *p, *n;
129 mrp_interpreter_t *i;
131 mrp_list_foreach(&interpreters, p, n) {
132 i = mrp_list_entry(p, typeof(*i), hook);
133 if (!strcmp(i->name, name))
141 mrp_scriptlet_t *mrp_create_script(const char *type, const char *source)
143 mrp_interpreter_t *i;
147 i = mrp_lookup_interpreter(type);
150 s = mrp_allocz(sizeof(*s));
154 s->source = mrp_strdup(source);
156 if (s->source != NULL)
171 void mrp_destroy_script(mrp_scriptlet_t *script)
173 if (script != NULL) {
174 if (script->interpreter && script->interpreter->cleanup)
175 script->interpreter->cleanup(script);
177 mrp_free(script->source);
183 int mrp_compile_script(mrp_scriptlet_t *s)
186 return s->interpreter->compile(s);
192 int mrp_prepare_script(mrp_scriptlet_t *s)
194 if (s != NULL && s->interpreter->prepare != NULL)
195 return s->interpreter->prepare(s);
201 int mrp_execute_script(mrp_scriptlet_t *s, mrp_context_tbl_t *ctbl)
204 return s->interpreter->execute(s, ctbl);
210 char *mrp_print_value(char *buf, size_t size, mrp_script_value_t *value)
212 #define HANDLE_TYPE(type, fmt, val) \
213 case MRP_SCRIPT_TYPE_##type: \
214 snprintf(buf, size, fmt, val); \
217 switch (value->type) {
218 HANDLE_TYPE(UNKNOWN, "%s" , "<unknown/invalid type>");
219 HANDLE_TYPE(STRING , "'%s'" , value->str);
220 HANDLE_TYPE(BOOL , "%s" , value->bln ? "true" : "false");
221 HANDLE_TYPE(UINT8 , "%uU8" , value->u8);
222 HANDLE_TYPE(SINT8 , "%dS8" , value->s8);
223 HANDLE_TYPE(UINT16 , "%uU16" , value->u16);
224 HANDLE_TYPE(SINT16 , "%dS16" , value->s16);
225 HANDLE_TYPE(UINT32 , "%uU32" , value->u32);
226 HANDLE_TYPE(SINT32 , "%dS32" , value->s32);
227 HANDLE_TYPE(UINT64 , "%lluU64", (unsigned long long)value->u64);
228 HANDLE_TYPE(SINT64 , "%lldS64", ( signed long long)value->s64);
229 HANDLE_TYPE(DOUBLE , "%f" , value->dbl);
231 snprintf(buf, size, "<invalid type 0x%x>", value->type);
240 mrp_context_tbl_t *mrp_create_context_table(void)
242 mrp_context_tbl_t *tbl;
243 mrp_htbl_config_t hcfg;
245 tbl = mrp_allocz(sizeof(*tbl));
249 hcfg.comp = mrp_string_comp;
250 hcfg.hash = mrp_string_hash;
254 tbl->names = mrp_htbl_create(&hcfg);
256 if (tbl->names != NULL)
266 void mrp_destroy_context_table(mrp_context_tbl_t *tbl)
269 while (mrp_pop_context_frame(tbl) == 0)
272 mrp_htbl_destroy(tbl->names, FALSE);
278 static context_var_t *lookup_context_var(mrp_context_tbl_t *tbl,
283 id = (int)(ptrdiff_t)mrp_htbl_lookup(tbl->names, (void *)name);
285 if (0 < id && id <= tbl->nvariable)
286 return tbl->variables + id - 1;
292 int mrp_declare_context_variable(mrp_context_tbl_t *tbl, const char *name,
293 mrp_script_type_t type)
297 var = lookup_context_var(tbl, name);
305 if (!type || var->type == type)
314 o = sizeof(*tbl->variables) * tbl->nvariable;
315 n = sizeof(*tbl->variables) * (tbl->nvariable + 1);
317 if (!mrp_reallocz(tbl->variables, o, n))
320 var = tbl->variables + tbl->nvariable++;
322 var->name = mrp_strdup(name);
324 var->id = tbl->nvariable; /* this is a 1-based index... */
326 if (var->name != NULL) {
327 if (mrp_htbl_insert(tbl->names, (void *)var->name,
328 (void *)(ptrdiff_t)var->id))
337 int mrp_push_context_frame(mrp_context_tbl_t *tbl)
341 f = mrp_allocz(sizeof(*f));
345 f->prev = tbl->frame;
348 mrp_debug("pushed new context frame...");
357 int mrp_pop_context_frame(mrp_context_tbl_t *tbl)
360 context_value_t *v, *n;
365 for (v = f->values; v != NULL; v = n) {
368 if (v->value.type == MRP_SCRIPT_TYPE_STRING)
369 mrp_free(v->value.str);
371 mrp_debug("popped variable <%d>", v->id);
375 tbl->frame = f->prev;
378 mrp_debug("popped context frame");
389 int get_context_id(mrp_context_tbl_t *tbl, const char *name)
391 return (int)(ptrdiff_t)mrp_htbl_lookup(tbl->names, (void *)name);
395 int get_context_value(mrp_context_tbl_t *tbl, int id, mrp_script_value_t *value)
400 if (0 < id && id <= tbl->nvariable) {
401 for (f = tbl->frame; f != NULL; f = f->prev) {
402 for (v = f->values; v != NULL; v = v->next) {
411 value->type = MRP_SCRIPT_TYPE_INVALID;
418 int set_context_value(mrp_context_tbl_t *tbl, int id, mrp_script_value_t *value)
422 context_value_t *val;
425 if (!(0 < id && id <= tbl->nvariable)) {
430 var = tbl->variables + id - 1;
431 if (var->type != MRP_SCRIPT_TYPE_INVALID && var->type != value->type) {
438 val = mrp_allocz(sizeof(*val));
444 if (val->value.type != MRP_SCRIPT_TYPE_STRING ||
445 ((val->value.str = mrp_strdup(val->value.str)) != NULL)) {
446 val->next = f->values;
449 mrp_debug("set &%s=%s", var->name,
450 mrp_print_value(vbuf, sizeof(vbuf), value));
465 int set_context_values(mrp_context_tbl_t *tbl, int *ids,
466 mrp_script_value_t *values, int nid)
470 for (i = 0; i < nid; i++) {
471 if (set_context_value(tbl, ids[i], values + i) < 0)
479 int mrp_get_context_id(mrp_context_tbl_t *tbl, const char *name)
483 id = get_context_id(tbl, name);
486 id = mrp_declare_context_variable(tbl, name, MRP_SCRIPT_TYPE_UNKNOWN);
491 int mrp_get_context_value(mrp_context_tbl_t *tbl, int id,
492 mrp_script_value_t *value)
494 return get_context_value(tbl, id, value);
498 int mrp_set_context_value(mrp_context_tbl_t *tbl, int id,
499 mrp_script_value_t *value)
501 return set_context_value(tbl, id, value);
505 int mrp_get_context_value_by_name(mrp_context_tbl_t *tbl, const char *name,
506 mrp_script_value_t *value)
508 return get_context_value(tbl, get_context_id(tbl, name), value);
512 int mrp_set_context_value_by_name(mrp_context_tbl_t *tbl, const char *name,
513 mrp_script_value_t *value)
517 id = get_context_id(tbl, name);
519 if (id <= 0) /* auto-declare as an untyped variable */
520 id = mrp_declare_context_variable(tbl, name, MRP_SCRIPT_TYPE_UNKNOWN);
522 return set_context_value(tbl, id, value);