{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Pretty.Simple.Internal.ExprParser
where
import Text.Pretty.Simple.Internal.Expr (CommaSeparated(..), Expr(..))
import Control.Arrow (first)
import Data.Char (isAlpha, isDigit)
testString1 :: String
testString1 :: String
testString1 = String
"Just [TextInput {textInputClass = Just (Class {unClass = \"class\"}), textInputId = Just (Id {unId = \"id\"}), textInputName = Just (Name {unName = \"name\"}), textInputValue = Just (Value {unValue = \"value\"}), textInputPlaceholder = Just (Placeholder {unPlaceholder = \"placeholder\"})}, TextInput {textInputClass = Just (Class {unClass = \"class\"}), textInputId = Just (Id {unId = \"id\"}), textInputName = Just (Name {unName = \"name\"}), textInputValue = Just (Value {unValue = \"value\"}), textInputPlaceholder = Just (Placeholder {unPlaceholder = \"placeholder\"})}]"
testString2 :: String
testString2 :: String
testString2 = String
"some stuff (hello [\"dia\\x40iahello\", why wh, bye] ) (bye)"
expressionParse :: String -> [Expr]
expressionParse :: String -> [Expr]
expressionParse = ([Expr], String) -> [Expr]
forall a b. (a, b) -> a
fst (([Expr], String) -> [Expr])
-> (String -> ([Expr], String)) -> String -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ([Expr], String)
parseExprs
parseExpr :: String -> (Expr, String)
parseExpr :: String -> (Expr, String)
parseExpr (Char
'(':String
rest) = ([[Expr]] -> Expr) -> ([[Expr]], String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (CommaSeparated [Expr] -> Expr
Parens (CommaSeparated [Expr] -> Expr)
-> ([[Expr]] -> CommaSeparated [Expr]) -> [[Expr]] -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Expr]] -> CommaSeparated [Expr]
forall a. [a] -> CommaSeparated a
CommaSeparated) (([[Expr]], String) -> (Expr, String))
-> ([[Expr]], String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ Char -> String -> ([[Expr]], String)
parseCSep Char
')' String
rest
parseExpr (Char
'[':String
rest) = ([[Expr]] -> Expr) -> ([[Expr]], String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (CommaSeparated [Expr] -> Expr
Brackets (CommaSeparated [Expr] -> Expr)
-> ([[Expr]] -> CommaSeparated [Expr]) -> [[Expr]] -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Expr]] -> CommaSeparated [Expr]
forall a. [a] -> CommaSeparated a
CommaSeparated) (([[Expr]], String) -> (Expr, String))
-> ([[Expr]], String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ Char -> String -> ([[Expr]], String)
parseCSep Char
']' String
rest
parseExpr (Char
'{':String
rest) = ([[Expr]] -> Expr) -> ([[Expr]], String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (CommaSeparated [Expr] -> Expr
Braces (CommaSeparated [Expr] -> Expr)
-> ([[Expr]] -> CommaSeparated [Expr]) -> [[Expr]] -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Expr]] -> CommaSeparated [Expr]
forall a. [a] -> CommaSeparated a
CommaSeparated) (([[Expr]], String) -> (Expr, String))
-> ([[Expr]], String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ Char -> String -> ([[Expr]], String)
parseCSep Char
'}' String
rest
parseExpr (Char
'"':String
rest) = (String -> Expr) -> (String, String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first String -> Expr
StringLit ((String, String) -> (Expr, String))
-> (String, String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ String -> (String, String)
parseStringLit String
rest
parseExpr (Char
'\'':String
rest) = (String -> Expr) -> (String, String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first String -> Expr
CharLit ((String, String) -> (Expr, String))
-> (String, String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ String -> (String, String)
parseCharLit String
rest
parseExpr (Char
c:String
rest) | Char -> Bool
isDigit Char
c = (String -> Expr) -> (String, String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first String -> Expr
NumberLit ((String, String) -> (Expr, String))
-> (String, String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ Char -> String -> (String, String)
parseNumberLit Char
c String
rest
parseExpr String
other = (String -> Expr) -> (String, String) -> (Expr, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first String -> Expr
Other ((String, String) -> (Expr, String))
-> (String, String) -> (Expr, String)
forall a b. (a -> b) -> a -> b
$ String -> (String, String)
parseOther String
other
parseExprs :: String -> ([Expr], String)
parseExprs :: String -> ([Expr], String)
parseExprs [] = ([], String
"")
parseExprs s :: String
s@(Char
c:String
_)
| Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (String
")]}," :: String) = ([], String
s)
| Bool
otherwise = let (Expr
parsed, String
rest') = String -> (Expr, String)
parseExpr String
s
([Expr]
toParse, String
rest) = String -> ([Expr], String)
parseExprs String
rest'
in (Expr
parsed Expr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
: [Expr]
toParse, String
rest)
parseCSep :: Char -> String -> ([[Expr]], String)
parseCSep :: Char -> String -> ([[Expr]], String)
parseCSep Char
_ [] = ([], String
"")
parseCSep Char
end s :: String
s@(Char
c:String
cs)
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
end = ([], String
cs)
| Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (String
")]}" :: String) = ([], String
s)
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
',' = Char -> String -> ([[Expr]], String)
parseCSep Char
end String
cs
| Bool
otherwise = let ([Expr]
parsed, String
rest') = String -> ([Expr], String)
parseExprs String
s
([[Expr]]
toParse, String
rest) = Char -> String -> ([[Expr]], String)
parseCSep Char
end String
rest'
in ([Expr]
parsed [Expr] -> [[Expr]] -> [[Expr]]
forall a. a -> [a] -> [a]
: [[Expr]]
toParse, String
rest)
parseStringLit :: String -> (String, String)
parseStringLit :: String -> (String, String)
parseStringLit [] = (String
"", String
"")
parseStringLit (Char
'"':String
rest) = (String
"", String
rest)
parseStringLit (Char
'\\':Char
c:String
cs) = (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs', String
rest)
where (String
cs', String
rest) = String -> (String, String)
parseStringLit String
cs
parseStringLit (Char
c:String
cs) = (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs', String
rest)
where (String
cs', String
rest) = String -> (String, String)
parseStringLit String
cs
parseCharLit :: String -> (String, String)
parseCharLit :: String -> (String, String)
parseCharLit [] = (String
"", String
"")
parseCharLit (Char
'\'':String
rest) = (String
"", String
rest)
parseCharLit (Char
'\\':Char
c:String
cs) = (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs', String
rest)
where (String
cs', String
rest) = String -> (String, String)
parseCharLit String
cs
parseCharLit (Char
c:String
cs) = (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs', String
rest)
where (String
cs', String
rest) = String -> (String, String)
parseCharLit String
cs
parseNumberLit :: Char -> String -> (String, String)
parseNumberLit :: Char -> String -> (String, String)
parseNumberLit Char
firstDigit String
rest1 =
case String
rest2 of
[] -> (Char
firstDigitChar -> String -> String
forall a. a -> [a] -> [a]
:String
remainingDigits, String
"")
Char
'.':String
rest3 ->
let (String
digitsAfterDot, String
rest4) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
rest3
in ((Char
firstDigit Char -> String -> String
forall a. a -> [a] -> [a]
: String
remainingDigits) String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Char
'.' Char -> String -> String
forall a. a -> [a] -> [a]
: String
digitsAfterDot), String
rest4)
String
_ -> (Char
firstDigitChar -> String -> String
forall a. a -> [a] -> [a]
:String
remainingDigits, String
rest2)
where
remainingDigits :: String
rest2 :: String
(String
remainingDigits, String
rest2) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit String
rest1
parseOther :: String -> (String, String)
parseOther :: String -> (String, String)
parseOther = Bool -> String -> (String, String)
go Bool
False
where
go
:: Bool
-> String
-> (String, String)
go :: Bool -> String -> (String, String)
go Bool
_ [] = (String
"", String
"")
go Bool
insideIdent cs :: String
cs@(Char
c:String
cs')
| Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (String
"{[()]}\"," :: String) = (String
"", String
cs)
| Char -> Bool
ignoreInIdent Char
c Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
insideIdent = (String
"", String
cs)
| Bool
insideIdent = (String -> String) -> (String, String) -> (String, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
:) (Bool -> String -> (String, String)
go (Char -> Bool
isIdentRest Char
c) String
cs')
| Bool
otherwise = (String -> String) -> (String, String) -> (String, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
:) (Bool -> String -> (String, String)
go (Char -> Bool
isIdentBegin Char
c) String
cs')
isIdentBegin :: Char -> Bool
isIdentBegin :: Char -> Bool
isIdentBegin Char
'_' = Bool
True
isIdentBegin Char
c = Char -> Bool
isAlpha Char
c
isIdentRest :: Char -> Bool
isIdentRest :: Char -> Bool
isIdentRest Char
'_' = Bool
True
isIdentRest Char
'\'' = Bool
True
isIdentRest Char
c = Char -> Bool
isAlpha Char
c Bool -> Bool -> Bool
|| Char -> Bool
ignoreInIdent Char
c
ignoreInIdent :: Char -> Bool
ignoreInIdent :: Char -> Bool
ignoreInIdent Char
x = Char -> Bool
isDigit Char
x Bool -> Bool -> Bool
|| Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\''