summaryrefslogtreecommitdiff
path: root/src/GF/API
diff options
context:
space:
mode:
Diffstat (limited to 'src/GF/API')
-rw-r--r--src/GF/API/GrammarToHaskell.hs133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/GF/API/GrammarToHaskell.hs b/src/GF/API/GrammarToHaskell.hs
new file mode 100644
index 000000000..c7e3488ce
--- /dev/null
+++ b/src/GF/API/GrammarToHaskell.hs
@@ -0,0 +1,133 @@
+module GrammarToHaskell (grammar2haskell) where
+
+import qualified GFC
+import Macros
+
+import Modules
+import Operations
+
+-- to write a GF abstract grammar into a Haskell module with translations from
+-- data objects into GF trees. Example: GSyntax for Agda.
+-- AR 11/11/1999 -- 7/12/2000 -- 18/5/2004
+
+-- the main function
+grammar2haskell :: GFC.CanonGrammar -> String
+grammar2haskell gr = foldr (++++) [] $
+ haskPreamble ++ [datatypes gr', gfinstances gr', fginstances gr']
+ where gr' = hSkeleton gr
+
+-- by this you can prefix all identifiers with stg; the default is 'G'
+gId :: OIdent -> OIdent
+gId i = 'G':i
+
+haskPreamble =
+ [
+ "module GSyntax where",
+ "",
+ "import Ident",
+ "import Grammar",
+ "import PrGrammar",
+ "import Macros",
+ "import Operations",
+ "----------------------------------------------------",
+ "-- automatic translation from GF to Haskell",
+ "----------------------------------------------------",
+ "",
+ "class Gf a where gf :: a -> Trm",
+ "class Fg a where fg :: Trm -> a",
+ "",
+ predefInst "String" "K s",
+ "",
+ predefInst "Int" "EInt s",
+ "",
+ "----------------------------------------------------",
+ "-- below this line machine-generated",
+ "----------------------------------------------------",
+ ""
+ ]
+
+predefInst typ patt = let gtyp = gId typ in
+ "newtype" +++ gtyp +++ "=" +++ gtyp +++ typ +++ " deriving Show" +++++
+ "instance Gf" +++ gtyp +++ "where" ++++
+ " gf (" ++ gtyp +++ "s) =" +++ patt +++++
+ "instance Fg" +++ gtyp +++ "where" ++++
+ " fg t =" ++++
+ " case termForm t of" ++++
+ " Ok ([]," +++ patt +++ ",[]) ->" +++ gtyp +++ "s" ++++
+ " _ -> error (\"no" +++ gtyp +++ "\" ++ prt t)"
+
+type OIdent = String
+
+type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
+
+datatypes, gfinstances, fginstances :: (String,HSkeleton) -> String
+datatypes = (foldr (+++++) "") . (filter (/="")) . (map hDatatype) . snd
+gfinstances (m,g) = (foldr (+++++) "") $ (filter (/="")) $ (map (hInstance m)) g
+fginstances (m,g) = (foldr (+++++) "") $ (filter (/="")) $ (map (fInstance m)) g
+
+hDatatype :: (OIdent, [(OIdent, [OIdent])]) -> String
+hInstance, fInstance :: String -> (OIdent, [(OIdent, [OIdent])]) -> String
+
+hDatatype ("Cn",_) = "" ---
+hDatatype (cat,[]) = ""
+hDatatype (cat,rules) =
+ "data" +++ gId cat +++ "=" ++
+ (if length rules == 1 then "" else "\n ") +++
+ foldr1 (\x y -> x ++ "\n |" +++ y)
+ [gId f +++ foldr (+++) "" (map gId xx) | (f,xx) <- rules] ++++
+ " deriving Show"
+
+----hInstance m ("Cn",_) = "" --- seems to belong to an old applic. AR 18/5/2004
+hInstance m (cat,[]) = ""
+hInstance m (cat,rules) =
+ "instance Gf" +++ gId cat +++ "where" ++
+ (if length rules == 1 then "" else "\n") +++
+ foldr1 (\x y -> x ++ "\n" +++ y) [mkInst f xx | (f,xx) <- rules]
+ where
+ mkInst f xx =
+ "gf " ++
+ (if length xx == 0 then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
+ "=" +++
+ "appqc \"" ++ m ++ "\" \"" ++ f ++ "\"" +++
+ "[" ++ prTList ", " ["gf" +++ x | x <- xx'] ++ "]"
+ where xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
+
+----fInstance m ("Cn",_) = "" ---
+fInstance m (cat,[]) = ""
+fInstance m (cat,rules) =
+ "instance Fg" +++ gId cat +++ "where" ++++
+ " fg t =" ++++
+ " case termForm t of" ++++
+ foldr1 (\x y -> x ++ "\n" ++ y) [mkInst f xx | (f,xx) <- rules] ++++
+ " _ -> error (\"no" +++ cat ++ " \" ++ prt t)"
+ where
+ mkInst f xx =
+ " Ok ([], Q (IC \"" ++ m ++ "\") (IC \"" ++ f ++ "\")," ++
+ "[" ++ prTList "," xx' ++ "])" +++
+ "->" +++
+ gId f +++
+ prTList " " [prParenth ("fg" +++ x) | x <- xx']
+ where xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
+
+hSkeleton :: GFC.CanonGrammar -> (String,HSkeleton)
+hSkeleton gr = (name,collectR rules [(c,[]) | c <- cats]) where
+ collectR rr hh =
+ case rr of
+ (fun,typ):rs -> case catSkeleton typ of
+ Ok (cats,cat) ->
+ collectR rs (updateSkeleton (symid (snd cat)) hh (fun,
+ map (symid . snd) cats))
+ _ -> collectR rs hh
+ _ -> hh
+ cats = [symid cat | (cat,GFC.AbsCat _ _) <- defs]
+ rules = [(symid fun, typ) | (fun,GFC.AbsFun typ _) <- defs]
+
+ defs = concat [tree2list (jments m) | im@(_,ModMod m) <- modules gr, isModAbs m]
+ name = ifNull "UnknownModule" (symid . last) [n | (n,ModMod m) <- modules gr, isModAbs m]
+
+updateSkeleton :: OIdent -> HSkeleton -> (OIdent, [OIdent]) -> HSkeleton
+updateSkeleton cat skel rule =
+ case skel of
+ (cat0,rules):rr | cat0 == cat -> (cat0, rule:rules) : rr
+ (cat0,rules):rr -> (cat0, rules) : updateSkeleton cat rr rule
+