Lines effect
This commit is contained in:
parent
db0f3a0427
commit
bd94410c01
13 changed files with 146 additions and 27 deletions
2
SSG.ipkg
2
SSG.ipkg
|
@ -17,7 +17,6 @@ depends = contrib
|
||||||
, structures
|
, structures
|
||||||
, tailrec
|
, tailrec
|
||||||
, eff
|
, eff
|
||||||
, refined
|
|
||||||
, elab-util
|
, elab-util
|
||||||
, elab-pretty
|
, elab-pretty
|
||||||
, prettier
|
, prettier
|
||||||
|
@ -26,6 +25,7 @@ depends = contrib
|
||||||
modules = SSG.HTML
|
modules = SSG.HTML
|
||||||
, SSG.HTML.ElementTypes
|
, SSG.HTML.ElementTypes
|
||||||
, SSG.Djot
|
, SSG.Djot
|
||||||
|
, SSG.Djot.Lines
|
||||||
|
|
||||||
-- main file (i.e. file to load at REPL)
|
-- main file (i.e. file to load at REPL)
|
||||||
main = Main
|
main = Main
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
module Djot
|
module SSG.Djot
|
||||||
|
|
102
src/SSG/Djot/Lines.idr
Normal file
102
src/SSG/Djot/Lines.idr
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
||| An effect for reading an input as a list of lines
|
||||||
|
module SSG.Djot.Lines
|
||||||
|
|
||||||
|
import Data.String
|
||||||
|
|
||||||
|
import Control.Eff
|
||||||
|
|
||||||
|
-- Only for iutils unit tests
|
||||||
|
import System
|
||||||
|
|
||||||
|
--*********************
|
||||||
|
--* Effect Definition *
|
||||||
|
--*********************
|
||||||
|
|
||||||
|
export
|
||||||
|
data Lines : Type -> Type where
|
||||||
|
||| Peek the next line
|
||||||
|
Peek : Lines (Maybe String)
|
||||||
|
||| Take the next line
|
||||||
|
Take : Lines (Maybe String)
|
||||||
|
|
||||||
|
--*********************
|
||||||
|
--* Effect Actions *
|
||||||
|
--*********************
|
||||||
|
|
||||||
|
export
|
||||||
|
peek : Has Lines fs => Eff fs (Maybe String)
|
||||||
|
peek = send Peek
|
||||||
|
|
||||||
|
export
|
||||||
|
take : Has Lines fs => Eff fs (Maybe String)
|
||||||
|
take = send Take
|
||||||
|
|
||||||
|
--*********************
|
||||||
|
--* Effect Handlers *
|
||||||
|
--*********************
|
||||||
|
|
||||||
|
||| Split the next line from a string
|
||||||
|
nextLine : String -> Maybe (String, String)
|
||||||
|
nextLine str =
|
||||||
|
if null str
|
||||||
|
then Nothing
|
||||||
|
else
|
||||||
|
let
|
||||||
|
(before, after) = break (\c => any (== c) ['\r', '\n']) str
|
||||||
|
in Just (before, removeNewline after)
|
||||||
|
where
|
||||||
|
-- If `after` is empty, we have hit the end of the string, and there is no newline
|
||||||
|
-- character to remove. If it has contents, then we need to remove the newline
|
||||||
|
removeNewline : String -> String
|
||||||
|
removeNewline str with (strM str)
|
||||||
|
removeNewline "" | StrNil = ""
|
||||||
|
removeNewline (strCons '\n' xs) | (StrCons '\n' xs) = xs
|
||||||
|
-- Handle either a \r or a \r\n
|
||||||
|
removeNewline (strCons '\r' xs) | (StrCons '\r' xs) with (strM xs)
|
||||||
|
removeNewline (strCons '\r' "") | (StrCons '\r' "") | StrNil = ""
|
||||||
|
removeNewline (strCons '\r' _) | (StrCons '\r' _) | (StrCons '\n' xs1) = xs1
|
||||||
|
removeNewline (strCons '\r' _) | (StrCons '\r' _) | (StrCons x xs1) = strCons x xs1
|
||||||
|
-- We shouldn't ever hit this case, as we would have to have contents after the
|
||||||
|
-- break, but no newline character, but we fill it in for the sake of totality
|
||||||
|
removeNewline (strCons x xs) | (StrCons x xs) = str
|
||||||
|
|
||||||
|
unLines : String -> Lines s -> (s, String)
|
||||||
|
unLines str Peek =
|
||||||
|
case nextLine str of
|
||||||
|
Nothing => (Nothing, str)
|
||||||
|
Just (before, after) => (Just before, str)
|
||||||
|
unLines str Take =
|
||||||
|
case nextLine str of
|
||||||
|
Nothing => (Nothing, str)
|
||||||
|
Just (before, after) => (Just before, after)
|
||||||
|
|
||||||
|
||| Feed a `Lines` from a provided input string
|
||||||
|
export
|
||||||
|
runLines : Has Lines fs =>
|
||||||
|
(input : String) -> Eff fs t -> Eff (fs - Lines) (t, String)
|
||||||
|
runLines input =
|
||||||
|
handleRelayS input (\x, y => pure (y, x)) $ \input2, lns, f =>
|
||||||
|
let (vv, input3) = unLines input2 lns
|
||||||
|
in f input3 vv
|
||||||
|
|
||||||
|
--*********************
|
||||||
|
--* Unit Tests *
|
||||||
|
--*********************
|
||||||
|
|
||||||
|
-- @@test runLines Smoke Test
|
||||||
|
runLinesSmoke : IO Bool
|
||||||
|
runLinesSmoke = do
|
||||||
|
let input = "Hello\nWorld\n\n"
|
||||||
|
putStrLn "Input: \{show input}"
|
||||||
|
let reference = lines input
|
||||||
|
putStrLn "Reference: \{show reference}"
|
||||||
|
let (output, rest) = extract $ runLines input lines'
|
||||||
|
putStrLn "Output: \{show output}"
|
||||||
|
putStrLn "Rest: \{show rest}"
|
||||||
|
pure $ output == reference && null rest
|
||||||
|
where
|
||||||
|
lines' : Eff [Lines] (List String)
|
||||||
|
lines' = do
|
||||||
|
Just next <- take
|
||||||
|
| _ => pure []
|
||||||
|
map (next ::) lines'
|
|
@ -4,5 +4,5 @@ import Test.Golden.RunnerHelper
|
||||||
|
|
||||||
main : IO ()
|
main : IO ()
|
||||||
main = goldenRunner
|
main = goldenRunner
|
||||||
[ "Djot -> HTML Golden Values" `atDir` "djot-to-html"
|
[ "Hedgehog Tests" `atDir` "hedgehog"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
module Main
|
|
||||||
|
|
||||||
import SSG.Djot
|
|
||||||
import SSG.HTML
|
|
||||||
|
|
||||||
import System
|
|
||||||
import System.File
|
|
||||||
|
|
||||||
main : IO ()
|
|
||||||
main = do
|
|
||||||
Right contents <- readFile "test.dj"
|
|
||||||
| Left err => do
|
|
||||||
printLn err
|
|
||||||
exitFailure
|
|
||||||
let parsed = djot contents
|
|
||||||
putStr . render . renderHtml $ parsed
|
|
|
@ -1,6 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang=en>
|
|
||||||
<body>
|
|
||||||
<p>Hello World!</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1 +0,0 @@
|
||||||
Hello World!
|
|
28
test/hedgehog/001-lines/Main.idr
Normal file
28
test/hedgehog/001-lines/Main.idr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
module Main
|
||||||
|
|
||||||
|
import SSG.Djot.Lines
|
||||||
|
|
||||||
|
import Control.Eff
|
||||||
|
import Data.String
|
||||||
|
import Hedgehog
|
||||||
|
|
||||||
|
lines' : Eff [Lines] (List String)
|
||||||
|
lines' = do
|
||||||
|
Just next <- take
|
||||||
|
| _ => pure []
|
||||||
|
map (next ::) lines'
|
||||||
|
|
||||||
|
propLinesEquiv : Property
|
||||||
|
propLinesEquiv = property $ do
|
||||||
|
str <- forAll $ string (linear 0 256) ascii
|
||||||
|
let std_lines = lines str
|
||||||
|
let (our_lines, rest) = extract $ runLines str lines'
|
||||||
|
our_lines === std_lines
|
||||||
|
|
||||||
|
main : IO ()
|
||||||
|
main = test $
|
||||||
|
[ MkGroup
|
||||||
|
"Lines effect"
|
||||||
|
[ ("Lines effect equivalent to lines", propLinesEquiv)
|
||||||
|
]
|
||||||
|
]
|
3
test/hedgehog/001-lines/expected
Normal file
3
test/hedgehog/001-lines/expected
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
━━━ Lines effect ━━━
|
||||||
|
✓ Lines effect equivalent to lines passed 1000 tests.
|
||||||
|
✓ 1 succeeded.
|
5
test/hedgehog/001-lines/pack.toml
Normal file
5
test/hedgehog/001-lines/pack.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[custom.all.SSG]
|
||||||
|
type = "local"
|
||||||
|
path = "../../.."
|
||||||
|
ipkg = "SSG.ipkg"
|
||||||
|
test = "test/test.ipkg"
|
|
@ -1,6 +1,6 @@
|
||||||
rm -rf build/
|
rm -rf build/
|
||||||
|
|
||||||
flock "$1" pack -q install-deps test.ipkg
|
flock "$1" pack -q install-deps test.ipkg
|
||||||
pack -q run test.ipkg
|
HEDGEHOG_COLOR=0 pack -q run test.ipkg -n 1000
|
||||||
|
|
||||||
rm -rf build/
|
rm -rf build/
|
|
@ -1,6 +1,8 @@
|
||||||
package a-test
|
package a-test
|
||||||
|
|
||||||
depends = SSG
|
depends = SSG
|
||||||
|
, hedgehog
|
||||||
|
, eff
|
||||||
|
|
||||||
main = Main
|
main = Main
|
||||||
|
|
2
todo.org
2
todo.org
|
@ -47,3 +47,5 @@ Decided to rename =Tag= to =Html=, and =Raw= to =Text=, which makes this make se
|
||||||
**** TODO Symbols
|
**** TODO Symbols
|
||||||
**** TODO Raw Inline
|
**** TODO Raw Inline
|
||||||
**** TODO Inline Attributes
|
**** TODO Inline Attributes
|
||||||
|
*** Lines effect
|
||||||
|
**** TODO =IO= Backed implementation
|
||||||
|
|
Loading…
Add table
Reference in a new issue