tools/pas2c.hs
changeset 7110 c91d33837b0d
parent 7075 6bd7e5ad3f2b
child 7134 beb16926ae5c
equal deleted inserted replaced
7020:846cea23aea2 7110:c91d33837b0d
    11 import Control.Monad.IO.Class
    11 import Control.Monad.IO.Class
    12 import PascalPreprocessor
    12 import PascalPreprocessor
    13 import Control.Exception
    13 import Control.Exception
    14 import System.IO.Error
    14 import System.IO.Error
    15 import qualified Data.Map as Map
    15 import qualified Data.Map as Map
       
    16 import qualified Data.Set as Set
    16 import Data.List (find)
    17 import Data.List (find)
    17 import Numeric
    18 import Numeric
    18 
    19 
    19 import PascalParser
    20 import PascalParser
    20 import PascalUnitSyntaxTree
    21 import PascalUnitSyntaxTree
    21 
    22 
    22 
    23 
    23 data InsertOption = 
    24 data InsertOption = 
    24     IOInsert
    25     IOInsert
    25     | IOLookup
    26     | IOLookup
       
    27     | IOLookupLast
       
    28     | IOLookupFunction Int
    26     | IODeferred
    29     | IODeferred
    27 
    30 
    28 type Record = (String, (String, BaseType))
    31 type Record = (String, BaseType)
       
    32 type Records = Map.Map String [Record]
    29 data RenderState = RenderState 
    33 data RenderState = RenderState 
    30     {
    34     {
    31         currentScope :: [Record],
    35         currentScope :: Records,
    32         lastIdentifier :: String,
    36         lastIdentifier :: String,
    33         lastType :: BaseType,
    37         lastType :: BaseType,
    34         stringConsts :: [(String, String)],
    38         stringConsts :: [(String, String)],
    35         uniqCounter :: Int,
    39         uniqCounter :: Int,
    36         namespaces :: Map.Map String [Record]
    40         toMangle :: Set.Set String,
       
    41         currentUnit :: String,
       
    42         namespaces :: Map.Map String Records
    37     }
    43     }
    38     
    44     
    39 emptyState = RenderState [] "" BTUnknown [] 0
    45 emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty ""
    40 
    46 
    41 getUniq :: State RenderState Int
    47 getUniq :: State RenderState Int
    42 getUniq = do
    48 getUniq = do
    43     i <- gets uniqCounter
    49     i <- gets uniqCounter
    44     modify(\s -> s{uniqCounter = uniqCounter s + 1})
    50     modify(\s -> s{uniqCounter = uniqCounter s + 1})
   113 
   119 
   114 renderCFiles :: Map.Map String PascalUnit -> IO ()
   120 renderCFiles :: Map.Map String PascalUnit -> IO ()
   115 renderCFiles units = do
   121 renderCFiles units = do
   116     let u = Map.toList units
   122     let u = Map.toList units
   117     let nss = Map.map (toNamespace nss) units
   123     let nss = Map.map (toNamespace nss) units
   118     hPutStrLn stderr $ "Units: " ++ (show . Map.keys . Map.filter (not . null) $ nss)
   124     hPutStrLn stderr $ "Units: " ++ (show . Map.keys . Map.filter (not . Map.null) $ nss)
   119     --writeFile "pas2c.log" $ unlines . map (\t -> show (fst t) ++ "\n" ++ (unlines . map ((:) '\t' . show) . snd $ t)) . Map.toList $ nss
   125     --writeFile "pas2c.log" $ unlines . map (\t -> show (fst t) ++ "\n" ++ (unlines . map ((:) '\t' . show) . snd $ t)) . Map.toList $ nss
   120     mapM_ (toCFiles nss) u
   126     mapM_ (toCFiles nss) u
   121     where
   127     where
   122     toNamespace :: Map.Map String [Record] -> PascalUnit -> [Record]
   128     toNamespace :: Map.Map String Records -> PascalUnit -> Records
   123     toNamespace nss (System tvs) = 
   129     toNamespace nss (System tvs) = 
   124         currentScope $ execState (mapM_ (tvar2C True) tvs) (emptyState nss)
   130         currentScope $ execState f (emptyState nss)
   125     toNamespace _ (Program {}) = []
   131         where
   126     toNamespace nss (Unit _ interface _ _ _) = 
   132         f = do
   127         currentScope $ execState (interface2C interface) (emptyState nss)
   133             checkDuplicateFunDecls tvs
       
   134             mapM_ (tvar2C True) tvs                
       
   135     toNamespace _ (Program {}) = Map.empty
       
   136     toNamespace nss (Unit (Identifier i _) interface _ _ _) = 
       
   137         currentScope $ execState (interface2C interface) (emptyState nss){currentUnit = map toLower i ++ "_"}
   128 
   138 
   129 
   139 
   130 withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a
   140 withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a
   131 withState' f sf = do
   141 withState' f sf = do
   132     st <- liftM f get
   142     st <- liftM f get
   140 
   150 
   141 withLastIdNamespace :: State RenderState Doc -> State RenderState Doc
   151 withLastIdNamespace :: State RenderState Doc -> State RenderState Doc
   142 withLastIdNamespace f = do
   152 withLastIdNamespace f = do
   143     li <- gets lastIdentifier
   153     li <- gets lastIdentifier
   144     nss <- gets namespaces
   154     nss <- gets namespaces
   145     withState' (\st -> st{currentScope = fromMaybe [] $ Map.lookup li (namespaces st)}) f
   155     withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f
   146 
   156 
   147 withRecordNamespace :: String -> [(String, BaseType)] -> State RenderState Doc -> State RenderState Doc
   157 withRecordNamespace :: String -> [(String, BaseType)] -> State RenderState Doc -> State RenderState Doc
   148 withRecordNamespace _ [] = error "withRecordNamespace: empty record"
   158 withRecordNamespace _ [] = error "withRecordNamespace: empty record"
   149 withRecordNamespace prefix recs = withState' f
   159 withRecordNamespace prefix recs = withState' f
   150     where
   160     where
   151         f st = st{currentScope = records ++ currentScope st}
   161         f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""}
   152         records = map (\(a, b) -> (map toLower a, (prefix ++ a, b))) recs
   162         records = Map.fromList $ map (\(a, b) -> (map toLower a, [(prefix ++ a, b)])) recs
   153 
   163         un [a] b = a : b
   154 toCFiles :: Map.Map String [Record] -> (String, PascalUnit) -> IO ()
   164 
       
   165 toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO ()
   155 toCFiles _ (_, System _) = return ()
   166 toCFiles _ (_, System _) = return ()
   156 toCFiles ns p@(fn, pu) = do
   167 toCFiles ns p@(fn, pu) = do
   157     hPutStrLn stderr $ "Rendering '" ++ fn ++ "'..."
   168     hPutStrLn stderr $ "Rendering '" ++ fn ++ "'..."
   158     toCFiles' p
   169     toCFiles' p
   159     where
   170     where
   160     toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p
   171     toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p
   161     toCFiles' (fn, (Unit unitId interface implementation _ _)) = do
   172     toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do
   162         let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState
   173         let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState{currentUnit = map toLower i ++ "_"}
   163         writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text ""))
   174         writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text ""))
   164         writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation
   175         writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation
   165     initialState = emptyState ns
   176     initialState = emptyState ns
   166 
   177 
   167     render2C :: RenderState -> State RenderState Doc -> String
   178     render2C :: RenderState -> State RenderState Doc -> String
   197     u <- uses2C uses
   208     u <- uses2C uses
   198     tv <- typesAndVars2C True tvars
   209     tv <- typesAndVars2C True tvars
   199     r <- renderStringConsts
   210     r <- renderStringConsts
   200     return (u $+$ r $+$ tv)
   211     return (u $+$ r $+$ tv)
   201 
   212 
       
   213 checkDuplicateFunDecls :: [TypeVarDeclaration] -> State RenderState ()
       
   214 checkDuplicateFunDecls tvs =
       
   215     modify $ \s -> s{toMangle = Map.keysSet . Map.filter (> 1) . foldr ins initMap $ tvs}
       
   216     where
       
   217         initMap = Map.empty
       
   218         --initMap = Map.fromList [("reset", 2)]
       
   219         ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m
       
   220         ins _ m = m
   202 
   221 
   203 typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc
   222 typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc
   204 typesAndVars2C b (TypesAndVars ts) = liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts
   223 typesAndVars2C b (TypesAndVars ts) = do
       
   224     checkDuplicateFunDecls ts
       
   225     liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts
   205 
   226 
   206 setBaseType :: BaseType -> Identifier -> Identifier
   227 setBaseType :: BaseType -> Identifier -> Identifier
   207 setBaseType bt (Identifier i _) = Identifier i bt
   228 setBaseType bt (Identifier i _) = Identifier i bt
   208 
   229 
   209 uses2C :: Uses -> State RenderState Doc
   230 uses2C :: Uses -> State RenderState Doc
   212     mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds
   233     mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds
   213     return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses
   234     return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses
   214     where
   235     where
   215     injectNamespace (Identifier i _) = do
   236     injectNamespace (Identifier i _) = do
   216         getNS <- gets (flip Map.lookup . namespaces)
   237         getNS <- gets (flip Map.lookup . namespaces)
   217         let f = flip (foldl (flip (:))) (fromMaybe [] (getNS i))
   238         modify (\s -> s{currentScope = Map.unionWith (++) (fromMaybe Map.empty (getNS i)) $ currentScope s})
   218         modify (\s -> s{currentScope = f $ currentScope s})
       
   219 
   239 
   220 uses2List :: Uses -> [String]
   240 uses2List :: Uses -> [String]
   221 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids
   241 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids
   222 
   242 
   223 
   243 
   224 id2C :: InsertOption -> Identifier -> State RenderState Doc
   244 id2C :: InsertOption -> Identifier -> State RenderState Doc
   225 id2C IOInsert (Identifier i t) = do
   245 id2C IOInsert (Identifier i t) = do
   226     ns <- gets currentScope
   246     ns <- gets currentScope
   227 {--    case t of 
   247     tom <- gets (Set.member n . toMangle)
   228         BTUnknown -> do
   248     cu <- gets currentUnit
   229             ns <- gets currentScope
   249     let i' = case (t, tom) of
   230             error $ "id2C IOInsert: type BTUnknown for " ++ show i ++ "\nnamespace: " ++ show (take 100 ns)
   250             (BTFunction p _, True) -> cu ++ i ++ ('_' : show p)
   231         _ -> do --}
   251             (BTFunction _ _, _) -> cu ++ i
   232     modify (\s -> s{currentScope = (n, (i, t)) : currentScope s, lastIdentifier = n})
   252             _ -> i
   233     return $ text i
   253     modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t)] (currentScope s), lastIdentifier = n})
       
   254     return $ text i'
   234     where
   255     where
   235         n = map toLower i
   256         n = map toLower i
   236 id2C IOLookup (Identifier i t) = do
   257 id2C IOLookup i = id2CLookup head i
       
   258 id2C IOLookupLast i = id2CLookup last i
       
   259 id2C (IOLookupFunction params) (Identifier i t) = do
   237     let i' = map toLower i
   260     let i' = map toLower i
   238     v <- gets $ find (\(a, _) -> a == i') . currentScope
   261     v <- gets $ Map.lookup i' . currentScope
   239     ns <- gets currentScope
       
   240     lt <- gets lastType
   262     lt <- gets lastType
   241     if isNothing v then 
   263     if isNothing v then 
   242         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\n" ++ show (take 100 ns)
   264         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v
   243         else 
   265         else 
   244         let vv = snd $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
   266         let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in 
       
   267             modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
       
   268     where
       
   269         checkParam (_, BTFunction p _) = p == params
       
   270         checkParam _ = False
   245 id2C IODeferred (Identifier i t) = do
   271 id2C IODeferred (Identifier i t) = do
   246     let i' = map toLower i
   272     let i' = map toLower i
   247     v <- gets $ find (\(a, _) -> a == i') . currentScope
   273     v <- gets $ Map.lookup i' . currentScope
   248     if (isNothing v) then
   274     if (isNothing v) then
   249         return $ text i
   275         modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i)
   250         else
   276         else
   251         return . text . fst . snd . fromJust $ v
   277         let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
   252 
   278 
       
   279 id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc
       
   280 id2CLookup f (Identifier i _) = do
       
   281     let i' = map toLower i
       
   282     v <- gets $ Map.lookup i' . currentScope
       
   283     lt <- gets lastType
       
   284     if isNothing v then 
       
   285         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt
       
   286         else 
       
   287         let vv = f $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
       
   288         
       
   289         
   253 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc
   290 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc
   254 id2CTyped t (Identifier i _) = do
   291 id2CTyped t (Identifier i _) = do
   255     tb <- resolveType t
   292     tb <- resolveType t
   256     ns <- gets currentScope
   293     case (t, tb) of 
   257     case tb of 
   294         (_, BTUnknown) -> do
   258         BTUnknown -> do
   295             error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t
   259             ns <- gets currentScope
   296         (SimpleType {}, BTRecord _ r) -> do
   260             error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t ++ "\nnamespace: " ++ show (take 100 ns)
   297             ts <- type2C t
   261         _ -> return ()
   298             id2C IOInsert (Identifier i (BTRecord (render $ ts empty) r))
   262     id2C IOInsert (Identifier i tb)
   299         (_, BTRecord _ r) -> do
       
   300             ts <- type2C t
       
   301             id2C IOInsert (Identifier i (BTRecord i r))
       
   302         _ -> id2C IOInsert (Identifier i tb)
       
   303     
   263 
   304 
   264 
   305 
   265 resolveType :: TypeDecl -> State RenderState BaseType
   306 resolveType :: TypeDecl -> State RenderState BaseType
   266 resolveType st@(SimpleType (Identifier i _)) = do
   307 resolveType st@(SimpleType (Identifier i _)) = do
   267     let i' = map toLower i
   308     let i' = map toLower i
   268     v <- gets $ find (\(a, _) -> a == i') . currentScope
   309     v <- gets $ Map.lookup i' . currentScope
   269     if isJust v then return . snd . snd $ fromJust v else return $ f i'
   310     if isJust v then return . snd . head $ fromJust v else return $ f i'
   270     where
   311     where
   271     f "integer" = BTInt
   312     f "integer" = BTInt
   272     f "pointer" = BTPointerTo BTVoid
   313     f "pointer" = BTPointerTo BTVoid
   273     f "boolean" = BTBool
   314     f "boolean" = BTBool
   274     f "float" = BTFloat
   315     f "float" = BTFloat
   277     f _ = error $ "Unknown system type: " ++ show st
   318     f _ = error $ "Unknown system type: " ++ show st
   278 resolveType (PointerTo (SimpleType (Identifier i _))) = return . BTPointerTo $ BTUnresolved (map toLower i)
   319 resolveType (PointerTo (SimpleType (Identifier i _))) = return . BTPointerTo $ BTUnresolved (map toLower i)
   279 resolveType (PointerTo t) = liftM BTPointerTo $ resolveType t
   320 resolveType (PointerTo t) = liftM BTPointerTo $ resolveType t
   280 resolveType (RecordType tv mtvs) = do
   321 resolveType (RecordType tv mtvs) = do
   281     tvs <- mapM f (concat $ tv : fromMaybe [] mtvs)
   322     tvs <- mapM f (concat $ tv : fromMaybe [] mtvs)
   282     return . BTRecord . concat $ tvs
   323     return . BTRecord "" . concat $ tvs
   283     where
   324     where
   284         f :: TypeVarDeclaration -> State RenderState [(String, BaseType)]
   325         f :: TypeVarDeclaration -> State RenderState [(String, BaseType)]
   285         f (VarDeclaration _ (ids, td) _) = mapM (\(Identifier i _) -> liftM ((,) i) $ resolveType td) ids
   326         f (VarDeclaration _ (ids, td) _) = mapM (\(Identifier i _) -> liftM ((,) i) $ resolveType td) ids
   286 resolveType (ArrayDecl (Just i) t) = do
   327 resolveType (ArrayDecl (Just i) t) = do
   287     t' <- resolveType t
   328     t' <- resolveType t
   288     return $ BTArray i BTInt t' 
   329     return $ BTArray i BTInt t' 
   289 resolveType (ArrayDecl Nothing t) = liftM (BTArray RangeInfinite BTInt) $ resolveType t
   330 resolveType (ArrayDecl Nothing t) = liftM (BTArray RangeInfinite BTInt) $ resolveType t
   290 resolveType (FunctionType t _) = liftM BTFunction $ resolveType t
   331 resolveType (FunctionType t a) = liftM (BTFunction (length a)) $ resolveType t
   291 resolveType (DeriveType (InitHexNumber _)) = return BTInt
   332 resolveType (DeriveType (InitHexNumber _)) = return BTInt
   292 resolveType (DeriveType (InitNumber _)) = return BTInt
   333 resolveType (DeriveType (InitNumber _)) = return BTInt
   293 resolveType (DeriveType (InitFloat _)) = return BTFloat
   334 resolveType (DeriveType (InitFloat _)) = return BTFloat
   294 resolveType (DeriveType (InitString _)) = return BTString
   335 resolveType (DeriveType (InitString _)) = return BTString
   295 resolveType (DeriveType (InitBinOp {})) = return BTInt
   336 resolveType (DeriveType (InitBinOp {})) = return BTInt
   304 resolveType (Set t) = liftM BTSet $ resolveType t
   345 resolveType (Set t) = liftM BTSet $ resolveType t
   305    
   346    
   306 
   347 
   307 resolve :: String -> BaseType -> State RenderState BaseType
   348 resolve :: String -> BaseType -> State RenderState BaseType
   308 resolve s (BTUnresolved t) = do
   349 resolve s (BTUnresolved t) = do
   309     v <- gets $ find (\(a, _) -> a == t) . currentScope
   350     v <- gets $ Map.lookup t . currentScope
   310     if isJust v then
   351     if isJust v then
   311         resolve s . snd . snd . fromJust $ v
   352         resolve s . snd . head . fromJust $ v
   312         else
   353         else
   313         error $ "Unknown type " ++ show t ++ "\n" ++ s
   354         error $ "Unknown type " ++ show t ++ "\n" ++ s
   314 resolve _ t = return t
   355 resolve _ t = return t
   315 
   356 
   316 fromPointer :: String -> BaseType -> State RenderState BaseType
   357 fromPointer :: String -> BaseType -> State RenderState BaseType
   317 fromPointer s (BTPointerTo t) = resolve s t
   358 fromPointer s (BTPointerTo t) = resolve s t
   318 fromPointer s (BTFunctionReturn _ (BTPointerTo t)) = resolve s t
       
   319 fromPointer s t = do
   359 fromPointer s t = do
   320     ns <- gets currentScope
   360     error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s
   321     error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s ++ "\n\n" ++ show (take 100 ns)
       
   322 
   361 
   323     
   362     
   324 functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False) params
   363 functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False) params
       
   364 
       
   365 numberOfDeclarations :: [TypeVarDeclaration] -> Int
       
   366 numberOfDeclarations = sum . map cnt
       
   367     where
       
   368         cnt (VarDeclaration _ (ids, _) _) = length ids
       
   369         cnt _ = 1
   325 
   370 
   326 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc]
   371 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc]
   327 fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do
   372 fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do
   328     t <- type2C returnType 
   373     t <- type2C returnType 
   329     t'<- gets lastType
   374     t'<- gets lastType
   330     p <- withState' id $ functionParams2C params
   375     p <- withState' id $ functionParams2C params
   331     n <- id2C IOInsert $ setBaseType (BTFunction t') name
   376     n <- id2C IOInsert $ setBaseType (BTFunction (numberOfDeclarations params) t') name
   332     return [t empty <+> n <> parens p]
   377     return [t empty <+> n <> parens p]
   333     
   378     
   334 fun2C True rv (FunctionDeclaration name returnType params (Just (tvars, phrase))) = do
   379 fun2C True rv (FunctionDeclaration name returnType params (Just (tvars, phrase))) = do
   335     let res = docToLower $ text rv <> text "_result"
   380     let res = docToLower $ text rv <> text "_result"
   336     t <- type2C returnType
   381     t <- type2C returnType
   337     t'<- gets lastType
   382     t'<- gets lastType
   338     n <- id2C IOInsert $ setBaseType (BTFunction t') name
   383     n <- id2C IOInsert $ setBaseType (BTFunction (numberOfDeclarations params) t') name
   339     (p, ph) <- withState' (\st -> st{currentScope = (map toLower rv, (render res, BTFunctionReturn (render n) t')) : currentScope st}) $ do
   384     (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st}) $ do
   340         p <- functionParams2C params
   385         p <- functionParams2C params
   341         ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase)
   386         ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase)
   342         return (p, ph)
   387         return (p, ph)
   343     let phrasesBlock = case returnType of
   388     let phrasesBlock = case returnType of
   344             VoidType -> ph
   389             VoidType -> ph
   352         $+$
   397         $+$
   353         text "}"]
   398         text "}"]
   354     where
   399     where
   355     phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p
   400     phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p
   356     phrase2C' p = phrase2C p
   401     phrase2C' p = phrase2C p
       
   402     un [a] b = a : b
   357     
   403     
   358 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name
   404 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name
   359 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv
   405 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv
   360 
   406 
   361 tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc]
   407 tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc]
   362 tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) =
   408 tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) =
   363     fun2C b name f
   409     fun2C b name f
   364 tvar2C _ td@(TypeDeclaration i' t) = do
   410 tvar2C _ td@(TypeDeclaration i' t) = do
   365     i <- id2CTyped t i'
   411     i <- id2CTyped t i'
   366     tp <- case t of
   412     tp <- type2C t
   367         FunctionType {} -> type2C (PointerTo t)
       
   368         _ -> type2C t
       
   369     return [text "typedef" <+> tp i]
   413     return [text "typedef" <+> tp i]
   370     
   414     
   371 tvar2C _ (VarDeclaration isConst (ids, t) mInitExpr) = do
   415 tvar2C _ (VarDeclaration isConst (ids, t) mInitExpr) = do
   372     t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t
   416     t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t
   373     ie <- initExpr mInitExpr
   417     ie <- initExpr mInitExpr
   378              return [text "enum" <> braces (i' <+> ie)]
   422              return [text "enum" <> braces (i' <+> ie)]
   379          (True, BTFloat, [i], Just e) -> do
   423          (True, BTFloat, [i], Just e) -> do
   380              i' <- id2CTyped t i
   424              i' <- id2CTyped t i
   381              ie <- initExpr2C e
   425              ie <- initExpr2C e
   382              return [text "#define" <+> i' <+> parens ie <> text "\n"]
   426              return [text "#define" <+> i' <+> parens ie <> text "\n"]
       
   427          (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' $ text "*" <+> i)) $ mapM (id2CTyped t) ids
   383          _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids
   428          _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids
   384     where
   429     where
   385     initExpr Nothing = return $ empty
   430     initExpr Nothing = return $ empty
   386     initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e)
   431     initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e)
   387     
   432     
   392     
   437     
   393 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier
   438 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier
   394 op2CTyped op t = do
   439 op2CTyped op t = do
   395     t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t
   440     t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t
   396     bt <- gets lastType
   441     bt <- gets lastType
   397     return $ case bt of
   442     return $ Identifier (t' ++ "_op_" ++ opStr) bt
   398          BTRecord {} -> Identifier (t' ++ "_op_" ++ opStr) bt
       
   399          _ -> Identifier t' bt
       
   400     where 
   443     where 
   401     opStr = case op of
   444     opStr = case op of
   402                     "+" -> "add"
   445                     "+" -> "add"
   403                     "-" -> "sub"
   446                     "-" -> "sub"
   404                     "*" -> "mul"
   447                     "*" -> "mul"
   405                     "/" -> "div"
   448                     "/" -> "div"
   406                     "=" -> "eq"
   449                     "=" -> "eq"
   407                     "<" -> "lt"
   450                     "<" -> "lt"
   408                     ">" -> "gt"
   451                     ">" -> "gt"
       
   452                     "<>" -> "neq"
   409                     _ -> error $ "op2CTyped: unknown op '" ++ op ++ "'"
   453                     _ -> error $ "op2CTyped: unknown op '" ++ op ++ "'"
   410     
   454     
   411 extractTypes :: [TypeVarDeclaration] -> [TypeDecl]
   455 extractTypes :: [TypeVarDeclaration] -> [TypeDecl]
   412 extractTypes = concatMap f
   456 extractTypes = concatMap f
   413     where
   457     where
   414         f (VarDeclaration _ (ids, t) _) = replicate (length ids) t
   458         f (VarDeclaration _ (ids, t) _) = replicate (length ids) t
   415         f a = error $ "extractTypes: can't extract from " ++ show a
   459         f a = error $ "extractTypes: can't extract from " ++ show a
   416 
   460 
   417 initExpr2C :: InitExpression -> State RenderState Doc
   461 initExpr2C, initExpr2C' :: InitExpression -> State RenderState Doc
   418 initExpr2C InitNull = return $ text "NULL"
   462 initExpr2C (InitArray values) = liftM (braces . vcat . punctuate comma) $ mapM initExpr2C values
   419 initExpr2C (InitAddress expr) = liftM ((<>) (text "&")) (initExpr2C expr)
   463 initExpr2C a = initExpr2C' a
   420 initExpr2C (InitPrefixOp op expr) = liftM (text (op2C op) <>) (initExpr2C expr)
   464 initExpr2C' InitNull = return $ text "NULL"
   421 initExpr2C (InitBinOp op expr1 expr2) = do
   465 initExpr2C' (InitAddress expr) = liftM ((<>) (text "&")) (initExpr2C' expr)
   422     e1 <- initExpr2C expr1
   466 initExpr2C' (InitPrefixOp op expr) = liftM (text (op2C op) <>) (initExpr2C' expr)
   423     e2 <- initExpr2C expr2
   467 initExpr2C' (InitBinOp op expr1 expr2) = do
       
   468     e1 <- initExpr2C' expr1
       
   469     e2 <- initExpr2C' expr2
   424     return $ parens $ e1 <+> text (op2C op) <+> e2
   470     return $ parens $ e1 <+> text (op2C op) <+> e2
   425 initExpr2C (InitNumber s) = return $ text s
   471 initExpr2C' (InitNumber s) = return $ text s
   426 initExpr2C (InitFloat s) = return $ text s
   472 initExpr2C' (InitFloat s) = return $ text s
   427 initExpr2C (InitHexNumber s) = return $ text "0x" <> (text . map toLower $ s)
   473 initExpr2C' (InitHexNumber s) = return $ text "0x" <> (text . map toLower $ s)
   428 initExpr2C (InitString [a]) = return . quotes $ text [a]
   474 initExpr2C' (InitString [a]) = return . quotes $ text [a]
   429 initExpr2C (InitString s) = return $ strInit s
   475 initExpr2C' (InitString s) = return $ strInit s
   430 initExpr2C (InitChar a) = return $ quotes $ text "\\x" <> text (showHex (read a) "")
   476 initExpr2C' (InitChar a) = return $ quotes $ text "\\x" <> text (showHex (read a) "")
   431 initExpr2C (InitReference i) = id2C IOLookup i
   477 initExpr2C' (InitReference i) = id2C IOLookup i
   432 initExpr2C (InitRecord fields) = do
   478 initExpr2C' (InitRecord fields) = do
   433     (fs :: [Doc]) <- mapM (\(Identifier a _, b) -> liftM (text "." <> text a <+> equals <+>) $ initExpr2C b) fields
   479     (fs :: [Doc]) <- mapM (\(Identifier a _, b) -> liftM (text "." <> text a <+> equals <+>) $ initExpr2C b) fields
   434     return $ lbrace $+$ (nest 4 . vcat . punctuate comma $ fs) $+$ rbrace
   480     return $ lbrace $+$ (nest 4 . vcat . punctuate comma $ fs) $+$ rbrace
   435 initExpr2C (InitArray [value]) = initExpr2C value
   481 initExpr2C' (InitArray [value]) = initExpr2C value
   436 initExpr2C (InitArray values) = liftM (braces . vcat . punctuate comma) $ mapM initExpr2C values
   482 initExpr2C' r@(InitRange (Range i@(Identifier i' _))) = do
   437 initExpr2C r@(InitRange (Range i@(Identifier i' _))) = do
       
   438     id2C IOLookup i
   483     id2C IOLookup i
   439     t <- gets lastType
   484     t <- gets lastType
   440     case t of
   485     case t of
   441          BTEnum s -> return . int $ length s
   486          BTEnum s -> return . int $ length s
   442          BTInt -> case i' of
   487          BTInt -> case i' of
   443                        "byte" -> return $ int 256
   488                        "byte" -> return $ int 256
   444                        _ -> error $ "InitRange identifier: " ++ i'
   489                        _ -> error $ "InitRange identifier: " ++ i'
   445          _ -> error $ "InitRange: " ++ show r
   490          _ -> error $ "InitRange: " ++ show r
   446 initExpr2C (InitRange (RangeFromTo (InitNumber "0") r)) = initExpr2C $ BuiltInFunction "succ" [r]
   491 initExpr2C' (InitRange (RangeFromTo (InitNumber "0") r)) = initExpr2C $ BuiltInFunction "succ" [r]
   447 initExpr2C (InitRange (RangeFromTo (InitChar "0") (InitChar r))) = initExpr2C $ BuiltInFunction "succ" [InitNumber r]
   492 initExpr2C' (InitRange (RangeFromTo (InitChar "0") (InitChar r))) = initExpr2C $ BuiltInFunction "succ" [InitNumber r]
   448 initExpr2C (InitRange a) = error $ show a --return $ text "<<range>>"
   493 initExpr2C' (InitRange a) = error $ show a --return $ text "<<range>>"
   449 initExpr2C (InitSet []) = return $ text "0"
   494 initExpr2C' (InitSet []) = return $ text "0"
   450 initExpr2C (InitSet a) = return $ text "<<set>>"
   495 initExpr2C' (InitSet a) = return $ text "<<set>>"
   451 initExpr2C (BuiltInFunction "low" [InitReference e]) = return $ 
   496 initExpr2C' (BuiltInFunction "low" [InitReference e]) = return $ 
   452     case e of
   497     case e of
   453          (Identifier "LongInt" _) -> int (-2^31)
   498          (Identifier "LongInt" _) -> int (-2^31)
   454          (Identifier "SmallInt" _) -> int (-2^15)
   499          (Identifier "SmallInt" _) -> int (-2^15)
   455          _ -> error $ "BuiltInFunction 'low': " ++ show e
   500          _ -> error $ "BuiltInFunction 'low': " ++ show e
   456 initExpr2C (BuiltInFunction "high" [e]) = do
   501 initExpr2C' (BuiltInFunction "high" [e]) = do
   457     initExpr2C e
   502     initExpr2C e
   458     t <- gets lastType
   503     t <- gets lastType
   459     case t of
   504     case t of
   460          (BTArray i _ _) -> initExpr2C $ BuiltInFunction "pred" [InitRange i]
   505          (BTArray i _ _) -> initExpr2C' $ BuiltInFunction "pred" [InitRange i]
   461          a -> error $ "BuiltInFunction 'high': " ++ show a
   506          a -> error $ "BuiltInFunction 'high': " ++ show a
   462 initExpr2C (BuiltInFunction "succ" [BuiltInFunction "pred" [e]]) = initExpr2C e
   507 initExpr2C' (BuiltInFunction "succ" [BuiltInFunction "pred" [e]]) = initExpr2C' e
   463 initExpr2C (BuiltInFunction "pred" [BuiltInFunction "succ" [e]]) = initExpr2C e
   508 initExpr2C' (BuiltInFunction "pred" [BuiltInFunction "succ" [e]]) = initExpr2C' e
   464 initExpr2C (BuiltInFunction "succ" [e]) = liftM (<> text " + 1") $ initExpr2C e
   509 initExpr2C' (BuiltInFunction "succ" [e]) = liftM (<> text " + 1") $ initExpr2C' e
   465 initExpr2C (BuiltInFunction "pred" [e]) = liftM (<> text " - 1") $ initExpr2C e
   510 initExpr2C' (BuiltInFunction "pred" [e]) = liftM (<> text " - 1") $ initExpr2C' e
   466 initExpr2C b@(BuiltInFunction _ _) = error $ show b    
   511 initExpr2C' b@(BuiltInFunction _ _) = error $ show b    
   467 initExpr2C a = error $ "initExpr2C: don't know how to render " ++ show a
   512 initExpr2C' a = error $ "initExpr2C: don't know how to render " ++ show a
   468 
   513 
   469 
   514 
   470 range2C :: InitExpression -> State RenderState [Doc]
   515 range2C :: InitExpression -> State RenderState [Doc]
   471 range2C (InitString [a]) = return [quotes $ text [a]]
   516 range2C (InitString [a]) = return [quotes $ text [a]]
   472 range2C (InitRange (Range i)) = liftM (flip (:) []) $ id2C IOLookup i
   517 range2C (InitRange (Range i)) = liftM (flip (:) []) $ id2C IOLookup i
   487     modify (\st -> st{lastType = rt})
   532     modify (\st -> st{lastType = rt})
   488     return r
   533     return r
   489     where
   534     where
   490     type2C' VoidType = return (text "void" <+>)
   535     type2C' VoidType = return (text "void" <+>)
   491     type2C' (String l) = return (text "string255" <+>)--return (text ("string" ++ show l) <+>)
   536     type2C' (String l) = return (text "string255" <+>)--return (text ("string" ++ show l) <+>)
   492     type2C' (PointerTo (SimpleType i)) = liftM (\i a -> text "struct __" <> i <+> text "*" <+> a) $ id2C IODeferred i
   537     type2C' (PointerTo (SimpleType i)) = do
       
   538         i' <- id2C IODeferred i
       
   539         lt <- gets lastType
       
   540         case lt of
       
   541              BTRecord _ _ -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
       
   542              BTUnknown -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
       
   543              _ -> return $ \a -> i' <+> text "*" <+> a
   493     type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t
   544     type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t
   494     type2C' (RecordType tvs union) = do
   545     type2C' (RecordType tvs union) = do
   495         t <- withState' id $ mapM (tvar2C False) tvs
   546         t <- withState' f $ mapM (tvar2C False) tvs
   496         u <- unions
   547         u <- unions
   497         return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i
   548         return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i
   498         where
   549         where
       
   550             f s = s{currentUnit = ""}
   499             unions = case union of
   551             unions = case union of
   500                      Nothing -> return empty
   552                      Nothing -> return empty
   501                      Just a -> do
   553                      Just a -> do
   502                          structs <- mapM struct2C a
   554                          structs <- mapM struct2C a
   503                          return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi
   555                          return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi
   504             struct2C tvs = do
   556             struct2C tvs = do
   505                 t <- withState' id $ mapM (tvar2C False) tvs
   557                 t <- withState' f $ mapM (tvar2C False) tvs
   506                 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi
   558                 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi
   507     type2C' (RangeType r) = return (text "int" <+>)
   559     type2C' (RangeType r) = return (text "int" <+>)
   508     type2C' (Sequence ids) = do
   560     type2C' (Sequence ids) = do
   509         is <- mapM (id2C IOInsert . setBaseType bt) ids
   561         is <- mapM (id2C IOInsert . setBaseType bt) ids
   510         return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [1..]) <+>)
   562         return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [0..]) <+>)
   511         where
   563         where
   512             bt = BTEnum $ map (\(Identifier i _) -> map toLower i) ids
   564             bt = BTEnum $ map (\(Identifier i _) -> map toLower i) ids
   513     type2C' (ArrayDecl Nothing t) = type2C (PointerTo t)
   565     type2C' (ArrayDecl Nothing t) = type2C (PointerTo t)
   514     type2C' (ArrayDecl (Just r) t) = do
   566     type2C' (ArrayDecl (Just r) t) = do
   515         t' <- type2C t
   567         t' <- type2C t
       
   568         lt <- gets lastType
       
   569         ft <- case lt of
       
   570                 BTFunction {} -> type2C (PointerTo t)
       
   571                 _ -> return t'
   516         r' <- initExpr2C (InitRange r)
   572         r' <- initExpr2C (InitRange r)
   517         return $ \i -> t' i <> brackets r'
   573         return $ \i -> ft i <> brackets r'
   518     type2C' (Set t) = return (text "<<set>>" <+>)
   574     type2C' (Set t) = return (text "<<set>>" <+>)
   519     type2C' (FunctionType returnType params) = do
   575     type2C' (FunctionType returnType params) = do
   520         t <- type2C returnType
   576         t <- type2C returnType
   521         p <- withState' id $ functionParams2C params
   577         p <- withState' id $ functionParams2C params
   522         return (\i -> t empty <+> i <> parens p)
   578         return (\i -> t empty <+> i <> parens p)
   553     elsePart | isNothing mphrase2 = return $ empty
   609     elsePart | isNothing mphrase2 = return $ empty
   554              | otherwise = liftM (text "else" $$) $ (phrase2C . wrapPhrase) (fromJust mphrase2)
   610              | otherwise = liftM (text "else" $$) $ (phrase2C . wrapPhrase) (fromJust mphrase2)
   555 phrase2C (Assignment ref expr) = do
   611 phrase2C (Assignment ref expr) = do
   556     r <- ref2C ref
   612     r <- ref2C ref
   557     t <- gets lastType
   613     t <- gets lastType
   558     e <- case (t, expr) of
   614     case (t, expr) of
   559          (BTFunction _, (Reference r')) -> ref2C r'
   615         (BTFunction {}, (Reference r')) -> do
   560          _ -> expr2C expr
   616             e <- ref2C r'
   561     return $ r <+> text "=" <+> e <> semi
   617             return $ r <+> text "=" <+> e <> semi
       
   618         (BTArray (Range _) _ _, _) -> phrase2C $ 
       
   619             ProcCall (FunCall
       
   620                 [
       
   621                 Reference $ Address ref
       
   622                 , Reference $ Address $ RefExpression expr
       
   623                 , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown))
       
   624                 ]
       
   625                 (SimpleReference (Identifier "memcpy" BTUnknown))
       
   626                 ) []
       
   627         _ -> do
       
   628             e <- expr2C expr
       
   629             return $ r <+> text "=" <+> e <> semi
   562 phrase2C (WhileCycle expr phrase) = do
   630 phrase2C (WhileCycle expr phrase) = do
   563     e <- expr2C expr
   631     e <- expr2C expr
   564     p <- phrase2C $ wrapPhrase phrase
   632     p <- phrase2C $ wrapPhrase phrase
   565     return $ text "while" <> parens e $$ p
   633     return $ text "while" <> parens e $$ p
   566 phrase2C (SwitchCase expr cases mphrase) = do
   634 phrase2C (SwitchCase expr cases mphrase) = do
   583                                          
   651                                          
   584 phrase2C wb@(WithBlock ref p) = do
   652 phrase2C wb@(WithBlock ref p) = do
   585     r <- ref2C ref 
   653     r <- ref2C ref 
   586     t <- gets lastType
   654     t <- gets lastType
   587     case t of
   655     case t of
   588         (BTRecord rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p
   656         (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p
   589         a -> do
   657         a -> do
   590             ns <- gets currentScope
   658             error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb
   591             error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb ++ "\nnamespace: " ++ show (take 100 ns)
       
   592 phrase2C (ForCycle i' e1' e2' p) = do
   659 phrase2C (ForCycle i' e1' e2' p) = do
   593     i <- id2C IOLookup i'
   660     i <- id2C IOLookup i'
   594     e1 <- expr2C e1'
   661     e1 <- expr2C e1'
   595     e2 <- expr2C e2'
   662     e2 <- expr2C e2'
   596     ph <- phrase2C (wrapPhrase p)
   663     ph <- phrase2C (wrapPhrase p)
   603     p <- phrase2C (Phrases p')
   670     p <- phrase2C (Phrases p')
   604     return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi
   671     return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi
   605 phrase2C NOP = return $ text ";"
   672 phrase2C NOP = return $ text ";"
   606 
   673 
   607 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "exit" BTUnknown))) = return $ text "return" <> semi
   674 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "exit" BTUnknown))) = return $ text "return" <> semi
   608 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "exit" BTUnknown))) = liftM (\e -> text "return" <> e <> semi) $ expr2C e
   675 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "break" BTUnknown))) = return $ text "break" <> semi
       
   676 phrase2C (BuiltInFunctionCall [] (SimpleReference (Identifier "continue" BTUnknown))) = return $ text "continue" <> semi
       
   677 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "exit" BTUnknown))) = liftM (\e -> text "return" <+> e <> semi) $ expr2C e
   609 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "dec" BTUnknown))) = liftM (\e -> text "--" <> e <> semi) $ expr2C e
   678 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "dec" BTUnknown))) = liftM (\e -> text "--" <> e <> semi) $ expr2C e
   610 phrase2C (BuiltInFunctionCall [e1, e2] (SimpleReference (Identifier "dec" BTUnknown))) = liftM2 (\a b -> a <> text " -= " <> b <> semi) (expr2C e1) (expr2C e2)
   679 phrase2C (BuiltInFunctionCall [e1, e2] (SimpleReference (Identifier "dec" BTUnknown))) = liftM2 (\a b -> a <> text " -= " <> b <> semi) (expr2C e1) (expr2C e2)
   611 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "inc" BTUnknown))) = liftM (\e -> text "++" <> e <> semi) $ expr2C e
   680 phrase2C (BuiltInFunctionCall [e] (SimpleReference (Identifier "inc" BTUnknown))) = liftM (\e -> text "++" <> e <> semi) $ expr2C e
   612 phrase2C (BuiltInFunctionCall [e1, e2] (SimpleReference (Identifier "inc" BTUnknown))) = liftM2 (\a b -> a <+> text "+=" <+> b <> semi) (expr2C e1) (expr2C e2)
   681 phrase2C (BuiltInFunctionCall [e1, e2] (SimpleReference (Identifier "inc" BTUnknown))) = liftM2 (\a b -> a <+> text "+=" <+> b <> semi) (expr2C e1) (expr2C e2)
   613 phrase2C a = error $ "phrase2C: " ++ show a
   682 phrase2C a = error $ "phrase2C: " ++ show a
   615 wrapPhrase p@(Phrases _) = p
   684 wrapPhrase p@(Phrases _) = p
   616 wrapPhrase p = Phrases [p]
   685 wrapPhrase p = Phrases [p]
   617 
   686 
   618 expr2C :: Expression -> State RenderState Doc
   687 expr2C :: Expression -> State RenderState Doc
   619 expr2C (Expression s) = return $ text s
   688 expr2C (Expression s) = return $ text s
   620 expr2C (BinOp op expr1 expr2) = do
   689 expr2C b@(BinOp op expr1 expr2) = do
   621     e1 <- expr2C expr1
   690     e1 <- expr2C expr1
   622     t1 <- gets lastType
   691     t1 <- gets lastType
   623     e2 <- expr2C expr2
   692     e2 <- expr2C expr2
   624     t2 <- gets lastType
   693     t2 <- gets lastType
   625     case (op2C op, t1, t2) of
   694     case (op2C op, t1, t2) of
   626         ("+", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strconcat" (BTFunction BTString))
   695         ("+", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strconcat" (BTFunction 2 BTString))
   627         ("+", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strappend" (BTFunction BTString))
   696         ("+", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strappend" (BTFunction 2 BTString))
   628         ("+", BTChar, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strprepend" (BTFunction BTString))
   697         ("+", BTChar, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strprepend" (BTFunction 2 BTString))
   629         ("==", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcompare" (BTFunction BTBool))
   698         ("==", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcomparec" (BTFunction 2 BTBool))
   630         ("!=", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strncompare" (BTFunction BTBool))
   699         ("==", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcompare" (BTFunction 2 BTBool))
       
   700         ("!=", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strncompare" (BTFunction 2 BTBool))
   631         ("&", BTBool, _) -> return $ parens e1 <+> text "&&" <+> parens e2
   701         ("&", BTBool, _) -> return $ parens e1 <+> text "&&" <+> parens e2
   632         ("|", BTBool, _) -> return $ parens e1 <+> text "||" <+> parens e2
   702         ("|", BTBool, _) -> return $ parens e1 <+> text "||" <+> parens e2
       
   703         (_, BTRecord t1 _, BTRecord t2 _) -> do
       
   704             i <- op2CTyped op [SimpleType (Identifier t1 undefined), SimpleType (Identifier t2 undefined)]
       
   705             ref2C $ FunCall [expr1, expr2] (SimpleReference i)
       
   706         (_, BTRecord t1 _, BTInt) -> do
       
   707             -- aw, "LongInt" here is hwengine-specific hack
       
   708             i <- op2CTyped op [SimpleType (Identifier t1 undefined), SimpleType (Identifier "LongInt" undefined)]
       
   709             ref2C $ FunCall [expr1, expr2] (SimpleReference i)
       
   710         ("in", _, _) -> 
       
   711             case expr2 of
       
   712                  SetExpression set -> do
       
   713                      ids <- mapM (id2C IOLookup) set
       
   714                      return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids
       
   715                  _ -> error "'in' against not set expression"
   633         (o, _, _) | o `elem` boolOps -> do
   716         (o, _, _) | o `elem` boolOps -> do
   634                         modify(\s -> s{lastType = BTBool})
   717                         modify(\s -> s{lastType = BTBool})
   635                         return $ parens e1 <+> text o <+> parens e2
   718                         return $ parens e1 <+> text o <+> parens e2
   636                   | otherwise -> return $ parens e1 <+> text o <+> parens e2
   719                   | otherwise -> return $ parens e1 <+> text o <+> parens e2
   637     where
   720     where
   638         boolOps = ["==", "!=", "<", ">", "<=", ">="]
   721         boolOps = ["==", "!=", "<", ">", "<=", ">="]
   639 expr2C (NumberLiteral s) = return $ text s
   722 expr2C (NumberLiteral s) = do
       
   723     modify(\s -> s{lastType = BTInt})
       
   724     return $ text s
   640 expr2C (FloatLiteral s) = return $ text s
   725 expr2C (FloatLiteral s) = return $ text s
   641 expr2C (HexNumber s) = return $ text "0x" <> (text . map toLower $ s)
   726 expr2C (HexNumber s) = return $ text "0x" <> (text . map toLower $ s)
   642 expr2C (StringLiteral [a]) = do
   727 {-expr2C (StringLiteral [a]) = do
   643     modify(\s -> s{lastType = BTChar})
   728     modify(\s -> s{lastType = BTChar})
   644     return . quotes $ text [a]
   729     return . quotes . text $ escape a
       
   730     where
       
   731         escape '\'' = "\\\'"
       
   732         escape a = [a]-}
   645 expr2C (StringLiteral s) = addStringConst s
   733 expr2C (StringLiteral s) = addStringConst s
       
   734 expr2C (PCharLiteral s) = return . doubleQuotes $ text s
   646 expr2C (Reference ref) = ref2CF ref
   735 expr2C (Reference ref) = ref2CF ref
   647 expr2C (PrefixOp op expr) = liftM (text (op2C op) <>) (expr2C expr)
   736 expr2C (PrefixOp op expr) = do
       
   737     e <- expr2C expr
       
   738     lt <- gets lastType
       
   739     case lt of
       
   740         BTRecord t _ -> do
       
   741             i <- op2CTyped op [SimpleType (Identifier t undefined)]
       
   742             ref2C $ FunCall [expr] (SimpleReference i)
       
   743         _ -> return $ text (op2C op) <> e
   648 expr2C Null = return $ text "NULL"
   744 expr2C Null = return $ text "NULL"
   649 expr2C (CharCode a) = do
   745 expr2C (CharCode a) = do
   650     modify(\s -> s{lastType = BTChar})
   746     modify(\s -> s{lastType = BTChar})
   651     return $ quotes $ text "\\x" <> text (showHex (read a) "")
   747     return $ quotes $ text "\\x" <> text (showHex (read a) "")
   652 expr2C (HexCharCode a) = return $ quotes $ text "\\x" <> text (map toLower a)
   748 expr2C (HexCharCode a) = if length a <= 2 then return $ quotes $ text "\\x" <> text (map toLower a) else expr2C $ HexNumber a
   653 expr2C (SetExpression ids) = mapM (id2C IOLookup) ids >>= return . parens . hcat . punctuate (text " | ")
   749 expr2C (SetExpression ids) = mapM (id2C IOLookup) ids >>= return . parens . hcat . punctuate (text " | ")
   654 
   750 
       
   751 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "low" _))) = do
       
   752     e' <- liftM (map toLower . render) $ expr2C e
       
   753     lt <- gets lastType
       
   754     case lt of
       
   755          BTEnum a -> return $ int 0
       
   756          BTInt -> case e' of
       
   757                   "longint" -> return $ int (-2147483648)
       
   758          BTArray {} -> return $ int 0
       
   759          _ -> error $ "BuiltInFunCall 'low' from " ++ show e ++ "\ntype: " ++ show lt
       
   760 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "high" _))) = do
       
   761     e' <- liftM (map toLower . render) $ expr2C e
       
   762     lt <- gets lastType
       
   763     case lt of
       
   764          BTEnum a -> return . int $ length a - 1
       
   765          BTInt -> case e' of
       
   766                   "longint" -> return $ int (2147483647)
       
   767          BTString -> return $ int 255
       
   768          BTArray (RangeFromTo _ n) _ _ -> initExpr2C n
       
   769          _ -> error $ "BuiltInFunCall 'high' from " ++ show e ++ "\ntype: " ++ show lt
   655 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e
   770 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e
   656 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e
   771 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e
   657 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - 1") $ expr2C e
   772 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - 1") $ expr2C e
       
   773 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "length" _))) = do
       
   774     e' <- expr2C e
       
   775     lt <- gets lastType
       
   776     modify (\s -> s{lastType = BTInt})
       
   777     case lt of
       
   778          BTString -> return $ text "Length" <> parens e'
       
   779          BTArray {} -> return $ text "length_ar" <> parens e'
       
   780          _ -> error $ "length() called on " ++ show lt
   658 expr2C (BuiltInFunCall params ref) = do
   781 expr2C (BuiltInFunCall params ref) = do
   659     r <- ref2C ref 
   782     r <- ref2C ref 
   660     t <- gets lastType
   783     t <- gets lastType
   661     ps <- mapM expr2C params
   784     ps <- mapM expr2C params
   662     case t of
   785     case t of
   663         BTFunction t' -> do
   786         BTFunction _ t' -> do
   664             modify (\s -> s{lastType = t'})
   787             modify (\s -> s{lastType = t'})
   665         _ -> error $ "BuiltInFunCall lastType: " ++ show t
   788         _ -> error $ "BuiltInFunCall lastType: " ++ show t
   666     return $ 
   789     return $ 
   667         r <> parens (hsep . punctuate (char ',') $ ps)
   790         r <> parens (hsep . punctuate (char ',') $ ps)
   668 expr2C a = error $ "Don't know how to render " ++ show a
   791 expr2C a = error $ "Don't know how to render " ++ show a
   670 ref2CF :: Reference -> State RenderState Doc
   793 ref2CF :: Reference -> State RenderState Doc
   671 ref2CF (SimpleReference name) = do
   794 ref2CF (SimpleReference name) = do
   672     i <- id2C IOLookup name
   795     i <- id2C IOLookup name
   673     t <- gets lastType
   796     t <- gets lastType
   674     case t of
   797     case t of
   675          BTFunction _ -> return $ i <> parens empty
   798          BTFunction _ rt -> do
       
   799              modify(\s -> s{lastType = rt})
       
   800              return $ i <> parens empty
       
   801          _ -> return $ i
       
   802 ref2CF r@(RecordField (SimpleReference _) (SimpleReference _)) = do
       
   803     i <- ref2C r
       
   804     t <- gets lastType
       
   805     case t of
       
   806          BTFunction _ rt -> do
       
   807              modify(\s -> s{lastType = rt})
       
   808              return $ i <> parens empty
   676          _ -> return $ i
   809          _ -> return $ i
   677 ref2CF r = ref2C r
   810 ref2CF r = ref2C r
   678 
   811 
   679 ref2C :: Reference -> State RenderState Doc
   812 ref2C :: Reference -> State RenderState Doc
   680 -- rewrite into proper form
   813 -- rewrite into proper form
   686 -- conversion routines
   819 -- conversion routines
   687 ref2C ae@(ArrayElement [expr] ref) = do
   820 ref2C ae@(ArrayElement [expr] ref) = do
   688     e <- expr2C expr
   821     e <- expr2C expr
   689     r <- ref2C ref 
   822     r <- ref2C ref 
   690     t <- gets lastType
   823     t <- gets lastType
   691     ns <- gets currentScope
       
   692     case t of
   824     case t of
   693          (BTArray _ _ t') -> modify (\st -> st{lastType = t'})
   825          (BTArray _ _ t') -> modify (\st -> st{lastType = t'})
   694          (BTFunctionReturn _ (BTArray _ _ t')) -> modify (\st -> st{lastType = t'})
   826 --         (BTFunctionReturn _ (BTArray _ _ t')) -> modify (\st -> st{lastType = t'})
   695          (BTFunctionReturn _ (BTString)) -> modify (\st -> st{lastType = BTChar})
   827 --         (BTFunctionReturn _ (BTString)) -> modify (\st -> st{lastType = BTChar})
   696          (BTString) -> modify (\st -> st{lastType = BTChar})
   828          (BTString) -> modify (\st -> st{lastType = BTChar})
   697          (BTPointerTo t) -> do
   829          (BTPointerTo t) -> do
   698                 t'' <- fromPointer (show t) =<< gets lastType
   830                 t'' <- fromPointer (show t) =<< gets lastType
   699                 case t'' of
   831                 case t'' of
   700                      BTChar -> modify (\st -> st{lastType = BTChar})
   832                      BTChar -> modify (\st -> st{lastType = BTChar})
   701                      a -> error $ "Getting element of " ++ show a ++ "\nReference: " ++ show ae ++ "\n" ++ show (take 100 ns)
   833                      a -> error $ "Getting element of " ++ show a ++ "\nReference: " ++ show ae
   702          a -> error $ "Getting element of " ++ show a ++ "\nReference: " ++ show ae ++ "\n" ++ show (take 100 ns)
   834          a -> error $ "Getting element of " ++ show a ++ "\nReference: " ++ show ae
   703     case t of
   835     case t of
   704          BTString ->  return $ r <> text ".s" <> brackets e
   836          BTString ->  return $ r <> text ".s" <> brackets e
   705          _ -> return $ r <> brackets e
   837          _ -> return $ r <> brackets e
   706 ref2C (SimpleReference name) = id2C IOLookup name
   838 ref2C (SimpleReference name) = id2C IOLookup name
   707 ref2C rf@(RecordField (Dereference ref1) ref2) = do
   839 ref2C rf@(RecordField (Dereference ref1) ref2) = do
   708     r1 <- ref2C ref1 
   840     r1 <- ref2C ref1 
   709     t <- fromPointer (show ref1) =<< gets lastType
   841     t <- fromPointer (show ref1) =<< gets lastType
   710     ns <- gets currentScope
       
   711     r2 <- case t of
   842     r2 <- case t of
   712         BTRecord rs -> withRecordNamespace "" rs $ ref2C ref2
   843         BTRecord _ rs -> withRecordNamespace "" rs $ ref2C ref2
   713         BTUnit -> withLastIdNamespace $ ref2C ref2
   844         BTUnit -> error "What??"
   714         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf ++ "\n" ++ show (take 100 ns)
   845         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
   715     return $ 
   846     return $ 
   716         r1 <> text "->" <> r2
   847         r1 <> text "->" <> r2
   717 ref2C rf@(RecordField ref1 ref2) = do
   848 ref2C rf@(RecordField ref1 ref2) = do
   718     r1 <- ref2C ref1
   849     r1 <- ref2C ref1
   719     t <- gets lastType
   850     t <- gets lastType
   720     ns <- gets currentScope
   851     case t of
   721     r2 <- case t of
   852         BTRecord _ rs -> do
   722         BTFunctionReturn s (BTRecord rs) -> withRecordNamespace "" rs $ ref2C ref2       
   853             r2 <- withRecordNamespace "" rs $ ref2C ref2
   723         BTRecord rs -> withRecordNamespace "" rs $ ref2C ref2
   854             return $ r1 <> text "." <> r2
   724         BTUnit -> withLastIdNamespace $ ref2C ref2        
   855         BTUnit -> withLastIdNamespace $ ref2C ref2
   725         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf ++ "\n" ++ show (take 100 ns)
   856         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
   726     return $ 
       
   727         r1 <> text "." <> r2
       
   728 ref2C d@(Dereference ref) = do
   857 ref2C d@(Dereference ref) = do
   729     r <- ref2C ref
   858     r <- ref2C ref
   730     t <- fromPointer (show d) =<< gets lastType
   859     t <- fromPointer (show d) =<< gets lastType
   731     modify (\st -> st{lastType = t})
   860     modify (\st -> st{lastType = t})
   732     return $ (parens $ text "*" <> r)
   861     return $ (parens $ text "*" <> r)
   733 ref2C f@(FunCall params ref) = do
   862 ref2C f@(FunCall params ref) = do
   734     r <- ref2C ref
   863     r <- fref2C ref
   735     t <- gets lastType
   864     t <- gets lastType
   736     case t of
   865     case t of
   737         BTFunction t' -> do
   866         BTFunction _ t' -> do
   738             ps <- liftM (parens . hsep . punctuate (char ',')) $ mapM expr2C params
   867             ps <- liftM (parens . hsep . punctuate (char ',')) $ mapM expr2C params
   739             modify (\s -> s{lastType = t'})
   868             modify (\s -> s{lastType = t'})
   740             return $ r <> ps
   869             return $ r <> ps
   741         BTFunctionReturn r t' -> do
       
   742             ps <- liftM (parens . hsep . punctuate (char ',')) $ mapM expr2C params
       
   743             modify (\s -> s{lastType = t'})
       
   744             return $ text r <> ps
       
   745         _ -> case (ref, params) of
   870         _ -> case (ref, params) of
   746                   (SimpleReference i, [p]) -> ref2C $ TypeCast i p
   871                   (SimpleReference i, [p]) -> ref2C $ TypeCast i p
   747                   _ -> error $ "ref2C FunCall erroneous type cast detected: " ++ show f ++ "\nType detected: " ++ show t
   872                   _ -> error $ "ref2C FunCall erroneous type cast detected: " ++ show f ++ "\nType detected: " ++ show t
       
   873     where
       
   874     fref2C (SimpleReference name) = id2C (IOLookupFunction $ length params) name
       
   875     fref2C a = ref2C a
   748         
   876         
   749 ref2C (Address ref) = do
   877 ref2C (Address ref) = do
   750     r <- ref2C ref
   878     r <- ref2C ref
   751     return $ text "&" <> parens r
   879     return $ text "&" <> parens r
   752 ref2C (TypeCast t'@(Identifier i _) expr) = do
   880 ref2C (TypeCast t'@(Identifier i _) expr) = do
   753     case map toLower i of
   881     case map toLower i of
   754         "pchar" -> ref2C $ FunCall [expr] (SimpleReference (Identifier "_pchar" $ BTPointerTo BTChar))
   882         "pchar" -> ref2C $ FunCall [expr] (SimpleReference (Identifier "_pchar" $ BTPointerTo BTChar))
   755         a -> do
   883         a -> do
   756             e <- expr2C expr
   884             e <- expr2C expr
   757             t <- id2C IOLookup t'    
   885             t <- id2C IOLookup t'    
   758             return $ parens t <> e
   886             return . parens $ parens t <> e
   759 ref2C (RefExpression expr) = expr2C expr
   887 ref2C (RefExpression expr) = expr2C expr
   760 
   888 
   761 
   889 
   762 op2C :: String -> String
   890 op2C :: String -> String
   763 op2C "or" = "|"
   891 op2C "or" = "|"