comparison python/c3/analyse.py @ 288:a747a45dcd78

Various styling work
author Windel Bouwman
date Thu, 21 Nov 2013 14:26:13 +0100
parents 1c7c1e619be8
children bd2593de3ff8
comparison
equal deleted inserted replaced
287:1c7c1e619be8 288:a747a45dcd78
2 from .visitor import Visitor 2 from .visitor import Visitor
3 from .astnodes import * 3 from .astnodes import *
4 from .scope import * 4 from .scope import *
5 5
6 6
7 class Analyzer: 7 class C3Pass:
8 """
9 Context handling is done here.
10 Scope is attached to the correct modules.
11 This class checks names and references.
12 """
13 def __init__(self, diag): 8 def __init__(self, diag):
14 self.diag = diag 9 self.diag = diag
15 self.logger = logging.getLogger('c3') 10 self.logger = logging.getLogger('c3')
16
17 def analyzePackage(self, pkg, packageProvider):
18 self.logger.info('Checking package {}'.format(pkg.name))
19 self.ok = True 11 self.ok = True
20 visitor = Visitor() 12 self.visitor = Visitor()
13
14 def error(self, msg, loc=None):
15 self.ok = False
16 self.diag.error(msg, loc)
17
18 def visit(self, pkg, pre, post):
19 self.visitor.visit(pkg, pre, post)
20
21
22 class AddScope(C3Pass):
23 """ Scope is attached to the correct modules. """
24 def addScope(self, pkg):
25 self.logger.info('Adding scoping to package {}'.format(pkg.name))
21 # Prepare top level scope and set scope to all objects: 26 # Prepare top level scope and set scope to all objects:
22 self.scopeStack = [topScope] 27 self.scopeStack = [topScope]
23 modScope = Scope(self.CurrentScope) 28 modScope = Scope(self.CurrentScope)
24 self.scopeStack.append(modScope) 29 self.scopeStack.append(modScope)
25 visitor.visit(pkg, self.enterScope, self.quitScope) 30 self.visit(pkg, self.enterScope, self.quitScope)
26 del self.scopeStack 31 assert len(self.scopeStack) == 2
27
28 # Handle imports:
29 for i in pkg.imports:
30 ip = packageProvider.getPackage(i)
31 if not ip:
32 self.error('Cannot import {}'.format(i))
33 continue
34 for x in ip.declarations:
35 modScope.addSymbol(x)
36 visitor.visit(pkg, self.findRefs)
37 return self.ok 32 return self.ok
38
39 def error(self, msg, loc=None):
40 self.ok = False
41 self.diag.error(msg, loc)
42 33
43 @property 34 @property
44 def CurrentScope(self): 35 def CurrentScope(self):
45 return self.scopeStack[-1] 36 return self.scopeStack[-1]
46 37
47 # Scope creation:
48 def addSymbol(self, sym): 38 def addSymbol(self, sym):
49 if self.CurrentScope.hasSymbol(sym.name): 39 if self.CurrentScope.hasSymbol(sym.name):
50 self.error('Redefinition of {0}'.format(sym.name), sym.loc) 40 self.error('Redefinition of {0}'.format(sym.name), sym.loc)
51 else: 41 else:
52 self.CurrentScope.addSymbol(sym) 42 self.CurrentScope.addSymbol(sym)
67 57
68 def quitScope(self, sym): 58 def quitScope(self, sym):
69 # Pop out of scope: 59 # Pop out of scope:
70 if type(sym) in [Package, Function]: 60 if type(sym) in [Package, Function]:
71 self.scopeStack.pop(-1) 61 self.scopeStack.pop(-1)
62
63
64 class Analyzer(C3Pass):
65 """
66 Context handling is done here.
67 Scope is attached to the correct modules.
68 This class checks names and references.
69 """
70
71 def analyzePackage(self, pkg, packageDict):
72 self.ok = True
73 # Prepare top level scope and set scope to all objects:
74 AddScope(self.diag).addScope(pkg)
75
76 self.logger.info('Resolving imports for package {}'.format(pkg.name))
77 # Handle imports:
78 for i in pkg.imports:
79 ip = packageDict[i]
80 if not ip:
81 self.error('Cannot import {}'.format(i))
82 continue
83 pkg.scope.addSymbol(ip)
84 FixRefs(self.diag).fixRefs(pkg)
85 return self.ok
86
87
88 class FixRefs(C3Pass):
89 def fixRefs(self, pkg):
90 self.visitor.visit(pkg, self.findRefs)
72 91
73 # Reference fixups: 92 # Reference fixups:
74 def resolveDesignator(self, d, scope): 93 def resolveDesignator(self, d, scope):
75 assert type(d) is Designator, type(d) 94 assert type(d) is Designator, type(d)
76 assert type(scope) is Scope 95 assert type(scope) is Scope
117 sym.proc = self.resolveDesignator(varuse.target, sym.scope) 136 sym.proc = self.resolveDesignator(varuse.target, sym.scope)
118 elif type(sym) is Function: 137 elif type(sym) is Function:
119 # Checkup function type: 138 # Checkup function type:
120 ft = sym.typ 139 ft = sym.typ
121 ft.returntype = self.resolveType(ft.returntype, sym.scope) 140 ft.returntype = self.resolveType(ft.returntype, sym.scope)
122 ft.parametertypes = [self.resolveType(pt, sym.scope) for pt in ft.parametertypes] 141 ft.parametertypes = [self.resolveType(pt, sym.scope) for pt in
142 ft.parametertypes]
123 # Mark local variables: 143 # Mark local variables:
124 for d in sym.declarations: 144 for d in sym.declarations:
125 if isinstance(d, Variable): 145 if isinstance(d, Variable):
126 d.isLocal = True 146 d.isLocal = True
127 elif type(sym) is DefinedType: 147 elif type(sym) is DefinedType:
128 sym.typ = self.resolveType(sym.typ, sym.scope) 148 sym.typ = self.resolveType(sym.typ, sym.scope)
129 149
150
130 # Type checking: 151 # Type checking:
131 152
132 def theType(t): 153 def theType(t):
133 """ 154 """ Recurse until a 'real' type is found """
134 Recurse until a 'real' type is found
135 """
136 if type(t) is DefinedType: 155 if type(t) is DefinedType:
137 return theType(t.typ) 156 return theType(t.typ)
138 return t 157 return t
139 158
159
140 def equalTypes(a, b): 160 def equalTypes(a, b):
141 """ 161 """ Compare types a and b for structural equavalence. """
142 Compare types a and b for equality.
143 Not equal until proven otherwise.
144 """
145 # Recurse into named types: 162 # Recurse into named types:
146 a = theType(a) 163 a, b = theType(a), theType(b)
147 b = theType(b) 164
148
149 # Compare for structural equivalence:
150 if type(a) is type(b): 165 if type(a) is type(b):
151 if type(a) is BaseType: 166 if type(a) is BaseType:
152 return a.name == b.name 167 return a.name == b.name
153 elif type(a) is PointerType: 168 elif type(a) is PointerType:
154 return equalTypes(a.ptype, b.ptype) 169 return equalTypes(a.ptype, b.ptype)
155 elif type(a) is StructureType: 170 elif type(a) is StructureType:
156 if len(a.mems) != len(b.mems): 171 if len(a.mems) != len(b.mems):
157 return False 172 return False
158 for amem, bmem in zip(a.mems, b.mems): 173 return all(equalTypes(am.typ, bm.typ) for am, bm in
159 if not equalTypes(amem.typ, bmem.typ): 174 zip(a.mems, b.mems))
160 return False 175 else:
161 return True 176 raise NotImplementedError(
162 else: 177 'Type compare for {} not implemented'.format(type(a)))
163 raise Exception('Type compare for {} not implemented'.format(type(a)))
164 return False 178 return False
179
165 180
166 def canCast(fromT, toT): 181 def canCast(fromT, toT):
167 fromT = theType(fromT) 182 fromT = theType(fromT)
168 toT = theType(toT) 183 toT = theType(toT)
169 if isinstance(fromT, PointerType) and isinstance(toT, PointerType): 184 if isinstance(fromT, PointerType) and isinstance(toT, PointerType):
170 return True 185 return True
171 elif fromT is intType and isinstance(toT, PointerType): 186 elif fromT is intType and isinstance(toT, PointerType):
172 return True 187 return True
173 return False 188 return False
174 189
190
175 def expectRval(s): 191 def expectRval(s):
176 # TODO: solve this better 192 # TODO: solve this better
177 s.expect_rvalue = True 193 s.expect_rvalue = True
178 194
179 class TypeChecker: 195
180 def __init__(self, diag): 196 class TypeChecker(C3Pass):
181 self.diag = diag
182
183 def error(self, msg, loc):
184 """
185 Wrapper that registers the message and marks the result invalid
186 """
187 self.diag.error(msg, loc)
188 self.ok = False
189
190 def checkPackage(self, pkg): 197 def checkPackage(self, pkg):
191 self.ok = True 198 self.ok = True
192 visitor = Visitor() 199 self.visit(pkg, None, self.check2)
193 visitor.visit(pkg, f_post=self.check2)
194 return self.ok 200 return self.ok
195 201
196 def check2(self, sym): 202 def check2(self, sym):
197 if type(sym) in [IfStatement, WhileStatement]: 203 if type(sym) in [IfStatement, WhileStatement]:
198 if not equalTypes(sym.condition.typ, boolType): 204 if not equalTypes(sym.condition.typ, boolType):