(* *) (* Dynamic web page generation with Standard ML *) (* Copyright (C) 2003 Adam Chlipala *) (* *) (* This library is free software; you can redistribute it and/or *) (* modify it under the terms of the GNU Lesser General Public *) (* License as published by the Free Software Foundation; either *) (* version 2.1 of the License, or (at your option) any later version. *) (* *) (* This library 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 *) (* Lesser General Public License for more details. *) (* *) (* You should have received a copy of the GNU Lesser General Public *) (* License along with this library; if not, write to the Free Software *) (* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) (* Grammar for ML template language *) open Tree fun rcomp ((a, _), (b, _)) = String.compare (a, b) = GREATER fun sortRcs x = ListMergeSort.sort rcomp x fun addNumbers L = let fun addNum (_, []) = [] | addNum (n, h::t) = (Int.toString n, h)::(addNum(n+1,t)) in addNum (1, L) end %% %header (functor MltLrValsFn(structure Token : TOKEN)) %term EOF | HTML of string | IF | THEN | ELSE | AS | WITH | OPEN | VAL | REF | TRY | CATCH | FOREACH | IN | CASE | ORELSE | ANDALSO | LPAREN | RPAREN | LBRACK | RBRACK | LBRACE | RBRACE | HASH | SEMI | CONS | PLUS | MINUS | TIMES | DIVIDE | MOD | NEG | DOLLAR | AT | STRCAT | ASN | EQ | NEQ | GT | GTE | LT | LTE | IDENT of string | DOT | DOTDOT | DOTDOTDOT | COMMA | COLON | CARET | TILDE | UNDER | INT of int | STRING of string | CHAR of string %nonterm file of block | block of block | exp of exp | appsL of exp list | apps of exp | term of exp | pterm of pat | papp of pat | pat of pat | path of ident list | pathList of ident list list | blockItem of blockItem | ifte of ((exp * block) list * block option) withext | matches of (pat * block) list withext | pexp of exp | ppat of pat | pseq of pat list | rseq of (ident * pat) list | frseq of (ident * pat) list | eseq of exp list | elseq of exp list | plseq of pat list | erseq of (ident * exp) list | ilist of ident list | ivlist of (ident * exp) list | catch of pat * block | catches of (pat * block) list %verbose (* print summary of errors *) %pos int (* positions *) %start file %pure %eop EOF %noshift EOF %name Mlt %left ANDALSO %left ORELSE %nonassoc EQ NEQ GT GTE LT LTE %left PLUS MINUS %left TIMES DIVIDE MOD %left STRCAT %nonassoc NEG %right CONS %% file : block (block) ilist : IDENT ilist (IDENT :: ilist) | IDENT ([IDENT]) ivlist : IDENT EQ exp COMMA ivlist ((IDENT, exp) :: ivlist) | IDENT EQ exp ([(IDENT, exp)]) catch : CATCH ppat LBRACE block RBRACE (ppat, block) catches : catch catches (catch::catches) | catch ([catch]) blockItem : HTML (BITEM (Html_i HTML, (HTMLleft, HTMLright))) | REF ivlist (BITEM (Ref_i ivlist, (REFleft, ivlistright))) | OPEN pathList (BITEM (Open_i pathList, (OPENleft, pathListright))) | VAL pat EQ exp (BITEM (Val_i (pat, exp), (patleft, expright))) | IDENT ASN exp (BITEM (Assn_i (IDENT, exp), (IDENTleft, expright))) | exp (BITEM (Exp_i exp, (expleft, expright))) | IF LPAREN exp RPAREN LBRACE block RBRACE ifte (let val ((L, O), _) = ifte in BITEM (Ifthenelse_i((exp, block) :: L, O), (IFleft, ifteright)) end) | FOREACH LPAREN IDENT IN exp RPAREN LBRACE block RBRACE (BITEM (Foreach_i (IDENT, exp, block), (FOREACHleft, RBRACEright))) | FOREACH LPAREN IDENT IN exp DOTDOT exp RPAREN LBRACE block RBRACE (BITEM (For_i (IDENT, exp1, exp2, block), (FOREACHleft, RBRACEright))) | CASE pexp matches (BITEM (Case_i (pexp, #1 matches), (CASEleft, matchesright))) | TRY LBRACE block RBRACE catches (BITEM (TryCatch_i (block, catches), (TRYleft, catchesright))) ifte : ELSE LBRACE block RBRACE (([], SOME block), (ELSEleft, RBRACEright)) | ELSE IF LPAREN exp RPAREN LBRACE block RBRACE ifte (let val ((L, O), _) = ifte in (((exp, block) :: L, O), (ELSEleft, ifteright)) end) | (([], NONE), (0, 0)) block : blockItem (BLOCK ([blockItem], (blockItemleft, blockItemright))) | blockItem SEMI block (BLOCK (blockItem :: (unblock block), (blockItemleft, blockright))) | blockItem block (BLOCK (blockItem :: (unblock block), (blockItemleft, blockright))) | SEMI block (block) | (BLOCK ([], (0, 0))) appsL : term appsL (term::appsL) | term ([term]) apps : appsL (let val e::r = appsL in foldl (fn (e, a) => EXP (App_e (a, e), (appsLleft, appsLright))) e r end) path : IDENT DOT path (IDENT::path) | IDENT ([IDENT]) pathList: path pathList (path::pathList) | path ([path]) eseq : exp COMMA eseq (exp :: eseq) | exp COMMA exp ([exp1, exp2]) elseq : eseq (eseq) | exp ([exp]) | ([]) erseq : IDENT EQ exp COMMA erseq ((IDENT, exp) :: erseq) | IDENT COMMA erseq ((IDENT, EXP (Ident_e [IDENT], (IDENTleft, IDENTright))) :: erseq) | IDENT ([(IDENT, EXP (Ident_e [IDENT], (IDENTleft, IDENTright)))]) | IDENT EQ exp ([(IDENT, exp)]) pexp : LPAREN eseq RPAREN (EXP (Record_e (true, addNumbers eseq), (LPARENleft, LPARENright))) | LPAREN RPAREN (EXP (Record_e (true, []), (LPARENleft, RPARENright))) | LPAREN exp RPAREN (exp) term : LBRACE erseq RBRACE (EXP (Record_e (false, sortRcs erseq), (LBRACEleft, RBRACEright))) | LBRACE RBRACE (EXP (Record_e (false, []), (LBRACEleft, RBRACEright))) | LBRACE term WITH erseq RBRACE (EXP (RecordUpd_e (term, erseq), (LBRACEleft, RBRACEright))) | pexp (pexp) | STRING (EXP (String_e STRING, (STRINGleft, STRINGright))) | CHAR (EXP (Char_e CHAR, (CHARleft, CHARright))) | path (EXP (Ident_e path, (pathleft, pathright))) | INT (EXP (Int_e INT, (INTleft, INTright))) | NEG (EXP (Neg_e, (NEGleft, NEGright))) | DOLLAR (EXP (Param_e, (DOLLARleft, DOLLARright))) | AT IDENT (EXP (Template_e IDENT, (ATleft, IDENTright))) | HASH INT (EXP (Proj_e (Int.toString INT), (HASHleft, INTright))) | HASH IDENT (EXP (Proj_e IDENT, (HASHleft, IDENTright))) | LBRACK elseq RBRACK (foldr (fn x => EXP (Cons_e x, (LBRACKleft, RBRACKright))) (EXP (Ident_e ["nil"], (0, 0))) elseq) exp : apps (apps) | exp PLUS exp (EXP (Plus_e (exp1, exp2), (exp1left, exp2right))) | exp MINUS exp (EXP (Minus_e (exp1, exp2), (exp1left, exp2right))) | exp TIMES exp (EXP (Times_e (exp1, exp2), (exp1left, exp2right))) | exp DIVIDE exp (EXP (Divide_e (exp1, exp2), (exp1left, exp2right))) | exp MOD exp (EXP (Mod_e (exp1, exp2), (exp1left, exp2right))) | exp EQ exp (EXP (Eq_e (exp1, exp2), (exp1left, exp2right))) | exp NEQ exp (EXP (Neq_e (exp1, exp2), (exp1left, exp2right))) | exp LT exp (EXP (Lt_e (exp1, exp2), (exp1left, exp2right))) | exp LTE exp (EXP (Lte_e (exp1, exp2), (exp1left, exp2right))) | exp GT exp (EXP (Gt_e (exp1, exp2), (exp1left, exp2right))) | exp GTE exp (EXP (Gte_e (exp1, exp2), (exp1left, exp2right))) | exp CONS exp (EXP (Cons_e (exp1, exp2), (exp1left, exp2right))) | exp STRCAT exp (EXP (StrCat_e (exp1, exp2), (exp1left, exp2right))) | exp ORELSE exp (EXP (Orelse_e (exp1, exp2), (exp1left, exp2right))) | exp ANDALSO exp (EXP (Andalso_e (exp1, exp2), (exp1left, exp2right))) matches : ppat LBRACE block RBRACE matches (((ppat, block) :: (#1 matches), (ppatleft, matchesright))) | ([], (0, 0)) rseq : IDENT EQ pat COMMA rseq ((IDENT, pat) :: rseq) | IDENT COMMA rseq ((IDENT, PAT (Ident_p [IDENT], (IDENTleft, IDENTright))) :: rseq) | IDENT ([(IDENT, PAT (Ident_p [IDENT], (IDENTleft, IDENTright)))]) | IDENT EQ pat ([(IDENT, pat)]) frseq : IDENT EQ pat COMMA frseq ((IDENT, pat) :: frseq) | IDENT COMMA frseq ((IDENT, PAT (Ident_p [IDENT], (IDENTleft, IDENTright))) :: frseq) | DOTDOTDOT ([]) ppat : LPAREN pat RPAREN (PAT (unpat pat, (LPARENleft, RPARENright))) | LPAREN pseq RPAREN (PAT (Record_p (true, addNumbers pseq), (LPARENleft, LPARENright))) | LPAREN RPAREN (PAT (Record_p (true, []), (LPARENleft, RPARENright))) pseq : pat COMMA pseq (pat :: pseq) | pat COMMA pat ([pat1, pat2]) plseq : pseq (pseq) | pat ([pat]) | ([]) pterm : path (PAT (Ident_p path, (pathleft, pathright))) | UNDER (PAT (Wild_p, (UNDERleft, UNDERright))) | INT (PAT (Int_p INT, (INTleft, INTright))) | STRING (PAT (String_p STRING, (STRINGleft, STRINGright))) | LBRACE rseq RBRACE (PAT (Record_p (false, sortRcs rseq), (LBRACEleft, RBRACEright))) | LBRACE RBRACE (PAT (Record_p (false, []), (LBRACEleft, RBRACEright))) | LBRACE frseq RBRACE (PAT (FlexRecord_p (sortRcs frseq), (LBRACEleft, RBRACEright))) | ppat (ppat) papp : path papp (PAT (App_p (path, papp), (pathleft, pappright))) | pterm (pterm) pat : papp CONS papp (PAT (Cons_p (papp1, papp2), (papp1left, papp2right))) | papp (papp) | IDENT AS pat (PAT (As_p (IDENT, pat), (IDENTleft, patright))) | LBRACK plseq RBRACK (foldr (fn x => PAT (Cons_p x, (LBRACKleft, RBRACKright))) (PAT (Ident_p ["nil"], (0, 0))) plseq)