Просмотр исходного кода

ncd: add support for method statements

ambrop7 15 лет назад
Родитель
Сommit
5b4af1b38a

+ 168 - 130
generated/NCDConfigParser_parse.c

@@ -70,17 +70,17 @@ struct parser_out {
 **                       defined, then do no error processing.
 */
 #define YYCODETYPE unsigned char
-#define YYNOCODE 20
+#define YYNOCODE 21
 #define YYACTIONTYPE unsigned char
 #define ParseTOKENTYPE void *
 typedef union {
   int yyinit;
   ParseTOKENTYPE yy0;
-  char * yy9;
-  struct NCDConfig_interfaces * yy20;
-  struct NCDConfig_statements * yy26;
-  struct NCDConfig_strings * yy30;
-  struct NCDConfig_arguments * yy36;
+  struct NCDConfig_strings * yy4;
+  struct NCDConfig_interfaces * yy14;
+  struct NCDConfig_arguments * yy24;
+  struct NCDConfig_statements * yy30;
+  char * yy33;
 } YYMINORTYPE;
 #ifndef YYSTACKDEPTH
 #define YYSTACKDEPTH 0
@@ -89,8 +89,8 @@ typedef union {
 #define ParseARG_PDECL ,struct parser_out *parser_out
 #define ParseARG_FETCH struct parser_out *parser_out = yypParser->parser_out
 #define ParseARG_STORE yypParser->parser_out = parser_out
-#define YYNSTATE 26
-#define YYNRULE 15
+#define YYNSTATE 35
+#define YYNRULE 17
 #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
 #define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
 #define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
@@ -160,32 +160,37 @@ static const YYMINORTYPE yyzerominor = { 0 };
 **  yy_default[]       Default action for each state.
 */
 static const YYACTIONTYPE yy_action[] = {
- /*     0 */    18,   14,   23,    9,   16,   10,   18,   16,   25,   42,
- /*    10 */    18,   17,   24,   12,   13,   22,   20,   13,   19,   26,
- /*    20 */    11,    6,   21,    4,   15,    2,    1,   43,    7,   43,
- /*    30 */     5,   43,    8,   43,   43,    3,
+ /*     0 */    26,   19,   32,   26,   22,   32,   14,   24,   15,   26,
+ /*    10 */    27,   34,   53,   30,   26,   25,   33,   17,   18,   13,
+ /*    20 */    28,   18,   29,   18,   10,   12,   24,   20,   21,   31,
+ /*    30 */    23,   35,   16,    8,    9,    5,   12,    3,    1,   54,
+ /*    40 */     2,    6,   11,   54,   54,   54,    7,   54,    4,
 };
 static const YYCODETYPE yy_lookahead[] = {
- /*     0 */    14,   15,   16,   12,    2,    1,   14,    2,   16,   18,
- /*    10 */    14,    9,   16,   13,   14,    2,   13,   14,   12,    0,
- /*    20 */     2,    4,   14,    3,   17,   10,    5,   19,    6,   19,
- /*    30 */     7,   19,    8,   19,   19,   10,
+ /*     0 */    15,   16,   17,   15,   16,   17,   13,    2,    1,   15,
+ /*    10 */    13,   17,   19,    2,   15,   10,   17,   14,   15,    2,
+ /*    20 */    14,   15,   14,   15,    8,    9,    2,   18,   15,   15,
+ /*    30 */    18,    0,    2,    4,    6,    3,    9,   11,    5,   20,
+ /*    40 */     5,    7,    6,   20,   20,   20,    7,   20,   11,
 };
 #define YY_SHIFT_USE_DFLT (-1)
-#define YY_SHIFT_MAX 18
+#define YY_SHIFT_MAX 26
 static const signed char yy_shift_ofst[] = {
- /*     0 */     4,    2,    2,    2,    5,    5,    4,   13,    5,   19,
- /*    10 */    18,   20,   17,   21,   22,   23,   24,   15,   25,
+ /*     0 */     7,    5,    5,    5,    5,   17,   17,   17,    7,   11,
+ /*    10 */    24,   11,   24,   16,   31,   30,   32,   29,   33,   28,
+ /*    20 */    34,   35,   36,   39,   27,   26,   37,
 };
-#define YY_REDUCE_USE_DFLT (-15)
-#define YY_REDUCE_MAX 8
+#define YY_REDUCE_USE_DFLT (-16)
+#define YY_REDUCE_MAX 12
 static const signed char yy_reduce_ofst[] = {
- /*     0 */    -9,  -14,   -8,   -4,    0,    3,    6,    7,    8,
+ /*     0 */    -7,  -15,  -12,   -6,   -1,    3,    6,    8,   -3,    9,
+ /*    10 */    13,   12,   14,
 };
 static const YYACTIONTYPE yy_default[] = {
- /*     0 */    41,   33,   41,   41,   41,   29,   27,   39,   41,   41,
- /*    10 */    41,   41,   41,   41,   41,   41,   31,   35,   36,   28,
- /*    20 */    30,   32,   40,   34,   38,   37,
+ /*     0 */    52,   44,   44,   52,   52,   52,   38,   40,   36,   50,
+ /*    10 */    52,   50,   52,   42,   52,   52,   52,   52,   52,   52,
+ /*    20 */    52,   52,   52,   52,   42,   46,   47,   37,   39,   41,
+ /*    30 */    51,   43,   45,   49,   48,
 };
 #define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
 
@@ -281,9 +286,9 @@ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
 static const char *const yyTokenName[] = { 
   "$",             "PROCESS",       "NAME",          "CURLY_OPEN",  
   "CURLY_CLOSE",   "ROUND_OPEN",    "ROUND_CLOSE",   "SEMICOLON",   
-  "DOT",           "STRING",        "COMMA",         "error",       
-  "interfaces",    "statements",    "statement_names",  "statement_args_maybe",
-  "statement_args",  "name_maybe",    "input",       
+  "ARROW",         "DOT",           "STRING",        "COMMA",       
+  "error",         "interfaces",    "statements",    "statement_names",
+  "statement_args_maybe",  "statement_args",  "name_maybe",    "input",       
 };
 #endif /* NDEBUG */
 
@@ -296,16 +301,18 @@ static const char *const yyRuleName[] = {
  /*   2 */ "interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE interfaces",
  /*   3 */ "statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON",
  /*   4 */ "statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements",
- /*   5 */ "statement_names ::= NAME",
- /*   6 */ "statement_names ::= NAME DOT statement_names",
- /*   7 */ "statement_args_maybe ::=",
- /*   8 */ "statement_args_maybe ::= statement_args",
- /*   9 */ "statement_args ::= STRING",
- /*  10 */ "statement_args ::= statement_names",
- /*  11 */ "statement_args ::= STRING COMMA statement_args",
- /*  12 */ "statement_args ::= statement_names COMMA statement_args",
- /*  13 */ "name_maybe ::=",
- /*  14 */ "name_maybe ::= NAME",
+ /*   5 */ "statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON",
+ /*   6 */ "statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements",
+ /*   7 */ "statement_names ::= NAME",
+ /*   8 */ "statement_names ::= NAME DOT statement_names",
+ /*   9 */ "statement_args_maybe ::=",
+ /*  10 */ "statement_args_maybe ::= statement_args",
+ /*  11 */ "statement_args ::= STRING",
+ /*  12 */ "statement_args ::= statement_names",
+ /*  13 */ "statement_args ::= STRING COMMA statement_args",
+ /*  14 */ "statement_args ::= statement_names COMMA statement_args",
+ /*  15 */ "name_maybe ::=",
+ /*  16 */ "name_maybe ::= NAME",
 };
 #endif /* NDEBUG */
 
@@ -392,49 +399,50 @@ static void yy_destructor(
     case 5: /* ROUND_OPEN */
     case 6: /* ROUND_CLOSE */
     case 7: /* SEMICOLON */
-    case 8: /* DOT */
-    case 9: /* STRING */
-    case 10: /* COMMA */
+    case 8: /* ARROW */
+    case 9: /* DOT */
+    case 10: /* STRING */
+    case 11: /* COMMA */
 {
 #line 43 "NCDConfigParser_parse.y"
  free((yypminor->yy0)); 
-#line 402 "NCDConfigParser_parse.c"
+#line 410 "NCDConfigParser_parse.c"
 }
       break;
-    case 12: /* interfaces */
+    case 13: /* interfaces */
 {
 #line 52 "NCDConfigParser_parse.y"
- NCDConfig_free_interfaces((yypminor->yy20)); 
-#line 409 "NCDConfigParser_parse.c"
+ NCDConfig_free_interfaces((yypminor->yy14)); 
+#line 417 "NCDConfigParser_parse.c"
 }
       break;
-    case 13: /* statements */
+    case 14: /* statements */
 {
 #line 53 "NCDConfigParser_parse.y"
- NCDConfig_free_statements((yypminor->yy26)); 
-#line 416 "NCDConfigParser_parse.c"
+ NCDConfig_free_statements((yypminor->yy30)); 
+#line 424 "NCDConfigParser_parse.c"
 }
       break;
-    case 14: /* statement_names */
+    case 15: /* statement_names */
 {
 #line 54 "NCDConfigParser_parse.y"
- NCDConfig_free_strings((yypminor->yy30)); 
-#line 423 "NCDConfigParser_parse.c"
+ NCDConfig_free_strings((yypminor->yy4)); 
+#line 431 "NCDConfigParser_parse.c"
 }
       break;
-    case 15: /* statement_args_maybe */
-    case 16: /* statement_args */
+    case 16: /* statement_args_maybe */
+    case 17: /* statement_args */
 {
 #line 55 "NCDConfigParser_parse.y"
- NCDConfig_free_arguments((yypminor->yy36)); 
-#line 431 "NCDConfigParser_parse.c"
+ NCDConfig_free_arguments((yypminor->yy24)); 
+#line 439 "NCDConfigParser_parse.c"
 }
       break;
-    case 17: /* name_maybe */
+    case 18: /* name_maybe */
 {
 #line 57 "NCDConfigParser_parse.y"
- free((yypminor->yy9)); 
-#line 438 "NCDConfigParser_parse.c"
+ free((yypminor->yy33)); 
+#line 446 "NCDConfigParser_parse.c"
 }
       break;
     default:  break;   /* If no destructor action specified: do nothing */
@@ -612,7 +620,7 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
     if (yypMinor) {
         free(yypMinor->yy0);
     }
-#line 616 "NCDConfigParser_parse.c"
+#line 624 "NCDConfigParser_parse.c"
    ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
 }
 
@@ -669,21 +677,23 @@ static const struct {
   YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
   unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
 } yyRuleInfo[] = {
-  { 18, 1 },
-  { 12, 5 },
-  { 12, 6 },
+  { 19, 1 },
+  { 13, 5 },
   { 13, 6 },
-  { 13, 7 },
-  { 14, 1 },
-  { 14, 3 },
-  { 15, 0 },
+  { 14, 6 },
+  { 14, 7 },
+  { 14, 8 },
+  { 14, 9 },
   { 15, 1 },
+  { 15, 3 },
+  { 16, 0 },
   { 16, 1 },
-  { 16, 1 },
-  { 16, 3 },
-  { 16, 3 },
-  { 17, 0 },
   { 17, 1 },
+  { 17, 1 },
+  { 17, 3 },
+  { 17, 3 },
+  { 18, 0 },
+  { 18, 1 },
 };
 
 static void yy_accept(yyParser*);  /* Forward Declaration */
@@ -741,156 +751,184 @@ static void yy_reduce(
       case 0: /* input ::= interfaces */
 #line 72 "NCDConfigParser_parse.y"
 {
-    parser_out->ast = yymsp[0].minor.yy20;
+    parser_out->ast = yymsp[0].minor.yy14;
 
-    if (!yymsp[0].minor.yy20) {
+    if (!yymsp[0].minor.yy14) {
         parser_out->out_of_memory = 1;
     }
 }
-#line 751 "NCDConfigParser_parse.c"
+#line 761 "NCDConfigParser_parse.c"
         break;
       case 1: /* interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE */
 #line 80 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy20 = NCDConfig_make_interfaces(yymsp[-3].minor.yy0, yymsp[-1].minor.yy26, 0, NULL);
-    if (!yygotominor.yy20) {
+    yygotominor.yy14 = NCDConfig_make_interfaces(yymsp[-3].minor.yy0, yymsp[-1].minor.yy30, 0, NULL);
+    if (!yygotominor.yy14) {
         parser_out->out_of_memory = 1;
     }
   yy_destructor(yypParser,1,&yymsp[-4].minor);
   yy_destructor(yypParser,3,&yymsp[-2].minor);
   yy_destructor(yypParser,4,&yymsp[0].minor);
 }
-#line 764 "NCDConfigParser_parse.c"
+#line 774 "NCDConfigParser_parse.c"
         break;
       case 2: /* interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE interfaces */
 #line 87 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy20 = NCDConfig_make_interfaces(yymsp[-4].minor.yy0, yymsp[-2].minor.yy26, 1, yymsp[0].minor.yy20);
-    if (!yygotominor.yy20) {
+    yygotominor.yy14 = NCDConfig_make_interfaces(yymsp[-4].minor.yy0, yymsp[-2].minor.yy30, 1, yymsp[0].minor.yy14);
+    if (!yygotominor.yy14) {
         parser_out->out_of_memory = 1;
     }
   yy_destructor(yypParser,1,&yymsp[-5].minor);
   yy_destructor(yypParser,3,&yymsp[-3].minor);
   yy_destructor(yypParser,4,&yymsp[-1].minor);
 }
-#line 777 "NCDConfigParser_parse.c"
+#line 787 "NCDConfigParser_parse.c"
         break;
       case 3: /* statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON */
 #line 94 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy26 = NCDConfig_make_statements(yymsp[-5].minor.yy30, yymsp[-3].minor.yy36, yymsp[-1].minor.yy9, NULL);
-    if (!yygotominor.yy26) {
+    yygotominor.yy30 = NCDConfig_make_statements(NULL, yymsp[-5].minor.yy4, yymsp[-3].minor.yy24, yymsp[-1].minor.yy33, NULL);
+    if (!yygotominor.yy30) {
         parser_out->out_of_memory = 1;
     }
   yy_destructor(yypParser,5,&yymsp[-4].minor);
   yy_destructor(yypParser,6,&yymsp[-2].minor);
   yy_destructor(yypParser,7,&yymsp[0].minor);
 }
-#line 790 "NCDConfigParser_parse.c"
+#line 800 "NCDConfigParser_parse.c"
         break;
       case 4: /* statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements */
 #line 101 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy26 = NCDConfig_make_statements(yymsp[-6].minor.yy30, yymsp[-4].minor.yy36, yymsp[-2].minor.yy9, yymsp[0].minor.yy26);
-    if (!yygotominor.yy26) {
+    yygotominor.yy30 = NCDConfig_make_statements(NULL, yymsp[-6].minor.yy4, yymsp[-4].minor.yy24, yymsp[-2].minor.yy33, yymsp[0].minor.yy30);
+    if (!yygotominor.yy30) {
         parser_out->out_of_memory = 1;
     }
   yy_destructor(yypParser,5,&yymsp[-5].minor);
   yy_destructor(yypParser,6,&yymsp[-3].minor);
   yy_destructor(yypParser,7,&yymsp[-1].minor);
 }
-#line 803 "NCDConfigParser_parse.c"
+#line 813 "NCDConfigParser_parse.c"
         break;
-      case 5: /* statement_names ::= NAME */
+      case 5: /* statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON */
 #line 108 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy30 = NCDConfig_make_strings(yymsp[0].minor.yy0, 0, NULL);
+    yygotominor.yy30 = NCDConfig_make_statements(yymsp[-7].minor.yy0, yymsp[-5].minor.yy4, yymsp[-3].minor.yy24, yymsp[-1].minor.yy33, NULL);
     if (!yygotominor.yy30) {
         parser_out->out_of_memory = 1;
     }
+  yy_destructor(yypParser,8,&yymsp[-6].minor);
+  yy_destructor(yypParser,5,&yymsp[-4].minor);
+  yy_destructor(yypParser,6,&yymsp[-2].minor);
+  yy_destructor(yypParser,7,&yymsp[0].minor);
 }
-#line 813 "NCDConfigParser_parse.c"
+#line 827 "NCDConfigParser_parse.c"
         break;
-      case 6: /* statement_names ::= NAME DOT statement_names */
+      case 6: /* statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements */
 #line 115 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy30 = NCDConfig_make_strings(yymsp[-2].minor.yy0, 1, yymsp[0].minor.yy30);
+    yygotominor.yy30 = NCDConfig_make_statements(yymsp[-8].minor.yy0, yymsp[-6].minor.yy4, yymsp[-4].minor.yy24, yymsp[-2].minor.yy33, yymsp[0].minor.yy30);
     if (!yygotominor.yy30) {
         parser_out->out_of_memory = 1;
     }
-  yy_destructor(yypParser,8,&yymsp[-1].minor);
+  yy_destructor(yypParser,8,&yymsp[-7].minor);
+  yy_destructor(yypParser,5,&yymsp[-5].minor);
+  yy_destructor(yypParser,6,&yymsp[-3].minor);
+  yy_destructor(yypParser,7,&yymsp[-1].minor);
 }
-#line 824 "NCDConfigParser_parse.c"
+#line 841 "NCDConfigParser_parse.c"
         break;
-      case 7: /* statement_args_maybe ::= */
+      case 7: /* statement_names ::= NAME */
 #line 122 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = NULL;
+    yygotominor.yy4 = NCDConfig_make_strings(yymsp[0].minor.yy0, 0, NULL);
+    if (!yygotominor.yy4) {
+        parser_out->out_of_memory = 1;
+    }
+}
+#line 851 "NCDConfigParser_parse.c"
+        break;
+      case 8: /* statement_names ::= NAME DOT statement_names */
+#line 129 "NCDConfigParser_parse.y"
+{
+    yygotominor.yy4 = NCDConfig_make_strings(yymsp[-2].minor.yy0, 1, yymsp[0].minor.yy4);
+    if (!yygotominor.yy4) {
+        parser_out->out_of_memory = 1;
+    }
+  yy_destructor(yypParser,9,&yymsp[-1].minor);
 }
-#line 831 "NCDConfigParser_parse.c"
+#line 862 "NCDConfigParser_parse.c"
         break;
-      case 8: /* statement_args_maybe ::= statement_args */
-#line 126 "NCDConfigParser_parse.y"
+      case 9: /* statement_args_maybe ::= */
+#line 136 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = yymsp[0].minor.yy36;
+    yygotominor.yy24 = NULL;
 }
-#line 838 "NCDConfigParser_parse.c"
+#line 869 "NCDConfigParser_parse.c"
         break;
-      case 9: /* statement_args ::= STRING */
-#line 130 "NCDConfigParser_parse.y"
+      case 10: /* statement_args_maybe ::= statement_args */
+#line 140 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = NCDConfig_make_arguments_string(yymsp[0].minor.yy0, NULL);
-    if (!yygotominor.yy36) {
+    yygotominor.yy24 = yymsp[0].minor.yy24;
+}
+#line 876 "NCDConfigParser_parse.c"
+        break;
+      case 11: /* statement_args ::= STRING */
+#line 144 "NCDConfigParser_parse.y"
+{
+    yygotominor.yy24 = NCDConfig_make_arguments_string(yymsp[0].minor.yy0, NULL);
+    if (!yygotominor.yy24) {
         parser_out->out_of_memory = 1;
     }
 }
-#line 848 "NCDConfigParser_parse.c"
+#line 886 "NCDConfigParser_parse.c"
         break;
-      case 10: /* statement_args ::= statement_names */
-#line 137 "NCDConfigParser_parse.y"
+      case 12: /* statement_args ::= statement_names */
+#line 151 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = NCDConfig_make_arguments_var(yymsp[0].minor.yy30, NULL);
-    if (!yygotominor.yy36) {
+    yygotominor.yy24 = NCDConfig_make_arguments_var(yymsp[0].minor.yy4, NULL);
+    if (!yygotominor.yy24) {
         parser_out->out_of_memory = 1;
     }
 }
-#line 858 "NCDConfigParser_parse.c"
+#line 896 "NCDConfigParser_parse.c"
         break;
-      case 11: /* statement_args ::= STRING COMMA statement_args */
-#line 144 "NCDConfigParser_parse.y"
+      case 13: /* statement_args ::= STRING COMMA statement_args */
+#line 158 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = NCDConfig_make_arguments_string(yymsp[-2].minor.yy0, yymsp[0].minor.yy36);
-    if (!yygotominor.yy36) {
+    yygotominor.yy24 = NCDConfig_make_arguments_string(yymsp[-2].minor.yy0, yymsp[0].minor.yy24);
+    if (!yygotominor.yy24) {
         parser_out->out_of_memory = 1;
     }
-  yy_destructor(yypParser,10,&yymsp[-1].minor);
+  yy_destructor(yypParser,11,&yymsp[-1].minor);
 }
-#line 869 "NCDConfigParser_parse.c"
+#line 907 "NCDConfigParser_parse.c"
         break;
-      case 12: /* statement_args ::= statement_names COMMA statement_args */
-#line 151 "NCDConfigParser_parse.y"
+      case 14: /* statement_args ::= statement_names COMMA statement_args */
+#line 165 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy36 = NCDConfig_make_arguments_var(yymsp[-2].minor.yy30, yymsp[0].minor.yy36);
-    if (!yygotominor.yy36) {
+    yygotominor.yy24 = NCDConfig_make_arguments_var(yymsp[-2].minor.yy4, yymsp[0].minor.yy24);
+    if (!yygotominor.yy24) {
         parser_out->out_of_memory = 1;
     }
-  yy_destructor(yypParser,10,&yymsp[-1].minor);
+  yy_destructor(yypParser,11,&yymsp[-1].minor);
 }
-#line 880 "NCDConfigParser_parse.c"
+#line 918 "NCDConfigParser_parse.c"
         break;
-      case 13: /* name_maybe ::= */
-#line 158 "NCDConfigParser_parse.y"
+      case 15: /* name_maybe ::= */
+#line 172 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy9 = NULL;
+    yygotominor.yy33 = NULL;
 }
-#line 887 "NCDConfigParser_parse.c"
+#line 925 "NCDConfigParser_parse.c"
         break;
-      case 14: /* name_maybe ::= NAME */
-#line 162 "NCDConfigParser_parse.y"
+      case 16: /* name_maybe ::= NAME */
+#line 176 "NCDConfigParser_parse.y"
 {
-    yygotominor.yy9 = yymsp[0].minor.yy0;
+    yygotominor.yy33 = yymsp[0].minor.yy0;
 }
-#line 894 "NCDConfigParser_parse.c"
+#line 932 "NCDConfigParser_parse.c"
         break;
       default:
         break;
@@ -955,7 +993,7 @@ static void yy_syntax_error(
 #line 61 "NCDConfigParser_parse.y"
 
     parser_out->syntax_error = 1;
-#line 959 "NCDConfigParser_parse.c"
+#line 997 "NCDConfigParser_parse.c"
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 

+ 4 - 3
generated/NCDConfigParser_parse.h

@@ -5,6 +5,7 @@
 #define ROUND_OPEN                      5
 #define ROUND_CLOSE                     6
 #define SEMICOLON                       7
-#define DOT                             8
-#define STRING                          9
-#define COMMA                          10
+#define ARROW                           8
+#define DOT                             9
+#define STRING                         10
+#define COMMA                          11

+ 178 - 87
generated/NCDConfigParser_parse.out

@@ -3,8 +3,8 @@ State 0:
           interfaces ::= * PROCESS NAME CURLY_OPEN statements CURLY_CLOSE
           interfaces ::= * PROCESS NAME CURLY_OPEN statements CURLY_CLOSE interfaces
 
-                       PROCESS shift  10
-                    interfaces shift  9
+                       PROCESS shift  15
+                    interfaces shift  14
                          input accept
 
 State 1:
@@ -12,33 +12,38 @@ State 1:
           statements ::= statement_names ROUND_OPEN * statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statement_names ::= * NAME
           statement_names ::= * NAME DOT statement_names
-      (7) statement_args_maybe ::= *
+      (9) statement_args_maybe ::= *
           statement_args_maybe ::= * statement_args
           statement_args ::= * STRING
           statement_args ::= * statement_names
           statement_args ::= * STRING COMMA statement_args
           statement_args ::= * statement_names COMMA statement_args
 
-                          NAME shift  16
-                        STRING shift  17
-               statement_names shift  18
-          statement_args_maybe shift  14
-                statement_args shift  23
-                     {default} reduce 7
+                          NAME shift  24
+                        STRING shift  25
+               statement_names shift  26
+          statement_args_maybe shift  19
+                statement_args shift  32
+                     {default} reduce 9
 
 State 2:
+          statements ::= NAME ARROW statement_names ROUND_OPEN * statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= NAME ARROW statement_names ROUND_OPEN * statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statement_names ::= * NAME
           statement_names ::= * NAME DOT statement_names
+      (9) statement_args_maybe ::= *
+          statement_args_maybe ::= * statement_args
           statement_args ::= * STRING
           statement_args ::= * statement_names
           statement_args ::= * STRING COMMA statement_args
-          statement_args ::= STRING COMMA * statement_args
           statement_args ::= * statement_names COMMA statement_args
 
-                          NAME shift  16
-                        STRING shift  17
-               statement_names shift  18
-                statement_args shift  25
+                          NAME shift  24
+                        STRING shift  25
+               statement_names shift  26
+          statement_args_maybe shift  22
+                statement_args shift  32
+                     {default} reduce 9
 
 State 3:
           statement_names ::= * NAME
@@ -46,163 +51,248 @@ State 3:
           statement_args ::= * STRING
           statement_args ::= * statement_names
           statement_args ::= * STRING COMMA statement_args
+          statement_args ::= STRING COMMA * statement_args
           statement_args ::= * statement_names COMMA statement_args
-          statement_args ::= statement_names COMMA * statement_args
 
-                          NAME shift  16
-                        STRING shift  17
-               statement_names shift  18
-                statement_args shift  24
+                          NAME shift  24
+                        STRING shift  25
+               statement_names shift  26
+                statement_args shift  34
 
 State 4:
+          statement_names ::= * NAME
+          statement_names ::= * NAME DOT statement_names
+          statement_args ::= * STRING
+          statement_args ::= * statement_names
+          statement_args ::= * STRING COMMA statement_args
+          statement_args ::= * statement_names COMMA statement_args
+          statement_args ::= statement_names COMMA * statement_args
+
+                          NAME shift  24
+                        STRING shift  25
+               statement_names shift  26
+                statement_args shift  33
+
+State 5:
           interfaces ::= PROCESS NAME CURLY_OPEN * statements CURLY_CLOSE
           interfaces ::= PROCESS NAME CURLY_OPEN * statements CURLY_CLOSE interfaces
           statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
           statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statement_names ::= * NAME
           statement_names ::= * NAME DOT statement_names
 
-                          NAME shift  16
-                    statements shift  12
-               statement_names shift  13
+                          NAME shift  13
+                    statements shift  17
+               statement_names shift  18
 
-State 5:
+State 6:
           statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
       (3) statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON *
           statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON * statements
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statement_names ::= * NAME
           statement_names ::= * NAME DOT statement_names
 
-                          NAME shift  16
-                    statements shift  20
-               statement_names shift  13
+                          NAME shift  13
+                    statements shift  28
+               statement_names shift  18
                      {default} reduce 3
 
-State 6:
+State 7:
+          statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+      (5) statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON *
+          statements ::= * NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON * statements
+          statement_names ::= * NAME
+          statement_names ::= * NAME DOT statement_names
+
+                          NAME shift  13
+                    statements shift  29
+               statement_names shift  18
+                     {default} reduce 5
+
+State 8:
           interfaces ::= * PROCESS NAME CURLY_OPEN statements CURLY_CLOSE
       (1) interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE *
           interfaces ::= * PROCESS NAME CURLY_OPEN statements CURLY_CLOSE interfaces
           interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE * interfaces
 
-                       PROCESS shift  10
-                    interfaces shift  19
+                       PROCESS shift  15
+                    interfaces shift  27
                      {default} reduce 1
 
-State 7:
+State 9:
           statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE * name_maybe SEMICOLON
           statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE * name_maybe SEMICOLON statements
-     (13) name_maybe ::= *
+     (15) name_maybe ::= *
           name_maybe ::= * NAME
 
-                          NAME shift  22
-                    name_maybe shift  15
-                     {default} reduce 13
+                          NAME shift  30
+                    name_maybe shift  20
+                     {default} reduce 15
 
-State 8:
+State 10:
+          statements ::= NAME ARROW * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= NAME ARROW * statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
           statement_names ::= * NAME
           statement_names ::= * NAME DOT statement_names
-          statement_names ::= NAME DOT * statement_names
 
-                          NAME shift  16
+                          NAME shift  24
                statement_names shift  21
 
-State 9:
+State 11:
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE * name_maybe SEMICOLON
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE * name_maybe SEMICOLON statements
+     (15) name_maybe ::= *
+          name_maybe ::= * NAME
+
+                          NAME shift  30
+                    name_maybe shift  23
+                     {default} reduce 15
+
+State 12:
+          statement_names ::= * NAME
+          statement_names ::= * NAME DOT statement_names
+          statement_names ::= NAME DOT * statement_names
+
+                          NAME shift  24
+               statement_names shift  31
+
+State 13:
+          statements ::= NAME * ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= NAME * ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
+      (7) statement_names ::= NAME *
+          statement_names ::= NAME * DOT statement_names
+
+                         ARROW shift  10
+                           DOT shift  12
+                     {default} reduce 7
+
+State 14:
       (0) input ::= interfaces *
 
                              $ reduce 0
 
-State 10:
+State 15:
           interfaces ::= PROCESS * NAME CURLY_OPEN statements CURLY_CLOSE
           interfaces ::= PROCESS * NAME CURLY_OPEN statements CURLY_CLOSE interfaces
 
-                          NAME shift  11
+                          NAME shift  16
 
-State 11:
+State 16:
           interfaces ::= PROCESS NAME * CURLY_OPEN statements CURLY_CLOSE
           interfaces ::= PROCESS NAME * CURLY_OPEN statements CURLY_CLOSE interfaces
 
-                    CURLY_OPEN shift  4
+                    CURLY_OPEN shift  5
 
-State 12:
+State 17:
           interfaces ::= PROCESS NAME CURLY_OPEN statements * CURLY_CLOSE
           interfaces ::= PROCESS NAME CURLY_OPEN statements * CURLY_CLOSE interfaces
 
-                   CURLY_CLOSE shift  6
+                   CURLY_CLOSE shift  8
 
-State 13:
+State 18:
           statements ::= statement_names * ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
           statements ::= statement_names * ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
 
                     ROUND_OPEN shift  1
 
-State 14:
+State 19:
           statements ::= statement_names ROUND_OPEN statement_args_maybe * ROUND_CLOSE name_maybe SEMICOLON
           statements ::= statement_names ROUND_OPEN statement_args_maybe * ROUND_CLOSE name_maybe SEMICOLON statements
 
-                   ROUND_CLOSE shift  7
+                   ROUND_CLOSE shift  9
 
-State 15:
+State 20:
           statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe * SEMICOLON
           statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe * SEMICOLON statements
 
-                     SEMICOLON shift  5
+                     SEMICOLON shift  6
 
-State 16:
-      (5) statement_names ::= NAME *
+State 21:
+          statements ::= NAME ARROW statement_names * ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= NAME ARROW statement_names * ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements
+
+                    ROUND_OPEN shift  2
+
+State 22:
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe * ROUND_CLOSE name_maybe SEMICOLON
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe * ROUND_CLOSE name_maybe SEMICOLON statements
+
+                   ROUND_CLOSE shift  11
+
+State 23:
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe * SEMICOLON
+          statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe * SEMICOLON statements
+
+                     SEMICOLON shift  7
+
+State 24:
+      (7) statement_names ::= NAME *
           statement_names ::= NAME * DOT statement_names
 
-                           DOT shift  8
-                     {default} reduce 5
+                           DOT shift  12
+                     {default} reduce 7
 
-State 17:
-      (9) statement_args ::= STRING *
+State 25:
+     (11) statement_args ::= STRING *
           statement_args ::= STRING * COMMA statement_args
 
-                         COMMA shift  2
-                     {default} reduce 9
+                         COMMA shift  3
+                     {default} reduce 11
 
-State 18:
-     (10) statement_args ::= statement_names *
+State 26:
+     (12) statement_args ::= statement_names *
           statement_args ::= statement_names * COMMA statement_args
 
-                         COMMA shift  3
-                     {default} reduce 10
+                         COMMA shift  4
+                     {default} reduce 12
 
-State 19:
+State 27:
       (2) interfaces ::= PROCESS NAME CURLY_OPEN statements CURLY_CLOSE interfaces *
 
                      {default} reduce 2
 
-State 20:
+State 28:
       (4) statements ::= statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements *
 
                      {default} reduce 4
 
-State 21:
-      (6) statement_names ::= NAME DOT statement_names *
+State 29:
+      (6) statements ::= NAME ARROW statement_names ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON statements *
 
                      {default} reduce 6
 
-State 22:
-     (14) name_maybe ::= NAME *
+State 30:
+     (16) name_maybe ::= NAME *
 
-                     {default} reduce 14
+                     {default} reduce 16
 
-State 23:
-      (8) statement_args_maybe ::= statement_args *
+State 31:
+      (8) statement_names ::= NAME DOT statement_names *
 
                      {default} reduce 8
 
-State 24:
-     (12) statement_args ::= statement_names COMMA statement_args *
+State 32:
+     (10) statement_args_maybe ::= statement_args *
 
-                     {default} reduce 12
+                     {default} reduce 10
 
-State 25:
-     (11) statement_args ::= STRING COMMA statement_args *
+State 33:
+     (14) statement_args ::= statement_names COMMA statement_args *
 
-                     {default} reduce 11
+                     {default} reduce 14
+
+State 34:
+     (13) statement_args ::= STRING COMMA statement_args *
+
+                     {default} reduce 13
 
 ----------------------------------------------------
 Symbols:
@@ -214,14 +304,15 @@ Symbols:
     5: ROUND_OPEN
     6: ROUND_CLOSE
     7: SEMICOLON
-    8: DOT
-    9: STRING
-   10: COMMA
-   11: error:
-   12: interfaces: PROCESS
-   13: statements: NAME
-   14: statement_names: NAME
-   15: statement_args_maybe: <lambda> NAME STRING
-   16: statement_args: NAME STRING
-   17: name_maybe: <lambda> NAME
-   18: input: PROCESS
+    8: ARROW
+    9: DOT
+   10: STRING
+   11: COMMA
+   12: error:
+   13: interfaces: PROCESS
+   14: statements: NAME
+   15: statement_names: NAME
+   16: statement_args_maybe: <lambda> NAME STRING
+   17: statement_args: NAME STRING
+   18: name_maybe: <lambda> NAME
+   19: input: PROCESS

+ 16 - 2
generated/NCDConfigParser_parse.y

@@ -92,14 +92,28 @@ interfaces(R) ::= PROCESS NAME(A) CURLY_OPEN statements(B) CURLY_CLOSE interface
 }
 
 statements(R) ::= statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON. {
-    R = NCDConfig_make_statements(A, B, C, NULL);
+    R = NCDConfig_make_statements(NULL, A, B, C, NULL);
     if (!R) {
         parser_out->out_of_memory = 1;
     }
 }
 
 statements(R) ::= statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON statements(N). {
-    R = NCDConfig_make_statements(A, B, C, N);
+    R = NCDConfig_make_statements(NULL, A, B, C, N);
+    if (!R) {
+        parser_out->out_of_memory = 1;
+    }
+}
+
+statements(R) ::= NAME(M) ARROW statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON. {
+    R = NCDConfig_make_statements(M, A, B, C, NULL);
+    if (!R) {
+        parser_out->out_of_memory = 1;
+    }
+}
+
+statements(R) ::= NAME(M) ARROW statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON statements(N). {
+    R = NCDConfig_make_statements(M, A, B, C, N);
     if (!R) {
         parser_out->out_of_memory = 1;
     }

+ 2 - 1
ncd/NCDModule.c

@@ -88,11 +88,12 @@ static void clean_job_handler (NCDModuleInst *n)
     }
 }
 
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, NCDModuleInst *method_object, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
                          NCDModule_handler_event handler_event, NCDModule_handler_getvar handler_getvar, void *user)
 {
     // init arguments
     n->m = m;
+    n->method_object = method_object;
     n->args = args;
     n->logprefix = logprefix;
     n->reactor = reactor;

+ 3 - 2
ncd/NCDModule.h

@@ -47,8 +47,9 @@ struct NCDModuleInitParams {
     BProcessManager *manager;
 };
 
-typedef struct {
+typedef struct NCDModuleInst_s {
     const struct NCDModule *m;
+    struct NCDModuleInst_s *method_object;
     NCDValue *args;
     const char *logprefix;
     BReactor *reactor;
@@ -66,7 +67,7 @@ typedef struct {
     DebugObject d_obj;
 } NCDModuleInst;
 
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, NCDModuleInst *method_object, NCDValue *args, const char *logprefix, BReactor *reactor, BProcessManager *manager,
                          NCDModule_handler_event handler_event, NCDModule_handler_getvar handler_getvar, void *user);
 void NCDModuleInst_Free (NCDModuleInst *n);
 void NCDModuleInst_Event (NCDModuleInst *n, int event);

+ 93 - 31
ncd/ncd.c

@@ -31,6 +31,7 @@
 #include <misc/offset.h>
 #include <misc/read_file.h>
 #include <misc/balloc.h>
+#include <misc/concat_strings.h>
 #include <structure/LinkedList2.h>
 #include <system/BLog.h>
 #include <system/BReactor.h>
@@ -58,7 +59,8 @@
 #define SSTATE_FORGOTTEN 4
 
 struct statement {
-    const struct NCDModule *module;
+    char *object_name;
+    char *method_name;
     struct argument_elem *first_arg;
     char *name;
 };
@@ -92,6 +94,7 @@ struct process_statement {
     size_t i;
     struct statement s;
     int state;
+    char *type;
     int have_error;
     btime_t error_until;
     NCDModuleInst inst;
@@ -147,6 +150,7 @@ static void process_schedule_work (struct process *p);
 static void process_work_job_handler (struct process *p);
 static void process_advance_job_handler (struct process *p);
 static void process_wait_timer_handler (struct process *p);
+static struct process_statement * process_find_statement (struct process *p, size_t pos, const char *name);
 static int process_resolve_variable (struct process *p, size_t pos, const char *modname, const char *varname, NCDValue *out);
 static void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...);
 static void process_statement_set_error (struct process_statement *ps);
@@ -520,22 +524,21 @@ const struct NCDModule * find_module (const char *name)
 
 int statement_init (struct statement *s, struct NCDConfig_statements *conf)
 {
-    // find module
-    char *module_name = NCDConfig_concat_strings(conf->names);
-    if (!module_name) {
-        BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
-        goto fail0;
-    }
-    const struct NCDModule *m = find_module(module_name);
-    if (!m) {
-        BLog(BLOG_ERROR, "no module for statement %s", module_name);
-        free(module_name);
-        goto fail0;
+    // set object name
+    if (!conf->objname) {
+        s->object_name = NULL;
+    } else {
+        if (!(s->object_name = strdup(conf->objname))) {
+            BLog(BLOG_ERROR, "strdup failed");
+            goto fail0;
+        }
     }
-    free(module_name);
     
-    // set module
-    s->module = m;
+    // set method name
+    if (!(s->method_name = NCDConfig_concat_strings(conf->names))) {
+        BLog(BLOG_ERROR, "NCDConfig_concat_strings failed");
+        goto fail1;
+    }
     
     // init arguments
     s->first_arg = NULL;
@@ -587,7 +590,7 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
     loop_fail1:
         free(e);
     loop_fail0:
-        goto fail1;
+        goto fail2;
     }
     
     // init name
@@ -602,8 +605,11 @@ int statement_init (struct statement *s, struct NCDConfig_statements *conf)
     
     return 1;
     
-fail1:
+fail2:
     statement_free_args(s);
+    free(s->method_name);
+fail1:
+    free(s->object_name);
 fail0:
     return 0;
 }
@@ -615,6 +621,12 @@ void statement_free (struct statement *s)
     
     // free arguments
     statement_free_args(s);
+    
+    // free method name
+    free(s->method_name);
+    
+    // free object name
+    free(s->object_name);
 }
 
 void statement_free_args (struct statement *s)
@@ -923,6 +935,42 @@ void process_advance_job_handler (struct process *p)
     
     process_statement_log(ps, BLOG_INFO, "initializing");
     
+    NCDModuleInst *method_object = NULL;
+    
+    // construct type
+    if (!ps->s.object_name) {
+        // this is a function_call(); type is "function_call"
+        if (!(ps->type = strdup(ps->s.method_name))) {
+            process_statement_log(ps, BLOG_ERROR, "strdup failed");
+            goto fail0;
+        }
+    } else {
+        // this is an object->method_call(); type is "typeof(object)::method_call"
+        
+        // find referred-to statement
+        struct process_statement *obj_ps = process_find_statement(p, p->ap, ps->s.object_name);
+        if (!obj_ps) {
+            process_statement_log(ps, BLOG_ERROR, "failed to find object for method call: %s", ps->s.object_name);
+            goto fail0;
+        }
+        ASSERT(obj_ps->state == SSTATE_ADULT)
+        
+        // build type string
+        if (!(ps->type = concat_strings(3, obj_ps->type, "::", ps->s.method_name))) {
+            process_statement_log(ps, BLOG_ERROR, "concat_strings failed");
+            goto fail0;
+        }
+        
+        method_object = &obj_ps->inst;
+    }
+    
+    // find module to instantiate
+    const struct NCDModule *module = find_module(ps->type);
+    if (!module) {
+        process_statement_log(ps, BLOG_ERROR, "failed to find module: %s", ps->type);
+        goto fail1;
+    }
+    
     // init arguments list
     NCDValue_InitList(&ps->inst_args);
     
@@ -934,12 +982,12 @@ void process_advance_job_handler (struct process *p)
         if (arg->is_var) {
             if (!process_resolve_variable(p, p->ap, arg->var.modname, arg->var.varname, &v)) {
                 process_statement_log(ps, BLOG_ERROR, "failed to resolve variable");
-                goto fail1;
+                goto fail2;
             }
         } else {
             if (!NCDValue_InitCopy(&v, &arg->val)) {
                 process_statement_log(ps, BLOG_ERROR, "NCDValue_InitCopy failed");
-                goto fail1;
+                goto fail2;
             }
         }
         
@@ -947,7 +995,7 @@ void process_advance_job_handler (struct process *p)
         if (!NCDValue_ListAppend(&ps->inst_args, v)) {
             process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
             NCDValue_Free(&v);
-            goto fail1;
+            goto fail2;
         }
         
         arg = arg->next_arg;
@@ -958,7 +1006,7 @@ void process_advance_job_handler (struct process *p)
     
     // initialize module instance
     NCDModuleInst_Init(
-        &ps->inst, ps->s.module, &ps->inst_args, ps->logprefix, &ss, &manager,
+        &ps->inst, module, method_object, &ps->inst_args, ps->logprefix, &ss, &manager,
         (NCDModule_handler_event)process_statement_instance_handler_event,
         (NCDModule_handler_getvar)process_statement_instance_handler_getvar,
         ps
@@ -976,9 +1024,11 @@ void process_advance_job_handler (struct process *p)
     process_assert_pointers(p);
     return;
     
-fail1:
+fail2:
     NCDValue_Free(&ps->inst_args);
-    
+fail1:
+    free(ps->type);
+fail0:
     // mark error
     process_statement_set_error(ps);
     
@@ -1006,23 +1056,32 @@ void process_wait_timer_handler (struct process *p)
     BPending_Set(&p->work_job);
 }
 
-int process_resolve_variable (struct process *p, size_t pos, const char *modname, const char *varname, NCDValue *out)
+struct process_statement * process_find_statement (struct process *p, size_t pos, const char *name)
 {
     process_assert_pointers(p);
     ASSERT(pos >= 0)
     ASSERT(pos <= process_rap(p))
-    ASSERT(modname)
-    ASSERT(varname)
     
-    // find referred-to statement
-    struct process_statement *rps = NULL;
     for (size_t i = pos; i > 0; i--) {
         struct process_statement *ps = &p->statements[i - 1];
-        if (ps->s.name && !strcmp(ps->s.name, modname)) {
-            rps = ps;
-            break;
+        if (ps->s.name && !strcmp(ps->s.name, name)) {
+            return ps;
         }
     }
+    
+    return NULL;
+}
+
+int process_resolve_variable (struct process *p, size_t pos, const char *modname, const char *varname, NCDValue *out)
+{
+    process_assert_pointers(p);
+    ASSERT(pos >= 0)
+    ASSERT(pos <= process_rap(p))
+    ASSERT(modname)
+    ASSERT(varname)
+    
+    // find referred-to statement
+    struct process_statement *rps = process_find_statement(p, pos, modname);
     if (!rps) {
         process_log(p, BLOG_ERROR, "unknown statement name in variable: %s.%s", modname, varname);
         return 0;
@@ -1104,6 +1163,9 @@ void process_statement_instance_handler_event (struct process_statement *ps, int
             // free instance arguments
             NCDValue_Free(&ps->inst_args);
             
+            // free type
+            free(ps->type);
+            
             // set state FORGOTTEN
             ps->state = SSTATE_FORGOTTEN;
             

+ 3 - 1
ncdconfig/NCDConfig.c

@@ -47,6 +47,7 @@ void NCDConfig_free_statements (struct NCDConfig_statements *v)
         return;
     }
     
+    free(v->objname);
     NCDConfig_free_strings(v->names);
     NCDConfig_free_arguments(v->args);
     free(v->name);
@@ -113,13 +114,14 @@ fail:
     return NULL;
 }
 
-struct NCDConfig_statements * NCDConfig_make_statements (struct NCDConfig_strings *names, struct NCDConfig_arguments *args, char *name, struct NCDConfig_statements *next)
+struct NCDConfig_statements * NCDConfig_make_statements (char *objname, struct NCDConfig_strings *names, struct NCDConfig_arguments *args, char *name, struct NCDConfig_statements *next)
 {
     struct NCDConfig_statements *v = malloc(sizeof(*v));
     if (!v) {
         goto fail;
     }
     
+    v->objname = objname;
     v->names = names;
     v->args = args;
     v->name = name;

+ 2 - 1
ncdconfig/NCDConfig.h

@@ -35,6 +35,7 @@ struct NCDConfig_interfaces {
 };
 
 struct NCDConfig_statements {
+    char *objname;
     struct NCDConfig_strings *names;
     struct NCDConfig_arguments *args;
     char *name;
@@ -63,7 +64,7 @@ void NCDConfig_free_statements (struct NCDConfig_statements *v);
 void NCDConfig_free_arguments (struct NCDConfig_arguments *v);
 void NCDConfig_free_strings (struct NCDConfig_strings *v);
 struct NCDConfig_interfaces * NCDConfig_make_interfaces (char *name, struct NCDConfig_statements *statements, int have_next, struct NCDConfig_interfaces *next);
-struct NCDConfig_statements * NCDConfig_make_statements (struct NCDConfig_strings *names, struct NCDConfig_arguments *args, char *name, struct NCDConfig_statements *next);
+struct NCDConfig_statements * NCDConfig_make_statements (char *objname, struct NCDConfig_strings *names, struct NCDConfig_arguments *args, char *name, struct NCDConfig_statements *next);
 struct NCDConfig_arguments * NCDConfig_make_arguments_string (char *str, struct NCDConfig_arguments *next);
 struct NCDConfig_arguments * NCDConfig_make_arguments_var (struct NCDConfig_strings *var, struct NCDConfig_arguments *next);
 struct NCDConfig_strings * NCDConfig_make_strings (char *value, int have_next, struct NCDConfig_strings *next);

+ 4 - 0
ncdconfig/NCDConfigParser.c

@@ -84,6 +84,10 @@ static int tokenizer_output (void *user, int token, char *value, size_t position
             Parse(state->parser, COMMA, NULL, &state->out);
         } break;
         
+        case NCD_TOKEN_ARROW: {
+            Parse(state->parser, ARROW, NULL, &state->out);
+        } break;
+        
         case NCD_TOKEN_PROCESS: {
             Parse(state->parser, PROCESS, NULL, &state->out);
         } break;

+ 16 - 2
ncdconfig/NCDConfigParser_parse.y

@@ -92,14 +92,28 @@ interfaces(R) ::= PROCESS NAME(A) CURLY_OPEN statements(B) CURLY_CLOSE interface
 }
 
 statements(R) ::= statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON. {
-    R = NCDConfig_make_statements(A, B, C, NULL);
+    R = NCDConfig_make_statements(NULL, A, B, C, NULL);
     if (!R) {
         parser_out->out_of_memory = 1;
     }
 }
 
 statements(R) ::= statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON statements(N). {
-    R = NCDConfig_make_statements(A, B, C, N);
+    R = NCDConfig_make_statements(NULL, A, B, C, N);
+    if (!R) {
+        parser_out->out_of_memory = 1;
+    }
+}
+
+statements(R) ::= NAME(M) ARROW statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON. {
+    R = NCDConfig_make_statements(M, A, B, C, NULL);
+    if (!R) {
+        parser_out->out_of_memory = 1;
+    }
+}
+
+statements(R) ::= NAME(M) ARROW statement_names(A) ROUND_OPEN statement_args_maybe(B) ROUND_CLOSE name_maybe(C) SEMICOLON statements(N). {
+    R = NCDConfig_make_statements(M, A, B, C, N);
     if (!R) {
         parser_out->out_of_memory = 1;
     }

+ 3 - 0
ncdconfig/NCDConfigTokenizer.c

@@ -87,6 +87,9 @@ void NCDConfigTokenizer_Tokenize (char *str, size_t left, NCDConfigTokenizer_out
         else if (l = data_begins_with(str, left, ",")) {
             token = NCD_TOKEN_COMMA;
         }
+        else if (l = data_begins_with(str, left, "->")) {
+            token = NCD_TOKEN_ARROW;
+        }
         else if (is_name_first_char(*str)) {
             l = 1;
             while (l < left) {

+ 1 - 0
ncdconfig/NCDConfigTokenizer.h

@@ -35,6 +35,7 @@
 #define NCD_TOKEN_PROCESS 8
 #define NCD_TOKEN_NAME 9
 #define NCD_TOKEN_STRING 10
+#define NCD_TOKEN_ARROW 11
 
 #define NCD_MAX_SIZE 128