[-*- 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) ))