Commit da0490ef authored by Xavier Thompson's avatar Xavier Thompson

Introduce 'frozen' and 'read' keywords

parent 0bb6f98b
......@@ -11399,16 +11399,15 @@ class ConsumeNode(ExprNode):
error(self.pos, "Can only consume cypclass (not '%s')" % operand_type)
self.type = PyrexTypes.error_type
return self
if operand_type.is_qualified_cyp_class:
self.generate_runtime_check = operand_type.qualifier not in ('iso', 'iso~')
self.check_refcount_only = operand_type.qualifier in ('active', 'lock', 'locked')
if operand_type.qualifier == 'iso~':
self.type = operand_type
else:
self.type = PyrexTypes.cyp_class_qualified_type(operand_type.qual_base_type, 'iso~')
if operand_type.qualifier == 'frozen':
error(self.pos, "Cannot consume '%s'" % operand_type)
self.type = PyrexTypes.error_type
return self
self.generate_runtime_check = operand_type.qualifier not in ('iso', 'iso~')
self.check_refcount_only = operand_type.qualifier in ('active', 'lock', 'locked')
if operand_type.qualifier == 'iso~':
self.type = operand_type
else:
self.generate_runtime_check = True
self.check_refcount_only = False
self.type = PyrexTypes.cyp_class_qualified_type(operand_type, 'iso~')
solid_operand = self.operand
while isinstance(solid_operand, TypecastNode) and not solid_operand.is_temp:
......
......@@ -981,7 +981,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for e in scope.entries.values():
if e.is_type or e.name == "this":
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)
elif e.type.is_template_typename:
check_template_attrs.append(e)
......
......@@ -680,13 +680,12 @@ class CFuncDeclaratorNode(CDeclaratorNode):
type = env.parent_type
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__":
# Accept 'f(<qualifier> self, ...) syntax'
unqualified_type = type
if type.is_qualified_cyp_class:
self.self_qualifier = type.qualifier
unqualified_type = type.qual_base_type
# check that the type of self is correct:
if not unqualified_type.same_as(env.parent_type):
# Check that the type of self is correct. Accept 'f(<qualifier> self, ...) syntax.
if type.is_cyp_class and env.parent_type.same_as(type.qual_base_type or type):
qualifier = self.self_qualifier = type.qualifier
if return_type.is_qualified_cyp_class and return_type.qualifier == 'self->' and qualifier == 'read':
type = PyrexTypes.cyp_class_qualified_type(type, 'self->')
else:
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
# to comply with C++ implicit 'this' argument passing.
......
......@@ -2513,6 +2513,19 @@ def p_c_complex_base_type(s, templates = None):
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):
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0
......@@ -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)
# Handle cypclass qualifiers
if s.sy == 'IDENT' and s.systring in ('active', 'iso', 'lock', 'locked'):
qualifier = s.systring
s.next()
qualifier = p_cypclass_qualifier(s)
if qualifier:
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)
......
......@@ -4767,7 +4767,10 @@ class QualifiedCypclassType(BaseType):
'iso->': ('iso~',),
'lock': ('lock', '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):
......@@ -5799,17 +5802,25 @@ def qualified_method_type(base_type, const, volatile):
else:
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.
if base_type.is_qualified_cyp_class:
return base_type
if base_type.is_cyp_class:
if qualifier.startswith('iso'):
qualifier = 'iso->'
elif qualifier.startswith('lock'):
qualifier = 'lock->'
return QualifiedCypclassType(base_type, qualifier)
return base_type
if not field_type.is_cyp_class:
return field_type
if origin != 'iso->read' and origin.startswith('iso') or origin.startswith('lock'):
origin = 'iso'
field = field_type.qualifier
qualifier = qualifier_adaptation[origin].get(field, field)
if qualifier == field:
return field_type
return QualifiedCypclassType(field_type, qualifier)
def same_type(type1, type2):
return type1.same_as(type2)
......
......@@ -3164,9 +3164,21 @@ class CppClassScope(Scope):
def lookup_here(self, 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:
# Cannot access self-qualified methods from unqualified cypclass.
return None
if entry and self.is_cyp_class_scope and entry.is_cfunction:
if entry.type.self_qualifier not in ('read', 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
def lookup_here_unfiltered(self, name):
......@@ -3280,18 +3292,11 @@ class CConstOrVolatileScope(Scope):
return entry
class QualifiedCypclassScope(Scope):
qualifier = 'qual'
class BaseAdapterScope(Scope):
def __init__(self, base_type_scope, qualifier = None):
qualifier = qualifier or self.qualifier
Scope.__init__(
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
def __init__(self, base_scope, name):
Scope.__init__(self, name, base_scope.outer_scope, base_scope.parent_scope)
self.base_scope = base_scope
self.cached_qualified_entries = {}
def lookup_here(self, name):
......@@ -3303,7 +3308,7 @@ class QualifiedCypclassScope(Scope):
return entry
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:
return None
alternatives = []
......@@ -3321,65 +3326,76 @@ class QualifiedCypclassScope(Scope):
return None
def qualified_cypclass_scope(base_type_scope, qualifier):
def qualified_cypclass_scope(base_scope, qualifier):
if qualifier == 'active':
return ActiveCypclassScope(base_type_scope)
elif qualifier.startswith('iso'):
return IsoCypclassScope(base_type_scope, qualifier)
elif qualifier.startswith('lock'):
return IsoCypclassScope(base_type_scope, qualifier)
return ActiveCypclassScope(base_scope)
else:
return QualifiedCypclassScope(base_type_scope, qualifier)
return QualifiedCypclassScope(base_scope, qualifier)
class ActiveCypclassScope(QualifiedCypclassScope):
class ActiveCypclassScope(BaseAdapterScope):
qualifier = 'active'
def __init__(self, base_scope):
name = 'active_%s' % base_scope.name
BaseAdapterScope.__init__(self, base_scope, name)
def adapt(self, base_entry):
if base_entry.is_cfunction and base_entry.type.self_qualifier == 'active':
return base_entry
return base_entry.active_entry
class IsoCypclassScope(QualifiedCypclassScope):
qualifier = 'iso'
def adapt_arg_type(self, arg):
arg = copy.copy(arg)
arg.type = viewpoint_adaptation(arg.type, self.qualifier)
return arg
class QualifiedCypclassScope(BaseAdapterScope):
def adapt_method_entry(self, base_entry):
base_type = base_entry.type
if base_type.self_qualifier:
if self.qualifier in PyrexTypes.QualifiedCypclassType.assignable_to[base_type.self_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 __init__(self, base_scope, qualifier):
name = '%s_%s' % (qualifier, base_scope.name)
BaseAdapterScope.__init__(self, base_scope, name)
self.qualifier = qualifier
def adapt(self, base_entry):
if base_entry.is_type:
return base_entry
if base_entry.is_cfunction:
return self.adapt_method_entry(base_entry)
return self.adapt_method(base_entry)
else:
base_entry_type = base_entry.type
adapted_type = viewpoint_adaptation(base_entry_type, self.qualifier)
if adapted_type is base_entry_type:
adapted_type = viewpoint_adaptation(base_entry.type, self.qualifier)
if self.qualifier.endswith('read') or self.qualifier == 'frozen':
adapted_type = PyrexTypes.c_const_or_volatile_type(adapted_type, True, False)
elif adapted_type is base_entry.type:
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.type = adapted_type
entry.type = method_type
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):
......
......@@ -106,7 +106,7 @@ _ERRORS = u'''
33:15: Cannot assign type 'lock A' to 'locked A'
36:12: Cannot assign type 'lock A' to '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'
80:15: Cannot cast 'lock A' to 'active 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