chiark / gitweb /
@@@ major overhaul, new primitives
[mLib] / utils / t / control-test.c
1 /* -*-c-*-
2  *
3  * Test the control-flow metaprogramming macros
4  *
5  * (c) 2022 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "control.h"
34
35 /*----- Main code ---------------------------------------------------------*/
36
37 static int step = 0;
38 static int rc = 0;
39
40 #define STEP(s) check_step(s, __FILE__ ": " STR(__LINE__))
41 #define MISSTEP STEP(-1)
42 static void check_step(int s, const char *where)
43 {
44   if (step != s) {
45     fprintf(stderr, "misstep at %s: expected %d but found %d\n",
46             where, step, s);
47     rc = 2;
48   }
49   step++;
50 }
51
52 #define LASTSTEP(s) laststep(s, __FILE__ ": " STR(__LINE__))
53 static void laststep(int s, const char *where)
54   { check_step(s, where); step = 0; }
55
56 #define FORELSE(head)                                                   \
57                         MC_GOTO(top)                                    \
58   MC_LABEL(out)         MC_ACT({ ; })                                   \
59   MC_LABEL(top)         ALLOWELSE(els)                                  \
60                         AFTER(outer, { GOELSE(els); })                  \
61                         for (head)                                      \
62                           WRAP(inner, { ; },                            \
63                                       { ; },                            \
64                                       { MC_GOTO(out); })
65
66 #define FOR_FIZZBUZZ(var, base, limit)                                  \
67                         MC_GOTO(top)                                    \
68   MC_LABEL(out)         MC_ACT({ ; })                                   \
69   MC_LABEL(top)         DECL(bounds,                                    \
70                              int _i = base COMMA _limit = limit)        \
71                         for (; _i < _limit; _i++)                       \
72                           DECL(buf, char _buf[24])                      \
73                           DECL(var, const char *var)                    \
74                           WRAP(wrap, {                                  \
75                             switch (_i%15) {                            \
76                               case 0:                                   \
77                                 var = "fizzbuzz";                       \
78                                 break;                                  \
79                               case 3: case 6: case 9: case 12:          \
80                                 var = "fizz";                           \
81                                 break;                                  \
82                               case 5: case 10:                          \
83                                 var = "buzz";                           \
84                                 break;                                  \
85                               default:                                  \
86                                 sprintf(_buf, "%d", _i); var = _buf;    \
87                                 break;                                  \
88                             }                                           \
89                           },                                            \
90                           { ; },                                        \
91                           { MC_GOTO(out); })
92
93 int main(void)
94 {
95   int i;
96
97   BEFORE(before0, { STEP(0); }) STEP(1);
98   AFTER(after0, { STEP(3); }) STEP(2);
99   LASTSTEP(4);
100
101   WRAP(wrap0, { STEP(0); }, { STEP(2); }, { MISSTEP; }) STEP(1);
102   WRAP(wrap1, { STEP(3); }, { MISSTEP; }, { STEP(5); }) { STEP(4); break; }
103   LASTSTEP(6);
104
105   STEP(0);
106   for (;;) {
107     AFTER(after1, { STEP(2); break; }) STEP(1);
108     MISSTEP; break;
109   }
110   LASTSTEP(3);
111
112   FORELSE (i = 0; i < 10; i++) {
113     STEP(i);
114     if (i == 7) break;
115   } else
116     MISSTEP;
117   LASTSTEP(8);
118
119   FORELSE (i = 0; i < 10; i++) {
120     STEP(i);
121     if (i == 12) break;
122   } else
123     STEP(10);
124   LASTSTEP(11);
125
126 #define TEST                                                            \
127                         MC_ACT({ STEP(0); MC_GOTO(in_plain); })         \
128   MC_LABEL(done_plain)  MC_ACT({ STEP(5); GOELSE(elsie); })             \
129   MC_LABEL(in_plain)    WRAP(outer_wrap, { STEP(1); },                  \
130                                          { STEP(7); },                  \
131                                          { MISSTEP; })                  \
132                         ALLOWELSE(elsie)                                \
133                           WRAP(inner_wrap, { STEP(2); },                \
134                                            { STEP(4);                   \
135                                              MC_GOTO(done_plain); },    \
136                                            { MISSTEP; })                \
137                           STEP(3);                                      \
138                         else                                            \
139                           STEP(6);                                      \
140                         LASTSTEP(8);
141   TEST
142 #undef TEST
143
144 #if __STDC_VERSION__ >= 199901 || defined(__cplusplus)
145   STEP(0);
146   DECL(decl0, int j = 1) STEP(j);
147   LASTSTEP(2);
148 #endif
149
150   FOR_FIZZBUZZ(fb, 19, 32) printf("%s\n", fb);
151
152   return (rc);
153 }
154
155 /*----- That's all, folks -------------------------------------------------*/