Przeglądaj źródła

ncd: Implement Do.

Ambroz Bizjak 11 lat temu
rodzic
commit
5f05470cd7

+ 3 - 0
examples/ncd_tokenizer_test.c

@@ -126,6 +126,9 @@ static int tokenizer_output (void *user, int token, char *value, size_t value_le
         case NCD_TOKEN_CARET:
             printf("caret\n");
             break;
+        case NCD_TOKEN_DO:
+            printf("do\n");
+            break;
         default:
             printf("UNKNOWN_TOKEN\n");
             break;

Plik diff jest za duży
+ 422 - 374
generated/NCDConfigParser_parse.c


+ 9 - 8
generated/NCDConfigParser_parse.h

@@ -15,11 +15,12 @@
 #define ELIF                           15
 #define ELSE                           16
 #define BLOCK                          17
-#define DOT                            18
-#define COMMA                          19
-#define BRACKET_OPEN                   20
-#define BRACKET_CLOSE                  21
-#define AT_SIGN                        22
-#define CARET                          23
-#define PROCESS                        24
-#define TEMPLATE                       25
+#define TOKEN_DO                       18
+#define DOT                            19
+#define COMMA                          20
+#define BRACKET_OPEN                   21
+#define BRACKET_CLOSE                  22
+#define AT_SIGN                        23
+#define CARET                          24
+#define PROCESS                        25
+#define TEMPLATE                       26

Plik diff jest za duży
+ 492 - 424
generated/NCDConfigParser_parse.out


+ 38 - 1
generated/NCDConfigParser_parse.y

@@ -309,7 +309,7 @@ statement(R) ::= IF ROUND_OPEN value(A) ROUND_CLOSE CURLY_OPEN statements(B) CUR
         goto failE0;
     }
 
-    if (!NCDStatement_InitIf(&R.v, C, I.v)) {
+    if (!NCDStatement_InitIf(&R.v, C, I.v, NCDIFTYPE_IF)) {
         goto failE0;
     }
     I.have = 0;
@@ -480,6 +480,43 @@ doneGA0:
     free(N);
 }
 
+statement(R) ::= TOKEN_DO CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!S.have) {
+        goto failGB0;
+    }
+    
+    NCDValue dummy_val;
+    NCDValue_InitList(&dummy_val);
+    
+    NCDIf the_if;
+    NCDIf_Init(&the_if, dummy_val, S.v);
+    S.have = 0;
+    
+    NCDIfBlock if_block;
+    NCDIfBlock_Init(&if_block);
+    
+    if (!NCDIfBlock_PrependIf(&if_block, the_if)) {
+        NCDIfBlock_Free(&if_block);
+        NCDIf_Free(&the_if);
+        goto failGB0;
+    }
+    
+    if (!NCDStatement_InitIf(&R.v, N, if_block, NCDIFTYPE_DO)) {
+        NCDIfBlock_Free(&if_block);
+        goto failGB0;
+    }
+    
+    R.have = 1;
+    goto doneGB0;
+    
+failGB0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneGB0:
+    free_block(S);
+    free(N);
+}
+
 statements(R) ::= statement(A). {
     if (!A.have) {
         goto failH0;

+ 9 - 1
ncd/NCDAst.c

@@ -782,7 +782,7 @@ fail:
     return 0;
 }
 
-int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock)
+int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock, int iftype)
 {
     o->name = NULL;
     
@@ -793,6 +793,7 @@ int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock)
     o->type = NCDSTATEMENT_IF;
     o->ifc.ifblock = ifblock;
     o->ifc.have_else = 0;
+    o->ifc.iftype = iftype;
     
     return 1;
 }
@@ -915,6 +916,13 @@ NCDValue * NCDStatement_RegArgs (NCDStatement *o)
     return &o->reg.args;
 }
 
+int NCDStatement_IfType (NCDStatement *o)
+{
+    ASSERT(o->type == NCDSTATEMENT_IF)
+    
+    return o->ifc.iftype;
+}
+
 NCDIfBlock * NCDStatement_IfBlock (NCDStatement *o)
 {
     ASSERT(o->type == NCDSTATEMENT_IF)

+ 6 - 1
ncd/NCDAst.h

@@ -118,6 +118,7 @@ struct NCDStatement_s {
             NCDIfBlock ifblock;
             int have_else;
             NCDBlock else_block;
+            int iftype;
         } ifc;
         struct {
             NCDValue collection;
@@ -155,6 +156,9 @@ struct NCDIf_s {
 #define NCDSTATEMENT_FOREACH 3
 #define NCDSTATEMENT_BLOCK 4
 
+#define NCDIFTYPE_IF 1
+#define NCDIFTYPE_DO 2
+
 void NCDValue_Free (NCDValue *o);
 int NCDValue_Type (NCDValue *o);
 int NCDValue_InitString (NCDValue *o, const char *str) WARN_UNUSED;
@@ -216,7 +220,7 @@ NCDStatement * NCDBlock_NextStatement (NCDBlock *o, NCDStatement *es);
 size_t NCDBlock_NumStatements (NCDBlock *o);
 
 int NCDStatement_InitReg (NCDStatement *o, const char *name, const char *objname, const char *cmdname, NCDValue args) WARN_UNUSED;
-int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock) WARN_UNUSED;
+int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock, int iftype) WARN_UNUSED;
 int NCDStatement_InitForeach (NCDStatement *o, const char *name, NCDValue collection, const char *name1, const char *name2, NCDBlock block) WARN_UNUSED;
 int NCDStatement_InitBlock (NCDStatement *o, const char *name, NCDBlock block) WARN_UNUSED;
 void NCDStatement_Free (NCDStatement *o);
@@ -225,6 +229,7 @@ const char * NCDStatement_Name (NCDStatement *o);
 const char * NCDStatement_RegObjName (NCDStatement *o);
 const char * NCDStatement_RegCmdName (NCDStatement *o);
 NCDValue * NCDStatement_RegArgs (NCDStatement *o);
+int NCDStatement_IfType (NCDStatement *o);
 NCDIfBlock * NCDStatement_IfBlock (NCDStatement *o);
 void NCDStatement_IfAddElse (NCDStatement *o, NCDBlock else_block);
 NCDBlock * NCDStatement_IfElse (NCDStatement *o);

+ 4 - 0
ncd/NCDConfigParser.c

@@ -170,6 +170,10 @@ static int tokenizer_output (void *user, int token, char *value, size_t value_le
             Parse(state->parser, CARET, minor, &state->out);
         } break;
         
+        case NCD_TOKEN_DO: {
+            Parse(state->parser, TOKEN_DO, minor, &state->out);
+        } break;
+        
         default:
             BLog(BLOG_ERROR, "line %zu, character %zu: invalid token", line, line_char);
             free(minor.str);

+ 38 - 1
ncd/NCDConfigParser_parse.y

@@ -309,7 +309,7 @@ statement(R) ::= IF ROUND_OPEN value(A) ROUND_CLOSE CURLY_OPEN statements(B) CUR
         goto failE0;
     }
 
-    if (!NCDStatement_InitIf(&R.v, C, I.v)) {
+    if (!NCDStatement_InitIf(&R.v, C, I.v, NCDIFTYPE_IF)) {
         goto failE0;
     }
     I.have = 0;
@@ -480,6 +480,43 @@ doneGA0:
     free(N);
 }
 
+statement(R) ::= TOKEN_DO CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!S.have) {
+        goto failGB0;
+    }
+    
+    NCDValue dummy_val;
+    NCDValue_InitList(&dummy_val);
+    
+    NCDIf the_if;
+    NCDIf_Init(&the_if, dummy_val, S.v);
+    S.have = 0;
+    
+    NCDIfBlock if_block;
+    NCDIfBlock_Init(&if_block);
+    
+    if (!NCDIfBlock_PrependIf(&if_block, the_if)) {
+        NCDIfBlock_Free(&if_block);
+        NCDIf_Free(&the_if);
+        goto failGB0;
+    }
+    
+    if (!NCDStatement_InitIf(&R.v, N, if_block, NCDIFTYPE_DO)) {
+        NCDIfBlock_Free(&if_block);
+        goto failGB0;
+    }
+    
+    R.have = 1;
+    goto doneGB0;
+    
+failGB0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneGB0:
+    free_block(S);
+    free(N);
+}
+
 statements(R) ::= statement(A). {
     if (!A.have) {
         goto failH0;

+ 3 - 0
ncd/NCDConfigTokenizer.c

@@ -147,6 +147,9 @@ void NCDConfigTokenizer_Tokenize (MemRef the_str, NCDConfigTokenizer_output outp
         else if (l = data_begins_with(str, left, "Block")) {
             token = NCD_TOKEN_BLOCK;
         }
+        else if (l = data_begins_with(str, left, "Do")) {
+            token = NCD_TOKEN_DO;
+        }
         else if (l = data_begins_with(str, left, "include_guard")) {
             token = NCD_TOKEN_INCLUDE_GUARD;
         }

+ 1 - 0
ncd/NCDConfigTokenizer.h

@@ -61,6 +61,7 @@
 #define NCD_TOKEN_AT 23
 #define NCD_TOKEN_BLOCK 24
 #define NCD_TOKEN_CARET 25
+#define NCD_TOKEN_DO 26
 
 typedef int (*NCDConfigTokenizer_output) (void *user, int token, char *value, size_t value_len, size_t line, size_t line_char);
 

+ 58 - 1
ncd/NCDSugar.c

@@ -41,6 +41,7 @@ struct desugar_state {
 static int add_template (struct desugar_state *state, NCDBlock block, NCDValue *out_name_val);
 static int desugar_block (struct desugar_state *state, NCDBlock *block);
 static int desugar_if (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
+static int desugar_do (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
 static int desugar_foreach (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
 static int desugar_blockstmt (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
 
@@ -87,7 +88,16 @@ static int desugar_block (struct desugar_state *state, NCDBlock *block)
             } break;
             
             case NCDSTATEMENT_IF: {
-                if (!desugar_if(state, block, stmt, &stmt)) {
+                int iftype = NCDStatement_IfType(stmt);
+                
+                int res = 0;
+                if (iftype == NCDIFTYPE_IF) {
+                    res = desugar_if(state, block, stmt, &stmt);
+                } else if (iftype == NCDIFTYPE_DO) {
+                    res = desugar_do(state, block, stmt, &stmt);
+                }
+                
+                if (!res) {
                     return 0;
                 }
             } break;
@@ -116,6 +126,7 @@ static int desugar_block (struct desugar_state *state, NCDBlock *block)
 static int desugar_if (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next)
 {
     ASSERT(NCDStatement_Type(stmt) == NCDSTATEMENT_IF)
+    ASSERT(NCDStatement_IfType(stmt) == NCDIFTYPE_IF)
     
     NCDValue args;
     NCDValue_InitList(&args);
@@ -202,6 +213,52 @@ fail0:
     return 0;
 }
 
+
+static int desugar_do (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next)
+{
+    ASSERT(NCDStatement_Type(stmt) == NCDSTATEMENT_IF)
+    ASSERT(NCDStatement_IfType(stmt) == NCDIFTYPE_DO)
+    
+    NCDIfBlock *ifblock = NCDStatement_IfBlock(stmt);
+    ASSERT(NCDIfBlock_FirstIf(ifblock))
+    
+    NCDIf the_if = NCDIfBlock_GrabIf(ifblock, NCDIfBlock_FirstIf(ifblock));
+    
+    NCDValue if_cond;
+    NCDBlock if_block;
+    NCDIf_FreeGrab(&the_if, &if_cond, &if_block);
+    
+    NCDValue_Free(&if_cond);
+    
+    NCDValue action_arg;
+    if (!add_template(state, if_block, &action_arg)) {
+        goto fail;
+    }
+    
+    NCDValue stmt_args;
+    NCDValue_InitList(&stmt_args);
+    
+    if (!NCDValue_ListAppend(&stmt_args, action_arg)) {
+        NCDValue_Free(&stmt_args);
+        NCDValue_Free(&action_arg);
+        goto fail;
+    }
+    
+    NCDStatement new_stmt;
+    if (!NCDStatement_InitReg(&new_stmt, NCDStatement_Name(stmt), NULL, "do", stmt_args)) {
+        NCDValue_Free(&stmt_args);
+        goto fail;
+    }
+    
+    stmt = NCDBlock_ReplaceStatement(block, stmt, new_stmt);
+    
+    *out_next = NCDBlock_NextStatement(block, stmt);
+    return 1;
+    
+fail:
+    return 0;
+}
+
 static int desugar_foreach (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next)
 {
     ASSERT(NCDStatement_Type(stmt) == NCDSTATEMENT_FOREACH)

+ 132 - 53
ncd/modules/try.c

@@ -28,32 +28,45 @@
  * 
  * @section DESCRIPTION
  * 
+ * 
  * Synopsis:
  *   try(string template_name, list args)
+ *   do(string template_name)
  * 
  * Description:
  *   Does the following:
  *   1. Starts a template process from the specified template and arguments.
  *   2. Waits for the process to initialize completely, or for a _try->assert()
- *      assertion to fail.
+ *      assertion to fail or a _do->break() call.
  *   3. Initiates termination of the process and waits for it to terminate.
  *   4. Goes to up state. The "succeeded" variable reflects whether the process
  *      managed to initialize, or an assertion failed.
  *   If at any point during these steps termination of the try statement is
  *   requested, requests the process to terminate (if not already), and dies
- *   when it terminates.
+ *   when it terminates. The differences between try() and do() are that do()
+ *   directly exposes the caller scope (try() does via _caller), and the
+ *   availability of assert/break.
  * 
  * Variables:
  *   string succeeded - "true" if the template process finished, "false" if assert
- *     was called.
+ *     or break was called.
+ * 
  * 
  * Synopsis:
  *   try.try::assert(string cond)
  * 
  * Description:
- *   Call as _try->assert() from the template process. If cond is "true",
- *   does nothing. Else, initiates termination of the process (if not already),
- *   and marks the try operation as not succeeded.
+ *   Call as _try->assert() from the template process of try(). If cond is
+ *   "true", does nothing. Else, initiates termination of the process (if not
+ *   already), and marks the try operation as not succeeded.
+ * 
+ * 
+ * Synopsis:
+ *   do.do::break()
+ * 
+ * Description:
+ *   Call as _do->break() from the template process of do() to initiate
+ *   premature termination, marking the do operation as not succeeded.
  */
 
 #include <stdlib.h>
@@ -67,27 +80,25 @@
 
 struct instance {
     NCDModuleInst *i;
+    int is_do;
     NCDModuleProcess process;
     int state;
     int dying;
     int succeeded;
 };
 
-#define STATE_INIT 1
-#define STATE_DEINIT 2
-#define STATE_FINISHED 3
+enum {STATE_INIT, STATE_DEINIT, STATE_FINISHED};
 
 static void process_handler_event (NCDModuleProcess *process, int event);
 static int process_func_getspecialobj (NCDModuleProcess *process, NCD_string_id_t name, NCDObject *out_object);
 static int process_caller_object_func_getobj (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object);
 static void start_terminating (struct instance *o);
 static void instance_free (struct instance *o);
+static void instance_break (struct instance *o);
 
-enum {STRING_TRY, STRING_TRY_TRY};
+enum {STRING_TRY, STRING_TRY_TRY, STRING_DO, STRING_DO_DO};
 
-static const char *strings[] = {
-    "_try", "try.try", NULL
-};
+static const char *strings[] = {"_try", "try.try", "_do", "do.do"};
 
 static void process_handler_event (NCDModuleProcess *process, int event)
 {
@@ -102,10 +113,8 @@ static void process_handler_event (NCDModuleProcess *process, int event)
         } break;
         
         case NCDMODULEPROCESS_EVENT_DOWN: {
-            ASSERT(o->state == STATE_INIT)
-            
-            // continue
-            NCDModuleProcess_Continue(&o->process);
+            // Can't happen since we start terminating with it comes up.
+            ASSERT(0)
         } break;
         
         case NCDMODULEPROCESS_EVENT_TERMINATED: {
@@ -134,17 +143,26 @@ static int process_func_getspecialobj (NCDModuleProcess *process, NCD_string_id_
     struct instance *o = UPPER_OBJECT(process, struct instance, process);
     ASSERT(o->state == STATE_INIT || o->state == STATE_DEINIT)
     
-    if (name == NCD_STRING_CALLER) {
-        *out_object = NCDObject_Build(-1, o, NCDObject_no_getvar, process_caller_object_func_getobj);
-        return 1;
-    }
-    
-    if (name == ModuleString(o->i, STRING_TRY)) {
-        *out_object = NCDObject_Build(ModuleString(o->i, STRING_TRY_TRY), o, NCDObject_no_getvar, NCDObject_no_getobj);
-        return 1;
+    if (o->is_do) {
+        if (name == ModuleString(o->i, STRING_DO)) {
+            *out_object = NCDObject_Build(ModuleString(o->i, STRING_DO_DO), o, NCDObject_no_getvar, NCDObject_no_getobj);
+            return 1;
+        }
+        
+        return NCDModuleInst_Backend_GetObj(o->i, name, out_object);
+    } else {
+        if (name == NCD_STRING_CALLER) {
+            *out_object = NCDObject_Build(-1, o, NCDObject_no_getvar, process_caller_object_func_getobj);
+            return 1;
+        }
+        
+        if (name == ModuleString(o->i, STRING_TRY)) {
+            *out_object = NCDObject_Build(ModuleString(o->i, STRING_TRY_TRY), o, NCDObject_no_getvar, NCDObject_no_getobj);
+            return 1;
+        }
+        
+        return 0;
     }
-    
-    return 0;
 }
 
 static int process_caller_object_func_getobj (const NCDObject *obj, NCD_string_id_t name, NCDObject *out_object)
@@ -166,25 +184,14 @@ static void start_terminating (struct instance *o)
     o->state = STATE_DEINIT;
 }
 
-static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+static void func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_do, NCDValRef template_name, NCDValRef args)
 {
     struct instance *o = vo;
     o->i = i;
-    
-    // check arguments
-    NCDValRef template_name_arg;
-    NCDValRef args_arg;
-    if (!NCDVal_ListRead(params->args, 2, &template_name_arg, &args_arg)) {
-        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
-        goto fail0;
-    }
-    if (!NCDVal_IsString(template_name_arg) || !NCDVal_IsList(args_arg)) {
-        ModuleLog(o->i, BLOG_ERROR, "wrong type");
-        goto fail0;
-    }
+    o->is_do = is_do;
     
     // start process
-    if (!NCDModuleProcess_InitValue(&o->process, i, template_name_arg, args_arg, process_handler_event)) {
+    if (!NCDModuleProcess_InitValue(&o->process, i, template_name, args, process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
         goto fail0;
     }
@@ -202,11 +209,63 @@ fail0:
     NCDModuleInst_Backend_DeadError(i);
 }
 
+static void func_new_try (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    // check arguments
+    NCDValRef template_name_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(params->args, 2, &template_name_arg, &args_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail;
+    }
+    if (!NCDVal_IsString(template_name_arg) || !NCDVal_IsList(args_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail;
+    }
+    
+    return func_new_common(vo, i, params, 0, template_name_arg, args_arg);
+    
+fail:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
+static void func_new_do (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    // check arguments
+    NCDValRef template_name_arg;
+    if (!NCDVal_ListRead(params->args, 1, &template_name_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail;
+    }
+    if (!NCDVal_IsString(template_name_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail;
+    }
+    
+    return func_new_common(vo, i, params, 1, template_name_arg, NCDVal_NewInvalid());
+    
+fail:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
 static void instance_free (struct instance *o)
 {   
     NCDModuleInst_Backend_Dead(o->i);
 }
 
+static void instance_break (struct instance *o)
+{
+    ASSERT(o->state == STATE_INIT || o->state == STATE_DEINIT)
+    
+    // mark not succeeded
+    o->succeeded = 0;
+    
+    // start terminating if not already
+    if (o->state == STATE_INIT) {
+        start_terminating(o);
+    }
+}
+
 static void func_die (void *vo)
 {
     struct instance *o = vo;
@@ -254,21 +313,12 @@ static void assert_func_new (void *unused, NCDModuleInst *i, const struct NCDMod
         goto fail1;
     }
     
-    // get instance
-    struct instance *mo = params->method_user;
-    ASSERT(mo->state == STATE_INIT || mo->state == STATE_DEINIT)
-    
     // signal up
     NCDModuleInst_Backend_Up(i);
     
+    // break if needed
     if (!NCDVal_StringEquals(cond_arg, "true")) {
-        // mark not succeeded
-        mo->succeeded = 0;
-        
-        // start terminating if not already
-        if (mo->state == STATE_INIT) {
-            start_terminating(mo);
-        }
+        instance_break((struct instance *)params->method_user);
     }
     
     return;
@@ -277,16 +327,45 @@ fail1:
     NCDModuleInst_Backend_DeadError(i);
 }
 
+static void break_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    // check arguments
+    if (!NCDVal_ListRead(params->args, 0)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    
+    // signal up
+    NCDModuleInst_Backend_Up(i);
+    
+    // break
+    instance_break((struct instance *)params->method_user);
+    
+    return;
+    
+fail1:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
 static struct NCDModule modules[] = {
     {
         .type = "try",
-        .func_new2 = func_new,
+        .func_new2 = func_new_try,
+        .func_die = func_die,
+        .func_getvar2 = func_getvar2,
+        .alloc_size = sizeof(struct instance)
+    }, {
+        .type = "do",
+        .func_new2 = func_new_do,
         .func_die = func_die,
         .func_getvar2 = func_getvar2,
         .alloc_size = sizeof(struct instance)
     }, {
         .type = "try.try::assert",
         .func_new2 = assert_func_new
+    }, {
+        .type = "do.do::break",
+        .func_new2 = break_func_new
     }, {
         .type = NULL
     }

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików