new tests for the def_parser
[mala.git] / std / std_macros.c
blob371a9838ee31c65b8523929d95f3729198d4f4d1
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),
47 MALA_PARSER_SIMPLE("--END", mala_end_parser),
48 // TODO MALA_PARSER_BRIEF("--END", "closes a block"),
49 //TODOMALA_PARSER_HELP("--END", ("an --END without a matching --BEGIN raises an error.")),
51 MALA_PARSER_SIMPLE("--DEF", mala_def_parser),
52 //MALA_PARSER_BRIEF("--DEF", "defines a substitution"),
53 //MALA_PARSER_SIGNATURE_TYPE("--DEF", ("WORD", "WORD-OR-BLOCK")),
54 //TODO MALA_PARSER_SIGNATURE_USAGE("--DEF", ("word to be substituted",
55 // "replaced with this")),
56 //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.")),
57 //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"),
58 //MALA_PARSER_BRIEF("MACROS", "TODO"),
59 //MALA_PARSER_HELP("MACROS", ("TODO")),
62 MALA_PARSER("--", mala__parser, NULL, NULL, NULL),
63 MALA_PARSER_BRIEF("--", ""),
64 MALA_PARSER_HELP("--", ("TODO")),
65 MALA_PARSER_SIGNATURE_TYPE("--", ("")),
66 MALA_PARSER_SIGNATURE_USAGE("--", ("")),
67 MALA_PARSER_RESULT_TYPE("--", ("")),
68 MALA_PARSER_RESULT_USAGE("--", ("")),
70 MALA_PARSER("--FOREACH-WORD", mala_foreach_word_parser, NULL, NULL, NULL),
71 MALA_PARSER_BRIEF("--", ""),
72 MALA_PARSER_HELP("--", ("TODO")),
73 MALA_PARSER_SIGNATURE_TYPE("--", ("")),
74 MALA_PARSER_SIGNATURE_USAGE("--", ("")),
75 MALA_PARSER_RESULT_TYPE("--", ("")),
76 MALA_PARSER_RESULT_USAGE("--", ("")),
82 //MALA_PARSER_BRIEF("--DEL", "deletes a macro"),
83 //TODO MALA_PARSER_SIGNATURE_TYPE("--DEL", ("WORD")),
84 //TODO MALA_PARSER_SIGNATURE_USAGE("--DEL", ("name of the Macro to delete")),
85 //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)")),
87 // MALA_PARSER_BRIEF("--BEGIN", "defines a block or list"),
88 //TODO MALA_PARSER_SIGNATURE_TYPE("--BEGIN", ("SEQUENCE","END")),
89 //TODO MALA_PARSER_SIGNATURE_USAGE("--BEGIN", ("content of the block", "a --END which closes the block")),
90 //TODO MALA_PARSER_RESULT_TYPE("--BEGIN", ("BLOCK")),
91 //TODO MALA_PARSER_RESULT_USAGE("--BEGIN", ("a unique name of the block")),
92 //TODO MALA_PARSER_HELP("--BEGIN", ("Blocks can have % substitutions, Blocks are garbage collected, TODO")),
94 MALA_ACTIONS_END
98 mala_state
99 mala_begin_parser (MalaProgram prg)
101 MalaStringList end;
102 unsigned depth = 0;
104 // find matching --END
105 MalaStringList begin = mala_stringlist_next (prg->pptr);
106 for (end = begin;
107 !mala_stringlist_is_end (prg->program, end);
108 mala_stringlist_fwd (&end))
110 if (mala_stringlist_string (end) == prg->engine->common_string[MALA_STRING_BEGIN])
111 ++depth;
112 else if (mala_stringlist_string (end) == prg->engine->common_string[MALA_STRING_END])
113 --depth;
115 if (!depth)
116 break;
119 if (depth)
120 return mala_program_commonexception (prg, MALA_STRING_ERROR_MISSING_END);
122 ACOGC_STACK_ENTER (&prg->engine->gcroot);
123 ACOGC_STACK_PTR (MalaStringList, list);
124 ACOGC_STACK_PTR (MalaString, name);
126 list.ptr = mala_stringlist_new (prg->engine);
127 unsigned length = 0;
129 // move elements into destionation list
130 while (mala_stringlist_next (begin) != end)
132 mala_stringlist_insert_tail (list.ptr, mala_stringlist_next (begin));
133 ++length;
136 MalaParserFunc parser;
137 int max_arg = -1;
138 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
140 const char* templ;
141 mala_state ret;
142 void * data = NULL;
144 if (length == 0)
146 // --BEGIN --END becomes --PASS
147 TODO ("direct --PASS substitute");
148 parser = mala_pass_parser;
149 templ = "--BLOCK_%08X";
150 ret = MALA_LIST;
152 else if (length == 1)
154 data = mala_stringlist_string (mala_stringlist_head_get (list.ptr));
155 mala_string_macrocheck ((MalaString) data, &max_arg, argt);
156 if (max_arg == INT_MAX)
158 mala_stringlist_insert_after_stringlist (begin, list.ptr);
159 ACOGC_STACK_LEAVE;
160 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
163 if (max_arg == -1)
165 // --BEGIN FOO --END becomes FOO
166 TODO ("direct name substitute");
167 parser = mala_substitute_parser;
168 templ = "--BLOCK_%08X";
169 ret = MALA_LIST;
171 else
173 parser = mala_macro_parser;
174 templ = "--BLOCK_%08X";
175 ret = MALA_MACRO;
178 else
180 data = list.ptr;
181 mala_stringlist_macrocheck (list.ptr, &max_arg, argt);
182 if (max_arg == INT_MAX)
184 mala_stringlist_insert_after_stringlist (begin, list.ptr);
185 ACOGC_STACK_LEAVE;
186 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
189 if (max_arg == -1)
191 parser = mala_expand_parser;
192 templ = "--BLOCK_%08X";
193 ret = MALA_MACRO;
195 else
197 parser = mala_macro_parser;
198 templ = "--BLOCK_%08X";
199 ret = MALA_MACRO;
203 MALA_MUTATOR_BEGIN
205 // insert new --nnn... in program
206 name.ptr = mala_engine_tmpname (prg->engine, templ);
207 TRACE (mala_module_std_macros, "Block %s", mala_string_cstr (name.ptr) );
208 mala_action_new (name.ptr, parser, data, data?ACOGC_GC:ACOGC_UNSET, prg->engine);
209 ACOGC_STACK_PTR (MalaStringList, node);
210 node.ptr = mala_stringlist_node_new (name.ptr, prg->engine);
211 mala_stringlist_insert_after (end, node.ptr);
213 MALA_MUTATOR_END;
215 ACOGC_STACK_LEAVE;
216 mala_program_action_done (prg, 1);
217 return ret;
220 mala_state
221 mala_substitute_parser (MalaProgram prg)
223 MALA_MUTATOR_BEGIN
225 REQUIRE (acogc_object_type (mala_program_pptr_action (prg)->data)
226 == &prg->engine->gcfactory_strings);
228 mala_stringlist_next (prg->pptr)->string = mala_action_string (mala_program_pptr_action (prg));
230 MALA_MUTATOR_END;
232 return MALA_CONTINUE;
235 mala_state
236 mala_expand_parser (MalaProgram prg)
238 MALA_MUTATOR_BEGIN
240 MalaAction act = mala_program_pptr_action (prg);
241 REQUIRE (acogc_object_type (mala_action_dataptr (act))
242 == &prg->engine->gcfactory_stringlists);
244 MalaStringList pos = mala_stringlist_next (prg->pptr);
245 MalaStringList itr;
247 for (itr = mala_stringlist_tail_get (mala_action_stringlist (act));
248 !mala_stringlist_is_end (mala_action_stringlist (act), itr);
249 mala_stringlist_rev (&itr))
251 MalaStringList node = mala_stringlist_node_new (mala_stringlist_string (itr), prg->engine);
252 mala_stringlist_insert_after (pos, node);
255 MALA_MUTATOR_END;
257 mala_program_action_done (prg, 0);
258 return MALA_CONTINUE;
262 mala_state
263 mala_macro_parser (MalaProgram prg)
265 NOTICE (mala_module_std_macros, "macro parser");
267 /* How much to eveluate the argument (for now, likely extended in future):
268 MALA_REMOVE is used as pseudo tag for unused arguments/initialization
269 MALA_START doesn't evaluate the argument
270 MALA_LITERAL will evaluate fully
271 .. other destination states are reserved for future
273 int max_arg = -1;
274 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
275 MalaAction act = mala_program_pptr_action (prg);
277 // scan for arguments
278 AcogcFactory type = mala_action_data_type (act);
279 if (type == &prg->engine->gcfactory_strings)
281 mala_string_macrocheck (mala_action_string (act), &max_arg, argt);
283 else if (type == &prg->engine->gcfactory_stringlists)
285 mala_stringlist_macrocheck (mala_action_stringlist (act), &max_arg, argt);
287 else
288 NOTREACHED;
290 if (max_arg == INT_MAX)
291 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
293 if (max_arg == -1)
294 return mala_expand_parser (prg);
296 // evaluate args
297 for (int i=1; i <= max_arg; ++i)
299 if (argt[i] < MALA_START)
301 if (mala_program_eval_arg (prg, i, argt[i], NULL) > MALA_EFAULT)
302 return mala_program_commonexception (prg, MALA_STRING_ERROR);
303 TODO("use dst in arg_eval");
307 MALA_MUTATOR_BEGIN
309 // construct result list
310 MalaString args[10];
311 MalaStringList p = mala_stringlist_next (prg->pptr);
312 for (int i=1; i <= max_arg; ++i)
314 mala_stringlist_fwd (&p);
315 args[i] = mala_stringlist_string (p);
318 ACOGC_STACK_ENTER (&prg->engine->gcroot);
319 // constructing list
320 if (type == &prg->engine->gcfactory_strings)
322 ACOGC_STACK_PTR (MalaString, string);
323 string.ptr = mala_string_new_macrosubst (mala_action_string (act),
324 args, prg->engine);
326 MalaStringList n = mala_stringlist_node_new (string.ptr, prg->engine);
327 mala_stringlist_insert_after (p, n);
329 else if (type == &prg->engine->gcfactory_stringlists)
331 ACOGC_STACK_PTR (MalaStringList, list);
332 list.ptr = mala_stringlist_new_macrosubst (mala_action_stringlist (act),
333 args, prg->engine);
334 mala_stringlist_insert_after_stringlist (p, list.ptr);
336 else
337 NOTREACHED;
339 ACOGC_STACK_LEAVE;
341 MALA_MUTATOR_END;
343 mala_program_action_done (prg, max_arg);
344 return MALA_CONTINUE;
347 mala_state
348 mala_end_parser (MalaProgram prg)
350 return mala_program_commonexception (prg, MALA_STRING_ERROR_END_WITHOUT_BEGIN);
353 mala_state
354 mala_def_parser (MalaProgram prg)
356 MalaStringList dst;
357 MalaString name;
358 MalaString expand;
360 // evaluate both args
361 if (mala_program_eval_arg (prg, 1, MALA_LITERAL, &dst) > MALA_EFAULT)
362 return mala_program_commonexception (prg, MALA_STRING_ERROR);
364 name = mala_stringlist_string (dst);
366 if (mala_program_eval_arg (prg, 2, MALA_MACRO, &dst) > MALA_EFAULT)
367 return mala_program_commonexception (prg, MALA_STRING_ERROR);
369 expand = mala_stringlist_string (dst);
371 MALA_MUTATOR_BEGIN
373 TODO("optimize direct expansions");
374 int max_arg = -1;
375 mala_state argt[10] = {[0 ... 9] = MALA_REMOVE};
376 mala_string_macrocheck (expand, &max_arg, argt);
378 if (max_arg == INT_MAX)
379 return mala_program_commonexception (prg, MALA_STRING_ERROR_MACRO_SYNTAX);
380 else if (max_arg == -1)
381 // register as simple substitute
382 mala_action_new (name, mala_substitute_parser, expand, ACOGC_GC, prg->engine);
383 else
384 // register as macro
385 mala_action_new (name, mala_macro_parser, expand, ACOGC_GC, prg->engine);
387 MALA_MUTATOR_END;
389 mala_program_action_done (prg, 2);
390 return MALA_CONTINUE;
393 static void
394 mala_stringlist_macrocheck (MalaStringList list, int * max_arg, mala_state argt[10])
396 LLIST_FOREACH (&list->node, itr)
398 MalaStringList l = LLIST_TO_STRUCTP(itr, mala_stringlist, node);
399 mala_string_macrocheck (mala_stringlist_string (l), max_arg, argt);
400 if (*max_arg == INT_MAX)
401 return;
405 static void
406 mala_string_macrocheck (MalaString string, int * max_arg, mala_state argt[10])
408 const char * c;
409 for (c = mala_string_cstr (string); *c; ++c)
411 if (*c == '%')
413 ++c;
414 if (*c == '%')
416 if (*max_arg == -1)
417 *max_arg = 0;
418 continue;
420 if (*c == '-')
422 ++c;
423 if (*c >= '0' && *c <= '9')
425 if (argt[*c - '0'] < MALA_REMOVE && argt[*c - '0'] != MALA_START)
426 goto esyntax;
427 if (*c > (char) *max_arg + '0')
428 *max_arg = *c - '0';
429 argt[*c - '0'] = MALA_START;
431 else
432 goto esyntax;
434 else if (*c >= '0' && *c <= '9')
436 if (argt[*c - '0'] != MALA_REMOVE && argt[*c - '0'] != MALA_LITERAL)
437 goto esyntax;
438 if (*c > (char) *max_arg + '0')
439 *max_arg = *c - '0';
440 argt[*c - '0'] = MALA_LITERAL;
442 else
443 goto esyntax;
446 return;
448 esyntax:
449 *max_arg = INT_MAX;
450 return;
454 static MalaString
455 mala_string_new_macrosubst (MalaString src, MalaString args[10], MalaEngine eng)
457 // 1st pass get size
458 size_t size = mala_string_length (src);
459 for (const char *c = mala_string_cstr (src); *c; ++c)
461 if (*c == '%')
463 ++c;
464 --size;
465 if (*c == '%')
466 continue;
467 if (*c == '-')
469 ++c;
470 --size;
472 --size;
473 TODO ("Handle %%-0");
474 size += mala_string_length (args[*c - '0']);
478 // 2nd pass create string
479 char* cstr = NULL;
480 acogc_alloc (&cstr, size+1, &eng->gcroot);
482 char* p = cstr;
484 for (const char *c = mala_string_cstr (src); *c; ++c)
486 if (*c == '%')
488 ++c;
489 if (*c == '%')
491 *p++ = *c;
492 continue;
494 if (*c == '-')
495 ++c;
497 TODO ("Handle %%-0");
499 strcpy (p, mala_string_cstr (args[*c - '0']));
500 p += mala_string_length (args[*c - '0']);
502 else
503 *p++ = *c;
505 *p = '\0';
507 return mala_string_new_attach_cstr (cstr, eng->words);
510 static MalaStringList
511 mala_stringlist_new_macrosubst (MalaStringList src, MalaString args[10], MalaEngine eng)
513 ACOGC_STACK_ENTER (&eng->gcroot);
514 ACOGC_STACK_PTR (MalaStringList, ret);
516 ret.ptr = mala_stringlist_new (eng);
518 LLIST_FOREACH (&src->node, node)
520 ACOGC_STACK_PTR (MalaString, str);
521 str.ptr = mala_string_new_macrosubst (mala_stringlist_string_from_llist(node), args, eng);
522 MalaStringList n = mala_stringlist_node_new (str.ptr, eng);
523 mala_stringlist_insert_tail (ret.ptr, n);
526 ACOGC_STACK_LEAVE;
527 return ret.ptr;
535 #if 0 // old macrodelete_parser
536 mala_state
537 mala_macrodelete_parser (MalaProgram prg, void * data)
539 (void) data;
541 mala_engine_arg_eval (eng, pptr, 1, -1, NULL, NULL);
543 MALA_MUTATOR_BEGIN
545 if (mala_stringlist_is_tail (&eng->program, mala_program_pos (prg)))
546 return mala_engine_exception (eng, pptr, mala_program_pos (prg),
547 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
549 mala_actiondesc_pop_delete (mala_stringlist_user_get (mala_stringlist_next (mala_program_pos (prg))));
551 MALA_MUTATOR_END;
553 mala_engine_command_done (eng, pptr, 1);
554 return MALA_SUCCESS;
556 #endif // old macrodelete
558 mala_state
559 mala_delete_parser (MalaProgram prg)
561 //mala_engine_arg_eval (eng, pptr, 1, MALA_LITERAL);
563 MALA_MUTATOR_BEGIN
565 #if 0 // TODO --PROGRAM
566 if (mala_stringlist_is_tail (&eng->program, mala_program_pos (prg)))
567 return mala_engine_exception (eng, pptr, mala_program_pos (prg),
568 eng->common_string[MALA_STRING_ERROR_MISSING_ARGUMENT]);
569 #endif
570 // TODO mala_actiondesc_pop_delete (mala_stringlist_user_get (mala_stringlist_next (mala_program_pos (prg))));
572 MALA_MUTATOR_END;
574 // mala_program_action_done (prg, 1);
575 return MALA_SUCCESS;
581 realloc a string to at least needed size
582 return the amount really reserved or 0 on error
584 #if 0 // TODO acogc reserve!
585 static size_t
586 reserve_string (char ** s, size_t actual, size_t needed)
588 size_t n;
589 char * r;
591 for (n = actual>64?actual:64; n <= needed; n += (n>>1)); /*n = n * 1.5*/
593 r = realloc (*s, n);
594 if (!r)
596 /* that was to much, try conservatively */
597 r = realloc (*s, n = needed);
598 if (!r)
599 return 0;
601 *s = r;
602 return n;
604 #endif
606 NOBUG_DEFINE_FLAG (mala_module_std_macros);
609 mala_module_std_macros_init (MalaEngine self)
611 NOBUG_INIT_FLAG (mala_module_std_macros);
612 return mala_engine_actions_register (self, std_macros);
616 // Local Variables:
617 // mode: C
618 // c-file-style: "gnu"
619 // End:
620 // arch-tag: 4722e09b-a020-4206-9ecc-9442505826c5
621 // end_of_file