Mercurial > repo
comparison src/ploki/transmogrify.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4222:b0f3e267bb1e | 4223:ac0403686959 |
---|---|
1 #include "config.h" | |
2 #include "Str.h" | |
3 #include "expr.h" | |
4 #include "kork.h" | |
5 #include "main_label.h" | |
6 #include "op.h" | |
7 #include "text.h" | |
8 #include "transmogrify.h" | |
9 #include "val.h" | |
10 #include "venus.h" | |
11 #include "xmalloc.h" | |
12 #include "zz.h" | |
13 | |
14 #include <ctype.h> | |
15 #include <math.h> | |
16 #include <stddef.h> | |
17 #include <assert.h> | |
18 | |
19 ATTR_PURE | |
20 static int liter_expr(const struct expr *const e) { | |
21 return | |
22 e->type == literE || | |
23 ( | |
24 e->type == symbolE && | |
25 e->op != S_ARG && e->op != S_ARGC && e->op != S_ARGV && | |
26 e->op != S_ERR && e->op != S_MATCH && e->op != S_RAND && | |
27 e->op != S_RESULT | |
28 ) || | |
29 ( | |
30 e->type == listE && | |
31 (e->right == NULL || liter_expr(e->right)) && | |
32 e->left.expr == NULL | |
33 ) | |
34 ; | |
35 } | |
36 | |
37 #define const_unop(op) \ | |
38 ( \ | |
39 (op) == F_ABS || (op) == F_ACOS || (op) == F_ASIN || \ | |
40 (op) == F_ATAN || (op) == F_ATAN2 || (op) == F_CHR || \ | |
41 (op) == F_CHR || (op) == F_COS || (op) == F_DEFINED || \ | |
42 (op) == F_EXP || (op) == F_GETENV || (op) == F_INT || \ | |
43 (op) == F_IO || (op) == F_LENGTH || (op) == F_LOG || \ | |
44 (op) == F_LOG10 || (op) == F_LOWER || (op) == F_NEG || \ | |
45 (op) == F_NOT || (op) == F_NUM || (op) == F_ORD || \ | |
46 (op) == F_QUOTE || (op) == F_RE_ESC || (op) == F_REVERSE || \ | |
47 (op) == F_SIN || (op) == F_TAN || (op) == F_SQRT || \ | |
48 (op) == F_STR || (op) == F_TYPEOF || (op) == F_UPPER \ | |
49 ) | |
50 | |
51 #define const_binop(op) \ | |
52 ( \ | |
53 !((op) == B_SPOT || (op) == B_SQIGGLE || (op) == B_XMATCH) \ | |
54 ) | |
55 | |
56 static int hp_expr(const struct expr *e) { | |
57 switch (e->type) { | |
58 case literE: | |
59 return 1; | |
60 | |
61 case varE: | |
62 return 1; | |
63 | |
64 case varhashE: | |
65 return hp_expr(e->right); | |
66 | |
67 case symbolE: | |
68 if (e->op != S_RAND) { | |
69 return 1; | |
70 } | |
71 return 0; | |
72 | |
73 case unopE: | |
74 if (!const_unop(e->op)) { | |
75 return 0; | |
76 } | |
77 return hp_expr(e->right); | |
78 | |
79 case binopE: | |
80 if (!const_binop(e->op)) { | |
81 return 0; | |
82 } | |
83 if (!hp_expr(e->left.expr)) { | |
84 return 0; | |
85 } | |
86 return hp_expr(e->right); | |
87 | |
88 case listE: | |
89 if (e->right) { | |
90 if (!hp_expr(e->right)) { | |
91 return 0; | |
92 } | |
93 if (!e->left.expr) { | |
94 return 1; | |
95 } | |
96 return hp_expr(e->left.expr); | |
97 } | |
98 return 1; | |
99 } | |
100 | |
101 NOTREACHED; | |
102 } | |
103 | |
104 void trans_fold(struct expr **e) { | |
105 struct val *v; | |
106 | |
107 switch ((*e)->type) { | |
108 case literE: | |
109 break; | |
110 | |
111 case varE: | |
112 break; | |
113 | |
114 case varhashE: | |
115 trans_fold(&(*e)->right); | |
116 break; | |
117 | |
118 case symbolE: | |
119 break; | |
120 | |
121 case unopE: | |
122 trans_fold(&(*e)->right); | |
123 if (liter_expr((*e)->right)) { | |
124 if ((*e)->op == F_NUL) { | |
125 v = eval_expr((*e)->right); | |
126 free_expr((*e)->right); | |
127 (*e)->right = xmalloc(1, sizeof *(*e)->right); | |
128 (*e)->right->type = literE; | |
129 (*e)->right->left.expr = (*e)->right->right = NULL; | |
130 (*e)->right->v.val = v_undef(); | |
131 TOLABEL(v); | |
132 if (((*e)->left.op = ve_findnext(&Venus, ko_str(v->ko), (*e)->left.bonus))) { | |
133 (*e)->op = F_CALL; | |
134 } else { | |
135 (*e)->op = F_HANG; | |
136 } | |
137 v_delete(v); | |
138 } else if (const_unop((*e)->op)) { | |
139 (*e)->v.val = eval_expr(*e); | |
140 free_expr((*e)->right); | |
141 (*e)->right = NULL; | |
142 (*e)->type = literE; | |
143 } | |
144 } else if ( | |
145 (*e)->right->type == unopE && | |
146 (*e)->op == (*e)->right->op && | |
147 ((*e)->op == F_STR || (*e)->op == F_NUM) | |
148 ) { | |
149 struct expr *const tmp = (*e)->right; | |
150 (*e)->right = (*e)->right->right; | |
151 tmp->right = NULL; | |
152 free_expr(tmp); | |
153 } | |
154 break; | |
155 | |
156 case binopE: | |
157 trans_fold(&(*e)->left.expr); | |
158 trans_fold(&(*e)->right); | |
159 if (liter_expr((*e)->left.expr) && liter_expr((*e)->right) && const_binop((*e)->op)) { | |
160 (*e)->v.val = eval_expr(*e); | |
161 free_expr((*e)->left.expr); | |
162 (*e)->left.expr = NULL; | |
163 free_expr((*e)->right); | |
164 (*e)->right = NULL; | |
165 (*e)->type = literE; | |
166 } else switch ((*e)->op) { | |
167 case B_INTERSECTION: | |
168 if ((*e)->left.expr->type == literE) { | |
169 V_NUM((*e)->left.expr->v.val); | |
170 if ((*e)->left.expr->v.val->num == 0.0) { | |
171 free_expr((*e)->left.expr); | |
172 (*e)->left.expr = NULL; | |
173 (*e)->op = F_NUM; | |
174 (*e)->type = unopE; | |
175 } | |
176 } else if ((*e)->right->type == literE) { | |
177 V_NUM((*e)->right->v.val); | |
178 if ((*e)->right->v.val->num == 0.0) { | |
179 free_expr((*e)->right); | |
180 (*e)->right = (*e)->left.expr; | |
181 (*e)->left.expr = NULL; | |
182 (*e)->op = F_NUM; | |
183 (*e)->type = unopE; | |
184 } | |
185 } | |
186 break; | |
187 | |
188 case B_TAIL: | |
189 if (hp_expr((*e)->left.expr)) { | |
190 struct expr *tmp; | |
191 | |
192 free_expr((*e)->left.expr); | |
193 tmp = *e; | |
194 *e = (*e)->right; | |
195 xfree(tmp); | |
196 } | |
197 break; | |
198 | |
199 case B_WORM: | |
200 if ((*e)->left.expr->type == literE) { | |
201 V_NUM((*e)->left.expr->v.val); | |
202 if ((*e)->left.expr->v.val->num == 0.0) { | |
203 free_expr((*e)->left.expr); | |
204 (*e)->left.expr = NULL; | |
205 (*e)->op = F_NEG; | |
206 (*e)->type = unopE; | |
207 } | |
208 } else if ((*e)->right->type == literE) { | |
209 V_NUM((*e)->right->v.val); | |
210 if ((*e)->right->v.val->num == 0.0) { | |
211 free_expr((*e)->right); | |
212 (*e)->right = (*e)->left.expr; | |
213 (*e)->left.expr = NULL; | |
214 (*e)->op = F_NUM; | |
215 (*e)->type = unopE; | |
216 } | |
217 } | |
218 break; | |
219 | |
220 case B_SHARK_FIN: | |
221 if ((*e)->left.expr->type == symbolE) { | |
222 if ((*e)->left.expr->op == S_EULER) { | |
223 free_expr((*e)->left.expr); | |
224 (*e)->left.expr = NULL; | |
225 (*e)->op = F_EXP; | |
226 (*e)->type = unopE; | |
227 } | |
228 } else if ((*e)->right->type == literE) { | |
229 V_NUM((*e)->right->v.val); | |
230 if ((*e)->right->v.val->num == 0.5) { | |
231 free_expr((*e)->right); | |
232 (*e)->right = (*e)->left.expr; | |
233 (*e)->left.expr = NULL; | |
234 (*e)->op = F_SQRT; | |
235 (*e)->type = unopE; | |
236 } | |
237 } | |
238 break; | |
239 | |
240 case B_FLATWORM: | |
241 if ((*e)->left.expr->type == literE) { | |
242 V_STR((*e)->left.expr->v.val); | |
243 if (!ko_length((*e)->left.expr->v.val->ko)) { | |
244 free_expr((*e)->left.expr); | |
245 (*e)->left.expr = NULL; | |
246 (*e)->op = F_STR; | |
247 (*e)->type = unopE; | |
248 } | |
249 } else if ((*e)->right->type == literE) { | |
250 V_STR((*e)->right->v.val); | |
251 if (!ko_length((*e)->right->v.val->ko)) { | |
252 free_expr((*e)->right); | |
253 (*e)->right = (*e)->left.expr; | |
254 (*e)->left.expr = NULL; | |
255 (*e)->op = F_STR; | |
256 (*e)->type = unopE; | |
257 } | |
258 } | |
259 break; | |
260 | |
261 case B_SQIGGLE: | |
262 case B_XMATCH: | |
263 if ((*e)->right->type == literE) { | |
264 t_regex *rx; | |
265 V_STR((*e)->right->v.val); | |
266 rx = re_compile(ko_str((*e)->right->v.val->ko)); | |
267 free_expr((*e)->right); | |
268 (*e)->right = (*e)->left.expr; | |
269 (*e)->left.rx = rx; | |
270 (*e)->op = F_MATCH; | |
271 (*e)->type = unopE; | |
272 } | |
273 break; | |
274 } | |
275 break; | |
276 | |
277 case listE: | |
278 if ((*e)->right) { | |
279 trans_fold(&(*e)->right); | |
280 if ((*e)->left.expr) { | |
281 trans_fold(&(*e)->left.expr); | |
282 } | |
283 } | |
284 break; | |
285 } | |
286 } | |
287 | |
288 #define SNAP(p) \ | |
289 do { \ | |
290 while ( \ | |
291 (p) && \ | |
292 (p)->type == OP_NOP && \ | |
293 (p) != (p)->next \ | |
294 ) { \ | |
295 (p) = (p)->next; \ | |
296 } \ | |
297 } while (0) | |
298 | |
299 static void walk(struct expr *e) { | |
300 for (;;) { | |
301 switch (e->type) { | |
302 case literE: | |
303 case symbolE: | |
304 return; | |
305 | |
306 case varE: | |
307 return; | |
308 | |
309 case varhashE: | |
310 e = e->right; | |
311 continue; | |
312 | |
313 case unopE: | |
314 if (e->op == F_CALL) { | |
315 SNAP(e->left.op); | |
316 if ( | |
317 e->left.op && | |
318 e->left.op->type == OP_RETURN && | |
319 hp_expr(e->right) && | |
320 liter_expr(e->left.op->arg) | |
321 ) { | |
322 free_expr(e->right); | |
323 e->right = NULL; | |
324 switch (e->left.op->arg->type) { | |
325 case literE: | |
326 e->v.val = v_undef(); | |
327 v_set(e->v.val, e->left.op->arg->v.val); | |
328 e->type = literE; | |
329 break; | |
330 | |
331 case symbolE: | |
332 e->op = e->left.op->arg->op; | |
333 e->type = symbolE; | |
334 break; | |
335 | |
336 case listE: | |
337 assert(!e->left.op->arg->left.expr && !e->left.op->arg->right); | |
338 e->type = listE; | |
339 break; | |
340 | |
341 default: | |
342 NOTREACHED; | |
343 } | |
344 e->left.expr = NULL; | |
345 return; | |
346 } | |
347 } | |
348 e = e->right; | |
349 continue; | |
350 | |
351 case binopE: | |
352 walk(e->left.expr); | |
353 e = e->right; | |
354 continue; | |
355 | |
356 case listE: | |
357 if (e->right) { | |
358 if (e->left.expr) { | |
359 walk(e->left.expr); | |
360 } | |
361 e = e->right; | |
362 continue; | |
363 } | |
364 return; | |
365 } | |
366 } | |
367 } | |
368 | |
369 void transmogrify(struct text *code) { | |
370 size_t i; | |
371 struct op *hang = NULL; | |
372 | |
373 for (i = 0; i < code->length; ++i) { | |
374 struct op *op = code->start[i]; | |
375 | |
376 switch (op->type) { | |
377 case OP_CALL: | |
378 case OP_CALL_DYN: | |
379 case OP_CLOSE: | |
380 case OP_EXIT: | |
381 case OP_FLUSH: | |
382 case OP_GOBACK: | |
383 case OP_GOTO: | |
384 case OP_IF: | |
385 case OP_RESET: | |
386 case OP_RETURN: | |
387 case OP_SYSTEM: | |
388 case OP_THROW: | |
389 trans_fold(&op->arg); | |
390 break; | |
391 | |
392 case OP_ASSIGN: | |
393 trans_fold(&op->arg); | |
394 if (!op->arh.expr) { | |
395 if (hp_expr(op->arg)) { | |
396 free_expr(op->arg); | |
397 op->arg = NULL; | |
398 op->type = OP_NOP; | |
399 } | |
400 } else { | |
401 trans_fold(&op->arh.expr); | |
402 if ( | |
403 op->arh.expr->type == varE && | |
404 op->arg->type == binopE && | |
405 op->arg->left.expr->type == varE && | |
406 op->arh.expr->v.val == op->arg->left.expr->v.val | |
407 ) { | |
408 struct expr *const tmp = op->arg; | |
409 op->arh.expr->op = op->arg->op; | |
410 op->arg = op->arg->right; | |
411 xfree(tmp->left.expr); | |
412 xfree(tmp); | |
413 op->type = OP_MODIFY; | |
414 } else if (op->arg->type == literE) { | |
415 op->type = OP_SET_VAL; | |
416 } | |
417 } | |
418 break; | |
419 | |
420 case OP_CALL_BACK: | |
421 case OP_MODIFY: | |
422 trans_fold(&op->arh.expr); | |
423 trans_fold(&op->arg); | |
424 break; | |
425 | |
426 case OP_PRINT: | |
427 case OP_PUTC: | |
428 case OP_TEMP: | |
429 trans_fold(&op->arg); | |
430 if (op->arh.expr) { | |
431 trans_fold(&op->arh.expr); | |
432 } | |
433 break; | |
434 | |
435 default: | |
436 break; | |
437 } | |
438 } | |
439 | |
440 for (i = 0; i < code->length; ++i) { | |
441 struct op *op = code->start[i]; | |
442 | |
443 switch (op->type) { | |
444 case OP_CALL_BACK: | |
445 if (liter_expr(op->arh.expr)) { | |
446 struct val *v; | |
447 | |
448 v = eval_expr(op->arh.expr); | |
449 TOLABEL(v); | |
450 free_expr(op->arh.expr); | |
451 if ((op->arh.op = ve_findprev(&Venus, ko_str(v->ko), op->line))) { | |
452 op->type = OP_CALL; | |
453 } else { | |
454 free_expr(op->arg); | |
455 op->arg = NULL; | |
456 op->type = OP_HANG; | |
457 hang = op; | |
458 } | |
459 v_end(v); | |
460 xfree(v); | |
461 } | |
462 break; | |
463 | |
464 case OP_CALL_DYN: | |
465 case OP_GOBACK: | |
466 case OP_GOTO: | |
467 if (liter_expr(op->arg)) { | |
468 struct val *v; | |
469 | |
470 v = eval_expr(op->arg); | |
471 TOLABEL(v); | |
472 free_expr(op->arg); | |
473 op->arg = NULL; | |
474 if ((op->arh.op = (op->type == OP_GOBACK ? ve_findprev : ve_findnext)(&Venus, ko_str(v->ko), op->line))) { | |
475 if (op->type == OP_CALL_DYN) { | |
476 op->type = OP_CALL; | |
477 op->arg = xmalloc(1, sizeof *op->arg); | |
478 op->arg->left.expr = op->arg->right = NULL; | |
479 op->arg->type = literE; | |
480 op->arg->v.val = v_undef(); | |
481 } else { | |
482 op->next = op->arh.op; | |
483 op->arh.op = NULL; | |
484 op->type = OP_NOP; | |
485 } | |
486 } else { | |
487 op->type = OP_HANG; | |
488 hang = op; | |
489 } | |
490 v_end(v); | |
491 xfree(v); | |
492 } | |
493 break; | |
494 | |
495 case OP_HANG: | |
496 hang = op; | |
497 break; | |
498 | |
499 case OP_IF: | |
500 if (liter_expr(op->arg)) { | |
501 struct val *v; | |
502 | |
503 v = eval_expr(op->arg); | |
504 if (v_true(v)) { | |
505 op->next = op->arh.op; | |
506 } | |
507 v_delete(v); | |
508 op->type = OP_NOP; | |
509 op->arh.expr = NULL; | |
510 free_expr(op->arg); | |
511 op->arg = NULL; | |
512 } | |
513 break; | |
514 | |
515 case OP_PRINT: | |
516 if ( | |
517 op->arg->type == literE && | |
518 ( | |
519 ( | |
520 op->arg->v.val->type == V_STR_K && | |
521 ko_length(op->arg->v.val->ko) == 0 | |
522 ) || | |
523 op->arg->v.val->type == V_UNDEF | |
524 ) | |
525 ) { | |
526 op->type = OP_NOP; | |
527 free_expr(op->arg); | |
528 op->arg = NULL; | |
529 if (op->arh.expr) { | |
530 free_expr(op->arh.expr); | |
531 op->arh.expr = NULL; | |
532 } | |
533 break; | |
534 } | |
535 if ( | |
536 op->arh.expr && | |
537 op->arh.expr->type == symbolE && | |
538 op->arh.expr->op == S_STDOUT | |
539 ) { | |
540 free_expr(op->arh.expr); | |
541 op->arh.expr = NULL; | |
542 } | |
543 break; | |
544 | |
545 default: | |
546 break; | |
547 } | |
548 } | |
549 | |
550 if (!hang) { | |
551 struct op tmp; | |
552 | |
553 tmp.type = OP_HANG; | |
554 tmp.arg = tmp.arh.expr = NULL; | |
555 tmp.next = NULL; | |
556 St_init(&tmp.txt); | |
557 St_clear(&tmp.txt); | |
558 tmp.line = -1; | |
559 | |
560 hang = text_push(code, &tmp); | |
561 } | |
562 | |
563 for (i = 0; i < code->length; ++i) { | |
564 struct op *op = code->start[i]; | |
565 | |
566 SNAP(op->next); | |
567 if (op->type == OP_IF) { | |
568 SNAP(op->arh.op); | |
569 } else if (op->type == OP_CALL) { | |
570 SNAP(op->arh.op); | |
571 if (!op->arh.op) { | |
572 struct expr *tmp = xmalloc(1, sizeof *tmp); | |
573 tmp->type = binopE; | |
574 tmp->op = B_TAIL; | |
575 tmp->left.expr = op->arg; | |
576 tmp->right = xmalloc(1, sizeof *tmp->right); | |
577 tmp->right->type = literE; | |
578 tmp->right->v.val = v_undef(); | |
579 tmp->right->left.expr = tmp->right->right = NULL; | |
580 op->arg = tmp; | |
581 op->type = OP_EXIT; | |
582 trans_fold(&op->arg); | |
583 } | |
584 } | |
585 | |
586 if (op == op->next) { | |
587 op->next = hang; | |
588 } | |
589 if (OP_1ARG_P(op->type)) { | |
590 walk(op->arg); | |
591 } else if (OP_2ARG_P(op->type)) { | |
592 if (op->arh.expr) { | |
593 walk(op->arh.expr); | |
594 } | |
595 walk(op->arg); | |
596 } | |
597 } | |
598 } |