Created
January 5, 2020 06:32
-
-
Save kakkun61/739718aa1bf5fe5be83ee497a58f0113 to your computer and use it in GitHub Desktop.
供養
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main | |
( Version (Version) | |
, VersionRange (..) | |
) where | |
import Prelude | |
import Effect (Effect) | |
import Effect.Console (log) | |
import Node.FS.Sync | |
import Node.Path | |
import Data.String.Regex | |
import Data.String.Read | |
import Data.Show | |
import Text.Parsing.Parser (Parser, runParser) | |
import Text.Parsing.Parser as P | |
import Text.Parsing.Parser.Combinators as P | |
import Text.Parsing.Parser.Token as P | |
import Text.Parsing.Parser.String as P | |
import Data.Array | |
import Data.Functor | |
import Data.Either | |
import Data.Maybe | |
import Data.Char.Unicode as Char | |
import Simple.JSON (class ReadForeign, readJSON) | |
import Node.Platform | |
import Node.Process | |
import Data.Semigroup | |
import Foreign | |
import Node.Buffer as Buffer | |
import Node.Encoding | |
import Data.Map (Map) | |
import Data.Map as Map | |
import Data.Set as Set | |
import Data.Set (Set) | |
import Effect.Exception | |
import Data.Traversable | |
import Data.Tuple | |
import Data.Array as Array | |
import Control.Plus | |
import Node.FS.Stats | |
import Control.Category | |
import Foreign as Foreign | |
import Foreign.Object (Object) | |
newtype Version = Version { major :: Int, minor :: Int, patch :: Int } | |
data VersionRange | |
= RangeEqual Version | |
| RangeLessThan Version | |
| RangeGreaterThan Version | |
| RangeAnd VersionRange VersionRange | |
| RangeOr VersionRange VersionRange | |
instance showVersion :: Show Version where | |
show (Version v) = show v.major <> "." <> show v.minor <> "." <> show v.patch | |
instance readVersion :: Read Version where | |
read str = e2m $ runParser str versionParser | |
instance readForeignVersion :: ReadForeign Version where | |
readImpl raw = do | |
str <- Foreign.readString raw | |
case read str of | |
Just ver -> pure ver | |
Nothing -> Foreign.fail $ ForeignError "version parsing failed" | |
instance showVersionRange :: Show VersionRange where | |
show (RangeEqual v) = "== " <> show v | |
show (RangeLessThan v) = "< " <> show v | |
show (RangeGreaterThan v) = "> " <> show v | |
show (RangeAnd r0 r1) = "(" <> show r0 <> " and " <> show r1 <> ")" | |
show (RangeOr r0 r1) = "(" <> show r0 <> " or " <> show r1 <> ")" | |
instance readVersionRange :: Read VersionRange where | |
read str = | |
e2m $ runParser str do | |
void P.whiteSpace | |
P.choice | |
[ do | |
v0 <- versionParser | |
void P.whiteSpace | |
P.choice | |
[ P.try P.eof $> RangeEqual v0 | |
, P.try do | |
void $ P.char '<' | |
eq0 <- P.option false $ P.char '=' $> true | |
void P.whiteSpace | |
void $ P.char 'v' | |
void P.whiteSpace | |
let | |
left = | |
if eq0 | |
then RangeOr (RangeEqual v0) (RangeGreaterThan v0) | |
else RangeGreaterThan v0 | |
P.choice | |
[ P.try P.eof $> left | |
, do | |
void $ P.whiteSpace | |
right <- rightParser | |
pure $ RangeAnd left right | |
] | |
] | |
, do | |
void $ P.char 'v' | |
void P.whiteSpace | |
rightParser | |
] | |
where | |
rightParser = do | |
void $ P.char '<' | |
eq <- P.option false $ P.char '=' $> true | |
void $ P.whiteSpace | |
v <- versionParser | |
void $ P.whiteSpace | |
pure | |
if eq | |
then RangeOr (RangeEqual v) (RangeLessThan v) | |
else RangeLessThan v | |
instance readForeignVersionRange :: ReadForeign VersionRange where | |
readImpl raw = do | |
str <- Foreign.readString raw | |
case read str of | |
Just vr -> pure vr | |
Nothing -> Foreign.fail $ ForeignError "version range parsing failed" | |
e2m :: forall e a. Either e a -> Maybe a | |
e2m (Left e) = Nothing | |
e2m (Right a) = Just a | |
m2p :: forall a. Maybe a -> Parser String a | |
m2p Nothing = P.fail "m2p" | |
m2p (Just a) = pure a | |
versionParser :: Parser String Version | |
versionParser = do | |
maybeMajor <- da2i <$> some P.digit | |
void $ P.char '.' | |
maybeMinor <- da2i <$> some P.digit | |
void $ P.char '.' | |
maybePatch <- da2i <$> some P.digit | |
m2p do | |
major <- maybeMajor | |
minor <- maybeMinor | |
patch <- maybePatch | |
pure $ Version { major, minor, patch } | |
where | |
da2i :: Array Char -> Maybe Int | |
da2i a = | |
go 0 a | |
where | |
go :: Int -> Array Char -> Maybe Int | |
go acc a = | |
case uncons a of | |
Just u -> do | |
i <- Char.digitToInt u.head | |
go (10 * acc + i) u.tail | |
Nothing -> pure acc |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment