if dst_type.is_reference and not src_type.is_reference:
dst_type = dst_type.ref_base_type
+ if src_type.is_const:
+ src_type = src_type.const_base_type
+
if src_type.is_fused or dst_type.is_fused:
# See if we are coercing a fused function to a pointer to a
# specialized function
self.entry = self.entry.as_variable
self.type = self.entry.type
+ if self.type.is_const:
+ error(self.pos, "Assignment to const '%s'" % self.name)
+ if self.type.is_reference:
+ error(self.pos, "Assignment to reference '%s'" % self.name)
if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue '%s'"
% self.name)
item_type = env.lookup_operator_for_types(self.pos, "*", [iterator_type]).type.return_type
if item_type.is_reference:
item_type = item_type.ref_base_type
+ if item_type.is_const:
+ item_type = item_type.const_base_type
return item_type
else:
# Avoid duplication of complicated logic.
def analyse_target_types(self, env):
self.analyse_base_and_index_types(env, setting = 1)
+ if self.type.is_const:
+ error(self.pos, "Assignment to const dereference")
if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)
def analyse_target_types(self, env):
self.analyse_types(env, target = 1)
+ if self.type.is_const:
+ error(self.pos, "Assignment to const attribute '%s'" % self.attribute)
if not self.is_lvalue():
error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)
return PyrexTypes.FusedType(types, name=self.name)
+class CConstTypeNode(CBaseTypeNode):
+ # base_type CBaseTypeNode
+
+ child_attrs = ["base_type"]
+
+ def analyse(self, env, could_be_name = False):
+ base = self.base_type.analyse(env, could_be_name)
+ if base.is_pyobject:
+ error(self.pos,
+ "Const base type cannot be a Python object")
+ return PyrexTypes.c_const_type(base)
+
+
class CVarDefNode(StatNode):
# C variable definition or forward/extern function declaration.
#
# overridable whether or not this is a cpdef function
# inline_in_pxd whether this is an inline function in a pxd file
# template_declaration String or None Used for c++ class methods
+ # is_const_method whether this is a const method
child_attrs = ["base_type", "declarator", "body", "py_func"]
directive_returns = None
override = None
template_declaration = None
+ is_const_method = False
def unqualified_name(self):
return self.entry.name
name = name_declarator.name
cname = name_declarator.cname
+ type.is_const_method = self.is_const_method
self.entry = env.declare_cfunction(
name, type, self.pos,
cname = cname, visibility = self.visibility, api = self.api,
pos = s.position()
if not s.sy == 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
+ if s.systring == 'const':
+ s.next()
+ base_type = p_c_base_type(s,
+ self_flag = self_flag, nonempty = nonempty, templates = templates)
+ return Nodes.CConstTypeNode(pos, base_type = base_type)
if looking_at_base_type(s):
#print "p_c_simple_base_type: looking_at_base_type at", s.position()
is_basic = 1
declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
assignable = 1, nonempty = 1)
declarator.overridable = ctx.overridable
+ if s.sy == 'IDENT' and s.systring == 'const' and ctx.level == 'cpp_class':
+ s.next()
+ is_const_method = 1
+ else:
+ is_const_method = 0
if s.sy == ':':
if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
s.error("C function definition not allowed here")
doc = doc,
modifiers = modifiers,
api = ctx.api,
- overridable = ctx.overridable)
+ overridable = ctx.overridable,
+ is_const_method = is_const_method)
else:
#if api:
# s.error("'api' not allowed with variable declaration")
# is_ptr boolean Is a C pointer type
# is_null_ptr boolean Is the type of NULL
# is_reference boolean Is a C reference type
+ # is_const boolean Is a C const type.
# is_cfunction boolean Is a C function type
# is_struct_or_union boolean Is a C struct or union type
# is_struct boolean Is a C struct type
is_ptr = 0
is_null_ptr = 0
is_reference = 0
+ is_const = 0
is_cfunction = 0
is_struct_or_union = 0
is_cpp_class = 0
return 0
+class CConstType(BaseType):
+
+ is_const = 1
+
+ def __init__(self, const_base_type):
+ self.const_base_type = const_base_type
+ if const_base_type.has_attributes and const_base_type.scope is not None:
+ import Symtab
+ self.scope = Symtab.CConstScope(const_base_type.scope)
+
+ def __repr__(self):
+ return "<CConstType %s>" % repr(self.const_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):
+ return self.const_base_type.declaration_code("const %s" % entity_code, for_display, dll_linkage, pyrex)
+
+ def specialize(self, values):
+ base_type = self.const_base_type.specialize(values)
+ if base_type == self.const_base_type:
+ return self
+ else:
+ return ConstType(base_type)
+
+ def create_to_py_utility_code(self, env):
+ if self.const_base_type.create_to_py_utility_code(env):
+ self.to_py_function = self.const_base_type.to_py_function
+ return True
+
+ def __getattr__(self, name):
+ return getattr(self.const_base_type, name)
+
+
class FusedType(CType):
"""
Represents a Fused Type. All it needs to do is keep track of the types
return 1
if other_type.is_null_ptr:
return 1
+ if self.base_type.is_const:
+ self = CPtrType(self.base_type.const_base_type)
if self.base_type.is_cfunction:
if other_type.is_ptr:
other_type = other_type.base_type.resolve()
def __str__(self):
return "%s &" % self.ref_base_type
- def as_argument_type(self):
- return self
-
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
# C function
# is_strict_signature boolean function refuses to accept coerced arguments
# (used for optimisation overrides)
+ # is_const_method boolean
is_cfunction = 1
original_sig = None
cached_specialized_types = None
from_fused = False
+ is_const_method = False
subtypes = ['return_type', 'args']
if (not entity_code and cc) or entity_code.startswith("*"):
entity_code = "(%s%s)" % (cc, entity_code)
cc = ""
+ if self.is_const_method:
+ trailer += " const"
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
def function_header_code(self, func_name, arg_code):
- return "%s%s(%s)" % (self.calling_convention_prefix(),
- func_name, arg_code)
+ if self.is_const_method:
+ trailer = " const"
+ else:
+ trailer = ""
+ return "%s%s(%s)%s" % (self.calling_convention_prefix(),
+ func_name, arg_code, trailer)
def signature_string(self):
s = self.declaration_code("")
else:
return CReferenceType(base_type)
+def c_const_type(base_type):
+ # Construct a C const type.
+ if base_type is error_type:
+ return error_type
+ else:
+ return CConstType(base_type)
+
def same_type(type1, type2):
return type1.same_as(type2)
# Symbol Table
#
+import copy
import re
from Errors import warning, error, InternalError
from StringEncoding import EncodedString
error(pos, "Only __get__, __set__ and __del__ methods allowed "
"in a property declaration")
return None
+
+class CConstScope(Scope):
+
+ def __init__(self, const_base_type_scope):
+ Scope.__init__(
+ self,
+ 'const_' + const_base_type_scope.name,
+ const_base_type_scope.outer_scope,
+ const_base_type_scope.parent_scope)
+ self.const_base_type_scope = const_base_type_scope
+
+ def lookup_here(self, name):
+ entry = self.const_base_type_scope.lookup_here(name)
+ if entry is not None:
+ entry = copy.copy(entry)
+ entry.type = PyrexTypes.c_const_type(entry.type)
+ return entry
result_type = reduce(find_spanning_type, types)
if result_type.is_reference:
result_type = result_type.ref_base_type
+ if result_type.is_const:
+ result_type = result_type.const_base_type
return result_type
def safe_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types)
+ if result_type.is_const:
+ result_type = result_type.const_base_type
if result_type.is_reference:
result_type = result_type.ref_base_type
if result_type.is_pyobject: