-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCTransform.hs
More file actions
222 lines (188 loc) · 9.42 KB
/
Copy pathCTransform.hs
File metadata and controls
222 lines (188 loc) · 9.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, NamedFieldPuns, LambdaCase, ViewPatterns
, FlexibleContexts, TemplateHaskell, RankNTypes #-}
-- | Reimplementation of Remix-C transformation program.
module CTransform where
import MiniC.ParseProgram
import MiniC.Representation
import MiniC.AST
import MiniC.PrettyPrint
import MiniC.GenTemplate
import MiniC.SourceNotation
import MiniC.RangeTree
import MiniC.Semantics
import MiniC.Helpers
import MiniC.SymbolTable
import MiniC.TransformInfo
import MiniC.Instances
import SourceCode.ASTElems
import SourceCode.ToSourceTree
import SourceCode.ASTNode
import Control.Monad
import Control.Lens hiding ((<.>))
import Control.Lens.Plated
import Data.Data.Lens
import Data.Function
import Data.Maybe
import Data.Either.Combinators
import Control.Applicative
import System.Environment
import System.Directory
import System.FilePath
import Debug.Trace
main :: IO ()
main = do (file:trfs) <- getArgs
wd <- getCurrentDirectory
transforms <- parseTrfs trfs
runProgram (ProgramParams file transforms) >>= \case
Right prog -> writeFile (modifiedFileName transforms file) (prettyPrint prog)
Left err -> putStrLn err
runProgram :: ProgramParams -> IO (Either String TranslationUnitNI)
runProgram (ProgramParams file transforms) =
readFile file
>>= parseProgram file
>>= return
. mapBoth show
( flip transformAST transforms
. analyseAST
. transformSourceInfo )
data ProgramParams
= ProgramParams { _inputFile :: String
, _transformations :: [Transformation]
}
deriving (Show)
-- | Transformations that the tool can produce
data Transformation = IntroduceIndirection QualifiedName
| RemoveIndirection QualifiedName
| CreateSkeleton
deriving Show
-- | Parses command line arguments
parseTrfs :: [String] -> IO [Transformation]
parseTrfs ("-ri":qname:rest)
= (:) <$> (RemoveIndirection <$> parseQualName qname) <*> parseTrfs rest
parseTrfs ("-ii":qname:rest)
= (:) <$> (IntroduceIndirection <$> parseQualName qname) <*> parseTrfs rest
parseTrfs ("-cc":rest)
= (CreateSkeleton :) <$> parseTrfs rest
parseTrfs [] = return []
-- handle command line errors
parseTrfs (tr:_) | tr `elem` ["-ri","-ii"]
= error ("Not enough parameters for transformation " ++ tr)
parseTrfs (command:_) = error $ "Unknown command: " ++ command
-- | Produces the name of the transformed file
modifiedFileName :: [Transformation] -> FilePath -> FilePath
modifiedFileName [CreateSkeleton] = addPlusExtension "skeleton"
modifiedFileName _ = addPlusExtension "configured"
-- | Adds a new extensions before an existing one
addPlusExtension ext fn
= dropExtensions fn <.> ext <.> takeExtensions fn
transformAST :: TranslationUnitNI -> [Transformation] -> TranslationUnitNI
transformAST = foldl doTrfAST
where doTrfAST :: TranslationUnitNI -> Transformation -> TranslationUnitNI
doTrfAST tu (RemoveIndirection name) = removeIndirection name tu
doTrfAST tu (IntroduceIndirection name) = addIndirection name tu
doTrfAST tu CreateSkeleton = createSkeleton tu
addIndirection :: QualifiedName -> TranslationUnitNI -> TranslationUnitNI
addIndirection qn tu
= let declaration :: Simple Traversal TranslationUnitNI VariableDeclarationNI
declaration = biplate . checkScope qn . filterTrav (has (matchQualItself qn)) simple
exprs = biplate :: Simple Traversal TranslationUnitNI ExpressionNI
in case toListOf declaration tu of
[] -> error "No matching declaration for adding indirection"
[_] -> over exprs trfExpr $ over declaration trfDecl tu
_ -> error "Multiple matching declarations for adding indirection"
where -- | Add indirection to a declaration
trfDecl :: VariableDeclarationNI -> VariableDeclarationNI
trfDecl vd = vd & matchQualItself qn %~ (addPtrToQual (vd ^? matchParentQual qn))
trfExpr :: ExpressionNI -> ExpressionNI
trfExpr memb@(Member{})
| toTrf qn (memb ^?! exprBase)
&& (case memb ^?! exprMemberDeref of SimpleMember {} -> True; _ -> False)
= memb & exprMemberDeref .~ genMemberDeref
trfExpr name
| toTrf qn name
= genDerefExpr name
trfExpr other
= over uniplate trfExpr other
-- | Match the parent or the qualifier itself where changes need to be done
matchParentQual, matchQualItself :: QualifiedName -> Simple Traversal VariableDeclarationNI TypeQualifierNI
matchParentQual qn = varDeclQualTyp . qualTypQual . matchQualParent (qn ^. qnTypeQual)
matchQualItself qn = varDeclQualTyp . qualTypQual . matchQual (qn ^. qnTypeQual)
createSizeOfQual :: QualifiedTypeNI -> ExpressionNI
createSizeOfQual = undefined
-- | Removes indirection
removeIndirection :: QualifiedName -> TranslationUnitNI -> TranslationUnitNI
removeIndirection qn tu
= let declaration :: Simple Traversal TranslationUnitNI VariableDeclarationNI
declaration = biplate . checkScope qn . filterTrav (has (matchQualItself qn)) simple
exprs = biplate :: Simple Traversal TranslationUnitNI ExpressionNI
in case toListOf declaration tu of
[] -> error "No matching declaration for removing indirection"
[_] -> over exprs trfExpr $ over declaration trfDecl tu
_ -> error "Multiple matching declarations for removing indirection"
where trfDecl :: VariableDeclarationNI -> VariableDeclarationNI
trfDecl vd = vd & matchQualItself qn %~ (removePtrFromQual (vd ^? matchParentQual qn))
trfExpr :: ExpressionNI -> ExpressionNI
trfExpr memb@(Member{})
| case memb ^?! exprMemberDeref of
DerefMember {} -> fmap (view qnTypeQual) (getQualName (memb ^?! exprBase))
== Just (removePtrFromQual Nothing (qn ^. qnTypeQual))
SimpleMember {} -> False
= memb & exprMemberDeref .~ genMemberSimple
trfExpr un
| Just (DereferenceOp {}) <- un ^? exprUnaryOp
, Just name <- un ^? exprOperand
, toTrf qn un
= name
trfExpr other
= over uniplate trfExpr other
-- | Check that the element is in the scope we search for
checkScope qn = filterTrav (((==) `on` view qnScope . simplifyQualName) qn)
(info.semanticInfo.declQualName._Just)
-- | Check that the elem is the element we want to transform
toTrf qn elem
| Just qualName <- getQualName elem
= simplifyQualName qualName == simplifyQualName qn
| otherwise
= False
getQualName elem = (join (elem ^? info.semanticInfo.referenceQualName)
<|> join (elem ^? info.semanticInfo.declQualName))
-- | Creates a skeleton file, a file where only declarations are kept.
createSkeleton :: TranslationUnitNI -> TranslationUnitNI
createSkeleton = transformOn (biplate :: Simple Traversal TranslationUnitNI StatementNI)
removeStatements
where removeStatements :: StatementNI -> StatementNI
removeStatements
= compoundStmts %~ astFilter hasDeclaration
hasDeclaration :: ASTEitherNI Declaration Statement
-> Maybe (ASTEitherNI Declaration Statement)
hasDeclaration (ASTLeft d) = Just (ASTLeft d)
hasDeclaration (ASTRight stmt)
= if null (universeOn (biplate :: Simple Traversal StatementNI DeclarationNI) stmt)
then Nothing
else Just (ASTRight (transform removeStatements stmt))
-- | Propagates additional information in the syntax tree
analyseAST :: TranslationUnitNI -> TranslationUnitNI
analyseAST = transformOn (biplate :: Simple Traversal TranslationUnitNI ExpressionNI)
additionalScopes
where additionalScopes expr@(Unary {})
| Just (DereferenceOp {}) <- expr ^? exprUnaryOp
, Just (Just qn) <- expr ^? exprOperand.refName
= expr & refName %~ (<|> Just (qn & qnTypeQual %~ addPtrToQual Nothing))
additionalScopes expr@(Indexing {})
| Just (Just qn) <- expr ^? exprBase.refName
= expr & refName %~ (<|> Just (qn & qnTypeQual %~ genArrayQual ))
additionalScopes expr@(NameExpr {})
| Just qn <- expr ^? exprIdent.refName
= expr & refName %~ (<|> qn)
-- additionalScopes expr@(Member {})
-- | Just qn <- expr ^? exprBase.refName
-- , Just deref <- expr ^? exprMemberDeref
-- = expr & refName %~ (<|> Just (qn & qnTypeQual %~ case deref of DerefMember {} -> addPtrToQual Nothing
-- SimpleMember {} -> id))
additionalScopes expr@(ParenExpr {})
| Just qn <- expr ^? parenExpr.refName
= expr & refName %~ (<|> qn)
additionalScopes expr = expr
refName :: ASTNode node NI => Lens' (node NI) (Maybe QualifiedName)
refName = info.semanticInfo.referenceQualName
$(makeLenses ''ProgramParams)