@@ -10,8 +10,11 @@ import Prelude
1010import Control.Alt ((<|>))
1111import Control.Apply ((<*), (*>))
1212import Control.Lazy as Lazy
13+ import Control.Monad (when )
1314
15+ import Data.Bifunctor (lmap )
1416import Data.Const (Const (..))
17+ import Data.Either (Either (..))
1518import Data.Foldable (elem )
1619import Data.Functor ((<$))
1720import Data.Functor.Compose (Compose (..))
@@ -34,11 +37,11 @@ parseInlines
3437 ∷ ∀ a
3538 . (SD.Value a )
3639 ⇒ L.List String
37- → L.List (SD.Inline a )
40+ → Either String ( L.List (SD.Inline a ) )
3841parseInlines s =
39- -- Note: `fromRight` is benign, because the parser never fails
40- consolidate <<< Data.Either.Unsafe .fromRight $
41- P .runParser (S .joinWith " \n " $ L .fromList s) inlines
42+ map consolidate
43+ $ lmap (\( P.ParseError {message}) → message)
44+ $ P .runParser (S .joinWith " \n " $ L .fromList s) inlines
4245
4346consolidate
4447 ∷ ∀ a
@@ -142,11 +145,15 @@ inlines = L.many inline2 <* PS.eof
142145 <|> PC .try link
143146
144147 inline2 ∷ P.Parser String (SD.Inline a )
145- inline2 =
146- PC .try formField
147- <|> PC .try inline1
148- <|> PC .try image
149- <|> other
148+ inline2 = do
149+ res ←
150+ PC .try formField
151+ <|> PC .try (Right <$> inline1)
152+ <|> PC .try (Right <$> image)
153+ <|> (Right <$> other)
154+ case res of
155+ Right v → pure v
156+ Left e → P .fail e
150157
151158 alphaNumStr ∷ P.Parser String (SD.Inline a )
152159 alphaNumStr = SD.Str <$> someOf isAlphaNum
@@ -158,7 +165,11 @@ inlines = L.many inline2 <* PS.eof
158165 (s >= " 0" && s <= " 9" )
159166 where s = S .fromChar c
160167
161- emphasis ∷ P.Parser String (SD.Inline a ) → (L.List (SD.Inline a ) → SD.Inline a ) → String → P.Parser String (SD.Inline a )
168+ emphasis
169+ ∷ P.Parser String (SD.Inline a )
170+ → (L.List (SD.Inline a ) → SD.Inline a )
171+ → String
172+ → P.Parser String (SD.Inline a )
162173 emphasis p f s = do
163174 PS .string s
164175 f <$> PC .manyTill p (PS .string s)
@@ -233,33 +244,63 @@ inlines = L.many inline2 <* PS.eof
233244 s ← (S .fromCharArray <<< L .fromList) <$> (PS .noneOf (S .toCharArray " ;" ) `PC.many1Till` PS .string " ;" )
234245 return $ SD.Entity $ " &" <> s <> " ;"
235246
236- formField ∷ P.Parser String (SD.Inline a )
247+ formField ∷ P.Parser String (Either String ( SD.Inline a ) )
237248 formField =
238- SD.FormField
239- <$> label
240- <*> (PU .skipSpaces *> required)
241- <*> (PU .skipSpaces *> PS .string " =" *> PU .skipSpaces *> formElement)
249+ do
250+ l ← label
251+ r ← do
252+ PU .skipSpaces
253+ required
254+ fe ← do
255+ PU .skipSpaces
256+ PS .string " ="
257+ PU .skipSpaces
258+ formElement
259+ pure $ map (SD.FormField l r) fe
242260 where
243- label = someOf isAlphaNum <|> (S .fromCharArray <<< L .fromList <$> (PS .string " [" *> PC .manyTill PS .anyChar (PS .string " ]" )))
261+ label =
262+ someOf isAlphaNum
263+ <|> (S .fromCharArray
264+ <<< L .fromList
265+ <$> (PS .string " [" *> PC .manyTill PS .anyChar (PS .string " ]" )))
266+
244267 required = PC .option false (PS .string " *" *> pure true )
245268
246- formElement ∷ P.Parser String (SD.FormField a )
269+ formElement ∷ P.Parser String (Either String ( SD.FormField a ) )
247270 formElement =
248271 PC .try textBox
249- <|> PC .try radioButtons
250- <|> PC .try checkBoxes
251- <|> PC .try dropDown
272+ <|> PC .try ( Right <$> radioButtons)
273+ <|> PC .try ( Right <$> checkBoxes)
274+ <|> PC .try ( Right <$> dropDown)
252275 where
253276
254- textBox ∷ P.Parser String (SD.FormField a )
277+ textBox ∷ P.Parser String (Either String ( SD.FormField a ) )
255278 textBox = do
256279 template ← parseTextBoxTemplate
257280 PU .skipSpaces
258- mdef ← PC .optionMaybe $ PU .parens $ parseTextBox (\x → x /= ' )' ) (expr id) template
259- pure $ SD.TextBox $
260- case mdef of
261- M.Nothing → SD .transTextBox (const $ Compose M.Nothing ) template
262- M.Just def → SD .transTextBox (M.Just >>> Compose ) def
281+ defVal ← PC .optionMaybe $ PS .string " ("
282+ case defVal of
283+ M.Nothing → pure $ Right $ SD.TextBox $ SD .transTextBox (const $ Compose M.Nothing ) template
284+ M.Just _ → do
285+ PU .skipSpaces
286+ mdef ← PC .optionMaybe $ PC .try $ parseTextBox (_ /= ' )' ) (expr id) template
287+ case mdef of
288+ M.Just def → do
289+ PU .skipSpaces
290+ PS .string " )"
291+ pure $ Right $ SD.TextBox $ SD .transTextBox (M.Just >>> Compose ) def
292+ M.Nothing →
293+ pure $ Left case template of
294+ SD.DateTime _ →
295+ " Incorrect datetime default value, please use \" YYYY-MM-DD HH:mm\" or \" YYYY-MM-DDTHH:mm\" format"
296+ SD.Date _ →
297+ " Incorrect date default value, please use \" YYYY-MM-DD\" format"
298+ SD.Time _ →
299+ " Incorrect time default value, please use \" HH:mm\" or \" HH:mm:ss\" format"
300+ SD.Numeric _ →
301+ " Incorrect numeric default value"
302+ SD.PlainText _ →
303+ " Incorrect default value"
263304
264305 parseTextBoxTemplate ∷ P.Parser String (SD.TextBox (Const Unit ))
265306 parseTextBoxTemplate =
@@ -372,22 +413,26 @@ parseTextBox isPlainText eta template =
372413 where
373414 parseDateTimeValue = do
374415 date ← parseDateValue
375- PU .skipSpaces
416+ ( PC .try $ void $ PS .string " T " ) <|> PU .skipSpaces
376417 time ← parseTimeValue
377418 pure { date, time }
378419
379420 parseDateValue = do
380- year ← natural
421+ year ← parseYear
381422 PU .skipSpaces *> dash *> PU .skipSpaces
382423 month ← natural
424+ when (month > 12 ) $ P .fail " Incorrect month"
383425 PU .skipSpaces *> dash *> PU .skipSpaces
384426 day ← natural
427+ when (day > 31 ) $ P .fail " Incorrect day"
385428 pure { month, day, year }
386429
387430 parseTimeValue = do
388431 hours ← natural
432+ when (hours > 23 ) $ P .fail " Incorrect hours"
389433 PU .skipSpaces *> colon *> PU .skipSpaces
390434 minutes ← natural
435+ when (minutes > 59 ) $ P .fail " Incorrect minutes"
391436 PU .skipSpaces
392437 amPm ←
393438 PC .optionMaybe $
@@ -432,6 +477,21 @@ parseTextBox isPlainText eta template =
432477 digit =
433478 PS .oneOf [' 0' ,' 1' ,' 2' ,' 3' ,' 4' ,' 5' ,' 6' ,' 7' ,' 8' ,' 9' ]
434479
480+ digitN = do
481+ ds ← digit
482+ ds
483+ # pure
484+ # S .fromCharArray
485+ # Data.Int .fromString
486+ # M .maybe (P .fail " Failed parsing digit" ) pure
487+
488+ parseYear = do
489+ millenia ← digitN
490+ centuries ← digitN
491+ decades ← digitN
492+ years ← digitN
493+ pure $ 1000 * millenia + 100 * centuries + 10 * decades + years
494+
435495 digits =
436496 L .some digit <#>
437497 L .fromList >>> S .fromCharArray
0 commit comments