view python/c3/analyse.py @ 227:82dfe6a32717

Fixed tests
author Windel Bouwman
date Fri, 12 Jul 2013 17:42:39 +0200
parents 240111e0456f
children 521567d17388
line wrap: on
line source

from .visitor import Visitor
from .astnodes import *
from .scope import Scope, topScope

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

    def analyzePackage(self, pkg):
        self.ok = True
        visitor = Visitor()
        # Prepare top level scope:
        self.scopeStack = [topScope]
        visitor.visit(pkg, self.enterScope, self.quitScope)
        del self.scopeStack
        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):
            self.addSymbol(sym)
        if 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:
            for mem in t.mems:
                mem.typ = self.resolveType(mem.typ, scope)
            return t
        elif type(t) is Designator:
            t = self.resolveDesignator(t, scope)
            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