From 995d0de9bbb0b36664456605e2e81582492bc9a6 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 13 Aug 2009 21:22:55 -0500 Subject: [PATCH] bug 510344: each translation unit needs its own symbol table. also fixed some parser error reporting and removed debugging |print|s --- ipc/ipdl/ipdl/cxx/ast.py | 1 - ipc/ipdl/ipdl/cxx/cgen.py | 1 - ipc/ipdl/ipdl/parser.py | 29 +++++++++------ ipc/ipdl/ipdl/type.py | 78 +++++++++++++++++++-------------------- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/ipc/ipdl/ipdl/cxx/ast.py b/ipc/ipdl/ipdl/cxx/ast.py index bb639bea226..9b0c3025eda 100644 --- a/ipc/ipdl/ipdl/cxx/ast.py +++ b/ipc/ipdl/ipdl/cxx/ast.py @@ -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): diff --git a/ipc/ipdl/ipdl/cxx/cgen.py b/ipc/ipdl/ipdl/cxx/cgen.py index a69aa52f04b..3bff336a884 100644 --- a/ipc/ipdl/ipdl/cxx/cgen.py +++ b/ipc/ipdl/ipdl/cxx/cgen.py @@ -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): diff --git a/ipc/ipdl/ipdl/parser.py b/ipc/ipdl/ipdl/parser.py index afd112f54bf..0c1536dc92b 100644 --- a/ipc/ipdl/ipdl/parser.py +++ b/ipc/ipdl/ipdl/parser.py @@ -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) diff --git a/ipc/ipdl/ipdl/type.py b/ipc/ipdl/ipdl/type.py index 18d37b463a5..370e4ce04a7 100644 --- a/ipc/ipdl/ipdl/type.py +++ b/ipc/ipdl/ipdl/type.py @@ -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):