fix acogc stack marker bug
[mala.git] / std / std_macros.c
blobefa4eb0c2c42e338669c36bebc47c9a80000fe1d
1 /*
2 std_macros.c - MaLa standard module macros
4 Copyright (C) 2005, 2006, Christian Thaeter <ct@pipapo.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
24 #include "mala.h"
25 #include "std_macros.h"
27 static void
28 mala_stringlist_macrocheck (MalaStringList list, int * max_arg, mala_state argt[10]);
30 static void
31 mala_string_macrocheck (MalaString string, int * max_arg, mala_state argt[10]);
33 static MalaString
34 mala_string_new_macrosubst (MalaString src, MalaString args[10], MalaEngine eng);
36 static MalaStringList
37 mala_stringlist_new_macrosubst (MalaStringList src, MalaString args[10], MalaEngine eng);
41 static
42 mala_actioninit std_macros[] =
44 MALA_PARSER_SIMPLE("--DEL", mala_delete_parser),
45 MALA_PARSER_SIMPLE("--BEGIN", mala_begin_parser),
46 // MALA_PARSER_BRIEF("--BEGIN", "defines a block or list"),
47 //TODO MALA_PARSER_SIGNATURE_TYPE("--BEGIN", ("SEQUENCE","END")),
48 //TODO MALA_PARSER_SIGNATURE_USAGE("--BEGIN", ("content of the block", "a --END which closes the block")),
49 //TODO MALA_PARSER_RESULT_TYPE("--BEGIN", ("BLOCK")),
50 //TODO MALA_PARSER_RESULT_USAGE("--BEGIN", ("a unique name of the block")),
51 //TODO MALA_PARSER_HELP("--BEGIN", ("Blocks can have % substitutions, Blocks are garbage collected, TODO")),
54 MALA_PARSER_SIMPLE("--END", mala_end_parser),
55 // TODO MALA_PARSER_BRIEF("--END", "closes a block"),
56 //TODOMALA_PARSER_HELP("--END", ("an --END without a matching --BEGIN raises an error.")),
58 MALA_PARSER_SIMPLE("--DEF", mala_def_parser),
59 //MALA_PARSER_BRIEF("--DEF", "defines a substitution"),
60 //MALA_PARSER_SIGNATURE_TYPE("--DEF", ("WORD", "WORD-OR-BLOCK")),
61 //TODO MALA_PARSER_SIGNATURE_USAGE("--DEF", ("word to be substituted",
62 // "replaced with this")),
63 //TODO MALA_PARSER_HELP("--DEF", ("The second argument can be a block of words enclosed in --BEGIN ... --END with % substitution sequences. See help for --BEGIN for details.")),
64 //TODO MALA_PARSER_EXAMPLE("--DEF", "--DEF `foo `bar\t expands foo to bar\n--DEF `--action --BEGIN foo bar --END\t --action will expand to foo bar"),
65 //MALA_PARSER_BRIEF("MACROS", "TODO"),
66 //MALA_PARSER_HELP("MACROS", ("TODO")),
69 MALA_PARSER("--", mala__parser, NULL, NULL, NULL),
70 MALA_PARSER_BRIEF("--", ""),
71 MALA_PARSER_HELP("--", ("TODO")),
72 MALA_PARSER_SIGNATURE_TYPE("--", ("")),
73 MALA_PARSER_SIGNATURE_USAGE("--", ("")),
74 MALA_PARSER_RESULT_TYPE("--", ("")),
75 MALA_PARSER_RESULT_USAGE("--", ("")),
77 MALA_PARSER("--FOREACH-WORD", mala_foreach_word_parser, NULL, NULL, NULL),
78 MALA_PARSER_BRIEF("--", ""),
79 MALA_PARSER_HELP("--", ("TODO")),
80 MALA_PARSER_SIGNATURE_TYPE("--", ("")),
81 MALA_PARSER_SIGNATURE_USAGE("--", ("")),
82 MALA_PARSER_RESULT_TYPE("--", ("")),
83 MALA_PARSER_RESULT_USAGE("--", ("")),
89 //MALA_PARSER_BRIEF("--DEL", "deletes a macro"),
90 //TODO MALA_PARSER_SIGNATURE_TYPE("--DEL", ("WORD")),
91 //TODO MALA_PARSER_SIGNATURE_USAGE("--DEL", ("name of the Macro to delete")),
92 //TODO MALA_PARSER_HELP("--DEL", ("Removes the last definition of the most recent definition with the matching name and any childs which where attached to it (see --ATTACH)")),
95 MALA_ACTIONS_END
99 mala_state
100 mala_begin_parser (MalaProgram prg)
102 MalaStringList end;
103 unsigned depth = 0;
105 // find matching --END
106 MalaStringList begin = mala_stringlist_next (prg->pptr);
107 for (end = begin;
108 !mala_stringlist_is_end (prg->program, end);
109 mala_stringlist_fwd (&end))
111 if (mala_stringlist_string (end) == prg->engine->common_string[MALA_STRING_BEGIN])
112 ++depth;
113 else if (mala_stringlist_string (end) == prg->engine->common_string[MALA_STRING_END])
114 --depth;
116 if (!depth)
117 break;
120 if (depth)
121 return mala_program_commonexception (prg, MALA_STRING_ERROR_MISSING_END);
123 ACOGC_STACK_ENTER (&prg->engine->gcroot);
124 ACOGC_STACK_PTR (MalaStringList, list);
125 ACOGC_STACK_PTR (MalaString, name);
127 list.ptr = mala_stringlist_new (prg->engine);
128 unsigned length = 0;
130 // move elements into destionation list
131 while (mala_stringlist_next (begin) != end)
133 mala_stringlist_insert_tail (list.ptr, mala_stringlist_next (begin));
134 ++length;
137 MalaParserFunc parser;
138 int max_arg = -1;
139 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
141 const char* templ;
142 mala_state ret;
143 void * data = NULL;
145 if (length == 0)
147 // --BEGIN --END becomes --PASS
148 TODO ("direct --PASS substitute");
149 parser = mala_pass_parser;
150 templ = "--BLOCK_%08X";
151 ret = MALA_LIST;
153 else if (length == 1)
155 data = mala_stringlist_string (mala_stringlist_head_get (list.ptr));
156 mala_string_macrocheck ((MalaString) data, &max_arg, argt);
157 if (max_arg == INT_MAX)
159 mala_stringlist_insert_after_stringlist (begin, list.ptr);
160 ACOGC_STACK_LEAVE;
161 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
164 if (max_arg == -1)
166 // --BEGIN FOO --END becomes FOO
167 TODO ("direct name substitute");
168 parser = mala_substitute_parser;
169 templ = "--BLOCK_%08X";
170 ret = MALA_LIST;
172 else
174 parser = mala_macro_parser;
175 templ = "--BLOCK_%08X";
176 ret = MALA_MACRO;
179 else
181 data = list.ptr;
182 mala_stringlist_macrocheck (list.ptr, &max_arg, argt);
183 if (max_arg == INT_MAX)
185 mala_stringlist_insert_after_stringlist (begin, list.ptr);
186 ACOGC_STACK_LEAVE;
187 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
190 if (max_arg == -1)
192 parser = mala_expand_parser;
193 templ = "--BLOCK_%08X";
194 ret = MALA_MACRO;
196 else
198 parser = mala_macro_parser;
199 templ = "--BLOCK_%08X";
200 ret = MALA_MACRO;
204 MALA_MUTATOR_BEGIN
206 // insert new --nnn... in program
207 name.ptr = mala_engine_tmpname (prg->engine, templ);
208 TRACE (mala_module_std_macros, "Block %s", mala_string_cstr (name.ptr) );
209 mala_action_new (name.ptr, parser, data, data?ACOGC_GC:ACOGC_UNSET, prg->engine);
210 ACOGC_STACK_PTR (MalaStringList, node);
211 node.ptr = mala_stringlist_node_new (name.ptr, prg->engine);
212 mala_stringlist_insert_after (end, node.ptr);
214 MALA_MUTATOR_END;
216 ACOGC_STACK_LEAVE;
217 mala_program_action_done (prg, 1);
218 return ret;
221 mala_state
222 mala_substitute_parser (MalaProgram prg)
224 MALA_MUTATOR_BEGIN
226 REQUIRE (acogc_object_type (mala_program_pptr_action (prg)->data)
227 == &prg->engine->gcfactory_strings);
229 mala_stringlist_next (prg->pptr)->string = mala_action_string (mala_program_pptr_action (prg));
231 MALA_MUTATOR_END;
233 return MALA_CONTINUE;
236 mala_state
237 mala_expand_parser (MalaProgram prg)
239 MALA_MUTATOR_BEGIN
241 MalaAction act = mala_program_pptr_action (prg);
242 REQUIRE (acogc_object_type (mala_action_dataptr (act))
243 == &prg->engine->gcfactory_stringlists);
245 MalaStringList pos = mala_stringlist_next (prg->pptr);
246 MalaStringList itr;
248 for (itr = mala_stringlist_tail_get (mala_action_stringlist (act));
249 !mala_stringlist_is_end (mala_action_stringlist (act), itr);
250 mala_stringlist_rev (&itr))
252 MalaStringList node = mala_stringlist_node_new (mala_stringlist_string (itr), prg->engine);
253 mala_stringlist_insert_after (pos, node);
256 MALA_MUTATOR_END;
258 mala_program_action_done (prg, 0);
259 return MALA_CONTINUE;
263 mala_state
264 mala_macro_parser (MalaProgram prg)
266 NOTICE (mala_module_std_macros, "macro parser");
268 /* How much to eveluate the argument (for now, likely extended in future):
269 MALA_REMOVE is used as pseudo tag for unused arguments/initialization
270 MALA_START doesn't evaluate the argument
271 MALA_LITERAL will evaluate fully
272 .. other destination states are reserved for future
274 int max_arg = -1;
275 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
276 MalaAction act = mala_program_pptr_action (prg);
278 // scan for arguments
279 AcogcFactory type = mala_action_data_type (act);
280 if (type == &prg->engine->gcfactory_strings)
282 mala_string_macrocheck (mala_action_string (act), &max_arg, argt);
284 else if (type == &prg->engine->gcfactory_stringlists)
286 mala_stringlist_macrocheck (mala_action_stringlist (act), &max_arg, argt);
288 else
289 NOTREACHED;
291 if (max_arg == INT_MAX)
292 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
294 if (max_arg == -1)
295 return mala_expand_parser (prg);
297 // evaluate args
298 for (int i=1; i <= max_arg; ++i)
300 if (argt[i] < MALA_START)
302 if (mala_program_eval_arg (prg, i, argt[i], NULL) > MALA_EFAULT)
303 return mala_program_commonexception (prg, MALA_STRING_ERROR);
304 TODO("use dst in arg_eval");
308 MALA_MUTATOR_BEGIN
310 // construct result list
311 MalaString args[10];
312 MalaStringList p = mala_stringlist_next (prg->pptr);
313 for (int i=1; i <= max_arg; ++i)
315 mala_stringlist_fwd (&p);
316 args[i] = mala_stringlist_string (p);
319 ACOGC_STACK_ENTER (&prg->engine->gcroot);
320 // constructing list
321 if (type == &prg->engine->gcfactory_strings)
323 ACOGC_STACK_PTR (MalaString, string);
324 string.ptr = mala_string_new_macrosubst (mala_action_string (act),
325 args, prg->engine);
327 MalaStringList n = mala_stringlist_node_new (string.ptr, prg->engine);
328 mala_stringlist_insert_after (p, n);
330 else if (type == &prg->engine->gcfactory_stringlists)
332 ACOGC_STACK_PTR (MalaStringList, list);
333 list.ptr = mala_stringlist_new_macrosubst (mala_action_stringlist (act),
334 args, prg->engine);
335 mala_stringlist_insert_after_stringlist (p, list.ptr);
337 else
338 NOTREACHED;
340 ACOGC_STACK_LEAVE;
342 MALA_MUTATOR_END;
344 mala_program_action_done (prg, max_arg);
345 return MALA_CONTINUE;
348 mala_state
349 mala_end_parser (MalaProgram prg)
351 return mala_program_commonexception (prg, MALA_STRING_ERROR_END_WITHOUT_BEGIN);
354 mala_state
355 mala_def_parser (MalaProgram prg)
357 MalaStringList dst;
358 MalaString name;
359 MalaString expand;
361 // evaluate both args
362 if (mala_program_eval_arg (prg, 1, MALA_LITERAL, &dst) > MALA_EFAULT)
363 return mala_program_commonexception (prg, MALA_STRING_ERROR);
365 name = mala_stringlist_string (dst);
367 if (mala_program_eval_arg (prg, 2, MALA_MACRO, &dst) > MALA_EFAULT)
368 return mala_program_commonexception (prg, MALA_STRING_ERROR);
370 expand = mala_stringlist_string (dst);
372 MALA_MUTATOR_BEGIN
374 TODO("optimize direct expansions");
375 int max_arg = -1;
376 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
377 mala_string_macrocheck (expand, &max_arg, argt);
379 if (max_arg == INT_MAX)
380 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
381 else if (max_arg == -1)
382 // register as simple substitute
383 mala_action_new (name, mala_substitute_parser, expand, ACOGC_GC, prg->engine);
384 else
385 // register as macro
386 mala_action_new (name, mala_macro_parser, expand, ACOGC_GC, prg->engine);
388 MALA_MUTATOR_END;
390 mala_program_action_done (prg, 2);
391 return MALA_CONTINUE;
395 mala_state
396 mala_delete_parser (MalaProgram prg)
398 MalaStringList dst;
400 if (mala_program_eval_arg (prg, 1, MALA_LITERAL, &dst) > MALA_EFAULT)
401 return mala_program_commonexception (prg, MALA_STRING_ERROR);
403 MALA_MUTATOR_BEGIN
405 MalaAction act = mala_string_action (mala_stringlist_string (dst));
406 if (act)
407 mala_action_delete (mala_string_action (mala_stringlist_string (dst)));
408 else
409 return mala_program_commonexception (prg, MALA_STRING_ERROR_ACTION_NOT_DEFINED);
411 MALA_MUTATOR_END;
413 mala_program_action_done (prg, 1);
414 return MALA_CONTINUE;
418 static void
419 mala_stringlist_macrocheck (MalaStringList list, int * max_arg, mala_state argt[10])
421 LLIST_FOREACH (&list->node, itr)
423 MalaStringList l = LLIST_TO_STRUCTP(itr, mala_stringlist, node);
424 mala_string_macrocheck (mala_stringlist_string (l), max_arg, argt);
425 if (*max_arg == INT_MAX)
426 return;
430 static void
431 mala_string_macrocheck (MalaString string, int * max_arg, mala_state argt[10])
433 const char * c;
434 for (c = mala_string_cstr (string); *c; ++c)
436 if (*c == '%')
438 ++c;
439 if (*c == '%')
441 if (*max_arg == -1)
442 *max_arg = 0;
443 continue;
445 if (*c == '-')
447 ++c;
448 if (*c >= '0' && *c <= '9')
450 if (argt[*c - '0'] < MALA_REMOVE && argt[*c - '0'] != MALA_START)
451 goto esyntax;
452 if (*c > (char) *max_arg + '0')
453 *max_arg = *c - '0';
454 argt[*c - '0'] = MALA_START;
456 else
457 goto esyntax;
459 else if (*c >= '0' && *c <= '9')
461 if (argt[*c - '0'] != MALA_REMOVE && argt[*c - '0'] != MALA_LITERAL)
462 goto esyntax;
463 if (*c > (char) *max_arg + '0')
464 *max_arg = *c - '0';
465 argt[*c - '0'] = MALA_LITERAL;
467 else
468 goto esyntax;
471 return;
473 esyntax:
474 *max_arg = INT_MAX;
475 return;
479 static MalaString
480 mala_string_new_macrosubst (MalaString src, MalaString args[10], MalaEngine eng)
482 // 1st pass get size
483 size_t size = mala_string_length (src);
484 for (const char *c = mala_string_cstr (src); *c; ++c)
486 if (*c == '%')
488 ++c;
489 --size;
490 if (*c == '%')
491 continue;
492 if (*c == '-')
494 ++c;
495 --size;
497 --size;
498 TODO ("Handle %%-0");
499 size += mala_string_length (args[*c - '0']);
503 // 2nd pass create string
504 char* cstr = NULL;
505 acogc_alloc (&cstr, size+1, &eng->gcroot);
507 char* p = cstr;
509 for (const char *c = mala_string_cstr (src); *c; ++c)
511 if (*c == '%')
513 ++c;
514 if (*c == '%')
516 *p++ = *c;
517 continue;
519 if (*c == '-')
520 ++c;
522 TODO ("Handle %%-0");
524 strcpy (p, mala_string_cstr (args[*c - '0']));
525 p += mala_string_length (args[*c - '0']);
527 else
528 *p++ = *c;
530 *p = '\0';
532 return mala_string_new_attach_cstr (cstr, eng->words);
535 static MalaStringList
536 mala_stringlist_new_macrosubst (MalaStringList src, MalaString args[10], MalaEngine eng)
538 ACOGC_STACK_ENTER (&eng->gcroot);
539 ACOGC_STACK_PTR (MalaStringList, ret);
540 ACOGC_STACK_PTR (MalaString, str);
542 ret.ptr = mala_stringlist_new (eng);
544 LLIST_FOREACH (&src->node, node)
546 str.ptr = mala_string_new_macrosubst (mala_stringlist_string_from_llist(node), args, eng);
547 MalaStringList n = mala_stringlist_node_new (str.ptr, eng);
548 mala_stringlist_insert_tail (ret.ptr, n);
551 ACOGC_STACK_LEAVE;
552 return ret.ptr;
561 realloc a string to at least needed size
562 return the amount really reserved or 0 on error
564 #if 0 // TODO acogc reserve!
565 static size_t
566 reserve_string (char ** s, size_t actual, size_t needed)
568 size_t n;
569 char * r;
571 for (n = actual>64?actual:64; n <= needed; n += (n>>1)); /*n = n * 1.5*/
573 r = realloc (*s, n);
574 if (!r)
576 /* that was to much, try conservatively */
577 r = realloc (*s, n = needed);
578 if (!r)
579 return 0;
581 *s = r;
582 return n;
584 #endif
586 NOBUG_DEFINE_FLAG (mala_module_std_macros);
589 mala_module_std_macros_init (MalaEngine self)
591 NOBUG_INIT_FLAG (mala_module_std_macros);
592 return mala_engine_actions_register (self, std_macros);
596 // Local Variables:
597 // mode: C
598 // c-file-style: "gnu"
599 // End:
600 // arch-tag: 4722e09b-a020-4206-9ecc-9442505826c5
601 // end_of_file