Commit da0490ef authored by Xavier Thompson's avatar Xavier Thompson

Introduce 'frozen' and 'read' keywords

parent 0bb6f98b
...@@ -11399,16 +11399,15 @@ class ConsumeNode(ExprNode): ...@@ -11399,16 +11399,15 @@ class ConsumeNode(ExprNode):
error(self.pos, "Can only consume cypclass (not '%s')" % operand_type) error(self.pos, "Can only consume cypclass (not '%s')" % operand_type)
self.type = PyrexTypes.error_type self.type = PyrexTypes.error_type
return self return self
if operand_type.is_qualified_cyp_class: if operand_type.qualifier == 'frozen':
self.generate_runtime_check = operand_type.qualifier not in ('iso', 'iso~') error(self.pos, "Cannot consume '%s'" % operand_type)
self.check_refcount_only = operand_type.qualifier in ('active', 'lock', 'locked') self.type = PyrexTypes.error_type
if operand_type.qualifier == 'iso~': return self
self.type = operand_type self.generate_runtime_check = operand_type.qualifier not in ('iso', 'iso~')
else: self.check_refcount_only = operand_type.qualifier in ('active', 'lock', 'locked')
self.type = PyrexTypes.cyp_class_qualified_type(operand_type.qual_base_type, 'iso~') if operand_type.qualifier == 'iso~':
self.type = operand_type
else: else:
self.generate_runtime_check = True
self.check_refcount_only = False
self.type = PyrexTypes.cyp_class_qualified_type(operand_type, 'iso~') self.type = PyrexTypes.cyp_class_qualified_type(operand_type, 'iso~')
solid_operand = self.operand solid_operand = self.operand
while isinstance(solid_operand, TypecastNode) and not solid_operand.is_temp: while isinstance(solid_operand, TypecastNode) and not solid_operand.is_temp:
......
...@@ -981,7 +981,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -981,7 +981,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for e in scope.entries.values(): for e in scope.entries.values():
if e.is_type or e.name == "this": if e.is_type or e.name == "this":
continue continue
elif e.type.is_cyp_class and not e.type.is_qualified_cyp_class: elif e.type.is_cyp_class and e.type.qualifier in ('read', None):
check_cypclass_attrs.append(e) check_cypclass_attrs.append(e)
elif e.type.is_template_typename: elif e.type.is_template_typename:
check_template_attrs.append(e) check_template_attrs.append(e)
......
...@@ -680,13 +680,12 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -680,13 +680,12 @@ class CFuncDeclaratorNode(CDeclaratorNode):
type = env.parent_type type = env.parent_type
elif i == 0 and env.is_cyp_class_scope and 'staticmethod' not in env.directives and self.declared_name() != "alloc": elif i == 0 and env.is_cyp_class_scope and 'staticmethod' not in env.directives and self.declared_name() != "alloc":
if self.declared_name() != "__new__": if self.declared_name() != "__new__":
# Accept 'f(<qualifier> self, ...) syntax' # Check that the type of self is correct. Accept 'f(<qualifier> self, ...) syntax.
unqualified_type = type if type.is_cyp_class and env.parent_type.same_as(type.qual_base_type or type):
if type.is_qualified_cyp_class: qualifier = self.self_qualifier = type.qualifier
self.self_qualifier = type.qualifier if return_type.is_qualified_cyp_class and return_type.qualifier == 'self->' and qualifier == 'read':
unqualified_type = type.qual_base_type type = PyrexTypes.cyp_class_qualified_type(type, 'self->')
# check that the type of self is correct: else:
if not unqualified_type.same_as(env.parent_type):
error(self.pos, "Wrong type for self argument - expected %s, got %s" % (env.parent_type, type)) error(self.pos, "Wrong type for self argument - expected %s, got %s" % (env.parent_type, type))
# skip 'self' argument from the list of actual arguments # skip 'self' argument from the list of actual arguments
# to comply with C++ implicit 'this' argument passing. # to comply with C++ implicit 'this' argument passing.
......
...@@ -2513,6 +2513,19 @@ def p_c_complex_base_type(s, templates = None): ...@@ -2513,6 +2513,19 @@ def p_c_complex_base_type(s, templates = None):
return type_node return type_node
def p_cypclass_qualifier(s):
qualifier = None
if s.sy == 'IDENT':
if s.systring in ('active', 'iso', 'lock', 'locked', 'read', 'frozen'):
qualifier = s.systring
s.next()
elif s.systring == 'self' and s.peek()[0] == '->':
qualifier = 'self->'
s.next()
s.next()
return qualifier
def p_c_simple_base_type(s, self_flag, nonempty, templates = None): def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty #print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0 is_basic = 0
...@@ -2545,9 +2558,8 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None): ...@@ -2545,9 +2558,8 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
base_type=base_type, is_const=is_const, is_volatile=is_volatile) base_type=base_type, is_const=is_const, is_volatile=is_volatile)
# Handle cypclass qualifiers # Handle cypclass qualifiers
if s.sy == 'IDENT' and s.systring in ('active', 'iso', 'lock', 'locked'): qualifier = p_cypclass_qualifier(s)
qualifier = s.systring if qualifier:
s.next()
base_type = p_c_base_type(s, self_flag=self_flag, nonempty=nonempty, templates=templates) base_type = p_c_base_type(s, self_flag=self_flag, nonempty=nonempty, templates=templates)
return Nodes.QualifiedCypclassNode(pos, base_type=base_type, qualifier=qualifier) return Nodes.QualifiedCypclassNode(pos, base_type=base_type, qualifier=qualifier)
......
...@@ -4767,7 +4767,10 @@ class QualifiedCypclassType(BaseType): ...@@ -4767,7 +4767,10 @@ class QualifiedCypclassType(BaseType):
'iso->': ('iso~',), 'iso->': ('iso~',),
'lock': ('lock', 'locked', 'iso~'), 'lock': ('lock', 'locked', 'iso~'),
'locked': ('locked', 'iso~'), 'locked': ('locked', 'iso~'),
'lock->': ('iso~',), 'frozen': ('frozen', 'iso~'),
'read': ('read', 'frozen', 'self->', None, 'iso~'),
'iso->read': ('iso~',),
'self->': ('self->', 'iso~'),
} }
def __new__(cls, base_type, qualifier): def __new__(cls, base_type, qualifier):
...@@ -5799,17 +5802,25 @@ def qualified_method_type(base_type, const, volatile): ...@@ -5799,17 +5802,25 @@ def qualified_method_type(base_type, const, volatile):
else: else:
return QualifiedMethodType(base_type, const, volatile) return QualifiedMethodType(base_type, const, volatile)
def viewpoint_adaptation(base_type, qualifier = 'iso->'): qualifier_adaptation = {
'iso': {None: 'iso->', 'read': 'iso->read'},
'read': {None: 'read', 'iso': 'iso->read'},
'frozen': {None: 'frozen', 'read': 'frozen', 'iso': 'frozen'},
'iso->read': {None: 'iso->read', 'read': 'iso->read', 'iso': 'iso->read'},
'self->': {None: 'self->', 'iso': 'iso->read'},
}
def viewpoint_adaptation(field_type, origin = 'iso'):
# Perform viewpoint adaptation for cypclass types. # Perform viewpoint adaptation for cypclass types.
if base_type.is_qualified_cyp_class: if not field_type.is_cyp_class:
return base_type return field_type
if base_type.is_cyp_class: if origin != 'iso->read' and origin.startswith('iso') or origin.startswith('lock'):
if qualifier.startswith('iso'): origin = 'iso'
qualifier = 'iso->' field = field_type.qualifier
elif qualifier.startswith('lock'): qualifier = qualifier_adaptation[origin].get(field, field)
qualifier = 'lock->' if qualifier == field:
return QualifiedCypclassType(base_type, qualifier) return field_type
return base_type return QualifiedCypclassType(field_type, qualifier)
def same_type(type1, type2): def same_type(type1, type2):
return type1.same_as(type2) return type1.same_as(type2)
......
...@@ -3164,9 +3164,21 @@ class CppClassScope(Scope): ...@@ -3164,9 +3164,21 @@ class CppClassScope(Scope):
def lookup_here(self, name): def lookup_here(self, name):
entry = super(CppClassScope,self).lookup_here(self.adapt_name_lookup(name)) entry = super(CppClassScope,self).lookup_here(self.adapt_name_lookup(name))
if entry and self.is_cyp_class_scope and entry.is_cfunction and entry.type.self_qualifier: if entry and self.is_cyp_class_scope and entry.is_cfunction:
# Cannot access self-qualified methods from unqualified cypclass. if entry.type.self_qualifier not in ('read', None):
return None # Cannot access self-qualified methods from unqualified cypclass except for 'read'.
return None
elif any(e.type.return_type.is_cyp_class and e.type.return_type.qualifier == 'self->' for e in entry.all_alternatives()):
alternatives = []
for e in entry.all_alternatives():
e = copy.copy(e)
if e.type.return_type.is_cyp_class and e.type.return_type.qualifier == 'self->':
method_type = copy.copy(e.type)
method_type.return_type = method_type.return_type.qual_base_type
e.type = method_type
e.overloaded_alternatives = alternatives
alternatives.append(e)
return alternatives[0]
return entry return entry
def lookup_here_unfiltered(self, name): def lookup_here_unfiltered(self, name):
...@@ -3280,18 +3292,11 @@ class CConstOrVolatileScope(Scope): ...@@ -3280,18 +3292,11 @@ class CConstOrVolatileScope(Scope):
return entry return entry
class QualifiedCypclassScope(Scope): class BaseAdapterScope(Scope):
qualifier = 'qual'
def __init__(self, base_type_scope, qualifier = None): def __init__(self, base_scope, name):
qualifier = qualifier or self.qualifier Scope.__init__(self, name, base_scope.outer_scope, base_scope.parent_scope)
Scope.__init__( self.base_scope = base_scope
self,
'%s_' % qualifier + base_type_scope.name,
base_type_scope.outer_scope,
base_type_scope.parent_scope)
self.base_type_scope = base_type_scope
self.qualifier = qualifier
self.cached_qualified_entries = {} self.cached_qualified_entries = {}
def lookup_here(self, name): def lookup_here(self, name):
...@@ -3303,7 +3308,7 @@ class QualifiedCypclassScope(Scope): ...@@ -3303,7 +3308,7 @@ class QualifiedCypclassScope(Scope):
return entry return entry
def resolve(self, name): def resolve(self, name):
base_entry = self.base_type_scope.lookup_here_unfiltered(name) base_entry = self.base_scope.lookup_here_unfiltered(name)
if base_entry is None: if base_entry is None:
return None return None
alternatives = [] alternatives = []
...@@ -3321,65 +3326,76 @@ class QualifiedCypclassScope(Scope): ...@@ -3321,65 +3326,76 @@ class QualifiedCypclassScope(Scope):
return None return None
def qualified_cypclass_scope(base_type_scope, qualifier): def qualified_cypclass_scope(base_scope, qualifier):
if qualifier == 'active': if qualifier == 'active':
return ActiveCypclassScope(base_type_scope) return ActiveCypclassScope(base_scope)
elif qualifier.startswith('iso'):
return IsoCypclassScope(base_type_scope, qualifier)
elif qualifier.startswith('lock'):
return IsoCypclassScope(base_type_scope, qualifier)
else: else:
return QualifiedCypclassScope(base_type_scope, qualifier) return QualifiedCypclassScope(base_scope, qualifier)
class ActiveCypclassScope(QualifiedCypclassScope): class ActiveCypclassScope(BaseAdapterScope):
qualifier = 'active' qualifier = 'active'
def __init__(self, base_scope):
name = 'active_%s' % base_scope.name
BaseAdapterScope.__init__(self, base_scope, name)
def adapt(self, base_entry): def adapt(self, base_entry):
if base_entry.is_cfunction and base_entry.type.self_qualifier == 'active': if base_entry.is_cfunction and base_entry.type.self_qualifier == 'active':
return base_entry return base_entry
return base_entry.active_entry return base_entry.active_entry
class IsoCypclassScope(QualifiedCypclassScope): class QualifiedCypclassScope(BaseAdapterScope):
qualifier = 'iso'
def adapt_arg_type(self, arg):
arg = copy.copy(arg)
arg.type = viewpoint_adaptation(arg.type, self.qualifier)
return arg
def adapt_method_entry(self, base_entry): def __init__(self, base_scope, qualifier):
base_type = base_entry.type name = '%s_%s' % (qualifier, base_scope.name)
if base_type.self_qualifier: BaseAdapterScope.__init__(self, base_scope, name)
if self.qualifier in PyrexTypes.QualifiedCypclassType.assignable_to[base_type.self_qualifier]: self.qualifier = qualifier
return base_entry
elif base_type.self_qualifier == 'locked' and self.qualifier == 'lock':
return base_entry
else:
return None
iso_method_type = copy.copy(base_type)
return_type = viewpoint_adaptation(base_type.return_type, self.qualifier)
iso_method_type.return_type = return_type
iso_method_type.args = [self.adapt_arg_type(arg) for arg in base_type.args]
entry = copy.copy(base_entry)
entry.type = iso_method_type
return entry
def adapt(self, base_entry): def adapt(self, base_entry):
if base_entry.is_type: if base_entry.is_type:
return base_entry return base_entry
if base_entry.is_cfunction: if base_entry.is_cfunction:
return self.adapt_method_entry(base_entry) return self.adapt_method(base_entry)
else: else:
base_entry_type = base_entry.type adapted_type = viewpoint_adaptation(base_entry.type, self.qualifier)
adapted_type = viewpoint_adaptation(base_entry_type, self.qualifier) if self.qualifier.endswith('read') or self.qualifier == 'frozen':
if adapted_type is base_entry_type: adapted_type = PyrexTypes.c_const_or_volatile_type(adapted_type, True, False)
elif adapted_type is base_entry.type:
return base_entry return base_entry
else: entry = copy.copy(base_entry)
entry.type = adapted_type
return entry
def adapt_method(self, base_entry):
base_type = base_entry.type
return_type = base_type.return_type
if return_type.is_cyp_class and return_type.qualifier == 'self->':
if self.qualifier in ('read', 'iso->read', 'frozen'):
method_type = copy.copy(base_type)
method_type.return_type = PyrexTypes.cyp_class_qualified_type(return_type, self.qualifier)
entry = copy.copy(base_entry) entry = copy.copy(base_entry)
entry.type = adapted_type entry.type = method_type
return entry return entry
elif self.qualifier in PyrexTypes.QualifiedCypclassType.assignable_to[base_type.self_qualifier]:
return base_entry
elif self.qualifier == 'lock' and base_type.self_qualifier == 'locked':
return base_entry
elif self.qualifier.startswith('iso') or self.qualifier.startswith('lock'):
if self.qualifier != 'iso->read' or base_type.self_qualifier == 'read':
iso_method_type = copy.copy(base_type)
iso_method_type.return_type = viewpoint_adaptation(return_type, self.qualifier)
iso_method_type.args = [self.adapt_arg(arg) for arg in base_type.args]
entry = copy.copy(base_entry)
entry.type = iso_method_type
return entry
return None
def adapt_arg(self, arg):
arg = copy.copy(arg)
arg.type = viewpoint_adaptation(arg.type, self.qualifier)
return arg
class TemplateScope(Scope): class TemplateScope(Scope):
......
...@@ -106,7 +106,7 @@ _ERRORS = u''' ...@@ -106,7 +106,7 @@ _ERRORS = u'''
33:15: Cannot assign type 'lock A' to 'locked A' 33:15: Cannot assign type 'lock A' to 'locked A'
36:12: Cannot assign type 'lock A' to 'A' 36:12: Cannot assign type 'lock A' to 'A'
40:14: Cannot assign type 'A' to 'lock A' 40:14: Cannot assign type 'A' to 'lock A'
56:9: Cannot assign type 'A' to 'lock-> A' 56:9: Cannot assign type 'A' to 'iso-> A'
77:20: Cannot cast 'lock A' to 'iso A' 77:20: Cannot cast 'lock A' to 'iso A'
80:15: Cannot cast 'lock A' to 'active A' 80:15: Cannot cast 'lock A' to 'active A'
83:15: Cannot cast 'lock A' to 'locked A' 83:15: Cannot cast 'lock A' to 'locked A'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment