Commit a4bc6221 authored by Xavier Thompson's avatar Xavier Thompson

Introduce 'active' qualifier for cypclass references

parent 03d7c50c
......@@ -1348,6 +1348,19 @@ class CConstOrVolatileTypeNode(CBaseTypeNode):
return PyrexTypes.c_const_or_volatile_type(base, self.is_const, self.is_volatile)
class QualifiedCypclassNode(CBaseTypeNode):
# base_type CBaseTypeNode
# qualifier string
child_attrs = ["base_type"]
def analyse(self, env, could_be_name=False):
base = self.base_type.analyse(env, could_be_name)
if not base.is_cyp_class:
error(self.pos, "Qualifier '%s' can only apply to cypclass types" % self.qualifier)
return base
return PyrexTypes.cyp_class_qualified_type(base, self.qualifier)
class CVarDefNode(StatNode):
# C variable definition or forward/extern function declaration.
#
......
......@@ -2534,6 +2534,13 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
return Nodes.CConstOrVolatileTypeNode(pos,
base_type=base_type, is_const=is_const, is_volatile=is_volatile)
# Handle cypclass qualifiers
if s.sy == 'IDENT' and s.systring in ('active',):
qualifier = s.systring
s.next()
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)
if s.sy != 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
if looking_at_base_type(s):
......
......@@ -256,6 +256,7 @@ class PyrexType(BaseType):
is_cpp_class = 0
is_cyp_class = 0
is_const_cyp_class = 0
is_qualified_cyp_class = 0
is_cpp_string = 0
is_struct = 0
is_enum = 0
......@@ -4768,6 +4769,108 @@ class ConstCypclassType(BaseType):
return getattr(self.const_base_type, name)
class QualifiedCypclassType(BaseType):
"A qualified cypclass reference"
# qualifier string the qualifier keyword
subtypes = ['qual_base_type']
is_cyp_class = 1
is_qualified_cyp_class = 1
def __init__(self, base_type, qualifier):
assert base_type.is_cyp_class
self.qual_base_type = base_type
self.qualifier = qualifier
if qualifier == 'active':
assert base_type.activable
# For now just redirect to the nested "Activated" cypclass scope
self.scope = self.qual_base_type.scope.lookup_here("Activated").type.scope
elif base_type.has_attributes and base_type.scope is not None:
from .Symtab import QualifiedCypclassScope
self.scope = QualifiedCypclassScope(base_type.scope, qualifier)
def __repr__(self):
return "<QualifiedCypclassType %s%r>" % self.qual_base_type
def __str__(self):
return self.declaration_code("", for_display=1)
def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0, template_params = None, deref = 0):
if for_display:
decl = self.qual_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex, template_params, deref)
return "%s %s" % (self.qualifier, decl)
if self.qualifier == 'active':
decl_type = self.qual_base_type.scope.lookup_here("Activated").type
else:
decl_type = self.qual_base_type
return decl_type.declaration_code(entity_code, for_display, dll_linkage, pyrex, template_params, deref)
def empty_declaration_code(self):
if self._empty_declaration is None:
self._empty_declaration = self.qual_base_type.empty_declaration_code()
return self._empty_declaration
def cast_code(self, expr_code):
return "((%s)%s)" % (self.declaration_code(''), expr_code)
def dynamic_cast_code(self, expr_code):
return "dynamic_cast<%s>(%s)" % (self.declaration_code(''), expr_code)
def resolve(self):
base_type = self.qual_base_type.resolve()
if base_type == self.qual_base_type:
return self
return QualifiedCypclassType(base_type, self.qualifier)
def specialize(self, values):
base_type = self.qual_base_type.specialize(values)
if base_type == self.qual_base_type:
return self
return QualifiedCypclassType(base_type, self.qualifier)
def as_argument_type(self):
return self
def deduce_template_params(self, actual):
return self.qual_base_type.deduce_template_params(actual)
def can_coerce_to_pyobject(self, env):
return self.qual_base_type.can_coerce_to_pyobject(env)
def can_coerce_from_pyobject(self, env):
return self.qual_base_type.can_coerce_from_pyobject(env)
def create_to_py_utility_code(self, env):
if self.qual_base_type.create_to_py_utility_code(env):
self.to_py_function = self.qual_base_type.to_py_function
return True
def assignable_from(self, src_type):
return self.assignable_from_resolved_type(src_type.resolve())
def assignable_from_resolved_type(self, src_type):
if src_type.is_qualified_cyp_class and self.qualifier == src_type.qualifier:
return self.qual_base_type.assignable_from_resolved_type(src_type.qual_base_type)
return 0
def same_as(self, other_type):
if not other_type.is_qualified_cyp_class:
return 0
return self.same_as_resolved_type(other_type.resolve())
def same_as_resolved_type(self, other_type):
if other_type.is_qualified_cyp_class and self.qualifier == other_type.qualifier:
return self.qual_base_type.same_as_resolved_type(other_type.qual_base_type)
return 0
def __getattr__(self, name):
return getattr(self.qual_base_type, name)
class TemplatePlaceholderType(CType):
is_template_typename = 1
......@@ -5669,6 +5772,13 @@ def cyp_class_const_type(base_type):
else:
return ConstCypclassType(base_type)
def cyp_class_qualified_type(base_type, qualifier):
# Construct a qualified cypclass type.
if base_type is error_type:
return error_type
else:
return QualifiedCypclassType(base_type, qualifier)
def qualified_method_type(base_type, const, volatile):
# Construct a proxy type for methods looked-up from qualified objects.
if base_type is error_type:
......
......@@ -919,6 +919,20 @@ class Scope(object):
activate_entry.is_variable = activate_entry.is_cfunction = 1
activate_entry.func_cname = "%s::%s" % (entry.type.empty_declaration_code(), "__activate__")
activate_func_arg = PyrexTypes.CFuncTypeArg(EncodedString("o"), entry.type, pos)
activate_func_return = PyrexTypes.cyp_class_qualified_type(entry.type, 'active')
activate_func_type = PyrexTypes.CFuncType(activate_func_return, [activate_func_arg], nogil = 1)
builtin_scope = scope.builtin_scope()
if 'activate' in builtin_scope.entries:
activate_func_entry = Entry(EncodedString('activate'), 'activate', activate_func_type, pos=None)
activate_func_entry.visibility = 'extern'
activate_func_entry.scope = builtin_scope
activate_func_entry.overloaded_alternatives = builtin_scope.entries['activate'].overloaded_alternatives
activate_func_entry.overloaded_alternatives.append(activate_func_entry)
else:
activate_func_entry = builtin_scope.declare(EncodedString('activate'), 'activate', activate_func_type, None, 'extern')
activate_func_entry.is_variable = activate_func_entry.is_cfunction = 1
if self.is_cpp_class_scope:
entry.type.namespace = self.outer_scope.lookup(self.name).type
return entry
......@@ -3279,6 +3293,25 @@ class CConstOrVolatileScope(Scope):
return entry
class QualifiedCypclassScope(Scope):
def __init__(self, base_type_scope, qualifier):
Scope.__init__(
self,
'cyp_qual_' + 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 = {}
def lookup_here(self, name):
try:
return self.cached_qualified_entries[name]
except KeyError:
# TODO
pass
class TemplateScope(Scope):
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None)
......
......@@ -449,6 +449,15 @@
return dynamic_cast<const typename std::remove_pointer<T>::type *>(ob) != NULL;
}
/*
* Activate a passive Cyobject.
*/
template <typename T>
static inline typename T::Activated * activate(T * ob) {
static_assert(std::is_convertible<T *, ActhonActivableClass *>::value, "wrong type for activate");
return ob->__activate__(NULL);
}
/*
* Cast from CyObject to PyObject:
* - borrow an atomic reference
......
......@@ -152,7 +152,7 @@ def test_acthon_chain(n):
after_sync1 = ActivityCounterSync(sync1)
obj = A()
with wlocked obj:
obj_actor = obj.__activate__()
obj_actor = activate(obj)
with wlocked obj_actor, wlocked sync1, wlocked after_sync1:
# Pushing things in the queue
obj_actor.setter(sync1, n)
......
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