PreviousUpNext

15.4.116  src/app/makelib/stuff/string-substitution.pkg

## string-substitution.pkg -- a string substitution facility.
## (C) 2001 Lucent Technologies, Bell Labs
## author: Matthias Blume (blume@research.bell-labs.com)

# Compiled by:
#     src/app/makelib/stuff/makelib-stuff.sublib


package string_substitution
:
api {

    Substitution = substring::Substring -> Null_Or( String );

    # Given the spec (1st argument), scan the second argument for
    # all occurences of prefixes and try the substitutions (left-to-right)
    # associated with the matching prefix until one matches.

    substitute:  List {
                        prefix:          String,
                        substitutions:   List( Substitution )
                     } 
                  -> String
                  -> String;

    #  A simple string replacement substitution 

    subfor:  String -> String -> Substitution;

    # Given prefix length and stop character,
    # use a given substitution on the subslice
    # without prefix and stop char

    submap:  (Int
               , Char)
              -> Substitution
              -> Substitution;

    # A list selection substitution:
    #  The first argument is the general spec, the second argument is the
    #  list to select from.  The general spec consists of:
    # - the length of the prefix (the prefix will be ignored),
    # - the stop character (which will also be ignored
    # - a selector that extracts the substitution string from a list element
    # - a separator string used when n = 0 or missing (the whole list gets
    #   inserted in this case, with the separator string separating elements)


    subnsel:  (Int
                , Char
                , (X -> String)
                , String)
               -> List(X)
               -> Substitution;

}
{
    package ss= substring;              # substring     is from   src/lib/std/substring.pkg

    Substitution = ss::Substring -> Null_Or( String );

    fun substitute rules
        =
        do_it
        where
            rules
                =
                map (fn { prefix, substitutions }
                        =
                        { prefix => ss::from_string prefix, substitutions })
                    rules;

            fun do_it s
                =
                loop (0, 0, [])
                where
                    len =  size s;

                    fun loop (i0, i, acc)
                        =
                        {   fun matchingrule { prefix, substitutions }
                                =
                                {   plen =  ss::size prefix;
                                
                                    i + plen  <=  len
                                    and
                                    ss::compare (prefix, ss::make_substring (s, i, plen))  ==  EQUAL;
                                };

                            fun findrule ()
                                =
                                null_or::map .substitutions (list::find matchingrule rules);

                            fun newacc k
                                =
                                if   (k > i0)
                                    
                                     ss::make_substring (s, i0, k - i0) ! acc;
                                else
                                     acc;
                                fi;
                        
                            if   (i >= len)
                                
                                 ss::cat (reverse (newacc len));
                            else
                                 case (findrule ())
                                   
                                      NULL => loop (i0, i + 1, acc);

                                      THE substitutions
                                       =>
                                       {   acc = newacc i;

                                           fun dosubst j
                                               =
                                               {   fun finddosubst []
                                                           =>
                                                           dosubst (j + 1);

                                                       finddosubst (replace ! sl)
                                                           =>
                                                           {   ss = ss::make_substring (s, i, j - i);

                                                               case (replace ss)
                                                                    NULL => finddosubst sl;
                                                                   THE r
                                                                    =>
                                                                    loop (j, j, ss::from_string r ! acc);
                                                               esac;
                                                           };
                                                   end;

                                                   if   (j > len)
                                                       
                                                        loop (i, len, acc);
                                                   else
                                                        finddosubst substitutions;
                                                   fi;
                                               };

                                           dosubst (i + 1);
                                       };
                                 esac;
                            fi;
                        };
                end;
        end;

    fun subfor p r ss
        =
        if     (substring::compare (substring::from_string p, ss)  ==  EQUAL)
               THE r;
        else   NULL;  fi;

    fun submap (plen, stopchar) m ss
        =
        {   sslen = ss::size ss;
        
            if     (ss::get (ss, sslen - 1) == stopchar)
                
                   m (ss::make_slice (ss, plen, THE (sslen - plen - 1)));
            else
                   NULL;
            fi;
        };

    fun subnsel (plen, stopchar, sel, sep) l ss
        =
        submap (plen, stopchar)  m  ss
        where
            fun m numslice
                =
                {   nums = ss::to_string numslice;

                    fun all ()
                        =
                        THE (string::join sep (map sel l));

                    fun seli i
                        =
                        THE ( sel (list::nth (l, i))
                              except
                                  (exceptions::SUBSCRIPT|exceptions::INDEX_OUT_OF_BOUNDS) =  ss::to_string ss
                            );
                
                    if     (nums == "")
                        
                           all ();
                    else
                           case (int::from_string nums)
                             
                                THE 0 =>  all ();
                                THE i =>  seli (i - 1);
                                NULL  =>  THE (ss::to_string ss);
                           esac;
                    fi;
                };
        
        end;
};


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext