; file warmelt-normatch.melt -*- Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (comment "*** Copyright 2008 - 2014 Free Software Foundation, Inc. Contributed by Basile Starynkevitch This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . ***") ;; the copyright notice above apply both to warmelt-normatch.melt and ;; to the generated file warmelt-normatch*.c ;; This MELT module is GPL compatible since it is GPLv3+ licensed. (module_is_gpl_compatible "GPLv3+") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This file is part of a bootstrapping compiler for the MELT lisp ;; dialect, compiler which should be able to compile itself (into ;; generated C file[s]) ;;; class for the context of normalization of patterns (defclass class_pattern_context :super class_root :doc #{The $CLASS_PATTERN_CONTEXT is for context of patterns' normalization. $PCTN_NORMCTXT is the $CLASS_NORMALIZATION_CONTEXT. $PCTN_SRC is the source match expression. $PCTN_MAPATVAR is the mapping from symbols to pattern variables. $PCTN_MAPATCNST is the mapping from constant objects to pattern constants. $PCTN_MAPOR is the mapping from or source patterns to their map of symbols to pattern variables. $PCTN_BINDLIST is the binding list for input arguments in matcher. $PCTN_STUFFMAP is the mapping from a matched stuff to the list of normaltesters matching it. $PCTN_PVARLOCMAP maps pattern variable symbols to local occurrences. $PCTN_TESTS is the list of normal testers. $PCTN_VARHANDERS is a list of pattern variable handler when scanning variables.}# :fields (pctn_normctxt ;the class_normalization_context pctn_src ;the source match expression pctn_env ;the current environment ;; mapping symbols to patternvars pctn_mapatvar ;objmap of patternvars ;; mapping constant objects to their patternconsts pctn_mapatcst ;objmap of patternconst ;; mapping or source patterns to their map of symbols to patternvars pctn_mapor ;; binding list for input arguments in matcher pctn_bindlist ;binding list ;; mapping matched stuff with list of normtesters pctn_stuffmap ;; mapping pattern variable symbols to local occurrences pctn_pvarlocmap ;; list of tests pctn_tests ;; list of pattern variables handlers when scanning pctn_varhandlers )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; selector to scan a pattern ;;; invoked with : ;;; * the source pattern as receiver ;;; * a parent source location ;;; * a ctype ;;; * a normpatcontext (defselector scan_pattern class_selector ) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; catch-all for scanning any receiver (by failing) (defun scanpat_anyrecv (recv psloc ctyp pcn) (debug "scanpat_anypattern recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (let ( (myclass (discrim recv)) (myclassname (get_field :named_name myclass)) ) (error_strv psloc "unimplemented scan_pattern for any " myclassname) (assert_msg "catchall scan_pattern unimplemented for any receiver" ()) )) (install_method discr_any_receiver scan_pattern scanpat_anyrecv) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; catch-all for scanning any pattern (by failing) (defun scanpat_anypattern (recv psloc ctyp pcn) (debug "scanpat_anypattern recv" recv) (assert_msg "check recv" (is_a recv class_source_pattern)) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (let ( (myclass (discrim recv)) (myclassname (get_field :named_name myclass)) ) (debug "scanpat_anypattern myclass [discrim of recv]" myclass) (error_strv psloc "unimplemented scan_pattern for pattern " myclassname) (assert_msg "catchall scan_pattern unimplemented for pattern" ()) )) (install_method class_source_pattern scan_pattern scanpat_anypattern) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning pattern variable (defun scanpat_srcpatvar (recv psloc ctyp pcn) (debug "scanpat_srcpatvar recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_variable)) (let ( (sloc (unsafe_get_field :loca_location recv)) (svar (unsafe_get_field :spatvar_symb recv)) (mapvar (unsafe_get_field :pctn_mapatvar pcn)) (varhdlerlist (unsafe_get_field :pctn_varhandlers pcn)) (mvar (mapobject_get mapvar svar)) ) (cond ( (null mvar) (mapobject_put mapvar svar recv) (debug "scanpat_srcpatvar return new svar" svar) (setq mvar recv) ) (:else (debug "scanpat_srcpatvar return found mvar" mvar) )) (assert_msg "check mvar" (is_a mvar class_source_pattern_variable)) (let ( (nboccbox (unsafe_get_field :spatvar_nbocc mvar)) (:long nbocc (get_int nboccbox)) ) (put_int nboccbox (+i nbocc 1))) (foreach_pair_component_in_list (varhdlerlist) (curpair curhdler) (if (is_closure curhdler) (curhdler mvar pcn recv))) )) (install_method class_source_pattern_variable scan_pattern scanpat_srcpatvar) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning pattern joker (defun scanpat_srcpatjoker (recv psloc ctyp pcn) (debug "scanpat_srcpatjoker recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_joker_variable)) ;; just return (return) ) (install_method class_source_pattern_joker_variable scan_pattern scanpat_srcpatjoker) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning a pattern constant (defun scanpat_srcpatconstant (recv psloc ctyp pcn) (debug "scanpat_srcpatconst recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_constant)) (let ( (sconst (unsafe_get_field :spat_constx recv)) (sloc (unsafe_get_field :loca_location recv)) (ncx (unsafe_get_field :pctn_normctxt pcn)) (mapcst (unsafe_get_field :pctn_mapatcst pcn)) (mcst (if (is_object sconst) (mapobject_get mapcst sconst))) (ncst mcst) (bindlist (unsafe_get_field :pctn_bindlist pcn)) (env (unsafe_get_field :pctn_env pcn)) ) (assert_msg "check bindlist" (is_list bindlist)) (cond ( (not (is_object sconst)) (debug "scanpat_srcpatconstant nonobj literal const" sconst) (setq ncst sconst) ) ( (null mcst) (multicall (nconst nbindconst) (normal_exp sconst env ncx sloc) (debug "scanpat_srcpatconstant nconst" nconst) (mapobject_put mapcst sconst nconst) (if nbindconst (list_append2list bindlist nbindconst)) (setq ncst nconst) )) (:else (debug "scanpat_srcpatconstant got mcst" mcst) )) (debug "scanpat_srcpatconstant ncst" ncst) (let ( (rectyp (get_ctype ncst env)) ) (debug "scanpat_srcpatconstant rectyp" rectyp) (assert_msg "check rectyp" (is_a rectyp class_ctype)) (cond ((!= rectyp ctyp) (error_strv sloc "invalid ctype in constant pattern - expecting" (unsafe_get_field :named_name rectyp)) (warning_strv sloc "got ctype" (unsafe_get_field :named_name ctyp)) (warning_plain (get_field :loca_location (get_field :pctn_src pcn)) "perhaps this MATCH expression is badly parenthesised") )) ))) (install_method class_source_pattern_constant scan_pattern scanpat_srcpatconstant) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning a pattern construct (defun scanpat_srcpatconstruct (recv psloc ctyp pcn) (debug "scanpat_srcpatconstruct recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_construct)) (let ( (sloc (unsafe_get_field :loca_location recv)) (subpa (unsafe_get_field :ctpat_subpa recv)) (ncx (unsafe_get_field :pctn_normctxt pcn)) ) (assert_msg "check ctyp is value" (== ctyp ctype_value)) (foreach_in_multiple (subpa) (cursubpa :long subix) (debug "scanpat_srcpatconstruct before scan_pattern cursubpa=" cursubpa " subix=" subix) (scan_pattern cursubpa sloc ctype_value pcn) (debug "scanpat_srcpatconstruct after scan_pattern cursubpa=" cursubpa " subix=" subix) ) (debug "scanpat_srcpatconstruct done subpa=" subpa) )) (install_method class_source_pattern_construct scan_pattern scanpat_srcpatconstruct) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning a pattern object or instance (defun scanpat_srcpatobject (recv psloc ctyp pcn) (debug "scanpat_srcpatobject recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_object)) (let ( (sloc (unsafe_get_field :loca_location recv)) (scla (unsafe_get_field :spat_class recv)) (sfields (unsafe_get_field :spat_fields recv)) ) (assert_msg "check scla" (is_a scla class_class)) (assert_msg "check sfields" (is_multiple sfields)) (foreach_in_multiple (sfields) (fldpa :long ix) (assert_msg "check fldp" (is_a fldpa class_source_field_pattern)) (let ( (fld (let ( ( f (get_field :spaf_field fldpa)) ) (assert_msg "check fld" (is_a f class_field)) f)) (flcla (get_field :fld_ownclass fld)) (fpat (unsafe_get_field :spaf_pattern fldpa)) ) (cond ( (not (subclass_or_eq scla flcla)) (error_strv sloc "bad field in object pattern" (unsafe_get_field :named_name fld)) (inform_strv sloc "class in pattern is" (get_field :named_name scla)) (inform_strv sloc "class of field is" (get_field :named_name flcla)) (return))) (scan_pattern fpat sloc ctype_value pcn) ) ) (debug "scanpat_srcpatobject end recv" recv) ) ) (install_method class_source_pattern_object scan_pattern scanpat_srcpatobject) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning a composite pattern (defun scanpat_srcpatcomposite (recv psloc ctyp pcn) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (debug "scanpat_srcpatcomposite start recv=" recv " ctyp=" ctyp) (assert_msg "check ctyp" (is_a ctyp class_ctype)) (assert_msg "check recv" (is_a recv class_source_pattern_composite)) (let ( (sloc (unsafe_get_field :loca_location recv)) (soper (let ((sop (unsafe_get_field :spac_operator recv))) (debug "scanpat_srcpatcomposite soper" sop) (assert_msg "check soper" (is_a sop class_any_matcher)) sop)) (sins (unsafe_get_field :spac_inargs recv)) (souts (unsafe_get_field :spac_outargs recv)) (matmb (let ( (mb (unsafe_get_field :amatch_matchbind soper)) ) (debug "scanpat_srcpatcomposite matmb" mb) (assert_msg "check matmb" (is_a mb class_formal_binding)) mb)) (matin (unsafe_get_field :amatch_in soper)) (matout (unsafe_get_field :amatch_out soper)) (opnam (unsafe_get_field :named_name soper)) (matctyp (unsafe_get_field :fbind_type matmb)) (env (unsafe_get_field :pctn_env pcn)) (ncx (unsafe_get_field :pctn_normctxt pcn)) (bindlist (unsafe_get_field :pctn_bindlist pcn)) ) (assert_msg "check matctyp" (is_a matctyp class_ctype)) (debug "scanpat_srcpatcomposite matout" matout) (cond ((!= ctyp matctyp) (error_strv sloc "invalid ctype in composite pattern - expecting" (unsafe_get_field :named_name matctyp)) (warning_strv sloc "got ctype" (unsafe_get_field :named_name ctyp)) (debug "scanpat_srcpatcomposite mismatched ctyp=" ctyp " matctyp=" matctyp " mismatched recv=" recv) ;; (return))) (multicall (nins bindins) (normalize_tuple sins env ncx sloc) (debug "scanpat_srcpatcomposite nins" nins) (if bindins (list_append2list bindlist bindins)) (debug "scanpat_srcpatcomposite souts=" souts " matout=" matout) (foreach_in_multiple (souts) (pout :long ix) (debug "scanpat_srcpatcomposite before scan_pattern pout" pout) (let ( (curobind (multiple_nth matout ix)) (curctype (get_field :fbind_type curobind)) ) (debug "scanpat_srcpatcomposite curobind=" curobind " curctype=" curctype) (assert_msg "check curctype" (is_a curctype class_ctype)) (scan_pattern pout sloc curctype pcn) (debug "scanpat_srcpatcomposite after scan_pattern pout" pout) )) (debug "scanpat_srcpatcomposite end recv" recv) ))) (install_method class_source_pattern_composite scan_pattern scanpat_srcpatcomposite) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning or pattern (defun scanpat_srcpator (recv psloc ctyp pcn) (debug "scanpat_srcpator recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_or)) (debug "scanpat_srcpator pcn start" pcn) (let ( (sloc (unsafe_get_field :loca_location recv)) (sdisj (unsafe_get_field :orpat_disj recv)) (pvarmap (unsafe_get_field :pctn_mapatvar pcn)) (:long cntpvarmap (mapobject_count pvarmap)) (ownvarmap (make_mapobject discr_map_objects (+i 4 (*i cntpvarmap 2)))) (varhdlerlist (unsafe_get_field :pctn_varhandlers pcn)) (ownvarhandler (lambda (mvar mypcn pvar) (debug "scanpat_srcpator.ownvarhandler mvar" mvar) (assert_msg "check mvar" (is_a mvar class_source_pattern_variable)) (assert_msg "check mypcn" (== mypcn pcn)) (let ( (msymb (unsafe_get_field :spatvar_symb mvar)) ) (mapobject_put ownvarmap msymb mvar)) )) (inipvarmap (let ( (inimap (make_mapobject discr_map_objects (+i 3 (/i (*i cntpvarmap 5) 4)))) ) (foreach_in_mapobject (pvarmap) (cursym curpatvar) (mapobject_put inimap cursym curpatvar)) inimap)) ) (debug "scanpat_srcpator sdisj" sdisj) (assert_msg "check sdisj" (is_multiple sdisj)) (list_prepend varhdlerlist ownvarhandler) (foreach_in_multiple (sdisj) (dis :long ix) (debug "scanpat_srcpator dis" dis) (scan_pattern dis sloc ctyp pcn) ) (let ( (:long incrpvarmap (-i (mapobject_count pvarmap) cntpvarmap)) (pmapor (get_field :pctn_mapor pcn)) (orvarmap (make_mapobject discr_map_objects (+i 3 (/i (*i incrpvarmap 5) 4)))) (oldvarhdler (list_popfirst varhdlerlist)) ) (assert_msg "check pmapor" (is_mapobject pmapor)) (assert_msg "check oldvarhdler" (== oldvarhdler ownvarhandler)) ;; scan the updated pvarmap for new entries w.r.t. inipvarmap (foreach_in_mapobject (pvarmap) (cursym curpatvar) (assert_msg "check cursym" (is_a cursym class_symbol)) (assert_msg "check curpatvar" (is_a curpatvar class_source_pattern_variable)) (assert_msg "good curpatvar" (== (get_field :spatvar_symb curpatvar) cursym)) (if (null (mapobject_get inipvarmap cursym)) (mapobject_put orvarmap cursym curpatvar)) ) (debug "scanpat_srcpator orvarmap" orvarmap) (mapobject_put pmapor recv orvarmap) ) (debug "scanpat_srcpator end pcn=" pcn " recv=" recv) )) (install_method class_source_pattern_or scan_pattern scanpat_srcpator) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;; scanning and pattern (defun scanpat_srcpatand (recv psloc ctyp pcn) (debug "scanpat_srcpatand recv=" recv "\n ctyp=" ctyp "\n pcn=" pcn) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_and)) (let ( (sloc (unsafe_get_field :loca_location recv)) (sconj (unsafe_get_field :andpat_conj recv)) ) (assert_msg "check sconj" (is_multiple sconj)) (foreach_in_multiple (sconj) (dis :long ix) (debug "scanpat_srcpatand dis=" dis "\n ix=" ix) (scan_pattern dis sloc ctyp pcn) ) (debug "scanpat_srcpatand end recv=" recv) )) (install_method class_source_pattern_and scan_pattern scanpat_srcpatand) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; selector to normalize a pattern ;;; receiver is the pattern to normalize ;;; arguments are ;;; the normal matched stuff ;;; the closure (if any) to handle the newly created stuff -e.g. tester ;;; the pattern context (defselector normal_pattern class_selector) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defclass class_normal_or_variable :super class_root :fields ( norvar_norexp norvar_locsym norvar_patvar norvar_nrepor ) :doc #{The $CLASS_NORMAL_OR_VARIABLE is an internal class for normalization of variables under an $OR pattern. Field $NORVAR_PATVAR gives the associated pattern variable, field $NORVAR_NREPOR gives the normalized or pattern, and field $NORVAR_LOCSYM gives the local symbol occurrence if any. $NORVAR_NOREXP gives the normalized matched expression.}# ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; all the testers share a common superclass (defclass class_normtester_any :super class_nrep_expression ;inherit fields: nrep_loc :fields (ntest_matched ;normal matched thing ntest_then ;tester to run if successful ntest_else ;tester to run if failed ntest_normatch ;the containing normalized match ;; a list of class_nrep_locsymocc ntest_locclist ;the local occurence list inside the test ;; list of tests going into this one ntest_comefrom )) ;; final successful tester (always succeed) just evaluate the expression (defclass class_normtester_success :super class_normtester_any :fields (ntsuccess_do ;single expression (usually a normlet) )) ;; quasi-tester used at failing end of disjuncts to clear a list of variables (defclass class_normtester_or_clear :super class_normtester_any :fields (ntorclear_locsym ;tuple of symbol occurrences to clear )) ;; quasi-tester used at start of or to initialize & clear a list of variables (defclass class_normtester_or_initial_clear :super class_normtester_or_clear :fields ( )) ;; quasi-tester used at succeeding end of disjuncts to transmit a list of variables (defclass class_normtester_or_transmit :super class_normtester_any :fields (ntortransmit_dst ;tuple of locsymocc destinations ntortransmit_src ;tuple of [normal] sources )) ;; all real tests share this superclass (defclass class_normtester_anytester :super class_normtester_any :fields ( )) ;;; the tester wrapping or. Needed to share the same ntest_then ;;; between disjuncts (compile_warning "we probably need to compute the ntdisj_setorvar field somewhere") (defclass class_normtester_disjunction :super class_normtester_anytester :fields (ntdisjuncts ;the tuple of disjunct tests ntdisj_freshorvar ;the tuple of fresh or variables ntdisj_setorvar ;the tuple of already set or variables ) ) ;; test for same (ie identical) stuff (defclass class_normtester_same :super class_normtester_anytester :fields (ntsame_identical ;checked normal stuff )) ;; test for matcher (defclass class_normtester_matcher :super class_normtester_anytester :fields ( ntmatch_matcher ;the matcher ntmatch_matndata ;the marcher's normal data ;; both inargs & outlocs are normalized ntmatch_inargs ;its input arguments tuple ntmatch_outlocs ;its output locals )) ;; test for instance (defclass class_normtester_instance :super class_normtester_anytester :fields (ntinst_class ;the class ;; a tuple similar to the class's fields ntinst_fieldlocs ;the tuple of field locals or nil )) ;; test for tuples (defclass class_normtester_tuple :super class_normtester_anytester :fields ( ;; a tuple similar to the class's fields nttuple_components ;the tuple of components )) ;;;;;;;;;;;;;;;; (defclass class_nrep_match :super class_nrep_typed_expression :fields (nmatch_tests ;sequence of tests nmatch_stuffmap ;mapping matched stuff with ;list or normal tests nmatch_matched ;the normal matched stuff )) ;;;;;; utility function to register a new normtester (defun register_new_normtester (ntest pcn) (debug "register_new_normtester ntest=" ntest " pcn=" pcn) (assert_msg "check ntest" (is_a ntest class_normtester_any)) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (let ( (nmatched (unsafe_get_field :ntest_matched ntest)) (stuffmap (unsafe_get_field :pctn_stuffmap pcn)) ) (assert_msg "check nmatched" (is_object nmatched)) (assert_msg "check stuffmap" (is_mapobject stuffmap)) (let ( (ntlist (let ( (ntl (mapobject_get stuffmap nmatched)) ) (if (is_list ntl) ntl (let ( (newntl (make_list discr_list)) ) (mapobject_put stuffmap nmatched newntl) newntl) ))) ) (assert_msg "check ntlist" (is_list ntlist)) (list_append ntlist ntest) (debug "register_new_normtester updated stuffmap" stuffmap) (return) ))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; utility to set the then of a last test; also handle the case of ;; disjunctions by propagating into them (defun put_tester_then (curtester thentester) (debug "put_tester_then curtester=" curtester " thentester=" thentester) (assert_msg "check curtester" (is_a curtester class_normtester_any)) (assert_msg "check thentester" (is_a thentester class_normtester_any)) (assert_msg "check curtester has no then" (null (unsafe_get_field :ntest_then curtester))) (let ( (thencome (unsafe_get_field :ntest_comefrom thentester)) ) (assert_msg "check thencome" (is_list thencome)) (list_append thencome curtester)) (assert_msg "check curtester not a normtester success" (is_not_a curtester class_normtester_success)) (unsafe_put_fields curtester :ntest_then thentester) ;;; propagate into disjunctions (if (is_a curtester class_normtester_disjunction) (let ( (curdisjtuple (unsafe_get_field :ntdisjuncts curtester)) ) (debug "put_tester_then curdisjtuple" curdisjtuple) (foreach_in_multiple (curdisjtuple) (curdisj :long disjix) (debug "put_tester_then curdisj=" curdisj) (let ( (curcont (instance class_reference :referenced_value curdisj)) ) (debug "put_tester_then curcont start=" curcont) (set_new_tester_last_then thentester curcont) (debug "put_tester_then curcont done" curcont) )) )) (debug "put_tester_then curtester done" curtester) ) ;; utility to set the newtester to the last of a ntest_then linked list (defun set_new_tester_last_then (newtester testercont) (debug "set_new_tester_last_then newtester=" newtester " testercont=" testercont) (shortbacktrace_dbg "set_new_tester_last_then start" 15) (assert_msg "check newtester" (is_a newtester class_normtester_any)) (assert_msg "check testercont" (is_a testercont class_reference)) (let ( (curtester (get_field :referenced_value testercont)) ) (forever lastesterloop (debug "set_new_tester_last_then loop curtester" curtester) ;; indeed a safe get_field to handle the nil case! (let ( (nextester (get_field :ntest_then curtester)) ) (if (is_a nextester class_normtester_any) (setq curtester nextester) (exit lastesterloop)))) (debug "set_new_tester_last_then final curtester" curtester) (assert_msg "check curtester set_new_tester_last_then" curtester) (put_fields testercont :referenced_value curtester) (put_tester_then curtester newtester) (debug "set_new_tester_last_then end testercont" testercont) )) ;; recursive utility to set a newtester as all the unset else branches ;; of a given partester return the list of updated testers, ie the ;; updatlist - which should be null initially (defun set_new_tester_all_elses (newtester partester updatlist) (debug "set_new_tester_all_elses newtester=" newtester "\n.. partester" partester "\n.. updatlist=" updatlist) (shortbacktrace_dbg "set_new_tester_all_elses start" 15) (assert_msg "check newtester" (is_a newtester class_normtester_any)) (assert_msg "check partester" (is_a partester class_normtester_any)) (if (null updatlist) (setq updatlist (make_list discr_list))) (assert_msg "check updatlist" (is_list updatlist)) (forever allelseloop (debug "set_new_tester_all_elses allelseloop partester" partester) (cond ((null partester) (exit allelseloop)) ((is_a partester class_normtester_anytester) (let ( (eltest (unsafe_get_field :ntest_else partester)) (thtest (unsafe_get_field :ntest_then partester)) ) (cond ((null eltest) (put_fields partester :ntest_else newtester) (debug "set_new_tester_all_elses updated partester=" partester) (list_append updatlist partester) ) (:else (foreach_pair_component_in_list (updatlist) (curpair curtest) (if (== curtest partester) (exit allelseloop)) (if (== curtest newtester) (exit allelseloop)) ) (setq partester eltest)) ) (debug "set_new_tester_all_elses here partester=" partester "\n thtest=" thtest) (cond ( (is_a thtest class_normtester_anytester) (foreach_pair_component_in_list (updatlist) (curpair curtest) (if (== curtest thtest) (exit allelseloop)) (if (== curtest newtester) (exit allelseloop)) ) (debug "set_new_tester_all_elses before recursion" thtest) (set_new_tester_all_elses newtester thtest updatlist) (debug "set_new_tester_all_elses after recursion" thtest) ))) ) (:else (exit allelseloop))) ) ;;;; end forever allelseloop (debug "set_new_tester_all_elses return updatlist" updatlist) (return updatlist) ) ;;; expansion of tuples in cmatcher should be done in warmelt-genobj ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; catch-all for normpat any receiver (by failing) (defun normpat_anyrecv (recv nmatch hdler pcn) (debug "normpat_anyrecv recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (let ( (myclass (discrim recv)) (myclassname (get_field :named_name myclass)) (psloc (get_field :loca_location (get_field :pctn_src pcn))) ) (error_strv psloc "unimplemented normal_pattern for any " myclassname) (assert_msg "catchall normal_pattern unimplemented" ()) )) (install_method discr_any_receiver normal_pattern normpat_anyrecv) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; catch-all for normpat any pattern (by failing) (defun normpat_anypat (recv nmatch hdler pcn) (debug "normpat_anyrecv recv" recv) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern)) (let ( (myclass (discrim recv)) (myclassname (get_field :named_name myclass)) (psloc (get_field :loca_location (get_field :pctn_src pcn))) ) (debug "normpat_anyrecv myclass=" myclass " recv=" recv " nmatch=" nmatch) (error_strv psloc "unimplemented NORMAL_PATTERN for pattern of " myclassname) (assert_msg "catchall normal_pattern unimplemented on pattern" ()) )) (install_method class_source_pattern normal_pattern normpat_anypat) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; internal function when normalizing a variable pattern to generate ;;; or reuse a test (defun normvarpat_genreusetest (sloc nmatch lococc testlist tstuff hdler pcn) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check lococc" (is_a lococc class_nrep_locsymocc)) (let ( (tester ()) (curhdler hdler) ) (forever loopstuff (debug "normvarpat_genreusetest tstuff" tstuff) (cond ( (== (get_field :ntsame_identical tstuff) lococc) (setq tester tstuff) (exit loopstuff) ) ( (is_a tstuff class_normtester_any) (setq tstuff (get_field :ntest_else tstuff)) (setq curhdler (lambda (tester) (shortbacktrace_dbg "normvarpat_genreusetest lambda curhdler" 15) (put_fields tstuff :ntest_else tester) (debug "normvarpat_genreusetest lambda curhdler updatelse of tstuff=" tstuff) (list_append (get_field :ntest_comefrom tester) tstuff) )) ) (:else (let ( (newtester (instance class_normtester_same :nrep_loc sloc :ntest_matched nmatch :ntest_then () :ntest_else () :ntest_locclist () :ntest_comefrom (make_list discr_list) :ntsame_identical lococc)) ) (shortbacktrace_dbg "normvarpat_genreusetest making same newtester" 15) (register_new_normtester newtester pcn) (debug "normvarpat_genreusetest newtester same" newtester) (setq tester newtester) (list_append testlist newtester) (curhdler newtester) (exit loopstuff) ) ) ) ) ) ) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; normalize variable pattern (defun normpat_variablepat (recv nmatch hdler pcn) (debug "normpat_variablepat recv=" recv " nmatch=" nmatch) (assert_msg "check recv" (is_a recv class_source_pattern_variable)) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (shortbacktrace_dbg "normpat_variablepat begin" 15) (let ( (stuffmap (get_field :pctn_stuffmap pcn)) (pvarlocmap (get_field :pctn_pvarlocmap pcn)) (psloc (get_field :loca_location (get_field :pctn_src pcn))) (sloc (get_field :loca_location recv)) (patvar (get_field :spatvar_symb recv)) (tstuff (mapobject_get stuffmap nmatch)) (lococc (mapobject_get pvarlocmap patvar)) (env (get_field :pctn_env pcn)) (ncx (get_field :pctn_normctxt pcn)) (testlist (get_field :pctn_tests pcn)) ) (debug "normpat_variablepat tstuff=" tstuff " lococc=" lococc " patvar=" patvar) (compile_warning "we need to generate the clear of all or-variables") (cond ( (is_a lococc class_nrep_locsymocc) ;; patvar already bound, generate or reuse a same test (debug "normpat_variablepat alreadybound lococc" lococc) (normvarpat_genreusetest sloc nmatch lococc testlist tstuff hdler pcn) ) ;; process specially or variables ((is_a lococc class_normal_or_variable) (debug "normpat_variablepat lococc orvariable" lococc) (compile_warning "normpat_variablepat unhandled orvariable") (let ( (realococc (unsafe_get_field :norvar_locsym lococc)) (npatvar (unsafe_get_field :norvar_patvar lococc)) (patsym (get_field :spatvar_symb npatvar)) ) (debug "normpat_variablepat orvariable npatvar" npatvar) (assert_msg "check patsym == patvar" (== patsym patvar)) (debug "normpat_variablepat orvariable realococc" realococc) (cond ( (null realococc) ;; the or-variable was not bound at all (let ( (ctyp (get_ctype nmatch env)) (cbind (instance class_normal_let_binding :letbind_loc sloc :binder patsym :letbind_type ctyp :letbind_expr nmatch )) (clocc (instance class_nrep_locsymocc :nrep_loc sloc :nocc_ctyp ctyp :nocc_symb patsym :nocc_bind cbind)) ) (debug "normpat_variablepat fresh orvariable clocc" clocc) (put_fields lococc :norvar_locsym clocc :norvar_norexp nmatch) (debug "normpat_variablepat updated fresh orvariable lococc" lococc) (shortbacktrace_dbg "normpat_variablepat updated fresh orvar" 15) ;; put the clocc in the symbol cache map (mapobject_put (get_field :nctx_symbcachemap ncx) patvar clocc) (mapobject_put pvarlocmap patvar clocc) (debug "normpat_variablepat updated fresh orvariable pvarlocmap" pvarlocmap) ) ) ;; ;; the or-variable was already bound within the same ;; disjunct, so generate or reuse a same test ( (is_a realococc class_nrep_locsymocc) (debug "normpat_variablepat bound orvariable realococccc" realococc) (normvarpat_genreusetest sloc nmatch realococc testlist tstuff hdler pcn) ) ;; the or-variable was already bound in a previous ;; disjunction ( (is_a realococc class_reference) (let ( (ctyp (get_ctype nmatch env)) (bxclocc (deref realococc)) ) (debug "normpat_variablepat bxclocc" bxclocc) (assert_msg "check bxclocc" (is_a bxclocc class_nrep_locsymocc)) ;; check ctype compatibility with former occurence (let ( (prevctyp (unsafe_get_field :nocc_ctyp bxclocc)) ) (if (!= ctyp prevctyp) (let ( (prevsloc (unsafe_get_field :nrep_loc bxclocc)) ) (error_strv sloc "incompatible type for pattern variable inside OR pattern" (get_field :named_name (unsafe_get_field :nocc_symb bxclocc))) (inform_strv sloc "disjunct pattern variable occurs here with type" (get_field :named_name (get_field :ctype_keyword ctyp))) (inform_strv prevsloc "disjunct pattern variable occurs previously with type" (get_field :named_name (get_field :ctype_keyword prevctyp))) ))) (put_fields lococc :norvar_locsym bxclocc :norvar_norexp nmatch) (debug "normpat_variablepat updated reusing orvariable lococc" lococc) (shortbacktrace_dbg "normpat_variablepat updated reused orvar" 15) )) ;; unexpected case (:else (assert_msg "normpat_variablepat corruption" ()) ) ) ) ) ;; else patvar unbound, so bind it ((null lococc) (let ( (ctyp (get_ctype nmatch env)) (cbind (instance class_normal_let_binding :letbind_loc sloc :binder patvar :letbind_type ctyp :letbind_expr nmatch )) (clocc (instance class_nrep_locsymocc :nrep_loc sloc :nocc_ctyp ctyp :nocc_symb patvar :nocc_bind cbind)) ) (debug "normpat_variablepat ctyp=" ctyp " clocc=" clocc) (shortbacktrace_dbg "normpat_variablepat:: new clocc" 12) ;; put the clocc in the symbol cache map (mapobject_put (get_field :nctx_symbcachemap ncx) patvar clocc) (mapobject_put pvarlocmap patvar clocc) (debug "normpat_variablepat updated patvar=" patvar " clocc=" clocc " pvarlocmap=" pvarlocmap) ) ) (:else (assert_msg "normpat_variablepat unexpected lococc" ()) ) ) ) ) (install_method class_source_pattern_variable normal_pattern normpat_variablepat) ;;;;;;;;;;;;;;;; ;;; normalize joker pattern (defun normpat_jokerpat (recv nmatch hdler pcn) (debug "normpat_jokerpat recv=" recv" nmatch=" nmatch) (assert_msg "check recv" (is_a recv class_source_pattern_joker_variable)) (assert_msg "check pcn" (is_a pcn class_pattern_context)) ;; we need nothing more, a joker pattern is essentially a black hole.. ) (install_method class_source_pattern_joker_variable normal_pattern normpat_jokerpat) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;; normalize instance pattern (defun normpat_instancepat (recv nmatch hdler pcn) (debug "normpat_instancepat start recv=" recv " nmatch=" nmatch) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_instance)) (let ( (psloc (get_field :loca_location (get_field :pctn_src pcn))) (sloc (get_field :loca_location recv)) (env (unsafe_get_field :pctn_env pcn)) (patcla (get_field :spat_class recv)) (patfields (get_field :spat_fields recv)) (oldenv env) (ncx (get_field :pctn_normctxt pcn)) (stuffmap (get_field :pctn_stuffmap pcn)) (tstuff (mapobject_get stuffmap nmatch)) (tester ()) (curhdler hdler) (testlist (get_field :pctn_tests pcn)) ;; we know for sure that patcla is a class_class ;; hence its normalization does not make any bindings! (npatcla (normal_exp patcla env ncx sloc)) ) (assert_msg "check patcla" (is_a patcla class_class)) ;; find the tester in the stuff (forever loopstuff (debug "normpat_instancepat loop tstuff" tstuff) ;; check if tstuff is a class_normtester_instance with good :ntinst_class (cond ( (== (get_field :ntinst_class tstuff) patcla) (setq tester tstuff) (exit loopstuff) ) ((is_a tstuff class_normtester_any) (setq tstuff (get_field :ntest_else tstuff)) (setq curhdler (lambda (tester) (shortbacktrace_dbg "normpat_instancepat lambda" 15) (put_fields tstuff :ntest_else tester) (debug "normpat_instancepat lambda updatelse of tstuff=" tstuff) (list_append (get_field :ntest_comefrom tester) tstuff) )) ) (:else (let ( (newfieldlocs (make_multiple discr_multiple (multiple_length (get_field :class_fields patcla)) )) (newtester (instance class_normtester_instance :nrep_loc sloc :ntest_matched nmatch :ntest_then () :ntest_else () :ntest_locclist (make_list discr_list) :ntest_comefrom (make_list discr_list) :ntinst_class npatcla :ntinst_fieldlocs newfieldlocs )) ) (debug "normpat_instancepat newtester" newtester) (register_new_normtester newtester pcn) (setq tester newtester) (list_append testlist newtester) (debug "normpat_instancepat before calling curhdler" curhdler) (curhdler tester) (debug "normpat_instancepat after calling curhdler" curhdler) (exit loopstuff) ) )) ) (debug "normpat_instancepat tester=" tester "recv=" recv " patcla=" patcla) (let ( (testloccl (get_field :ntest_locclist tester)) (testercont (instance class_reference :referenced_value tester )) (sortedpatfields (multiple_sort patfields (lambda (pf1 pf2) (assert_msg "check pf1" (is_a pf1 class_source_field_pattern)) (assert_msg "check pf2" (is_a pf2 class_source_field_pattern)) (let ( (:long wpf1 (get_int (get_field :pat_weight (get_field :spaf_pattern pf1)))) (:long wpf2 (get_int (get_field :pat_weight (get_field :spaf_pattern pf2)))) ) (cond ((==i wpf2 wpf2) (return '0 ())) ((i nbinargs 0) (let ( (newenv (fresh_env env)) ) (foreach_in_multiple (nins) (ncurin :long ix) (debug "normpat_anymatchpat ncurin" ncurin) (let ( (curmatch (multiple_nth inmatchs ix)) (curctype (get_ctype ncurin env)) (matchtype (get_field :fbind_type curmatch)) ) (debug "normpat_anymatchpat curmatch" curmatch) (assert_msg "check curmatch" (is_a curmatch class_formal_binding)) (debug "normpat_anymatchpat curctype=" curctype " matchtype=" matchtype) (if (!= curctype matchtype) (progn (error_strv sloc "type mismatch for match argument in matcher" (get_field :named_name mat)) (inform_strv sloc "mismatched formal name in matcher is" (get_field :named_name (get_field :binder curmatch))) (inform_strv sloc "mismatched input type is" (get_field :named_name curctype)) (inform_strv sloc "expected match type is" (get_field :named_name matchtype)) ) (let ( (newb (instance class_normal_let_binding :letbind_loc sloc :binder (get_field :binder curmatch) :letbind_type curctype :letbind_expr ncurin) ) ) (debug "normpat_anymatchpat newb=" newb) (put_env newenv newb) )))) (setq env newenv) (put_fields pcn :pctn_env newenv) ))) ;; output args (debug "normpat_anymatchpat outargs=" outargs " outmatchs=" outmatchs) (let ( (:long nboutargs (multiple_length outargs)) ) (if (!=i nboutargs (multiple_length outmatchs)) (error_strv sloc "formal and actual number of output matched arguments differ for anymatch" (get_field :named_name mat))) (let ( (tstuff (mapobject_get stuffmap nmatch)) (curhdler hdler) ) (forever loopstuff (debug "normpat_anymatchpat tstuff" tstuff) (cond ((and (is_a tstuff class_normtester_matcher) (== (get_field :ntmatch_matcher tstuff) mat)) (let ((tinargs (get_field :ntmatch_inargs tstuff)) (:long good 1) ) (foreach_in_multiple (tinargs) (curinarg :long ix) (let ( (nthins (multiple_nth nins ix)) ) (if (!= curinarg nthins) (setq good 0))) ) (if good (progn (debug "normpat_anymatchpat good tstuff" tstuff) (setq tester tstuff) (exit loopstuff)) (progn (setq tstuff (get_field :ntest_else tstuff)) (setq curhdler (lambda (tester) (shortbacktrace_dbg "normpat_anymatchpat lambda updating else" 15) (put_fields tstuff :ntest_else tester) (debug "normpat_anymatchpat lambda updatelse of tstuff" tstuff) (list_append (get_field :ntest_comefrom tester) tstuff) )) )) ) (assert_msg "normpat_anymatchpat incomplete found tstuff" ()) ) ((is_a tstuff class_normtester_any) (setq tstuff (get_field :ntest_else tstuff)) (setq curhdler (lambda (tester) (put_fields tstuff :ntest_else tester) (shortbacktrace_dbg "normpat_anymatchpat updatelse" 15) (debug "normpat_anymatchpat updatelse tsuff" tstuff) (list_append (get_field :ntest_comefrom tester) tstuff) )) ) (:else (let ( (outlocs (multiple_map outmatchs (lambda (curoutmatch :long ix) (debug "normpat_anymatchpat curoutmatch" curoutmatch) (assert_msg "check curoutmatch" (is_a curoutmatch class_formal_binding)) (let ( (csym (clone_symbol (get_field :binder curoutmatch))) (curtyp (get_field :fbind_type curoutmatch)) (cbind (instance class_normal_let_binding :letbind_loc sloc :binder csym :letbind_type curtyp ;; this is really nil, ;; the binding should ;; be cleared :letbind_expr () )) (clocc (instance class_nrep_locsymocc :nrep_loc sloc :nocc_ctyp curtyp :nocc_symb csym :nocc_bind cbind)) ) ;; put the clocc in the symbol cache map (mapobject_put (get_field :nctx_symbcachemap ncx) csym clocc) (debug "normpat_anymatchpat clocc=" clocc) clocc )))) (newtester (instance class_normtester_matcher :nrep_loc sloc :ntest_matched nmatch :ntest_then () :ntest_else () ;;;; one could imagine having some ;;;; subclass of cmatcher which add ;;;; additional local stuff... :ntest_locclist (multiple_to_list outlocs) :ntest_comefrom (make_list discr_list) :ntmatch_matcher mat :ntmatch_matndata matndata :ntmatch_inargs nins :ntmatch_outlocs outlocs )) ) (debug "normpat_anymatchpat newtester" newtester) (register_new_normtester newtester pcn) (setq tester newtester) (list_append testlist newtester) (shortbacktrace_dbg "normpat_anymatchpat before curhdler" 12) (curhdler newtester) (exit loopstuff) )) )) ) ) (debug "normpat_anymatchpat got tester" tester) (assert_msg "check tester" (is_a tester class_normtester_matcher)) ;; (let ( (outlocs (get_field :ntmatch_outlocs tester)) ) (debug "normpat_anymatchpatfrom tester outlocs=" outlocs " outargs=" outargs " outmatchs=" outmatchs) (foreach_in_multiple (outmatchs) (curmatch :long ixm) (messagenum_dbg "normpat_anymatchpat ixm in outmatchs" ixm) (debug "normpat_anymatchpat curmatch in foreach" curmatch) (let ( (clocc (multiple_nth outlocs ixm)) (curout (multiple_nth outargs ixm)) (testercont (instance class_reference :referenced_value tester)) (subhdler ;; put the new tester as the last element of its ;; ntest_then chain (lambda (newtester) (debug "normpat_anymatchpat subhdler newtester" newtester) (shortbacktrace_dbg "normpat_anymatchpat subhdler" 14) (set_new_tester_last_then newtester testercont) )) ) (debug "normpat_anymatchpat before normal_pattern curout=" curout " clocc=" clocc) (shortbacktrace_dbg "normpat_anymatchpat before normal_pattern curout" 14) (normal_pattern curout clocc subhdler pcn) (debug "normpat_anymatchpat curout after normal_pattern" curmatch) ) ) ) (debug "normpat_anymatchpat outbinds" outbinds) ) ) ) (if (!= env oldenv) (put_fields pcn :pctn_env oldenv)) ) ) (install_method class_source_pattern_matcher normal_pattern normpat_anymatchpat) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; ;;;; normalize a constant pattern (defun normpat_constpat (recv nmatch hdler pcn) (debug "normpat_constpat recv=" recv " nmatch=" nmatch " pcn=" pcn) (assert_msg "check pcn" (is_a pcn class_pattern_context)) (assert_msg "check recv" (is_a recv class_source_pattern_constant)) (let ( (sloc (get_field :loca_location recv)) (sconst (get_field :spat_constx recv)) (stuffmap (get_field :pctn_stuffmap pcn)) (pvarlocmap (get_field :pctn_pvarlocmap pcn)) (psloc (get_field :loca_location (get_field :pctn_src pcn))) (tstuff (mapobject_get stuffmap nmatch)) (env (get_field :pctn_env pcn)) (ncx (get_field :pctn_normctxt pcn)) (testlist (get_field :pctn_tests pcn)) (mapcst (get_field :pctn_mapatcst pcn)) ) ;;; the constant has already been normalized in scanpat_srcpatconst (debug "normpat_constpat tstuff" tstuff) (let ( (tester ()) (curhdler hdler) (nconst (if (is_object sconst) (mapobject_get mapcst sconst) sconst)) ) (debug "normpat_constpat nconst" nconst) (forever loopstuff (debug "normpat_constpat tstuff" tstuff) (cond ( (== (get_field :ntsame_identical tstuff) nconst) (setq tester tstuff) (exit loopstuff)) ( (is_a tstuff class_normtester_any) (setq tstuff (get_field :ntest_else tstuff)) (setq curhdler (lambda (tester) (put_fields tstuff :ntest_else tester) (shortbacktrace_dbg "normpat_constpat lambda updatelse" 15) (debug "normpat_constpat lambda updatelse tstuff=" tstuff) (list_append (get_field :ntest_comefrom tester) tstuff) )) ) (:else (let ( (newtester (instance class_normtester_same :nrep_loc psloc :ntest_matched nmatch :ntest_then () :ntest_else () :ntest_locclist () :ntest_comefrom (make_list discr_list) :ntsame_identical nconst)) ) (shortbacktrace_dbg "normpat_constpat making newtester same" 15) (register_new_normtester newtester pcn) (debug "normpat_constpat newtester same" newtester) (setq tester newtester) (list_append testlist newtester) (curhdler newtester) (exit loopstuff) ) ) ) ) ;end forever (debug "normpat_constpat got tester" tester) ) ) ) (install_method class_source_pattern_constant normal_pattern normpat_constpat) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; to ease debugging, we offer the option to generate .dot files ;;;;; for graphviz (see http://www.graphviz.org/ for more) ;; the instance containing the string value prefix of the generated ;; .dot file, should be something like /tmp/mygr to generated ;; /tmp/mygr1.dot /tmp/mygr2.dot etc... (definstance match_graphic_dot_prefix class_reference :referenced_value ()) ;;; a private class to help generate dot graphics (defclass class_match_graphic :doc #{$CLASS_MATCH_GRAPHIC is a private class to generate graphviz .dot graphics files to debug the MELT translation of matching. Don't use it yourself.}# :super class_proped :fields ( mchgx_filename ;the filename mchgx_nodout ;the output strbuf for nodes mchgx_edgout ;the output strbuf for edges mchgx_datanamemap ;the objmap for name of datas mchgx_stepnamemap ;the objmap for name of steps )) ;; internal function to out the node name for the match graphic (defun mg_out_node_name (out ntest) (assert_msg "check out" (is_out out)) (assert_msg "check ntest" (is_a ntest class_normtester_any)) (let ( (cla (discrim ntest)) (clanam (get_field :named_name cla)) (:long clanamlen (string_length clanam)) (:long ix (get_int ntest)) ) ;; the classname starts with CLASS_ which has six characters, we ;; skip them for the node name (assert_msg "check clanamlen" (>i clanamlen 6)) (code_chunk outchunk #{ /* mg_node_name $OUTCHUNK */ meltgc_add_out ((melt_ptr_t) $OUT, melt_string_str ((melt_ptr_t) $CLANAM) +6); meltgc_out_printf ((melt_ptr_t) $OUT, "_%d", (int) $IX); }# ) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; internal selector to output the label of a test in "HTML-like" ;; graphiz format (defselector matchgraphic_label class_selector ) (defun mglabel_any (recv mg) (let ( (dis (discrim recv)) (disname (get_field :named_name dis)) ) (debug "mglabel_any recv=" recv " mg=" mg " dis=" dis) (errormsg_strv "unimplemented MATCHGRAPHIC_LABEL for " disname) (assert_msg "@$@unexpected mglabel_anyobj") )) (install_method discr_any_receiver matchgraphic_label mglabel_any) (defun mglabel_any_test (ntest mg) (debug "mglabel_any_test start ntest" ntest) (assert_msg "check ntest" (is_a ntest class_normtester_any)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (nloc (unsafe_get_field :nrep_loc ntest)) (nmatched (unsafe_get_field :ntest_matched ntest)) (nodout (unsafe_get_field :mchgx_nodout mg)) (edgout (unsafe_get_field :mchgx_edgout mg)) ) (debug "mglabel_any_test nloc=" nloc " nmatched=" nmatched) (assert_msg "check nodout" (is_out nodout)) (assert_msg "check edgout" (is_out edgout)) ;; first table row: output the node name in blue bold and the hashcode (add2out_strconst nodout "") (add2out_strconst nodout "") (mg_out_node_name nodout ntest) (add2out_strconst nodout " ") (add2out_strconst nodout "#") (add2out_longhex nodout (obj_hash ntest)) (add2out_strconst nodout " ") (add2out_strconst nodout "") (add2out_indentnl nodout 2) ;; if we have a location, it makes a row (cond ( (is_mixloc nloc) (add2out_strconst nodout "") (add2out_strconst nodout "") (add2out_mixloc nodout nloc) (add2out_strconst nodout " ") (add2out_indentnl nodout 2) ) ) ;; if the matched is a locsymocc [it usually should] display it, ;; that is its symbol and the hashcode of the locsymocc (if (is_a nmatched class_nrep_locsymocc) (let ( (nmaloc (unsafe_get_field :nrep_loc nmatched)) (nmasymb (unsafe_get_field :nocc_symb nmatched)) (:long nmarank (get_int (get_field :csym_urank nmasymb))) ) (add2out_strconst nodout "") (add2out_strconst nodout "") (add2out_string nodout (get_field :named_name nmasymb)) (if (>i nmarank 0) (progn (add2out_strconst nodout " #") (add2out_longhex nodout nmarank) (add2out_strconst nodout " ") )) (add2out_strconst nodout " ##") (add2out_longhex nodout (obj_hash nmatched)) (add2out_strconst nodout " ") (add2out_indentnl nodout 2) )) (debug "mglabel_any_test end ntest" ntest) )) (install_method class_normtester_any matchgraphic_label mglabel_any_test) ;; output an instance test (defun mglabel_instance_test (ntest mg) (debug "mglabel_instance_test start ntest" ntest) (assert_msg "check ntest" (is_a ntest class_normtester_instance)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (nloc (unsafe_get_field :nrep_loc ntest)) (nmatched (unsafe_get_field :ntest_matched ntest)) (nodout (unsafe_get_field :mchgx_nodout mg)) (edgout (unsafe_get_field :mchgx_edgout mg)) ) (debug "mglabel_instance_test nloc=" nloc "nmatched=" nmatched) (assert_msg "check nodout" (is_out nodout)) (assert_msg "check edgout" (is_out edgout)) ;; first table row: output the node name in blue bold and the hashcode and the tested class (add2out_strconst nodout "") (add2out_strconst nodout "") (mg_out_node_name nodout ntest) (add2out_strconst nodout " ") (add2out_strconst nodout "#") (add2out_longhex nodout (obj_hash ntest)) (add2out_strconst nodout " ") (add2out_strconst nodout "") (add2out_string nodout (get_field :named_name (get_field :nocc_symb (get_field :ntinst_class ntest)))) (add2out_strconst nodout " ") (add2out_strconst nodout "") (add2out_indentnl nodout 2) ;; if we have a location, it makes a row (cond ( (is_mixloc nloc) (add2out_strconst nodout "") (add2out_strconst nodout "") (add2out_mixloc nodout nloc) (add2out_strconst nodout " ") (add2out_indentnl nodout 2) ) ) ;; if the matched is a locsymocc [it usually should] display it, ;; that is its symbol and the hashcode of the locsymocc (if (is_a nmatched class_nrep_locsymocc) (let ( (nmaloc (unsafe_get_field :nrep_loc nmatched)) (nmasymb (unsafe_get_field :nocc_symb nmatched)) (:long nmarank (get_int (get_field :csym_urank nmasymb))) ) (add2out_strconst nodout "") (add2out_strconst nodout "") (add2out_string nodout (get_field :named_name nmasymb)) (if (>i nmarank 0) (progn (add2out_strconst nodout " #") (add2out_longhex nodout nmarank) (add2out_strconst nodout " ") )) (add2out_strconst nodout " ##") (add2out_longhex nodout (obj_hash nmatched)) (add2out_strconst nodout " ") (add2out_indentnl nodout 2) )) (debug "mglabel_instance_test end ntest" ntest) )) (install_method class_normtester_instance matchgraphic_label mglabel_instance_test) ;;; output a success test (defun mglabel_success_test (ntest mg) (debug "mglabel_success_test start ntest" ntest) (assert_msg "check ntest" (is_a ntest class_normtester_success)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (nloc (unsafe_get_field :nrep_loc ntest)) (nmatched (unsafe_get_field :ntest_matched ntest)) (nodout (unsafe_get_field :mchgx_nodout mg)) (edgout (unsafe_get_field :mchgx_edgout mg)) ) (debug "mglabel_success_test nloc=" nloc " nmatched=" nmatched) (assert_msg "check nodout" (is_out nodout)) (assert_msg "check edgout" (is_out edgout)) ;; first table row: output the node name and the hashcode (add2out_strconst nodout "") (add2out_strconst nodout "") (mg_out_node_name nodout ntest) (add2out_strconst nodout " ") (add2out_strconst nodout "#") (add2out_longhex nodout (obj_hash ntest)) (add2out_strconst nodout " ") (add2out_strconst nodout "") (add2out_indentnl nodout 2) ;; if we have a location, it makes a row (cond ( (is_mixloc nloc) (add2out_strconst nodout "") (add2out_strconst nodout "") (add2out_mixloc nodout nloc) (add2out_strconst nodout " ") (add2out_indentnl nodout 2) ) ) (debug "mglabel_success_test end ntest" ntest) )) (install_method class_normtester_success matchgraphic_label mglabel_success_test) ;; internal function to out a tuple of test nodes in graphiz format (defun matchgraphic_tests (testup mg) (debug "matchgraphic_tests start testup=" testup " mg=" mg) (assert_msg "check testup" (is_multiple testup)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (nodout (unsafe_get_field :mchgx_nodout mg)) (edgout (unsafe_get_field :mchgx_edgout mg)) ) (add2out_indentnl nodout 0) (add2out_indentnl edgout 0) (foreach_in_multiple testup (curtest :long tix) (assert_msg "check curtest" (is_a curtest class_normtester_any)) (debug "matchgraphic_tests curtest" curtest) ;; output the node and its label (mg_out_node_name nodout curtest) (add2out_strconst nodout " [ label=<") (add2out_strconst nodout "") (add2out_indentnl nodout 1) (matchgraphic_label curtest mg) (add2out_indentnl nodout 1) (add2out_strconst nodout "
") (add2out_strconst nodout ">, margin=0") (if (==i tix 0) (add2out_strconst nodout ", style=\"bold\"")) (add2out_strconst nodout " ];") (add2out_indentnl nodout 0) ;; output the outgoing edges (let ( (nthen (unsafe_get_field :ntest_then curtest)) (nelse (unsafe_get_field :ntest_else curtest)) ) (if (is_a nthen class_normtester_any) (progn (mg_out_node_name edgout curtest) (add2out_strconst edgout " -> /*then*/ ") (mg_out_node_name edgout nthen) (add2out_strconst edgout " [ arrowhead=normal, color=green ];") (add2out_indentnl edgout 0) )) (if (is_a nelse class_normtester_any) (progn (mg_out_node_name edgout curtest) (add2out_strconst edgout " -> /*else*/ ") (mg_out_node_name edgout nelse) (add2out_strconst edgout " [ arrowhead=diamond, color=red ];") (add2out_indentnl edgout 0) )) ) ) )) ;; utility to out a graphviz .dot file for the tests inside match (defun mg_draw_match_graphviz_file (nmatch dotprefix teststupl) (let ( (:long hcodnmatch (obj_hash nmatch)) (:long cnt 0) (:long nbtests (multiple_length teststupl)) (pathsbuf (make_strbuf discr_strbuf)) (dotfilename (progn (code_chunk uniqcnt #{ /* mg_draw_match_graphviz_file $UNIQCNT */ { static long uniqcounter; uniqcounter ++; $CNT = uniqcounter; } }#) (assert_msg "check pathsbuf" (is_strbuf pathsbuf)) (add2sbuf_string pathsbuf dotprefix) (add2sbuf_longdec pathsbuf cnt) (add2sbuf_strconst pathsbuf ".dot") (debug "mg_draw_match_graphviz_file pathsbuf" pathsbuf) (strbuf2string discr_string pathsbuf))) (nodbuf (make_strbuf discr_strbuf)) (edgbuf (make_strbuf discr_strbuf)) (mg (instance class_match_graphic :mchgx_filename dotfilename :mchgx_nodout nodbuf :mchgx_edgout edgbuf )) ) (debug "mg_draw_match_graphviz_file initial mg" mg) (matchgraphic_tests teststupl mg) (debug "mg_draw_match_graphviz_file final mg" mg) (assert_msg "check dotfilename" (is_string dotfilename)) (code_chunk outputmg #{ /* mg_draw_match_graphviz_file $OUTPUTMG */ { time_t nowt = 0; char nowbuf[60]; FILE* dotfil = fopen (melt_string_str ((melt_ptr_t) $DOTFILENAME), "w"); if (!dotfil) melt_fatal_error ("failed to open matchdot file %s - %m", melt_string_str ((melt_ptr_t) $DOTFILENAME)); fprintf (dotfil, "// melt matchdot file %s\n", melt_string_str ((melt_ptr_t) $DOTFILENAME)); time (&nowt); memset (nowbuf, 0, sizeof(nowbuf)); strftime (nowbuf, sizeof(nowbuf)-1, "%Y %b %d %Hh%M", localtime (&nowt)); fprintf (dotfil, "// generated %s\n", nowbuf); fprintf (dotfil, "digraph meltmatch_%lx {\n", $HCODNMATCH); fprintf (dotfil, " graph [ label=\"Melt Match %d #%#lx %s\", pad=\"0.5\", margin=\"0.3\" ];\n", (int) $CNT, $HCODNMATCH, nowbuf); fprintf (dotfil, " node [ shape=\"box\", fontsize=\"12\" ];\n"); fprintf (dotfil, "// %d tests\n", (int) $NBTESTS); melt_putstrbuf (dotfil, (melt_ptr_t) $NODBUF); fprintf (dotfil, "\n /// edges\n"); melt_putstrbuf (dotfil, (melt_ptr_t) $EDGBUF); fprintf (dotfil, "\n} // eof %s\n", melt_string_str ((melt_ptr_t) $DOTFILENAME)); fclose (dotfil); } /* end mg_draw_match_graphviz_file $OUTPUTMG */ }#) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; normalize a match (defun normexp_match (recv env ncx psloc) (assert_msg "check match recv" (is_a recv class_source_match)) (assert_msg "check env" (is_a env class_environment)) (assert_msg "check nctxt" (is_a ncx class_normalization_context)) (debug "normexp_match recv" recv) (let ( (sloc (unsafe_get_field :loca_location recv)) (smatsx (unsafe_get_field :smat_matchedx recv)) (scases (unsafe_get_field :smat_cases recv)) (:long nbcases (multiple_length scases)) (tupvarmap (make_multiple discr_multiple nbcases)) (tupcstmap (make_multiple discr_multiple nbcases)) ;; the shabindlist & the stuffmap are shared for all match cases (stuffmap (make_mapobject discr_map_objects (+i 20 (*i 5 nbcases)))) (shabindlist (make_list discr_list)) (testlist (make_list discr_list)) (wholectype ()) ;the ctype of the whole match (oldtester ()) ;the previous tester (cintsymb (clone_symbol 'match_inter_)) (nchint (instance class_nrep_checksignal :nrep_loc sloc)) (cintbind (instance class_normal_let_binding :binder cintsymb :letbind_type ctype_void :letbind_expr nchint)) ) (debug "normexp_match smatsx=" smatsx " cintbind=" cintbind) (multicall (nmatx nbindmatx) (normal_exp smatsx env ncx sloc) (debug "normexp_match nmatx=" nmatx " nbindmatx=" nbindmatx " scases=" scases) (if (is_list nbindmatx) (list_append nbindmatx cintbind) (setq nbindmatx (list cintbind))) ;; (let ( (ctyp (get_ctype nmatx env)) ) (debug "normexp_match ctyp" ctyp) ;; if the matched stuff is not an object, it is a constant, so ;; make a binding for it (if (not (is_object nmatx)) (let ( (csym (clone_symbol '_matched_)) (cbind (instance class_normal_let_binding :letbind_loc sloc :binder csym :letbind_type ctyp :letbind_expr nmatx)) (clocc (instance class_nrep_locsymocc :nrep_loc sloc :nocc_ctyp ctyp :nocc_symb csym :nocc_bind cbind)) ) (assert_msg "check no binding" (null nbindmatx)) (debug "normexp_match clocc=" clocc) ;; put the clocc in the symbol cache map (mapobject_put (get_field :nctx_symbcachemap ncx) csym clocc) (setq nbindmatx (list cbind)) (setq nmatx clocc) )) ;; if no binding list, make an empty one (if (null nbindmatx) (setq nbindmatx (make_list discr_list))) ;; ;; loop on each case (foreach_in_multiple (scases) (curcas :long ix) (debug "normexp_match curcas" curcas) (assert_msg "check curcas" (is_a curcas class_source_match_case)) (let ( (curloc (unsafe_get_field :loca_location curcas)) (curpat (unsafe_get_field :scam_patt curcas)) (curbody (unsafe_get_field :scam_body curcas)) (mapvar (make_mapobject discr_map_objects 13)) (mapcst (make_mapobject discr_map_objects 11)) (mapor (make_mapobject discr_map_objects 7)) (pvarlocmap (make_mapobject discr_map_objects 23)) (varhdlerlist (make_list discr_list)) (pcn (instance class_pattern_context :pctn_normctxt ncx :pctn_src recv :pctn_env env :pctn_mapatvar mapvar :pctn_mapatcst mapcst :pctn_mapor mapor :pctn_bindlist shabindlist :pctn_stuffmap stuffmap :pctn_pvarlocmap pvarlocmap :pctn_tests testlist :pctn_varhandlers varhdlerlist )) (ntestcont (instance class_reference)) ;container for tester ) (debug "normexp_match curpat before scan_pattern" curpat) ;; I am not entirely sure of this assert! Perhaps there maybe ;; strange cases where curpat is null... (assert_msg "normexp_match check curpat" curpat) (scan_pattern curpat curloc ctyp pcn) (debug "normexp_match after scan_pattern curpat=" curpat " mapvar=" mapvar " pvarlocmap=" pvarlocmap " mapcst=" mapcst) (multiple_put_nth tupvarmap ix mapvar) (multiple_put_nth tupcstmap ix mapcst) (debug "normexp_match before normal_pattern shabindlist=" shabindlist " curpat=" curpat) ;; normalize the current pattern, with the handler storing its topmost tester (normal_pattern curpat nmatx (lambda (tester) (debug "normexp_match.lambda tester" tester) (shortbacktrace_dbg "normexp_match lambda tester" 12) (assert_msg "check empty ntestcont" (null (unsafe_get_field :referenced_value ntestcont))) (put_fields ntestcont :referenced_value tester)) pcn) (debug "normexp_match after normal_pattern curpat=" curpat " pvarlocmap=" pvarlocmap "ntestcont= " ntestcont "shabindlist= " shabindlist) ;; (let ( (newenv (get_field :pctn_env pcn)) (curtester (get_field :referenced_value ntestcont)) ;; we need a success. For the last joker case, it ;; becomes the curtester; for the usual case it is ;; added as the last then. Anyway, it will contain ;; the action part of the current case. (newsuctester (instance class_normtester_success :nrep_loc curloc ;; we really don't match anything :ntest_matched () :ntest_then () :ntest_else () :ntest_comefrom (make_list discr_list) ;; the success do should be the wrapped ;; let of the normalized actions :ntsuccess_do () )) ) (debug "normexp_match after normal_pattern newenv=" newenv " newsuctester=" newsuctester " pvarlocmap=" pvarlocmap " curcas=" curcas " curtester=" curtester " oldtester=" oldtester) ;; append the new success to the test list, so that it ;; will get its ntest_normatch later (list_append testlist newsuctester) (cond ((null curtester) (debug "normexp_match curcas for null curtester" curcas) ;; curtester is null if the whole case is a joker, ;; this should be the last case (if (=i tstix 0)) (assert_msg "check tstix not too big" (i lastrank 0))) (let ( (mflag (instance class_match_flag :loca_location sloc :mflag_spat spat :mflag_rank (make_integerbox discr_constant_integer (+i lastrank 1)) :mflag_string str )) ) (list_append flaglist mflag) (debug "make_match_flag return mflag" mflag) mflag ) )) ;;;;;;;;;;;;;;;; (defselector scan_subpatterns class_selector :doc #{Apply a given function $FUN to the subpatterns of receiver $RECV with extra context $CTX.}# :formals (recv fun ctx) ) (defselector scan_step_data class_selector :doc #{Given a receiver $STEP, apply a given function $FUN to all the data of the $STEP with an extra context $CTX.}# :formals (step fun ctx)) (defselector scan_step_flag class_selector :doc #{Given a receiver $STEP, apply a given function $FUN to all the flags of the $STEP with an extra context $CTX.}# :formals (step fun ctx)) (defun scansubpat_anyrecv (recv fun ctx) (let ( (dis (discrim recv)) ) (debug "scansubpat_anyrecv recv=" recv " of discrim=" dis) (errormsg_strv "unexpected scan_subpatterns for" (unsafe_get_field :named_name dis)) (assert_msg "@$@unexpected scansubpat_anyrecv") )) (install_method discr_any_receiver scan_subpatterns scansubpat_anyrecv) (defun scanstepdata_anyrecv (recv fun ctx) (let ( (dis (discrim recv)) ) (debug "scanstepdata_anyrecv recv=" recv " of discrim=" dis) (errormsg_strv "unexpected scan_step_data for" (unsafe_get_field :named_name dis)) (assert_msg "@$@unexpected scanstepdata_anyrecv") )) (install_method discr_any_receiver scan_step_data scanstepdata_anyrecv) (defun scanstepflag_anyrecv (recv fun ctx) (let ( (dis (discrim recv)) ) (debug "scanstepflag_anyrecv recv=" recv " of discrim=" dis) (errormsg_strv "unexpected scan_step_flag for" (unsafe_get_field :named_name dis)) (assert_msg "@$@unexpected scanstepflag_anyrecv") )) (install_method discr_any_receiver scan_step_flag scanstepflag_anyrecv) (defun scansubpat_noop (recv fun ctx) (debug "scansubpat_noop recv=" recv) () ) (install_method class_source_pattern_variable scan_subpatterns scansubpat_noop) (install_method class_source_pattern_constant scan_subpatterns scansubpat_noop) (defun scansubpat_or (recv fun ctx) (debug "scansubpat_or recv=" recv) (let ( (disjtup (unsafe_get_field :orpat_disj recv)) ) (foreach_in_multiple (disjtup) (curdisj :long dix) (fun curdisj ctx)))) (install_method class_source_pattern_or scan_subpatterns scansubpat_or) (defun scansubpat_and (recv fun ctx) (debug "scansubpat_and recv=" recv) (let ( (conjtup (unsafe_get_field :andpat_conj recv)) ) (foreach_in_multiple (conjtup) (curconj :long cix) (debug "scansubpat_and curconj=" curconj " cix=" cix) (fun curconj ctx)))) (install_method class_source_pattern_and scan_subpatterns scansubpat_and) (defun scansubpat_construct (recv fun ctx) (debug "scansubpat_construct recv=" recv " fun=" fun) (shortbacktrace_dbg "scansubpat_construct" 10) (assert_msg "check recv" (is_a recv class_source_pattern_construct)) (let ( (subpatup (get_field :ctpat_subpa recv)) ) (debug "scansubpat_construct subpatup=" subpatup) (foreach_in_multiple (subpatup) (curpa :long pix) (debug "scansubpat_construct before curpa=" curpa " pix=" pix) (fun curpa ctx) (debug "scansubpat_construct after curpa=" curpa " pix=" pix) ))) (install_method class_source_pattern_construct scan_subpatterns scansubpat_construct) (defun scansubpat_object (recv fun ctx) (debug "scansubpat_object recv=" recv) (let ( (patfieltup (unsafe_get_field :spat_fields recv)) ) (foreach_in_multiple (patfieltup) (curpatfld :long flix) (if (is_a curpatfld class_source_field_pattern) (fun (unsafe_get_field :spaf_pattern curpatfld) ctx))))) (install_method class_source_pattern_object scan_subpatterns scansubpat_object) (defun fill_matchcase (curmcase sloc) (debug "fill_matchcase curmcase=" curmcase " sloc=" sloc) (shortbacktrace_dbg "fill_matchcase" 10) (assert_msg "check curmcase" (is_a curmcase class_match_case)) (let ( (ourpatvarmap (make_mapobject discr_map_objects 17)) (curscas (unsafe_get_field :mcase_source curmcase)) (curpat (unsafe_get_field :scam_patt curscas)) ) (debug "fill_matchcase ourpatvarmap=" ourpatvarmap) (letrec ( (varpatscanner (lambda (pat patvarmap) (debug "fill_matchcase/varpatscanner pat=" pat " patvarmap=" patvarmap) (assert_msg "check patvarmap" (is_mapobject patvarmap)) (assert_msg "same patvarmap" (== patvarmap ourpatvarmap)) (shortbacktrace_dbg "fill_matchcase/varpatscanner" 10) (if (is_a pat class_source_pattern_variable) (let ( (pvarsymb (unsafe_get_field :spatvar_symb pat)) (varocclist (mapobject_get patvarmap pvarsymb)) ) (if (null varocclist) (progn (setq varocclist (make_list discr_list)) (mapobject_put patvarmap pvarsymb varocclist) (debug "fill_matchcase/varpatscanner updated patvarmap=" patvarmap " for pat=" pat) )) (list_append varocclist pat) ) (progn (debug "fill_matchcase/varpatscanner before scan_subpatterns pat=" pat "\n ourpatvarmap=" ourpatvarmap) (scan_subpatterns pat varpatscanner ourpatvarmap) (debug "fill_matchcase/varpatscanner after scan_subpatterns pat=" pat "\n ourpatvarmap=" ourpatvarmap) ) ) )) ) (debug "fill_matchcase before varpatscanner curpat=" curpat " ourpatvarmap=" ourpatvarmap "\n varpatscanner=" varpatscanner) (varpatscanner curpat ourpatvarmap) (debug "fill_matchcase after varpatscanner curpat=" curpat "\n ourpatvarmap=" ourpatvarmap) ) (debug "fill_matchcase final ourpatvarmap=" ourpatvarmap " for curmcase=" curmcase) (put_fields curmcase :mcase_varmap ourpatvarmap) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; the selectors to set the then & else part of a match step (defselector put_then_match class_selector :doc #{Put the then part of a match test $RECV to $THENSTEP.}# :formals (recv thenstep) ) (defun putthen_matchany (recv thenstep) (let ( (dis (discrim recv)) ) (debug "putelse_mathany recv=" recv "thenstep=" thenstep " for discrim=" dis) (errormsg_strv "unexpected PUT_THEN_MATCH for " (get_field :named_name dis)) (assert_msg "@$@unexpected PUT_THEN_MATCH [putthen_matchany]") )) (install_method class_root put_then_match putthen_matchany) (defun start_step (step) (cond ( (null step) (return) ) ( (is_a step class_match_step_test_group) (let ( (stastep (unsafe_get_field :mstgroup_start step)) ) (debug "start_step group step" step) (debug "stastep return stastep" stastep) (assert_msg "check stastep" (is_a stastep class_match_step)) (return stastep))) (:else (debug "start_step ordinary step" step) (assert_msg "check step" (is_a step class_match_step)) (return step)))) (defun putthen_matchthen (recv thenstep) (debug "putthen_matchthen recv" recv) (assert_msg "check recv" (is_a recv class_match_step_then)) (debug "putthen_matchthen thenstep" thenstep) (assert_msg "check thenstep" (is_a thenstep class_match_step)) (assert_msg "check recv!=then" (!= recv thenstep)) (compile_warning "temporary check for application depth..." (assert_msg "putthen_matchthen check shallow100" (melt_application_shallower 100))) (compile_warning "temporary backtrace when test_instance...." (if (is_a recv class_match_step_test_instance) (shortbacktrace_dbg "putthen_matchthen testinstance!!!" 20))) (let ( (mythen (unsafe_get_field :mstep_then recv)) (starthen (start_step thenstep)) ) (if (== recv starthen) (progn (debug "putthen_matchthen recv same starthen" starthen) (return))) (if (== mythen starthen) (progn (debug "putthen_matchthen mythen same starthen" starthen) (return))) (if (null mythen) (progn (unsafe_put_fields recv :mstep_then starthen) (debug "putthen_matchthen updated recv" recv) ;(shortbacktrace_dbg "putthen_matchthen" 12) ) (progn (debug "putthen_matchthen recursing in mythen" mythen) (debug "putthen_matchthen recursing for starthen" starthen) (put_then_match mythen starthen) (debug "putthen_matchthen did mythen" mythen)))) ) (install_method class_match_step_then put_then_match putthen_matchthen) (defun putthen_matchgroup (recv thenstep) (debug "putthen_matchgroup recv" recv) (assert_msg "check recv" (is_a recv class_match_step_test_group)) (debug "putthen_matchgroup thenstep" thenstep) (assert_msg "check thenstep" (is_a thenstep class_match_step)) (putthen_matchthen recv thenstep) (let ( (thengroup (unsafe_get_field :mstgroup_then recv)) ) (cond ((null thengroup) (return)) ((is_a thengroup class_match_step) (put_then_match thengroup thenstep)) ((is_list thengroup) (foreach_pair_component_in_list (thengroup) (curpair curthen) (put_then_match curthen thenstep))) ((is_multiple thengroup) (foreach_in_multiple (thengroup) (curthen :long thix) (put_then_match curthen thenstep))) (:else (debug "putthen_matchgroup bad thengroup" thengroup) (assert_msg "bad thengroup" ()))))) (install_method class_match_step_test_group put_then_match putthen_matchgroup) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defselector put_else_match class_selector :doc #{Put the else part of a match test $RECV to $ELSESTEP.}# :formals (recv elsestep) ) (defun putelse_matchany (recv elsestep) (let ( (dis (discrim recv)) ) (debug "putelse_mathany recv=" recv "elsestep=" elsestep " for discrim=" dis) (errormsg_strv "unexpected PUT_ELSE_MATCH for " (get_field :named_name dis)) (assert_msg "@$@unexpected PUT_ELSE_MATCH [putelse_matchany]") )) (install_method class_root put_else_match putelse_matchany) ;; method to putelse inside then-steps (defun putelse_matchstepthen (recv elsestep) (debug "putelse_matchstepthen recv=" recv "\n elsestep=" elsestep) (shortbacktrace_dbg "putelse_matchstepthen" 10) (assert_msg "check recv" (is_a recv class_match_step_then)) (debug "putelse_matchstepthen elsestep" elsestep) (assert_msg "check elsestep" (is_a elsestep class_match_step)) (compile_warning "temporary check for application depth..." (assert_msg "putelse_matchstepthen check shallow100" (melt_application_shallower 100))) (let ( (mythen (unsafe_get_field :mstep_then recv)) (elsestart (start_step elsestep)) ) (cond ( (== recv elsestart) (debug "putelse_matchstepthen recv same elsestart" recv) (return)) ( (== mythen elsestep) (debug "putelse_matchstepthen mythen same elsestep" mythen) (return)) ( (== mythen elsestart) (debug "putelse_matchstepthen mythen same elsestart" mythen) (return)) (mythen (debug "putelse_matchstepthen recursing in mythen" mythen) (debug "putelse_matchstepthen recursing for elsestart" elsestart) (debug "putelse_matchstepthen recursing from recv" recv) (put_else_match mythen elsestart) (debug "putelse_matchstepthen done recursing in mythen" mythen)) ) (debug "putelse_matchstepthen end recv" recv))) (install_method class_match_step_then put_else_match putelse_matchstepthen) ;; method to putelse inside tests (defun putelse_matchtest (recv elsestep) (debug "putelse_matchtest recv=" recv " elsestep=" elsestep) (shortbacktrace_dbg "putelse_matchtest" 10) (assert_msg "check recv" (is_a recv class_match_step_test)) (assert_msg "check elsestep" (is_a elsestep class_match_step)) (compile_warning "temporary check for application depth..." (assert_msg "putelse_matchtest check shallow100" (melt_application_shallower 100))) (let ( (myelse (unsafe_get_field :mstep_else recv)) (mythen (unsafe_get_field :mstep_then recv)) (elsestart (start_step elsestep)) ) (cond ( (== recv elsestep) (debug "putelse_matchtest recv same as elsestep=" recv) (return)) ( (== recv elsestart) (debug "putelse_matchtest recv same as elsestart=" recv) (return)) ( (== myelse elsestart) (debug "putelse_matchtest myelse same as elsestart=" recv) (return)) ( (== myelse elsestep) (debug "putelse_matchtest myelse same as elsestep=" recv) (return)) ( (== mythen elsestep) (debug "putelse_matchtest mythen same as elsestep=" recv) (return)) ( (== mythen elsestart) (debug "putelse_matchtest mythen same as elsestart=" recv) (return)) ( (null myelse) (put_fields recv :mstep_else elsestart) (debug "putelse_matchtest updated recv=" recv) (shortbacktrace_dbg "putelse_matchtest" 12) ) (:else (debug "putelse_matchtest myelse appending then" myelse) (put_then_match myelse elsestart) ) ) (if mythen (progn (debug "putelse_matchtest recursing in mythen=" mythen "\n..with elsestart=" elsestart) (put_else_match mythen elsestart))) ;; (debug "putelse_matchtest end recv=" recv) )) (install_method class_match_step_test put_else_match putelse_matchtest) ;;;;;;;;;;;;;;;; (defun putelse_matchgroup (recv elsestep) (debug "putelse_matchgroup recv=" recv "\n elsestep=" elsestep) (assert_msg "check recv" (is_a recv class_match_step_test_group)) (assert_msg "check elsestep" (is_a elsestep class_match_step)) (shortbacktrace_dbg "putelse_matchgroup" 10) (let ( (elsegroup (unsafe_get_field :mstgroup_else recv)) (elsestart (start_step elsestep)) (startgroup (unsafe_get_field :mstgroup_start recv)) ) (debug "putelse_matchgroup elsestart=" elsestart "\n startgroup=" startgroup) (when startgroup (debug "putelse_matchgroup recursing startgroup=" startgroup) (put_else_match startgroup elsestart) ) (debug "putelse_matchgroup elsegroup=" elsegroup) (cond ((null elsegroup) ()) ((is_a elsegroup class_match_step) (debug "putelse_matchgroup elsegroup=" elsegroup) (put_else_match elsegroup elsestart)) ((is_list elsegroup) (foreach_pair_component_in_list (elsegroup) (curpair curelse) (debug "putelse_matchgroup from list curelse=" curelse) (put_else_match curelse elsestart))) ((is_multiple elsegroup) (foreach_in_multiple (elsegroup) (curelse :long thix) (debug "putelse_matchgroup from tuple curelse=" curelse) (put_else_match curelse elsestart))) (:else (debug "putelse_matchgroup bad elsegroup=" elsegroup) (assert_msg "bad elsegroup" ()))) (debug "putelse_matchgroup end recv=" recv) )) (install_method class_match_step_test_group put_else_match putelse_matchgroup) ;;;;;;;;;;;;;;;; (defun scanstepdata_testins (step fun ctx) (assert_msg "check step" (is_a step class_match_step_test_instance)) (debug "scanstepdata_testins step=" step " fun=" fun) (let ( (slotup (unsafe_get_field :mstins_slots step)) ) (foreach_in_multiple (slotup) (curslot :long ix) (if curslot (fun curslot ctx))))) (install_method class_match_step_test_instance scan_step_data scanstepdata_testins) (defun scanstepdata_testtuple (step fun ctx) (debug "scanstepdata_testtuple step=" step " fun=" fun) (assert_msg "check step" (is_a step class_match_step_test_multiple)) (let ( (mtupcomp (get_field :msttup_components step)) ) (debug "scanstepdata_testtuple mtupcomp=" mtupcomp) (foreach_in_multiple (mtupcomp) (curcomp :long mix) (if curcomp (fun curcomp ctx)) ) )) (install_method class_match_step_test_multiple scan_step_data scanstepdata_testtuple) ;;; scan step data for test with flag is a no-op (defun scanstepdata_testwithflag (step fun ctx) (debug "scanstepdata_testwithflag step=" step " fun=" fun) ) (install_method class_match_step_with_flag scan_step_data scanstepdata_testwithflag) (defun scanstepdata_testmatcher (step fun ctx) (assert_msg "check step" (is_a step class_match_step_test_matcher)) (let ( (outs (unsafe_get_field :mstma_outs step)) ) (foreach_in_multiple (outs) (curout :long outix) (if curout (fun curout ctx))) )) (install_method class_match_step_test_matcher scan_step_data scanstepdata_testmatcher) ;;; (defun scanstepdata_testvariable (step fun ctx) (debug "scanstepdata_testvariable step=" step "\n fun=" fun "\n ctx=" ctx) (assert_msg "check step" (is_a step class_match_step_test_variable)) (let ( (tvdata (get_field :msteptestvar_data step)) ) (if tvdata (fun tvdata ctx))) ) (install_method class_match_step_test_variable scan_step_data scanstepdata_testvariable) ;;; (defun scanstepflag_stepwithflag (step fun ctx) (assert_msg "check step" (is_a step class_match_step_with_flag)) (let ( (flag (unsafe_get_field :mstep_flag step)) ) (if flag (fun flag ctx)) )) (install_method class_match_step_with_flag scan_step_flag scanstepflag_stepwithflag) (defun scanstepflag_stepflagoper (step fun ctx) (assert_msg "check step" (is_a step class_match_step_flag_operation)) (let ( (flag (unsafe_get_field :mstep_flag step)) (flagargs (unsafe_get_field :mstep_flagargs step)) ) (if flag (fun flag ctx)) (if flagargs (foreach_in_multiple (flagargs) (curflag :long flagix) (fun curflag ctx))) )) (install_method class_match_step_flag_operation scan_step_flag scanstepflag_stepflagoper) ;; scan step flag on step with data is a no-op (defun scanstepflag_stepwithdata (step fun ctx) (debug "scanstepflag_stepwithdata step=" step " fun=" fun) (assert_msg "check step" (is_a step class_match_step_with_data)) ) (install_method class_match_step_with_data scan_step_flag scanstepflag_stepwithdata) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; the selector to translate a pattern (defselector translate_pattern class_selector :doc #{Translate a pattern into a match step. $RECV is the receiver, $MDATA is the matched data, $MCASE is the match case, and $SLOC is the source location. Returns the match step and secundarily the match flag.}# :formals (recv mdata mcase varmap sloc)) (defun translpat_anyrecv (recv mdata mcase varmap sloc) (debug "translpat_anyrecv recv" recv) (debug "translpat_anyrecv mdata" mdata) (let ( (dis (discrim recv)) ) (debug "translpat_anyrecv dis" dis) (error_strv sloc "unexpected TRANSLATE_PATTERN for" (unsafe_get_field :named_name dis)) (assert_msg "@$@unexpected translpat_anyrecv") )) (install_method discr_any_receiver translate_pattern translpat_anyrecv) (defun translpat_jokerpat (recv mdata mcase varmap sloc) (assert_msg "check recv" (is_a recv class_source_pattern_joker_variable)) (debug "translpat_jokerpat recv" recv) (return) ) (install_method class_source_pattern_joker_variable translate_pattern translpat_jokerpat) (defun translpat_constpat (recv mdata mcase varmap psloc) (debug "translpat_constpat recv" recv) (assert_msg "check recv" (is_a recv class_source_pattern_constant)) (debug "translpat_constpat mdata" mdata) (assert_msg "check mdata" (is_a mdata class_matched_data)) (debug "translpat_constpat mcase" mcase) (assert_msg "check mcase" (is_a mcase class_match_case)) (let ( (sloc (or (unsafe_get_field :loca_location recv) psloc)) (spatweight (unsafe_get_field :pat_weight recv)) (sconstx (unsafe_get_field :spat_constx recv)) (mctxt (unsafe_get_field :mcase_mctxt mcase)) (ncx (get_field :mctx_normctxt mctxt)) (env (get_field :mctx_env mctxt)) (steplist (get_field :mdata_steps mdata)) ) (assert_msg "check ncx" (is_a ncx class_normalization_context)) (assert_msg "check env" (is_a env class_environment)) (assert_msg "check steplist" (is_list steplist)) (debug "translpat_constpat before normalization sconstx" sconstx) (multicall (nconst nbindconst) (normal_exp sconstx env ncx sloc) (debug "translpat_constpat nconst" nconst) (debug "translpat_constpat nbindconst" nbindconst) (let ( (mflag (make_match_flag recv mctxt (or (get_field :named_name nconst) '"constant_pattern"))) (flagstep (instance class_match_step_flag_set :loca_location sloc :mstep_then () :mstep_flag mflag)) (steptest (instance class_match_step_test_constant :loca_location sloc :mstep_data mdata :mstep_then flagstep :mstep_else () :msteptestconst_data nconst :msteptestconst_bind nbindconst )) ) (debug "translpat_constpat flagstep=" flagstep "\n steptest=" steptest) (shortbacktrace_dbg "translpat_constpat" 7) (list_append steplist steptest) (list_append steplist flagstep) (debug "translpat_constpat return steptest=" steptest "\n.. mflag=" mflag) (return steptest mflag) ;; )))) (install_method class_source_pattern_constant translate_pattern translpat_constpat) ;;;;;;;;;;;;;;;; (defun translpat_listpat (recv mdata mcase varmap sloc) (assert_msg "check recv" (is_a recv class_source_pattern_list)) (debug "translpat_listpat recv" recv) (error_plain sloc "@@unimplemented translpat_listpat") (assert_msg "$@$ translpat_listpat unimplemented") ) (install_method class_source_pattern_list translate_pattern translpat_listpat) ;;;;;;;;;;;;;;;; (defun translpat_tuplepat (recv mdata mcase varmap psloc) (debug "translpat_tuplepat recv=" recv " mdata=" mdata " mcase=" mcase) (assert_msg "check recv" (is_a recv class_source_pattern_tuple)) (assert_msg "check mdata" (is_a mdata class_matched_data)) (assert_msg "check mcase" (is_a mcase class_match_case)) (let ( (sloc (or (unsafe_get_field :loca_location recv) psloc)) (subpatup (unsafe_get_field :ctpat_subpa recv)) (:long nbsubpat (multiple_length subpatup)) (patcomplist (make_list discr_list)) (mctxt (unsafe_get_field :mcase_mctxt mcase)) ) (foreach_in_multiple (subpatup) (cursubpat :long patix) (debug "translpat_tuplepat cursubpat=" cursubpat " patix=" patix) (assert_msg "check cursubpat" (is_a cursubpat class_source_pattern)) (if (is_not_a cursubpat class_source_pattern_joker_variable) (let ( (tucomp (instance class_tuple_component_pattern :tupcp_pattern cursubpat :tupcp_index (make_integerbox discr_constant_integer patix))) ) (list_append patcomplist tucomp) ))) (debug "translpat_tuplepat patcomplist=" patcomplist) (let ( (rawpatcomptup (list_to_multiple patcomplist discr_multiple)) (sortedpatcomptup (multiple_sort rawpatcomptup (lambda (tc1 tc2) (let ( (:long wtc1 (get_int (get_field :pat_weight (get_field :tupcp_pattern tc1)))) (:long wtc2 (get_int (get_field :pat_weight (get_field :tupcp_pattern tc2)))) ) (cond ( (==i wtc1 wtc2) '0) ( (") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (compile_warning "testdata is usually not a symbol but a matched data...") (debug "mgaltstep_steptestvar testdata" testdata) (let ( (testdatasymb (get_field :mdata_symb testdata)) ) (add2out_string nodebuf (get_field :named_name testdatasymb)) (if (is_a testdatasymb class_cloned_symbol) (let ( (:long syrank (get_int (get_field :csym_urank testdatasymb))) ) (add2out_strconst nodebuf "$") (add2out_longdec nodebuf syrank) ))) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) (if elsename (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*else*/ -> ") (add2out_string edgebuf elsename) (add2out_strconst edgebuf " [ arrowhead=diamond, color=red ];") )) )) (install_method class_match_step_test_variable matchgraphic_altstep mgaltstep_steptestvar) ;;;;;;;;;;;;;;;; (defun mgaltstep_steptestinst (step mg) (debug "mgaltstep_steptestinst step" step) (assert_msg "check step" (is_a step class_match_step_test_instance)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (selse (unsafe_get_field :mstep_else step)) (testclass (unsafe_get_field :mstins_class step)) (testslots (unsafe_get_field :mstins_slots step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (elsename (if selse (mapobject_get stepmap selse))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (add2out_string nodebuf (get_field :named_name testclass)) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (foreach_in_multiple (testslots) (curslot :long slix) (if curslot (progn (assert_msg "check curslot" (is_a curslot class_matched_data)) (let ( (curslotdata (mapobject_get datamap curslot)) (fld (multiple_nth (get_field :class_fields testclass) slix)) (fldname (get_field :named_name fld)) ) (add2out_indentnl edgebuf 0) (assert_msg "check fld" (is_a fld class_field)) (add2out edgebuf ##{$STEPNAME /* testinslot */ -> /*data*/ $CURSLOTDATA [ arrowhead=open, label=<$FLDNAME>, color=violet, style=dotted ]; }#) ) )) ) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*then*/ -> $THENNAME [ arrowhead=normal, color=green ];}# ))) (if elsename (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*then*/ -> $ELSENAME [ arrowhead=diamond, color=red ];}# ))) )) (install_method class_match_step_test_instance matchgraphic_altstep mgaltstep_steptestinst) ;;;;;;;;;;;;;;;; (defun mgaltstep_steptestmult (step mg) (debug "mgaltstep_steptestmult step=" step) (assert_msg "check step" (is_a step class_match_step_test_multiple)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (sthen (unsafe_get_field :mstep_then step)) (selse (unsafe_get_field :mstep_else step)) (sdata (unsafe_get_field :mstep_data step)) (sindex (unsafe_get_field :mstep_index step)) (scomp (unsafe_get_field :msttup_components step)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (elsename (if selse (mapobject_get stepmap selse))) (:long stephash (obj_hash step)) (:long nbcomp (multiple_length scomp)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out nodebuf ##{ ^$NBCOMP}#) (add2out_strconst nodebuf "") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) ;; (debug "mgaltstep_steptestmult scomp=" scomp) (foreach_in_multiple (scomp) (curcomp :long cpix) (debug "mgaltstep_steptestmult curcomp=" curcomp " cpix=" cpix) (if curcomp (progn (assert_msg "check curcomp" (is_a curcomp class_matched_data)) (let ( (curcompdata (mapobject_get datamap curcomp)) ) (debug "mgaltstep_steptestmult curcompdata=" curcompdata " cpix=" cpix) (if (null curcompdata) (debug "mgaltstep_steptestmult bad datamap=" datamap " for curcomp=" curcomp)) (assert_msg "check curcompdata" curcompdata) (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /* testtuplcomp */ -> /*data*/ $CURCOMPDATA [ arrowhead=open, label=<[$CPIX]>, color=violet, style=dotted ]; }#) )))) ;; (if thenname (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*then*/ -> $THENNAME [ arrowhead=normal, color=green ];}# ))) (if elsename (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*else*/ -> $ELSENAME [ arrowhead=diamond, color=red ];}# ))) )) (install_method class_match_step_test_multiple matchgraphic_altstep mgaltstep_steptestmult) ;;;;;;;;;;;;;;;; (defun mgaltstep_steptestgroup (step mg) (debug "mgaltstep_steptestgroup step" step) (assert_msg "check step" (is_a step class_match_step_test_group)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (selse (unsafe_get_field :mstep_else step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (elsename (if selse (mapobject_get stepmap selse))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*then*/ -> $THENNAME [ arrowhead=normal, color=green ];}# ))) (if elsename (progn (add2out_indentnl edgebuf 0) (add2out edgebuf ##{$STEPNAME /*else*/ -> $ELSENAME [ arrowhead=diamond, color=red ];}# ))) )) (install_method class_match_step_test_group matchgraphic_altstep mgaltstep_steptestgroup) ;;;;;;;;;;;;;;;; (defun mgaltstep_steptestmatcher (step mg) (debug "mgaltstep_steptestmatcher step" step) (assert_msg "check step" (is_a step class_match_step_test_matcher)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (selse (unsafe_get_field :mstep_else step)) (smatcher (unsafe_get_field :mstma_matcher step)) (souts (unsafe_get_field :mstma_outs step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (elsename (if selse (mapobject_get stepmap selse))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (add2out_string nodebuf (get_field :named_name smatcher)) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (foreach_in_multiple (souts) (curout :long outix) (debug "mgaltstep_steptestmatcher curout" curout) (assert_msg "check curout" (is_a curout class_matched_data)) (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*matchstep*/ -> /*data*/ ") (add2out_string edgebuf (mapobject_get datamap curout)) (add2out_strconst edgebuf " [ arrowhead=open, ") (let ( (outbind (multiple_nth (get_field :amatch_out smatcher) outix)) (outsymb (get_field :binder outbind)) ) (if (is_a outsymb class_symbol) (progn (add2out_strconst edgebuf " label=<") (add2out_string edgebuf (get_field :named_name outsymb)) (add2out_strconst edgebuf ">, ")))) (add2out_strconst edgebuf " color=violet, style=dotted ];") ) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) (if elsename (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*else*/ -> ") (add2out_string edgebuf elsename) (add2out_strconst edgebuf " [ arrowhead=diamond, color=red ];") )) )) (install_method class_match_step_test_matcher matchgraphic_altstep mgaltstep_steptestmatcher) ;;;;;;;;;;;;;;;; (defun mgaltstep_stepsuccess (step mg) (debug "mgaltstep_stepsuccess step" step) (assert_msg "check step" (is_a step class_match_step_success_when_flag)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (sflag (unsafe_get_field :mstep_flag step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (:long stephash (obj_hash step)) (flagrank (get_field :mflag_rank sflag)) (flagstring (get_field :mflag_string sflag)) (flagloc (get_field :loca_location sflag)) (argfstep (get_field :mflag_setstep sflag)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (debug "mgaltstep_stepsuccess sflag" sflag) (assert_msg "check sflag" (is_a sflag class_match_flag)) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "flag#") (add2out_longdec nodebuf (get_int flagrank)) (add2out_strconst nodebuf " ") (add2out_string nodebuf flagstring) (add2out_strconst nodebuf " ") (add2sbuf_short_mixloc nodebuf flagloc) (add2sbuf_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) (if (is_a argfstep class_match_step_with_flag) (let ( (argfstepname (mapobject_get stepmap argfstep)) ) (debug "mgaltstep_stepsuccess argfstep" argfstep) (debug "mgaltstep_stepsuccess argfstepname" argfstepname) (assert_msg "mgaltstep_stepsuccess check argfstepname" (is_string argfstepname)) (add2out_indentnl edgebuf 0) (add2out_string edgebuf argfstepname) (add2out_strconst edgebuf " /*argflag suc*/ -> ") (add2out_string edgebuf stepname) (add2out_strconst edgebuf " [ arrowhead=olnormal, color=chartreuse2, style=dotted ];") )) )) (install_method class_match_step_success_when_flag matchgraphic_altstep mgaltstep_stepsuccess) ;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;; (defun mgaltstep_stepclear (step mg) (debug "mgaltstep_stepclear step" step) (assert_msg "check step" (is_a step class_match_step_clear)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (scleardata (unsafe_get_field :mstep_cleardata step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (foreach_in_multiple (scleardata) (curcdata :long cix) (if (>i cix 0) (add2out_strconst nodebuf " ")) (let ( (cdatanam (mapobject_get datamap curcdata)) ) (add2out_string nodebuf cdatanam) (add2out_indentnl edgebuf 0) (add2out_string edgebuf cdatanam) (add2out_strconst edgebuf " /*cleared data*/ -> ") (add2out_string edgebuf stepname) (add2out_strconst edgebuf " [ arrowhead=open,") (add2out_strconst edgebuf " color=violet, style=dotted ];") )) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) )) (install_method class_match_step_clear matchgraphic_altstep mgaltstep_stepclear) (defun mgaltstep_stepflagset (step mg) (debug "mgaltstep_stepflagset step" step) (assert_msg "check step" (is_a step class_match_step_flag_set)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (sflag (unsafe_get_field :mstep_flag step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) (flagrank (get_field :mflag_rank sflag)) (flagstring (get_field :mflag_string sflag)) (flagloc (get_field :loca_location sflag)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "flag#") (add2out_longdec nodebuf (get_int flagrank)) (add2out_strconst nodebuf " ") (add2out_string nodebuf flagstring) (add2out_strconst nodebuf " ") (add2sbuf_short_mixloc nodebuf flagloc) (add2sbuf_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) )) (install_method class_match_step_flag_set matchgraphic_altstep mgaltstep_stepflagset) ;;;;;;;;;;;;;;;; (defun mgaltstep_stepflagoper (step mg) (debug "mgaltstep_stepflagoper step" step) (assert_msg "check step" (is_a step class_match_step_flag_operation)) (assert_msg "check mg" (is_a mg class_match_graphic)) (let ( (loca (unsafe_get_field :loca_location step)) (sthen (unsafe_get_field :mstep_then step)) (sflag (unsafe_get_field :mstep_flag step)) (sflagargs (unsafe_get_field :mstep_flagargs step)) (nodebuf (unsafe_get_field :mchgx_nodout mg)) (edgebuf (unsafe_get_field :mchgx_edgout mg)) (datamap (unsafe_get_field :mchgx_datanamemap mg)) (stepmap (unsafe_get_field :mchgx_stepnamemap mg)) (stepname (mapobject_get stepmap step)) (thenname (if sthen (mapobject_get stepmap sthen))) (:long stephash (obj_hash step)) (dis (discrim step)) (clanam (get_field :named_name dis)) (flagrank (get_field :mflag_rank sflag)) (flagstring (get_field :mflag_string sflag)) (flagloc (get_field :loca_location sflag)) ) (add2out_strconst nodebuf "") (code_chunk outclanam #{ /* $OUTCLANAM */ meltgc_add_out ((melt_ptr_t) $NODEBUF, melt_string_str ((melt_ptr_t) $CLANAM) +6) ; }#) (add2out_strconst nodebuf " ") (add2out_strconst nodebuf "") (add2sbuf_short_mixloc nodebuf loca) (add2out_strconst nodebuf " ") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "flag#") (add2out_longdec nodebuf (get_int flagrank)) (if flagstring (progn (add2out_strconst nodebuf " ") (add2out_string nodebuf flagstring) )) (add2out_strconst nodebuf " ") (add2sbuf_short_mixloc nodebuf loca) (add2sbuf_strconst nodebuf " ") (if (is_multiple sflagargs) (progn (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "flags{") (foreach_in_multiple (sflagargs) (argflag :long argix) (assert_msg "check argflag" (is_a argflag class_match_flag)) (let ( (:long argrank (get_int (get_field :mflag_rank argflag))) (argfstep (get_field :mflag_setstep argflag)) ) (if (>i argrank 0) (progn (add2sbuf_strconst nodebuf " ") (add2sbuf_longdec nodebuf argrank) )) (if (is_a argfstep class_match_step_with_flag) (let ( (argfstepname (mapobject_get stepmap argfstep)) ) (debug "mgaltstep_stepflagoper argfstep" argfstep) (debug "mgaltstep_stepflagoper argfstepname" argfstepname) (if (null argfstepname) (debug "mgaltstep_stepflagoper bad stepmap" stepmap)) (assert_msg "check argstepname" (is_string argfstepname)) (add2out_indentnl edgebuf 0) (add2out_string edgebuf argfstepname) (add2out_strconst edgebuf " /*argflag flagop*/ -> ") (add2out_string edgebuf stepname) (add2out_strconst edgebuf " [ arrowhead=olnormal, color=chartreuse2, style=dotted ];") )) )) (add2sbuf_strconst nodebuf " } ") )) (if thenname (progn (add2out_indentnl edgebuf 0) (add2out_string edgebuf stepname) (add2out_strconst edgebuf " /*then*/ -> ") (add2out_string edgebuf thenname) (add2out_strconst edgebuf " [ arrowhead=normal, color=green ];") )) )) (install_method class_match_step_flag_operation matchgraphic_altstep mgaltstep_stepflagoper) ;;;;;;;;;;;;;;;; (compile_warning "missing other methods for matchgraphic_altstep on other step classes") (defun translate_matchcase (curmcase sloc prevstep) (debug "translate_matchcase curmcase=" curmcase "\n..prevstep=" prevstep) (shortbacktrace_dbg "translate_matchcase" 10) (assert_msg "check curmcase" (is_a curmcase class_match_case)) (let ( (matctx (unsafe_get_field :mcase_mctxt curmcase)) (curscas (unsafe_get_field :mcase_source curmcase)) (mloc (unsafe_get_field :loca_location curscas)) ) (assert_msg "check matctx" (is_a matctx class_matching_context)) (debug "translate_matchcase curscas" curscas) (debug "translate_matchcase prevstep" prevstep) (assert_msg "check curscas" (is_a curscas class_source_match_case)) (let ( (curloc (unsafe_get_field :loca_location curscas)) (curpat (unsafe_get_field :scam_patt curscas)) (curbody (unsafe_get_field :scam_body curscas)) (nmatx (unsafe_get_field :mctx_nmatched matctx)) (mdata (unsafe_get_field :mctx_mdata matctx)) (ncx (unsafe_get_field :mctx_normctxt matctx)) (env (unsafe_get_field :mctx_env matctx)) (varmap (make_mapobject discr_map_objects (+i 12 (*i 2 (mapobject_count (unsafe_get_field :mcase_varmap curmcase)))))) (sycmap (unsafe_get_field :nctx_symbcachemap ncx)) (newenv (fresh_env env)) ) (debug "translate_matchcase nmatx=" nmatx "\n.. curpat" curpat "\n.. mdata" mdata) (assert_msg "check ncx" (is_a ncx class_normalization_context)) (assert_msg "check env" (is_a env class_environment)) (multicall (mstep mflag) (translate_pattern curpat mdata curmcase varmap sloc) (debug "translate_matchcase got mstep=" mstep " mflag=" mflag " curbody=" curbody " varmap=" varmap) (foreach_in_mapobject (varmap) (cursym curmdata) (assert_msg "check cursym" (is_a cursym class_symbol)) (assert_msg "check curmdata" (is_a curmdata class_matched_data)) (let ( (matchbind (instance class_matched_binding :binder cursym :matchbind_data curmdata :matchbind_nbocc (make_integerbox discr_integer 0) )) ) (debug "translate_matchcase matchbind=" matchbind) (put_env newenv matchbind) )) (debug "translate_matchcase updated newenv=" newenv "\n before normalizing curbody=" curbody) (multicall (nbody nbinds) (normalize_tuple curbody newenv ncx sloc) (debug "translate_matchcase after body normalization nbody=" nbody "\n nbinds=" nbinds) (let ( (listvarocc (make_list discr_list)) (newbindmap (get_field :env_bind newenv)) (stepsucc (instance class_match_step_success_when_flag :loca_location sloc :mstep_then () :mstep_flag mflag :mstepsuccess_varocc () :mstepsuccess_binds nbinds :mstepsuccess_body nbody )) ) (foreach_in_mapobject (newbindmap) (bsymb binding) (if (and (is_a binding class_matched_binding) (>i (get_int (unsafe_get_field :matchbind_nbocc binding)) 0)) (let ( (syocc (mapobject_get sycmap bsymb)) ) (debug "translate_matchcase found syocc=" syocc) (assert_msg "check syocc" (is_a syocc class_nrep_locsymocc)) (assert_msg "check syocc binding" (== (get_field :nocc_bind syocc) binding)) (list_append listvarocc syocc) ) )) (debug "translate_matchcase listvarocc=" listvarocc "\n mstep" mstep) (let ( (sortedvarocc (multiple_sort (list_to_multiple listvarocc discr_multiple) (lambda (o1 o2) (compare_named_alpha (get_field :nocc_symb o1) (get_field :nocc_symb o2))) discr_multiple)) ) (debug "translate_matchcase sortedvarocc=" sortedvarocc) (put_fields stepsucc :mstepsuccess_varocc sortedvarocc)) (debug "translate_matchcase before putthen stepsucc=" stepsucc " mstep=" mstep) (put_then_match mstep stepsucc) (debug "translate_matchcase updated mstep=" mstep "\n.. prevstep=" prevstep) (when prevstep (debug "translate_matchcase before put_else_match prevstep=" prevstep "\n.. mstep=" mstep) ;;@@@@@THIS IS PROBABLY NEEDED@@@@ (put_else_match prevstep mstep) ;; beware: tmatch-5.melt is now looping ) (debug "translate_matchcase updated prevstep=" prevstep) (debug "translate_matchcase return mstep=" mstep "\n stepsucc" stepsucc) (return mstep stepsucc) )))))) ;;;; normal representation for alternate match uses match blocks (defclass class_nrep_matchalt :super class_nrep_typed_expression :doc #{The $CLASS_NREP_MATCHALT is the representation for normal matches. Field $NAMATCH_MATCHED is the normal matched stuff. $NAMATCH_RESULT gives if any the result of the match. $NAMATCH_BODY is the body tuple, in particular labels of $CLASS_NREP_MATCH_LABEL. $NAMATCH_FLAGS is the tuple of normal flags, instances of $CLASS_NREP_MATCH_FLAG, and $NAMATCH_MDATAS is the tuple of normal data, instances of $CLASS_NREP_MATCHED_DATA.}# :fields ( namatch_matched ;the normal matched stuff namatch_result ;the local for the result namatch_body ;the body namatch_flags ;the tuple of normalized flags namatch_mdatas ;the tuple of normalized match data namatch_startlabel )) (defclass class_nrep_match_label :super class_nrep_expression :doc #{ A normal match label of $CLASS_NREP_MATCH_LABEL is just a point which can be jumped to. It corresponds to a match step given by the field $NMLAB_STEP.}# :fields (nmlab_step)) (defclass class_nrep_match_label_end :super class_nrep_match_label :doc #{The $CLASS_NREP_MATCH_LABEL_END is for the end label.}#) (defclass class_nrep_match_jump :super class_nrep_expression :doc #{ A normal match jump of $CLASS_NREP_MATCH_JUMP is just a goto to a match label given by field $NMJMP_LABEL. }# :fields (nmjmp_label)) (defclass class_nrep_match_data_action :super class_nrep_expression :doc #{The $CLASS_NREP_MATCH_DATA_ACTION is the common super-class for actions concerning a normal match data $NMDAC_DATA.}# :fields (nmdac_data)) (defclass class_nrep_match_data_initializer :super class_nrep_match_data_action :doc #{ A normal match data initializer of $CLASS_NREP_MATCH_DATA_INITIALIZER initializes, allocates resource, and clears a normal match data given by field $NMDAC_DATA.}# :fields ()) (defclass class_nrep_match_data_clear :super class_nrep_match_data_action :doc #{ A normal match data clear of $CLASS_NREP_MATCH_DATA_CLEAR clears a normal match data given by field $NMDAC_DATA.}# :fields ()) (defclass class_nrep_match_data_finalizer :super class_nrep_match_data_action :doc #{ A normal match data finalizer of $CLASS_NREP_MATCH_DATA_FINALIZER finalizes and unleashes the resources associated with a normal match data given by field $NMDAC_DATA.}# :fields ()) (defclass class_nrep_jump_when_is_a :super class_nrep_expression :doc #{The $CLASS_NREP_JUMP_WHEN_IS_A is testing if a simple value $NTESTISA_VALUE us an instance of $NTESTISA_CLASS. If yes, it jumps to $NTESTISA_JUMP.}# :fields (ntestisa_value ntestisa_class ntestisa_jump)) (defclass class_match_normalization_context :super class_root :doc #{The $CLASS_MATCH_NORMALIZATION_CONTEXT is agreggating data for normalization of a graph of match steps, indirect instances of $CLASS_MATCH_STEP. Field $MATNORX_RESLOC gives the instance of $CLASS_NREP_LOCSYMOCC for the result of the match. $MATNORX_NMATCH gives the partially built normal representation, instance of $CLASS_NREP_MATCHALT, of the match. Field $MATNORX_FLAGMAP is the read-mostly map associating match flags to normalized flags. Field $MATNORX_STEPMAP is the read-mostly map associating match steps to labels of $CLASS_NREP_MATCH_LABEL. Field $MATNORX_MDATAMAP is the read-mostly map associating match datas to their normalization. $MATNORX_MDATAQUEUE is the read-mostly queue list of match datas to process. $MATNORX_MSTEPQUEUE is the read-mostly queue list of match steps, with already an associated label, to process. $MATNORX_BODYLIST is the incomplete list of the match body. $MATNORX_ENDLABEL is the ending label. $MATNORX_MATCHCTXT gives the matching context of $CLASS_MATCHING_CONTEXT.}# :fields (matnorx_resloc matnorx_nmatch matnorx_datamap matnorx_flagmap matnorx_stepmap matnorx_mdataqueue matnorx_mstepqueue matnorx_bodylist matnorx_endlabel matnorx_startlabel matnorx_matchctxt )) ;;; utility to normalize a flag with a match normalization context (defun matchalt_normalize_flag (flag nmctxt) (debug "matchalt_normalize_flag flag" flag) (assert_msg "matchalt_normalize_flag check flag" (is_a flag class_match_flag)) (assert_msg "matchalt_normalize_flag check nmctxt" (is_a nmctxt class_match_normalization_context)) (let ( (flagmap (unsafe_get_field :matnorx_flagmap nmctxt)) (nfla (mapobject_get flagmap flag)) (nmatch (unsafe_get_field :matnorx_nmatch nmctxt)) ) (if (null nfla) (progn (setq nfla (instance class_nrep_match_flag :nrpfla_flag flag :nrpfla_nmatch nmatch)) (mapobject_put flagmap flag nfla))) (assert_msg "matchalt_normalize_flag check nfla" (is_a nfla class_nrep_match_flag)) (return nfla) )) ;;;;;;;;;;;;;;;; (defselector normalize_step class_selector :doc #{The selector $NORMALIZE_STEP normalize a given $STEP within a match normalization context $NMCTXT, a source location $SLOC, and returns a list or tuple of normalized expressions, or a single such normalized expression.}# :formals (step nmctxt sloc) ) ;; utility function to update each index of data steps in a data (defun match_data_update_data_steps_index (mdata) (debug "match_data_update_steps_index mdata=" mdata) (assert_msg "check mdata" (is_a mdata class_matched_data)) (let ( (msteps (get_field :mdata_steps mdata)) ) (cond ( (is_list_or_null msteps) (let ( (msteptup (list_to_multiple msteps)) ) (debug "match_data_update_steps_index msteptup=" msteptup) (foreach_in_multiple (msteptup) (curmstep :long stix) (debug "match_data_update_data_steps_index curmstep=" curmstep) (if (is_a curmstep class_match_step_with_data) (let ( (oldixv (unsafe_get_field :mstep_index curmstep)) ) (if oldixv (assert_msg "check oldix" (==i (get_int oldixv) (+i stix 1))) (unsafe_put_fields curmstep :mstep_index (make_integerbox discr_constant_integer (+i stix 1)))))) ) (put_fields mdata :mdata_steps msteptup) (debug "match_data_update_data_steps_index updated msteptup=" msteptup "\n* updated mdata=" mdata) ) ) ( (is_multiple msteps) (debug "match_data_update_data_steps_index already tuple msteps=" msteps) ) (:else (debug "match_data_update_data_steps_index unexpected msteps=" msteps) (assert_msg "@$@unexpected msteps in match_data_update_data_steps_index" ()))))) ;; utility function to compute the index of a match step and update ;; the mdata_steps of its data to a tuple (defun match_step_index (mstep) (debug "match_step_index mstep start" mstep) (assert_msg "check mstep" (is_a mstep class_match_step)) (if (is_not_a mstep class_match_step_with_data) (progn (debug "match_step_index mstep without data so return nil" mstep) (return))) (let ( (matindex (unsafe_get_field :mstep_index mstep)) ) (if matindex (progn (assert_msg "check matindex" (is_integerbox matindex)) (return matindex)) (let ( (matdata (get_field :mstep_data mstep)) ) (debug "match_step_index matdata before match_data_update_data_steps_index" matdata) (match_data_update_data_steps_index matdata) (debug "match_step_index matdata after match_data_update_data_steps_index" matdata) (setq matindex (unsafe_get_field :mstep_index mstep)) (debug "match_step_index final matindex" matindex) (assert_msg "match_step_index bad matindex" (is_integerbox matindex)) (return matindex) )))) ;; this utility function completes a normstep if the step is the last ;; in its data, or else return the normstep unchanged... (defun complete_normstep_if_last (step normstep nmctxt) (debug "complete_normstep_if_last start step=" step "\n normstep=" normstep) (assert_msg "check step" (is_a step class_match_step)) (assert_msg "check nmctxt" (is_a nmctxt class_match_normalization_context)) (shortbacktrace_dbg "complete_normstep_if_last" 7) (when (is_not_a step class_match_step_with_data) (debug "complete_normstep_if_last returning unchanged normstep=" normstep "\n without data step=" step) (return normstep)) ;; (let ( (matdata (get_field :mstep_data step)) ) (debug "complete_normstep_if_last matdata=" matdata) (assert_msg "check matdata" (is_a matdata class_matched_data)) (match_data_update_data_steps_index matdata) (debug "complete_normstep_if_last updated matdata=" matdata) (let ( (matindex (match_step_index step)) (datamap (get_field :matnorx_datamap nmctxt)) (ndata (mapobject_get datamap matdata)) ) (debug "complete_normstep_if_last matindex=" matindex "\n ndata=" ndata "\n datamap=" datamap) (assert_msg "check datamap" (is_mapobject datamap)) (assert_msg "check matindex" (is_integerbox matindex)) (assert_msg "check ndata" (is_a ndata class_nrep_simple)) (let ( (:long numindex (get_int matindex)) (datasteps (get_field :mdata_steps matdata)) (:long nbdatasteps (multiple_length datasteps)) ) (assert_msg "check numindex" (>i numindex 0)) (assert_msg "check nbdatasteps" (>i nbdatasteps 0)) (assert_msg "good numindex" (<=i numindex nbdatasteps)) (if (i curnrk 0)) (assert_msg "emprty datatup slot" (null (multiple_nth ndatatup curnrkm1))) (multiple_put_nth ndatatup curnrkm1 curndata) ) ) (list_append nbodyl endlab) (debug "normexp_matchalt ndatatup=" ndatatup "\n *nbodyl=" nbodyl) ;; (put_fields nresmatch :namatch_matched nmatx ;; normal matched stuff :namatch_result nresloc :namatch_body (list_to_multiple nbodyl) :namatch_flags sortedflagstup :namatch_mdatas ndatatup :namatch_startlabel nstartlab ) (let ( (csym (clone_symbol 'matchaltres_)) (cbind (instance class_normal_let_binding :letbind_loc sloc :binder csym :letbind_type matresctyp :letbind_expr nresmatch)) (clocc (instance class_nrep_locsymocc :nrep_loc sloc :nocc_ctyp matresctyp :nocc_symb csym :nocc_bind cbind )) ) (debug "normexp_matchalt nresmatch=" nresmatch "\n* of discrim:" (discrim nresmatch) "\n* matresctyp=" matresctyp ) (debug "normexp_matchalt final nresbind=" nresbind "\n cbind=" cbind "\n clocc=" clocc "\n nresloc=" nresloc) (return clocc (list nresbind cbind)) )))))))))) (install_method class_source_matchalt normal_exp normexp_matchalt) ;;;;;;;;;;;;;;;; (defun alternate_match_optset (optsymb :cstring opts) (debug "alternate_match_optset optsymb" optsymb) (informsg_plain "exchange alternate matching implementation") (install_method class_source_match normal_exp normexp_matchalt) (install_method class_source_matchalt normal_exp normexp_matchalt) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; display the graphic of matchalt normalization for Graphviz in .dot ;; format notice that the numbering of steps is local to this ;; function... (defun mg_altdraw_graphviz (mdata dotprefix) (let ( (mapdata (make_mapobject discr_map_objects 43)) (mapstep (make_mapobject discr_map_objects 43)) (nodebuf (make_strbuf discr_strbuf)) (edgebuf (make_strbuf discr_strbuf)) (datacountbox (make_integerbox discr_integer 0)) (:long cnt 0) (:long mdatahash (obj_hash mdata)) (pathsbuf (make_strbuf discr_strbuf)) (dotfilename (progn (code_chunk uniqcnt #{ /* mg_draw_match_graphviz_file $UNIQCNT */ static long uniqcounter ; uniqcounter ++ ; $CNT = uniqcounter ; }#) (assert_msg "check pathsbuf" (is_strbuf pathsbuf)) (add2sbuf_string pathsbuf dotprefix) (add2sbuf_strconst pathsbuf "+") (add2sbuf_longdec pathsbuf cnt) (add2sbuf_strconst pathsbuf ".dot") (debug "mg_draw_match_graphviz_file pathsbuf" pathsbuf) (strbuf2string discr_string pathsbuf))) (mg (instance class_match_graphic :mchgx_filename dotfilename :mchgx_nodout nodebuf :mchgx_edgout edgebuf :mchgx_datanamemap mapdata :mchgx_stepnamemap mapstep )) ) ;; recursive scan of data & steps to fill the mapdata associating ;; each data with its printable name and mapstep associating each ;; step with its printable name (letrec ( (scandata (lambda (data) (debug "mg_altdraw_graphviz/scandata data=" data) (assert_msg "mg_altdraw_graphviz.scandata check data" (is_a data class_matched_data)) (let ( (oldname ( (mapobject_get mapdata data) )) ) (if oldname (progn (debug "mg_altdraw_graphviz/scandata found oldname" oldname) (return oldname)))) (let ( (nambuf (make_strbuf discr_strbuf)) (msymb (unsafe_get_field :mdata_symb data)) (:long datacnt (+i 1 (get_int datacountbox))) (msteps (unsafe_get_field :mdata_steps data)) (symbname (get_field :named_name msymb)) ) (add2out nambuf ##{mdata_$DATACNT#_$SYMBNAME}#) (put_int datacountbox datacnt) (if (is_a msymb class_cloned_symbol) (let ( (:long clonrk (get_int (get_field :csym_urank msymb))) ) (add2out nambuf ##{__$CLONRK}#))) (let ( (newname (strbuf2string discr_string nambuf)) ) (mapobject_put mapdata data newname) (debug "mg_altdraw_graphviz/scandata newname=" newname " updated mapdata=" mapdata) (foreach_pair_component_in_list (msteps) (curpair curstep) (scanstep curstep)) (return newname) ) ))) (scanstep (lambda (step) (debug "mg_altdraw_graphviz/scanstep step=" step) (assert_msg "mg_altdraw_graphviz.scanstep check step" (is_a step class_match_step)) (let ( (oldname (mapobject_get mapstep step)) ) (if oldname (progn (debug "mg_altdraw_graphviz.scanstep found oldname" oldname) (return oldname)))) (let ( (nambuf (make_strbuf discr_strbuf)) (:long mapcnt (mapobject_count mapstep)) (disnam (get_field :named_name (discrim step))) ;; not every step has a data (sdata (get_field :mstep_data step)) ) (code_chunk chunkdisnam #{/*$CHUNKDISNAM*/ meltgc_add_strbuf ((melt_ptr_t)$NAMBUF, melt_string_str ((melt_ptr_t)$DISNAM) + strlen("CLASS_")) }#) (add2sbuf_strconst nambuf "_ms_") (add2sbuf_longdec nambuf (+i mapcnt 1)) (mapobject_put mapstep step (strbuf2string discr_string nambuf)) (if sdata (scandata sdata)) (scan_step_data step scandata ()) (scan_step_flag step scanflag ()) (let ( ;;; these are checked get fields!! (sthen (get_field :mstep_then step)) (selse (get_field :mstep_else step)) (sflag (get_field :mstep_flag step)) ) (if sthen (scanstep sthen)) (if selse (scanstep selse)) (if sflag (scanflag sflag)) )))) (scanflag (lambda (flag) (debug "mg_altdraw_graphviz.scanflag flag=" flag) (let ( (flstep (get_field :mflag_setstep flag)) ) (if flstep (progn (debug "mg_altdraw_graphviz.scanflag flstep" flstep) (assert_msg "check flstep" (is_a flstep class_match_step)) (scanstep flstep) )) ))) ) (debug "mg_altdraw_graphviz before scandata mdata=" mdata " scandata=" scandata) (assert_msg "check mdata" (is_a mdata class_matched_data)) (scandata mdata) (debug "mg_altdraw_graphviz after scandata mdata=" mdata " mapdata=" mapdata " mapstep=" mapstep) ) (let ( (:long datacount 0) (:long stepcount 0) (tupdata (make_multiple discr_multiple (mapobject_count mapdata))) (tupstep (make_multiple discr_multiple (mapobject_count mapstep))) ) (foreach_in_mapobject (mapdata) (curdata dataname) (multiple_put_nth tupdata datacount curdata) (setq datacount (+i 1 datacount)) ) (foreach_in_mapobject (mapstep) (curstep stepname) (multiple_put_nth tupstep stepcount curstep) (setq stepcount (+i 1 stepcount)) ) (let ( (sortupdata (multiple_sort tupdata (lambda (d1 d2) (let ( (sn1 (mapobject_get mapdata d1)) (sn2 (mapobject_get mapdata d2)) ) (cond ( (string< sn1 sn2) '-1) ( (string> sn1 sn2) '1) (:else '0 ))) ) discr_multiple )) (sortupstep (multiple_sort tupstep (lambda (s1 s2) (let ( (sn1 (mapobject_get mapstep s1)) (sn2 (mapobject_get mapstep s2)) ) (cond ( (string< sn1 sn2) '-1) ( (string> sn1 sn2) '1) (:else '0 ))) ) discr_multiple )) ) ;; draw the data nodes (debug "mg_altdraw_graphviz sortupdata" sortupdata) (foreach_in_multiple (sortupdata) (curdata :long dix) (debug "mg_altdraw_graphviz curdata" curdata) (assert_msg "mg_altdraw_graphviz check curdata" (is_a curdata class_matched_data)) (let ( (curdataname (mapobject_get mapdata curdata)) (datactype (unsafe_get_field :mdata_ctype curdata)) (datasymb (unsafe_get_field :mdata_symb curdata)) (datasteps (unsafe_get_field :mdata_steps curdata)) ) (add2out_indentnl nodebuf 0) (add2out_string nodebuf curdataname) (add2out_strconst nodebuf " [ margin=0, ") (if (== curdata mdata) (add2out_strconst nodebuf " style=\"bold,dashed,filled,rounded\", fillcolor=\"lightyellow\", ") (add2out_strconst nodebuf " style=\"dashed,rounded\", ")) (add2out_strconst nodebuf "label=<") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (add2out_strconst nodebuf "
") (add2out_string nodebuf curdataname) (add2out_strconst nodebuf " #") (add2out_longhex nodebuf (obj_hash curdata)) (add2out_strconst nodebuf "
") (add2out_string nodebuf (get_field :named_name datasymb)) (if (is_a datasymb class_cloned_symbol) (let ( (:long clonum (get_int (unsafe_get_field :csym_urank datasymb))) ) (add2out nodebuf ##{$CLONUM}#) )) (add2out_strconst nodebuf " ") (add2out_string nodebuf (get_field :named_name (get_field :ctype_keyword datactype))) (add2out_strconst nodebuf "
> ];") (add2out_indentnl nodebuf 0) ;;; output edges to the steps (foreach_pair_component_in_list (datasteps) (pairstep curstep) (add2out_indentnl edgebuf 0) (add2out_string edgebuf curdataname) (add2out_strconst edgebuf " /*data*/ -> /*step*/ ") (add2out_string edgebuf (mapobject_get mapstep curstep)) (add2out_strconst edgebuf " [ arrowhead=open, color=blueviolet, style=dotted ];") ) ) ) ;; draw the step nodes (debug "mg_altdraw_graphviz sortupstep" sortupstep) (foreach_in_multiple (sortupstep) (curstep :long dix) (debug "mg_altdraw_graphviz curstep" curstep) (assert_msg "mg_altdraw_graphviz check curstep" (is_a curstep class_match_step)) (let ( (curstepname (mapobject_get mapstep curstep)) ) (assert_msg "mg_altdraw_graphviz check curstepname" (is_string curstepname)) (add2out_indentnl nodebuf 0) (add2out_string nodebuf curstepname) (add2out_strconst nodebuf " [ margin=0, ") (if (is_a curstep class_match_step_success_when_flag) (add2out_strconst nodebuf " style=\"filled\", bgcolor=\"palegreen\", ") ) (add2out_strconst nodebuf "label=<") (add2out_indentnl nodebuf 0) (add2out_strconst nodebuf "") (add2out_indentnl nodebuf 0) (matchgraphic_altstep curstep mg) (add2out_strconst nodebuf "
") (add2out_string nodebuf curstepname) (add2out_strconst nodebuf " #") (add2out_longhex nodebuf (obj_hash curstep)) (add2out_strconst nodebuf "
> ];") (add2out_indentnl nodebuf 0) ) ) ;; output the file (let ( ) (code_chunk outputmgfile #{ /* $outputmgfile start */ time_t nowt = 0 ; char nowbuf[60] ; FILE* dotfil = fopen (melt_string_str ((melt_ptr_t) $DOTFILENAME), "w") ; if (!dotfil) melt_fatal_error ("failed to open matchdot file %s - %m", melt_string_str ((melt_ptr_t) $DOTFILENAME)) ; fprintf (dotfil, "// melt matchdot file %s\n", melt_string_str ((melt_ptr_t) $DOTFILENAME)) ; time (&nowt) ; memset (nowbuf, 0, sizeof(nowbuf)) ; strftime (nowbuf, sizeof(nowbuf)-1, "%Y %b %d %Hh%M", localtime (&nowt)) ; fprintf (dotfil, "// generated %s\n", nowbuf) ; fprintf (dotfil, "digraph meltmatchalt_%lx {", $MDATAHASH) ; fprintf (dotfil, " graph [ label=<Melt Alt Match %s ** %s>,", lbasename (melt_string_str ((melt_ptr_t) $DOTFILENAME)), nowbuf) ; fprintf (dotfil," pad=\"0.5\", margin=\"0.3\" ];\n") ; fprintf (dotfil, " node [ shape=\"box\", fontsize=\"9\" ];\n") ; melt_putstrbuf (dotfil, (melt_ptr_t) $NODEBUF) ; fprintf (dotfil, "\n /// edges\n") ; melt_putstrbuf (dotfil, (melt_ptr_t) $EDGEBUF) ; fprintf (dotfil, "\n} // eof %s\n", melt_string_str ((melt_ptr_t) $DOTFILENAME)) ; fclose (dotfil) ; /* $outputmgfile end */ }#) ))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; export our classes (export_class class_pattern_context class_normtester_any class_normtester_anytester class_normtester_disjunction class_normtester_instance class_normtester_matcher class_normtester_or_clear class_normtester_or_initial_clear class_normtester_or_transmit class_normtester_same class_normtester_success class_normtester_tuple class_nrep_match ;; ;; for alternate matching class_match_case class_match_flag class_match_normalization_context class_match_step class_match_step_clear class_match_step_flag_conjunction class_match_step_flag_disjunction class_match_step_flag_operation class_match_step_flag_set class_match_step_success_when_flag class_match_step_test class_match_step_test_group class_match_step_test_instance class_match_step_test_matcher class_match_step_test_multiple class_match_step_test_variable class_match_step_then class_match_step_with_data class_match_step_with_flag class_matched_binding class_matched_data class_matched_normal_data class_matching_context ;; class_nrep_matchalt class_nrep_jump_when_is_a class_nrep_match_data_action class_nrep_match_data_clear class_nrep_match_data_finalizer class_nrep_match_data_initializer class_nrep_match_flag class_nrep_match_jump class_nrep_match_label class_nrep_match_label_end class_nrep_matched_data ) ;;; export our values (export_values scan_pattern normal_pattern ) ;; eof warmelt-normatch.melt