diff options
| author | John J. Camilleri <john@digitalgrammars.com> | 2019-07-10 19:32:49 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-07-10 19:32:49 +0200 |
| commit | 1ceb8c0342a4be31b3f7be9dc39d7f093b781c3b (patch) | |
| tree | a9487e62ff440997abf0f56b8bd2c06c1650932e /src | |
| parent | 32379a8d1118838e8f3487e1c54ab6eee813e7a5 (diff) | |
| parent | eab9fb88aaa5408c342927693d8593f1e0ba2b91 (diff) | |
Merge pull request #45 from GrammaticalFramework/pgf2json
Add export to PGF JSON format
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler/GF/Compile/Export.hs | 2 | ||||
| -rw-r--r-- | src/compiler/GF/Compile/PGFtoJSON.hs | 156 | ||||
| -rw-r--r-- | src/compiler/GF/Compile/pgf.schema.json | 232 | ||||
| -rw-r--r-- | src/compiler/GF/Infra/Option.hs | 4 |
4 files changed, 393 insertions, 1 deletions
diff --git a/src/compiler/GF/Compile/Export.hs b/src/compiler/GF/Compile/Export.hs index e0811d40d..7d3337e3d 100644 --- a/src/compiler/GF/Compile/Export.hs +++ b/src/compiler/GF/Compile/Export.hs @@ -7,6 +7,7 @@ import GF.Compile.PGFtoHaskell import GF.Compile.PGFtoJava import GF.Compile.PGFtoProlog import GF.Compile.PGFtoJS +import GF.Compile.PGFtoJSON import GF.Compile.PGFtoPython import GF.Infra.Option --import GF.Speech.CFG @@ -38,6 +39,7 @@ exportPGF opts fmt pgf = FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical) FmtCanonicalJson-> [] FmtJavaScript -> multi "js" pgf2js + FmtJSON -> multi "json" pgf2json FmtPython -> multi "py" pgf2python FmtHaskell -> multi "hs" (grammar2haskell opts name) FmtJava -> multi "java" (grammar2java opts name) diff --git a/src/compiler/GF/Compile/PGFtoJSON.hs b/src/compiler/GF/Compile/PGFtoJSON.hs new file mode 100644 index 000000000..e634dae67 --- /dev/null +++ b/src/compiler/GF/Compile/PGFtoJSON.hs @@ -0,0 +1,156 @@ +module GF.Compile.PGFtoJSON (pgf2json) where + +import PGF (showCId) +import qualified PGF.Internal as M +import PGF.Internal ( + Abstr, + CId, + CncCat(..), + CncFun(..), + Concr, + DotPos, + Equation(..), + Literal(..), + PArg(..), + PGF, + Production(..), + Symbol(..), + Type, + absname, + abstract, + cflags, + cnccats, + cncfuns, + concretes, + funs, + productions, + sequences, + totalCats + ) + +import qualified Text.JSON as JSON +import Text.JSON (JSValue(..)) + +import qualified Data.Array.IArray as Array +import Data.Map (Map) +import qualified Data.Set as Set +import qualified Data.Map as Map +import qualified Data.IntMap as IntMap + +pgf2json :: PGF -> String +pgf2json pgf = + JSON.encode $ JSON.makeObj + [ ("abstract", json_abstract) + , ("concretes", json_concretes) + ] + where + n = showCId $ absname pgf + as = abstract pgf + cs = Map.assocs (concretes pgf) + start = showCId $ M.lookStartCat pgf + json_abstract = abstract2json n start as + json_concretes = JSON.makeObj $ map concrete2json cs + +abstract2json :: String -> String -> Abstr -> JSValue +abstract2json name start ds = + JSON.makeObj + [ ("name", mkJSStr name) + , ("startcat", mkJSStr start) + , ("funs", JSON.makeObj $ map absdef2json (Map.assocs (funs ds))) + ] + +absdef2json :: (CId,(Type,Int,Maybe ([Equation],[[M.Instr]]),Double)) -> (String,JSValue) +absdef2json (f,(typ,_,_,_)) = (showCId f,sig) + where + (args,cat) = M.catSkeleton typ + sig = JSON.makeObj + [ ("args", JSArray $ map (mkJSStr.showCId) args) + , ("cat", mkJSStr $ showCId cat) + ] + +lit2json :: Literal -> JSValue +lit2json (LStr s) = mkJSStr s +lit2json (LInt n) = mkJSInt n +lit2json (LFlt d) = JSRational True (toRational d) + +concrete2json :: (CId,Concr) -> (String,JSValue) +concrete2json (c,cnc) = (showCId c,obj) + where + obj = JSON.makeObj + [ ("flags", JSON.makeObj [ (showCId k, lit2json v) | (k,v) <- Map.toList (cflags cnc) ]) + , ("productions", JSON.makeObj [ (show cat, JSArray (map frule2json (Set.toList set))) | (cat,set) <- IntMap.toList (productions cnc)]) + , ("functions", JSArray (map ffun2json (Array.elems (cncfuns cnc)))) + , ("sequences", JSArray (map seq2json (Array.elems (sequences cnc)))) + , ("categories", JSON.makeObj $ map cats2json (Map.assocs (cnccats cnc))) + , ("totalfids", mkJSInt (totalCats cnc)) + ] + +cats2json :: (CId, CncCat) -> (String,JSValue) +cats2json (c,CncCat start end _) = (showCId c, ixs) + where + ixs = JSON.makeObj + [ ("start", mkJSInt start) + , ("end", mkJSInt end) + ] + +frule2json :: Production -> JSValue +frule2json (PApply fid args) = + JSON.makeObj + [ ("type", mkJSStr "Apply") + , ("fid", mkJSInt fid) + , ("args", JSArray (map farg2json args)) + ] +frule2json (PCoerce arg) = + JSON.makeObj + [ ("type", mkJSStr "Coerce") + , ("arg", mkJSInt arg) + ] + +farg2json :: PArg -> JSValue +farg2json (PArg hypos fid) = + JSON.makeObj + [ ("type", mkJSStr "PArg") + , ("hypos", JSArray $ map (mkJSInt . snd) hypos) + , ("fid", mkJSInt fid) + ] + +ffun2json :: CncFun -> JSValue +ffun2json (CncFun f lins) = + JSON.makeObj + [ ("name", mkJSStr $ showCId f) + , ("lins", JSArray (map mkJSInt (Array.elems lins))) + ] + +seq2json :: Array.Array DotPos Symbol -> JSValue +seq2json seq = JSArray [sym2json s | s <- Array.elems seq] + +sym2json :: Symbol -> JSValue +sym2json (SymCat n l) = new "SymCat" [mkJSInt n, mkJSInt l] +sym2json (SymLit n l) = new "SymLit" [mkJSInt n, mkJSInt l] +sym2json (SymVar n l) = new "SymVar" [mkJSInt n, mkJSInt l] +sym2json (SymKS t) = new "SymKS" [mkJSStr t] +sym2json (SymKP ts alts) = new "SymKP" [JSArray (map sym2json ts), JSArray (map alt2json alts)] +sym2json SymBIND = new "SymKS" [mkJSStr "&+"] +sym2json SymSOFT_BIND = new "SymKS" [mkJSStr "&+"] +sym2json SymSOFT_SPACE = new "SymKS" [mkJSStr "&+"] +sym2json SymCAPIT = new "SymKS" [mkJSStr "&|"] +sym2json SymALL_CAPIT = new "SymKS" [mkJSStr "&|"] +sym2json SymNE = new "SymNE" [] + +alt2json :: ([Symbol],[String]) -> JSValue +alt2json (ps,ts) = new "Alt" [JSArray (map sym2json ps), JSArray (map mkJSStr ts)] + +new :: String -> [JSValue] -> JSValue +new f xs = + JSON.makeObj + [ ("type", mkJSStr f) + , ("args", JSArray xs) + ] + +-- | Make JSON value from string +mkJSStr :: String -> JSValue +mkJSStr = JSString . JSON.toJSString + +-- | Make JSON value from integer +mkJSInt :: Integral a => a -> JSValue +mkJSInt = JSRational False . toRational diff --git a/src/compiler/GF/Compile/pgf.schema.json b/src/compiler/GF/Compile/pgf.schema.json new file mode 100644 index 000000000..2058e9a70 --- /dev/null +++ b/src/compiler/GF/Compile/pgf.schema.json @@ -0,0 +1,232 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://grammaticalframework.org/pgf.schema.json", + "type": "object", + "title": "PGF JSON Schema", + "required": [ + "abstract", + "concretes" + ], + "properties": { + "abstract": { + "type": "object", + "required": [ + "name", + "startcat", + "funs" + ], + "properties": { + "name": { + "type": "string" + }, + "startcat": { + "type": "string" + }, + "funs": { + "type": "object", + "additionalProperties": { + "type": "object", + "required": [ + "args", + "cat" + ], + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "cat": { + "type": "string" + } + } + } + } + } + }, + "concretes": { + "type": "object", + "additionalProperties": { + "required": [ + "flags", + "productions", + "functions", + "sequences", + "categories", + "totalfids" + ], + "properties": { + "flags": { + "type": "object", + "additionalProperties": { + "type": ["string", "number"] + } + }, + "productions": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/apply" + }, + { + "$ref": "#/definitions/coerce" + } + ] + } + } + }, + "functions": { + "type": "array", + "items": { + "title": "CncFun", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "lins": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + }, + "sequences": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/sym" + } + } + }, + "categories": { + "type": "object", + "additionalProperties": { + "title": "CncCat", + "type": "object", + "required": [ + "start", + "end" + ], + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + } + } + }, + "totalfids": { + "type": "integer" + } + } + } + } + }, + "definitions": { + "apply": { + "required": [ + "type", + "fid", + "args" + ], + "properties": { + "type": { + "type": "string", + "enum": ["Apply"] + }, + "fid": { + "type": "integer" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/parg" + } + } + } + }, + "coerce": { + "required": [ + "type", + "arg" + ], + "properties": { + "type": { + "type": "string", + "enum": ["Coerce"] + }, + "arg": { + "type": "integer" + } + } + }, + "parg": { + "required": [ + "type", + "hypos", + "fid" + ], + "properties": { + "type": { + "type": "string", + "enum": ["PArg"] + }, + "hypos": { + "type": "array", + "items": { + "type": "integer" + } + }, + "fid": { + "type": "integer" + } + } + }, + "sym": { + "title": "Sym", + "required": [ + "type", + "args" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "SymCat", + "SymLit", + "SymVar", + "SymKS", + "SymKP", + "SymNE" + ] + }, + "args": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "$ref": "#/definitions/sym" + } + ] + } + } + } + } + } +} diff --git a/src/compiler/GF/Infra/Option.hs b/src/compiler/GF/Infra/Option.hs index 7e1c22b9d..7455c83c4 100644 --- a/src/compiler/GF/Infra/Option.hs +++ b/src/compiler/GF/Infra/Option.hs @@ -90,6 +90,7 @@ data OutputFormat = FmtPGFPretty | FmtCanonicalGF | FmtCanonicalJson | FmtJavaScript + | FmtJSON | FmtPython | FmtHaskell | FmtJava @@ -328,7 +329,7 @@ optDescr = Option ['f'] ["output-format"] (ReqArg outFmt "FMT") (unlines ["Output format. FMT can be one of:", "Canonical GF grammar: canonical_gf, canonical_json, (and haskell with option --haskell=concrete)", - "Multiple concrete: pgf (default), js, pgf_pretty, prolog, python, ...", -- gar, + "Multiple concrete: pgf (default), json, js, pgf_pretty, prolog, python, ...", -- gar, "Single concrete only: bnf, ebnf, fa, gsl, jsgf, regexp, slf, srgs_xml, srgs_abnf, vxml, ....", -- cf, lbnf, "Abstract only: haskell, ..."]), -- prolog_abs, Option [] ["sisr"] (ReqArg sisrFmt "FMT") @@ -474,6 +475,7 @@ outputFormatsExpl = (("canonical_gf", FmtCanonicalGF),"Canonical GF source files"), (("canonical_json", FmtCanonicalJson),"Canonical JSON source files"), (("js", FmtJavaScript),"JavaScript (whole grammar)"), + (("json", FmtJSON),"JSON (whole grammar)"), (("python", FmtPython),"Python (whole grammar)"), (("haskell", FmtHaskell),"Haskell (abstract syntax)"), (("java", FmtJava),"Java (abstract syntax)"), |
