Blob Blame History Raw
From 192d922697726dc59c7af1480a04e9fcd022cffc Mon Sep 17 00:00:00 2001
From: David Beazley <dave@dabeaz.com>
Date: Thu, 7 May 2015 15:53:44 -0500
Subject: [PATCH 1/2] Fixed issue 63

---
 CHANGES     |  6 ++++++
 ply/lex.py  | 41 ++++++++++++++++++++++-------------------
 ply/yacc.py | 30 +++++++++++++++++++-----------
 3 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/CHANGES b/CHANGES
index fdda63fccbecd1fea842a517b12439a6706c8c16..91800a4d35d096be013fdb22436bb3cd24b695d9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
+Version 3.7
+---------------------
+05/07/15: beazley
+          Fixed regression in handling of table modules if specified as module
+          objects.   See https://github.com/dabeaz/ply/issues/63
+
 Version 3.6
 ---------------------
 04/25/15: beazley
           If PLY is unable to create the 'parser.out' or 'parsetab.py' files due
           to permission issues, it now just issues a warning message and
diff --git a/ply/lex.py b/ply/lex.py
index 8ba2051d4a75af219118023ca3551afc5931dd4b..ed1e2ed9d965500afa405791cdd5d4e1f5ca7775 100644
--- a/ply/lex.py
+++ b/ply/lex.py
@@ -169,11 +169,14 @@ class Lexer:
         return c
 
     # ------------------------------------------------------------
     # writetab() - Write lexer information to a table file
     # ------------------------------------------------------------
-    def writetab(self, basetabmodule, outputdir=''):
+    def writetab(self, lextab, outputdir=''):
+        if isinstance(lextab, types.ModuleType):
+            raise IOError("Won't overwrite existing lextab module")
+        basetabmodule = lextab.split('.')[-1]
         filename = os.path.join(outputdir, basetabmodule) + '.py'
         with open(filename, 'w') as tf:
             tf.write('# %s.py. This file automatically created by PLY (version %s). Don\'t edit!\n' % (basetabmodule, __version__))
             tf.write('_tabversion   = %s\n' % repr(__tabversion__))
             tf.write('_lextokens    = %s\n' % repr(self.lextokens))
@@ -883,33 +886,17 @@ def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab',
         if '__file__' not in ldict:
             ldict['__file__'] = sys.modules[ldict['__module__']].__file__
     else:
         ldict = get_caller_module_dict(2)
 
-    if outputdir is None:
-        # If no output directory is set, the location of the output files
-        # is determined according to the following rules:
-        #     - If lextab specifies a package, files go into that package directory
-        #     - Otherwise, files go in the same directory as the specifying module
-        if '.' not in lextab:
-            srcfile = ldict['__file__']
-        else:
-            parts = lextab.split('.')
-            pkgname = '.'.join(parts[:-1])
-            exec('import %s' % pkgname)
-            srcfile = getattr(sys.modules[pkgname], '__file__', '')
-        outputdir = os.path.dirname(srcfile)
-
     # Determine if the module is package of a package or not.
     # If so, fix the tabmodule setting so that tables load correctly
     pkg = ldict.get('__package__')
-    if pkg:
+    if pkg and isinstance(lextab, str):
         if '.' not in lextab:
             lextab = pkg + '.' + lextab
 
-    baselextab = lextab.split('.')[-1]
-
     # Collect parser information from the dictionary
     linfo = LexerReflect(ldict, log=errorlog, reflags=reflags)
     linfo.get_all()
     if not optimize:
         if linfo.validate_all():
@@ -1027,12 +1014,28 @@ def lex(module=None, object=None, debug=False, optimize=False, lextab='lextab',
     input = lexobj.input
     lexer = lexobj
 
     # If in optimize mode, we write the lextab
     if lextab and optimize:
+        if outputdir is None:
+            # If no output directory is set, the location of the output files
+            # is determined according to the following rules:
+            #     - If lextab specifies a package, files go into that package directory
+            #     - Otherwise, files go in the same directory as the specifying module
+            if isinstance(lextab, types.ModuleType):
+                srcfile = lextab.__file__
+            else:
+                if '.' not in lextab:
+                    srcfile = ldict['__file__']
+                else:
+                    parts = lextab.split('.')
+                    pkgname = '.'.join(parts[:-1])
+                    exec('import %s' % pkgname)
+                    srcfile = getattr(sys.modules[pkgname], '__file__', '')
+            outputdir = os.path.dirname(srcfile)
         try:
-            lexobj.writetab(baselextab, outputdir)
+            lexobj.writetab(lextab, outputdir)
         except IOError as e:
             errorlog.warning("Couldn't write lextab module %r. %s" % (lextab, e))
 
     return lexobj
 
diff --git a/ply/yacc.py b/ply/yacc.py
index f18e3ebbe596dd8eb833db9065cffe90d045c9f5..e0b4fafc9e2dca050b4d7311324b6b16aa9bd3bf 100644
--- a/ply/yacc.py
+++ b/ply/yacc.py
@@ -2690,11 +2690,15 @@ class LRGeneratedTable(LRTable):
     # write()
     #
     # This function writes the LR parsing tables to a file
     # -----------------------------------------------------------------------------
 
-    def write_table(self, basemodulename, outputdir='', signature=''):
+    def write_table(self, tabmodule, outputdir='', signature=''):
+        if isinstance(tabmodule, types.ModuleType):
+            raise IOError("Won't overwrite existing tabmodule")
+
+        basemodulename = tabmodule.split('.')[-1]
         filename = os.path.join(outputdir, basemodulename) + '.py'
         try:
             f = open(filename, 'w')
 
             f.write('''
@@ -3202,26 +3206,30 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star
     if outputdir is None:
         # If no output directory is set, the location of the output files
         # is determined according to the following rules:
         #     - If tabmodule specifies a package, files go into that package directory
         #     - Otherwise, files go in the same directory as the specifying module
-        if '.' not in tabmodule:
-            srcfile = pdict['__file__']
+        if isinstance(tabmodule, types.ModuleType):
+            srcfile = tabmodule.__file__
         else:
-            parts = tabmodule.split('.')
-            pkgname = '.'.join(parts[:-1])
-            exec('import %s' % pkgname)
-            srcfile = getattr(sys.modules[pkgname], '__file__', '')
+            if '.' not in tabmodule:
+                srcfile = pdict['__file__']
+            else:
+                parts = tabmodule.split('.')
+                pkgname = '.'.join(parts[:-1])
+                exec('import %s' % pkgname)
+                srcfile = getattr(sys.modules[pkgname], '__file__', '')
         outputdir = os.path.dirname(srcfile)
 
     # Determine if the module is package of a package or not.
     # If so, fix the tabmodule setting so that tables load correctly
     pkg = pdict.get('__package__')
-    if pkg and '.' not in tabmodule:
-        tabmodule = pkg + '.' + tabmodule
+    if pkg and isinstance(tabmodule, str):
+        if '.' not in tabmodule:
+            tabmodule = pkg + '.' + tabmodule
+
 
-    basetabmodule = tabmodule.split('.')[-1]
 
     # Set start symbol if it's specified directly using an argument
     if start is not None:
         pdict['start'] = start
 
@@ -3430,11 +3438,11 @@ def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, star
                 warned_never.append(rejected)
 
     # Write the table file if requested
     if write_tables:
         try:
-            lr.write_table(basetabmodule, outputdir, signature)
+            lr.write_table(tabmodule, outputdir, signature)
         except IOError as e:
             errorlog.warning("Couldn't create %r. %s" % (tabmodule, e))
 
     # Write a pickled version of the tables
     if picklefile:
-- 
2.4.3