浏览代码

ncd: modules: call: Implement inline_code calls.

Ambroz Bizjak 11 年之前
父节点
当前提交
98a7f642b0
共有 3 个文件被更改,包括 171 次插入11 次删除
  1. 1 0
      ncd/NCDStringIndex.c
  2. 169 11
      ncd/modules/call2.c
  3. 1 0
      ncd/static_strings.h

+ 1 - 0
ncd/NCDStringIndex.c

@@ -85,6 +85,7 @@ static const char *static_strings[] = {
     "exit_status",
     "size",
     "eof",
+    "_scope",
 };
 
 static NCD_string_id_t do_get (NCDStringIndex *o, const char *str, size_t str_len)

+ 169 - 11
ncd/modules/call2.c

@@ -28,6 +28,7 @@
  * 
  * @section DESCRIPTION
  * 
+ * 
  * Synopsis:
  *   call(string template, list args)
  * 
@@ -63,6 +64,7 @@
  *     concat("branch_", x) name;
  *     call(name, {});
  * 
+ * 
  * Synopsis:
  *   call_with_caller_target(string template, list args, string caller_target)
  * 
@@ -76,6 +78,7 @@
  *   there is no choice of 'caller_target' that would make call_with_caller_target()
  *   equivalent to call().
  * 
+ * 
  * Synopsis:
  *   embcall2_multif(string cond1, string template1, ..., [string else_template])
  * 
@@ -86,6 +89,23 @@
  *   template corresponding to the first condition equal to "true" is called; if
  *   there is no true condition, either the template 'else_template' is called,
  *   if it is provided, or nothing is performed, if 'else_template' is not provided.
+ * 
+ * 
+ * Synopsis:
+ *   inline_code(string template)
+ *   inline_code::call(list args)
+ * 
+ * Description:
+ *   The inline_code() acts as a proxy object for calling the specified template.
+ *   The inline_code::call calls the template of the corresponding inline_code
+ *   instance, in a manner similar to a simple "call". The called template will
+ *   have access to the following resources:
+ *   - The arguments will be available in the usual fashion.
+ *   - The scope of the inline_code::call instance will be available as "_caller".
+ *   - The scope of the inline_code instance will be directly available.
+ *   - The scope of the inline_code instance will also be available as "_scope".
+ *     This is useful to access shadowed names, e.g. "_caller" and the arguments
+ *     stuff (_argN, _args).
  */
 
 #include <stdlib.h>
@@ -93,6 +113,7 @@
 
 #include <misc/debug.h>
 #include <misc/offset.h>
+#include <structure/LinkedList0.h>
 
 #include <ncd/module_common.h>
 
@@ -106,8 +127,13 @@
 
 #define NUM_STATIC_NAMES 4
 
+struct instance;
+
+typedef void (*call_extra_free_cb) (struct instance *o);
+
 struct instance {
     NCDModuleInst *i;
+    call_extra_free_cb extra_free_cb;
     NCDModuleProcess process;
     int state;
 };
@@ -119,6 +145,18 @@ struct instance_with_caller_target {
     NCD_string_id_t static_names[NUM_STATIC_NAMES];
 };
 
+struct inline_code {
+    NCDModuleInst *i;
+    NCDValRef template_name;
+    LinkedList0 calls_list;
+};
+
+struct inline_code_call {
+    struct instance base;
+    struct inline_code *ic;
+    LinkedList0Node ic_node;
+};
+
 #define NAMES_PARAM_NAME CallNames
 #define NAMES_PARAM_TYPE struct instance_with_caller_target
 #define NAMES_PARAM_MEMBER_DYNAMIC_NAMES dynamic_names
@@ -133,8 +171,11 @@ static int process_func_getspecialobj_noembed (NCDModuleProcess *process, NCD_st
 static int process_func_getspecialobj_with_caller_target (NCDModuleProcess *process, NCD_string_id_t name, NCDObject *out_object);
 static int caller_obj_func_getobj (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object);
 static int caller_obj_func_getobj_with_caller_target (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object);
-static void func_new_templ (void *vo, NCDModuleInst *i, NCDValRef template_name, NCDValRef args, int embed);
+static int func_new_templ (void *vo, NCDModuleInst *i, NCDValRef template_name, NCDValRef args, NCDModuleProcess_func_getspecialobj func_getspecialobj, call_extra_free_cb extra_free_cb);
 static void instance_free (struct instance *o);
+static void inline_code_extra_free (struct instance *bo);
+static int inline_code_call_process_getspecialobj (NCDModuleProcess *process, NCD_string_id_t name, NCDObject *out_object);
+static int inline_code_scope_obj_getobj (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object);
 
 static void process_handler_event (NCDModuleProcess *process, int event)
 {
@@ -236,14 +277,15 @@ static int caller_obj_func_getobj_with_caller_target (const NCDObject *obj, NCD_
     return NCDObject_GetObj(&obj2, name, out_object);
 }
 
-static void func_new_templ (void *vo, NCDModuleInst *i, NCDValRef template_name, NCDValRef args, int embed)
+static int func_new_templ (void *vo, NCDModuleInst *i, NCDValRef template_name, NCDValRef args, NCDModuleProcess_func_getspecialobj func_getspecialobj, call_extra_free_cb extra_free_cb)
 {
     ASSERT(NCDVal_IsInvalid(template_name) || NCDVal_IsString(template_name))
     ASSERT(NCDVal_IsInvalid(args) || NCDVal_IsList(args))
-    ASSERT(embed == !!embed)
+    ASSERT(func_getspecialobj)
     
     struct instance *o = vo;
     o->i = i;
+    o->extra_free_cb = extra_free_cb;
     
     if (NCDVal_IsInvalid(template_name) || ncd_is_none(template_name)) {
         // signal up
@@ -259,24 +301,25 @@ static void func_new_templ (void *vo, NCDModuleInst *i, NCDValRef template_name,
         }
         
         // set special functions
-        if (embed) {
-            NCDModuleProcess_SetSpecialFuncs(&o->process, process_func_getspecialobj_embed);
-        } else {
-            NCDModuleProcess_SetSpecialFuncs(&o->process, process_func_getspecialobj_noembed);
-        }
+        NCDModuleProcess_SetSpecialFuncs(&o->process, func_getspecialobj);
         
         // set state working
         o->state = STATE_WORKING;
     }
     
-    return;
+    return 1;
     
 fail0:
     NCDModuleInst_Backend_DeadError(i);
+    return 0;
 }
 
 static void instance_free (struct instance *o)
 {
+    if (o->extra_free_cb) {
+        o->extra_free_cb(o);
+    }
+    
     // free process
     if (o->state != STATE_NONE) {
         NCDModuleProcess_Free(&o->process);
@@ -298,7 +341,7 @@ static void func_new_call (void *vo, NCDModuleInst *i, const struct NCDModuleIns
         goto fail0;
     }
     
-    func_new_templ(vo, i, template_arg, args_arg, 0);
+    func_new_templ(vo, i, template_arg, args_arg, process_func_getspecialobj_noembed, NULL);
     return;
     
 fail0:
@@ -310,6 +353,7 @@ static void func_new_call_with_caller_target (void *vo, NCDModuleInst *i, const
     struct instance *o = vo;
     struct instance_with_caller_target *o_ct = vo;
     o->i = i;
+    o->extra_free_cb = NULL;
     
     NCDValRef template_arg;
     NCDValRef args_arg;
@@ -402,7 +446,7 @@ static void func_new_embcall_multif (void *vo, NCDModuleInst *i, const struct NC
         j += 2;
     }
     
-    func_new_templ(vo, i, template_value, NCDVal_NewInvalid(), 1);
+    func_new_templ(vo, i, template_value, NCDVal_NewInvalid(), process_func_getspecialobj_embed, NULL);
     return;
     
 fail0:
@@ -461,6 +505,107 @@ static int func_getobj (void *vo, NCD_string_id_t name, NCDObject *out_object)
     return NCDModuleProcess_GetObj(&o->process, name, out_object);
 }
 
+static void inline_code_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    NCDValRef template_arg;
+    if (!NCDVal_ListRead(params->args, 1, &template_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    if (!NCDVal_IsString(template_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail0;
+    }
+    
+    struct inline_code *o = vo;
+    o->i = i;
+    o->template_name = template_arg;
+    LinkedList0_Init(&o->calls_list);
+    
+    NCDModuleInst_Backend_Up(i);
+    return;
+    
+fail0:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
+static void inline_code_die (void *vo)
+{
+    struct inline_code *o = vo;
+    
+    for (LinkedList0Node *ln = LinkedList0_GetFirst(&o->calls_list); ln; ln = LinkedList0Node_Next(ln)) {
+        struct inline_code_call *call = UPPER_OBJECT(ln, struct inline_code_call, ic_node);
+        ASSERT(call->ic == o)
+        call->ic = NULL;
+    }
+    
+    NCDModuleInst_Backend_Dead(o->i);
+}
+
+static void inline_code_call_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(params->args, 1, &args_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    if (!NCDVal_IsList(args_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail0;
+    }
+    
+    struct inline_code_call *o = vo;
+    struct inline_code *ic = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
+    
+    if (func_new_templ(vo, i, ic->template_name, args_arg, inline_code_call_process_getspecialobj, inline_code_extra_free)) {
+        o->ic = ic;
+        LinkedList0_Prepend(&ic->calls_list, &o->ic_node);
+    }
+    
+    return;
+    
+fail0:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
+static void inline_code_extra_free (struct instance *bo)
+{
+    struct inline_code_call *o = (void *)bo;
+    
+    if (o->ic) {
+        LinkedList0_Remove(&o->ic->calls_list, &o->ic_node);
+    }
+}
+
+static int inline_code_call_process_getspecialobj (NCDModuleProcess *process, NCD_string_id_t name, NCDObject *out_object)
+{
+    struct inline_code_call *o = UPPER_OBJECT(process, struct inline_code_call, base.process);
+    
+    if (name == NCD_STRING_CALLER) {
+        *out_object = NCDObject_Build(-1, o, NCDObject_no_getvar, caller_obj_func_getobj);
+        return 1;
+    }
+    
+    if (!o->ic) {
+        ModuleLog(o->base.i, BLOG_ERROR, "inline_code object is gone");
+        return 0;
+    }
+    
+    if (name == NCD_STRING_SCOPE) {
+        *out_object = NCDObject_Build(-1, o->ic, NCDObject_no_getvar, inline_code_scope_obj_getobj);
+        return 1;
+    }
+    
+    return NCDModuleInst_Backend_GetObj(o->ic->i, name, out_object);
+}
+
+static int inline_code_scope_obj_getobj (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object)
+{
+    struct inline_code *ic = NCDObject_DataPtr(obj);
+    
+    return NCDModuleInst_Backend_GetObj(ic->i, name, out_object);
+}
+
 static struct NCDModule modules[] = {
     {
         .type = "call",
@@ -486,6 +631,19 @@ static struct NCDModule modules[] = {
         .func_getobj = func_getobj,
         .flags = NCDMODULE_FLAG_CAN_RESOLVE_WHEN_DOWN|NCDMODULE_FLAG_ACCEPT_NON_CONTINUOUS_STRINGS,
         .alloc_size = sizeof(struct instance)
+    }, {
+        .type = "inline_code",
+        .func_new2 = inline_code_new,
+        .func_die = inline_code_die,
+        .alloc_size = sizeof(struct inline_code)
+    }, {
+        .type = "inline_code::call",
+        .func_new2 = inline_code_call_new,
+        .func_die = func_die,
+        .func_clean = func_clean,
+        .func_getobj = func_getobj,
+        .flags = NCDMODULE_FLAG_CAN_RESOLVE_WHEN_DOWN|NCDMODULE_FLAG_ACCEPT_NON_CONTINUOUS_STRINGS,
+        .alloc_size = sizeof(struct inline_code_call)
     }, {
         .type = NULL
     }

+ 1 - 0
ncd/static_strings.h

@@ -66,6 +66,7 @@ enum {
     NCD_STRING_EXIT_STATUS,
     NCD_STRING_SIZE,
     NCD_STRING_EOF,
+    NCD_STRING_SCOPE,
 };
 
 #endif