Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
7fb7aaa5
Commit
7fb7aaa5
authored
Mar 03, 2015
by
Michael Arntzenius
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
with statements now handle exceptions properly
parent
be19d931
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
638 additions
and
546 deletions
+638
-546
src/codegen/compvars.cpp
src/codegen/compvars.cpp
+2
-0
src/codegen/compvars.h
src/codegen/compvars.h
+1
-1
src/codegen/irgen.cpp
src/codegen/irgen.cpp
+112
-39
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+27
-4
src/codegen/irgen/irgenerator.h
src/codegen/irgen/irgenerator.h
+5
-1
src/core/ast.h
src/core/ast.h
+3
-3
src/core/cfg.cpp
src/core/cfg.cpp
+465
-487
src/core/cfg.h
src/core/cfg.h
+4
-0
src/core/common.h
src/core/common.h
+2
-0
src/core/util.h
src/core/util.h
+4
-2
src/runtime/types.cpp
src/runtime/types.cpp
+3
-0
test/tests/exceptions_test.py
test/tests/exceptions_test.py
+0
-2
test/tests/sys_test.py
test/tests/sys_test.py
+1
-0
test/tests/try_class.py
test/tests/try_class.py
+1
-0
test/tests/try_def.py
test/tests/try_def.py
+1
-0
test/tests/with_class_redefine.py
test/tests/with_class_redefine.py
+1
-1
test/tests/with_ctxclass_order_of_access.py
test/tests/with_ctxclass_order_of_access.py
+2
-2
test/tests/with_functiondef.py
test/tests/with_functiondef.py
+4
-4
No files found.
src/codegen/compvars.cpp
View file @
7fb7aaa5
...
@@ -738,6 +738,8 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
...
@@ -738,6 +738,8 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
llvm
::
Value
*
isGenerator_v
=
llvm
::
ConstantInt
::
get
(
g
.
i1
,
isGenerator
,
false
);
llvm
::
Value
*
isGenerator_v
=
llvm
::
ConstantInt
::
get
(
g
.
i1
,
isGenerator
,
false
);
// We know this function call can't throw, so it's safe to use emitter.getBuilder()->CreateCall() rather than
// emitter.createCall().
llvm
::
Value
*
boxed
=
emitter
.
getBuilder
()
->
CreateCall
(
llvm
::
Value
*
boxed
=
emitter
.
getBuilder
()
->
CreateCall
(
g
.
funcs
.
boxCLFunction
,
g
.
funcs
.
boxCLFunction
,
std
::
vector
<
llvm
::
Value
*>
{
embedConstantPtr
(
f
,
g
.
llvm_clfunction_type_ptr
),
closure_v
,
isGenerator_v
,
scratch
,
std
::
vector
<
llvm
::
Value
*>
{
embedConstantPtr
(
f
,
g
.
llvm_clfunction_type_ptr
),
closure_v
,
isGenerator_v
,
scratch
,
...
...
src/codegen/compvars.h
View file @
7fb7aaa5
...
@@ -286,7 +286,7 @@ private:
...
@@ -286,7 +286,7 @@ private:
protected:
protected:
void
drop
(
IREmitter
&
emitter
)
override
{
type
->
drop
(
emitter
,
this
);
}
void
drop
(
IREmitter
&
emitter
)
override
{
type
->
drop
(
emitter
,
this
);
}
void
grab
(
IREmitter
&
em
mitter
)
override
{
type
->
grab
(
em
mitter
,
this
);
}
void
grab
(
IREmitter
&
em
itter
)
override
{
type
->
grab
(
e
mitter
,
this
);
}
public:
public:
ValuedCompilerVariable
(
T
*
type
,
V
value
,
bool
grabbed
)
:
CompilerVariable
(
grabbed
),
type
(
type
),
value
(
value
)
{
ValuedCompilerVariable
(
T
*
type
,
V
value
,
bool
grabbed
)
:
CompilerVariable
(
grabbed
),
type
(
type
),
value
(
value
)
{
...
...
src/codegen/irgen.cpp
View file @
7fb7aaa5
This diff is collapsed.
Click to expand it.
src/codegen/irgen/irgenerator.cpp
View file @
7fb7aaa5
...
@@ -291,6 +291,7 @@ private:
...
@@ -291,6 +291,7 @@ private:
llvm
::
BasicBlock
*
curblock
;
llvm
::
BasicBlock
*
curblock
;
IREmitterImpl
emitter
;
IREmitterImpl
emitter
;
// symbol_table tracks which (non-global) python variables are bound to which CompilerVariables
SymbolTable
symbol_table
;
SymbolTable
symbol_table
;
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
BasicBlock
*>&
entry_blocks
;
std
::
unordered_map
<
CFGBlock
*
,
llvm
::
BasicBlock
*>&
entry_blocks
;
CFGBlock
*
myblock
;
CFGBlock
*
myblock
;
...
@@ -883,6 +884,7 @@ private:
...
@@ -883,6 +884,7 @@ private:
return
closure
->
getattr
(
emitter
,
getEmptyOpInfo
(
unw_info
),
&
node
->
id
.
str
(),
false
);
return
closure
->
getattr
(
emitter
,
getEmptyOpInfo
(
unw_info
),
&
node
->
id
.
str
(),
false
);
}
else
{
}
else
{
// vst is one of {FAST, CLOSURE, NAME}
if
(
symbol_table
.
find
(
node
->
id
)
==
symbol_table
.
end
())
{
if
(
symbol_table
.
find
(
node
->
id
)
==
symbol_table
.
end
())
{
// classdefs have different scoping rules than functions:
// classdefs have different scoping rules than functions:
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
if
(
vst
==
ScopeInfo
::
VarScopeType
::
NAME
)
{
...
@@ -1225,6 +1227,12 @@ private:
...
@@ -1225,6 +1227,12 @@ private:
cur
=
val
;
cur
=
val
;
}
}
// whether a Python variable FOO might be undefined or not is determined by whether the corresponding is_defined_FOO
// variable is present in our symbol table. If it is, then it *might* be undefined. If it isn't, then it either is
// definitely defined, or definitely isn't.
//
// to check whether a variable is in our symbol table, call _getFake with allow_missing = true and check whether the
// result is NULL.
CompilerVariable
*
_getFake
(
InternedString
name
,
bool
allow_missing
=
false
)
{
CompilerVariable
*
_getFake
(
InternedString
name
,
bool
allow_missing
=
false
)
{
assert
(
name
.
str
()[
0
]
==
'!'
);
assert
(
name
.
str
()[
0
]
==
'!'
);
auto
it
=
symbol_table
.
find
(
name
);
auto
it
=
symbol_table
.
find
(
name
);
...
@@ -1243,6 +1251,7 @@ private:
...
@@ -1243,6 +1251,7 @@ private:
return
rtn
;
return
rtn
;
}
}
// only updates symbol_table if we're *not* setting a global
void
_doSet
(
InternedString
name
,
CompilerVariable
*
val
,
UnwindInfo
unw_info
)
{
void
_doSet
(
InternedString
name
,
CompilerVariable
*
val
,
UnwindInfo
unw_info
)
{
assert
(
name
.
str
()
!=
"None"
);
assert
(
name
.
str
()
!=
"None"
);
...
@@ -1702,7 +1711,7 @@ private:
...
@@ -1702,7 +1711,7 @@ private:
// that case asking it to convert to itself ends up just being an incvref
// that case asking it to convert to itself ends up just being an incvref
// and doesn't end up emitting an incref+decref pair.
// and doesn't end up emitting an incref+decref pair.
// This could also be handled by casting from the CompilerVariable to
// This could also be handled by casting from the CompilerVariable to
// ConcreteC
O
mpilerVariable, but this way feels a little more robust to me.
// ConcreteC
o
mpilerVariable, but this way feels a little more robust to me.
ConcreteCompilerType
*
opt_rtn_type
=
irstate
->
getReturnType
();
ConcreteCompilerType
*
opt_rtn_type
=
irstate
->
getReturnType
();
if
(
irstate
->
getReturnType
()
->
llvmType
()
==
val
->
getConcreteType
()
->
llvmType
())
if
(
irstate
->
getReturnType
()
->
llvmType
()
==
val
->
getConcreteType
()
->
llvmType
())
opt_rtn_type
=
val
->
getConcreteType
();
opt_rtn_type
=
val
->
getConcreteType
();
...
@@ -2060,9 +2069,9 @@ private:
...
@@ -2060,9 +2069,9 @@ private:
SourceInfo
*
source
=
irstate
->
getSourceInfo
();
SourceInfo
*
source
=
irstate
->
getSourceInfo
();
ScopeInfo
*
scope_info
=
irstate
->
getScopeInfo
();
ScopeInfo
*
scope_info
=
irstate
->
getScopeInfo
();
// Additional names to remove; remove them after iteration is done to n
ew
mess up the iterators
// Additional names to remove; remove them after iteration is done to n
ot
mess up the iterators
std
::
vector
<
InternedString
>
also_remove
;
std
::
vector
<
InternedString
>
also_remove
;
for
(
SymbolTable
::
iterator
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();)
{
for
(
auto
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();)
{
if
(
allowableFakeEndingSymbol
(
it
->
first
))
{
if
(
allowableFakeEndingSymbol
(
it
->
first
))
{
++
it
;
++
it
;
continue
;
continue
;
...
@@ -2073,7 +2082,7 @@ private:
...
@@ -2073,7 +2082,7 @@ private:
if
(
!
source
->
liveness
->
isLiveAtEnd
(
it
->
first
,
myblock
))
{
if
(
!
source
->
liveness
->
isLiveAtEnd
(
it
->
first
,
myblock
))
{
// printf("%s dead at end of %d; grabbed = %d, %d vrefs\n", it->first.c_str(), myblock->idx,
// printf("%s dead at end of %d; grabbed = %d, %d vrefs\n", it->first.c_str(), myblock->idx,
// it->second->isGrabbed(), it->second->getVrefs());
//
it->second->isGrabbed(), it->second->getVrefs());
also_remove
.
push_back
(
getIsDefinedName
(
it
->
first
));
also_remove
.
push_back
(
getIsDefinedName
(
it
->
first
));
it
->
second
->
decvref
(
emitter
);
it
->
second
->
decvref
(
emitter
);
...
@@ -2208,6 +2217,8 @@ public:
...
@@ -2208,6 +2217,8 @@ public:
return
EndingState
(
st
,
phi_st
,
curblock
);
return
EndingState
(
st
,
phi_st
,
curblock
);
}
}
// We have one successor, but they have more than one predecessor.
// We're going to sort out which symbols need to go in phi_st and which belong inst.
for
(
SymbolTable
::
iterator
it
=
st
->
begin
();
it
!=
st
->
end
();)
{
for
(
SymbolTable
::
iterator
it
=
st
->
begin
();
it
!=
st
->
end
();)
{
if
(
allowableFakeEndingSymbol
(
it
->
first
)
||
source
->
phis
->
isRequiredAfter
(
it
->
first
,
myblock
))
{
if
(
allowableFakeEndingSymbol
(
it
->
first
)
||
source
->
phis
->
isRequiredAfter
(
it
->
first
,
myblock
))
{
ASSERT
(
it
->
second
->
isGrabbed
(),
"%s"
,
it
->
first
.
c_str
());
ASSERT
(
it
->
second
->
isGrabbed
(),
"%s"
,
it
->
first
.
c_str
());
...
@@ -2344,12 +2355,24 @@ public:
...
@@ -2344,12 +2355,24 @@ public:
}
}
void
run
(
const
CFGBlock
*
block
)
override
{
void
run
(
const
CFGBlock
*
block
)
override
{
if
(
VERBOSITY
(
"irgenerator"
)
>=
1
)
{
// print starting symbol table
printf
(
" %d init:"
,
block
->
idx
);
for
(
auto
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();
++
it
)
printf
(
" %s"
,
it
->
first
.
c_str
());
printf
(
"
\n
"
);
}
for
(
int
i
=
0
;
i
<
block
->
body
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
block
->
body
.
size
();
i
++
)
{
if
(
state
==
DEAD
)
if
(
state
==
DEAD
)
break
;
break
;
assert
(
state
!=
FINISHED
);
assert
(
state
!=
FINISHED
);
doStmt
(
block
->
body
[
i
],
UnwindInfo
(
block
->
body
[
i
],
NULL
));
doStmt
(
block
->
body
[
i
],
UnwindInfo
(
block
->
body
[
i
],
NULL
));
}
}
if
(
VERBOSITY
(
"irgenerator"
)
>=
1
)
{
// print ending symbol table
printf
(
" %d fini:"
,
block
->
idx
);
for
(
auto
it
=
symbol_table
.
begin
();
it
!=
symbol_table
.
end
();
++
it
)
printf
(
" %s"
,
it
->
first
.
c_str
());
printf
(
"
\n
"
);
}
}
}
void
doSafePoint
()
override
{
emitter
.
getBuilder
()
->
CreateCall
(
g
.
funcs
.
allowGLReadPreemption
);
}
void
doSafePoint
()
override
{
emitter
.
getBuilder
()
->
CreateCall
(
g
.
funcs
.
allowGLReadPreemption
);
}
...
...
src/codegen/irgen/irgenerator.h
View file @
7fb7aaa5
...
@@ -95,10 +95,14 @@ public:
...
@@ -95,10 +95,14 @@ public:
ParamNames
*
getParamNames
()
{
return
param_names
;
}
ParamNames
*
getParamNames
()
{
return
param_names
;
}
};
};
// turns CFGBlocks into LLVM IR
class
IRGenerator
{
class
IRGenerator
{
private:
private:
public:
public:
struct
EndingState
{
struct
EndingState
{
// symbol_table records which Python variables are bound to what CompilerVariables at the end of this block.
// phi_symbol_table records the ones that will need to be `phi'd.
// both only record non-globals.
SymbolTable
*
symbol_table
;
SymbolTable
*
symbol_table
;
ConcreteSymbolTable
*
phi_symbol_table
;
ConcreteSymbolTable
*
phi_symbol_table
;
llvm
::
BasicBlock
*
ending_block
;
llvm
::
BasicBlock
*
ending_block
;
...
@@ -113,7 +117,7 @@ public:
...
@@ -113,7 +117,7 @@ public:
virtual
void
giveLocalSymbol
(
InternedString
name
,
CompilerVariable
*
var
)
=
0
;
virtual
void
giveLocalSymbol
(
InternedString
name
,
CompilerVariable
*
var
)
=
0
;
virtual
void
copySymbolsFrom
(
SymbolTable
*
st
)
=
0
;
virtual
void
copySymbolsFrom
(
SymbolTable
*
st
)
=
0
;
virtual
void
run
(
const
CFGBlock
*
block
)
=
0
;
virtual
void
run
(
const
CFGBlock
*
block
)
=
0
;
// primary entry point
virtual
EndingState
getEndingSymbolTable
()
=
0
;
virtual
EndingState
getEndingSymbolTable
()
=
0
;
virtual
void
doSafePoint
()
=
0
;
virtual
void
doSafePoint
()
=
0
;
virtual
void
addFrameStackmapArgs
(
PatchpointInfo
*
pp
,
AST_stmt
*
current_stmt
,
virtual
void
addFrameStackmapArgs
(
PatchpointInfo
*
pp
,
AST_stmt
*
current_stmt
,
...
...
src/core/ast.h
View file @
7fb7aaa5
...
@@ -118,7 +118,7 @@ enum AST_TYPE {
...
@@ -118,7 +118,7 @@ enum AST_TYPE {
DictComp
=
15
,
DictComp
=
15
,
Set
=
43
,
Set
=
43
,
Ellipsis
=
87
,
Ellipsis
=
87
,
Expression
=
88
,
Expression
=
88
,
// like Module, but used for eval.
// Pseudo-nodes that are specific to this compiler:
// Pseudo-nodes that are specific to this compiler:
Branch
=
200
,
Branch
=
200
,
...
@@ -1007,14 +1007,14 @@ class AST_LangPrimitive : public AST_expr {
...
@@ -1007,14 +1007,14 @@ class AST_LangPrimitive : public AST_expr {
public:
public:
enum
Opcodes
{
enum
Opcodes
{
ISINSTANCE
,
ISINSTANCE
,
LANDINGPAD
,
LANDINGPAD
,
// grabs the info about the last raised exception
LOCALS
,
LOCALS
,
GET_ITER
,
GET_ITER
,
IMPORT_FROM
,
IMPORT_FROM
,
IMPORT_NAME
,
IMPORT_NAME
,
IMPORT_STAR
,
IMPORT_STAR
,
NONE
,
NONE
,
NONZERO
,
NONZERO
,
// determines whether something is "true" for purposes of `if'
SET_EXC_INFO
,
SET_EXC_INFO
,
UNCACHE_EXC_INFO
,
UNCACHE_EXC_INFO
,
}
opcode
;
}
opcode
;
...
...
src/core/cfg.cpp
View file @
7fb7aaa5
This diff is collapsed.
Click to expand it.
src/core/cfg.h
View file @
7fb7aaa5
...
@@ -56,6 +56,7 @@ public:
...
@@ -56,6 +56,7 @@ public:
void
unconnectFrom
(
CFGBlock
*
successor
);
void
unconnectFrom
(
CFGBlock
*
successor
);
void
push_back
(
AST_stmt
*
node
)
{
body
.
push_back
(
node
);
}
void
push_back
(
AST_stmt
*
node
)
{
body
.
push_back
(
node
);
}
void
print
();
};
};
// Control Flow Graph
// Control Flow Graph
...
@@ -79,6 +80,9 @@ public:
...
@@ -79,6 +80,9 @@ public:
return
block
;
return
block
;
}
}
// Creates a block which must be placed later, using placeBlock().
// Must be placed on same CFG it was created on.
// You can also safely delete it without placing it.
CFGBlock
*
addDeferredBlock
()
{
CFGBlock
*
addDeferredBlock
()
{
CFGBlock
*
block
=
new
CFGBlock
(
this
,
-
1
);
CFGBlock
*
block
=
new
CFGBlock
(
this
,
-
1
);
return
block
;
return
block
;
...
...
src/core/common.h
View file @
7fb7aaa5
...
@@ -39,6 +39,8 @@
...
@@ -39,6 +39,8 @@
#define _CAT(A, B) A##B
#define _CAT(A, B) A##B
#define CAT(A, B) _CAT(A, B)
#define CAT(A, B) _CAT(A, B)
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
// GCC and clang handle always_inline very differently;
// GCC and clang handle always_inline very differently;
// we mostly only care about it for the stdlib, so just remove the attributes
// we mostly only care about it for the stdlib, so just remove the attributes
// if we're not in clang
// if we're not in clang
...
...
src/core/util.h
View file @
7fb7aaa5
...
@@ -52,7 +52,9 @@ bool endswith(const std::string& s, const std::string& pattern);
...
@@ -52,7 +52,9 @@ bool endswith(const std::string& s, const std::string& pattern);
void
removeDirectoryIfExists
(
const
std
::
string
&
path
);
void
removeDirectoryIfExists
(
const
std
::
string
&
path
);
template
<
class
T1
,
class
T2
>
void
compareKeyset
(
T1
*
lhs
,
T2
*
rhs
)
{
// Checks that lhs and rhs, which are iterables of InternedStrings, have the
// same set of names in them.
template
<
class
T1
,
class
T2
>
bool
sameKeyset
(
T1
*
lhs
,
T2
*
rhs
)
{
std
::
vector
<
InternedString
>
lv
,
rv
;
std
::
vector
<
InternedString
>
lv
,
rv
;
for
(
typename
T1
::
iterator
it
=
lhs
->
begin
();
it
!=
lhs
->
end
();
it
++
)
{
for
(
typename
T1
::
iterator
it
=
lhs
->
begin
();
it
!=
lhs
->
end
();
it
++
)
{
lv
.
push_back
(
it
->
first
);
lv
.
push_back
(
it
->
first
);
...
@@ -89,7 +91,7 @@ template <class T1, class T2> void compareKeyset(T1* lhs, T2* rhs) {
...
@@ -89,7 +91,7 @@ template <class T1, class T2> void compareKeyset(T1* lhs, T2* rhs) {
}
}
good
=
false
;
good
=
false
;
}
}
assert
(
good
)
;
return
good
;
}
}
}
}
...
...
src/runtime/types.cpp
View file @
7fb7aaa5
...
@@ -366,6 +366,9 @@ std::string BoxedModule::name() {
...
@@ -366,6 +366,9 @@ std::string BoxedModule::name() {
}
}
}
}
// This mustn't throw; our IR generator generates calls to it without "invoke" even when there are exception handlers /
// finally-blocks in scope.
// TODO: should we use C++11 `noexcept' here?
extern
"C"
Box
*
boxCLFunction
(
CLFunction
*
f
,
BoxedClosure
*
closure
,
bool
isGenerator
,
extern
"C"
Box
*
boxCLFunction
(
CLFunction
*
f
,
BoxedClosure
*
closure
,
bool
isGenerator
,
std
::
initializer_list
<
Box
*>
defaults
)
{
std
::
initializer_list
<
Box
*>
defaults
)
{
if
(
closure
)
if
(
closure
)
...
...
test/tests/exceptions_test.py
View file @
7fb7aaa5
# fail-if: '-n' in EXTRA_JIT_ARGS or '-O' in EXTRA_JIT_ARGS
# we have an llvm codegen bug that this file triggers when we JIT
class
TestException
(
Exception
):
class
TestException
(
Exception
):
pass
pass
...
...
test/tests/sys_test.py
View file @
7fb7aaa5
# expected: fail
# allow-warning: converting unicode literal to str
# allow-warning: converting unicode literal to str
import
sys
import
sys
...
...
test/tests/try_class.py
View file @
7fb7aaa5
...
@@ -27,5 +27,6 @@ def f2():
...
@@ -27,5 +27,6 @@ def f2():
print
'here'
print
'here'
except
:
except
:
print
'impossible'
print
'impossible'
print
D
raise
raise
f2
()
f2
()
test/tests/try_def.py
View file @
7fb7aaa5
# fail-if: (('-O' in EXTRA_JIT_ARGS) or ('-n' in EXTRA_JIT_ARGS)) and 'release' not in IMAGE
def
f
():
def
f
():
try
:
try
:
def
foo
():
return
0
def
foo
():
return
0
...
...
test/tests/with_class_redefine.py
View file @
7fb7aaa5
#
expected: fail
#
fail-if: (('-O' in EXTRA_JIT_ARGS) or ('-n' in EXTRA_JIT_ARGS)) and 'release' not in IMAGE
def
f
():
def
f
():
C
=
23
C
=
23
try
:
try
:
...
...
test/tests/with_ctxclass_order_of_access.py
View file @
7fb7aaa5
...
@@ -5,7 +5,7 @@ class Mgr(object):
...
@@ -5,7 +5,7 @@ class Mgr(object):
def
__enter__
(
self
):
def
__enter__
(
self
):
print
'Mgr.__enter__ accessed'
print
'Mgr.__enter__ accessed'
def
enterer
(
*
args
):
def
enterer
(
*
args
):
print
'Mgr.__enter__
%r called'
%
(
args
,)
print
'Mgr.__enter__
called'
return
23
return
23
return
enterer
return
enterer
...
@@ -13,7 +13,7 @@ class Mgr(object):
...
@@ -13,7 +13,7 @@ class Mgr(object):
def
__exit__
(
self
):
def
__exit__
(
self
):
print
'Mgr.__exit__ accessed'
print
'Mgr.__exit__ accessed'
def
exiter
(
*
args
):
def
exiter
(
*
args
):
print
'Mgr.__exit__
%r called'
%
(
args
,)
print
'Mgr.__exit__
called'
return
False
return
False
return
exiter
return
exiter
...
...
test/tests/with_functiondef.py
View file @
7fb7aaa5
# fail-if: (('-O' in EXTRA_JIT_ARGS) or ('-n' in EXTRA_JIT_ARGS)) and 'release' not in IMAGE
def
f
():
def
f
():
#
originally this exposed a bug in our irgen phase, so even `with None`
#
this exposes a bug in our irgen phase, so even `with None` bugs out here;
#
failed here; the bug happened before actual execution. Just to test more
#
the bug happens before actual execution. Just to test more things, though,
#
things, though,
we use an actual contextmanager here.
# we use an actual contextmanager here.
with
open
(
'/dev/null'
):
with
open
(
'/dev/null'
):
def
foo
():
def
foo
():
# raises a syntaxerror
pass
pass
f
()
f
()
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