2015-06-12 Basile Starynkevitch <basile@starynkevitch.net>
[official-gcc.git] / gcc / melt / warmelt-moremacro.melt
blob53b5a30707878c7437c3987f6f67b07b418a1050
1 ;; file warmelt-moremacro.melt -*- Lisp -*-
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 (comment "***
4     Copyright 2008 - 2014  Free Software Foundation, Inc.
5     Contributed by Basile Starynkevitch <basile@starynkevitch.net>
7     This file is part of GCC.
9     GCC is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 3, or (at your option)
12     any later version.
14     GCC is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
19     You should have received a copy of the GNU General Public License
20     along with GCC; see the file COPYING3.  If not see
21     <http://www.gnu.org/licenses/>.
22 ***")
24 ;; the copyright notice above apply both to warmelt-moremacro.melt and 
25 ;; to the generated files warmelt-moremacro*.c
28 ;; This MELT module is GPL compatible since it is GPLv3+ licensed.
29 (module_is_gpl_compatible "GPLv3+")
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 ;;    This file is part of a bootstrapping compiler for the MELT lisp
34 ;;    dialect, compiler which should be able to compile itself (into
35 ;;    generated C file[s])
36 ;;    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38 ;; this file should define macros which are used only later in
39 ;; warmelt* files...
41 ;; the each_component_in_list macro has to be in a file after the
42 ;; expand_tuple_slice_as_tuple function
44 (defmacro each_component_in_list (sexp env mexpander modctx)
45   :doc #{Macro $EACH_COMPONENT_IN_LIST to be invoked with a
46   list-giving @var{expr} and a local variable @var{compvar} expands into
47   @code{(foreach_pair_component_in_list (@var{expr}) 
48                                         (@var{curpairvar} @var{compvar}) @var{body...})} 
49   where @var{curpairvar} is fresh.}#
50   (debug "each_component_in_list macro sexp=" sexp "\n env=" debug_less env)
51   (let (
52         (sloc (get_field :loca_location sexp))
53         (sexcont (get_field :sexp_contents sexp))
54         )
55     (debug "each_component_in_list sloc=" debug_less sloc " sexcont=" sexcont)
56     (assert_msg "check sexcont" (is_list sexcont) sexcont)
57     (let ( 
58           (tcont (list_to_multiple sexcont discr_multiple))
59           (:long tcontlen (multiple_length tcont))
60           )
61       (debug "each_component_in_list tcont=" tcont "; tcontlen=" tcontlen)
62       (assert_msg "check tcont" (is_multiple tcont) tcont sexcont)
63       (assert_msg "check tcontlen" (>i tcontlen 0) tcontlen tcont)
64       (when (<i tcontlen 4)
65         (error_plain sloc "EACH_COMPONENT_IN_LIST <expr-list> <var-comp> too short")
66         (return () ()))
67       (let ( 
68             (sexplist (let ( (se (multiple_nth tcont 1)) 
69                              )
70                         (debug "each_component_in_list sexplist=" se)
71                         se))
72             (svarcomp  (let ( (sv (multiple_nth tcont 2))
73                               )
74                          (debug "each_component_in_list svarcomp=" sv)
75                          sv))
76             (mlistexp (let ( (me (mexpander sexplist env mexpander modctx))
77                              )
78                         (debug "each_component_in_list mlistexp=" me)
79                         me))
80             (mvarcomp  (let ( (mv (mexpander svarcomp env mexpander modctx))
81                               )
82                          (debug "each_component_in_list mvarcomp=" mv)
83                          mv))
84             (bodyexp (progn 
85                        (debug "each_component_in_list tcont=" tcont
86                               "\n.. before expand_tuple_slice_as_tuple=" expand_tuple_slice_as_tuple)
87                        (let ( (be (expand_tuple_slice_as_tuple tcont 3 -1 env mexpander modctx))
88                               )
89                        (debug "each_component_in_list bodyexp=" be)
90                        be)))
91             )
92         (when (is_not_a mvarcomp class_symbol)
93           (error_plain sloc "EACH_COMPONENT_IN_LIST <expr-list> <var-comp> bad second argument for component variable")
94           (return () ()))
95         (with_cloned_symb 
96          (curpairinlistsymb)
97          (let ( (resexp
98                  `(foreach_pair_component_in_list 
99                    (,mlistexp)
100                    (,curpairinlistsymb ,mvarcomp)
101                    ,bodyexp))
102                 )
103            (debug "each_component_in_list resexp=" resexp)
104            (let ( (mexp (mexpander resexp env mexpander modctx))
105                   )
106              (put_fields mexp :loca_location sloc)
107              (debug "each_component_in_list final mexp=" mexp)
108              (return mexp)
109              )
110            ))))))
112 (export_macro each_component_in_list)
113 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
114 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
115 ;;; gccif support
116 (defun filtergccversion (versionstr)
117   (assert_msg "check versionstr" (is_string versionstr) versionstr )
118   (let ( (:long versionlen (string_length versionstr))
119          (res ())
120          (:cstring gccverstr "?")
121          (:cstring gccverest "-?-")
122          )
123     ;;; versionstr should be e.g. "4.9" or "4.8"
124     ;;; melt_gccversionstr starts with e.g. "4.8 20140217" for a plugin
125     ;;; or "4.9.0 20140226" for a MELT branch
126     (code_chunk 
127      filtergcc
128      #{ /* filtergccversion $FILTERGCC*/
129         $GCCVERSTR = melt_gccversionstr;
130         $GCCVEREST = melt_gccversionstr+$VERSIONLEN;
131         if ($VERSIONLEN>0
132             && !strncmp (melt_string_str((melt_ptr_t)$VERSIONSTR),
133                          melt_gccversionstr,
134                          $VERSIONLEN)
135             && !ISDIGIT (melt_gccversionstr[$VERSIONLEN]))
136         $RES = $VERSIONSTR; 
137         }#)
138     (debug "filtergccversion versionlen=" versionlen " versionstr=" versionstr
139            " gccverstr='" gccverstr "'; gccverest='" gccverest "'\n.. res=" res)
140     (return res)))
142 ;;;;
143 (defun mexpand_gccif (sexpr env mexpander modctx)
144   (assert_msg "check sexpr" (is_a sexpr class_sexpr) sexpr)
145   (assert_msg "check env" (is_a env class_environment) env)
146   (debug "mexpand_gccif sexpr=" sexpr)
147   (let (
148         (cont (unsafe_get_field :sexp_contents sexpr))
149         (sloc  (unsafe_get_field :loca_location sexpr))
150         (curpair (pair_tail (list_first cont)))
151         (curif (pair_head curpair)) 
152         (restpair (pair_tail curpair))
153         )
154     (debug "mexpand_gccif restpair=" restpair "\n.. first curif=" curif)
155     (if (is_a curif class_sexpr)
156         (let ( (xcurif (get_field :sexp_contents curif))
157                )
158           (debug "mexpand_gccif xcurif=" xcurif " sloc=" debug_less sloc)
159           (setq curif xcurif)
160           ))
161     (cond 
162      ((is_string curif)
163       (debug "mexpand_gccif string curif=" curif " sloc=" debug_less sloc)
164       (cond ((filtergccversion curif)
165              (debug "mexpand_gccif filtered curif=" curif)
166              (let ( (exprestlist (expand_pairlist_as_list restpair env mexpander modctx))
167                     )
168                (debug "mexpand_gccif stringy exprestlist=" exprestlist)
169             (let ( (expfirst (list_first_element exprestlist))
170                    (exptail (progn (list_pop_first exprestlist) exprestlist))
171                    )
172               (debug "mexpand_gccif stringy return expfirst=" expfirst " exptail=" exptail)
173               (return expfirst exptail)))
174              )
175         (:else
176           (debug "mexpand_gccif gcc version mismatched curif=" curif " sloc=" debug_less sloc)
177           (return))))
178      ((is_list curif)
179       (debug "mexpand_gccif list curif=" curif " sloc=" debug_less sloc)
180       (let ( (ok ())
181              )
182         (foreach_pair_component_in_list 
183          (curif)
184          (curpair curstr)
185          (if (not (is_string curstr))
186              (error_plain sloc "GCCIF condition not a list of strings"))
187          (if (filtergccversion curstr)
188              (setq ok :true))
189          )
190         (debug "mexpand_gccif ok=" ok " sloc=" debug_less sloc)
191         (if ok
192             (let ( (exprestlist (expand_pairlist_as_list restpair env mexpander modctx))
193                    )
194               (debug "mexpand_gccif multicond exprestlist=" exprestlist
195                      " sloc=" debug_less sloc)
196               (let ( (expfirst (list_first_element exprestlist))
197                      (exptail (progn (list_pop_first exprestlist)
198                                      exprestlist))
199                      )
200                 (debug "mexpand_gccif multicond  return expfirst=" expfirst
201                        "\n.. exptail=" exptail)
202                 (shortbacktrace_dbg "mexpand_gccif multicond" 8)
203                 (return expfirst exptail))
204               )
205           (progn
206             (debug "mexpand_gccif sexpr gcc version multicond mismatched" sexpr)
207             (return))))
208       )
209      (:else 
210       (error_plain sloc "GCCIF bad condition, should be a string or a list of strings")
211       (return)
212       ))))
214 (install_initial_macro 'gccif mexpand_gccif)
215 (export_macro gccif mexpand_gccif
216  :doc #{The $GCCIF macro expands the rest of the expression if the
217 version string of the GCC translating this MELT expression matches the
218 condition. Syntax is ($GCCIF condition expr...), where the condition
219 is a constant string such as "4.8" for @code{gcc-4.8} or a list of
220 such strings.}#)
222 ;;;;;;;;;;;;;;;;
223 ;;;; obsolete CONTAINER same as REFERENCE
225 (defun mexpandobsolete_container (sexpr env mexpander modctx)
226   (debug "mexpandobsolete_container sexpr=" sexpr)
227   (assert_msg "check sexpr" (is_a sexpr class_sexpr) sexpr)
228   (warning_plain (get_field :loca_location sexpr)
229                  "obsolete use of CONTAINER in expression; use REFERENCE instead")
230   (mexpand_reference sexpr env mexpander modctx))
232 (defun patexpandobsolete_container (sexpr env pctx)
233   (debug "patexpandobsolete_container sexpr=" sexpr)
234   (assert_msg "check sexpr" (is_a sexpr class_sexpr) sexpr)
235   (warning_plain (get_field :loca_location sexpr)
236                  "obsolete use of CONTAINER in pattern; use REFERENCE instead")
237   (patexpand_reference sexpr env pctx))
238   
239 (install_initial_patmacro 'container patexpandobsolete_container mexpandobsolete_container)
240 (export_patmacro container patexpandobsolete_container mexpandobsolete_container
241  :doc #{The $CONTAINER syntax for expressions or patterns is obsolete. Use $REFERENCE instead}#)
244 ;;;;;;;; for QUOTE 
245 ;; utility to expand an s-expression into a suitable invocation of melt_make_sexpr
246 (defun expand_quoted_sexpr (sexpr env antiquotefun mexpander modctx)
247   (debug "expand_quoted_sexpr sexpr=" sexpr)
248   (assert_msg "check sexpr" (is_a sexpr class_sexpr) sexpr)
249   (assert_msg "check env" (is_a env class_environment) env)
250   (assert_msg "check modctx" (is_object modctx) modctx)
251   (let ( (cont (unsafe_get_field :sexp_contents sexpr))
252          (loc  (unsafe_get_field :loca_location sexpr))
253          (:long dline (get_int loc))
254          (dfilnam (cond
255                    ((is_mixint loc) (mixint_val loc))
256                    ((is_mixloc loc) (mixloc_val loc))))
257          (locexp (instance class_source_hook_call
258                            :loca_location loc
259                            :shook_called hook_melt_make_location
260                            :sargop_args (tuple dfilnam (constant_box dline))))
261          (arglist (make_list discr_list))
262          )
263     (debug "expand_quoted_sexpr dline=" dline " dfilnam=" dfilnam)
264     (foreach_pair_component_in_list
265      (cont)
266      (curpair curcomp)
267      (debug "expand_quoted_sexpr curcomp=" curcomp "\n.. arglist=" arglist)
268      (cond ( (null curcomp)
269              (list_append arglist ())
270              )
271            ( (is_integerbox curcomp)
272              (list_append arglist curcomp))
273            ( (is_string curcomp)
274              (list_append arglist curcomp))
275            ( (is_a curcomp class_keyword)
276              (list_append arglist curcomp))
277            ( (is_a curcomp class_symbol)
278              (let ( (qsymb (instance class_source_quote
279                                      :loca_location loc
280                                      :squoted curcomp))
281                     )
282                (list_append arglist qsymb)))
283            ( (is_a curcomp class_sexpr)
284              (if (is_closure antiquotefun)
285                  (let ( (curloc (unsafe_get_field :loca_location curcomp))
286                         (curcont (unsafe_get_field :sexp_contents curcomp))
287                         )
288                    (if (and 
289                         (==i (list_length curcont) 2)
290                         (== (list_first_element curcont) 'comma))
291                        (let ( (commaexp (list_nth_element curcont 1))
292                               )
293                          (debug "expand_quoted_sexpr commaexp=" commaexp " curloc=" curloc)
294                          (antiquotefun commaexp arglist curloc env mexpander modctx)
295                          (debug "expand_quoted_sexpr after antiquotefun arglist=" arglist)
296                          )
297                      (list_append arglist (expand_quoted_sexpr curcomp env antiquotefun mexpander modctx))))
298                (list_append arglist (expand_quoted_sexpr curcomp env antiquotefun mexpander modctx))
299                ))
300            ;; the below cases don't happen for expressions which have
301            ;; been read, only for computed s-exprs...
302            ( (is_list curcomp)
303              (list_append2list arglist curcomp))
304            ( (is_multiple curcomp)
305              (foreach_in_multiple
306               (curcomp)
307               (subcomp :long ix)
308               (list_append arglist subcomp)))
309            (:else
310             (list_append arglist curcomp))
311            )
312      )                                  ; end foreach_pair_component_in_list
313     (debug "expand_quoted_sexpr arglist=" arglist)
314     (list_prepend arglist locexp)
315     (debug "expand_quoted_sexpr final arglist=" arglist)
316     (let ( (xexp (instance class_source_apply
317                            :loca_location loc
318                            :sapp_fun 'melt_make_sexpr
319                            :sargop_args (list_to_multiple arglist discr_multiple)))
320            )
321       (debug "expand_quoted_sexpr result xexp=" xexp)
322       (return xexp)
323       )
324     )
325   )
327 (defun mexpand_quote (sexpr env mexpander modctx)
328   (assert_msg "check sexpr" (is_a sexpr class_sexpr) sexpr)
329   (assert_msg "check env" (is_a env class_environment) env)
330   (assert_msg "check modctx" (is_object modctx) modctx)
331   (let ( (cont (unsafe_get_field :sexp_contents sexpr))
332          (loc  (unsafe_get_field :loca_location sexpr))
333          (curpair (pair_tail (list_first cont))) 
334          (quoted (pair_head curpair))
335          )
336     (when (pair_tail curpair)
337       (debug "mexpand_quote polyarg sexpr=" sexpr " cont=" cont)
338       (unless (is_a sexpr class_sexpr_macrostring)
339         (warning_at loc "QUOTE used with $1 arguments outside of macro-string [as $2], consider using antiquotations"
340                     (list_length cont) sexpr))
341       (let (
342             (restlist (make_list_from_pair discr_list curpair))
343             (newsexpr (instance class_sexpr_macrostring :sexp_contents restlist :loca_location loc))
344             (expmquo (expand_quoted_sexpr newsexpr env () mexpander modctx))
345              )
346         (debug "mexpand_quot polyarg sexpr=" sexpr " newsexpr=" newsexpr " result expmquo=" expmquo)
347         (return expmquo)
348         )      
349       )
350     (cond ( (is_a quoted class_symbol) 
351             ()
352             )
353           ( (is_string quoted)
354             ()
355             )
356           ( (is_integerbox quoted)
357             ()
358             )
359           ( (is_a quoted class_source)
360             (debug "mexpand_quote sexpr return source=" quoted)
361             (return quoted))
362           ( (is_a quoted class_sexpr)
363               (debug "mexpand_quote sexpr quoted=" quoted)
364             (let ( (expquo (expand_quoted_sexpr quoted env () mexpander modctx))
365                    )
366               (debug "mexpander expquo=" expquo)
367               (return expquo)))
368           (:else
369            (error_at loc "QUOTE should have a symbol, string, or integer or s-expr argument bit is $1" cont))
370           )
371     (if (is_a quoted class_keyword)
372         (return quoted))
373     (let ( (squ (instance class_source_quote
374                           :loca_location loc
375                           :squoted quoted)) )
376       (return squ)
377       )))
378 (install_initial_macro 'quote mexpand_quote)
379 (export_macro
380  quote mexpand_quote
381  :doc #{The $QUOTE syntax (usually noted with a prefix quote-character
382  @code{'}) is for quotations. A quoted literal reifies a value, so
383  @code{'2} is a value of $DISCR_CONSTANT_INTEGER. A quoted
384  s-expression invokes $MELT_MAKE_SEXPR using
385  $HOOK_MELT_MAKE_LOCATION.}#)
388 ;; could be passed to expand_quoted_sexpr for future
389 ;; mexpand_backquote; the result of antiquoter is ignored, but it
390 ;; usually updates the arglist.
391 (defun antiquoter (aexp arglist loc env mexpander modctx)
392   (debug "antiquoter aexp=" aexp " arglist=" arglist)
393   (shortbacktrace_dbg "antiquoter" 15)
394   (let ( (mexp (mexpander aexp env mexpander modctx))
395          )
396     (debug "antiquoter mexp=" mexp)
397     (list_append arglist mexp)
398     )
399   (debug "antiquoter ends with arglist=" arglist))
404 ;;;;;;; for BACKQUOTE
405 (defun mexpand_backquote (sexpr env mexpander modctx)
406   (debug "mexpand_backquote sexpr=" sexpr)
407   (let ( (cont (unsafe_get_field :sexp_contents sexpr))
408          (loc  (unsafe_get_field :loca_location sexpr))
409          (curpair (pair_tail (list_first cont))) 
410          (backquoted (pair_head curpair))
411          )
412     (if (pair_tail curpair)
413         (error_plain loc "BACKQUOTE should have only one argument"_))
414     (cond ( (is_a backquoted class_sexpr)
415             (debug "mexpand_backquote backquoted sexpr " backquoted)
416             (let ( (expbk (expand_quoted_sexpr backquoted env antiquoter mexpander modctx))
417                    )
418               (debug "mexpand_backquote result expbk=" expbk)
419               (return expbk)
420               ))
421           (:else
422            (debug "mexpand_backquote backquoted return verbatim " backquoted)
423            (return backquoted)))
424     ))
425 (install_initial_macro 'backquote mexpand_backquote)
426 (export_macro
427  backquote mexpand_backquote
428  :doc #{The $BACKQUOTE macro is expanding into an s-expr, except for
429 $COMMA It is often noted with a prefix backquote-character
430 @code{`}....}# )
434 ;;;;;;; for COMMA
435 (defun mexpand_comma (sexpr env mexpander modctx)
436   (debug "mexpand_comma sexpr=" sexpr)
437   (let ( (cont (unsafe_get_field :sexp_contents sexpr))
438          (loc  (unsafe_get_field :loca_location sexpr))
439          (curpair (pair_tail (list_first cont))) 
440          )
441     (error_plain loc "COMMA outside of BACKQUOTE-d expression")
443 (install_initial_macro 'comma mexpand_comma)
444 (export_macro
445  comma mexpand_comma
446  :doc #{The $COMMA macro is related to $BACKQUTE.
447 $COMMA It is often noted with a prefix comma-character
448 @code{,}....}# )
451 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
452 ;;; utility function, e.g. to substitute *some* symbols in macrostrings.
453 (defun substitute_sexpr (sexpr symbrepf insidef)
454   :doc #{The $SUBSTITUTE_SEXPR is substituting some symbols inside the
455   given $SEXPR. Each symbol inside $SEXPR is passed to the $SYMBREPF
456   function which can return a list or a tuple to be replaced by
457   @i{several} -or none- elements. When a component of $SEXPR is itself
458   an s-expression, the function $INSIDEF, if given, decides -by
459   returning non-nil- if the substitution goes inside recursively. By
460   default the substitution does not recurse inside inner
461   sub-s-expressions.}#
462   (debug "substitute_sexpr" " sexpr=" sexpr)
463   (when (is_not_a sexpr class_sexpr)
464     (debug "substitute_sexpr" " not an S-expr:" sexpr)
465     (return sexpr))
466   (let ( (clist (make_list discr_list))
467          (cont (unsafe_get_field :sexp_contents sexpr))
468          (loc (unsafe_get_field :loca_location sexpr))
469          (newsexpr (if (is_a sexpr class_sexpr_macrostring)
470                        (instance class_sexpr_macrostring
471                                  :loca_location loc
472                                  :sexp_contents clist)
473                      (instance class_sexpr
474                                :loca_location loc
475                                :sexp_contents clist)))
476          )
477     (each_component_in_list
478      cont
479      curcont
480      (debug "substitute_sexpr" " curcont=" curcont)
481      (cond
482       ( (is_a curcont class_keyword)
483         (list_append clist curcont))
484       ( (is_a curcont class_symbol)
485         (let ( (repsymb (if (is_closure symbrepf)
486                             (symbrepf curcont)
487                           curcont))
488                )
489           (cond
490            ( (is_multiple repsymb)
491              (foreach_in_multiple
492               (repsymb)
493               (currep :long rix)
494               (list_append clist currep)
495               )
496              (void)
497              )
498            ( (is_list repsymb)
499              (each_component_in_list
500               repsymb
501               curlrep
502               (list_append clist curlrep))
503              (void))
504            (:else
505             (list_append clist repsymb))))
506         )
507       ( (is_a curcont class_sexpr)
508         (let (
509               (insidev (if (is_closure insidef) (insidef curcont)))
510               (replcont (if insidev (substitute_sexpr curcont symbrepf insidef) curcont))
511               )
512           (cond
513            ( (is_multiple replcont)
514              (foreach_in_multiple
515               (insidev)
516               (curins :long insix)
517               (list_append clist curins)))
518            ( (is_list replcont)
519              (each_component_in_list
520               replcont
521               subcont
522               (list_append clist subcont)))
523            (:else
524             (list_append clist replcont)))
525           )
526         )
527       (:else
528        (list_append clist curcont)
529        )
530       )
531      )
532     ;;
533     (debug "substitute_sexpr" " result newsexpr=" newsexpr)
534     (return newsexpr)
535     )
536   )
537 (export_values substitute_sexpr)
538 ;; eof warmelt-moremacro.melt