summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn J. Camilleri <john@digitalgrammars.com>2019-07-10 19:32:49 +0200
committerGitHub <noreply@github.com>2019-07-10 19:32:49 +0200
commit1ceb8c0342a4be31b3f7be9dc39d7f093b781c3b (patch)
treea9487e62ff440997abf0f56b8bd2c06c1650932e /src
parent32379a8d1118838e8f3487e1c54ab6eee813e7a5 (diff)
parenteab9fb88aaa5408c342927693d8593f1e0ba2b91 (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.hs2
-rw-r--r--src/compiler/GF/Compile/PGFtoJSON.hs156
-rw-r--r--src/compiler/GF/Compile/pgf.schema.json232
-rw-r--r--src/compiler/GF/Infra/Option.hs4
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)"),