mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-09 04:59:31 -06:00
162 lines
5.3 KiB
Haskell
162 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,ModuleName(..))
|
|
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 PGF2.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 (convModId modid) extends (Abstract startcat cats funs) []
|
|
|
|
convExtends = mapM convExtend
|
|
convExtend (modid,MIAll) = return (convModId 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
|
|
convModId (MN m) = convId m
|
|
|
|
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 (convModId modid) extends abs [conc]
|
|
|
|
convOpens = mapM convOpen
|
|
|
|
convOpen o =
|
|
case o of
|
|
OSimple id -> return (convModId 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
|