halogen-websocket-ipc-playzone/drop/PlayingWithParsers.purs

202 lines
6.9 KiB
Plaintext
Raw Normal View History

2023-07-22 15:48:00 +02:00
-- | `App.HomeInterface` presents the website and its features.
module App.HomeInterface where
2023-07-22 12:38:56 +02:00
import Prelude
2023-07-22 15:48:00 +02:00
import Control.Alt ((<|>))
import Control.Lazy (defer)
2023-07-23 14:06:09 +02:00
import Data.Array (many, length, snoc, last)
2023-07-22 15:48:00 +02:00
import Data.Either (Either(..))
import Data.Foldable (fold, foldl)
2023-07-22 15:48:00 +02:00
import Data.Maybe (Maybe(..))
import Data.Array.NonEmpty as NonEmpty
2023-07-22 14:58:52 +02:00
import Data.String.CodeUnits as CU
2023-07-23 14:06:09 +02:00
import Data.String as S -- length
2023-07-22 15:48:00 +02:00
-- import Data.String.Regex as R
-- import Data.String.Regex.Flags as RF
import Data.Tuple (Tuple(..))
2023-07-22 15:48:00 +02:00
import Effect.Aff.Class (class MonadAff)
import Effect (Effect)
import Halogen as H
import Halogen.HTML as HH
-- import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Parsing
import Parsing.Combinators as PC
import Parsing.Combinators.Array (many1)
2023-07-22 15:48:00 +02:00
import Parsing (Parser, runParser)
import Parsing.String
import Parsing.String.Basic
2023-07-22 12:38:56 +02:00
import Parsing.String.Basic (alphaNum, letter)
2023-07-22 15:48:00 +02:00
import Parsing.String (char, string, eof)
-- import TryPureScript (h1, h3, p, text, render, code)
import Bulma (h1, h3, p, text, code)
import Bulma as Bulma
type Input = Unit
data Action = UpdateStuff String
data Query a = DoNothing a
type Output = Unit
type Slot = H.Slot Query Output
type State = { stuff :: String }
component :: forall m. MonadAff m => H.Component Query Input Output m
component =
H.mkComponent
{ initialState
, render
, eval: H.mkEval $ H.defaultEval
{ handleAction = handleAction
}
}
handleAction :: forall m. MonadAff m => Action -> H.HalogenM State Action () Output m Unit
handleAction = case _ of
UpdateStuff val -> H.modify_ _ { stuff = val }
initialState :: forall input. input -> State
initialState _ = { stuff: "" }
render :: forall m. State -> H.ComponentHTML Action () m
render state
= HH.div_ $
[ Bulma.hero_danger "A simple input" "Nothing much to see"
, Bulma.section_small $
[ h1 "Examples of domain parsing in Purescript"
2023-07-23 14:06:09 +02:00
] <> test_domains [ "ex.net"
, "e-x.net"
, "way-too-long--way-too-long--way-too-long--way-too-long--way-too-long.net"
, "way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.way-too-long--way-too-long--way-too-long--way-too-long.net"
, "e-.net"
, "-x.net"
, "truc-blah.example.com"
, "te.s-t.net"
, "example.com"
]
2023-07-22 15:48:00 +02:00
, Bulma.section_small [ render_stuff ]
2023-07-23 14:06:09 +02:00
]
2023-07-22 15:48:00 +02:00
where
-- Some helpers.
title = Bulma.h3
p = Bulma.p
b x = Bulma.column_ [ Bulma.box x ]
render_stuff = Bulma.columns_ [ b [ title "stuff"
, stuff_input
]
, b [ title "result"
, p $ case runParser state.stuff parse_stuff of
Left _ -> "NOT OKAY"
Right _ -> "OKAY"
]
]
stuff_input
= Bulma.box_input "stuff" "stuff" "stuff"
UpdateStuff
state.stuff
true
should_be_disabled
should_be_disabled = (if true then (HP.enabled true) else (HP.disabled true))
-- test_domains :: Array String -> _
2023-07-23 15:36:12 +02:00
test_domains doms = map tests_on_domain doms
2023-07-23 14:06:09 +02:00
2023-07-22 15:48:00 +02:00
-- tests_on_domain :: String -> _
tests_on_domain d
2023-07-23 15:36:12 +02:00
= b [ Bulma.strong $ d <> " -> [ldhstr, label, subdomain, domain]"
, p $ d <> " : ldhstr : " <> (show $ runParser d ldhstr)
, p $ d <> " : label : " <> (show $ runParser d label)
, p $ d <> " : subdomain : " <> (show $ runParser d subdomain)
, p $ d <> " : domain : " <> (show $ runParser d domain)
]
2023-07-22 15:48:00 +02:00
aye :: Parser String Char
aye = defer \_ -> char 'a' *> aye
ayebee :: Parser String Boolean
ayebee = do
_ <- char 'a'
b <- char 'b' <|> char 'B'
pure (b == 'B')
parse_stuff :: Parser String Boolean
parse_stuff = do
void $ label
2023-07-22 15:48:00 +02:00
void $ eof
pure true
2023-07-22 12:38:56 +02:00
-- From RFC 1035: <domain> ::= <subdomain> | " "
2023-07-22 12:38:56 +02:00
domain :: Parser String String
2023-07-23 14:06:09 +02:00
domain = PC.try (string " ") <|> sub_eof
2023-07-22 14:58:52 +02:00
sub_eof :: Parser String String
sub_eof = do
2023-07-23 14:06:09 +02:00
sub <- subdomain
-- TODO: optional "." at the end?
2023-07-22 14:58:52 +02:00
eof
2023-07-23 15:36:12 +02:00
if S.length sub > 255
then fail $ "domain length is > 255 bytes (" <> show (S.length sub) <> ")"
else pure sub
2023-07-22 12:38:56 +02:00
-- From RFC 1035: <subdomain> ::= <label> | <subdomain> "." <label>
2023-07-22 12:38:56 +02:00
subdomain :: Parser String String
2023-07-23 15:36:12 +02:00
subdomain = do
-- First: read a label. This is bare minimum for a subdomain.
2023-07-22 14:58:52 +02:00
lab <- label
2023-07-23 15:36:12 +02:00
-- Second: the rest is optional. TODO
-- TODO
where
point_sub :: Parser String String
point_sub = do
point <- string "."
sub <- defer \_ -> subdomain
pure $ point <> sub
2023-07-22 12:38:56 +02:00
-- From RFC 1035: <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
2023-07-22 14:58:52 +02:00
label :: Parser String String
2023-07-23 14:06:09 +02:00
label = let_then_str_then_alpha
2023-07-22 14:58:52 +02:00
where
let_then_str_then_alpha :: Parser String String
let_then_str_then_alpha = do
l <- letter
2023-07-23 15:36:12 +02:00
s <- ldhstr
2023-07-23 14:06:09 +02:00
case last s of
Nothing -> pure $ CU.singleton l
Just last_char -> case runParser (CU.singleton last_char) alphaNum of
Left _ -> fail $ "Label is wrong: last char is '" <> (CU.singleton last_char) <> "' which isn't an alphanum"
Right _ -> if length s > 62 -- Remember: we already did read a letter (l).
then fail $ "Label is larger than expected (max 63 characters, current: " <> show (1 + length s) <> ")"
else pure $ CU.singleton l <> CU.fromCharArray (foldl (\acc x -> snoc acc x) [] s)
2023-07-22 12:38:56 +02:00
-- From RFC 1035: <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
2023-07-23 15:36:12 +02:00
ldhstr :: Parser String (Array Char)
ldhstr = many let_dig_hyp
2023-07-22 14:58:52 +02:00
-- From RFC 1035: <let-dig-hyp> ::= <let-dig> | "-"
2023-07-22 14:58:52 +02:00
-- Either a Letter, Digital or an Hyphenation character.
2023-07-22 12:38:56 +02:00
let_dig_hyp :: Parser String Char
2023-07-23 15:36:12 +02:00
let_dig_hyp = let_dig <|> char '-' -- TODO: push error
-- From RFC 1035: <let-dig> ::= <letter> | <digit>
let_dig :: Parser String Char
2023-07-23 14:06:09 +02:00
let_dig = alphaNum
2023-07-22 12:38:56 +02:00
2023-07-22 14:58:52 +02:00
-- | Converting a single letter parser to a String parser.
char_to_string :: Parser String Char -> Parser String String
char_to_string p = do
2023-07-23 15:36:12 +02:00
character <- p
pure $ CU.singleton character
2023-07-22 14:58:52 +02:00
-- Not used currently.
hyp_then_string :: Parser String String
hyp_then_string = do
a <- char_to_string let_dig_hyp
b <- ldhstr
pure $ a <> b