1 /*
2  * macro.c - macro implementation
3  *
4  *   Copyright (c) 2000-2020  Shiro Kawai  <shiro@acm.org>
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *   1. Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *
13  *   2. Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  *   3. Neither the name of the authors nor the names of its contributors
18  *      may be used to endorse or promote products derived from this
19  *      software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #define LIBGAUCHE_BODY
35 #include "gauche.h"
36 #include "gauche/code.h"
37 #include "gauche/vminsn.h"
38 #include "gauche/priv/macroP.h"
39 #include "gauche/priv/identifierP.h"
40 #include "gauche/priv/builtin-syms.h"
41 
42 /* avoid C++ reserved name conflict.
43    (I hate languages that take away names from programmers!) */
44 #define template templat
45 
46 /* define if you want to debug syntax-rule expander */
47 /*#define DEBUG_SYNRULE*/
48 
49 /*===================================================================
50  * Syntax object
51  */
52 
syntax_print(ScmObj obj,ScmPort * port,ScmWriteContext * mode SCM_UNUSED)53 static void syntax_print(ScmObj obj, ScmPort *port,
54                          ScmWriteContext *mode SCM_UNUSED)
55 {
56     ScmSymbol *name = SCM_SYNTAX(obj)->name;
57     ScmModule *mod = SCM_SYNTAX(obj)->mod;
58     if (mod == NULL) {
59         Scm_Printf(port, "#<syntax %A>", (name ? SCM_OBJ(name) : SCM_FALSE));
60     } else {
61         Scm_Printf(port, "#<syntax %A#%A>",
62                    mod->name,
63                    (name ? SCM_OBJ(name) : SCM_FALSE));
64     }
65 }
66 
67 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_SyntaxClass, syntax_print);
68 
Scm_MakeSyntax(ScmSymbol * name,ScmModule * mod,ScmObj handler)69 ScmObj Scm_MakeSyntax(ScmSymbol *name, ScmModule *mod, ScmObj handler)
70 {
71     ScmSyntax *s = SCM_NEW(ScmSyntax);
72     SCM_SET_CLASS(s, SCM_CLASS_SYNTAX);
73     s->name = name;
74     s->mod = mod;
75     s->handler = handler;
76     return SCM_OBJ(s);
77 }
78 
79 /*===================================================================
80  * Macro object
81  */
82 
Scm_MakeMacro(ScmObj name,ScmObj transformer,ScmObj src,ScmObj describer)83 ScmObj Scm_MakeMacro(ScmObj name, ScmObj transformer,
84                      ScmObj src, ScmObj describer)
85 {
86     ScmMacro *s = SCM_NEW(ScmMacro);
87     SCM_SET_CLASS(s, SCM_CLASS_MACRO);
88     s->name = name;
89     s->transformer = transformer;
90     s->src = src;
91     s->describer = describer;
92     return SCM_OBJ(s);
93 }
94 
Scm_MacroTransformer(ScmMacro * mac)95 ScmObj Scm_MacroTransformer(ScmMacro *mac)
96 {
97     return mac->transformer;
98 }
99 
Scm_MacroName(ScmMacro * mac)100 ScmObj Scm_MacroName(ScmMacro *mac)
101 {
102     return (mac->name? SCM_OBJ(mac->name) : SCM_FALSE);
103 }
104 
105 /*===================================================================
106  * SyntaxPattern object
107  * Repesents a repeatable subpattern
108  * (e.g. x ...), as well as the placeholder of the repeated match
109  * in a template.
110  */
111 
112 typedef struct ScmSyntaxPatternRec {
113     SCM_HEADER;
114     ScmObj pattern;             /* subpattern */
115     ScmObj vars;                /* pattern variables in this subpattern */
116     short level;                /* level of this subpattern */
117     short numFollowingItems;    /* only used in pattern (not template).
118                                    this specifies the # of items that follows
119                                    the repetition, excluding the last CDR.
120 
121                                    E.g. From (x ... y z), `x ...' part becomes
122                                    SyntaxPattern with numFollowingItems=2.
123                                    From (x ... . y), `x ...' part becomes
124                                    SyntaxPattern with numFollowingItems=0. */
125 } ScmSyntaxPattern;
126 
127 SCM_CLASS_DECL(Scm_SyntaxPatternClass);
128 #define SCM_CLASS_SYNTAX_PATTERN  (&Scm_SyntaxPatternClass)
129 
130 #define SCM_SYNTAX_PATTERN(obj)   ((ScmSyntaxPattern*)(obj))
131 #define SCM_SYNTAX_PATTERN_P(obj) SCM_XTYPEP(obj, SCM_CLASS_SYNTAX_PATTERN)
132 
pattern_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)133 static void pattern_print(ScmObj obj, ScmPort *port,
134                           ScmWriteContext *ctx SCM_UNUSED)
135 {
136     Scm_Printf(port, "#<pattern:%d%S %S%s>",
137                SCM_SYNTAX_PATTERN(obj)->level,
138                SCM_SYNTAX_PATTERN(obj)->vars,
139                SCM_SYNTAX_PATTERN(obj)->pattern,
140                SCM_SYNTAX_PATTERN(obj)->numFollowingItems? " ..." : "");
141 }
142 
143 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_SyntaxPatternClass, pattern_print);
144 
make_syntax_pattern(int level,int numFollowing)145 ScmSyntaxPattern *make_syntax_pattern(int level, int numFollowing)
146 {
147     ScmSyntaxPattern *p = SCM_NEW(ScmSyntaxPattern);
148     SCM_SET_CLASS(p, SCM_CLASS_SYNTAX_PATTERN);
149     p->pattern = SCM_NIL;
150     p->vars = SCM_NIL;
151     p->level = level;
152     p->numFollowingItems = numFollowing;
153     return p;
154 }
155 
156 /*===================================================================
157  * SyntaxRules object
158  *   Internal object to construct pattern matcher
159  */
160 
synrule_print(ScmObj obj,ScmPort * port,ScmWriteContext * mode SCM_UNUSED)161 static void synrule_print(ScmObj obj, ScmPort *port,
162                           ScmWriteContext *mode SCM_UNUSED)
163 {
164     ScmSyntaxRules *r = SCM_SYNTAX_RULES(obj);
165 
166     Scm_Printf(port, "#<syntax-rules(%d)\n", r->numRules);
167     for (int i = 0; i < r->numRules; i++) {
168         Scm_Printf(port, "%2d: (numPvars=%d, maxLevel=%d)\n",
169                    i, r->rules[i].numPvars, r->rules[i].maxLevel);
170         Scm_Printf(port, "   pattern  = %S\n", r->rules[i].pattern);
171         Scm_Printf(port, "   template = %S\n", r->rules[i].template);
172     }
173     Scm_Printf(port, ">");
174 }
175 
176 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_SyntaxRulesClass, synrule_print);
177 
make_syntax_rules(int nr)178 ScmSyntaxRules *make_syntax_rules(int nr)
179 {
180     ScmSyntaxRules *r = SCM_NEW2(ScmSyntaxRules *,
181                                  sizeof(ScmSyntaxRules)+(nr-1)*sizeof(ScmSyntaxRuleBranch));
182     SCM_SET_CLASS(r, SCM_CLASS_SYNTAX_RULES);
183     r->numRules = nr;
184     return r;
185 }
186 
187 /*===================================================================
188  * Traditional Macro
189  */
190 
191 /* TRANSIENT
192    This used to be called via make-macro-transformer, but no longer.
193    We leave stub here for ABI compatibility. */
194 #if GAUCHE_API_VERSION < 1000
Scm_MakeMacroTransformerOld(ScmSymbol * name SCM_UNUSED,ScmProcedure * proc SCM_UNUSED)195 ScmObj Scm_MakeMacroTransformerOld(ScmSymbol *name SCM_UNUSED,
196                                    ScmProcedure *proc SCM_UNUSED)
197 {
198     Scm_Panic("Obsoleted Scm_MakeMacroTransformerOld called!  Something is wrong!");
199 }
200 #endif /*GAUCHE_API_VERSION < 1000*/
201 
resolve_macro_autoload(ScmAutoload * adata)202 static ScmMacro *resolve_macro_autoload(ScmAutoload *adata)
203 {
204     ScmObj mac = Scm_ResolveAutoload(adata, 0);
205     if (SCM_UNBOUNDP(mac)) {
206         Scm_Error("tried to autoload macro %S, but it caused circular autoload.", adata->name);
207     }
208     if (!SCM_MACROP(mac)) {
209         Scm_Error("tried to autoload macro %S, but it yields non-macro object: %S", adata->name, mac);
210     }
211     return SCM_MACRO(mac);
212 }
213 
macro_autoload(ScmObj * argv,int argc,void * data)214 static ScmObj macro_autoload(ScmObj *argv, int argc, void *data)
215 {
216     SCM_ASSERT(argc == 2);
217     ScmObj form = argv[0];
218     ScmObj env = argv[1];
219     /* Important to save form and env before calling resolve_macro_autoload,
220        for it may overwrite stack region pointed by argv. */
221     SCM_ASSERT(SCM_AUTOLOADP(data));
222     ScmMacro *mac = resolve_macro_autoload(SCM_AUTOLOAD(data));
223     return Scm_CallMacroExpander(mac, form, env);
224 }
225 
226 #define AUTOLOAD_MACRO_SUFFIX " (autoload)"
227 
Scm_MakeMacroAutoload(ScmSymbol * name,ScmAutoload * adata)228 ScmObj Scm_MakeMacroAutoload(ScmSymbol *name, ScmAutoload *adata)
229 {
230     ScmObj transformer = Scm_MakeSubr(macro_autoload, adata,
231                                       2, 0, SCM_FALSE);
232     ScmObj name1 = Scm_StringAppendC(SCM_SYMBOL_NAME(name),
233                                      AUTOLOAD_MACRO_SUFFIX,
234                                      sizeof(AUTOLOAD_MACRO_SUFFIX)-1,
235                                      sizeof(AUTOLOAD_MACRO_SUFFIX)-1);
236     return Scm_MakeMacro(Scm_MakeSymbol(SCM_STRING(name1), FALSE),
237                          transformer, SCM_FALSE, SCM_FALSE);
238 }
239 
240 /*===================================================================
241  * R5RS Macro
242  */
243 
244 /* Keeping hygienic reference
245  *
246  *  - symbols which a template inserts into the expanded form are
247  *    converted to identifiers at the macro definition time, encapsulating
248  *    the defining environment of the macro.   So it doesn't interfere
249  *    with the macro call environment.
250  *
251  *  - literal symbols provided to the syntax-rules are also converted
252  *    to identifiers encapsulating the defining environment, and the
253  *    environment information is used when comparing with the symbols
254  *    in the macro call.
255  *
256  *  - symbols in the macro call is treated as they are.  Since the result
257  *    of macro expansion is immediately compiled in the macro call
258  *    environment, those symbols can refer proper bindings.
259  */
260 
261 /*-------------------------------------------------------------------
262  * pattern language compiler
263  *   - recognize repeatable subpatterns and replace it to SyntaxPattern node.
264  *   - convert free symbols in the template into identifiers
265  *   - convert pattern variables into LREF object.
266  */
267 /* TODO: avoid unnecessary consing as much as possible */
268 
269 /* context of pattern traversal */
270 typedef struct {
271     ScmObj name;                /* name of this macro (for error msg)*/
272     ScmObj form;                /* form being compiled (for error msg) */
273     ScmObj literals;            /* list of literals */
274     ScmObj pvars;               /* list of (pvar . pvref) */
275     ScmObj renames;             /* list of (var . identifier)  Keep mapping
276                                    of input symbol/identifier to fresh
277                                    identifier */
278     ScmObj ellipsis;            /* symbol/identifier/keyword for ellipsis
279                                    SCM_TRUE means default (...)
280                                    SCM_FALSE means disabled */
281     int pvcnt;                  /* counter of pattern variables */
282     int maxlev;                 /* maximum level */
283     ScmModule *mod;             /* module where this macro is defined */
284     ScmObj env;                 /* compiler env of this macro definition */
285 } PatternContext;
286 
287 #define PVREF_P(pvref)         SCM_PVREF_P(pvref)
288 #define PVREF_LEVEL(pvref)     (int)SCM_PVREF_LEVEL(pvref)
289 #define PVREF_COUNT(pvref)     (int)SCM_PVREF_COUNT(pvref)
290 
291 #define PVREF_LEVEL_MAX 0xff
292 #define PVREF_COUNT_MAX 0xff
293 
294 /* add pattern variable pvar.  called when compiling a pattern */
add_pvar(PatternContext * ctx,ScmSyntaxPattern * pat,ScmObj pvar)295 static inline ScmObj add_pvar(PatternContext *ctx,
296                               ScmSyntaxPattern *pat,
297                               ScmObj pvar)
298 {
299     if (pat->level > PVREF_LEVEL_MAX) {
300         Scm_Error("Pattern levels too deeply nested in the macro definition of %S", ctx->name);
301     }
302     if (ctx->pvcnt > PVREF_COUNT_MAX) {
303         Scm_Error("Too many pattern variables in the macro definition of %S", ctx->name);
304     }
305     ScmObj pvref = SCM_MAKE_PVREF(pat->level, ctx->pvcnt);
306     if (!SCM_FALSEP(Scm_Assq(pvar, ctx->pvars))) {
307         Scm_Error("Pattern variable %S appears more than once in the macro definition of %S: %S",
308                   pvar, ctx->name, ctx->form);
309     }
310     ctx->pvcnt++;
311     ctx->pvars = Scm_Acons(pvar, pvref, ctx->pvars);
312     pat->vars = Scm_Cons(pvref, pat->vars);
313     return pvref;
314 }
315 
316 /* returns pvref corresponds to the given pvar in template compilation.
317    if pvar is not a valid pvar, returns pvar itself. */
pvar_to_pvref(PatternContext * ctx,ScmSyntaxPattern * pat,ScmObj pvar)318 static inline ScmObj pvar_to_pvref(PatternContext *ctx,
319                                    ScmSyntaxPattern *pat,
320                                    ScmObj pvar)
321 {
322     ScmObj q = Scm_Assq(pvar, ctx->pvars);
323     if (!SCM_PAIRP(q)) return pvar;
324     ScmObj pvref = SCM_CDR(q);
325     if (PVREF_LEVEL(pvref) > pat->level) {
326         Scm_Error("%S: Pattern variable %S is used in wrong level: %S",
327                   ctx->name, pvar, ctx->form);
328     }
329     return pvref;
330 }
331 
isEllipsis(PatternContext * ctx,ScmObj obj)332 static int isEllipsis(PatternContext *ctx, ScmObj obj)
333 {
334     if (SCM_FALSEP(ctx->ellipsis)) return FALSE; /* inside (... TEMPLATE) */
335     if (SCM_TRUEP(ctx->ellipsis)) {
336         /* default ellipsis (...) */
337         return Scm__ERCompare(SCM_SYM_ELLIPSIS, obj, ctx->mod, ctx->env);
338     } else {
339         /* specified ellipsis */
340         return SCM_EQ(ctx->ellipsis, obj);
341     }
342 }
343 
344 #define ELLIPSIS_FOLLOWING(Pat, Ctx)                                    \
345     (SCM_PAIRP(SCM_CDR(Pat)) && isEllipsis(Ctx, SCM_CADR(Pat)))
346 
347 #define BAD_ELLIPSIS(Ctx)                                               \
348     Scm_Error("Bad ellipsis usage in macro definition of %S: %S",       \
349                Ctx->name, Ctx->form)
350 
check_literals(ScmObj literals)351 static ScmObj check_literals(ScmObj literals)
352 {
353     ScmObj lp, h = SCM_NIL, t = SCM_NIL;
354     SCM_FOR_EACH(lp, literals) {
355         ScmObj lit = SCM_CAR(lp);
356         if (SCM_SYMBOLP(lit) || SCM_IDENTIFIERP(lit))
357             SCM_APPEND1(h, t, lit);
358         else if (SCM_KEYWORDP(lit))
359             /* This branch is to allow r7rs-compliant code to go through
360                with legacy mode.  If keyword-symbol integration is turned on,
361                we never reach here. */;
362         else Scm_Error("literal list contains non-symbol: %S", literals);
363     }
364     if (!SCM_NULLP(lp))
365         Scm_Error("bad literal list in syntax-rules: %S", literals);
366     return h;
367 }
368 
369 /* Renaming: Map input variable (symbol or identifier) to fresh identifier.
370    The same (eq?) variable must map to the same identifier. */
rename_variable(ScmObj var,ScmObj * id_alist,ScmModule * mod,ScmObj env)371 static ScmObj rename_variable(ScmObj var,
372                               ScmObj *id_alist, /* ((var . id) ...) */
373                               ScmModule *mod,
374                               ScmObj env)
375 {
376     ScmObj id, p = Scm_Assq(var, *id_alist);
377     if (SCM_PAIRP(p)) return SCM_CDR(p);
378     if (SCM_SYMBOLP(var)) {
379         id = Scm_MakeIdentifier(var, mod, env);
380     } else {
381         SCM_ASSERT(SCM_IDENTIFIERP(var));
382         id = Scm_WrapIdentifier(SCM_IDENTIFIER(var));
383     }
384     *id_alist = Scm_Acons(var, id, *id_alist);
385     return id;
386 }
387 
388 
389 /* Compile a pattern or a template.
390    In the pattern, we replace variables to identifiers.
391    We also recognize pattern variables, and replace them for PVARs in
392    the pattern, and for PVREFs in the template.
393    When encounters a repeatable subpattern, replace it with
394    SyntaxPattern node.
395 */
compile_rule1(ScmObj form,ScmSyntaxPattern * spat,PatternContext * ctx,int patternp)396 static ScmObj compile_rule1(ScmObj form,
397                             ScmSyntaxPattern *spat,
398                             PatternContext *ctx,
399                             int patternp)
400 {
401     if (SCM_PAIRP(form)) {
402         ScmObj h = SCM_NIL, t = SCM_NIL;
403         int ellipsis_seen = FALSE;
404 
405         if (SCM_PAIRP(SCM_CDR(form)) && isEllipsis(ctx, SCM_CAR(form))) {
406             /* (... <template>) */
407             if (patternp) {
408                 Scm_Error("in definition of macro %S: "
409                           "<ellipsis> can't appear at the beginning of "
410                           "list/vector: %S", ctx->name, form);
411             }
412             ScmObj save_elli = ctx->ellipsis, r;
413             ctx->ellipsis = SCM_FALSE;
414             r = compile_rule1(SCM_CADR(form), spat, ctx, FALSE);
415             ctx->ellipsis = save_elli;
416             return r;
417         }
418 
419         ScmObj pp;
420         SCM_FOR_EACH(pp, form) {
421             if (ELLIPSIS_FOLLOWING(pp, ctx)) {
422                 if (patternp && ellipsis_seen) {
423                     Scm_Error("in definition of macro %S: "
424                               "Ellipses are not allowed to appear "
425                               "within the same list/vector more than once "
426                               "in a pattern: %S", ctx->name, form);
427                 }
428                 ellipsis_seen = TRUE;
429 
430                 ScmObj base = SCM_CAR(pp);
431                 pp = SCM_CDR(pp);
432 
433                 int num_trailing = 0;
434                 int ellipsis_nesting = 1;
435                 if (patternp) {
436                     /* Count trailing items to set ScmSyntaxPattern->repeat. */
437                     ScmObj trailing = SCM_CDR(pp);
438                     while (SCM_PAIRP(trailing)) {
439                         num_trailing++;
440                         trailing = SCM_CDR(trailing);
441                     }
442                 } else {
443                     /* srfi-149 allows more than one ellipsis to follow a
444                        template. */
445                     while (ELLIPSIS_FOLLOWING(pp, ctx)) {
446                         ellipsis_nesting++;
447                         if (!SCM_PAIRP(SCM_CDR(pp))) break;
448                         pp = SCM_CDR(pp);
449                     }
450                 }
451                 /* at this point, pp points the last ellipsis */
452 
453                 if (ctx->maxlev < spat->level + ellipsis_nesting)
454                     ctx->maxlev = spat->level + ellipsis_nesting + 1;
455 
456                 ScmSyntaxPattern *outermost =
457                     make_syntax_pattern(spat->level+1, num_trailing);
458                 ScmSyntaxPattern *outer = outermost;
459                 for (int i=1; i<ellipsis_nesting; i++) {
460                     ScmSyntaxPattern *inner =
461                         make_syntax_pattern(spat->level+i+1, 0);
462                     outer->pattern = SCM_OBJ(inner);
463                     outer = inner;
464                 }
465                 outer->pattern = compile_rule1(base, outer, ctx, patternp);
466                 outermost->vars = outer->vars;
467                 SCM_APPEND1(h, t, SCM_OBJ(outermost));
468                 if (!patternp) {
469                     ScmObj vp;
470                     if (SCM_NULLP(outermost->vars)) {
471                         Scm_Error("in definition of macro %S: "
472                                   "a template contains repetition "
473                                   "of constant form: %S",
474                                   ctx->name, form);
475                     }
476                     SCM_FOR_EACH(vp, outermost->vars) {
477                         if (PVREF_LEVEL(SCM_CAR(vp)) >= outermost->level) break;
478                     }
479                     if (SCM_NULLP(vp)) {
480                         Scm_Error("in definition of macro %S: "
481                                   "template's ellipsis nesting"
482                                   " is deeper than pattern's: %S",
483                                   ctx->name, form);
484                     }
485                 }
486                 spat->vars = Scm_Append2(spat->vars, outermost->vars);
487             } else {
488                 SCM_APPEND1(h, t,
489                             compile_rule1(SCM_CAR(pp), spat, ctx, patternp));
490             }
491         }
492         if (!SCM_NULLP(pp))
493             SCM_APPEND(h, t, compile_rule1(pp, spat, ctx, patternp));
494         return h;
495     }
496     else if (SCM_VECTORP(form)) {
497         /* TODO: this is a sloppy implementation.
498            Eliminate intermediate list structure! */
499         ScmObj l = Scm_VectorToList(SCM_VECTOR(form), 0, -1);
500         return Scm_ListToVector(compile_rule1(l, spat, ctx, patternp), 0, -1);
501     }
502     if (SCM_SYMBOLP(form)||SCM_IDENTIFIERP(form)) {
503         if (isEllipsis(ctx, form)) BAD_ELLIPSIS(ctx);
504         if (!SCM_FALSEP(Scm_Memq(form, ctx->literals))) {
505             if (patternp)
506                 return rename_variable(form, &ctx->renames, ctx->mod, ctx->env);
507             else
508                 return form;  /* template renaming is done in expansion time */
509         }
510         if (patternp && Scm__ERCompare(form, SCM_SYM_UNDERBAR,
511                                        ctx->mod, ctx->env)) {
512             return SCM_SYM_UNDERBAR;
513         }
514         if (patternp) {
515             return add_pvar(ctx, spat, form);
516         } else {
517             ScmObj pvref = pvar_to_pvref(ctx, spat, form);
518             if (pvref == form) {
519                 return form;
520             } else {
521                 spat->vars = Scm_Cons(pvref, spat->vars);
522                 return pvref;
523             }
524         }
525     }
526     return form;
527 }
528 
529 /* compile rules into ScmSyntaxRules structure
530    NB: We use ScmSyntaxPattern for the toplevel node of pattern and template;
531    they are just a placeholders and they don't represent repetition. */
compile_rules(ScmObj name,ScmObj ellipsis,ScmObj literals,ScmObj rules,ScmModule * mod,ScmObj env)532 static ScmSyntaxRules *compile_rules(ScmObj name,
533                                      ScmObj ellipsis,
534                                      ScmObj literals,
535                                      ScmObj rules,
536                                      ScmModule *mod,
537                                      ScmObj env) /* compiler env */
538 {
539     PatternContext ctx;
540     int numRules = Scm_Length(rules);
541 
542     if (numRules < 0) goto badform;
543     if (Scm_Length(literals) < 0) goto badform;
544 
545     ctx.name = name;
546     ctx.ellipsis = ellipsis;
547     ctx.literals = check_literals(literals);
548     ctx.mod = mod;
549     ctx.env = env;
550     ctx.renames = SCM_NIL;
551 
552     /* Corner case when literal contains the same (free-identifer=?) symbol
553        as ellipsis.  R7RS specifies the literal has precedence.
554        https://srfi-email.schemers.org/srfi-148/msg/6115633 */
555     if (!SCM_FALSEP(ellipsis)) {
556         ScmObj cp;
557         SCM_FOR_EACH(cp, ctx.literals) {
558             if (isEllipsis(&ctx, SCM_CAR(cp))) {
559                 ctx.ellipsis = SCM_FALSE;
560                 break;
561             }
562         }
563     }
564 
565     ScmSyntaxRules *sr = make_syntax_rules(numRules);
566     sr->name = name;
567     sr->numRules = numRules;
568     sr->maxNumPvars = 0;
569     sr->mod = mod;
570     sr->env = env;
571     ScmObj rp = rules;
572     for (int i=0; i < numRules; i++, rp = SCM_CDR(rp)) {
573         ScmObj rule = SCM_CAR(rp);
574         if (Scm_Length(rule) != 2) goto badform;
575 
576         ScmSyntaxPattern *pat  = make_syntax_pattern(0, 0);
577         ScmSyntaxPattern *tmpl = make_syntax_pattern(0, 0);
578         ctx.pvars = SCM_NIL;
579         ctx.pvcnt = 0;
580         ctx.maxlev = 0;
581 
582         ctx.form = SCM_CAR(rule);
583         if (!SCM_PAIRP(ctx.form)) goto badform;
584         pat->pattern = compile_rule1(SCM_CDR(ctx.form), pat, &ctx, TRUE);
585 
586         ctx.form = SCM_CADR(rule);
587         tmpl->pattern = compile_rule1(ctx.form, tmpl, &ctx, FALSE);
588 
589         sr->rules[i].pattern  = SCM_OBJ(pat->pattern);
590         sr->rules[i].template = SCM_OBJ(tmpl->pattern);
591         sr->rules[i].numPvars = ctx.pvcnt;
592         sr->rules[i].maxLevel = ctx.maxlev;
593         if (ctx.pvcnt > sr->maxNumPvars) sr->maxNumPvars = ctx.pvcnt;
594     }
595     return sr;
596 
597   badform:
598     Scm_Error("malformed macro %S: %S", name,
599               Scm_Cons(SCM_SYM_SYNTAX_RULES, Scm_Cons(literals, rules)));
600     return NULL;       /* dummy */
601 }
602 
603 /*-------------------------------------------------------------------
604  * pattern language matcher
605  */
606 
607 /* Matchvec
608  *   A sort of shallow binding technique is used to bind pattern
609  *   variables with matched patterns.
610  *
611  *   Matchlist itself is an assoc list whose key is a pattern variable.
612  *   It's value is a tree of the same depth of the pattern variable.
613  *
614  *   Suppose you have a pattern
615  *      (?a (?b (?c ?d ...) ...) ...)
616  *   In it, pattern variable ?a is level 0, ?b is 1, ?c is 2 and ?d is 3.
617  *   When the pattern matches the following form:
618  *      (1 (2 (3 4 5) (6)) (7 (8 9) (10 11 12)))
619  *   trees bound to each pattern variables are like this:
620  *
621  *      ?a => 1
622  *      ?b => (2 7)
623  *      ?c => ((3 6) (8 10))
624  *      ?d => (((4 5) ()) ((9) (11 12)))
625  */
626 
627 typedef struct {
628     ScmObj branch;              /* current level match */
629     ScmObj sprout;              /* current sprout */
630     ScmObj root;                /* root of the tree */
631 } MatchVar;
632 
alloc_matchvec(int numPvars)633 static MatchVar *alloc_matchvec(int numPvars)
634 {
635     return SCM_NEW_ARRAY(MatchVar, numPvars);
636 }
637 
init_matchvec(MatchVar * mvec,int numPvars)638 static void init_matchvec(MatchVar *mvec, int numPvars)
639 {
640     int i;
641     for (i=0; i<numPvars; i++) {
642         mvec[i].branch = mvec[i].sprout = mvec[i].root = SCM_NIL;
643     }
644 }
645 
646 /* get value associated to the pvref.  if exhausted, return SCM_UNBOUND
647    and set exhaust level in *exlev. */
get_pvref_value(ScmObj pvref,MatchVar * mvec,int * indices,int * exlev)648 static ScmObj get_pvref_value(ScmObj pvref, MatchVar *mvec,
649                               int *indices, int *exlev)
650 {
651     int level = PVREF_LEVEL(pvref), count = PVREF_COUNT(pvref);
652     ScmObj tree = mvec[count].root;
653     for (int i=1; i<=level; i++) {
654         for (int j=0; j<indices[i]; j++) {
655             if (!SCM_PAIRP(tree)) {
656                 *exlev = i;
657                 return SCM_UNBOUND;
658             }
659             tree = SCM_CDR(tree);
660         }
661         if (!SCM_PAIRP(tree)) {
662             *exlev = i;
663             return SCM_UNBOUND;
664         }
665         tree = SCM_CAR(tree);
666     }
667     return tree;
668 }
669 
670 /* for debug */
671 #ifdef DEBUG_SYNRULE
print_matchvec(MatchVar * mvec,int numPvars,ScmPort * port)672 static void print_matchvec(MatchVar *mvec, int numPvars, ScmPort *port)
673 {
674     for (int i=0; i<numPvars; i++) {
675         Scm_Printf(port, "[%S %S %S]\n",
676                    mvec[i].branch, mvec[i].sprout, mvec[i].root);
677     }
678 }
679 #endif
680 
681 static int match_synrule(ScmObj form, ScmObj pattern, ScmObj mod, ScmObj env,
682                          MatchVar *mvec);
683 
684 #define SPROUT  Scm_Cons(SCM_NIL, SCM_NIL)
685 
686 /* add a new "sprout" to the given tree at the given level. */
grow_branch(MatchVar * rec,int level)687 static void grow_branch(MatchVar *rec, int level)
688 {
689     if (level <= 1) return;
690     if (rec->root == SCM_NIL) {
691         rec->sprout = rec->root = SPROUT;
692         if (level == 2) return;
693     }
694 
695     ScmObj trunc = rec->root;
696     for (int i=1; i<level-1; i++, trunc = SCM_CAR(trunc)) {
697         SCM_FOR_EACH(trunc, trunc) {
698             if (SCM_NULLP(SCM_CDR(trunc))) break;
699         }
700         if (SCM_NULLP(SCM_CAR(trunc))) {
701             for (i++; i<level-1; i++, trunc = SCM_CAR(trunc)) {
702                 SCM_SET_CAR_UNCHECKED(trunc, SPROUT);
703             }
704             rec->sprout = SPROUT;
705             SCM_SET_CAR_UNCHECKED(trunc, rec->sprout);
706             return;
707         }
708     }
709     SCM_FOR_EACH(trunc, trunc) {
710         if (SCM_NULLP(SCM_CDR(trunc))) {
711             rec->sprout = SPROUT;
712             SCM_SET_CDR_UNCHECKED(trunc, rec->sprout);
713             break;
714         }
715     }
716 }
717 
enter_subpattern(ScmSyntaxPattern * subpat,MatchVar * mvec)718 static void enter_subpattern(ScmSyntaxPattern *subpat, MatchVar *mvec)
719 {
720     ScmObj pp;
721     SCM_FOR_EACH(pp, subpat->vars) {
722         ScmObj pvref = SCM_CAR(pp);
723         int count = PVREF_COUNT(pvref);
724         grow_branch(mvec+count, subpat->level);
725     }
726 }
727 
exit_subpattern(ScmSyntaxPattern * subpat,MatchVar * mvec)728 static void exit_subpattern(ScmSyntaxPattern *subpat, MatchVar *mvec)
729 {
730     ScmObj pp;
731     SCM_FOR_EACH(pp, subpat->vars) {
732         ScmObj pvref = SCM_CAR(pp);
733         int count = PVREF_COUNT(pvref);
734         if (PVREF_LEVEL(pvref) == subpat->level) {
735             if (subpat->level == 1) {
736                 mvec[count].root = Scm_ReverseX(mvec[count].branch);
737             } else {
738                 SCM_SET_CAR_UNCHECKED(mvec[count].sprout,
739                                       Scm_ReverseX(mvec[count].branch));
740                 mvec[count].branch = SCM_NIL;
741             }
742         }
743     }
744 }
745 
746 /* add pattern variable PVREF and its matched object MATCHED into MVEC */
match_insert(ScmObj pvref,ScmObj matched,MatchVar * mvec)747 static inline void match_insert(ScmObj pvref, ScmObj matched, MatchVar *mvec)
748 {
749     int count = PVREF_COUNT(pvref);
750     if (PVREF_LEVEL(pvref) == 0) {
751         mvec[count].root = matched;
752     } else {
753         mvec[count].branch = Scm_Cons(matched, mvec[count].branch);
754     }
755 }
756 
match_subpattern(ScmObj form,ScmSyntaxPattern * pat,ScmObj rest,ScmObj mod,ScmObj env,MatchVar * mvec)757 static inline int match_subpattern(ScmObj form, ScmSyntaxPattern *pat,
758                                    ScmObj rest, ScmObj mod, ScmObj env,
759                                    MatchVar *mvec)
760 {
761     /* TODO: If pat->numFollowingItems == 0, we don't need to calculate
762        length beforehand.  Some optimization opportunity. */
763     int limit = 0;
764     for (ScmObj p = form; SCM_PAIRP(p); p = SCM_CDR(p)) {
765         limit++;
766     }
767     limit -= pat->numFollowingItems;
768 
769     enter_subpattern(pat, mvec);
770     while (limit > 0) {
771         if (!match_synrule(SCM_CAR(form), pat->pattern, mod, env, mvec))
772             return FALSE;
773         form = SCM_CDR(form);
774         limit--;
775     }
776     exit_subpattern(pat, mvec);
777     return match_synrule(form, rest, mod, env, mvec);
778 }
779 
780 /* See if form matches pattern.  If match, add matched syntax variable
781    bindings to match vector and return TRUE; otherwise, return FALSE
782 */
match_synrule(ScmObj form,ScmObj pattern,ScmObj mod,ScmObj env,MatchVar * mvec)783 static int match_synrule(ScmObj form, ScmObj pattern, ScmObj mod, ScmObj env,
784                          MatchVar *mvec)
785 {
786     if (PVREF_P(pattern)) {
787         match_insert(pattern, form, mvec);
788         return TRUE;
789     }
790     if (SCM_EQ(pattern, SCM_SYM_UNDERBAR)) {
791         return TRUE;            /* unconditional match */
792     }
793     if (SCM_IDENTIFIERP(pattern)) {
794         return Scm__ERCompare(pattern, form, SCM_MODULE(mod), env);
795     }
796     if (SCM_SYNTAX_PATTERN_P(pattern)) {
797         return match_subpattern(form, SCM_SYNTAX_PATTERN(pattern),
798                                 SCM_NIL, mod, env, mvec);
799     }
800     if (SCM_PAIRP(pattern)) {
801         while (SCM_PAIRP(pattern)) {
802             ScmObj elt = SCM_CAR(pattern);
803             if (SCM_SYNTAX_PATTERN_P(elt)) {
804                 return match_subpattern(form, SCM_SYNTAX_PATTERN(elt),
805                                         SCM_CDR(pattern),
806                                         mod, env, mvec);
807             } else if (!SCM_PAIRP(form)) {
808                 return FALSE;
809             } else {
810                 if (!match_synrule(SCM_CAR(form), elt, mod, env, mvec))
811                     return FALSE;
812                 pattern = SCM_CDR(pattern);
813                 form = SCM_CDR(form);
814             }
815         }
816         if (!SCM_NULLP(pattern))
817             return match_synrule(form, pattern, mod, env, mvec);
818         else
819             return SCM_NULLP(form);
820     }
821     if (SCM_VECTORP(pattern)) {
822         if (!SCM_VECTORP(form)) return FALSE;
823         int plen = SCM_VECTOR_SIZE(pattern);
824         int elli = SCM_VECTOR_SIZE(form);
825         int flen = elli;
826         int has_elli = FALSE;
827         if (plen == 0) return (flen == 0);
828         for (int i=0; i < plen; i++) {
829             if (SCM_SYNTAX_PATTERN_P(SCM_VECTOR_ELEMENT(pattern, i))) {
830                 has_elli = TRUE;
831                 elli = i;
832                 break;
833             }
834         }
835         if ((!has_elli && plen!=flen) || (has_elli && plen-1>flen)) return FALSE;
836 
837         for (int i=0; i < elli; i++) {
838             if (!match_synrule(SCM_VECTOR_ELEMENT(form, i),
839                                SCM_VECTOR_ELEMENT(pattern, i),
840                                mod, env, mvec))
841                 return FALSE;
842         }
843         if (elli < flen) {
844             ScmObj pat = SCM_VECTOR_ELEMENT(pattern, elli);
845             ScmObj prest = Scm_VectorToList(SCM_VECTOR(pattern), elli+1, plen);
846             ScmObj frest = Scm_VectorToList(SCM_VECTOR(form), elli, flen);
847             return match_subpattern(frest, SCM_SYNTAX_PATTERN(pat),
848                                     prest, mod, env, mvec);
849         } else {
850             return TRUE;
851         }
852     }
853 
854     /* literal */
855     return Scm_EqualP(pattern, form);
856 }
857 
858 /*-------------------------------------------------------------------
859  * pattern language transformer
860  */
861 
862 /* If a pattern variable is exhausted, SCM_UNDEFINED is returned. */
realize_template_rec(ScmSyntaxRules * sr,ScmObj template,MatchVar * mvec,int level,int * indices,ScmObj * idlist,int * exlev)863 static ScmObj realize_template_rec(ScmSyntaxRules *sr,
864                                    ScmObj template,
865                                    MatchVar *mvec,
866                                    int level,
867                                    int *indices,
868                                    ScmObj *idlist,
869                                    int *exlev)
870 {
871     if (SCM_PAIRP(template)) {
872         ScmObj h = SCM_NIL, t = SCM_NIL;
873         while (SCM_PAIRP(template)) {
874             ScmObj e = SCM_CAR(template);
875             if (SCM_SYNTAX_PATTERN_P(e)) {
876                 ScmObj r = realize_template_rec(sr, e, mvec, level, indices, idlist, exlev);
877                 if (SCM_UNBOUNDP(r)) return r;
878                 SCM_APPEND(h, t, r);
879             } else {
880                 ScmObj r = realize_template_rec(sr, e, mvec, level, indices, idlist, exlev);
881                 if (SCM_UNBOUNDP(r)) return r;
882                 SCM_APPEND1(h, t, r);
883             }
884             template = SCM_CDR(template);
885         }
886         if (!SCM_NULLP(template)) {
887             ScmObj r = realize_template_rec(sr, template, mvec, level, indices, idlist, exlev);
888             if (SCM_UNBOUNDP(r)) return r;
889             if (SCM_NULLP(h)) return r; /* (a ... . b) and a ... is empty */
890             SCM_APPEND(h, t, r);
891         }
892         return h;
893     }
894     if (PVREF_P(template)) {
895         return get_pvref_value(template, mvec, indices, exlev);
896     }
897     if (SCM_SYNTAX_PATTERN_P(template)) {
898         ScmSyntaxPattern *pat = SCM_SYNTAX_PATTERN(template);
899         ScmObj h = SCM_NIL, t = SCM_NIL;
900         indices[level+1] = 0;
901         for (;;) {
902             ScmObj r = realize_template_rec(sr, pat->pattern, mvec, level+1, indices, idlist, exlev);
903             if (SCM_UNBOUNDP(r)) return (*exlev < pat->level)? r : h;
904             if (SCM_SYNTAX_PATTERN_P(pat->pattern)) {
905                 SCM_APPEND(h, t, r);
906             } else {
907                 SCM_APPEND1(h, t, r);
908             }
909             indices[level+1]++;
910         }
911     }
912     if (SCM_VECTORP(template)) {
913         ScmObj h = SCM_NIL, t = SCM_NIL;
914         int len = SCM_VECTOR_SIZE(template);
915         ScmObj *pe = SCM_VECTOR_ELEMENTS(template);
916 
917         for (int i=0; i<len; i++, pe++) {
918             if (SCM_SYNTAX_PATTERN_P(*pe)) {
919                 ScmObj r = realize_template_rec(sr, *pe, mvec, level, indices, idlist, exlev);
920                 if (SCM_UNBOUNDP(r)) return r;
921                 SCM_APPEND(h, t, r);
922             } else {
923                 ScmObj r = realize_template_rec(sr, *pe, mvec, level, indices, idlist, exlev);
924                 if (SCM_UNBOUNDP(r)) return r;
925                 SCM_APPEND1(h, t, r);
926             }
927         }
928         return Scm_ListToVector(h, 0, -1);
929     }
930     if (SCM_SYMBOLP(template) || SCM_IDENTIFIERP(template)) {
931         return rename_variable(template, idlist, sr->mod, sr->env);
932     }
933     return template;
934 }
935 
936 #define DEFAULT_MAX_LEVEL  10
937 
realize_template(ScmSyntaxRules * sr,ScmSyntaxRuleBranch * branch,MatchVar * mvec)938 static ScmObj realize_template(ScmSyntaxRules *sr,
939                                ScmSyntaxRuleBranch *branch,
940                                MatchVar *mvec)
941 {
942     int index[DEFAULT_MAX_LEVEL], *indices = index;
943     int exlev = 0;
944     ScmObj idlist = SCM_NIL;
945 
946     if (branch->maxLevel > DEFAULT_MAX_LEVEL)
947         indices = SCM_NEW_ATOMIC2(int*, (branch->maxLevel+1) * sizeof(int));
948     for (int i=0; i<=branch->maxLevel; i++) indices[i] = 0;
949     return realize_template_rec(sr, branch->template, mvec, 0,
950                                 indices, &idlist, &exlev);
951 }
952 
synrule_expand(ScmObj form,ScmObj mod,ScmObj env,ScmSyntaxRules * sr)953 static ScmObj synrule_expand(ScmObj form, ScmObj mod, ScmObj env, ScmSyntaxRules *sr)
954 {
955     MatchVar *mvec = alloc_matchvec(sr->maxNumPvars);
956 
957 #ifdef DEBUG_SYNRULE
958     Scm_Printf(SCM_CUROUT, "**** synrule_transform: %S\n", form);
959 #endif
960     for (int i=0; i<sr->numRules; i++) {
961 #ifdef DEBUG_SYNRULE
962         Scm_Printf(SCM_CUROUT, "pattern #%d: %S\n", i, sr->rules[i].pattern);
963 #endif
964         init_matchvec(mvec, sr->rules[i].numPvars);
965         if (match_synrule(SCM_CDR(form), sr->rules[i].pattern, mod, env, mvec)) {
966 #ifdef DEBUG_SYNRULE
967             Scm_Printf(SCM_CUROUT, "success #%d:\n", i);
968             print_matchvec(mvec, sr->rules[i].numPvars, SCM_CUROUT);
969 #endif
970             ScmObj expanded = realize_template(sr, &sr->rules[i], mvec);
971 #ifdef DEBUG_SYNRULE
972             Scm_Printf(SCM_CUROUT, "result: %S\n", expanded);
973 #endif
974             return expanded;
975         }
976     }
977     Scm_Error("malformed %S: %S", SCM_CAR(form), form);
978     return SCM_NIL;
979 }
980 
synrule_transform(ScmObj * argv,int argc,void * data)981 static ScmObj synrule_transform(ScmObj *argv, int argc, void *data)
982 {
983     SCM_ASSERT(argc == 2);
984     ScmObj form = argv[0];
985     ScmObj cenv = argv[1];
986     SCM_ASSERT(SCM_VECTORP(cenv));
987     ScmObj module = SCM_VECTOR_ELEMENT(cenv, 0); /* macro use env */
988     ScmObj frames = SCM_VECTOR_ELEMENT(cenv, 1); /* macro use env */
989     ScmSyntaxRules *sr = (ScmSyntaxRules *)data;
990     return synrule_expand(form, module, frames, sr);
991 }
992 
993 /* NB: a stub for the new compiler (TEMPORARY) */
Scm_CompileSyntaxRules(ScmObj name,ScmObj src,ScmObj ellipsis,ScmObj literals,ScmObj rules,ScmObj mod,ScmObj env)994 ScmObj Scm_CompileSyntaxRules(ScmObj name, ScmObj src, ScmObj ellipsis,
995                               ScmObj literals, ScmObj rules,
996                               ScmObj mod, ScmObj env)
997 {
998     if (SCM_IDENTIFIERP(name)) name = SCM_OBJ(SCM_IDENTIFIER(name)->name);
999     if (!SCM_MODULEP(mod)) Scm_Error("module required, but got %S", mod);
1000     ScmSyntaxRules *sr = compile_rules(name, ellipsis, literals, rules,
1001                                        SCM_MODULE(mod), env);
1002     ScmObj sr_xform = Scm_MakeSubr(synrule_transform, sr,
1003                                    2, 0, SCM_FALSE);
1004     return Scm_MakeMacro(name, sr_xform, src, SCM_FALSE);
1005 }
1006 
1007 /*===================================================================
1008  * macro-expand
1009  */
1010 
1011 /* TRANSIENT
1012    Now it's in compile.scm (%internal-macro-expand).  This is kept
1013    for ABI compatibility, but nobody is supposed to call this.
1014  */
1015 #if GAUCHE_API_VERSION < 1000
Scm_VMMacroExpand(ScmObj expr SCM_UNUSED,ScmObj env SCM_UNUSED,int oncep SCM_UNUSED)1016 ScmObj Scm_VMMacroExpand(ScmObj expr SCM_UNUSED,
1017                          ScmObj env SCM_UNUSED,
1018                          int oncep SCM_UNUSED)
1019 {
1020     Scm_Error("Scm_VMMacroExpand is obsoleted.");
1021     return SCM_UNDEFINED;
1022 }
1023 #endif /*GAUCHE_API_VERSION < 1000*/
1024 
Scm_CallMacroExpander(ScmMacro * mac,ScmObj expr,ScmObj cenv)1025 ScmObj Scm_CallMacroExpander(ScmMacro *mac, ScmObj expr, ScmObj cenv)
1026 {
1027     SCM_ASSERT(SCM_VECTORP(cenv));
1028     return Scm_ApplyRec2(mac->transformer, expr, cenv);
1029 }
1030 
1031 /*===================================================================
1032  * Initializer
1033  */
1034 
Scm__InitMacro(void)1035 void Scm__InitMacro(void)
1036 {
1037     Scm_InitStaticClass(&Scm_SyntaxPatternClass, "<syntax-pattern>",
1038                         Scm_GaucheInternalModule(), NULL, 0);
1039 }
1040