mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-13 06:49:31 -06:00
GF.Text.Pretty provides the class Pretty and overloaded versions of the pretty printing combinators in Text.PrettyPrint, allowing pretty printable values to be used directly instead of first having to convert them to Doc with functions like text, int, char and ppIdent. Some modules have been converted to use GF.Text.Pretty, but not all. Precedences could be added to simplify the pretty printers for terms and patterns. GF.Infra.Location contains the types Location and L, factored out from GF.Grammar.Grammar, and the class HasSourcePath. This allowed the import of GF.Grammar.Grammar to be removed from GF.Infra.CheckM, making it more like a pure library module.
161 lines
5.3 KiB
Haskell
161 lines
5.3 KiB
Haskell
{-# LANGUAGE NoMonomorphismRestriction #-}
|
|
module SimpleEditor.Convert where
|
|
|
|
import Control.Monad(unless,foldM,ap,mplus)
|
|
import Data.List(sortBy)
|
|
import Data.Function(on)
|
|
import qualified Data.Map as Map
|
|
import Text.JSON(makeObj) --encode
|
|
import GF.Text.Pretty(render,(<+>))
|
|
|
|
import qualified Data.ByteString.UTF8 as UTF8(fromString)
|
|
|
|
import GF.Infra.Option(optionsGFO)
|
|
import GF.Infra.Ident(showIdent)
|
|
import GF.Grammar.Grammar
|
|
import GF.Grammar.Printer(ppParams,ppTerm,getAbs,TermPrintQual(..))
|
|
import GF.Grammar.Parser(runP,pModDef)
|
|
import GF.Grammar.Lexer(Posn(..))
|
|
import GF.Data.ErrM
|
|
import PGF.Internal(Literal(LStr))
|
|
|
|
import SimpleEditor.Syntax as S
|
|
import SimpleEditor.JSON
|
|
|
|
|
|
parseModule (path,source) =
|
|
(path.=) $
|
|
case runP pModDef (UTF8.fromString source) of
|
|
Left (Pn l c,msg) ->
|
|
makeObj ["error".=msg, "location".= show l++":"++show c]
|
|
Right mod -> case convModule mod of
|
|
Ok g -> makeObj ["converted".=g]
|
|
Bad msg -> makeObj ["parsed".=msg]
|
|
|
|
{-
|
|
convAbstractFile path =
|
|
appIOE (fmap encode . convAbstract =<< getSourceModule noOptions path)
|
|
-}
|
|
|
|
convModule m@(modid,src) =
|
|
if isModAbs src
|
|
then convAbstract m
|
|
else if isModCnc src
|
|
then convConcrete m
|
|
else fail "An abstract or concrete syntax module was expected"
|
|
|
|
convAbstract (modid,src) =
|
|
do unless (isModAbs src) $ fail "Abstract syntax expected"
|
|
unless (isCompleteModule src) $ fail "A complete abstract syntax expected"
|
|
extends <- convExtends (mextend src)
|
|
(cats0,funs0) <- convAbsJments (jments src)
|
|
let cats = reverse cats0
|
|
funs = reverse funs0
|
|
flags = optionsGFO (mflags src)
|
|
startcat =
|
|
case lookup "startcat" flags of
|
|
Just (LStr cat) -> cat
|
|
_ -> "-"
|
|
return $ Grammar (convId modid) extends (Abstract startcat cats funs) []
|
|
|
|
convExtends = mapM convExtend
|
|
convExtend (modid,MIAll) = return (convId modid)
|
|
convExtend _ = fail "unsupported module extension"
|
|
|
|
convAbsJments jments = foldM convAbsJment ([],[]) (jmentList jments)
|
|
|
|
convAbsJment (cats,funs) (name,jment) =
|
|
case jment of
|
|
AbsCat octx -> do unless (null (maybe [] unLoc octx)) $
|
|
fail "category with context"
|
|
let cat = convId name
|
|
return (cat:cats,funs)
|
|
AbsFun (Just lt) _ oeqns _ -> do unless (null (maybe [] id oeqns)) $
|
|
fail "function with equations"
|
|
let f = convId name
|
|
typ <- convType (unLoc lt)
|
|
let fun = Fun f typ
|
|
return (cats,fun:funs)
|
|
_ -> fail $ "unsupported judgement form: "++show jment
|
|
|
|
convType (Prod _ _ t1 t2) = (:) `fmap` convSimpleType t1 `ap` convType t2
|
|
convType t = (:[]) `fmap` convSimpleType t
|
|
|
|
|
|
convSimpleType (Vr id) = return (convId id)
|
|
convSimpleType t = fail "unsupported type"
|
|
|
|
convId = showIdent
|
|
|
|
convConcrete (modid,src) =
|
|
do unless (isModCnc src) $ fail "Concrete syntax expected"
|
|
unless (isCompleteModule src) $ fail "A complete concrete syntax expected"
|
|
extends <- convExtends (mextend src)
|
|
opens <- convOpens (mopens src)
|
|
js <- convCncJments (jments src)
|
|
let ps = [p | Pa p <-js]
|
|
lcs = [lc | LC lc<-js]
|
|
os = [o | Op o <-js]
|
|
ls = [l | Li l <-js]
|
|
langcode = "" -- !!!
|
|
conc = Concrete langcode opens ps lcs os ls
|
|
abs = Abstract "-" [] [] -- dummy
|
|
return $ Grammar (convId modid) extends abs [conc]
|
|
|
|
convOpens = mapM convOpen
|
|
|
|
convOpen o =
|
|
case o of
|
|
OSimple id -> return (convId id)
|
|
_ -> fail "unsupported module open"
|
|
|
|
|
|
data CncJment = Pa S.Param | LC Lincat | Op Oper | Li Lin | Ignored
|
|
|
|
convCncJments = mapM convCncJment . jmentList
|
|
|
|
convCncJment (name,jment) =
|
|
case jment of
|
|
ResParam ops _ ->
|
|
return $ Pa $ Param i (maybe "" (render . ppParams q . unLoc) ops)
|
|
ResValue _ -> return Ignored
|
|
CncCat (Just (L _ typ)) Nothing Nothing pprn _ -> -- ignores printname !!
|
|
return $ LC $ Lincat i (render $ ppTerm q 0 typ)
|
|
ResOper oltyp (Just lterm) -> return $ Op $ Oper lhs rhs
|
|
where
|
|
lhs = i++maybe "" ((" : "++) . render . ppTerm q 0 . unLoc) oltyp
|
|
rhs = render (" ="<+>ppTerm q 0 (unLoc lterm))
|
|
ResOverload [] defs -> return $ Op $ Oper lhs rhs
|
|
where
|
|
lhs = i
|
|
rhs = render $ " = overload"<+>ppTerm q 0 r
|
|
r = R [(lab,(Just ty,fu)) | (L _ ty,L _ fu) <-defs]
|
|
lab = ident2label name
|
|
CncFun _ (Just ldef) pprn _ -> -- ignores printname !!
|
|
do let (xs,e') = getAbs (unLoc ldef)
|
|
lin = render $ ppTerm q 0 e'
|
|
args <- mapM convBind xs
|
|
return $ Li $ Lin i args lin
|
|
_ -> fail $ "unsupported judgement form: "++show jment
|
|
where
|
|
i = convId name
|
|
q = Unqualified
|
|
|
|
convBind (Explicit,v) = return $ convId v
|
|
convBind (Implicit,v) = fail "implicit binding not supported"
|
|
|
|
jmentList = sortBy (compare `on` (jmentLocation.snd)) . Map.toList
|
|
|
|
jmentLocation jment =
|
|
case jment of
|
|
AbsCat ctxt -> fmap loc ctxt
|
|
AbsFun ty _ _ _ -> fmap loc ty
|
|
ResParam ops _ -> fmap loc ops
|
|
CncCat ty _ _ _ _ ->fmap loc ty
|
|
ResOper ty rhs -> fmap loc rhs `mplus` fmap loc ty
|
|
CncFun _ rhs _ _ -> fmap loc rhs
|
|
_ -> Nothing
|
|
|
|
|
|
loc (L l _) = l
|