{- BNF Converter: Named instance variables Copyright (C) 2004 Author: Michael Pellauer -} {- ************************************************************** BNF Converter Module Description : This module provides support for languages which need named instance variables. (IE Java, C, C++) It provides a data type to represent the name mapping and utility functions to work with it. Variables are grouped and numbered in a nice way. Author : Michael Pellauer (pellauer@cs.chalmers.se) ************************************************************** The idea of this module is the following (if I got it correctly): In some target languages (e.g. java or C) you need to create a variable name for each non terminal in a given rule. For instance, the following rules: > SomeFunction. A ::= B C D ; could be represented in C by a structure like: @ struct A { B b_; C c_; D d_; } @ (note that this is not exactly the representation produced by bnfc) but if there is several non terminal of the same category, we need to number them. Eg: > SomeFunction. A = B B ; Should become something like: @ struct A { B b_1, b_2; } @ This is what this module does. -} module BNFC.Backend.Common.NamedVariables where import Control.Arrow (left, (&&&)) import Data.Char (toLower) import Data.Either (lefts) import Data.List (nub) import Data.Map (Map) import Text.PrettyPrint (Doc) import qualified Text.PrettyPrint as P import BNFC.CF type IVar = (String, Int) --The type of an instance variable --and a # unique to that type type UserDef = TokenCat --user-defined types -- | A symbol-mapping environment. type SymEnv = KeywordEnv -- | Map keywords to their token name. type KeywordEnv = [(String, String)] -- | Map keywords and user-defined token types to their token name. type SymMap = Map SymKey String data SymKey = Keyword String -- ^ Keyword like "(", "while", "true", ... | Tokentype String -- ^ Token type like "Integer", "Char", ... deriving (SymKey -> SymKey -> Bool (SymKey -> SymKey -> Bool) -> (SymKey -> SymKey -> Bool) -> Eq SymKey forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a /= :: SymKey -> SymKey -> Bool $c/= :: SymKey -> SymKey -> Bool == :: SymKey -> SymKey -> Bool $c== :: SymKey -> SymKey -> Bool Eq, Eq SymKey Eq SymKey -> (SymKey -> SymKey -> Ordering) -> (SymKey -> SymKey -> Bool) -> (SymKey -> SymKey -> Bool) -> (SymKey -> SymKey -> Bool) -> (SymKey -> SymKey -> Bool) -> (SymKey -> SymKey -> SymKey) -> (SymKey -> SymKey -> SymKey) -> Ord SymKey SymKey -> SymKey -> Bool SymKey -> SymKey -> Ordering SymKey -> SymKey -> SymKey forall a. Eq a -> (a -> a -> Ordering) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> a) -> (a -> a -> a) -> Ord a min :: SymKey -> SymKey -> SymKey $cmin :: SymKey -> SymKey -> SymKey max :: SymKey -> SymKey -> SymKey $cmax :: SymKey -> SymKey -> SymKey >= :: SymKey -> SymKey -> Bool $c>= :: SymKey -> SymKey -> Bool > :: SymKey -> SymKey -> Bool $c> :: SymKey -> SymKey -> Bool <= :: SymKey -> SymKey -> Bool $c<= :: SymKey -> SymKey -> Bool < :: SymKey -> SymKey -> Bool $c< :: SymKey -> SymKey -> Bool compare :: SymKey -> SymKey -> Ordering $ccompare :: SymKey -> SymKey -> Ordering Ord, Int -> SymKey -> ShowS [SymKey] -> ShowS SymKey -> String (Int -> SymKey -> ShowS) -> (SymKey -> String) -> ([SymKey] -> ShowS) -> Show SymKey forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a showList :: [SymKey] -> ShowS $cshowList :: [SymKey] -> ShowS show :: SymKey -> String $cshow :: SymKey -> String showsPrec :: Int -> SymKey -> ShowS $cshowsPrec :: Int -> SymKey -> ShowS Show) -- | Converts a list of categories into their types to be used as instance -- variables. If a category appears only once, it is given the number 0, -- if it appears more than once, its occurrences are numbered from 1. ex: -- -- >>> getVars [Cat "A", Cat "B", Cat "A"] -- [("A",1),("B",0),("A",2)] -- getVars :: [Cat] -> [IVar] getVars :: [Cat] -> [IVar] getVars [Cat] cs = ([IVar] -> String -> [IVar]) -> [IVar] -> [String] -> [IVar] forall (t :: * -> *) b a. Foldable t => (b -> a -> b) -> b -> t a -> b foldl [IVar] -> String -> [IVar] forall {t} {t}. (Eq t, Eq t, Num t) => [(t, t)] -> t -> [(t, t)] addVar [] ((Cat -> String) -> [Cat] -> [String] forall a b. (a -> b) -> [a] -> [b] map Cat -> String identCat [Cat] cs) where addVar :: [(t, t)] -> t -> [(t, t)] addVar [(t, t)] vs = [(t, t)] -> t -> t -> [(t, t)] forall {t} {t}. (Eq t, Eq t, Num t) => [(t, t)] -> t -> t -> [(t, t)] addVar' [(t, t)] vs t 0 addVar' :: [(t, t)] -> t -> t -> [(t, t)] addVar' [] t n t c = [(t c, t n)] addVar' (i :: (t, t) i@(t t,t x):[(t, t)] is) t n t c = if t c t -> t -> Bool forall a. Eq a => a -> a -> Bool == t t then if t x t -> t -> Bool forall a. Eq a => a -> a -> Bool == t 0 then (t t, t 1) (t, t) -> [(t, t)] -> [(t, t)] forall a. a -> [a] -> [a] : [(t, t)] -> t -> t -> [(t, t)] addVar' [(t, t)] is t 2 t c else (t, t) i (t, t) -> [(t, t)] -> [(t, t)] forall a. a -> [a] -> [a] : [(t, t)] -> t -> t -> [(t, t)] addVar' [(t, t)] is (t xt -> t -> t forall a. Num a => a -> a -> a +t 1) t c else (t, t) i (t, t) -> [(t, t)] -> [(t, t)] forall a. a -> [a] -> [a] : [(t, t)] -> t -> t -> [(t, t)] addVar' [(t, t)] is t n t c -- # Create variable names for rules rhs -- This is about creating variable names for the right-hand side of rules. -- In particular, if you have a rule like Foo. Bar ::= A B A, you need to -- create unique variable names for the two instances of category A -- | Anotate the right hand side of a rule with variable names -- for the non-terminals. -- >>> numVars [Left (Cat "A"), Right "+", Left (Cat "B")] -- [Left (A,a_),Right "+",Left (B,b_)] -- >>> numVars [Left (Cat "A"), Left (Cat "A"), Right ";"] -- [Left (A,a_1),Left (A,a_2),Right ";"] numVars :: [Either Cat a] -> [Either (Cat, Doc) a] numVars :: forall a. [Either Cat a] -> [Either (Cat, Doc) a] numVars [Either Cat a] cats = -- First, we anotate each Left _ with a variable name (not univque) let withNames :: [Either (Cat, String) a] withNames = (Either Cat a -> Either (Cat, String) a) -> [Either Cat a] -> [Either (Cat, String) a] forall a b. (a -> b) -> [a] -> [b] map ((Cat -> (Cat, String)) -> Either Cat a -> Either (Cat, String) a forall (a :: * -> * -> *) b c d. ArrowChoice a => a b c -> a (Either b d) (Either c d) left (Cat -> Cat forall a. a -> a id (Cat -> Cat) -> (Cat -> String) -> Cat -> (Cat, String) forall (a :: * -> * -> *) b c c'. Arrow a => a b c -> a b c' -> a b (c, c') &&& (ShowS varName ShowS -> (Cat -> String) -> Cat -> String forall b c a. (b -> c) -> (a -> b) -> a -> c . Cat -> String identCat (Cat -> String) -> (Cat -> Cat) -> Cat -> String forall b c a. (b -> c) -> (a -> b) -> a -> c . Cat -> Cat normCat))) [Either Cat a] cats -- next, the function f' adds numbers where needed... in [IVar] -> [Either (Cat, String) a] -> [Either (Cat, Doc) a] forall {a} {b}. [IVar] -> [Either (a, String) b] -> [Either (a, Doc) b] f' [] [Either (Cat, String) a] withNames where f' :: [IVar] -> [Either (a, String) b] -> [Either (a, Doc) b] f' [IVar] _ [] = [] f' [IVar] env (Right b t:[Either (a, String) b] xs) = b -> Either (a, Doc) b forall a b. b -> Either a b Right b tEither (a, Doc) b -> [Either (a, Doc) b] -> [Either (a, Doc) b] forall a. a -> [a] -> [a] :[IVar] -> [Either (a, String) b] -> [Either (a, Doc) b] f' [IVar] env [Either (a, String) b] xs f' [IVar] env (Left (a c,String n):[Either (a, String) b] xs) = -- we should use n_i as var name let i :: Int i = Int -> (Int -> Int) -> Maybe Int -> Int forall b a. b -> (a -> b) -> Maybe a -> b maybe Int 1 (Int -> Int -> Int forall a. Num a => a -> a -> a +Int 1) (String -> [IVar] -> Maybe Int forall a b. Eq a => a -> [(a, b)] -> Maybe b lookup String n [IVar] env) -- Is there more use of the name u_ ? thereIsMore :: Bool thereIsMore = String n String -> [String] -> Bool forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool `elem` ((a, String) -> String) -> [(a, String)] -> [String] forall a b. (a -> b) -> [a] -> [b] map (a, String) -> String forall a b. (a, b) -> b snd ([Either (a, String) b] -> [(a, String)] forall a b. [Either a b] -> [a] lefts [Either (a, String) b] xs) vname :: Doc vname = String -> Doc P.text String n Doc -> Doc -> Doc P.<> if Int i Int -> Int -> Bool forall a. Ord a => a -> a -> Bool > Int 1 Bool -> Bool -> Bool || Bool thereIsMore then Int -> Doc P.int Int i else Doc P.empty in (a, Doc) -> Either (a, Doc) b forall a b. a -> Either a b Left (a c, Doc vname) Either (a, Doc) b -> [Either (a, Doc) b] -> [Either (a, Doc) b] forall a. a -> [a] -> [a] : [IVar] -> [Either (a, String) b] -> [Either (a, Doc) b] f' ((String n,Int i)IVar -> [IVar] -> [IVar] forall a. a -> [a] -> [a] :[IVar] env) [Either (a, String) b] xs --This fixes the problem with coercions. fixCoercions :: [(Cat, [Rule])] -> [(Cat, [Rule])] fixCoercions :: [(Cat, [Rule])] -> [(Cat, [Rule])] fixCoercions [(Cat, [Rule])] rs = [(Cat, [Rule])] -> [(Cat, [Rule])] forall a. Eq a => [a] -> [a] nub ([(Cat, [Rule])] -> [(Cat, [Rule])] -> [(Cat, [Rule])] fixAll [(Cat, [Rule])] rs [(Cat, [Rule])] rs) where fixCoercion :: Cat -> [(Cat, [Rule])] -> [Rule] fixCoercion :: Cat -> [(Cat, [Rule])] -> [Rule] fixCoercion Cat _ [] = [] fixCoercion Cat cat ((Cat c,[Rule] rules):[(Cat, [Rule])] cats) = if Cat -> Cat normCat Cat c Cat -> Cat -> Bool forall a. Eq a => a -> a -> Bool == Cat -> Cat normCat Cat cat then [Rule] rules [Rule] -> [Rule] -> [Rule] forall a. [a] -> [a] -> [a] ++ Cat -> [(Cat, [Rule])] -> [Rule] fixCoercion Cat cat [(Cat, [Rule])] cats else Cat -> [(Cat, [Rule])] -> [Rule] fixCoercion Cat cat [(Cat, [Rule])] cats fixAll :: [(Cat, [Rule])] -> [(Cat, [Rule])] -> [(Cat, [Rule])] fixAll :: [(Cat, [Rule])] -> [(Cat, [Rule])] -> [(Cat, [Rule])] fixAll [(Cat, [Rule])] _ [] = [] fixAll [(Cat, [Rule])] top ((Cat cat,[Rule] _):[(Cat, [Rule])] cats) = if WithPosition String -> Bool forall a. IsFun a => a -> Bool isCoercion (String -> WithPosition String forall a. a -> WithPosition a noPosition (String -> WithPosition String) -> String -> WithPosition String forall a b. (a -> b) -> a -> b $ Cat -> String catToStr Cat cat) -- This is weird: isCoercion is supposed to be applied to functions!!!! then [(Cat, [Rule])] -> [(Cat, [Rule])] -> [(Cat, [Rule])] fixAll [(Cat, [Rule])] top [(Cat, [Rule])] cats else (Cat -> Cat normCat Cat cat, Cat -> [(Cat, [Rule])] -> [Rule] fixCoercion Cat cat [(Cat, [Rule])] top) (Cat, [Rule]) -> [(Cat, [Rule])] -> [(Cat, [Rule])] forall a. a -> [a] -> [a] : [(Cat, [Rule])] -> [(Cat, [Rule])] -> [(Cat, [Rule])] fixAll [(Cat, [Rule])] top [(Cat, [Rule])] cats --A generic variable name for C-like languages. varName :: ShowS varName String c = (Char -> Char) -> ShowS forall a b. (a -> b) -> [a] -> [b] map Char -> Char toLower String c String -> ShowS forall a. [a] -> [a] -> [a] ++ String "_" --this makes var names a little cleaner. showNum :: a -> String showNum a n = if a n a -> a -> Bool forall a. Eq a => a -> a -> Bool == a 0 then String "" else a -> String forall a. Show a => a -> String show a n -- Makes the first letter a lowercase. firstLowerCase :: String -> String firstLowerCase :: ShowS firstLowerCase String "" = String "" firstLowerCase (Char a:String b) = Char -> Char toLower Char aChar -> ShowS forall a. a -> [a] -> [a] :String b