{- BNF Converter: Non-pretty-printer generator (no "deriving Show" in OCaml...) Copyright (C) 2005 Author: Kristofer Johannisson 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} -- there is no "deriving Show" in OCaml, although there are solutions based -- on camlp4. Here we generate our own "show module". module CFtoOCamlShow (cf2show) where import CF import Utils import CFtoTemplate import List (intersperse) import Char(toLower,isDigit) import OCamlUtil cf2show :: String -> String -> CF -> String cf2show name absMod cf = unlines [ prologue name absMod, integerRule cf, doubleRule cf, if hasIdent cf then identRule cf else "", unlines [ownPrintRule cf own | (own,_) <- tokenPragmas cf], rules cf ] prologue :: String -> String -> String prologue name absMod = unlines [ "(* show functions generated by the BNF converter *)\n", "open " ++ absMod, "", "(* use string buffers for efficient string concatenations *)", "type showable = Buffer.t -> unit", "", "let show (s : showable) : string = ", " let init_size = 16 in (* you may want to adjust this *)", " let b = Buffer.create init_size in", " s b;", " Buffer.contents b", " ", "let emptyS : showable = fun buf -> ()", "", "let c2s (c:char) : showable = fun buf -> Buffer.add_char buf c", "let s2s (s:string) : showable = fun buf -> Buffer.add_string buf s", "", "let ( >> ) (s1 : showable) (s2 : showable) : showable = fun buf -> s1 buf; s2 buf", "", "let showChar (c:char) : showable = fun buf -> ", " Buffer.add_string buf (\"'\" ^ Char.escaped c ^ \"'\")", "", "let showString (s:string) : showable = fun buf -> ", " Buffer.add_string buf (\"\\\"\" ^ String.escaped s ^ \"\\\"\")", "", "let showList (showFun : 'a -> showable) (xs : 'a list) : showable = fun buf -> ", " let rec f ys = match ys with", " [] -> ()", " | [y] -> showFun y buf", " | y::ys -> showFun y buf; Buffer.add_string buf \"; \"; f ys ", " in", " Buffer.add_char buf '[';", " f xs;", " Buffer.add_char buf ']'", "" ] integerRule cf = "let showInt (i:int) : showable = s2s (string_of_int i)" doubleRule cf = "let showFloat (f:float) : showable = s2s (string_of_float f)" identRule cf = ownPrintRule cf "Ident" ownPrintRule cf own = unlines $ [ "let rec" +++ showsFun own +++ "(" ++ own ++ posn ++ ") : showable = s2s \"" ++ own ++ " \" >> showString i" ] where posn = if isPositionCat cf own then " (_,i)" else " i" -- copy and paste from CFtoTemplate rules :: CF -> String rules cf = unlines $ mutualDefs $ map (\(s,xs) -> case_fun s (map toArgs xs)) $ cf2data cf -- ++ ifList cf s where toArgs (cons,args) = ((cons, names (map (checkRes . var) args) (0 :: Int)), ruleOf cons) names [] _ = [] names (x:xs) n | elem x xs = (x ++ show n) : names xs (n+1) | otherwise = x : names xs n var ('[':xs) = var (init xs) ++ "s" var "Ident" = "id" var "Integer" = "n" var "String" = "str" var "Char" = "c" var "Double" = "d" var xs = map toLower xs checkRes s | elem s reservedOCaml = s ++ "'" | otherwise = s ruleOf s = maybe undefined id $ lookup s (rulesOfCF cf) --- case_fun :: Cat -> [(Constructor,Rule)] -> String case_fun cat xs = unlines [ -- "instance Print" +++ cat +++ "where", showsFun cat +++ "(e:" ++ fixType cat ++ ") : showable = match e with", unlines $ insertBar $ map (\ ((c,xx),r) -> " " ++ c +++ mkTuple xx +++ "->" +++ "s2s" +++ show c +++ case mkRhs xx (snd r) of {[] -> []; str -> ">> c2s ' ' >> " ++ str} ) xs ] mkRhs args its = case unwords (intersperse " >> s2s \", \" >> " (mk args its)) of [] -> "" str -> "c2s '(' >> " ++ str ++ " >> c2s ')'" where mk args (Left "#" : items) = mk args items mk (arg:args) (Left c : items) = (showsFun c +++ arg) : mk args items mk args (Right s : items) = mk args items mk _ _ = [] prt c = showsFun c +++ show (precCat c) showsFun :: Cat -> String showsFun c = case c of '[':xs -> case break (== ']') xs of (t,"]") -> "showList" +++ showsFun t -- showFun t ++ "List" _ -> c -- should not occur (this means an invariant of the type Cat is broken) _ -> if precCat c > 0 -- precedence-level cats are not in abstract syntax then "show" ++ (fixTypeUpper $ reverse (dropWhile isDigit (reverse c))) else "show" ++ (fixTypeUpper c)