PreviousUpNext

15.4.131  src/app/makelib/tools/noweb/tool.pkg

# A tool for source code written using Norman Ramsey's "noweb".
#
#   (C) 2000 Lucent Technologies, Bell Laboratories
#
# Author: Matthias Blume (blume@kurims.kyoto-u.ac.jp)

# Compiled by:
#     src/app/makelib/tools/noweb/noweb-tool.lib

stipulate
    package fil =  file__premicrothread;                                # file__premicrothread  is from   src/lib/std/src/posix/file--premicrothread.pkg
herein

    package noweb_tool {
        #
        stipulate
            #
            include package   tools;

            tool = "Noweb";
            ilk = "noweb";

            std_cmd_path = "notangle";

            kw_subdir = "subdir";
            kw_witness = "witness";
            kw_target = "target";       #  "master" keyword 

            kw_name = "name";           #  sub-keywords... 
            kw_root = "root";
            kw_ilk = "ilk";
            kw_options = "options";
            kw_lineformat = "lineformat";

            keywords = [kw_name, kw_root, kw_ilk, kw_options, kw_lineformat];

            dfl_subdir = "NW";

            fun err msg = raise exception TOOL_ERROR { tool, msg };
            fun kwerr what kw = err (cat [what, " keyword `", kw, "'"]);
            fun badkw kw = kwerr "unknown" kw;
            fun misskw kw = kwerr "missing" kw;
            fun badspec kw = kwerr "bad specification for " kw;
            fun dup kw = kwerr "duplicate" kw;

            package string_map
                =
                red_black_map_g(                                                # red_black_map_g               is from   src/lib/src/red-black-map-g.pkg

                     Key = String;
                     compare = string::compare;
                );

            lnr = REF (fold_forward

                           string_map::set'

                           string_map::empty

                           [ ("sml", "/*#line %L \"%F\"*/"),
                             ("cm", "#line %L %F%N")
                           ]
                      );

            fun rule { spec, context, native2pathmaker, default_ilk_of, sysinfo }
                =
                {   spec ->  { name => str, make_path, tool_options => too, derived, ... } : Spec;
                    p = srcpath (make_path ());
                    sname = native_spec p;

                    my (sd, wn)    #  "wn" probably means "witness" (meaning "timestampFile") all through the following code. 
                        =           #  "s" and "t" are generally "source" and "target" (filename) 
                        case too
                            #                 
                            NULL => (NULL, NULL);

                            THE l
                                =>
                                loop (l, NULL, NULL)
                                where
                                    fun loop ([], sd, wn)
                                            =>
                                            (sd, wn);

                                        loop (STRING _ ! t, sd, wn)
                                            =>
                                            loop (t, sd, wn);

                                        loop (SUBOPTS { name, tool_options => [STRING s] } ! t, sd, wn)
                                            =>
                                            if (name == kw_subdir)
                                                #
                                                case sd
                                                    #
                                                    NULL  =>  loop (t, THE (s.make_path ()), wn);
                                                    #
                                                    THE _ =>  dup kw_subdir;
                                                esac;

                                            else
                                                if (name == kw_witness)
                                                    #
                                                    case wn
                                                        #
                                                        NULL  =>   loop (t, sd, THE (s.make_path ()));
                                                        #
                                                        THE _ =>   dup kw_witness;
                                                    esac;
                                                else
                                                    loop (t, sd, wn);
                                                fi;
                                            fi;

                                        loop (SUBOPTS { name, ... } ! t, sd, wn)
                                            =>
                                            if  (name == kw_witness
                                            or   name == kw_subdir
                                            )
                                                badspec name;
                                            else
                                                loop (t, sd, wn);
                                            fi;
                                    end;
                                end;
                        esac;

                    subdir_pp
                        =
                        case sd
                            THE prettyprint =>  prettyprint;
                            NULL            =>  native2pathmaker dfl_subdir ();
                        esac;

                    subdir = native_pre_spec subdir_pp;

                    fun in_subdir f
                        =
                        if (winix__premicrothread::path::is_relative f)
                            winix__premicrothread::path::cat (subdir, f);
                        else
                            f;
                        fi;

                    timestamp_file_name
                        =
                        null_or::map (in_subdir o native_spec o srcpath) wn;

                    my (cpif, outd, update_timestamp_file)
                        =
                        case timestamp_file_name
                            #                 
                            NULL   => ( FALSE,
                                        \\ tname =  outdated tool ([tname], sname),
                                        \\ () = ()
                                      );

                            THE wn => ( TRUE,
                                        \\ tname =  outdated' tool { source_file_name => sname,
                                                                     target_file_name => tname,
                                                                     timestamp_file_name => wn
                                                                   },

                                        \\ () = fil::close_output (open_text_output wn)
                                      );
                        esac;

                    fun one_target (tname, tfns, rname, tilk, tool_options, lf)
                        =
                        {   tname = in_subdir tname;

                            fun runcmd ()
                                =
                                {   cmdname =  resolve_command_path  std_cmd_path;
                                    #
                                    fun number f
                                        =
                                        cat ["-L'", f, "' "];

                                    nonumber =  "";

                                    fmtopt   =  case lf
                                                    #
                                                    THE f =>   number f;

                                                    NULL => {   fun ilk_numbering c
                                                                    =
                                                                    case (string_map::get (*lnr, c))
                                                                        NULL => nonumber;
                                                                        THE f => number f;
                                                                    esac;

                                                                case tilk
                                                                    #
                                                                    THE c =>   ilk_numbering c;

                                                                    NULL  =>
                                                                        case (default_ilk_of tfns)
                                                                            #
                                                                            THE c =>  ilk_numbering c;
                                                                            NULL  =>  nonumber;
                                                                        esac;
                                                                esac;
                                                            };

                                                esac;

                                    redirect = if cpif  "| cpif "; else ">";fi;

                                    cmd = cat [cmdname, " ", fmtopt, "-R'", rname, "' ", sname, " ", redirect, tname];


                                    make_all_directories_on_path  tname;

                                    say {. cat ["[", cmd, "]\n"]; };


                                    if (winix__premicrothread::process::bin_sh' cmd  !=  winix__premicrothread::process::success)
                                        #
                                        err cmd;
                                    fi;
                                };

                            if (outd tname)
                                #                            
                                runcmd ();
                            fi;

                            { name              =>  tname,
                              make_path =>  native2pathmaker tname,
                              #
                              ilk               =>  tilk,
                              tool_options,
                              derived   =>  TRUE
                            };
                        };

                    fun one_target' (tname, tfns)
                        =
                        one_target (tname, tfns, tname, NULL, NULL, NULL);


                    fun simple_target (tfns as { name, make_path } )
                        =
                        one_target' (native_spec (srcpath (make_path ())), tfns);


                    fun one_opt (STRING x, rest)
                            =>
                            simple_target x ! rest;

                        one_opt (SUBOPTS { name, tool_options }, rest)
                            =>
                            {
                                fun subopts [STRING x]
                                        =>
                                        simple_target x;

                                    subopts tool_options
                                        =>
                                        {
                                            my { matches, remaining_options }
                                                =
                                                parse_options { tool, keywords, tool_options };

                                            fun fmatch kw
                                                =
                                                case (matches kw)
                                                    #
                                                    THE [STRING (fns as { name, make_path } )]
                                                        =>
                                                        (native_spec (srcpath (make_path ())), fns);

                                                    NULL =>  misskw kw;
                                                    _    =>  badspec kw;
                                                esac;

                                            fun smatch kw
                                                =
                                                case (matches kw)
                                                    #
                                                    THE [STRING { name, ... } ] =>  THE name;
                                                    NULL                        =>  NULL;
                                                    _                           =>  badspec kw;
                                                esac;

                                            case remaining_options
                                                #
                                                [] =>
                                                    {   (fmatch  kw_name) ->   (tname, tfns);
                                                        #
                                                        rname        =  the_else (smatch kw_root, tname);
                                                        tilk         =  smatch kw_ilk;
                                                        tool_options =  matches kw_options;
                                                        lf           =  smatch kw_lineformat;

                                                        one_target  (tname, tfns, rname, tilk, tool_options, lf);
                                                    };

                                                _   => err "unrecognized target option (s)";
                                            esac;
                                        };
                                end;

                                if (name == kw_target)
                                    #                           
                                    subopts tool_options ! rest;
                                else
                                    if (name == kw_subdir
                                    or  name == kw_witness)
                                        #
                                        rest;
                                    else
                                        badkw name;
                                    fi;
                                fi;
                            };
                    end;

                    fun rulefn ()
                      =
                      ( { makelib_files  =>  [],
                          source_files =>  [],
                          sources      =>  [(p, { ilk, derived } )]
                        },

                        case too
                            #
                            THE opts =>   fold_backward one_opt [] opts;
                            #
                            NULL
                                =>
                                {   my { base, ext }
                                        =
                                        winix__premicrothread::path::split_base_ext  sname;

                                    base
                                        =
                                        case ext
                                            #
                                            NULL => base;
                                            #
                                            THE e
                                                =>
                                                if (e == "nw")   base;
                                                else            sname;
                                                fi;
                                        esac;

                                    fun expression e
                                        =
                                        {   tname = winix__premicrothread::path::join_base_ext
                                                            { base, ext => THE e };

                                            tfns = {  name      =>  tname,
                                                      make_path =>  native2pathmaker tname
                                                   };

                                            one_target' (tname, tfns);
                                        };

                                    [ expression "api",
                                      expression "pkg"
                                    ];
                                };
                        esac
                      );

                    context rulefn
                    then
                        update_timestamp_file ();
                };

            fun suffix s
                =
                note_filename_classifier (standard_filename_suffix_classifier { suffix => s, ilk } );

        herein

            my _ = note_ilk (ilk, rule);
            my _ = suffix "nw";

            fun line_numbering ilk
                =
                {   fun get ()
                        =
                        string_map::get (*lnr, ilk);

                    fun set NULL    =>  lnr :=  string_map::drop (*lnr, ilk);
                        set (THE f) =>  lnr :=  string_map::set   (*lnr, ilk, f);
                    end;

                    { get,
                      set
                    };
                };
        end;
    };
end;



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext