-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParseList.hs
132 lines (121 loc) · 6.56 KB
/
ParseList.hs
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
-- |
-- Module : DobutokO.Sound.ParseList
-- Copyright : (c) OleksandrZhabenko 2020
-- License : MIT
-- Stability : Experimental
-- Maintainer : olexandr543@yahoo.com
--
-- Helps to create experimental music from a file (or its part) and a Ukrainian text.
-- It can also generate a timbre for the notes. Uses SoX inside.
{-# OPTIONS_GHC -threaded #-}
module DobutokO.Sound.ParseList where
import Data.Char (isSpace)
import qualified Data.Vector as V
import Text.Read (lex,readMaybe)
import Data.Maybe (isNothing,fromMaybe)
parseTup :: String -> [String]
parseTup xs = map (dropWhile isSpace . fst) (takeWhile (/= ("","")) . iterate (head . lex . snd) $ head (lex xs))
parseTupV :: String -> V.Vector String
parseTupV = V.fromList . parseTup
containsExt :: [String] -> Bool
containsExt = elem ".."
containsExtV :: V.Vector String -> Bool
containsExtV = V.elem ".."
-- | Predicate to check whether a 'V.Vector' does not contain round parentheses or dash (a minus sign) as its elements. Is used internally in the
-- 'parseStoLInts' function to avoid lists with negative elements.
canBePreParseV :: V.Vector String -> Bool
canBePreParseV v = not (V.elem "(" v || V.elem "-" v || V.elem ")" v)
-- | Notification. Uses an 'Int' limitation to avoid infinite lists. All arguments must be not negative.
parseV :: Int -> V.Vector String -> Maybe [Int]
parseV n v
| compare n 0 /= LT && V.findIndices (== "..") v == V.singleton 2 && V.length v == 4 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 3 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int in
case ins1 of
Just ins -> if compare n ins /= GT then Just [ins] else Just [ins..n]
Nothing -> Nothing
else Nothing
| compare n 0 /= LT && V.findIndices (== "..") v == V.singleton 2 && V.length v == 5 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 4 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in
case (ins1,ins2) of
(Just ins01,Just ins02) -> if ins02 >= ins01 then Just [ins01..ins02] else Nothing
_ -> Nothing
else Nothing
| compare n 0 /= LT && V.findIndices (== "..") v == V.singleton 4 && V.length v == 6 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 5 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in
case (ins1,ins2) of
(Just ins01,Just ins02) ->
case compare ins02 ins01 of
GT -> if compare n ins02 /= LT then Just [ins01,ins02..n] else Just [ins01,ins02]
EQ -> Just [ins01]
_ -> Just [ins01,ins02..0]
_ -> Nothing
else Nothing
| compare n 0 /= LT && V.findIndices (== "..") v == V.singleton 4 && V.length v == 7 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 6 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int
ins3 = readMaybe (V.unsafeIndex v 5)::Maybe Int in
case (ins1,ins2,ins3) of
(Just ins01,Just ins02,Just ins03) -> if null [ins01,ins02..ins03] then Nothing else Just [ins01,ins02..ins03]
_ -> Nothing
else Nothing
| compare n 0 /= LT && V.unsafeIndex v 0 == "[" && V.unsafeIndex v (V.length v - 1) == "]" && V.length v `rem` 2 == 1 &&
(V.toList . V.findIndices (== ",") $ v) == [2,4..(V.length v - 2)] =
let insV1 = V.imap (\i _ -> readMaybe (V.unsafeIndex v (2 * i + 1))::Maybe Int) (V.unsafeSlice 0 (V.length v `quot` 2) v) in
if V.any isNothing insV1
then Nothing
else Just (V.toList . V.mapMaybe id $ insV1)
| otherwise = Nothing
-- | From the 0.19.0.0 version. Can be used to parse also into infinite lists.
parseVInf :: V.Vector String -> Maybe [Int]
parseVInf v
| V.findIndices (== "..") v == V.singleton 2 && V.length v == 4 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 3 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int in
case ins1 of
Just ins -> Just [ins..]
Nothing -> Nothing
else Nothing
| V.findIndices (== "..") v == V.singleton 2 && V.length v == 5 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 4 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in
case (ins1,ins2) of
(Just ins01,Just ins02) -> if ins02 >= ins01 then Just [ins01..ins02] else Nothing
_ -> Nothing
else Nothing
| V.findIndices (== "..") v == V.singleton 4 && V.length v == 6 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 5 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int in
case (ins1,ins2) of
(Just ins01,Just ins02) -> Just [ins01,ins02..]
_ -> Nothing
else Nothing
| V.findIndices (== "..") v == V.singleton 4 && V.length v == 7 =
if V.unsafeIndex v 0 == "[" && V.unsafeIndex v 2 == "," && V.unsafeIndex v 6 == "]"
then let ins1 = readMaybe (V.unsafeIndex v 1)::Maybe Int
ins2 = readMaybe (V.unsafeIndex v 3)::Maybe Int
ins3 = readMaybe (V.unsafeIndex v 5)::Maybe Int in
case (ins1,ins2,ins3) of
(Just ins01,Just ins02,Just ins03) -> if null [ins01,ins02..ins03] then Nothing else Just [ins01,ins02..ins03]
_ -> Nothing
else Nothing
| V.unsafeIndex v 0 == "[" && V.unsafeIndex v (V.length v - 1) == "]" && V.length v `rem` 2 == 1 &&
(V.toList . V.findIndices (== ",") $ v) == [2,4..(V.length v - 2)] =
let insV1 = V.imap (\i _ -> readMaybe (V.unsafeIndex v (2 * i + 1))::Maybe Int) (V.unsafeSlice 0 (V.length v `quot` 2) v) in
if V.any isNothing insV1
then Nothing
else Just (V.toList . V.mapMaybe id $ insV1)
| otherwise = Nothing
-- | Parses a 'String' being a list of Ints written with Haskell rules, e. g. \"[1..]\", \"[2,4..45]\", \"[3,5,6,7,8,3]\" etc. into a list of 'Int'.
-- If it is not possible or list is empty, returns []. Preceding whitespaces are ignored. An 'Int' argument is used as a delimiter to avoid infinite lists.
parseStoLInts :: Int -> String -> [Int]
parseStoLInts n xs
| canBePreParseV . parseTupV . dropWhile isSpace $ xs = fromMaybe [] (parseV n (parseTupV . dropWhile isSpace $ xs))
| otherwise = []