зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
e0aa6caead
Коммит
995d0de9bb
|
@ -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):
|
||||
|
|
Загрузка…
Ссылка в новой задаче