bug 510344: each translation unit needs its own symbol table. also fixed some parser error reporting and removed debugging |print|s

This commit is contained in:
Chris Jones 2009-08-13 21:22:55 -05:00
Родитель bfa6bff11f
Коммит 3d6f398809
4 изменённых файлов: 55 добавлений и 54 удалений

Просмотреть файл

@ -308,7 +308,6 @@ class Inherit(Node):
class FriendClassDecl(Node):
def __init__(self, friend):
Node.__init__(self)
print "FriendClassDecl: %r" % friend
self.friend = friend
class MethodDecl(Node):

Просмотреть файл

@ -134,7 +134,6 @@ class CxxCodeGen(CodePrinter, Visitor):
self.write(inh.viz +' '+ inh.name)
def visitFriendClassDecl(self, fcd):
print >>sys.stderr, "visitFriendClassDecl: %r" % fcd
self.printdentln('friend class '+ fcd.friend +';')
def visitMethodDecl(self, md):

Просмотреть файл

@ -49,10 +49,20 @@ _thisdir, _ = os.path.split(_getcallerpath())
class ParseError(Exception):
def __init__(self, loc, fmt, *args):
self.loc = loc
self.error = ('%s: error: %s'% (loc, fmt)) % args
self.error = ('%s%s: error: %s'% (
Parser.includeStackString(), loc, fmt)) % args
def __str__(self):
return self.error
def _safeLinenoValue(t):
lineno, value = 0, '???'
if hasattr(t, 'lineno'): lineno = t.lineno
if hasattr(t, 'value'): value = t.value
return lineno, value
def _error(loc, fmt, *args):
raise ParseError(loc, fmt, *args)
class Parser:
# when we reach an |include protocol "foo.ipdl";| statement, we need to
# save the current parser state and create a new one. this "stack" is
@ -109,7 +119,7 @@ class Parser:
def resolveIncludePath(self, filepath):
'''Return the absolute path from which the possibly partial
|filepath| should be read, or |None| if |filepath| can't be located.'''
|filepath| should be read, or |None| if |filepath| cannot be located.'''
for incdir in self.includedirs +[ '' ]:
realpath = os.path.join(incdir, filepath)
if os.path.isfile(realpath):
@ -189,10 +199,8 @@ def t_STRING(t):
return t
def t_error(t):
includeStackStr = Parser.includeStackString()
raise ParseError(
Loc(Parser.current.filename, t.lineno),
"%s: lexically invalid characters `%s'"% (includeStackStr, t.value))
_error(Loc(Parser.current.filename, t.lineno),
'lexically invalid characters `%s', t.value)
##-----------------------------------------------------------------------------
@ -324,7 +332,7 @@ def p_MessageDirectionLabel(p):
def p_MessageDecl(p):
"""MessageDecl : OptionalSendSemanticsQual MessageBody"""
if Parser.current.direction is None:
p_error(p[1])
_error(locFromTok(p, 1), 'missing message direction')
if 2 == len(p):
msg = p[1]
@ -499,7 +507,6 @@ def p_CxxTemplateInst(p):
p[0] = (locFromTok(p, 1), str(p[1]) +'<'+ str(p[3]) +'>')
def p_error(t):
includeStackStr = Parser.includeStackString()
raise ParseError(
Loc(Parser.current.filename, t.lineno),
"%s: bad syntax near `%s'"% (includeStackStr, t.value))
lineno, value = _safeLinenoValue(t)
_error(Loc(Parser.current.filename, lineno),
"bad syntax near `%s'", value)

Просмотреть файл

@ -298,7 +298,6 @@ With this information, it finally type checks the AST.'''
# NB: no IPDL compile will EVER print a warning. A program has
# one of two attributes: it is either well typed, or not well typed.
self.errors = [ ] # [ string ]
self.symtab = SymbolTable(self.errors)
def check(self, tu, errout=sys.stderr):
def runpass(tcheckpass):
@ -312,15 +311,15 @@ With this information, it finally type checks the AST.'''
# tag each relevant node with "decl" information, giving type, name,
# and location of declaration
if not runpass(GatherDecls(builtinUsing, self.symtab, self.errors)):
if not runpass(GatherDecls(builtinUsing, self.errors)):
return False
# now that the nodes have decls, type checking is much easier.
if not runpass(CheckTypes(self.symtab, self.errors)):
if not runpass(CheckTypes(self.errors)):
return False
if (tu.protocol.startState is not None
and not runpass(CheckStateMachine(self.symtab, self.errors))):
and not runpass(CheckStateMachine(self.errors))):
return False
return True
@ -348,35 +347,35 @@ class TcheckVisitor(Visitor):
return d
class GatherDecls(TcheckVisitor):
def __init__(self, builtinUsing, symtab, errors):
TcheckVisitor.__init__(self, symtab, errors)
def __init__(self, builtinUsing, errors):
# |self.symtab| is the symbol table for the translation unit
# currently being visited
TcheckVisitor.__init__(self, None, errors)
self.builtinUsing = builtinUsing
self.depth = 0
def declareBuiltins(self):
for using in self.builtinUsing:
fullname = str(using.type)
if using.type.basename() == fullname:
fullname = None
using.decl = self.declareLocalGlobal(
loc=using.loc,
type=BuiltinCxxType(using.type.spec),
shortname=using.type.basename(),
fullname=fullname)
self.symtab.declare(using.decl)
def visitTranslationUnit(self, tu):
# all TranslationUnits declare symbols in global scope
if hasattr(tu, '_tchecked') and tu._tchecked:
if hasattr(tu, 'symtab'):
return
tu._tchecked = True
self.depth += 1
tu.symtab = SymbolTable(self.errors)
savedSymtab = self.symtab
self.symtab = tu.symtab
# bit of a hack here --- we want the builtin |using|
# statements to be added to the symbol table before anything
# else, but we also want them in the translation units' list
# of using stmts so that we can use them later down the pipe.
# so we add them to the symbol table before anything else, and
# prepend them to the TUs after visiting all their |using|
# decls
if 1 == self.depth:
for using in self.builtinUsing:
fullname = str(using.type)
if using.type.basename() == fullname:
fullname = None
using.decl = self.declare(
loc=using.loc,
type=BuiltinCxxType(using.type.spec),
shortname=using.type.basename(),
fullname=fullname)
# pretend like the translation unit "using"-ed these for the
# sake of type checking and C++ code generation
tu.using = self.builtinUsing + tu.using
p = tu.protocol
@ -400,26 +399,21 @@ class GatherDecls(TcheckVisitor):
for pinc in tu.protocolIncludes:
pinc.accept(self)
# each protocol has its own scope for types brought in through |using|
self.symtab.enterScope(tu)
# and for all imported C++ types
# declare imported (and builtin) C++ types
for using in tu.using:
using.accept(self)
# (see long comment above)
tu.using = self.builtinUsing + tu.using
# grab symbols in the protocol itself
p.accept(self)
self.symtab.exitScope(tu)
tu.type = VOID
self.depth -= 1
self.symtab = savedSymtab
def visitProtocolInclude(self, pi):
pi.tu.accept(self)
self.symtab.declare(pi.tu.protocol.decl)
def visitUsingStmt(self, using):
fullname = str(using.type)
@ -679,8 +673,9 @@ class GatherDecls(TcheckVisitor):
##-----------------------------------------------------------------------------
class CheckTypes(TcheckVisitor):
def __init__(self, symtab, errors):
TcheckVisitor.__init__(self, symtab, errors)
def __init__(self, errors):
# don't need the symbol table, we just want the error reporting
TcheckVisitor.__init__(self, None, errors)
self.visited = set()
def visitProtocolInclude(self, inc):
@ -797,8 +792,9 @@ class CheckTypes(TcheckVisitor):
##-----------------------------------------------------------------------------
class CheckStateMachine(TcheckVisitor):
def __init__(self, symtab, errors):
TcheckVisitor.__init__(self, symtab, errors)
def __init__(self, errors):
# don't need the symbol table, we just want the error reporting
TcheckVisitor.__init__(self, None, errors)
self.p = None
def visitProtocol(self, p):