Rune - Change regsave burden for syscalls
[rune.git] / librune / stmt.c
1 /*
2  * STMT.C
3  *
4  * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved.  See the  
5  *    COPYRIGHT file at the base of the distribution.
6  */
7
8 #include "defs.h"
9
10 static Stmt *
11 allocStmt(Stmt *par, int type)
12 {
13         Stmt *st = zalloc(sizeof(Stmt));
14
15         st->st_Op = type;
16         st->st_Run = RunUnresolvedStmt;
17         st->st_Gen = GenUnresolvedStmt;
18         RUNE_INIT(&st->st_List);
19         if (par != NULL) {
20                 st->st_Parent = par;
21                 st->st_Run = par->st_Run;
22                 RUNE_INSERT_TAIL(&par->st_List, st, st_Node);
23         }
24         return(st);
25 }
26
27 Stmt *
28 PushStmt(Parse *p, Stmt **pst, int type, int flags)
29 {
30         Stmt *st;
31         sg_type_t sgtype;
32
33         switch(type) {
34         case ST_Proc:
35                 sgtype = SG_PROCTOP;
36                 break;
37         case ST_Class:
38                 sgtype = SG_CLASS;
39                 break;
40         case ST_Module:
41                 sgtype = SG_MODULE;
42                 break;
43         default:
44                 sgtype = SG_EXEC;
45                 break;
46         }
47
48         st = allocStmt(p->p_CurStmt, type);
49         st->st_Flags |= flags;
50         LexInitRef(&st->st_LexRef, &p->p_Token);
51         if (pst)
52                 *pst = st;
53         p->p_CurStmt = st;
54         if (st->st_Flags & STF_SEMANTIC) {
55                 SemGroup *sg = AllocSemGroup(sgtype, p, p->p_CurSemGroup, st);
56                 p->p_CurSemGroup = sg;
57                 if (st->st_Flags & STF_SEMTOP) {
58                         sg->sg_Flags |= SGF_SEMTOP;
59                         if (st->st_Flags & STF_NESTED) {
60                                 sg->sg_NestLevel =
61                                         sg->sg_Parent->sg_NestLevel + 1;
62                                 sg->sg_Flags |= SGF_NESTED;
63                         } else {
64                                 sg->sg_NestLevel = 0;
65                         }
66                         AdjustNestSize(sg, sg->sg_NestLevel + 1);
67                 }
68         }
69         st->st_MyGroup = p->p_CurSemGroup;
70
71         return(st);
72 }
73
74 void *
75 PopStmt(Parse *p, Stmt *st)
76 {
77         dassert_stmt(st, p->p_CurStmt == st);
78         p->p_CurStmt = st->st_Parent;
79
80         if (st->st_Flags & STF_SEMANTIC) {
81                 dassert_stmt(st, p->p_CurSemGroup == st->st_MyGroup);
82                 p->p_CurSemGroup = st->st_MyGroup->sg_Parent;
83         }
84         return(p->p_CurStmt);
85 }
86
87 Stmt *
88 DupStmt(SemGroup *sg, Stmt *par, Stmt *sst)
89 {
90         Stmt *st;
91         Stmt *scan;
92         Declaration *d;
93
94         if (sst == NULL)
95                 return(NULL);
96
97         st = allocStmt(par, sst->st_Op);
98
99         LexDupRef(&sst->st_LexRef, &st->st_LexRef);
100         st->st_Flags |= sst->st_Flags;
101         st->st_Flags &= ~(STF_RESOLVING | STF_RESOLVED | STF_TMPRESOLVED |
102                           STF_ALIGNRESOLVED);
103         if (st->st_Flags & STF_SEMANTIC) {
104                 st->st_MyGroup = sg = DupSemGroup(sg, st, sst->st_MyGroup, 0);
105         } else {
106                 st->st_MyGroup = sg;
107         }
108         switch(sst->st_Op) {
109         case ST_Import:
110                 /*
111                  * An import statement is never dup'd
112                  */
113 #if 0
114                 st->st_ImportStmt.es_Parser = sst->st_ImportStmt.es_Parser;
115                 st->st_ImportStmt.es_Path =
116                         StrTableDup(sst->st_ImportStmt.es_Path);
117                 st->st_ImportStmt.es_AsId =
118                         StrTableDup(sst->st_ImportStmt.es_AsId);
119 #endif
120                 dassert_stmt(sst, 0);
121         case ST_Class:
122                 /*
123                  * note: declaration is placed in parent SemGroup
124                  */
125                 dassert_stmt(st, 0);
126                 break;
127         case ST_Typedef:
128                 st->st_TypedefStmt.es_Decl =
129                         DupDeclaration(sg, sst->st_TypedefStmt.es_Decl);
130                 break;
131         case ST_Decl:
132                 /*
133                  * YYY duplicate multiple declarations
134                  *
135                  * Procedure definitions will have sub-statements
136                  * (under st->st_List), but we do not duplicate it here.
137                  */
138                 st->st_DeclStmt.es_Decl =
139                         DupDeclaration(sg, sst->st_DeclStmt.es_Decl);
140                 st->st_DeclStmt.es_Decl->d_Stmt = st;
141                 st->st_DeclStmt.es_DeclCount = 1;
142                 st->st_DeclStmt.es_Scope = sst->st_DeclStmt.es_Scope;
143                 d = sst->st_DeclStmt.es_Decl;
144                 while (st->st_DeclStmt.es_DeclCount <
145                        sst->st_DeclStmt.es_DeclCount)
146                 {
147                         Declaration *nd;
148
149                         d = RUNE_NEXT(d, d_Node);
150                         dassert_stmt(st, d->d_Stmt == sst);
151                         nd = DupDeclaration(sg, d);
152                         nd->d_Stmt = st;
153                         ++st->st_DeclStmt.es_DeclCount;
154                 }
155 #if 0
156                 d = st->st_DeclStmt.es_Decl;
157                 if (d->d_Op == DOP_PROC) {
158                         if (sg->sg_Stmt->st_Op != ST_Class) {
159                                 scan = getHead(&sst->st_List);
160                                 dassert_stmt(sst,
161                                              scan && scan->st_Op == ST_Proc);
162                                 dassert_stmt(sst,
163                                              getSucc(&sst->st_List,
164                                                      &scan->st_Node) == NULL);
165                                 /* DupStmt(sg, st, scan);*/
166                                 d->d_ProcDecl.ed_OrigBody = scan;
167                         }
168                 } else {
169                         dassert_stmt(st, listIsEmpty(&st->st_List));
170                 }
171 #endif
172                 break;
173         case ST_Proc:
174                 /*
175                  * Procedure bodies are usually only duplicated from
176                  * resolveDecl() on-demand (see ST_Decl case above).
177                  * Otherwise we would have a billion copies of a procedure
178                  * due to subclassing, so this case does not normally occur
179                  * until the actual procedure is referenced.
180                  *
181                  * Also note that the resolution on demand will change the
182                  * ordering of the statements within its parent statement
183                  * (typically a Class statement).
184                  *
185                  * If the procedure was inlined we must copy the
186                  * already-resolved es_Decl and es_Scope, if not inlined
187                  * the resolver will [re]calculate it.
188                  */
189                 if (sst->st_Flags & STF_INLINED_PROC) {
190                         st->st_ProcStmt.es_Decl = sst->st_ProcStmt.es_Decl;
191                         st->st_ProcStmt.es_Scope = sst->st_ProcStmt.es_Scope;
192                 }
193                 /* fall through */
194         case ST_Block:
195                 if (sst->st_Op == ST_Block && sst->st_BlockStmt.es_BlockId) {
196                         st->st_BlockStmt.es_BlockId =
197                                 StrTableDup(sst->st_BlockStmt.es_BlockId);
198                 }
199                 RUNE_FOREACH(scan, &sst->st_List, st_Node) {
200                         DupStmt(sg, st, scan);
201                 }
202                 break;
203         case ST_Nop:
204                 break;
205         case ST_Loop:
206                 st->st_LoopStmt.es_Init =
207                         DupStmt(sg, st, sst->st_LoopStmt.es_Init);
208                 st->st_LoopStmt.es_BCond =
209                         SetDupExp(sg, sst->st_LoopStmt.es_BCond);
210                 st->st_LoopStmt.es_ACond =
211                         SetDupExp(sg, sst->st_LoopStmt.es_ACond);
212                 st->st_LoopStmt.es_AExp =
213                         SetDupExp(sg, sst->st_LoopStmt.es_AExp);
214                 st->st_LoopStmt.es_Body =
215                         DupStmt(sg, st, sst->st_LoopStmt.es_Body);
216                 break;
217         case ST_BreakCont:
218                 st->st_BreakStmt.es_IsCont = sst->st_BreakStmt.es_IsCont;
219                 st->st_BreakStmt.es_Count = sst->st_BreakStmt.es_Count;
220                 st->st_BreakStmt.es_StmtType = sst->st_BreakStmt.es_StmtType;
221                 if (sst->st_BreakStmt.es_BlockId) {
222                         st->st_BreakStmt.es_BlockId =
223                                 StrTableDup(sst->st_BreakStmt.es_BlockId);
224                 }
225                 break;
226         case ST_Bad:
227                 break;
228         case ST_IfElse:
229                 st->st_IfStmt.es_Exp =
230                         SetDupExp(sg, sst->st_IfStmt.es_Exp);
231                 st->st_IfStmt.es_TrueStmt =
232                         DupStmt(sg, st, sst->st_IfStmt.es_TrueStmt);
233                 st->st_IfStmt.es_FalseStmt =
234                         DupStmt(sg, st, sst->st_IfStmt.es_FalseStmt);
235                 break;
236         case ST_Return:
237                 st->st_RetStmt.es_Count = sst->st_RetStmt.es_Count;
238                 st->st_RetStmt.es_Exp = SetDupExp(sg, sst->st_RetStmt.es_Exp);
239                 break;
240         case ST_Result:
241                 st->st_ResStmt.es_Count = sst->st_ResStmt.es_Count;
242                 st->st_ResStmt.es_Exp = SetDupExp(sg, sst->st_ResStmt.es_Exp);
243                 break;
244         case ST_Switch:
245                 st->st_SwStmt.es_Exp = SetDupExp(sg, sst->st_SwStmt.es_Exp);
246                 RUNE_FOREACH(scan, &sst->st_List, st_Node) {
247                         dassert_stmt(scan, scan->st_Op == ST_Case);
248                         if (scan->st_CaseStmt.es_Exp == NULL) {
249                                 st->st_SwStmt.es_Default =
250                                         DupStmt(sg, st, scan);
251                         } else {
252                                 DupStmt(sg, st, scan);
253                         }
254                 }
255                 break;
256         case ST_Case:
257                 st->st_CaseStmt.es_Exp = SetDupExp(sg, sst->st_CaseStmt.es_Exp);
258                 RUNE_FOREACH(scan, &sst->st_List, st_Node) {
259                         DupStmt(sg, st, scan);
260                 }
261                 break;
262         case ST_ThreadSched:
263                 st->st_ThreadSchedStmt.es_Mode =
264                         sst->st_ThreadSchedStmt.es_Mode;
265                 break;
266         case ST_Exp:
267                 st->st_ExpStmt.es_Exp = SetDupExp(sg, sst->st_ExpStmt.es_Exp);
268                 break;
269         default:
270                 dassert_stmt(sst, 0);
271         }
272         return(st);
273 }
274
275 void
276 FreeStmt(Stmt *st)
277 {
278         dassert_stmt(st, st->st_Parent == NULL);
279         if (st != NULL) {
280                 Stmt *st2;
281                 while ((st2 = RUNE_FIRST(&st->st_List)) != NULL) {
282                         RUNE_REMOVE(&st->st_List, st2, st_Node);
283                         st2->st_Parent = NULL;
284                         FreeStmt(st2);
285                 }
286         }
287         zfree(st, sizeof(Stmt));
288 }
289
290 /*
291  * BuildRootImportStmt()
292  *
293  *      Note that st_LexRef will be set by ParseModule().  There is no
294  *      SemGroup for the fake root import statement.  The real SemGroup
295  *      starts at the ST_Module that will be generated under the import
296  *      statement.
297  *
298  *      If executed with insufficient path information to identify the
299  *      directory, attempt to locate the directory via the $PATH env.
300  */
301 Stmt *
302 BuildRootImportStmt(const char *path)
303 {
304         Stmt *st = allocStmt(NULL, ST_Import);
305         const char *epath;
306
307         if ((epath = strrchr(path, '/')) != NULL) {
308                 ++epath;
309                 safe_asprintf(&st->st_ImportStmt.es_Path, "%*.*s",
310                               epath - path, epath - path, path);
311                 st->st_ImportStmt.es_File = safe_strdup(epath);
312         } else {
313                 st->st_ImportStmt.es_Path = safe_strdup("");
314                 st->st_ImportStmt.es_File = safe_strdup(path);
315         }
316 #if 0
317         st->st_Flags = STF_SEMANTIC|STF_SEMTOP|STF_FORWARD;
318         st->st_MyGroup = AllocSemGroup(XXX, NULL, NULL, st);
319 #endif
320         return(st);
321 }
322
323 void
324 StmtPrintError(Stmt *st, int type)
325 {
326         LexPrintRef(&st->st_LexRef, type);
327 }