Mercurial > lcfOS
view python/c3/analyse.py @ 267:e7c8f7eb3f59
Added tag Working chain 1 for changeset 649884d9dc61
author | Windel Bouwman |
---|---|
date | Mon, 12 Aug 2013 20:14:47 +0200 |
parents | 7416c923a02a |
children | e64bae57cda8 |
line wrap: on
line source
import logging from .visitor import Visitor from .astnodes import * from .scope import Scope, topScope from .typecheck import theType class Analyzer: """ Context handling is done here. Scope is attached to the correct modules. This class checks names and references """ def __init__(self, diag): self.diag = diag self.logger = logging.getLogger('c3') def analyzePackage(self, pkg, packageProvider): self.logger.info('Checking package {}'.format(pkg.name)) self.ok = True visitor = Visitor() # Prepare top level scope: self.scopeStack = [topScope] modScope = Scope(self.CurrentScope) self.scopeStack.append(modScope) visitor.visit(pkg, self.enterScope, self.quitScope) del self.scopeStack # Handle imports: for i in pkg.imports: ip = packageProvider.getPackage(i) if not ip: self.error('Cannot import {}'.format(i)) continue for x in ip.declarations: modScope.addSymbol(x) visitor.visit(pkg, self.findRefs) visitor.visit(pkg, self.sanity) return self.ok def error(self, msg, loc=None): self.ok = False self.diag.error(msg, loc) @property def CurrentScope(self): return self.scopeStack[-1] # Scope creation: def addSymbol(self, sym): if self.CurrentScope.hasSymbol(sym.name): self.error('Redefinition of {0}'.format(sym.name), sym.loc) else: self.CurrentScope.addSymbol(sym) def enterScope(self, sym): # Distribute the scope: sym.scope = self.CurrentScope # Add symbols to current scope: if isinstance(sym, Symbol) or isinstance(sym, DefinedType): self.addSymbol(sym) # Create subscope: if type(sym) in [Package, Function]: newScope = Scope(self.CurrentScope) self.scopeStack.append(newScope) sym.innerScope = self.CurrentScope def quitScope(self, sym): # Pop out of scope: if type(sym) in [Package, Function]: self.scopeStack.pop(-1) # Reference fixups: def resolveDesignator(self, d, scope): assert type(d) is Designator, type(d) assert type(scope) is Scope if scope.hasSymbol(d.tname): s = scope.getSymbol(d.tname) if hasattr(s, 'addRef'): # TODO: make this nicer s.addRef(None) return s else: self.ok = False msg = 'Cannot resolve name {0}'.format(d.tname) self.diag.error(msg, d.loc) def resolveType(self, t, scope): # TODO: what about structs? if type(t) is PointerType: t.ptype = self.resolveType(t.ptype, scope) return t elif type(t) is StructureType: offset = 0 for mem in t.mems: mem.offset = offset mem.typ = self.resolveType(mem.typ, scope) offset += theType(mem.typ).bytesize t.bytesize = offset return t elif type(t) is Designator: t = self.resolveDesignator(t, scope) if t: return self.resolveType(t, scope) elif isinstance(t, Type): # Already resolved?? return t else: raise Exception('Error resolving type {} {}'.format(t, type(t))) def findRefs(self, sym): if type(sym) in [Variable, Constant]: sym.typ = self.resolveType(sym.typ, sym.scope) elif type(sym) is TypeCast: sym.to_type = self.resolveType(sym.to_type, sym.scope) elif type(sym) is VariableUse: sym.target = self.resolveDesignator(sym.target, sym.scope) elif type(sym) is FunctionCall: varuse = sym.proc sym.proc = self.resolveDesignator(varuse.target, sym.scope) elif type(sym) is Function: # Checkup function type: ft = sym.typ ft.returntype = self.resolveType(ft.returntype, sym.scope) ft.parametertypes = [self.resolveType(pt, sym.scope) for pt in ft.parametertypes] elif type(sym) is DefinedType: sym.typ = self.resolveType(sym.typ, sym.scope) def sanity(self, sym): if type(sym) is FunctionType: pass elif type(sym) is Function: pass