Skip to content

Commit

Permalink
ogma-core: Add support for XML files to standalone backend. Refs nasa…
Browse files Browse the repository at this point in the history
…#202.

There is a need in Ogma to support XML-based input files, since this is
produced by many standard tools in the industry. Like with JSON, we want
users to be able to customize the input format via a command-line flag,
so that users can work with XML-based files whose format is previously
unknown to Ogma without having to modify the tool.

A prior commit has introduced a library to parse Ogma specifications
from XML files.

This commit extends ogma-core to accept input files in XML, and to treat
any configuration file with the prefix "xml" as format specification for
an XML-based input file.
  • Loading branch information
ivanperez-keera committed Jan 19, 2025
1 parent ae964bf commit 7875ff4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
1 change: 1 addition & 0 deletions ogma-core/ogma-core.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ library
, ogma-language-copilot >= 1.5.0 && < 1.6
, ogma-language-jsonspec >= 1.5.0 && < 1.6
, ogma-language-smv >= 1.5.0 && < 1.6
, ogma-language-xmlspec >= 1.5.0 && < 1.6
, ogma-spec >= 1.5.0 && < 1.6

hs-source-dirs:
Expand Down
34 changes: 24 additions & 10 deletions ogma-core/src/Command/Standalone.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- Copyright 2020 United States Government as represented by the Administrator
Expand Down Expand Up @@ -44,7 +45,7 @@ import Control.Exception as E
import Data.Aeson (decode, eitherDecode, object, (.=))
import Data.ByteString.Lazy (fromStrict)
import Data.Foldable (for_)
import Data.List (isInfixOf, nub, (\\))
import Data.List (isInfixOf, isPrefixOf, nub, (\\))
import Data.Maybe (fromMaybe)
import System.Directory (doesFileExist)
import System.Process (readProcess)
Expand All @@ -64,6 +65,7 @@ import Paths_ogma_core (getDataDir)
import Data.OgmaSpec (ExternalVariableDef (..), InternalVariableDef (..),
Requirement (..), Spec (..))
import Language.JSONSpec.Parser (JSONFormat (..), parseJSONSpec)
import Language.XMLSpec.Parser (parseXMLSpec)

-- Internal imports: language ASTs, transformers
import qualified Language.CoCoSpec.AbsCoCoSpec as CoCoSpec
Expand Down Expand Up @@ -135,7 +137,7 @@ standalone' :: FilePath
-> StandaloneOptions
-> ExprPair
-> IO (Either String (String, String, String, String, String))
standalone' fp options (ExprPair parse replace print ids) = do
standalone' fp options (ExprPair parse replace print ids def) = do
let name = standaloneFilename options
typeMaps = typeToCopilotTypeMapping options

Expand All @@ -160,19 +162,25 @@ standalone' fp options (ExprPair parse replace print ids) = do
if formatMissing
then return $ Left $ standaloneIncorrectFormatSpec formatFile
else do
format <- read <$> readFile formatFile
format <- readFile formatFile

let wrapper = wrapVia (standalonePropVia options) parse

-- All of the following operations use Either to return error messages.
-- The use of the monadic bind to pass arguments from one function to the
-- next will cause the program to stop at the earliest error.
content <- B.safeReadFile fp
res <- case content of
Left s -> return $ Left s
Right b -> do case eitherDecode b of
Left e -> return $ Left e
Right v -> parseJSONSpec wrapper format v
res <-
if | isPrefixOf "xml" (standaloneFormat options)
-> do let xmlFormat = read format
content <- readFile fp
parseXMLSpec wrapper def xmlFormat content
| otherwise
-> do let jsonFormat = read format
content <- B.safeReadFile fp
case content of
Left s -> return $ Left s
Right b -> do case eitherDecode b of
Left e -> return $ Left e
Right v -> parseJSONSpec wrapper jsonFormat v

-- Complement the specification with any missing/implicit definitions
let res' = fmap (addMissingIdentifiers ids) res
Expand Down Expand Up @@ -276,11 +284,15 @@ typeToCopilotTypeMapping options =

-- | Handler for boolean expressions that knows how to parse them, replace
-- variables in them, and convert them to Copilot.
--
-- It also contains a default value to be used whenever an expression cannot be
-- found in the input file.
data ExprPair = forall a . ExprPair
{ exprParse :: String -> Either String a
, exprReplace :: [(String, String)] -> a -> a
, exprPrint :: a -> String
, exprIdents :: a -> [String]
, exprUnknown :: a
}

-- | Return a handler depending on whether it should be for CoCoSpec boolean
Expand All @@ -291,10 +303,12 @@ exprPair "cocospec" = ExprPair (CoCoSpec.pBoolSpec . CoCoSpec.myLexer)
(\_ -> id)
(CoCoSpec.boolSpec2Copilot)
(CoCoSpec.boolSpecNames)
(CoCoSpec.BoolSpecSignal (CoCoSpec.Ident "undefined"))
exprPair _ = ExprPair (SMV.pBoolSpec . SMV.myLexer)
(substituteBoolExpr)
(SMV.boolSpec2Copilot)
(SMV.boolSpecNames)
(SMV.BoolSpecSignal (SMV.Ident "undefined"))

-- | Add to a spec external variables for all identifiers mentioned in
-- expressions that are not defined anywhere.
Expand Down

0 comments on commit 7875ff4

Please sign in to comment.