From: Robert Bradshaw Date: Tue, 30 Sep 2008 02:08:45 +0000 (-0700) Subject: Refactoring of type parsing X-Git-Tag: 0.9.9.2.beta~80 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=231240e19e2e3cc8aa0e8431747e33b8618f793e;p=cython.git Refactoring of type parsing This paves the way for "cimport *" cimporting types, as well as other simplifications. --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index bcd29039..d7ea1d11 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -289,6 +289,11 @@ class ExprNode(Node): # If this node can be interpreted as a reference to a # cimported module, return its scope, else None. return None + + def analyse_as_type(self, env): + # If this node can be interpreted as a reference to a + # type, return that type, else None. + return None def analyse_as_extension_type(self, env): # If this node can be interpreted as a reference to an @@ -879,6 +884,15 @@ class NameNode(AtomicExprNode): if entry and entry.as_module: return entry.as_module return None + + def analyse_as_type(self, env): + entry = self.entry + if not entry: + entry = env.lookup(self.name) + if entry and entry.is_type: + return entry.type + else: + return None def analyse_as_extension_type(self, env): # Try to interpret this as a reference to an extension type. @@ -1362,6 +1376,12 @@ class IndexNode(ExprNode): def analyse_target_declaration(self, env): pass + + def analyse_as_type(self, env): + base_type = self.base.analyse_as_type(env) + if base_type and not base_type.is_pyobject: + return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env))) + return None def analyse_types(self, env): self.analyse_base_and_index_types(env, getting = 1) @@ -2182,6 +2202,14 @@ class AttributeNode(ExprNode): self.mutate_into_name_node(env, ubcm_entry, None) return 1 return 0 + + def analyse_as_type(self, env): + module_scope = self.obj.analyse_as_module(env) + if module_scope: + entry = module_scope.lookup_here(self.attribute) + if entry and entry.is_type: + return entry.type + return None def analyse_as_extension_type(self, env): # Try to interpret this as a reference to an extension type @@ -3107,6 +3135,8 @@ class TypecastNode(ExprNode): class SizeofNode(ExprNode): # Abstract base class for sizeof(x) expression nodes. + + type = PyrexTypes.c_int_type def check_const(self): pass @@ -3126,7 +3156,7 @@ class SizeofTypeNode(SizeofNode): def analyse_types(self, env): # we may have incorrectly interpreted a dotted name as a type rather than an attribute # this could be better handled by more uniformly treating types as runtime-available objects - if self.base_type.module_path: + if self.base_type.module_path and 0: path = self.base_type.module_path obj = env.lookup(path[0]) if obj.as_module is None: @@ -3141,13 +3171,16 @@ class SizeofTypeNode(SizeofNode): base_type = self.base_type.analyse(env) _, arg_type = self.declarator.analyse(base_type, env) self.arg_type = arg_type + self.check_type() + + def check_type(self): + arg_type = self.arg_type if arg_type.is_pyobject and not arg_type.is_extension_type: error(self.pos, "Cannot take sizeof Python object") elif arg_type.is_void: error(self.pos, "Cannot take sizeof void") elif not arg_type.is_complete(): error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type) - self.type = PyrexTypes.c_int_type def calculate_result_code(self): if self.arg_type.is_extension_type: @@ -3167,8 +3200,15 @@ class SizeofVarNode(SizeofNode): subexprs = ['operand'] def analyse_types(self, env): - self.operand.analyse_types(env) - self.type = PyrexTypes.c_int_type + # We may actually be looking at a type rather than a variable... + # If we are, traditional analysis would fail... + operand_as_type = self.operand.analyse_as_type(env) + if operand_as_type: + self.arg_type = operand_as_type + self.__class__ = SizeofTypeNode + self.check_type() + else: + self.operand.analyse_types(env) def calculate_result_code(self): return "(sizeof(%s))" % self.operand.result() diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 415c29b9..d8e7f2e9 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -250,7 +250,10 @@ def p_sizeof(s): pos = s.position() s.next() s.expect('(') - if looking_at_type(s) or looking_at_dotted_name(s): + # Here we decide if we are looking at an expression or type + # If it is actually a type, but parsable as an expression, + # we treat it as an expression here. + if looking_at_type(s): base_type = p_c_base_type(s) declarator = p_c_declarator(s, empty = 1) node = ExprNodes.SizeofTypeNode(pos, @@ -1030,7 +1033,13 @@ def p_from_import_statement(s, first_statement = 0): elif kind == 'cimport': for (name_pos, name, as_name, kind) in imported_names: local_name = as_name or name - s.add_type_name(local_name) + if local_name == "*" and False: + print s.__dict__.keys() + module = s.context.find_module(dotted_name) + for type in module.type_entries: + s.add_type_name(type.name) + else: + s.add_type_name(local_name) return Nodes.FromCImportStatNode(pos, module_name = dotted_name, imported_names = imported_names) @@ -1619,7 +1628,15 @@ def p_c_simple_base_type(s, self_flag, nonempty): s.next() else: name = 'int' - elif s.looking_at_type_name(): + elif looking_at_dotted_name(s): + #print "p_c_simple_base_type: looking_at_type_name at", s.position() + name = s.systring + s.next() + while s.sy == '.': + module_path.append(name) + s.next() + name = p_ident(s) + elif s.looking_at_type_name(): # looking_at_type(s): name = s.systring s.next() if nonempty and s.sy != 'IDENT': @@ -1636,14 +1653,6 @@ def p_c_simple_base_type(s, self_flag, nonempty): elif s.sy not in ('*', '**', '['): s.put_back('IDENT', name) name = None - elif looking_at_dotted_name(s): - #print "p_c_simple_base_type: looking_at_type_name at", s.position() - name = s.systring - s.next() - while s.sy == '.': - module_path.append(name) - s.next() - name = p_ident(s) else: #print "p_c_simple_base_type: not looking at type at", s.position() name = None @@ -1687,8 +1696,45 @@ def p_buffer_access(s, base_type_node): return result +def looking_at_possible_type(s): + return s.sy == 'IDENT' and not s.systring in calling_convention_words +# return looking_at_base_type(s) or s.looking_at_type_name() + def looking_at_type(s): - return looking_at_base_type(s) or s.looking_at_type_name() + if s.systring in base_type_start_words: + return True + elif s.sy == 'IDENT': + is_type = False + name = s.systring + dotted_path = [] + s.next() + while s.sy == '.': + s.next() + dotted_path.append(s.systring) + s.expect('IDENT') + saved = s.sy, s.systring + if s.sy == '*' or s.sy == '**': + s.next() + is_type = s.sy == ')' + s.put_back(*saved) + elif s.sy == '(': + s.next() + is_type = s.sy == '*' + s.put_back(*saved) + elif s.sy == '[': + s.next() + is_type = s.sy == ']' + s.put_back(*saved) + elif s.sy == 'IDENT': + is_type = True + dotted_path.reverse() + for p in dotted_path: + s.put_back('IDENT', p) + s.put_back('.', '.') + s.put_back('IDENT', name) + return is_type + else: + return False def looking_at_base_type(s): #print "looking_at_base_type?", s.sy, s.systring, s.position() @@ -1703,7 +1749,7 @@ def looking_at_dotted_name(s): return result else: return 0 - + basic_c_type_names = ("void", "char", "int", "float", "double", "Py_ssize_t", "bint") sign_and_longness_words = ("short", "long", "signed", "unsigned") @@ -1744,7 +1790,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0, pos = s.position() if s.sy == '(': s.next() - if s.sy == ')' or looking_at_type(s): + if s.sy == ')' or looking_at_possible_type(s): base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None) result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag) else: diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 35ce1c17..ec41d83d 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -313,6 +313,7 @@ class Scope: entry.is_type = 1 if defining: self.type_entries.append(entry) + # here we would set as_variable to an object representing this type return entry def declare_typedef(self, name, base_type, pos, cname = None, diff --git a/tests/run/sizeof.pyx b/tests/run/sizeof.pyx index f2832cd7..3360273f 100644 --- a/tests/run/sizeof.pyx +++ b/tests/run/sizeof.pyx @@ -11,4 +11,9 @@ def f(): i = sizeof(p) i = sizeof(j + k) i = sizeof(int) + i = sizeof(long int) + i = sizeof(void*) i = sizeof(Spam) + i = sizeof(Spam*) + i = sizeof(Spam[5]) + i = sizeof(Spam (*)())