15 import qualified Data.Map as Map |
15 import qualified Data.Map as Map |
16 import qualified Data.Set as Set |
16 import qualified Data.Set as Set |
17 import Data.List (find) |
17 import Data.List (find) |
18 import Numeric |
18 import Numeric |
19 |
19 |
20 import PascalParser |
20 import PascalParser(pascalUnit) |
21 import PascalUnitSyntaxTree |
21 import PascalUnitSyntaxTree |
22 |
22 |
23 |
23 |
24 data InsertOption = |
24 data InsertOption = |
25 IOInsert |
25 IOInsert |
|
26 | IOInsertWithType Doc |
26 | IOLookup |
27 | IOLookup |
27 | IOLookupLast |
28 | IOLookupLast |
28 | IOLookupFunction Int |
29 | IOLookupFunction Int |
29 | IODeferred |
30 | IODeferred |
30 |
31 |
31 type Record = (String, BaseType) |
32 data Record = Record |
|
33 { |
|
34 lcaseId :: String, |
|
35 baseType :: BaseType, |
|
36 typeDecl :: Doc |
|
37 } |
|
38 deriving Show |
32 type Records = Map.Map String [Record] |
39 type Records = Map.Map String [Record] |
33 data RenderState = RenderState |
40 data RenderState = RenderState |
34 { |
41 { |
35 currentScope :: Records, |
42 currentScope :: Records, |
36 lastIdentifier :: String, |
43 lastIdentifier :: String, |
37 lastType :: BaseType, |
44 lastType :: BaseType, |
|
45 lastIdTypeDecl :: Doc, |
38 stringConsts :: [(String, String)], |
46 stringConsts :: [(String, String)], |
39 uniqCounter :: Int, |
47 uniqCounter :: Int, |
40 toMangle :: Set.Set String, |
48 toMangle :: Set.Set String, |
41 currentUnit :: String, |
49 currentUnit :: String, |
42 currentFunctionResult :: String, |
50 currentFunctionResult :: String, |
43 namespaces :: Map.Map String Records |
51 namespaces :: Map.Map String Records |
44 } |
52 } |
45 |
53 |
46 emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty "" "" |
54 rec2Records = map (\(a, b) -> Record a b empty) |
|
55 |
|
56 emptyState = RenderState Map.empty "" BTUnknown empty [] 0 Set.empty "" "" |
47 |
57 |
48 getUniq :: State RenderState Int |
58 getUniq :: State RenderState Int |
49 getUniq = do |
59 getUniq = do |
50 i <- gets uniqCounter |
60 i <- gets uniqCounter |
51 modify(\s -> s{uniqCounter = uniqCounter s + 1}) |
61 modify(\s -> s{uniqCounter = uniqCounter s + 1}) |
147 , uniqCounter = uniqCounter s |
164 , uniqCounter = uniqCounter s |
148 , stringConsts = stringConsts s |
165 , stringConsts = stringConsts s |
149 }) |
166 }) |
150 return a |
167 return a |
151 |
168 |
152 withLastIdNamespace :: State RenderState Doc -> State RenderState Doc |
|
153 withLastIdNamespace f = do |
169 withLastIdNamespace f = do |
154 li <- gets lastIdentifier |
170 li <- gets lastIdentifier |
155 nss <- gets namespaces |
171 nss <- gets namespaces |
156 withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f |
172 withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f |
157 |
173 |
158 withRecordNamespace :: String -> [(String, BaseType)] -> State RenderState Doc -> State RenderState Doc |
174 withRecordNamespace :: String -> [Record] -> State RenderState Doc -> State RenderState Doc |
159 withRecordNamespace _ [] = error "withRecordNamespace: empty record" |
175 withRecordNamespace _ [] = error "withRecordNamespace: empty record" |
160 withRecordNamespace prefix recs = withState' f |
176 withRecordNamespace prefix recs = withState' f |
161 where |
177 where |
162 f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""} |
178 f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""} |
163 records = Map.fromList $ map (\(a, b) -> (map toLower a, [(prefix ++ a, b)])) recs |
179 records = Map.fromList $ map (\(Record a b d) -> (map toLower a, [Record (prefix ++ a) b d])) recs |
164 un [a] b = a : b |
180 un [a] b = a : b |
165 |
181 |
166 toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO () |
182 toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO () |
167 toCFiles _ (_, System _) = return () |
183 toCFiles _ (_, System _) = return () |
|
184 toCFiles _ (_, Redo _) = return () |
168 toCFiles ns p@(fn, pu) = do |
185 toCFiles ns p@(fn, pu) = do |
169 hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..." |
186 hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..." |
170 toCFiles' p |
187 toCFiles' p |
171 where |
188 where |
172 toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p |
189 toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n" ++ (render2C initialState . pascal2C) p |
173 toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do |
190 toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do |
174 let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState{currentUnit = map toLower i ++ "_"} |
191 let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface True) initialState{currentUnit = map toLower i ++ "_"} |
|
192 (a', s') = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface False) initialState{currentUnit = map toLower i ++ "_"} |
175 writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text "")) |
193 writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text "")) |
176 writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation |
194 writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n\n#include \"" ++ fn ++ ".h\"\n" ++ render (a' $+$ text "") ++ (render2C s . implementation2C) implementation |
177 initialState = emptyState ns |
195 initialState = emptyState ns |
178 |
196 |
179 render2C :: RenderState -> State RenderState Doc -> String |
197 render2C :: RenderState -> State RenderState Doc -> String |
180 render2C a = render . ($+$ empty) . flip evalState a |
198 render2C a = render . ($+$ empty) . flip evalState a |
181 |
199 |
|
200 |
182 usesFiles :: PascalUnit -> [String] |
201 usesFiles :: PascalUnit -> [String] |
183 usesFiles (Program _ (Implementation uses _) _) = "pas2cSystem" : uses2List uses |
202 usesFiles (Program _ (Implementation uses _) _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses |
184 usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = "pas2cSystem" : uses2List uses1 ++ uses2List uses2 |
203 usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses1 ++ uses2List uses2 |
185 usesFiles (System {}) = [] |
204 usesFiles (System {}) = [] |
186 |
205 usesFiles (Redo {}) = [] |
187 |
206 |
188 pascal2C :: PascalUnit -> State RenderState Doc |
207 pascal2C :: PascalUnit -> State RenderState Doc |
189 pascal2C (Unit _ interface implementation init fin) = |
208 pascal2C (Unit _ interface implementation init fin) = |
190 liftM2 ($+$) (interface2C interface) (implementation2C implementation) |
209 liftM2 ($+$) (interface2C interface True) (implementation2C implementation) |
191 |
210 |
192 pascal2C (Program _ implementation mainFunction) = do |
211 pascal2C (Program _ implementation mainFunction) = do |
193 impl <- implementation2C implementation |
212 impl <- implementation2C implementation |
194 [main] <- tvar2C True |
213 [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) False (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction))) |
195 (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [] (Just (TypesAndVars [], mainFunction))) |
|
196 return $ impl $+$ main |
214 return $ impl $+$ main |
197 |
215 |
198 |
216 |
199 |
217 -- the second bool indicates whether do normal interface translation or generate variable declarations |
200 interface2C :: Interface -> State RenderState Doc |
218 -- that will be inserted into implementation files |
201 interface2C (Interface uses tvars) = do |
219 interface2C :: Interface -> Bool -> State RenderState Doc |
|
220 interface2C (Interface uses tvars) True = do |
202 u <- uses2C uses |
221 u <- uses2C uses |
203 tv <- typesAndVars2C True tvars |
222 tv <- typesAndVars2C True True True tvars |
204 r <- renderStringConsts |
223 r <- renderStringConsts |
205 return (u $+$ r $+$ tv) |
224 return (u $+$ r $+$ tv) |
|
225 interface2C (Interface uses tvars) False = do |
|
226 u <- uses2C uses |
|
227 tv <- typesAndVars2C True False False tvars |
|
228 r <- renderStringConsts |
|
229 return tv |
206 |
230 |
207 implementation2C :: Implementation -> State RenderState Doc |
231 implementation2C :: Implementation -> State RenderState Doc |
208 implementation2C (Implementation uses tvars) = do |
232 implementation2C (Implementation uses tvars) = do |
209 u <- uses2C uses |
233 u <- uses2C uses |
210 tv <- typesAndVars2C True tvars |
234 tv <- typesAndVars2C True False True tvars |
211 r <- renderStringConsts |
235 r <- renderStringConsts |
212 return (u $+$ r $+$ tv) |
236 return (u $+$ r $+$ tv) |
213 |
237 |
214 checkDuplicateFunDecls :: [TypeVarDeclaration] -> State RenderState () |
238 checkDuplicateFunDecls :: [TypeVarDeclaration] -> State RenderState () |
215 checkDuplicateFunDecls tvs = |
239 checkDuplicateFunDecls tvs = |
216 modify $ \s -> s{toMangle = Map.keysSet . Map.filter (> 1) . foldr ins initMap $ tvs} |
240 modify $ \s -> s{toMangle = Map.keysSet . Map.filter (> 1) . foldr ins initMap $ tvs} |
217 where |
241 where |
218 initMap = Map.empty |
242 initMap = Map.empty |
219 --initMap = Map.fromList [("reset", 2)] |
243 --initMap = Map.fromList [("reset", 2)] |
220 ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m |
244 ins (FunctionDeclaration (Identifier i _) _ _ _ _) m = Map.insertWith (+) (map toLower i) 1 m |
221 ins _ m = m |
245 ins _ m = m |
222 |
246 |
223 typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc |
247 -- the second bool indicates whether declare variable as extern or not |
224 typesAndVars2C b (TypesAndVars ts) = do |
248 -- the third bool indicates whether include types or not |
|
249 |
|
250 typesAndVars2C :: Bool -> Bool -> Bool -> TypesAndVars -> State RenderState Doc |
|
251 typesAndVars2C b externVar includeType(TypesAndVars ts) = do |
225 checkDuplicateFunDecls ts |
252 checkDuplicateFunDecls ts |
226 liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts |
253 liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b externVar includeType False) ts |
227 |
254 |
228 setBaseType :: BaseType -> Identifier -> Identifier |
255 setBaseType :: BaseType -> Identifier -> Identifier |
229 setBaseType bt (Identifier i _) = Identifier i bt |
256 setBaseType bt (Identifier i _) = Identifier i bt |
230 |
257 |
231 uses2C :: Uses -> State RenderState Doc |
258 uses2C :: Uses -> State RenderState Doc |
232 uses2C uses@(Uses unitIds) = do |
259 uses2C uses@(Uses unitIds) = do |
|
260 |
233 mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds) |
261 mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds) |
|
262 mapM_ injectNamespace (Identifier "pas2cRedo" undefined : unitIds) |
234 mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds |
263 mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds |
235 return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses |
264 return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses |
236 where |
265 where |
237 injectNamespace (Identifier i _) = do |
266 injectNamespace (Identifier i _) = do |
238 getNS <- gets (flip Map.lookup . namespaces) |
267 getNS <- gets (flip Map.lookup . namespaces) |
240 |
269 |
241 uses2List :: Uses -> [String] |
270 uses2List :: Uses -> [String] |
242 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids |
271 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids |
243 |
272 |
244 |
273 |
|
274 setLastIdValues vv = (\s -> s{lastType = baseType vv, lastIdentifier = lcaseId vv, lastIdTypeDecl = typeDecl vv}) |
|
275 |
245 id2C :: InsertOption -> Identifier -> State RenderState Doc |
276 id2C :: InsertOption -> Identifier -> State RenderState Doc |
246 id2C IOInsert (Identifier i t) = do |
277 id2C IOInsert i = id2C (IOInsertWithType empty) i |
|
278 id2C (IOInsertWithType d) (Identifier i t) = do |
247 ns <- gets currentScope |
279 ns <- gets currentScope |
248 tom <- gets (Set.member n . toMangle) |
280 tom <- gets (Set.member n . toMangle) |
249 cu <- gets currentUnit |
281 cu <- gets currentUnit |
250 let (i', t') = case (t, tom) of |
282 let (i', t') = case (t, tom) of |
251 (BTFunction _ p _, True) -> (cu ++ i ++ ('_' : show p), t) |
283 (BTFunction _ p _, True) -> (cu ++ i ++ ('_' : show p), t) |
252 (BTFunction _ _ _, _) -> (cu ++ i, t) |
284 (BTFunction _ _ _, _) -> (cu ++ i, t) |
253 (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t') |
285 (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t') |
254 _ -> (i, t) |
286 _ -> (i, t) |
255 modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t')] (currentScope s), lastIdentifier = n}) |
287 modify (\s -> s{currentScope = Map.insertWith (++) n [Record i' t' d] (currentScope s), lastIdentifier = n}) |
256 return $ text i' |
288 return $ text i' |
257 where |
289 where |
258 n = map toLower i |
290 n = map toLower i |
|
291 |
259 id2C IOLookup i = id2CLookup head i |
292 id2C IOLookup i = id2CLookup head i |
260 id2C IOLookupLast i = id2CLookup last i |
293 id2C IOLookupLast i = id2CLookup last i |
261 id2C (IOLookupFunction params) (Identifier i t) = do |
294 id2C (IOLookupFunction params) (Identifier i t) = do |
262 let i' = map toLower i |
295 let i' = map toLower i |
263 v <- gets $ Map.lookup i' . currentScope |
296 v <- gets $ Map.lookup i' . currentScope |
264 lt <- gets lastType |
297 lt <- gets lastType |
265 if isNothing v then |
298 if isNothing v then |
266 error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v |
299 error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v |
267 else |
300 else |
268 let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in |
301 let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in |
269 modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) |
302 modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) |
270 where |
303 where |
271 checkParam (_, BTFunction _ p _) = p == params |
304 checkParam (Record _ (BTFunction _ p _) _) = p == params |
272 checkParam _ = False |
305 checkParam _ = False |
273 id2C IODeferred (Identifier i t) = do |
306 id2C IODeferred (Identifier i t) = do |
274 let i' = map toLower i |
307 let i' = map toLower i |
275 v <- gets $ Map.lookup i' . currentScope |
308 v <- gets $ Map.lookup i' . currentScope |
276 if (isNothing v) then |
309 if (isNothing v) then |
277 modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i) |
310 modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i) |
278 else |
311 else |
279 let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) |
312 let vv = head $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) |
280 |
313 |
281 id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc |
314 id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc |
282 id2CLookup f (Identifier i _) = do |
315 id2CLookup f (Identifier i t) = do |
283 let i' = map toLower i |
316 let i' = map toLower i |
284 v <- gets $ Map.lookup i' . currentScope |
317 v <- gets $ Map.lookup i' . currentScope |
285 lt <- gets lastType |
318 lt <- gets lastType |
286 if isNothing v then |
319 if isNothing v then |
287 error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt |
320 error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt |
288 else |
321 else |
289 let vv = f $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) |
322 let vv = f $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) |
290 |
323 |
291 |
324 |
292 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc |
325 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc |
293 id2CTyped t (Identifier i _) = do |
326 id2CTyped = id2CTyped2 Nothing |
|
327 |
|
328 id2CTyped2 :: Maybe Doc -> TypeDecl -> Identifier -> State RenderState Doc |
|
329 id2CTyped2 md t (Identifier i _) = do |
294 tb <- resolveType t |
330 tb <- resolveType t |
295 case (t, tb) of |
331 case (t, tb) of |
296 (_, BTUnknown) -> do |
332 (_, BTUnknown) -> do |
297 error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t |
333 error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t |
298 (SimpleType {}, BTRecord _ r) -> do |
334 (SimpleType {}, BTRecord _ r) -> do |
299 ts <- type2C t |
335 ts <- type2C t |
300 id2C IOInsert (Identifier i (BTRecord (render $ ts empty) r)) |
336 id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord (render $ ts empty) r)) |
301 (_, BTRecord _ r) -> do |
337 (_, BTRecord _ r) -> do |
302 ts <- type2C t |
338 ts <- type2C t |
303 id2C IOInsert (Identifier i (BTRecord i r)) |
339 id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord i r)) |
304 _ -> id2C IOInsert (Identifier i tb) |
340 _ -> case md of |
305 |
341 Nothing -> id2C IOInsert (Identifier i tb) |
|
342 Just ts -> id2C (IOInsertWithType ts) (Identifier i tb) |
306 |
343 |
307 |
344 |
308 resolveType :: TypeDecl -> State RenderState BaseType |
345 resolveType :: TypeDecl -> State RenderState BaseType |
309 resolveType st@(SimpleType (Identifier i _)) = do |
346 resolveType st@(SimpleType (Identifier i _)) = do |
310 let i' = map toLower i |
347 let i' = map toLower i |
311 v <- gets $ Map.lookup i' . currentScope |
348 v <- gets $ Map.lookup i' . currentScope |
312 if isJust v then return . snd . head $ fromJust v else return $ f i' |
349 if isJust v then return . baseType . head $ fromJust v else return $ f i' |
313 where |
350 where |
314 f "integer" = BTInt |
351 f "integer" = BTInt |
315 f "pointer" = BTPointerTo BTVoid |
352 f "pointer" = BTPointerTo BTVoid |
316 f "boolean" = BTBool |
353 f "boolean" = BTBool |
317 f "float" = BTFloat |
354 f "float" = BTFloat |
390 abc = hcat . punctuate comma . map (char . fst) $ ps |
427 abc = hcat . punctuate comma . map (char . fst) $ ps |
391 cparams = hcat . punctuate comma . map (\(c, v) -> if v then char '&' <> parens (char c) else char c) $ ps |
428 cparams = hcat . punctuate comma . map (\(c, v) -> if v then char '&' <> parens (char c) else char c) $ ps |
392 ps = zip ['a'..] (toIsVarList params) |
429 ps = zip ['a'..] (toIsVarList params) |
393 |
430 |
394 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc] |
431 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc] |
395 fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do |
432 fun2C _ _ (FunctionDeclaration name inline returnType params Nothing) = do |
396 t <- type2C returnType |
433 t <- type2C returnType |
397 t'<- gets lastType |
434 t'<- gets lastType |
398 p <- withState' id $ functionParams2C params |
435 p <- withState' id $ functionParams2C params |
399 n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name |
436 n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name |
|
437 let decor = if inline then text "inline" else empty |
400 if hasVars then |
438 if hasVars then |
401 return [funWithVarsToDefine n params $+$ t empty <+> text (n ++ "__vars") <> parens p] |
439 return [funWithVarsToDefine n params $+$ decor <+> t empty <+> text (n ++ "__vars") <> parens p] |
402 else |
440 else |
403 return [t empty <+> text n <> parens p] |
441 return [decor <+> t empty <+> text n <> parens p] |
404 where |
442 where |
405 hasVars = hasPassByReference params |
443 hasVars = hasPassByReference params |
406 |
444 |
407 |
445 |
408 fun2C True rv (FunctionDeclaration name@(Identifier i _) returnType params (Just (tvars, phrase))) = do |
446 fun2C True rv (FunctionDeclaration name@(Identifier i _) inline returnType params (Just (tvars, phrase))) = do |
409 let res = docToLower $ text rv <> text "_result" |
447 let res = docToLower $ text rv <> text "_result" |
410 t <- type2C returnType |
448 t <- type2C returnType |
411 t'<- gets lastType |
449 t'<- gets lastType |
412 |
450 |
413 notDeclared <- liftM isNothing . gets $ Map.lookup (map toLower i) . currentScope |
451 notDeclared <- liftM isNothing . gets $ Map.lookup (map toLower i) . currentScope |
438 phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p |
480 phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p |
439 phrase2C' p = phrase2C p |
481 phrase2C' p = phrase2C p |
440 un [a] b = a : b |
482 un [a] b = a : b |
441 hasVars = hasPassByReference params |
483 hasVars = hasPassByReference params |
442 |
484 |
443 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name |
485 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _ _) = error $ "nested functions not allowed: " ++ name |
444 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv |
486 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv |
445 |
487 |
446 tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc] |
488 -- the second bool indicates whether declare variable as extern or not |
447 tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) = |
489 -- the third bool indicates whether include types or not |
448 fun2C b name f |
490 -- the fourth bool indicates whether ignore initialization or not (basically for dynamic arrays since we cannot do initialization in function params) |
449 tvar2C _ td@(TypeDeclaration i' t) = do |
491 tvar2C :: Bool -> Bool -> Bool -> Bool -> TypeVarDeclaration -> State RenderState [Doc] |
|
492 tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _ _) = do |
|
493 t <- fun2C b name f |
|
494 if includeType then return t else return [] |
|
495 tvar2C _ _ includeType _ td@(TypeDeclaration i' t) = do |
450 i <- id2CTyped t i' |
496 i <- id2CTyped t i' |
451 tp <- type2C t |
497 tp <- type2C t |
452 return [text "typedef" <+> tp i] |
498 return $ if includeType then [text "typedef" <+> tp i] else [] |
453 |
499 |
454 tvar2C _ (VarDeclaration True _ (ids, t) Nothing) = do |
500 tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do |
455 t' <- liftM ((empty <+>) . ) $ type2C t |
501 t' <- liftM ((empty <+>) . ) $ type2C t |
456 liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids |
502 liftM (map(\i -> t' i)) $ mapM (id2CTyped2 (Just $ t' empty) (VarParamType t)) ids |
457 |
503 |
458 tvar2C _ (VarDeclaration _ isConst (ids, t) mInitExpr) = do |
504 tvar2C _ externVar includeType ignoreInit (VarDeclaration _ isConst (ids, t) mInitExpr) = do |
459 t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t |
505 t' <- liftM (((if isConst then text "static const" else if externVar |
|
506 then text "extern" |
|
507 else empty) |
|
508 <+>) . ) $ type2C t |
460 ie <- initExpr mInitExpr |
509 ie <- initExpr mInitExpr |
461 lt <- gets lastType |
510 lt <- gets lastType |
462 case (isConst, lt, ids, mInitExpr) of |
511 case (isConst, lt, ids, mInitExpr) of |
463 (True, BTInt, [i], Just _) -> do |
512 (True, BTInt, [i], Just _) -> do |
464 i' <- id2CTyped t i |
513 i' <- id2CTyped t i |
465 return [text "enum" <> braces (i' <+> ie)] |
514 return $ if includeType then [text "enum" <> braces (i' <+> ie)] else [] |
466 (True, BTFloat, [i], Just e) -> do |
515 (True, BTFloat, [i], Just e) -> do |
467 i' <- id2CTyped t i |
516 i' <- id2CTyped t i |
468 ie <- initExpr2C e |
517 ie <- initExpr2C e |
469 return [text "#define" <+> i' <+> parens ie <> text "\n"] |
518 return $ if includeType then [text "#define" <+> i' <+> parens ie <> text "\n"] else [] |
470 (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids |
519 (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids |
471 _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids |
520 (_, BTArray r _ _, [i], _) -> do |
|
521 i' <- id2CTyped t i |
|
522 ie' <- return $ case (r, mInitExpr, ignoreInit) of |
|
523 (RangeInfinite, Nothing, False) -> text "= NULL" -- force dynamic array to be initialized as NULL if not initialized at all |
|
524 (_, _, _) -> ie |
|
525 result <- liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie')) $ mapM (id2CTyped t) ids |
|
526 case (r, ignoreInit) of |
|
527 (RangeInfinite, False) -> |
|
528 -- if the array is dynamic, add dimension info to it |
|
529 return $ [dimDecl] ++ result |
|
530 where |
|
531 arrayDimStr = show $ arrayDimension t |
|
532 arrayDimInitExp = text ("={" ++ ".dim = " ++ arrayDimStr ++ ", .a = {0, 0, 0, 0}}") |
|
533 dimDecl = varDeclDecision isConst includeType (text "fpcrtl_dimension_t" <+> i' <> text "_dimension_info") arrayDimInitExp |
|
534 |
|
535 (_, _) -> return result |
|
536 |
|
537 _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped2 (Just $ t' empty) t) ids |
472 where |
538 where |
473 initExpr Nothing = return $ empty |
539 initExpr Nothing = return $ empty |
474 initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e) |
540 initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e) |
475 |
541 varDeclDecision True True varStr expStr = varStr <+> expStr |
476 tvar2C f (OperatorDeclaration op (Identifier i _) ret params body) = do |
542 varDeclDecision False True varStr expStr = if externVar then varStr else varStr <+> expStr |
|
543 varDeclDecision False False varStr expStr = varStr <+> expStr |
|
544 varDeclDecision True False varStr expStr = empty |
|
545 arrayDimension a = case a of |
|
546 ArrayDecl Nothing t -> let a = arrayDimension t in if a > 3 then error "Dynamic array with dimension > 4 is not supported." else 1 + arrayDimension t |
|
547 ArrayDecl _ _ -> error "Mixed dynamic array and static array are not supported." |
|
548 _ -> 0 |
|
549 |
|
550 tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) inline ret params body) = do |
477 r <- op2CTyped op (extractTypes params) |
551 r <- op2CTyped op (extractTypes params) |
478 fun2C f i (FunctionDeclaration r ret params body) |
552 fun2C f i (FunctionDeclaration r inline ret params body) |
479 |
553 |
480 |
554 |
481 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier |
555 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier |
482 op2CTyped op t = do |
556 op2CTyped op t = do |
483 t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t |
557 t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t |
589 BTRecord _ _ -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a |
664 BTRecord _ _ -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a |
590 BTUnknown -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a |
665 BTUnknown -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a |
591 _ -> return $ \a -> i' <+> text "*" <+> a |
666 _ -> return $ \a -> i' <+> text "*" <+> a |
592 type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t |
667 type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t |
593 type2C' (RecordType tvs union) = do |
668 type2C' (RecordType tvs union) = do |
594 t <- withState' f $ mapM (tvar2C False) tvs |
669 t <- withState' f $ mapM (tvar2C False False True False) tvs |
595 u <- unions |
670 u <- unions |
596 return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i |
671 return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i |
597 where |
672 where |
598 f s = s{currentUnit = ""} |
673 f s = s{currentUnit = ""} |
599 unions = case union of |
674 unions = case union of |
600 Nothing -> return empty |
675 Nothing -> return empty |
601 Just a -> do |
676 Just a -> do |
602 structs <- mapM struct2C a |
677 structs <- mapM struct2C a |
603 return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi |
678 return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi |
604 struct2C tvs = do |
679 struct2C tvs = do |
605 t <- withState' f $ mapM (tvar2C False) tvs |
680 t <- withState' f $ mapM (tvar2C False False True False) tvs |
606 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi |
681 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi |
607 type2C' (RangeType r) = return (text "int" <+>) |
682 type2C' (RangeType r) = return (text "int" <+>) |
608 type2C' (Sequence ids) = do |
683 type2C' (Sequence ids) = do |
609 is <- mapM (id2C IOInsert . setBaseType bt) ids |
684 is <- mapM (id2C IOInsert . setBaseType bt) ids |
610 return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [0..]) <+>) |
685 return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [0..]) <+>) |
702 case2C (e, p) = do |
788 case2C (e, p) = do |
703 ies <- mapM range2C e |
789 ies <- mapM range2C e |
704 ph <- phrase2C p |
790 ph <- phrase2C p |
705 return $ |
791 return $ |
706 vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;") |
792 vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;") |
707 dflt | isNothing mphrase = return [] |
793 dflt | isNothing mphrase = return [text "default: break;"] -- avoid compiler warning |
708 | otherwise = do |
794 | otherwise = do |
709 ph <- mapM phrase2C $ fromJust mphrase |
795 ph <- mapM phrase2C $ fromJust mphrase |
710 return [text "default:" <+> nest 4 (vcat ph)] |
796 return [text "default:" <+> nest 4 (vcat ph)] |
711 |
797 |
712 phrase2C wb@(WithBlock ref p) = do |
798 phrase2C wb@(WithBlock ref p) = do |
713 r <- ref2C ref |
799 r <- ref2C ref |
714 t <- gets lastType |
800 t <- gets lastType |
715 case t of |
801 case t of |
716 (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p |
802 (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") (rec2Records rs) $ phrase2C $ wrapPhrase p |
717 a -> do |
803 a -> do |
718 error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb |
804 error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb |
719 phrase2C (ForCycle i' e1' e2' p) = do |
805 phrase2C (ForCycle i' e1' e2' p up) = do |
720 i <- id2C IOLookup i' |
806 i <- id2C IOLookup i' |
|
807 iType <- gets lastIdTypeDecl |
721 e1 <- expr2C e1' |
808 e1 <- expr2C e1' |
722 e2 <- expr2C e2' |
809 e2 <- expr2C e2' |
723 ph <- phrase2C (wrapPhrase p) |
810 let inc = if up then "inc" else "dec" |
724 return $ |
811 let add = if up then "+ 1" else "- 1" |
725 text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> e1, i <+> text "<=" <+> e2, text "++" <> i]) |
812 let iEnd = i <> text "__end__" |
|
813 ph <- phrase2C . appendPhrase (BuiltInFunctionCall [Reference $ SimpleReference i'] (SimpleReference (Identifier inc BTUnknown))) $ wrapPhrase p |
|
814 return . braces $ |
|
815 i <+> text "=" <+> e1 <> semi |
726 $$ |
816 $$ |
727 ph |
817 iType <+> iEnd <+> text "=" <+> e2 <> semi |
|
818 $$ |
|
819 text "if" <+> (parens $ i <+> text "<=" <+> iEnd) <+> text "do" <+> ph <+> |
|
820 text "while" <> parens (i <+> text "!=" <+> iEnd <+> text add) <> semi |
|
821 where |
|
822 appendPhrase p (Phrases ps) = Phrases $ ps ++ [p] |
728 phrase2C (RepeatCycle e' p') = do |
823 phrase2C (RepeatCycle e' p') = do |
729 e <- expr2C e' |
824 e <- expr2C e' |
730 p <- phrase2C (Phrases p') |
825 p <- phrase2C (Phrases p') |
731 return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi |
826 return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi |
732 phrase2C NOP = return $ text ";" |
827 phrase2C NOP = return $ text ";" |
775 ref2C $ FunCall [expr1, expr2] (SimpleReference i) |
870 ref2C $ FunCall [expr1, expr2] (SimpleReference i) |
776 ("in", _, _) -> |
871 ("in", _, _) -> |
777 case expr2 of |
872 case expr2 of |
778 SetExpression set -> do |
873 SetExpression set -> do |
779 ids <- mapM (id2C IOLookup) set |
874 ids <- mapM (id2C IOLookup) set |
|
875 modify(\s -> s{lastType = BTBool}) |
780 return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids |
876 return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids |
781 _ -> error "'in' against not set expression" |
877 _ -> error "'in' against not set expression" |
782 (o, _, _) | o `elem` boolOps -> do |
878 (o, _, _) | o `elem` boolOps -> do |
783 modify(\s -> s{lastType = BTBool}) |
879 modify(\s -> s{lastType = BTBool}) |
784 return $ parens e1 <+> text o <+> parens e2 |
880 return $ parens e1 <+> text o <+> parens e2 |
785 | otherwise -> return $ parens e1 <+> text o <+> parens e2 |
881 | otherwise -> do |
|
882 o' <- return $ case o of |
|
883 "/(float)" -> text "/(float)" -- pascal returns real value |
|
884 _ -> text o |
|
885 e1' <- return $ case (o, t1, t2) of |
|
886 ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e1 |
|
887 _ -> parens e1 |
|
888 e2' <- return $ case (o, t1, t2) of |
|
889 ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e2 |
|
890 _ -> parens e2 |
|
891 return $ e1' <+> o' <+> e2' |
786 where |
892 where |
787 boolOps = ["==", "!=", "<", ">", "<=", ">="] |
893 boolOps = ["==", "!=", "<", ">", "<=", ">="] |
788 expr2C (NumberLiteral s) = do |
894 expr2C (NumberLiteral s) = do |
789 modify(\s -> s{lastType = BTInt}) |
895 modify(\s -> s{lastType = BTInt}) |
790 return $ text s |
896 return $ text s |