pre-Py3k fixes
[cython.git] / Cython / Compiler / Scanning.py
index d57137626964a57255f2908ec3df011ee924ea7e..e48c8dcea590480bf5c5778ed99f473860579903 100644 (file)
@@ -6,6 +6,7 @@
 import cPickle as pickle
 
 import os
+import platform
 import stat
 import sys
 from time import time
@@ -41,7 +42,7 @@ def hash_source_file(path):
             f = open(path, "rU")
             text = f.read()
         except IOError, e:
-            print "Unable to hash scanner source file (%s)" % e
+            print("Unable to hash scanner source file (%s)" % e)
             return ""
     finally:
         f.close()
@@ -68,12 +69,12 @@ def open_pickled_lexicon(expected_hash):
                 result = f
                 f = None
             else:
-                print "Lexicon hash mismatch:" ###
-                print "   expected", expected_hash ###
-                print "   got     ", actual_hash ###
+                print("Lexicon hash mismatch:")       ###
+                print("   expected " + expected_hash) ###
+                print("   got     " + actual_hash)    ###
         except IOError, e:
-            print "Warning: Unable to read pickled lexicon", lexicon_pickle
-            print e
+            print("Warning: Unable to read pickled lexicon " + lexicon_pickle)
+            print(e)
     if f:
         f.close()
     return result
@@ -88,37 +89,37 @@ def try_to_unpickle_lexicon():
     if f:
         if notify_lexicon_unpickling:
             t0 = time()
-            print "Unpickling lexicon..."
+            print("Unpickling lexicon...")
         lexicon = pickle.load(f)
         f.close()
         if notify_lexicon_unpickling:
             t1 = time()
-            print "Done (%.2f seconds)" % (t1 - t0)
+            print("Done (%.2f seconds)" % (t1 - t0))
 
 def create_new_lexicon():
     global lexicon
     t0 = time()
-    print "Creating lexicon..."
+    print("Creating lexicon...")
     lexicon = make_lexicon()
     t1 = time()
-    print "Done (%.2f seconds)" % (t1 - t0)
+    print("Done (%.2f seconds)" % (t1 - t0))
 
 def pickle_lexicon():
     f = None
     try:
         f = open(lexicon_pickle, "wb")
     except IOError:
-        print "Warning: Unable to save pickled lexicon in", lexicon_pickle
+        print("Warning: Unable to save pickled lexicon in " + lexicon_pickle)
     if f:
         if notify_lexicon_pickling:
             t0 = time()
-            print "Pickling lexicon..."
+            print("Pickling lexicon...")
         pickle.dump(lexicon_hash, f, binary_lexicon_pickle)
         pickle.dump(lexicon, f, binary_lexicon_pickle)
         f.close()
         if notify_lexicon_pickling:
             t1 = time()
-            print "Done (%.2f seconds)" % (t1 - t0)
+            print("Done (%.2f seconds)" % (t1 - t0))
 
 def get_lexicon():
     global lexicon
@@ -138,7 +139,7 @@ reserved_words = [
     "raise", "import", "exec", "try", "except", "finally",
     "while", "if", "elif", "else", "for", "in", "assert",
     "and", "or", "not", "is", "in", "lambda", "from",
-    "NULL", "cimport", "by", "withGIL"
+    "NULL", "cimport", "by", "with", "cpdef", "DEF", "IF", "ELIF", "ELSE"
 ]
 
 class Method:
@@ -160,7 +161,53 @@ def build_resword_dict():
 
 #------------------------------------------------------------------
 
+class CompileTimeScope(object):
+
+    def __init__(self, outer = None):
+        self.entries = {}
+        self.outer = outer
+    
+    def declare(self, name, value):
+        self.entries[name] = value
+    
+    def lookup_here(self, name):
+        return self.entries[name]
+    
+    def lookup(self, name):
+        try:
+            return self.lookup_here(name)
+        except KeyError:
+            outer = self.outer
+            if outer:
+                return outer.lookup(name)
+            else:
+                raise
+
+def initial_compile_time_env():
+    benv = CompileTimeScope()
+    names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE',
+        'UNAME_VERSION', 'UNAME_MACHINE')
+    for name, value in zip(names, platform.uname()):
+        benv.declare(name, value)
+    import __builtin__
+    names = ('False', 'True',
+        'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
+        'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
+        'oct', 'ord', 'pow', 'range', 'reduce', 'repr', 'round', 'slice', 'str',
+        'sum', 'tuple', 'xrange', 'zip')
+    for name in names:
+        benv.declare(name, getattr(__builtin__, name))
+    denv = CompileTimeScope(benv)
+    return denv
+
+#------------------------------------------------------------------
+
 class PyrexScanner(Scanner):
+    #  context            Context  Compilation context
+    #  type_names         set      Identifiers to be treated as type names
+    #  compile_time_env   dict     Environment for conditional compilation
+    #  compile_time_eval  boolean  In a true conditional compilation context
+    #  compile_time_expr  boolean  In a compile-time expression context
     
     resword_dict = build_resword_dict()
 
@@ -170,9 +217,15 @@ class PyrexScanner(Scanner):
         if parent_scanner:
             self.context = parent_scanner.context
             self.type_names = parent_scanner.type_names
+            self.compile_time_env = parent_scanner.compile_time_env
+            self.compile_time_eval = parent_scanner.compile_time_eval
+            self.compile_time_expr = parent_scanner.compile_time_expr
         else:
             self.context = context
             self.type_names = type_names
+            self.compile_time_env = initial_compile_time_env()
+            self.compile_time_eval = 1
+            self.compile_time_expr = 0
         self.trace = trace_scanner
         self.indentation_stack = [0]
         self.indentation_char = None
@@ -231,9 +284,9 @@ class PyrexScanner(Scanner):
                 self.indentation_char = c
                 #print "Scanner.indentation_action: setting indent_char to", repr(c)
             else:
-                if self.indentation_char <> c:
+                if self.indentation_char != c:
                     self.error("Mixed use of tabs and spaces")
-            if text.replace(c, "") <> "":
+            if text.replace(c, "") != "":
                 self.error("Mixed use of tabs and spaces")
         # Figure out how many indents/dedents to do
         current_level = self.current_level()
@@ -251,7 +304,7 @@ class PyrexScanner(Scanner):
                 self.indentation_stack.pop()
                 self.produce('DEDENT', '')
             #print "...current level now", self.current_level() ###
-            if new_level <> self.current_level():
+            if new_level != self.current_level():
                 self.error("Inconsistent indentation")
 
     def eof_action(self, text):
@@ -275,7 +328,7 @@ class PyrexScanner(Scanner):
                 t = self.sy
             else:
                 t = "%s %s" % (self.sy, self.systring)
-            print "--- %3d %2d %s" % (line, col, t)
+            print("--- %3d %2d %s" % (line, col, t))
     
     def put_back(self, sy, systring):
         self.unread(self.sy, self.systring)
@@ -303,10 +356,19 @@ class PyrexScanner(Scanner):
         if self.sy == what:
             self.next()
         else:
-            if message:
-                self.error(message)
-            else:
-                self.error("Expected '%s'" % what)
+            self.expected(what, message)
+    
+    def expect_keyword(self, what, message = None):
+        if self.sy == 'IDENT' and self.systring == what:
+            self.next()
+        else:
+            self.expected(what, message)
+    
+    def expected(self, what, message):
+        if message:
+            self.error(message)
+        else:
+            self.error("Expected '%s'" % what)
         
     def expect_indent(self):
         self.expect('INDENT',
@@ -316,7 +378,7 @@ class PyrexScanner(Scanner):
         self.expect('DEDENT',
             "Expected a decrease in indentation level")
 
-    def expect_newline(self, message):
+    def expect_newline(self, message = "Expected a newline"):
         # Expect either a newline or end of file
-        if self.sy <> 'EOF':
+        if self.sy != 'EOF':
             self.expect('NEWLINE', message)