Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
8c4a6299
Commit
8c4a6299
authored
Sep 18, 2012
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'const'
parents
eae1ada8
84ce8038
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
234 additions
and
6 deletions
+234
-6
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+13
-0
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+16
-0
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+12
-1
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+57
-5
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+18
-0
Cython/Compiler/TypeInference.py
Cython/Compiler/TypeInference.py
+4
-0
tests/compile/const_decl.pyx
tests/compile/const_decl.pyx
+7
-0
tests/errors/const_decl_errors.pyx
tests/errors/const_decl_errors.pyx
+21
-0
tests/run/cpp_const_method.pyx
tests/run/cpp_const_method.pyx
+86
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
8c4a6299
...
...
@@ -618,6 +618,9 @@ class ExprNode(Node):
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
...
...
@@ -1511,6 +1514,10 @@ class NameNode(AtomicExprNode):
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
)
...
...
@@ -2233,6 +2240,8 @@ class NextNode(AtomicExprNode):
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.
...
...
@@ -2598,6 +2607,8 @@ class IndexNode(ExprNode):
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
)
...
...
@@ -4453,6 +4464,8 @@ class AttributeNode(ExprNode):
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
)
...
...
Cython/Compiler/Nodes.py
View file @
8c4a6299
...
...
@@ -1048,6 +1048,19 @@ class FusedTypeNode(CBaseTypeNode):
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.
#
...
...
@@ -1941,6 +1954,7 @@ class CFuncDefNode(FuncDefNode):
# 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"
]
...
...
@@ -1950,6 +1964,7 @@ class CFuncDefNode(FuncDefNode):
directive_returns
=
None
override
=
None
template_declaration
=
None
is_const_method
=
False
def
unqualified_name
(
self
):
return
self
.
entry
.
name
...
...
@@ -2021,6 +2036,7 @@ class CFuncDefNode(FuncDefNode):
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
,
...
...
Cython/Compiler/Parsing.py
View file @
8c4a6299
...
...
@@ -1982,6 +1982,11 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
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
...
...
@@ -2703,6 +2708,11 @@ def p_c_func_or_var_declaration(s, pos, ctx):
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"
)
...
...
@@ -2715,7 +2725,8 @@ def p_c_func_or_var_declaration(s, pos, ctx):
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")
...
...
Cython/Compiler/PyrexTypes.py
View file @
8c4a6299
...
...
@@ -138,6 +138,7 @@ class PyrexType(BaseType):
# 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
...
...
@@ -192,6 +193,7 @@ class PyrexType(BaseType):
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
...
...
@@ -1151,6 +1153,42 @@ class CType(PyrexType):
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
...
...
@@ -2281,6 +2319,8 @@ class CPtrType(CPointerBaseType):
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
()
...
...
@@ -2328,9 +2368,6 @@ class CReferenceType(BaseType):
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 ###
...
...
@@ -2364,11 +2401,13 @@ class CFuncType(CType):
# 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'
]
...
...
@@ -2575,13 +2614,19 @@ class CFuncType(CType):
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
(
""
)
...
...
@@ -3802,6 +3847,13 @@ def c_ref_type(base_type):
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
)
...
...
Cython/Compiler/Symtab.py
View file @
8c4a6299
...
...
@@ -2,6 +2,7 @@
# Symbol Table
#
import
copy
import
re
from
Errors
import
warning
,
error
,
InternalError
from
StringEncoding
import
EncodedString
...
...
@@ -2151,3 +2152,20 @@ class PropertyScope(Scope):
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
Cython/Compiler/TypeInference.py
View file @
8c4a6299
...
...
@@ -442,10 +442,14 @@ def aggressive_spanning_type(types, might_overflow):
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
:
...
...
tests/compile/const_decl.pyx
0 → 100644
View file @
8c4a6299
# mode: compile
cdef
const_args
(
const
int
a
,
const
int
*
b
,
const
(
int
*
)
c
):
print
a
print
b
[
0
]
b
=
NULL
# OK, the pointer itself is not const
c
[
0
]
=
4
# OK, the value is not const
tests/errors/const_decl_errors.pyx
0 → 100644
View file @
8c4a6299
# mode: error
cdef
const
object
o
# TODO: This requires making the assignment at declaration time.
# (We could fake this case by dropping the const here in the C code,
# as it's not needed for agreeing with external libraries.
cdef
const
int
x
=
10
cdef
func
(
const
int
a
,
const
int
*
b
,
const
(
int
*
)
c
):
a
=
10
b
[
0
]
=
100
c
=
NULL
_ERRORS
=
"""
3:5: Const base type cannot be a Python object
8:5: Assignment to const 'x'
11:6: Assignment to const 'a'
12:5: Assignment to const dereference
13:6: Assignment to const 'c'
"""
tests/run/cpp_const_method.pyx
0 → 100644
View file @
8c4a6299
# cython: experimental_cpp_class_def=True
# tag: cpp
from
libcpp.vector
cimport
vector
cdef
cppclass
Wrapper
[
T
]:
T
value
__init__
(
T
&
value
):
this
.
value
=
value
void
set
(
T
&
value
):
this
.
value
=
value
T
get
()
const
:
return
this
.
value
def
test_const_get
(
int
x
):
"""
>>> test_const_get(10)
10
"""
cdef
const
Wrapper
[
int
]
*
wrapper
=
new
Wrapper
[
int
](
x
)
try
:
return
const_get
(
wrapper
[
0
])
finally
:
del
wrapper
cdef
int
const_get
(
const
Wrapper
[
int
]
wrapper
):
return
wrapper
.
get
()
def
test_const_ref_get
(
int
x
):
"""
>>> test_const_ref_get(100)
100
"""
cdef
const
Wrapper
[
int
]
*
wrapper
=
new
Wrapper
[
int
](
x
)
try
:
return
const_ref_get
(
wrapper
[
0
])
finally
:
del
wrapper
cdef
int
const_ref_get
(
const
Wrapper
[
int
]
&
wrapper
):
return
wrapper
.
get
()
def
test_const_pointer_get
(
int
x
):
"""
>>> test_const_pointer_get(1000)
1000
"""
cdef
Wrapper
[
int
]
*
wrapper
=
new
Wrapper
[
int
](
x
)
cdef
const
Wrapper
[
int
]
*
const_wrapper
=
wrapper
try
:
return
const_wrapper
.
get
()
finally
:
del
wrapper
# TODO: parse vector[Wrapper[int]*]
ctypedef
Wrapper
[
int
]
wrapInt
def
test_vector_members
(
py_a
,
py_b
):
"""
>>> test_vector_members([1, 2, 3], [4,5, 6])
([1, 2, 3], 4)
"""
cdef
Wrapper
[
int
]
*
value
cdef
const
Wrapper
[
int
]
*
const_value
cdef
vector
[
const
Wrapper
[
int
]
*
]
a
cdef
vector
[
wrapInt
*
]
b
for
x
in
py_a
:
a
.
push_back
(
new
Wrapper
[
int
](
x
))
for
x
in
py_b
:
b
.
push_back
(
new
Wrapper
[
int
](
x
))
try
:
return
vector_members
(
a
,
b
)
finally
:
for
const_value
in
a
:
del
const_value
for
value
in
b
:
del
value
cdef
vector_members
(
vector
[
const
Wrapper
[
int
]
*
]
a
,
const
vector
[
wrapInt
*
]
b
):
# TODO: Cython-level error.
# b[0].set(100)
# TODO: const_iterator
return
[
x
.
get
()
for
x
in
a
],
b
[
0
].
get
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment