Mercurial > lcfOS
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): |