1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
Module : Text.Pandoc.Lua.Marshaling.Version
Copyright : © 2019-2021 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
Stability : alpha
Marshaling of @'Version'@s. The marshaled elements can be compared using
default comparison operators (like @>@ and @<=@).
-}
module Text.Pandoc.Lua.Marshaling.Version
( peekVersion
, pushVersion
, peekVersionFuzzy
)
where
import Data.Maybe (fromMaybe)
import Data.Version (Version (..), makeVersion, parseVersion, showVersion)
import HsLua as Lua
import Safe (lastMay)
import Text.ParserCombinators.ReadP (readP_to_S)
import qualified Text.Pandoc.UTF8 as UTF8
instance Peekable Version where
peek = forcePeek . peekVersionFuzzy
instance Pushable Version where
push = pushVersion
-- | Push a @'Version'@ element to the Lua stack.
pushVersion :: LuaError e => Pusher e Version
pushVersion = pushUD typeVersion
peekVersionFuzzy :: LuaError e => Peeker e Version
peekVersionFuzzy idx = retrieving "Version" $ liftLua (Lua.ltype idx) >>= \case
Lua.TypeUserdata -> peekVersion idx
Lua.TypeString -> do
versionStr <- peekString idx
let parses = readP_to_S parseVersion versionStr
case lastMay parses of
Just (v, "") -> return v
_ -> Lua.failPeek $
UTF8.fromString $ "could not parse as Version: " ++ versionStr
Lua.TypeNumber -> do
(makeVersion . (:[])) <$> peekIntegral idx
Lua.TypeTable ->
makeVersion <$> peekList peekIntegral idx
_ ->
Lua.failPeek "could not peek Version"
peekVersion :: LuaError e => Peeker e Version
peekVersion = peekUD typeVersion
typeVersion :: LuaError e => DocumentedType e Version
typeVersion = deftype "Version"
[ operation Eq $ defun "__eq"
### liftPure2 (==)
<#> parameter peekVersionFuzzy "Version" "v1" ""
<#> parameter peekVersionFuzzy "Version" "v2" ""
=#> functionResult pushBool "boolean" "true iff v1 == v2"
, operation Lt $ defun "__lt"
### liftPure2 (<)
<#> parameter peekVersionFuzzy "Version" "v1" ""
<#> parameter peekVersionFuzzy "Version" "v2" ""
=#> functionResult pushBool "boolean" "true iff v1 < v2"
, operation Le $ defun "__le"
### liftPure2 (<=)
<#> parameter peekVersionFuzzy "Version" "v1" ""
<#> parameter peekVersionFuzzy "Version" "v2" ""
=#> functionResult pushBool "boolean" "true iff v1 <= v2"
, operation Len $ defun "__len"
### liftPure (length . versionBranch)
<#> parameter peekVersionFuzzy "Version" "v1" ""
=#> functionResult pushIntegral "integer" "number of version components"
, operation Tostring $ defun "__tostring"
### liftPure showVersion
<#> parameter peekVersionFuzzy "Version" "version" ""
=#> functionResult pushString "string" "stringified version"
]
[ method $ defun "must_be_at_least"
### must_be_at_least
<#> parameter peekVersionFuzzy "Version" "self" "version to check"
<#> parameter peekVersionFuzzy "Version" "reference" "minimum version"
<#> optionalParameter peekString "string" "msg" "alternative message"
=?> "Returns no result, and throws an error if this version is older than reference"
]
-- | Throw an error if this version is older than the given version.
-- FIXME: This function currently requires the string library to be
-- loaded.
must_be_at_least :: LuaError e
=> Version -> Version -> Maybe String
-> LuaE e NumResults
must_be_at_least actual expected mMsg = do
let msg = fromMaybe versionTooOldMessage mMsg
if expected <= actual
then return 0
else do
Lua.getglobal' "string.format"
Lua.push msg
Lua.push (showVersion expected)
Lua.push (showVersion actual)
Lua.call 3 1
Lua.error
-- | Default error message when a version is too old. This message is
-- formatted in Lua with the expected and actual versions as arguments.
versionTooOldMessage :: String
versionTooOldMessage = "expected version %s or newer, got %s"
|