PreviousUpNext

15.4.805  src/lib/html/check-html-g.pkg

## check-html-g.pkg
#
# This implements a tree walk over an HTML file to check for
# errors, such as violations of exclusions.

# Compiled by:
#     src/lib/html/html.lib


stipulate
    package has =  html_abstract_syntax;                                                        # html_abstract_syntax                  is from   src/lib/html/html-abstract-syntax.pkg
herein

    generic package check_html_g (err:  Html_Error )                                            # Html_Error                            is from   src/lib/html/html-error.api
    : (weak)
    api {
        Context = { file:  Null_Or( String ), line:  Int };

        check:  Context -> has::Html -> Void;
    }
    {
        Context = err::Context;

        fun check context (has::HTML { body=>has::BODY { content, ... }, ... } )
            =
            check_body_content { in_form=>FALSE } content
            where
                fun error (element, ctx)
                    =
                    err::syntax_error context
                        (sfprintf::sprintf' "unexpected %s element in %s" [
                            sfprintf::STRING element, sfprintf::STRING ctx
                          ]);

                fun content_error ctx
                    =
                    err::syntax_error context
                        (sfprintf::sprintf' "unexpected element in %s" [sfprintf::STRING ctx]);

                fun form_error element
                    =
                    err::syntax_error context
                        (sfprintf::sprintf' "unexpected %s element not in FORM" [
                            sfprintf::STRING element
                          ]);

                fun attribute_error attribute
                    =
                    err::missing_attribute context attribute;


                fun check_body_content { in_form } b
                    =
                    case b
                         has::HN { n, align, content }
                             =>
                             check_text { in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet=>FALSE } content;

                         has::ADDRESS block
                             =>
                             check_address { in_form } block;

                         has::BLOCK_LIST bl
                             =>
                             list::apply (check_body_content { in_form } ) bl;

                         block =>
                             check_block { in_form } block;
                    esac


                also
                fun check_address { in_form } blk
                    =
                    case blk

                        has::BLOCK_LIST bl
                            =>
                            list::apply (check_address { in_form } ) bl;

                        has::TEXTABLOCK txt
                            =>
                            check_text { in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet => FALSE } txt;

                        has::PP { content, ... }
                            =>
                            check_text { in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet => FALSE } content;

                        _   =>
                            content_error "ADDRESS";
                    esac

                also
                fun check_block { in_form } blk
                     =
                     case blk

                         has::BLOCK_LIST bl
                             =>
                             list::apply (check_block { in_form } ) bl;

                         has::TEXTABLOCK txt
                             =>
                             check_text { in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet => FALSE } txt;

                         has::PP { content, ... }
                             =>
                             check_text { in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet => FALSE } content;

                         has::UL { content, ... }
                             =>
                             check_items { in_form, in_dir_or_menu=>FALSE } content;

                         has::OL { content, ... }
                             =>
                             check_items { in_form, in_dir_or_menu=>FALSE } content;

                         has::DIR { content, ... }
                             =>
                             check_items { in_form, in_dir_or_menu=>TRUE } content;

                         has::MENU { content, ... }
                             =>
                             check_items { in_form, in_dir_or_menu=>TRUE } content;

                         has::DL { content, ... }
                             =>
                             check_dlitems { in_form } content;

                         has::PRE { content, ... }
                             =>
                             check_text { in_anchor=>FALSE, in_form, in_pre=>TRUE, in_applet => FALSE } content;

                         has::DIV { content, ... }
                             =>
                             check_body_content { in_form } content;

                         has::CENTER content
                             =>
                             check_body_content { in_form } content;

                         has::BLOCKQUOTE content
                             =>
                             check_body_content { in_form } content;

                         has::FORM { content, ... }
                             =>
                             {   if  in_form    error("FORM", "FORM");  fi;
                                 check_body_content { in_form=>TRUE } content;
                             };

                         has::ISINDEX _ => ();
                         has::HR _      => ();

                         has::TABLE { caption=>THE (has::CAPTION { content=>caption, ... } ), content, ... }
                             =>
                             {   check_text {
                                     in_anchor=>FALSE, in_form, in_pre=>FALSE,
                                     in_applet => FALSE
                                   } caption;

                                 check_rows { in_form } content;
                             };

                         has::TABLE { content, ... }
                             =>
                             check_rows { in_form } content;

                         has::HN      _ =>  error ("HN",      "block");
                         has::ADDRESS _ =>  error ("ADDRESS", "block");
                      esac

                also
                fun check_items { in_form, in_dir_or_menu } items
                    =
                    list::apply check items
                    where
                        fun check_blk (has::BLOCK_LIST bl)   =>  list::apply check_blk bl;
                            check_blk (has::TEXTABLOCK txt) =>  ();
                            check_blk (has::PP _)            =>  ();
                            check_blk _                       =>  error ("block", "DIR/MENU");
                        end;

                        check
                            =
                            if   in_dir_or_menu

                                 \\ (has::LI { content, ... } )
                                     =
                                     {   check_blk content;
                                         check_block { in_form } content;
                                     };
                            else
                                 \\ (has::LI { content, ... } )
                                     =
                                     check_block { in_form } content;
                            fi;
                    end

                also
                fun check_dlitems { in_form } items
                    =
                    list::apply check items
                    where
                        fun check { dt, dd }
                            =
                            {
                                list::apply
                                  (check_text {
                                    in_anchor=>FALSE, in_form, in_pre=>FALSE, in_applet=>FALSE
                                  } )
                                    dt;

                                check_block { in_form } dd;
                            };
                    end

                also
                fun check_rows { in_form } rows
                    =
                    list::apply check_row rows
                    where

                        fun check_cell (has::TH { content, ... } )
                                =>
                                check_body_content { in_form } content;

                            check_cell (has::TD { content, ... } )
                                =>
                                check_body_content { in_form } content;
                        end;


                        fun check_row (has::TR { content, ... } )
                            =
                            list::apply check_cell content;

                    end

                also
                fun check_text { in_anchor, in_form, in_pre, in_applet }
                    =
                    check
                    where
                        fun check txt
                            =
                            case txt

                                has::TEXT_LIST tl => list::apply check tl;
                                has::PCDATA _ => ();

                                has::TT     txt => check txt;
                                has::IX     txt => check txt;
                                has::BX     txt => check txt;
                                has::UX     txt => check txt;
                                has::STRIKE txt => check txt;
                                has::EM     txt => check txt;
                                has::STRONG txt => check txt;
                                has::DFN    txt => check txt;
                                has::CODE   txt => check txt;
                                has::SAMP   txt => check txt;
                                has::KBD    txt => check txt;
                                has::VAR    txt => check txt;
                                has::CITE   txt => check txt;

                                has::BIG   txt => { if in_pre  error("BIG",   "PRE"); fi; check txt; };
                                has::SMALL txt => { if in_pre  error("SMALL", "PRE"); fi; check txt; };
                                has::SUB   txt => { if in_pre  error("SUB",   "PRE"); fi; check txt; };
                                has::SUP   txt => { if in_pre  error("SUP",   "PRE"); fi; check txt; };

                                has::AX { content, ... }
                                   =>
                                   {   if in_anchor  error("anchor", "anchor"); fi;

                                       check_text {
                                           in_anchor=>TRUE, in_form, in_pre,
                                           in_applet
                                         } content;
                                   };

                                has::IMG _ =>
                                   if in_pre  error("IMG", "PRE"); fi;

                                has::APPLET { content, ... }  => check_text {
                                     in_anchor=>FALSE, in_form, in_pre,
                                     in_applet=>TRUE
                                   } content;

                                has::PARAM _                    => if in_applet  error ("parameter", "applet"); fi;
                                has::FONT {     content, ... }  => if in_pre     error("FONT",       "PRE"   ); fi;
                                has::BASEFONT { content, ... }  => if in_pre     error("BASEFONT",   "PRE"   ); fi;

                                has::BR _ => ();
                                has::MAP _ => ();

                                has::INPUT { type, name, value, ... } 
                                    =>
                                    {
                                        if (not in_form)  form_error "INPUT"; fi;

                                        if ((name == NULL)
                                        and (type != THE has::input_type::submit)
                                        and (type != THE has::input_type::reset))
                                              attribute_error "NAME";
                                        fi;

                                        if ((value == NULL)
                                        and ((type == THE has::input_type::radio)
                                        or (type == THE has::input_type::checkbox)))
                                             attribute_error "VALUE";
                                        fi;
                                    };

                                has::SELECT   _ =>  if (not in_form)  form_error "SELECT";   fi;
                                has::TEXTAREA _ =>  if (not in_form)  form_error "TEXTAREA"; fi;

                                has::SCRIPT _   => ();
                            esac;
                    end;                        # fun check_text
            end;                                # fun check
    };
end;

## COPYRIGHT (c) 1996 AT&T Research.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext