replace aeson with json

This commit is contained in:
krangelov
2019-02-26 19:27:36 +01:00
parent 2fdfef13d8
commit 25dc934871
5 changed files with 101 additions and 291 deletions

View File

@@ -143,8 +143,7 @@ Library
---- GF compiler as a library: ---- GF compiler as a library:
build-depends: filepath, directory, time, time-compat, build-depends: filepath, directory, time, time-compat,
process, haskeline, parallel>=3, process, haskeline, parallel>=3
aeson>=1.3, yaml, unordered-containers, scientific, text
hs-source-dirs: src/compiler hs-source-dirs: src/compiler
exposed-modules: exposed-modules:

View File

@@ -37,7 +37,6 @@ exportPGF opts fmt pgf =
FmtPGFPretty -> multi "txt" (render . ppPGF) FmtPGFPretty -> multi "txt" (render . ppPGF)
FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical) FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical)
FmtCanonicalJson-> [] FmtCanonicalJson-> []
FmtCanonicalYaml-> []
FmtJavaScript -> multi "js" pgf2js FmtJavaScript -> multi "js" pgf2js
FmtPython -> multi "py" pgf2python FmtPython -> multi "py" pgf2python
FmtHaskell -> multi "hs" (grammar2haskell opts name) FmtHaskell -> multi "hs" (grammar2haskell opts name)

View File

@@ -24,7 +24,7 @@ import Data.Maybe
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy as BSL
import GF.Grammar.CanonicalJSON (encodeJSON, encodeYAML) import GF.Grammar.CanonicalJSON (encodeJSON)
import System.FilePath import System.FilePath
import Control.Monad(when,unless,forM_) import Control.Monad(when,unless,forM_)
@@ -65,7 +65,6 @@ compileSourceFiles opts fs =
mapM_ abs2canonical canonical mapM_ abs2canonical canonical
mapM_ cnc2canonical canonical mapM_ cnc2canonical canonical
when (FmtCanonicalJson `elem` ofmts) $ mapM_ grammar2json canonical when (FmtCanonicalJson `elem` ofmts) $ mapM_ grammar2json canonical
when (FmtCanonicalYaml `elem` ofmts) $ mapM_ grammar2yaml canonical
where where
ofmts = flag optOutputFormats opts ofmts = flag optOutputFormats opts
@@ -86,10 +85,6 @@ compileSourceFiles opts fs =
where absname = srcAbsName gr cnc where absname = srcAbsName gr cnc
gr_canon = grammar2canonical opts absname gr gr_canon = grammar2canonical opts absname gr
grammar2yaml (cnc,gr) = encodeYAML (render absname ++ ".yaml") gr_canon
where absname = srcAbsName gr cnc
gr_canon = grammar2canonical opts absname gr
writeExport (path,s) = writing opts path $ writeUTF8File path s writeExport (path,s) = writing opts path $ writeUTF8File path s

View File

@@ -1,35 +1,14 @@
{-# language OverloadedStrings, OverloadedLists #-}
module GF.Grammar.CanonicalJSON ( module GF.Grammar.CanonicalJSON (
encodeJSON, encodeYAML, encodeJSON
decodeJSON, decodeYAML
) where ) where
import Text.JSON
import qualified Control.Monad as CM (mapM, msum) import qualified Control.Monad as CM (mapM, msum)
import qualified Data.HashMap.Strict as HM (toList)
import qualified Data.Yaml as Yaml (encodeFile, decodeFileEither, ParseException)
import qualified Data.Aeson as Aeson (encodeFile, eitherDecodeFileStrict')
import Data.Aeson (ToJSON(..), object, (.=))
import Data.Aeson (FromJSON(..), Value(..), withObject, (.:), (.:?), (.!=))
import Data.Aeson.Types (typeMismatch, modifyFailure, Pair, Parser)
import Data.Text (Text, pack, unpack)
import Data.Scientific (floatingOrInteger)
import GF.Grammar.Canonical import GF.Grammar.Canonical
encodeJSON :: FilePath -> Grammar -> IO () encodeJSON :: FilePath -> Grammar -> IO ()
encodeJSON = Aeson.encodeFile encodeJSON fpath g = writeFile fpath (encode g)
encodeYAML :: FilePath -> Grammar -> IO ()
encodeYAML = Yaml.encodeFile
decodeJSON :: FilePath -> IO (Either String Grammar)
decodeJSON = Aeson.eitherDecodeFileStrict'
decodeYAML :: FilePath -> IO (Either Yaml.ParseException Grammar)
decodeYAML = Yaml.decodeFileEither
-- in general we encode grammars using JSON objects/records, -- in general we encode grammars using JSON objects/records,
@@ -38,317 +17,157 @@ decodeYAML = Yaml.decodeFileEither
-- the top-level definitions use normal record labels, -- the top-level definitions use normal record labels,
-- but recursive types/values/ids use labels staring with a "." -- but recursive types/values/ids use labels staring with a "."
instance ToJSON Grammar where instance JSON Grammar where
toJSON (Grammar abs cncs) = object ["abstract" .= abs, "concretes" .= cncs] showJSON (Grammar abs cncs) = makeObj [("abstract", showJSON abs), ("concretes", showJSON cncs)]
instance FromJSON Grammar where
parseJSON = withObject "Grammar" $ \o -> Grammar <$> o .: "abstract" <*> o .: "concretes"
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- ** Abstract Syntax -- ** Abstract Syntax
instance ToJSON Abstract where instance JSON Abstract where
toJSON (Abstract absid flags cats funs) showJSON (Abstract absid flags cats funs)
= object ["abs" .= absid, = makeObj [("abs", showJSON absid),
"flags" .= flags, ("flags", showJSON flags),
"cats" .= cats, ("cats", showJSON cats),
"funs" .= funs] ("funs", showJSON funs)]
instance FromJSON Abstract where instance JSON CatDef where
parseJSON = withObject "Abstract" $ \o -> Abstract
<$> o .: "abs"
<*> o .:? "flags" .!= Flags []
<*> o .: "cats"
<*> o .: "funs"
instance ToJSON CatDef where
-- non-dependent categories are encoded as simple strings: -- non-dependent categories are encoded as simple strings:
toJSON (CatDef c []) = toJSON c showJSON (CatDef c []) = showJSON c
toJSON (CatDef c cs) = object ["cat" .= c, "args" .= cs] showJSON (CatDef c cs) = makeObj [("cat", showJSON c), ("args", showJSON cs)]
instance FromJSON CatDef where
parseJSON (String s) = return $ CatDef (CatId (unpack s)) []
parseJSON (Object o) = CatDef <$> o .: "cat" <*> o .: "args"
parseJSON val = typeMismatch "CatDef" val
instance ToJSON FunDef where
toJSON (FunDef f ty) = object ["fun" .= f, "type" .= ty]
instance JSON FunDef where
showJSON (FunDef f ty) = makeObj [("fun", showJSON f), ("type", showJSON ty)]
{-
instance FromJSON FunDef where instance FromJSON FunDef where
parseJSON = withObject "FunDef" $ \o -> FunDef <$> o .: "fun" <*> o .: "type" parseJSON = withObject "FunDef" $ \o -> FunDef <$> o .: "fun" <*> o .: "type"
-}
instance JSON Type where
showJSON (Type bs ty) = makeObj [("args", showJSON bs), ("result", showJSON ty)]
instance ToJSON Type where instance JSON TypeApp where
toJSON (Type bs ty) = object [".args" .= bs, ".result" .= ty]
instance FromJSON Type where
parseJSON = withObject "Type" $ \o -> Type <$> o .: ".args" <*> o .: ".result"
instance ToJSON TypeApp where
-- non-dependent categories are encoded as simple strings: -- non-dependent categories are encoded as simple strings:
toJSON (TypeApp c []) = toJSON c showJSON (TypeApp c []) = showJSON c
toJSON (TypeApp c args) = object [".cat" .= c, ".args" .= args] showJSON (TypeApp c args) = makeObj [("cat", showJSON c), ("args", showJSON args)]
instance FromJSON TypeApp where instance JSON TypeBinding where
parseJSON (String s) = return $ TypeApp (CatId (unpack s)) []
parseJSON (Object o) = TypeApp <$> o .: ".cat" <*> o .: ".args"
parseJSON val = typeMismatch "TypeApp" val
instance ToJSON TypeBinding where
-- non-dependent categories are encoded as simple strings: -- non-dependent categories are encoded as simple strings:
toJSON (TypeBinding Anonymous (Type [] (TypeApp c []))) = toJSON c showJSON (TypeBinding Anonymous (Type [] (TypeApp c []))) = showJSON c
toJSON (TypeBinding x ty) = object [".var" .= x, ".type" .= ty] showJSON (TypeBinding x ty) = makeObj [("var", showJSON x), ("type", showJSON ty)]
instance FromJSON TypeBinding where
parseJSON (String s) = return $ TypeBinding Anonymous (Type [] (TypeApp (CatId (unpack s)) []))
parseJSON (Object o) = TypeBinding <$> o .: ".var" <*> o .: ".type"
parseJSON val = typeMismatch "TypeBinding" val
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- ** Concrete syntax -- ** Concrete syntax
instance ToJSON Concrete where instance JSON Concrete where
toJSON (Concrete cncid absid flags params lincats lins) showJSON (Concrete cncid absid flags params lincats lins)
= object ["cnc" .= cncid, = makeObj [("cnc", showJSON cncid),
"abs" .= absid, ("abs", showJSON absid),
"flags" .= flags, ("flags", showJSON flags),
"params" .= params, ("params", showJSON params),
"lincats" .= lincats, ("lincats", showJSON lincats),
"lins" .= lins] ("lins", showJSON lins)]
instance FromJSON Concrete where instance JSON ParamDef where
parseJSON = withObject "Concrete" $ \o -> Concrete showJSON (ParamDef p pvs) = makeObj [("param", showJSON p), ("values", showJSON pvs)]
<$> o .: "cnc" showJSON (ParamAliasDef p t) = makeObj [("param", showJSON p), ("alias", showJSON t)]
<*> o .: "abs"
<*> o .:? "flags" .!= Flags []
<*> o .: "params"
<*> o .: "lincats"
<*> o .: "lins"
instance JSON LincatDef where
showJSON (LincatDef c lt) = makeObj [("cat", showJSON c), ("lintype", showJSON lt)]
instance ToJSON ParamDef where instance JSON LinDef where
toJSON (ParamDef p pvs) = object ["param" .= p, "values" .= pvs] showJSON (LinDef f xs lv) = makeObj [("fun", showJSON f), ("args", showJSON xs), ("lin", showJSON lv)]
toJSON (ParamAliasDef p t) = object ["param" .= p, "alias" .= t]
instance FromJSON ParamDef where instance JSON LinType where
parseJSON = withObject "ParamDef" $ \o -> showJSON lt = case lt of
choose [ ParamDef <$> o .: "param" <*> o .: "values"
, ParamAliasDef <$> o .: "param" <*> o .: "alias"
]
instance ToJSON LincatDef where
toJSON (LincatDef c lt) = object ["cat" .= c, "lintype" .= lt]
instance FromJSON LincatDef where
parseJSON = withObject "LincatDef" $ \v -> LincatDef <$> v .: "cat" <*> v .: "lintype"
instance ToJSON LinDef where
toJSON (LinDef f xs lv) = object ["fun" .= f, "args" .= xs, "lin" .= lv]
instance FromJSON LinDef where
parseJSON = withObject "LinDef" $ \v -> LinDef <$> v .: "fun" <*> v .: "args" <*> v .: "lin"
instance ToJSON LinType where
toJSON lt = case lt of
-- the basic types (Str, Float, Int) are encoded as strings: -- the basic types (Str, Float, Int) are encoded as strings:
StrType -> "Str" StrType -> showJSON "Str"
FloatType -> "Float" FloatType -> showJSON "Float"
IntType -> "Int" IntType -> showJSON "Int"
-- parameters are also encoded as strings: -- parameters are also encoded as strings:
ParamType pt -> toJSON pt ParamType pt -> showJSON pt
-- tables/tuples are encoded as JSON objects: -- tables/tuples are encoded as JSON objects:
TableType pt lt -> object [".tblarg" .= pt, ".tblval" .= lt] TableType pt lt -> makeObj [("tblarg", showJSON pt), ("tblval", showJSON lt)]
TupleType lts -> object [".tuple" .= lts] TupleType lts -> makeObj [("tuple", showJSON lts)]
-- records are encoded as records: -- records are encoded as records:
RecordType rows -> toJSON rows RecordType rows -> showJSON rows
instance FromJSON LinType where instance JSON LinValue where
parseJSON (String "Str") = return StrType showJSON lv = case lv of
parseJSON (String "Float") = return FloatType
parseJSON (String "Int") = return IntType
parseJSON (String param) = return (ParamType (ParamTypeId (ParamId (unpack param))))
parseJSON val@(Object o) = choose [ (TableType <$> o .: ".tblarg" <*> o .: ".tblval")
, (TupleType <$> o .: ".tuple")
, (RecordType <$> parseJSON val)
]
parseJSON val = typeMismatch "LinType" val
instance ToJSON LinValue where
toJSON lv = case lv of
-- basic values (Str, Float, Int) are encoded as JSON strings/numbers: -- basic values (Str, Float, Int) are encoded as JSON strings/numbers:
StrConstant s -> toJSON s StrConstant s -> showJSON s
FloatConstant f -> toJSON f FloatConstant f -> showJSON f
IntConstant n -> toJSON n IntConstant n -> showJSON n
-- concatenation is encoded as a JSON array: -- concatenation is encoded as a JSON array:
ConcatValue v v' -> Array [toJSON v, toJSON v'] ConcatValue v v' -> showJSON [showJSON v, showJSON v']
-- most values are encoded as JSON objects: -- most values are encoded as JSON objects:
ParamConstant pv -> object [".param" .= pv] ParamConstant pv -> makeObj [("param", showJSON pv)]
PredefValue p -> object [".predef" .= p] PredefValue p -> makeObj [("predef", showJSON p)]
TableValue t tvs -> object [".tblarg" .= t, ".tblrows" .= tvs] TableValue t tvs -> makeObj [("tblarg", showJSON t), ("tblrows", showJSON tvs)]
-- VTableValue t ts -> object [".vtblarg" .= t, ".vtblrows" .= ts] TupleValue lvs -> makeObj [("tuple", showJSON lvs)]
TupleValue lvs -> object [".tuple" .= lvs] VarValue v -> makeObj [("var", showJSON v)]
VarValue v -> object [".var" .= v] ErrorValue s -> makeObj [("error", showJSON s)]
ErrorValue s -> object [".error" .= s] Projection lv l -> makeObj [("project", showJSON lv), ("label", showJSON l)]
Projection lv l -> object [".project" .= lv, ".label" .= l] Selection tv pv -> makeObj [("select", showJSON tv), ("key", showJSON pv)]
Selection tv pv -> object [".select" .= tv, ".key" .= pv] VariantValue vs -> makeObj [("variants", showJSON vs)]
VariantValue vs -> object [".variants" .= vs] PreValue alts def -> makeObj [("pre", showJSON alts), ("default", showJSON def)]
PreValue alts def -> object [".pre" .= alts, ".default" .= def]
-- records are encoded directly as JSON records: -- records are encoded directly as JSON records:
RecordValue rows -> toJSON rows RecordValue rows -> showJSON rows
instance FromJSON LinValue where instance JSON LinPattern where
parseJSON (String s) = return (StrConstant (unpack s)) showJSON linpat = case linpat of
parseJSON (Number n) = return (either FloatConstant IntConstant (floatingOrInteger n))
parseJSON (Array [v,v']) = ConcatValue <$> parseJSON v <*> parseJSON v'
parseJSON val@(Object o) = choose [ ParamConstant <$> o .: ".param"
, PredefValue <$> o .: ".predef"
, TableValue <$> o .: ".tblarg" <*> o .: ".tblrows"
-- , VTableValue <$> o .: ".vtblarg" <*> o .: ".vtblrows"
, TupleValue <$> o .: ".tuple"
, VarValue <$> o .: ".var"
, ErrorValue <$> o .: ".error"
, Projection <$> o .: ".project" <*> o .: ".label"
, Selection <$> o .: ".select" <*> o .: ".key"
, VariantValue <$> o .: ".variants"
, PreValue <$> o .: ".pre" <*> o .: ".default"
, RecordValue <$> parseJSON val
]
parseJSON val = typeMismatch "LinValue" val
instance ToJSON LinPattern where
toJSON linpat = case linpat of
-- wildcards and patterns without arguments are encoded as strings: -- wildcards and patterns without arguments are encoded as strings:
WildPattern -> "_" WildPattern -> showJSON "_"
ParamPattern (Param p []) -> toJSON p ParamPattern (Param p []) -> showJSON p
-- complex patterns are encoded as JSON objects: -- complex patterns are encoded as JSON objects:
ParamPattern pv -> toJSON pv ParamPattern pv -> showJSON pv
-- and records as records: -- and records as records:
RecordPattern r -> toJSON r RecordPattern r -> showJSON r
instance FromJSON LinPattern where instance JSON arg => JSON (Param arg) where
parseJSON (String "_") = return WildPattern
parseJSON (String s) = return (ParamPattern (Param (ParamId (unpack s)) []))
parseJSON val = choose [ ParamPattern <$> parseJSON val
, RecordPattern <$> parseJSON val
, typeMismatch "LinPattern" val
]
instance ToJSON arg => ToJSON (Param arg) where
-- parameters without arguments are encoded as strings: -- parameters without arguments are encoded as strings:
toJSON (Param p []) = toJSON p showJSON (Param p []) = showJSON p
toJSON (Param p args) = object [".paramid" .= p, ".args" .= args] showJSON (Param p args) = makeObj [("paramid", showJSON p), ("args", showJSON args)]
instance FromJSON arg => FromJSON (Param arg) where instance JSON a => JSON (RecordRow a) where
parseJSON (String p) = return (Param (ParamId (unpack p)) [])
parseJSON (Object o) = Param <$> o .: ".paramid" <*> o .: ".args"
parseJSON val = typeMismatch "Param" val
instance ToJSON a => ToJSON (RecordRow a) where
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects) -- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
toJSON row = object [toJSONRecordRow row] showJSON row = makeObj [toJSONRecordRow row]
toJSONList = object . map toJSONRecordRow
toJSONRecordRow :: ToJSON a => RecordRow a -> Pair toJSONRecordRow :: JSON a => RecordRow a -> (String,JSValue)
toJSONRecordRow (RecordRow (LabelId lbl) val) = pack lbl .= val toJSONRecordRow (RecordRow (LabelId lbl) val) = (lbl, showJSON val)
instance FromJSON a => FromJSON (RecordRow a) where instance JSON TableRowValue where
parseJSON = withObject "RecordRow" $ \o -> parseJSONRecordRow (head (HM.toList o)) showJSON (TableRowValue l v) = makeObj [("pattern", showJSON l), ("value", showJSON l)]
parseJSONList = withObject "[RecordRow]" $ \o -> CM.mapM parseJSONRecordRow (HM.toList o)
parseJSONRecordRow :: FromJSON a => (Text, Value) -> Parser (RecordRow a)
parseJSONRecordRow (lbl, val) = do val' <- parseJSON val
return (RecordRow (LabelId (unpack lbl)) val')
instance ToJSON TableRowValue where
toJSON (TableRowValue l v) = object [".pattern" .= l, ".value" .= v]
instance FromJSON TableRowValue where
parseJSON = withObject "TableRowValue" $ \v -> TableRowValue <$> v .: ".pattern" <*> v .: ".value"
-- *** Identifiers in Concrete Syntax -- *** Identifiers in Concrete Syntax
instance ToJSON PredefId where toJSON (PredefId s) = toJSON s instance JSON PredefId where showJSON (PredefId s) = showJSON s
instance ToJSON LabelId where toJSON (LabelId s) = toJSON s instance JSON LabelId where showJSON (LabelId s) = showJSON s
instance ToJSON VarValueId where toJSON (VarValueId s) = toJSON s instance JSON VarValueId where showJSON (VarValueId s) = showJSON s
instance ToJSON ParamId where toJSON (ParamId s) = toJSON s instance JSON ParamId where showJSON (ParamId s) = showJSON s
instance ToJSON ParamType where toJSON (ParamTypeId s) = toJSON s instance JSON ParamType where showJSON (ParamTypeId s) = showJSON s
instance FromJSON PredefId where parseJSON = coerceFrom "PredefId" PredefId
instance FromJSON LabelId where parseJSON = coerceFrom "LabelId" LabelId
instance FromJSON VarValueId where parseJSON = coerceFrom "VarValueId" VarValueId
instance FromJSON ParamId where parseJSON = coerceFrom "ParamId" ParamId
instance FromJSON ParamType where parseJSON = coerceFrom "ParamType" ParamTypeId
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- ** Used in both Abstract and Concrete Syntax -- ** Used in both Abstract and Concrete Syntax
instance ToJSON ModId where toJSON (ModId s) = toJSON s instance JSON ModId where showJSON (ModId s) = showJSON s
instance ToJSON CatId where toJSON (CatId s) = toJSON s instance JSON CatId where showJSON (CatId s) = showJSON s
instance ToJSON FunId where toJSON (FunId s) = toJSON s instance JSON FunId where showJSON (FunId s) = showJSON s
instance FromJSON ModId where parseJSON = coerceFrom "ModId" ModId instance JSON VarId where
instance FromJSON CatId where parseJSON = coerceFrom "CatId" CatId
instance FromJSON FunId where parseJSON = coerceFrom "FunId" FunId
instance ToJSON VarId where
-- the anonymous variable is the underscore: -- the anonymous variable is the underscore:
toJSON Anonymous = "_" showJSON Anonymous = showJSON "_"
toJSON (VarId x) = toJSON x showJSON (VarId x) = showJSON x
instance FromJSON VarId where instance JSON Flags where
parseJSON (String "_") = return Anonymous
parseJSON (String s) = return (VarId (unpack s))
parseJSON val = typeMismatch "VarId" val
instance ToJSON Flags where
-- flags are encoded directly as JSON records (i.e., objects): -- flags are encoded directly as JSON records (i.e., objects):
toJSON (Flags fs) = object [ pack f .= v | (f, v) <- fs ] showJSON (Flags fs) = makeObj [(f,showJSON v) | (f, v) <- fs]
instance FromJSON Flags where instance JSON FlagValue where
parseJSON = withObject "Flags" $ \o -> Flags <$> CM.mapM parseJSONFlag (HM.toList o)
where parseJSONFlag (flag, val) = do val' <- parseJSON val
return (unpack flag, val')
instance ToJSON FlagValue where
-- flag values are encoded as basic JSON types: -- flag values are encoded as basic JSON types:
toJSON (Str s) = toJSON s showJSON (Str s) = showJSON s
toJSON (Int i) = toJSON i showJSON (Int i) = showJSON i
toJSON (Flt f) = toJSON f showJSON (Flt f) = showJSON f
instance FromJSON FlagValue where
parseJSON (String s) = return $ Str (unpack s)
parseJSON (Number n) = return $ case floatingOrInteger n of
Left f -> Flt f
Right i -> Int i
parseJSON invalid = typeMismatch "FlagValue" invalid
--------------------------------------------------------------------------------
-- ** Helper functions
choose :: [Parser a] -> Parser a
choose = CM.msum
coerceFrom :: FromJSON s => String -> (s -> a) -> Value -> Parser a
coerceFrom expected constructor obj = modifyFailure failure $ fmap constructor $ parseJSON obj
where failure f = "(while parsing " ++ expected ++ ") " ++ f

View File

@@ -89,7 +89,6 @@ data Phase = Preproc | Convert | Compile | Link
data OutputFormat = FmtPGFPretty data OutputFormat = FmtPGFPretty
| FmtCanonicalGF | FmtCanonicalGF
| FmtCanonicalJson | FmtCanonicalJson
| FmtCanonicalYaml
| FmtJavaScript | FmtJavaScript
| FmtPython | FmtPython
| FmtHaskell | FmtHaskell
@@ -474,7 +473,6 @@ outputFormatsExpl =
[(("pgf_pretty", FmtPGFPretty),"human-readable pgf"), [(("pgf_pretty", FmtPGFPretty),"human-readable pgf"),
(("canonical_gf", FmtCanonicalGF),"Canonical GF source files"), (("canonical_gf", FmtCanonicalGF),"Canonical GF source files"),
(("canonical_json", FmtCanonicalJson),"Canonical JSON source files"), (("canonical_json", FmtCanonicalJson),"Canonical JSON source files"),
(("canonical_yaml", FmtCanonicalYaml),"Canonical YAML source files"),
(("js", FmtJavaScript),"JavaScript (whole grammar)"), (("js", FmtJavaScript),"JavaScript (whole grammar)"),
(("python", FmtPython),"Python (whole grammar)"), (("python", FmtPython),"Python (whole grammar)"),
(("haskell", FmtHaskell),"Haskell (abstract syntax)"), (("haskell", FmtHaskell),"Haskell (abstract syntax)"),