{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module BNFC.Backend.Haskell.CFtoHappy (cf2Happy, convert) where
import Prelude hiding ((<>))
import Data.Foldable (toList)
import Data.List (intersperse)
import BNFC.CF
import BNFC.Backend.Common.StrUtils (escapeChars)
import BNFC.Backend.Haskell.Utils
import BNFC.Options (HappyMode(..), TokenText(..))
import BNFC.PrettyPrint
import BNFC.Utils
type Rules = [(NonTerminal,[(Pattern,Action)])]
type Pattern = String
type Action = String
type MetaVar = String
tokenName :: String
tokenName = String
"Token"
cf2Happy
:: ModuleName
-> ModuleName
-> ModuleName
-> HappyMode
-> TokenText
-> Bool
-> CF
-> String
cf2Happy :: String
-> String
-> String
-> HappyMode
-> TokenText
-> Bool
-> CF
-> String
cf2Happy String
name String
absName String
lexName HappyMode
mode TokenText
tokenText Bool
functor CF
cf = [String] -> String
unlines
[ String -> String -> String -> TokenText -> [Cat] -> String
header String
name String
absName String
lexName TokenText
tokenText [Cat]
eps
, Doc -> String
render (Doc -> String) -> Doc -> String
forall a b. (a -> b) -> a -> b
$ HappyMode -> [Cat] -> Doc
declarations HappyMode
mode [Cat]
eps
, Doc -> String
render (Doc -> String) -> Doc -> String
forall a b. (a -> b) -> a -> b
$ CF -> Doc
tokens CF
cf
, String
delimiter
, String -> TokenText -> CF -> String
specialRules String
absName TokenText
tokenText CF
cf
, Doc -> String
render (Doc -> String) -> Doc -> String
forall a b. (a -> b) -> a -> b
$ String -> Bool -> Rules -> Doc
prRules String
absName Bool
functor (String -> Bool -> CF -> Rules
rulesForHappy String
absName Bool
functor CF
cf)
, String
footer
]
where
eps :: [Cat]
eps = NonEmpty Cat -> [Cat]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (NonEmpty Cat -> [Cat]) -> NonEmpty Cat -> [Cat]
forall a b. (a -> b) -> a -> b
$ CF -> NonEmpty Cat
forall f. CFG f -> NonEmpty Cat
allEntryPoints CF
cf
header :: ModuleName -> ModuleName -> ModuleName -> TokenText -> [Cat] -> String
String
modName String
absName String
lexName TokenText
tokenText [Cat]
eps = [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
[ [ String
"-- This Happy file was machine-generated by the BNF converter"
, String
"{"
, String
"{-# OPTIONS_GHC -fno-warn-incomplete-patterns -fno-warn-overlapping-patterns #-}"
, String
"module " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
modName
, String
" ( happyError"
, String
" , myLexer"
]
, (Cat -> String) -> [Cat] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((String
" , " String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> (Cat -> String) -> Cat -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> String
render (Doc -> String) -> (Cat -> Doc) -> Cat -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Doc
parserName) [Cat]
eps
, [ String
" ) where"
, String
"import qualified " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
absName
, String
"import " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
lexName
]
, TokenText -> [String]
tokenTextImport TokenText
tokenText
, [ String
"}"
]
]
declarations :: HappyMode -> [Cat] -> Doc
declarations :: HappyMode -> [Cat] -> Doc
declarations HappyMode
mode [Cat]
ns = [Doc] -> Doc
vcat
[ [Doc] -> Doc
vcat ([Doc] -> Doc) -> [Doc] -> Doc
forall a b. (a -> b) -> a -> b
$ (Cat -> Doc) -> [Cat] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map Cat -> Doc
generateP [Cat]
ns
, case HappyMode
mode of
HappyMode
Standard -> Doc
"-- no lexer declaration"
HappyMode
GLR -> Doc
"%lexer { myLexer } { Either String _ }",
Doc
"%monad { Either String } { (>>=) } { return }",
Doc
"%tokentype" Doc -> Doc -> Doc
<+> Doc -> Doc
braces (String -> Doc
text String
tokenName)
]
where
generateP :: Cat -> Doc
generateP Cat
n = Doc
"%name" Doc -> Doc -> Doc
<+> Cat -> Doc
parserName Cat
n Doc -> Doc -> Doc
<+> String -> Doc
text (Cat -> String
identCat Cat
n)
delimiter :: String
delimiter :: String
delimiter = String
"\n%%\n"
tokens :: CF -> Doc
tokens :: CF -> Doc
tokens CF
cf
| [Doc] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Doc]
ts = Doc
empty
| Bool
otherwise = Doc
"%token" Doc -> Doc -> Doc
$$ (Int -> Doc -> Doc
nest Int
2 (Doc -> Doc) -> Doc -> Doc
forall a b. (a -> b) -> a -> b
$ [Doc] -> Doc
vcat [Doc]
ts)
where
ts :: [Doc]
ts = ((String, Int) -> Doc) -> [(String, Int)] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (String, Int) -> Doc
forall a. Show a => (String, a) -> Doc
prToken (CF -> [(String, Int)]
forall f. CFG f -> [(String, Int)]
cfTokens CF
cf) [Doc] -> [Doc] -> [Doc]
forall a. [a] -> [a] -> [a]
++ (String -> Doc) -> [String] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map String -> Doc
text (CF -> [String]
specialToks CF
cf)
prToken :: (String, a) -> Doc
prToken (String
t,a
k) = [Doc] -> Doc
hsep [ String -> Doc
convert String
t, Doc
lbrace, String -> Doc
text (String
"PT _ (TS _ " String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
k String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"), Doc
rbrace ]
convert :: String -> Doc
convert :: String -> Doc
convert = Doc -> Doc
quotes (Doc -> Doc) -> (String -> Doc) -> String -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Doc
text (String -> Doc) -> (String -> String) -> String -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
escapeChars
rulesForHappy :: ModuleName -> Bool -> CF -> Rules
rulesForHappy :: String -> Bool -> CF -> Rules
rulesForHappy String
absM Bool
functor CF
cf = [(Cat, [Rule])]
-> ((Cat, [Rule]) -> (Cat, [(String, String)])) -> Rules
forall a b. [a] -> (a -> b) -> [b]
for (CF -> [(Cat, [Rule])]
ruleGroups CF
cf) (((Cat, [Rule]) -> (Cat, [(String, String)])) -> Rules)
-> ((Cat, [Rule]) -> (Cat, [(String, String)])) -> Rules
forall a b. (a -> b) -> a -> b
$ \ (Cat
cat, [Rule]
rules) ->
(Cat
cat, (Rule -> (String, String)) -> [Rule] -> [(String, String)]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Bool -> Rule -> (String, String)
forall f. IsFun f => String -> Bool -> Rul f -> (String, String)
constructRule String
absM Bool
functor) [Rule]
rules)
constructRule :: IsFun f => String -> Bool -> Rul f -> (Pattern, Action)
constructRule :: String -> Bool -> Rul f -> (String, String)
constructRule String
absName Bool
functor (Rule f
fun0 RCat
_cat SentForm
rhs InternalRule
Parsable) = (String
pattern, String
action)
where
fun :: String
fun = f -> String
forall a. IsFun a => a -> String
funName f
fun0
(String
pattern, [String]
metavars) = SentForm -> (String, [String])
generatePatterns SentForm
rhs
action :: String
action | String -> Bool
forall a. IsFun a => a -> Bool
isCoercion String
fun = [String] -> String
unwords [String]
metavars
| String -> Bool
forall a. IsFun a => a -> Bool
isNilCons String
fun = [String] -> String
unwords (String -> String
qualify String
fun String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
metavars)
| Bool
functor = [String] -> String
unwords (String -> String
qualify String
fun String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
"()" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
metavars)
| Bool
otherwise = [String] -> String
unwords (String -> String
qualify String
fun String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
metavars)
qualify :: String -> String
qualify String
f
| String -> Bool
forall a. IsFun a => a -> Bool
isConsFun String
f Bool -> Bool -> Bool
|| String -> Bool
forall a. IsFun a => a -> Bool
isNilCons String
f = String
f
| String -> Bool
forall a. IsFun a => a -> Bool
isDefinedRule String
f = String
absName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. IsFun a => a -> String
mkDefName String
f
| Bool
otherwise = String
absName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f
constructRule String
_ Bool
_ (Rule f
_ RCat
_ SentForm
_ InternalRule
Internal) = (String, String)
forall a. HasCallStack => a
undefined
generatePatterns :: SentForm -> (Pattern, [MetaVar])
generatePatterns :: SentForm -> (String, [String])
generatePatterns [] = (String
"{- empty -}", [])
generatePatterns SentForm
its =
( [String] -> String
unwords ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ SentForm -> (Either Cat String -> String) -> [String]
forall a b. [a] -> (a -> b) -> [b]
for SentForm
its ((Either Cat String -> String) -> [String])
-> (Either Cat String -> String) -> [String]
forall a b. (a -> b) -> a -> b
$ (Cat -> String)
-> (String -> String) -> Either Cat String -> String
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Cat -> String
identCat (Doc -> String
render (Doc -> String) -> (String -> Doc) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Doc
convert)
, [ (Char
'$' Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> String
forall a. Show a => a -> String
show Int
i) | (Int
i, Left{}) <- [Int] -> SentForm -> [(Int, Either Cat String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
1 :: Int ..] SentForm
its ]
)
prRules :: ModuleName -> Bool -> Rules -> Doc
prRules :: String -> Bool -> Rules -> Doc
prRules String
absM Bool
functor = [Doc] -> Doc
vsep ([Doc] -> Doc) -> (Rules -> [Doc]) -> Rules -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Cat, [(String, String)]) -> Doc) -> Rules -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (Cat, [(String, String)]) -> Doc
prOne
where
prOne :: (Cat, [(String, String)]) -> Doc
prOne (Cat
_ , [] ) = Doc
empty
prOne (Cat
nt, (String
p,String
a):[(String, String)]
ls) =
[Doc] -> Doc
hsep [ Doc
nt', Doc
"::", Doc
"{", Cat -> Doc
type' Cat
nt, Doc
"}" ]
Doc -> Doc -> Doc
$$ Doc
nt' Doc -> Doc -> Doc
<+> [Doc] -> Doc
sep (Doc -> (String, String) -> Doc
pr Doc
":" (String
p, String
a) Doc -> [Doc] -> [Doc]
forall a. a -> [a] -> [a]
: ((String, String) -> Doc) -> [(String, String)] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (Doc -> (String, String) -> Doc
pr Doc
"|") [(String, String)]
ls)
where
nt' :: Doc
nt' = String -> Doc
text (Cat -> String
identCat Cat
nt)
pr :: Doc -> (String, String) -> Doc
pr Doc
pre (String
p,String
a) = [Doc] -> Doc
hsep [Doc
pre, String -> Doc
text String
p, Doc
"{", String -> Doc
text String
a , Doc
"}"]
type' :: Cat -> Doc
type' = (Doc -> Doc) -> Doc -> Cat -> Doc
catToType Doc -> Doc
qualify (Doc -> Cat -> Doc) -> Doc -> Cat -> Doc
forall a b. (a -> b) -> a -> b
$ if Bool
functor then Doc
"()" else Doc
empty
qualify :: Doc -> Doc
qualify
| String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
absM = Doc -> Doc
forall a. a -> a
id
| Bool
otherwise = ((String -> Doc
text String
absM Doc -> Doc -> Doc
<> Doc
".") Doc -> Doc -> Doc
<>)
footer :: String
= [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
[ String
"{"
, String
""
, String
"happyError :: [" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
tokenName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"] -> Either String a"
, String
"happyError ts = Left $"
, String
" \"syntax error at \" ++ tokenPos ts ++ "
, String
" case ts of"
, String
" [] -> []"
, String
" [Err _] -> \" due to lexer error\""
, [String] -> String
unwords
[ String
" t:_ -> \" before `\" ++"
, String
"(prToken t)"
, String
"++ \"'\""
]
, String
""
, String
"myLexer = tokens"
, String
"}"
]
specialToks :: CF -> [String]
specialToks :: CF -> [String]
specialToks CF
cf = ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
`map` CF -> [String]
forall f. CFG f -> [String]
literals CF
cf) ((String -> String) -> [String]) -> (String -> String) -> [String]
forall a b. (a -> b) -> a -> b
$ \case
String
"Ident" -> String
"L_Ident { PT _ (TV $$) }"
String
"String" -> String
"L_quoted { PT _ (TL $$) }"
String
"Integer" -> String
"L_integ { PT _ (TI $$) }"
String
"Double" -> String
"L_doubl { PT _ (TD $$) }"
String
"Char" -> String
"L_charac { PT _ (TC $$) }"
String
own -> String
"L_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" { PT _ (T_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
posn String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
") }"
where posn :: String
posn = if CF -> String -> Bool
forall f. CFG f -> String -> Bool
isPositionCat CF
cf String
own then String
"_" else String
"$$"
specialRules :: ModuleName -> TokenText -> CF -> String
specialRules :: String -> TokenText -> CF -> String
specialRules String
absName TokenText
tokenText CF
cf = [String] -> String
unlines ([String] -> String)
-> ((String -> String) -> [String]) -> (String -> String) -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
intersperse String
"" ([String] -> [String])
-> ((String -> String) -> [String])
-> (String -> String)
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
`map` CF -> [String]
forall f. CFG f -> [String]
literals CF
cf) ((String -> String) -> String) -> (String -> String) -> String
forall a b. (a -> b) -> a -> b
$ \case
String
"String" -> String
"String :: { String }"
String -> String -> String
++++ String
"String : L_quoted { " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
stringUnpack String
"$1" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" }"
String
"Integer" -> String
"Integer :: { Integer }"
String -> String -> String
++++ String
"Integer : L_integ { (read (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
stringUnpack String
"$1" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")) :: Integer }"
String
"Double" -> String
"Double :: { Double }"
String -> String -> String
++++ String
"Double : L_doubl { (read (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
stringUnpack String
"$1" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")) :: Double }"
String
"Char" -> String
"Char :: { Char }"
String -> String -> String
++++ String
"Char : L_charac { (read (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
stringUnpack String
"$1" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")) :: Char }"
String
own -> String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" :: { " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
qualify String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"}"
String -> String -> String
++++ String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" : L_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" { " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
qualify String
own String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
posn String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" }"
where posn :: String
posn = if CF -> String -> Bool
forall f. CFG f -> String -> Bool
isPositionCat CF
cf String
own then String
" (mkPosToken $1)" else String
" $1"
where
stringUnpack :: String -> String
stringUnpack = TokenText -> String -> String
tokenTextUnpack TokenText
tokenText
qualify :: String -> String
qualify
| String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
absName = String -> String
forall a. a -> a
id
| Bool
otherwise = ((String
absName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
".") String -> String -> String
forall a. [a] -> [a] -> [a]
++)