Skip to content

Commit ae76abd

Browse files
authored
Render to TOML (#119)
* Initial TOML rendering * Handle key escaping * Uncomment tests * Allow no toml checks for now * Test harness updates * Make acceptance tests fail then pass. NB temporarily removing all heterogeneous arrays to keep toml rendering happy. Should get back in for the other formats.
1 parent cbabc5b commit ae76abd

File tree

17 files changed

+466
-34
lines changed

17 files changed

+466
-34
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ jobs:
118118
-e EXECUTABLE=/tmp/workspace/eu
119119
-e GHCRTS=-N2
120120
curvelogic/eucalypt-test-harness:${CIRCLE_SHA1}
121-
pipenv run ./eut.py -o /tmp/artifacts"
121+
bash -c 'pipenv install && pipenv run ./eut.py -o /tmp/artifacts'"
122122
- store_artifacts:
123123
path: /tmp/artifacts
124124

harness/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Build Eucalypt test harness as a container. The eu executable must
22
# be provided at runtime in an attached volume and env var EXECUTABLE
33
# must contain the path.
4-
FROM ubuntu:18.04
4+
FROM ubuntu:19.04
55

66
RUN apt-get update \
77
&& apt-get install -y libgmp10 python3-pip python3-dev

harness/Pipfile

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,4 @@ name = "pypi"
55

66
[packages]
77
PyYAML = ">=4.2b1"
8-
9-
[requires]
10-
python_version = "3.6"
8+
toml = ">=0.10.0"

harness/Pipfile.lock

+22-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

harness/eut.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
import yaml
1414
except:
1515
print("WARNING: yaml not available")
16+
try:
17+
import toml
18+
except:
19+
print("WARNING: toml not available")
1620
import json
1721
from enum import Enum
1822
from pathlib import (Path)
@@ -50,14 +54,21 @@ def check(self):
5054
if self.format == "yaml":
5155
with open(self.outfile) as stream:
5256
try:
53-
content_passes = yaml.load(stream).get("RESULT") == "PASS"
57+
content_passes = yaml.load(stream, Loader=yaml.SafeLoader).get("RESULT") == "PASS"
5458
except:
5559
pass
5660

5761
if self.format == "json":
5862
with open(self.outfile) as stream:
5963
content_passes = json.load(stream).get("RESULT") == "PASS"
6064

65+
if self.format == "toml":
66+
with open(self.outfile) as stream:
67+
try:
68+
content_passes = toml.load(stream).get("RESULT") == "PASS"
69+
except:
70+
pass
71+
6172
return self.proc.returncode == 0 and content_passes
6273

6374
def execute(self):
@@ -228,7 +239,7 @@ def find_simple_tests(testdir, outdir):
228239
testdir.glob("*.yaml"),
229240
testdir.glob("*.json"),
230241
testdir.glob("*.toml"))),
231-
["yaml", "json"])]
242+
["yaml", "json", "toml"])]
232243

233244
def find_error_tests(testdir, outdir):
234245
return [ErrorTest(p, outdir) for p in sorted(testdir.glob("errors/*.eu"))]
@@ -273,4 +284,4 @@ def main():
273284
return 0
274285

275286
if __name__ == '__main__':
276-
main()
287+
sys.exit(main())

harness/test/015_block_fns.eu

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ block1: {
66

77
block2: block1
88

9+
10+
`{ export: :suppress doc: "Heterogeneous array so can't be rendered to TOML" }
911
items: block2 elements
1012

1113
block3: items block

harness/test/039_tags.eu

+3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
tagged-sym: :blah // { tag: "!Ref" }
22

3+
`{ export: :suppress doc: "Heterogeneous array so can't be rendered to TOML" }
34
tagged-list: ["-", [:a, :b, :c]] // { tag: "!Fn::Join" }
45

6+
homogeneous-tagged-list: [1, 2, 3, 4] // { tag: "!Periwabble" }
7+
58
tagged-block: { a: 1 } // { tag: "!Blah" }
69

710
mblock: meta(tagged-block)

harness/test/045_csv_import.eu

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ checks: {
1010
ƍ: scoped.pass
1111
}
1212

13-
PASS: checks values all-true? then(:PASS, :FAIL)
13+
RESULT: checks values all-true? then(:PASS, :FAIL)

src/Eucalypt/Driver/Options.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ exportOption =
6262
optional $
6363
strOption
6464
(long "exportType" <> short 'x' <> metavar "FORMAT" <>
65-
help "Format for export (e.g. yaml, json)") <|>
65+
help "Format for export (e.g. yaml, json, toml, text)") <|>
6666
flag'
6767
"json"
6868
(long "json" <> short 'j' <> help "JSON output (equivalent to -x json)")
@@ -317,6 +317,7 @@ inferOutputFormat opts =
317317
".json" -> Just "json"
318318
".yaml" -> Just "yaml"
319319
".yml" -> Just "yaml"
320+
".toml" -> Just "toml"
320321
".eu" -> Just "eu"
321322
".csv" -> Just "csv"
322323
_ -> Just "yaml"

src/Eucalypt/Driver/Stg.hs

+9-4
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ import Eucalypt.Core.Syn (CoreExpr)
2525
import Eucalypt.Driver.Options (EucalyptOptions(..))
2626
import qualified Eucalypt.Render.Json as Json
2727
import qualified Eucalypt.Render.Text as Text
28+
import qualified Eucalypt.Render.Toml as Toml
2829
import qualified Eucalypt.Render.Yaml as Yaml
2930
import Eucalypt.Stg.Compiler.CompileCore (compileForRender)
31+
import Eucalypt.Render.Error
3032
import Eucalypt.Reporting.Error
3133
import Eucalypt.Stg.Error
3234
import Eucalypt.Stg.Eval (step)
@@ -96,7 +98,7 @@ renderConduit ::
9698
=> EucalyptOptions
9799
-> CoreExpr
98100
-> m BS.ByteString
99-
renderConduit opts expr = handle handler $ do
101+
renderConduit opts expr = handle wrapStg $ handle wrapRender $ do
100102
syn <- compile expr
101103
ms <- newMachine syn
102104
runConduitRes $ machineSource ms .| renderPipeline format
@@ -106,8 +108,10 @@ renderConduit opts expr = handle handler $ do
106108
if optionDebug opts
107109
then debugMachine
108110
else machine
109-
handler :: MonadCatch m => StgException -> m BS.ByteString
110-
handler e = throwM $ Execution e
111+
wrapStg :: MonadCatch m => StgException -> m BS.ByteString
112+
wrapStg e = throwM $ Execution e
113+
wrapRender :: MonadCatch m => RenderError -> m BS.ByteString
114+
wrapRender e = throwM $ Render e
111115

112116

113117

@@ -137,7 +141,8 @@ machineSource ms = do
137141
-- | Select an appropriate render pipeline based on the requested
138142
-- format
139143
renderPipeline ::
140-
(MonadResource m) => String -> ConduitT Event Void m BS.ByteString
144+
(MonadThrow m, MonadResource m) => String -> ConduitT Event Void m BS.ByteString
141145
renderPipeline "json" = Json.pipeline
142146
renderPipeline "text" = Text.pipeline
147+
renderPipeline "toml" = Toml.pipeline
143148
renderPipeline _ = Yaml.pipeline

src/Eucalypt/Render/Error.hs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{-|
2+
Module : Eucalypt.Render.Error
3+
Description : Render errors
4+
Copyright : (c) Greg Hawkins, 2019
5+
License :
6+
Maintainer : [email protected]
7+
Stability : experimental
8+
-}
9+
module Eucalypt.Render.Error where
10+
11+
import Control.Exception.Safe
12+
import Eucalypt.Reporting.Common
13+
import Eucalypt.Reporting.Classes
14+
import Text.PrettyPrint ((<+>))
15+
import qualified Text.PrettyPrint as P
16+
17+
-- | An issue with a eucalypt document that impedes rendering to a
18+
-- given format
19+
data RenderProblem = HeterogeneousArray | NonTextualKey
20+
deriving (Eq, Show, Typeable)
21+
22+
instance Reportable RenderProblem where
23+
report HeterogeneousArray = P.text "a heterogeneous array"
24+
report NonTextualKey = P.text "a non-textual key"
25+
26+
-- | An error during rendering
27+
data RenderError =
28+
Unrenderable String
29+
RenderProblem
30+
deriving (Show, Eq, Typeable)
31+
32+
instance Exception RenderError
33+
34+
instance Reportable RenderError where
35+
report (Unrenderable f prob) =
36+
title "RENDER ERROR" P.$$ P.text "Could not render to" <+>
37+
P.text f <+> P.text "because of" <+> (report prob <> P.text ".")

0 commit comments

Comments
 (0)