[-*- emacs-lisp -*-]
[
Copyright 2012 Ken Takusagawa
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
]
[-----grammar
(gz start (prog))
(gz prog (module))
(gz module (id language-pragma-opt exports imports topdecl-star
::pr("[[language-pragma-opt]]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('\n ( ','\n , ','\n )')]]"))
(:export-everything ::pr("")))
(gz export
(id)
(f :module-export id j ::pr("module [[id]]"))
(f :type-export id constructors-export j ::pr("[[id]][[constructors-export]]"))
)
(gz constructors-export
(:all-constructors ::pr("(..)"))
(id-non-star ::pr("[[id-non-star('(',',',')')]]"))
)
(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 f id-non-plus j type-class-decl-star 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 decl-mark name :tysig ret-type-and-params j
::pr("[[name]] :: [[ret-type-and-params]]")))
(gz instance (f :instance (type ::is id) (name ::is simpletype) context-opt decls j
::pr ("instance [[context-opt]] [[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}" (outer-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("\n 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(outer-constr-star ::pr("[[outer-constr-star('','\n | ','')]]")))
(gz field-type-and-param (f param type j
::pr("[[param]] :: [[type]]")))
(gz type-and-param ( f param type j ::pr("[[type]]")))
(gz outer-constr(outer-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')]]}")))
(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 outer-positional-constructor ["this one is sketchy"]
(type-ctor ::pr("[[type-ctor]]"))
(f type-ctor type-star j
::pr("[[type-ctor]][[type-star(' ',' ','')]]"))
(f :tuple type-plus j
::pr("[[type-plus('(',', ',')')]]"))
)
(gz positional-constructor ["this one is sketchy"]
(type-ctor ::pr("[[type-ctor]]"))
(f type-ctor type-star j
::pr("([[type-ctor]][[type-star(' ',' ','')]])"))
(f :tuple type-plus j
::pr("[[type-plus('(',', ',')')]]"))
)
(gz pattern
(id)
["avoid pattern-star because it causes weird spacing"]
(f pattern-ctor j
::pr ("[[pattern-ctor]]"))
(f pattern-ctor pattern-plus j
::pr ("([[pattern-ctor]] [[pattern-plus('',' ','')]])"))
(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"]
( :v id type ::pr("([[id]] :: [[type]])"))
)
(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)
(f :strict type j ::pr ("![[type]]"))
)
[(gz typepls (paren-type-plus))]
[(gz strict-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 ("(:)"))
(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 :msum expr-star j ::pr ("[[expr-star('(',' \x60mplus\x60 ',')')]]"))
(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 :mzerocase expr alt-star j
::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ',';\n')]]"
" _ -> mzero\n"
"})"))
(f :case expr alt-plus :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-plus(' ',';\n ',';\n')]]"
" _ -> [[underbar]]\n"
"})"))
(f :case expr :else (underbar ::is expr) alt-star j
::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-plus :else (underbar ::is expr) j
::pr("(\x5clambda_case_var ->"
"case lambda_case_var of {\n"
"[[alt-plus(' ',';\n ',';\n')]]"
" _ -> [[underbar]]\n"
"})"))
(f :lcase :else (underbar ::is expr) alt-star 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')]]} in [[expr]])"))
(f :rlet expr decl-star j
::pr("(let {[[decl-star('\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-plus j ::pr("[[expr-plus('(',':',')')]]"))
(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 expr j ::pr("[[pattern]] <- [[expr]];"))
(f :dlet decl-star j ::pr ("let {[[decl-star('\n',';\n','\n')]]};"))
)
(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 ("[[pred-expr-star('\n ','\n ','')]][[where-opt]]\n "
)))
(gz pred-expr ( f (pred ::is expr) (do ::is expr) j
::pr ("| [[pred]] -> [[do]]")))
(gz where (:where decls ::pr ("\n where [[decls]]")))
(gz decl-mark (":"))
(gz haddock ( :doc f docline-star j
::pr ("[[docline-star('\x7b\x2d |','\n',' \x2d\x7d\n')]]")))
(gz docline (astring))
]
Main :language-pragma
(
ScopedTypeVariables
)
:export-everything
(
(:specific System.Environment getArgs)
(:specific Control.Monad guard)
Text.Printf
)
(: main :fun (IO :unit) ()
(:join
getArgs
(:lcase
((:plist(:pstring "nothing"))(return :nothing))
((:plist n)(:rpipe n
read
Complexity
list-expr-of-complexity [listn]
(filter ok-commutative)
(filter (:rcompose bad-expr not))
(mapM- ans)))
:else
(putStrLn "need max complexity")
)))
(: euler-constant :fun Double () (exp 1))
(: phi :fun Double () (/ (+ 1 (sqrt 5))2))
(: Expr :data
E
Pi
Phi
TwoPi
InvPhi
Zero
Unity
Two
(Add Expr Expr)
(Sub Expr Expr)
(Mul Expr Expr)
(Div Expr Expr)
(Pow Expr Expr)
(Root Expr Expr)
(Log Expr Expr)
:deriving (Show Ord Eq)
)
(: evalop :fun (Maybe Double) ((op(:fn Double ((x Double)(y Double))))
(x Expr)
(y Expr))
(:do
(:= (:v jx Double) (eval x))
(:= (:v jy Double) (eval y))
(return (op jx jy))
))
(: loglimit :fun Double ()
(* 1023 (log 2)))
(: eval :fun (Maybe Double) ((e Expr))
(:case
e
(E (return euler-constant))
(Pi (return pi))
(Phi (return phi))
(TwoPi (return (* 2 pi)))
(InvPhi (return (/ 1 phi)))
(Zero (return 0))
(Unity (return 1))
(Two (return 2))
((Add x y)(evalop + x y))
((Sub x y)(evalop - x y))
((Mul x y)(evalop * x y))
((Div x y)(:do
(:= (:v jy Double) (eval y))
(guard (/= 0 jy))
(:= (:v jx Double) (eval x))
(return (/ jx jy))))
((Pow mx my)(:do
(:= (:v x Double) (eval mx))
(:= (:v y Double) (eval my))
(guard (<= 0 x))
(guard (< (* y (log x)) loglimit))
(return (** x y))))
((Root base expo)(eval (Pow base (eReciprocal expo))))
((Log mbase mx)(:do
(:= (:v x Double) (eval mx))
(:= (:v base Double) (eval mbase))
(guard (< 0 x))
(guard (< 0 base))
(guard (/= 1 base))
(return (/ (log x)(log base)))))
))
(: leaf :fun (:list Expr) ()
(:mlist E Pi Phi TwoPi InvPhi Zero Unity Two [(eSqrt Two)]))
(: Complexity :newtype (Complexity Integer) :deriving(Show))
(: list-expr-of-complexity :fun (:list Expr) ((n Complexity))
(:case n
((Complexity 0) (:mlist))
((Complexity 1) leaf)
:else
(:do
(:join (:mlist False True)
(:lcase
(False
(:do
(:= f one-arg)
(:= x (list-expr-of-complexity (pred-complexity n)))
(return (f x))))
(True
(:do
(:= f two-arg)
(:= first (enum-complexity (pred-complexity n)))
(:= x (list-expr-of-complexity first))
(:= y (list-expr-of-complexity (subtract-complexity (pred-complexity n) first)))
(return (f x y))))
)))))
(: enum-complexity :fun (:list Complexity) (((Complexity cmax) Complexity))
(:rpipe cmax (enumFromTo 0) (map Complexity)))
(: subtract-complexity :fun Complexity (((Complexity x)Complexity)
((Complexity y)Complexity))
(Complexity (- x y)))
(: pred-complexity :fun Complexity (((Complexity x)Complexity))
(Complexity (pred x)))
(: listn :fun (:list Expr)((n Complexity))
(concatMap list-expr-of-complexity (enum-complexity n)))
(: one-arg :fun (:list (:fn Expr ((x Expr))))()
(:mlist eSqrt eSqr eNegate eReciprocal eDouble))
(: eSqrt :fun Expr ((x Expr))
(Root x Two))
(: eSqr :fun Expr ((x Expr))
(Pow x Two))
(: eNegate :fun Expr ((x Expr))
(Sub Zero x))
(: eReciprocal :fun Expr ((x Expr))
(Div Unity x))
(: eDouble :fun Expr ((x Expr))
(Mul Two x))
(: two-arg :fun (:list (:fn Expr ((x Expr)(y Expr))))()
(:mlist Add Sub Mul Div Pow Root Log))
(: ans :fun (IO :unit) ((e Expr))
(:case (eval e)
(Nothing (return :nothing))
((Just x)
(:case True [(clock x)]
(True (putStrLn(:cc (printf "%.6f" x)" "(show e))))
:else (return :nothing)))
))
(: clock :fun Bool ((x Double))
(&& (< 1 x) (< x 13)))
(: ok-commutative :fun Bool ((e Expr))
(:let
(: twook :fun (:fn Bool ((x Expr)(y Expr))) ()
(two-boilerplate ok-commutative &&))
(:case e
(E True)(Pi True)(Phi True)(TwoPi True)(InvPhi True)(Zero True)(Unity True)(Two True)
((Add x y)(&& (<= x y) (twook x y)))
((Mul x y)(&& (<= x y) (twook x y)))
((Sub x y)(twook x y))
((Div x y)(twook x y))
((Root x y)(twook x y))
((Log x y)(twook x y))
((Pow x y)(twook x y))
)))
(: bad-denominator :fun Bool ((e Expr))
(:case e
(Phi True)(InvPhi True)
(Unity True)(Zero True)
((Div _ _)True)
:else
False
))
(: bad-expr-inner :fun Bool ((e1 Expr))
(:let
(: two-bad :fun Bool ((x Expr)(y Expr))
(two-boilerplate bad-expr-inner || x y))
(: bad-log :fun Bool ((base Expr)(e Expr))
(:case e
((Mul x y)(two-bad (Log base x)(Log base y)))
((Div x y)(two-bad (Log base x)(Log base y)))
((Pow x _)(bad-expr-inner (Log base x)))
:else
False))
(:case e1
(E False)(Pi False)(Phi False)(TwoPi False)(InvPhi False)(Zero False)(Unity False)(Two False)
((Add (Sub x y) (Sub fy fx)):gpats((&&(== x fx)(== y fy))True))
((Add _ (Log InvPhi _))True) [Sub _ (Log Phi _)]
((Add (Log x Phi)(Log y InvPhi)):gpats((== x y)True))
((Add Pi Pi)True)
((Add Unity Unity)True)
((Add _ Zero)True)
((Add Zero _)True)
((Add x y)(||(two-bad x y)(== x y))) [equals should by Mul Two x]
((Sub _ (Sub _ _))True)
((Sub InvPhi Phi)True)
((Sub Phi InvPhi) True)
((Sub Pi TwoPi)True)
((Sub _ Zero)True)
((Sub Two Unity)True)
((Sub x y)(|| (two-bad x y) (== x y)))
((Mul Zero _)True)
((Mul _ Zero)True)
((Mul Unity _)True)
((Mul _ Unity)True)
((Mul Phi InvPhi)True)
((Mul x y)(or(:mlist(two-bad x y)
(== x y)
)))
((Div _ Zero)True)
((Div Zero _)True)
((Div _ Unity)True)
((Div _ Phi)True)
((Div TwoPi Pi)True)
((Div Pi TwoPi)True)
((Div _ InvPhi)True) [sqr phi]
((Div x y)(or(:mlist(two-bad x y)
(== x y)
(bad-denominator y)
)))
((Pow Zero _)True)
((Pow Unity _)True)
((Pow _ Zero)True)
((Pow _ Unity)True)
((Pow (Root _ x) y):gpats((== x y)True))
((Pow (Pow _ _) _)True)
((Pow x y)(or(:mlist(two-bad x y))))
((Root Zero _)True)
((Root Unity _)True) [assuming 1 is the "only" root of unity]
((Root _ Unity)True)
((Root _ Phi)True)
((Root _ InvPhi)True)
((Root _ (Div _ _))True)
((Root x y)(or(:mlist(two-bad x y))))
((Log _ Unity)True)
((Log Phi InvPhi)True) [negate 1]
((Log InvPhi Phi)True) [negate 1]
((Log x y)(or(:mlist(two-bad x y)
(== x y)
(bad-log y x)
(bad-log x y)
)))
))
)
(: bad-expr :fun Bool ((e Expr))
(:rpipe e [non-special-terms] bad-expr-inner))
(: two-boilerplate :fun b ((process(:fn b((x a))))
(join (:fn b ((x b)(y b))))
(x a)(y a))
(join (process x)(process y)))