[-*- Mode: emacs-lisp -*-] [-----grammar (gz start (prog)) (gz prog (module)) (gz module (id language-pragma-opt exports imports topdecl-star ::pr("[[language-pragma-opt]]" "{-\n" "Copyright 2011 Ken Takusagawa\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU Affero General Public License as published by\n" "the Free Software Foundation, either version 3 of the License, or\n" "(at your option) any later version.\n\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n\n" "You should have received a copy of the GNU Affero General Public License\n" "along with this program. If not, see .\n" "-}\n\n" "module [[id]] [[exports]] where{\n[[imports]]\n" "[[topdecl-star('',';\n','\n')]]}\n\n"))) (gz language-pragma ( :language-pragma f id-non-star j ::pr ("{-# LANGUAGE [[id-non-star('',',','')]] #-}\n"))) (gz exports (f export-star j ::pr("[[export-star('(',', ',')')]]")) (:export-everything ::pr(""))) (gz export (id) (f :module-export id j ::pr("module [[id]]")) ) (gz imports (f import-star j ::pr("[[import-star('',';\n',';\n')]]"))) (gz import(id ::pr( "import [[id]]")) (f :qualified (original-name ::is id) (new-name ::is id) j ::pr ( "import qualified [[original-name]] as [[new-name]]")) (f :specific id id-non-star j ::pr ("import [[id]][[id-non-star('(',',',')')]]")) (f :hiding import id-non-star j ::pr("[[import]] hiding[[id-non-star('(',',',')')]]") [dunno if this will work for complicated cases] ) ) (gz type-class (f decl-mark (class-name ::is id) :type-class context-opt id-non-plus f type-class-decl-star j j ::pr("class [[context-opt]][[class-name]] [[id-non-plus('',' ','')]] where{\n" "[[type-class-decl-star('',';\n','\n')]]}"))) (gz topdecl (decl) (data)(type-synonym)(newtype)(instance)(type-class)) (gz type-class-decl (type-signature)(decl)) (gz type-signature (f :tysig name ret-type-and-params j ::pr("[[name]] :: [[ret-type-and-params]]"))) (gz instance (f :instance (type ::is id) (name ::is simpletype) decls j ::pr ("instance [[type]] ([[name]]) where [[decls]]"))) [(gz instance (f :instance context-opt (type ::is id) simpletype-plus :x decls j ::pr ("instance [[context-opt]][[type]] [[simpletype-plus('(',')(',')')]] where [[decls]]")))] (gz newtype (f decl-mark (name ::is id) :newtype type-vars-opt constr-or-wrap deriving-opt j ::pr("newtype [[name]] [[type-vars-opt]] = [[constr-or-wrap{my_name}]][[deriving-opt]]"))) (gz constr-or-wrap ::gets "tr-id*{name}" (constr)(wrap-constr ::pr("[[wrap-constr{name}]]"))) (gz wrap-constr ::gets "tr-id*{name}" ( :wrap id ::pr( (::c "name->print();") " {un_" (::c "name->print();") " :: [[id]]}"))) (gz deriving (:deriving f id-non-plus j ::pr(" deriving [[id-non-plus('(',', ',')')]]"))) (gz id-non (id)) (gz type-synonym (f decl-mark id :type-synonym type-vars-opt type j ::pr("type [[id]] [[type-vars-opt]] = [[type]]"))) (gz data (f decl-mark id :data type-vars-opt constrs deriving-opt j ::pr("data [[id]] [[type-vars-opt]] = [[constrs]][[deriving-opt]]"))) (gz simpletype (f id-non-plus j ::pr ("[[id-non-plus('',' ','')]]"))) (gz type-vars (:args f id-non-star j ::pr ("[[id-non-star('',' ','')]]"))) (gz constrs(constr-star ::pr("[[constr-star('',' | ','')]]")) ) (gz field-type-and-param (f param type j ::pr("[[param]] :: [[type]]"))) (gz type-and-param ( f param type j ::pr("[[type]]"))) (gz constr(positional-constructor) (field-label-constructor) ) (gz field-label-constructor(f type-ctor :field field-type-and-param-star j ::pr("[[type-ctor]][[field-type-and-param-star('{',', ','}')]]"))) (gz decls ( decl-star ::pr("{[[decl-star('\n',';\n','\n')]]}\n"))) (gz context (:context f a-context-plus j ::pr ("[[a-context-plus('(',', ',')')]] => "))) (gz a-context [(f (type ::is id) id-non-plus j ::pr("[[type]] [[id-non-plus('',' ','')]]"))] (f (class ::is id) type-plus j ::pr("[[class]] [[type-plus('(',')(',')')]]")) ) (gz forall (:forall f id-non-plus j ::pr("forall [[id-non-plus('',' ','')]] . "))) (gz ret-type-and-params (type f type-and-param-star j forall-opt context-opt ::pr("[[forall-opt]][[context-opt]][[type-and-param-star('',' \x2d> ','')]]" (::c "if(my_type_and_param_star->v.size()>0)out(' \x2d> ');") "[[type]]"))) (gz decl (f decl-mark name :fun haddock-opt ret-type-and-params expr j ::pr("[[haddock-opt]]" "[[name]] :: [[ret-type-and-params]];\n" "[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]")) (f decl-mark name :fun :no-sig ret-type-and-params expr j ::pr("[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]")) (f decl-mark name :simple expr j ::pr("[[name]] = [[expr]]")) ) (gz name (id)) (gz positional-constructor ["this one is sketchy"] (type-ctor ::pr("[[type-ctor]]")) (f type-ctor typepls-opt j ::pr("[[type-ctor]][[typepls-opt]]")) (f :tuple type-plus j ::pr("[[type-plus('(',', ',')')]]")) ) (gz pattern (id) (f pattern-ctor pattern-star j ::pr ("([[pattern-ctor]] [[pattern-star('',' ','')]])")) (f pattern-ctor :fpat f fpat-star j j ::pr ("[[pattern-ctor]][[fpat-star('{',', ','}')]]")) (f :ptuple pattern-plus j [pattern-plus cuz :nil exists for empty lists] ::pr("[[pattern-plus('(',', ',')')]]")) (f :plist pattern-plus j [pattern-plus cuz :nil exists for empty lists] ::pr("[[pattern-plus('\x5b',', ','\x5d')]]")) (f :pchar astring j ::pr("(\x27[[astring]]\x27)")) (f :pstring astring j ::pr("\x22[[astring]]\x22")) (f :as id pattern j ::pr("[[id]]@[[pattern]]")) ) (gz pattern-ctor (id) (:cons ::pr ("(:)")) (:nil ::pr ("[]")) (:paren id ::pr("([[id]])")) ["workaround for Qualified parenthesized constructors"] ) (gz fpat (f (variable ::is id) pattern j ::pr("[[variable]] = [[pattern]]"))) (gz type (f :fn ret-type-and-params j ::pr ("([[ret-type-and-params]])")) (:inforall f id-non-plus j type ::pr("(forall [[id-non-plus('',' ','')]] . [[type]])")) (:unit ::pr("()")) (positional-constructor)) (gz typepls (paren-type-plus)) (gz paren-type (type ::pr( "([[type]])")) (f :strict type j ::pr("!([[type]])")) (f :generic id j ::pr (" [[id]] "))) (gz type-ctor(id)(:list ::pr ("[]"))(:nondet ::pr ("[]"))) (gz param (pattern)) (gz qastring (astring ::pr("\x22[[astring]]\x22"))) (gz expr (id) (:mcons ::pr ("(:)")) [(:nil ::pr ("[]"))] (f :chain astring expr-plus j ::pr ([("[[expr-plus('(',' op ',')')]]")] "(" (::c "for(many_trees::const_iterator pos=my_expr_plus->v.begin();pos!=my_expr_plus->v.end();++pos){") (::c "if(pos!=my_expr_plus->v.begin()){") "[[astring]]" (::c "}(*pos)->print();}") ")" )) (f :join expr-plus j ::pr("[[expr-plus('(',' >>= ',')')]]")) (f :cc expr-star j ::pr ("[[expr-star('(',' ++ ',')')]]")) (f :rpipe expr-plus j ::pr[("[[expr-star('(',' $ ',')')]]")] (["http;//gcc.gnu.org/bugzilla/show_bug.cgi?id=11729"] (::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();" "pos!=my_expr_plus->v.rend();++pos){") "(" (::c "(*pos)->print();" "}") (::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();" "pos!=my_expr_plus->v.end();++pos){") ")" (::c "}") ) ) (f :rcompose expr-plus j ::pr ("(" (::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();" "pos!=my_expr_plus->v.rend();++pos){") (::c "if(pos!=my_expr_plus->v.rbegin())") " . " (::c "(*pos)->print();" "}") ")" ) ) (qastring) (f :lit astring j ::pr("[[astring]]")) (f :ty type expr j ::pr("([[expr]] :: [[type]])")) (f (fun-name ::is expr) expr-star j ::pr ("([[fun-name]][[expr-star(' ',' ','')]])")) (f :do stmt-star j ::pr("(do{\n[[stmt-star(' ','\n ','\n')]]})")) (f :case expr alt-star j ::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ','\n')]]})")) (f :case expr alt-star :else (underbar ::is expr) j ["the else is there so the grammar does not have a reduce/reduce conflict"] ::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ',';\n')]]" " _ -> [[underbar]]\n" "})")) (f :lcase alt-star j ::pr("(\x5clambda_case_var ->" "case lambda_case_var of {\n" "[[alt-star(' ',';\n ','\n')]]})")) (f :lcase alt-star :else (underbar ::is expr) j ::pr("(\x5clambda_case_var ->" "case lambda_case_var of {\n" "[[alt-star(' ',';\n ',';\n')]]" " _ -> [[underbar]]\n" "})")) (f :let decl-star expr j ::pr("(let {[[decl-star('\n',';\n','\n')]]}\n in [[expr]])")) (f :rlet expr decl-star j ::pr("(let {[[decl-star('\n',';\n','\n')]]}\n in [[expr]])")) (f :cfd expr assignments-star j ::pr("([[expr]][[assignments-star('{',', ','}')]])")) (f :mlist expr-star j ::pr("[[expr-star('\x5b',', ','\x5d')]]")) (f :cons-list expr-star j ::pr("[[expr-star('(',':',')')]]")) (f :mtuple expr-star j ::pr("[[expr-star('(',', ',')')]]")) (:nothing ::pr ("()")) (f :lambda name ret-type-and-params expr j ::pr("(let {[[name]] :: [[ret-type-and-params]];\n" "[[name]]" (::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){" "const tr_type_and_param* t=dynamic_cast(*pos);" "assert(t);" "out(' ');" "t->my_param->print();" "}") " = [[expr]]} in [[name]])")) (f :lambda-simple id-non expr j [recommended only for reordering arguments to functions and other simple expressions] [only one variable to keep it simple] ::pr ("(\x5c[[id-non]] -> [[expr]])")) (f :field-edit expr field-edit-plus j [plus is required by Haskell] ::pr("([[expr]][[field-edit-plus('{',',','}')]])")) ) (gz field-edit (f id expr j ::pr ("[[id]] = [[expr]]"))) (gz assignments (f id expr j ::pr("[[id]] = [[expr]]"))) (gz stmt (expr ::pr("[[expr]];")) (f ":=" pattern type expr j ::pr("[[pattern]] :: [[type]] <- [[expr]];")) (f :let-many decl-star j ::pr ("let {[[decl-star('\n',';\n','\n')]]};")) (f :dlet id type expr j ::pr ("let {" " [[id]] :: [[type]];" " [[id]] = [[expr]];" "};")) ) (gz alt (f pattern expr-or-gpat j ::pr("[[pattern]][[expr-or-gpat]]"))) (gz expr-or-gpat (expr ::pr ("-> [[expr]]")) (where-opt :gpats pred-expr-star [silly lookahead limitation] ::pr ("\n[[pred-expr-star('','','')]] [[where-opt]]" ))) (gz pred-expr ( f (pred ::is expr) (do ::is expr) j ::pr ("| [[pred]]\n -> [[do]]\n"))) (gz where (:where decls ::pr ("where [[decls]]"))) (gz decl-mark (":")) (gz haddock ( :doc f docline-star j ::pr ("[[docline-star('\n\x7b\x2d |','\n',' \x2d\x7d\n')]]"))) (gz docline (astring)) ] Main :language-pragma ( ScopedTypeVariables [GeneralizedNewtypeDeriving] [RankNTypes] ) (main) ( System.Environment Data.Time Data.List Network.CGI Text.Printf Factor_cmd Control.Monad System.Locale ) (: cgi-main :fun (CGI CGIResult)() (:do (:= yr (Maybe Integer) (readInput "yr")) (:= mo (Maybe Int) (readInput "mo")) (:= dy (Maybe Int) (readInput "dy")) (:= offset (Maybe Integer) (readInput "offset")) (:= action (Maybe String) (getInput "action")) (:case (:mtuple yr mo dy offset) ((:ptuple(Just yr)(Just mo)(Just dy)(Just offset)) (:rlet (:join (liftIO (f yr mo dy offset)) output) (: f :fun (:fn(IO String) ((yr Integer)(mo Int)(dy Int)(offset Integer)))() (:case action ((Just(:pstring "list"))gen-list) :else gen-test)))) :else (outputInternalServerError (:mlist (show yr)(show mo)(show dy)(show offset)))) [only one output line is permitted, the last one takes precedence] )) (: main :fun (IO :unit)() (runCGI (handleErrors cgi-main)) ) (: main2 :fun (IO :unit)() (:do (:= args (:list String) getArgs) (:join (gen-test (read (!! args 0)) (read (!! args 1))(read (!! args 2)) (read (!! args 3))) putStrLn ))) (: gen-test :fun (IO String)((yr Integer)(mo Int)(dy Int)(offset Integer)) (:do (:dlet start Day (fromGregorian yr mo dy)) (:= today Day (:join getToday (:rcompose (addDays offset) return))) (:dlet interval Integer (diffDays today start)) (:dlet today-string String (:cc "\n")) (:= info-today String (:case (compare interval 0) (EQ (return "You are born today!")) (LT (return "Requested date is in the future.")) :else (:do (:= fs (:list Integer) (factor interval)) (:case (length fs) (0 (return "You are 1 day old.")) (1 (do-prime-day today)) :else (find-from-composite today interval fs) )))) (:= nextp String (:case (compare interval 0) (LT (return "") ) :else (next-prime-day interval today) )) (:rpipe (:cc "

Peek tomorrow

\n" today-string "

" info-today "

"nextp"

\n" (:case (its-your-birthday today start) (True "

Also, happy birthday!

\n") :else "") (:case offset (0 "

Bookmark this page to automatically recalculate whenever you open the bookmark.

\n") :else "") "\n
\n

" "List all your Prime Days this year

" "Back to Prime Day Calculator

" "Leave comments on this blog post

" "View source code

" ) (create-html (:cc (show start) " birthday Prime Day calculator")) return) )) (: getToday :fun (IO Day) () (:join getZonedTime (:rcompose zonedTimeToLocalTime localDay return))) (: make-day :fun Day ((x(:list String))) (:case x ((:plist(yr)(mo)(dy))(fromGregorian (read yr)(read mo)(read dy))) :else (error (:cc "expecting [year,month,day], but got " (show x))))) (: do-prime-day :fun (IO String)((today Day)) (return (:cc "Happy Prime Day!

You have lived a prime number of days, as of " (show-day today)"."))) (: find-from-composite :fun (IO String)((today Day)(total Integer)(factors(:list Integer))) (:do (:dlet dm (:tuple Integer Integer) (divMod total (last factors))) (:dlet last-chapter-ago Integer (fst dm)) (:dlet last-chapter-start Day (addDays (negate last-chapter-ago) today)) (:case (snd dm) (0 (return :nothing)) :else (error "did not divide cleanly")) [(putStrLn (:cc "Composite " (show total)" = " (show factors)))] (return (:cc "Happy Composite Day!

" "As of today, " (show-day today) ", your life may be divided into exactly " (:rpipe factors last show) " chapters" " of " (show last-chapter-ago) " days each." [", each an equal number of days."] "
The latest chapter started on " (show-day last-chapter-start) " and ended yesterday. The next chapter begins today!" )) )) (: plural :fun String ((i Integer)) (:case i (1 "") :else "s")) (: next-prime-day :fun (IO String) ((total Integer)(today Day)) [(:= np Day (:join (next-prime total) (:rcompose (- total) negate ((flip addDays) today) return)))] (:do (:= np Integer (next-prime (+ 1 total))) (:dlet interval Integer (- np total)) (:dlet the-day Day (addDays interval today)) (return (:cc "Your next Prime Day is " (:case interval (1 "tomorrow") :else (:cc "in "(show interval)" days") )", on "(show-day the-day) ".

" (:case (compare total 0) (GT (:cc "

Your average spacing between Prime Days is " (printf "%.4f" (:ty Double (:rpipe total fromInteger log ))) " days.")) :else "") )) )) (: create-html :fun String ((title String)(body String)) (unlines (:mlist "" (:cc "" title "") body " "))) (: gen-list :fun (IO String)( (yr Integer)(mo Int)(dy Int) (offset Integer)) (:do (:dlet start Day (fromGregorian yr mo dy)) (:= today Day getToday) (:dlet target Integer (:rpipe today get-year (+ offset))) (:= prime-days (:list Day) (get-prime-days start target)) (:let-many (: link :fun String ((offset Integer)) (:cc "\"primeday.cgi?action=list" "&yr="(show yr) "&mo="(show mo) "&dy="(show dy) "&offset="(show offset) "\""))) (return (create-html (:cc "Your Prime Days for "(show target)) (:cc "

Your Prime Days for "(show target)"

\n

" (:rpipe prime-days (map show-day) (intersperse "
\n") concat) "

\n

" "Previous year - " "Next year" "

" "\n
Back to Prime Day Calculator
" "View source code" ))) )) (: get-year :fun Integer ((d Day)) (:case (toGregorian d) ((:ptuple yr _ _)yr))) (: days-of-the-year :fun (:list Day)((yr Integer)) (:rlet (takeWhile this-year (enumFrom (fromGregorian yr 1 1))) (: this-year :fun Bool ((d Day)) (== yr (get-year d))))) (: is-prime-day :fun (IO Bool) ((start Day)(today Day)) (is-prime (diffDays today start))) (: get-prime-days :fun (IO (:list Day)) ((start Day)(yr Integer)) (filterM (is-prime-day start) (days-of-the-year yr))) (: its-your-birthday :fun Bool ((x Day)(y Day)) (:case (:mtuple (toGregorian x)(toGregorian y)) ((:ptuple(:ptuple _ xm xd)(:ptuple _ ym yd)) (&& (== xm ym)(== xd yd))))) (: show-day :fun String ((d Day)) (:cc (show d) " "(formatTime defaultTimeLocale "%A" d) ))