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
151d1c84
Commit
151d1c84
authored
Jan 10, 2015
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'nonzero'
parents
eae111dd
c27db779
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
231 additions
and
29 deletions
+231
-29
src/analysis/type_analysis.cpp
src/analysis/type_analysis.cpp
+2
-0
src/codegen/ast_interpreter.cpp
src/codegen/ast_interpreter.cpp
+18
-5
src/codegen/irgen.cpp
src/codegen/irgen.cpp
+1
-1
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+17
-10
src/core/ast.cpp
src/core/ast.cpp
+7
-0
src/core/ast.h
src/core/ast.h
+11
-0
src/core/cfg.cpp
src/core/cfg.cpp
+46
-12
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+5
-0
test/tests/boolops.py
test/tests/boolops.py
+13
-1
test/tests/exception_subclasscheck.py
test/tests/exception_subclasscheck.py
+21
-0
test/tests/nonzero_exceptions.py
test/tests/nonzero_exceptions.py
+90
-0
No files found.
src/analysis/type_analysis.cpp
View file @
151d1c84
...
@@ -372,6 +372,8 @@ private:
...
@@ -372,6 +372,8 @@ private:
return
UNKNOWN
;
return
UNKNOWN
;
case
AST_LangPrimitive
:
:
NONE
:
case
AST_LangPrimitive
:
:
NONE
:
return
NONE
;
return
NONE
;
case
AST_LangPrimitive
:
:
NONZERO
:
return
BOOL
;
default:
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
}
...
...
src/codegen/ast_interpreter.cpp
View file @
151d1c84
...
@@ -403,7 +403,10 @@ Value ASTInterpreter::visit_slice(AST_Slice* node) {
...
@@ -403,7 +403,10 @@ Value ASTInterpreter::visit_slice(AST_Slice* node) {
}
}
Value
ASTInterpreter
::
visit_branch
(
AST_Branch
*
node
)
{
Value
ASTInterpreter
::
visit_branch
(
AST_Branch
*
node
)
{
if
(
nonzero
(
visit_expr
(
node
->
test
).
o
))
Value
v
=
visit_expr
(
node
->
test
);
ASSERT
(
v
.
o
==
True
||
v
.
o
==
False
,
"Should have called NONZERO before this branch"
);
if
(
v
.
o
==
True
)
next_block
=
node
->
iftrue
;
next_block
=
node
->
iftrue
;
else
else
next_block
=
node
->
iffalse
;
next_block
=
node
->
iffalse
;
...
@@ -441,6 +444,8 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
...
@@ -441,6 +444,8 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
if
(
phis
->
isPotentiallyUndefinedAfter
(
name
,
current_block
))
{
if
(
phis
->
isPotentiallyUndefinedAfter
(
name
,
current_block
))
{
bool
is_defined
=
it
!=
sym_table
.
end
();
bool
is_defined
=
it
!=
sym_table
.
end
();
sorted_symbol_table
[
getIsDefinedName
(
name
)]
=
(
Box
*
)
is_defined
;
sorted_symbol_table
[
getIsDefinedName
(
name
)]
=
(
Box
*
)
is_defined
;
if
(
is_defined
)
assert
(
it
->
getValue
()
!=
NULL
);
sorted_symbol_table
[
name
]
=
is_defined
?
it
->
getValue
()
:
NULL
;
sorted_symbol_table
[
name
]
=
is_defined
?
it
->
getValue
()
:
NULL
;
}
else
{
}
else
{
ASSERT
(
it
!=
sym_table
.
end
(),
"%s"
,
name
.
c_str
());
ASSERT
(
it
!=
sym_table
.
end
(),
"%s"
,
name
.
c_str
());
...
@@ -567,6 +572,7 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
...
@@ -567,6 +572,7 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
v
=
boxBool
(
isinstance
(
obj
.
o
,
cls
.
o
,
unboxInt
(
flags
.
o
)));
v
=
boxBool
(
isinstance
(
obj
.
o
,
cls
.
o
,
unboxInt
(
flags
.
o
)));
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
LOCALS
)
{
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
LOCALS
)
{
assert
(
node
->
args
.
size
()
==
0
);
BoxedDict
*
dict
=
new
BoxedDict
;
BoxedDict
*
dict
=
new
BoxedDict
;
for
(
auto
&
p
:
sym_table
)
{
for
(
auto
&
p
:
sym_table
)
{
llvm
::
StringRef
s
=
p
.
first
();
llvm
::
StringRef
s
=
p
.
first
();
...
@@ -576,6 +582,10 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
...
@@ -576,6 +582,10 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
dict
->
d
[
new
BoxedString
(
s
.
str
())]
=
p
.
second
;
dict
->
d
[
new
BoxedString
(
s
.
str
())]
=
p
.
second
;
}
}
v
=
dict
;
v
=
dict
;
}
else
if
(
node
->
opcode
==
AST_LangPrimitive
::
NONZERO
)
{
assert
(
node
->
args
.
size
()
==
1
);
Value
obj
=
visit_expr
(
node
->
args
[
0
]);
v
=
boxBool
(
nonzero
(
obj
.
o
));
}
else
}
else
RELEASE_ASSERT
(
0
,
"not implemented"
);
RELEASE_ASSERT
(
0
,
"not implemented"
);
return
v
;
return
v
;
...
@@ -735,8 +745,13 @@ Value ASTInterpreter::visit_raise(AST_Raise* node) {
...
@@ -735,8 +745,13 @@ Value ASTInterpreter::visit_raise(AST_Raise* node) {
}
}
Value
ASTInterpreter
::
visit_assert
(
AST_Assert
*
node
)
{
Value
ASTInterpreter
::
visit_assert
(
AST_Assert
*
node
)
{
if
(
!
nonzero
(
visit_expr
(
node
->
test
).
o
))
#ifndef NDEBUG
assertFail
(
source_info
->
parent_module
,
node
->
msg
?
visit_expr
(
node
->
msg
).
o
:
0
);
// Currently we only generate "assert 0" statements
Value
v
=
visit_expr
(
node
->
test
);
assert
(
v
.
o
->
cls
==
int_cls
&&
static_cast
<
BoxedInt
*>
(
v
.
o
)
->
n
==
0
);
#endif
assertFail
(
source_info
->
parent_module
,
node
->
msg
?
visit_expr
(
node
->
msg
).
o
:
0
);
return
Value
();
return
Value
();
}
}
...
@@ -1002,8 +1017,6 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
...
@@ -1002,8 +1017,6 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
SymMap
::
iterator
it
=
sym_table
.
find
(
node
->
id
);
SymMap
::
iterator
it
=
sym_table
.
find
(
node
->
id
);
if
(
it
!=
sym_table
.
end
())
{
if
(
it
!=
sym_table
.
end
())
{
Box
*
value
=
it
->
second
;
Box
*
value
=
it
->
second
;
if
(
!
value
)
assertNameDefined
(
value
,
node
->
id
.
c_str
(),
UnboundLocalError
,
true
);
return
value
;
return
value
;
}
}
...
...
src/codegen/irgen.cpp
View file @
151d1c84
...
@@ -752,7 +752,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
...
@@ -752,7 +752,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
// TODO: inneficient
// TODO: inneficient
sym_table
=
new
SymbolTable
(
*
sym_table
);
sym_table
=
new
SymbolTable
(
*
sym_table
);
assert
(
sym_table
->
count
(
name
->
id
));
ASSERT
(
sym_table
->
count
(
name
->
id
),
"%d %s
\n
"
,
block
->
idx
,
name
->
id
.
c_str
(
));
sym_table
->
erase
(
name
->
id
);
sym_table
->
erase
(
name
->
id
);
created_new_sym_table
=
true
;
created_new_sym_table
=
true
;
}
}
...
...
src/codegen/irgen/irgenerator.cpp
View file @
151d1c84
...
@@ -543,6 +543,17 @@ private:
...
@@ -543,6 +543,17 @@ private:
case
AST_LangPrimitive
:
:
NONE
:
{
case
AST_LangPrimitive
:
:
NONE
:
{
return
getNone
();
return
getNone
();
}
}
case
AST_LangPrimitive
:
:
NONZERO
:
{
assert
(
node
->
args
.
size
()
==
1
);
CompilerVariable
*
obj
=
evalExpr
(
node
->
args
[
0
],
unw_info
);
ConcreteCompilerVariable
*
rtn
=
obj
->
nonzero
(
emitter
,
getOpInfoForNode
(
node
,
unw_info
));
assert
(
rtn
->
getType
()
==
BOOL
);
llvm
::
Value
*
v
=
i1FromBool
(
emitter
,
rtn
);
assert
(
v
->
getType
()
==
g
.
i1
);
return
boolFromI1
(
emitter
,
v
);
}
default:
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
}
...
@@ -1812,22 +1823,18 @@ private:
...
@@ -1812,22 +1823,18 @@ private:
assert
(
state
!=
PARTIAL
);
assert
(
state
!=
PARTIAL
);
assert
(
val
);
assert
(
val
);
// ASSERT(val->getType() == BOOL, "%s", val->getType()->debugName().c_str());
// We could call nonzero here if there is no try-catch block?
ASSERT
(
val
->
getType
()
==
BOOL
,
"should have called NONZERO before this; is %s"
,
val
->
getType
()
->
debugName
().
c_str
());
llvm
::
Value
*
v
=
i1FromBool
(
emitter
,
static_cast
<
ConcreteCompilerVariable
*>
(
val
));
assert
(
v
->
getType
()
==
g
.
i1
);
ConcreteCompilerVariable
*
nonzero
=
val
->
nonzero
(
emitter
,
getOpInfoForNode
(
node
,
unw_info
));
ASSERT
(
nonzero
->
getType
()
==
BOOL
,
"%s %s"
,
val
->
getType
()
->
debugName
().
c_str
(),
nonzero
->
getType
()
->
debugName
().
c_str
());
val
->
decvref
(
emitter
);
llvm
::
Value
*
llvm_nonzero
=
i1FromBool
(
emitter
,
nonzero
);
llvm
::
BasicBlock
*
iftrue
=
entry_blocks
[
node
->
iftrue
];
llvm
::
BasicBlock
*
iftrue
=
entry_blocks
[
node
->
iftrue
];
llvm
::
BasicBlock
*
iffalse
=
entry_blocks
[
node
->
iffalse
];
llvm
::
BasicBlock
*
iffalse
=
entry_blocks
[
node
->
iffalse
];
nonzero
->
decvref
(
emitter
);
endBlock
(
FINISHED
);
endBlock
(
FINISHED
);
emitter
.
getBuilder
()
->
CreateCondBr
(
llvm_nonzero
,
iftrue
,
iffalse
);
emitter
.
getBuilder
()
->
CreateCondBr
(
v
,
iftrue
,
iffalse
);
}
}
void
doExpr
(
AST_Expr
*
node
,
UnwindInfo
unw_info
)
{
void
doExpr
(
AST_Expr
*
node
,
UnwindInfo
unw_info
)
{
...
...
src/core/ast.cpp
View file @
151d1c84
...
@@ -24,6 +24,10 @@
...
@@ -24,6 +24,10 @@
namespace
pyston
{
namespace
pyston
{
#ifndef NDEBUG
int
AST
::
next_lineno
=
100000
;
#endif
llvm
::
StringRef
getOpSymbol
(
int
op_type
)
{
llvm
::
StringRef
getOpSymbol
(
int
op_type
)
{
switch
(
op_type
)
{
switch
(
op_type
)
{
case
AST_TYPE
:
:
Add
:
case
AST_TYPE
:
:
Add
:
...
@@ -1448,6 +1452,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
...
@@ -1448,6 +1452,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case
AST_LangPrimitive
:
:
NONE
:
case
AST_LangPrimitive
:
:
NONE
:
printf
(
"NONE"
);
printf
(
"NONE"
);
break
;
break
;
case
AST_LangPrimitive
:
:
NONZERO
:
printf
(
"NONZERO"
);
break
;
default:
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
opcode
);
}
}
...
...
src/core/ast.h
View file @
151d1c84
...
@@ -148,7 +148,17 @@ public:
...
@@ -148,7 +148,17 @@ public:
virtual
void
accept
(
ASTVisitor
*
v
)
=
0
;
virtual
void
accept
(
ASTVisitor
*
v
)
=
0
;
#ifndef NDEBUG
private:
static
int
next_lineno
;
public:
// In debug mode, initialize lineno to something unique, so that if we see something ridiculous
// appear in the traceback, we can isolate the allocation which created it.
AST
(
AST_TYPE
::
AST_TYPE
type
)
:
type
(
type
),
lineno
(
++
next_lineno
)
{}
#else
AST
(
AST_TYPE
::
AST_TYPE
type
)
:
type
(
type
)
{}
AST
(
AST_TYPE
::
AST_TYPE
type
)
:
type
(
type
)
{}
#endif
};
};
class
AST_expr
:
public
AST
{
class
AST_expr
:
public
AST
{
...
@@ -966,6 +976,7 @@ public:
...
@@ -966,6 +976,7 @@ public:
IMPORT_NAME
,
IMPORT_NAME
,
IMPORT_STAR
,
IMPORT_STAR
,
NONE
,
NONE
,
NONZERO
,
}
opcode
;
}
opcode
;
std
::
vector
<
AST_expr
*>
args
;
std
::
vector
<
AST_expr
*>
args
;
...
...
src/core/cfg.cpp
View file @
151d1c84
...
@@ -131,6 +131,22 @@ private:
...
@@ -131,6 +131,22 @@ private:
return
NULL
;
return
NULL
;
}
}
AST_expr
*
callNonzero
(
AST_expr
*
e
)
{
AST_LangPrimitive
*
call
=
new
AST_LangPrimitive
(
AST_LangPrimitive
::
NONZERO
);
call
->
args
.
push_back
(
e
);
call
->
lineno
=
e
->
lineno
;
call
->
col_offset
=
e
->
col_offset
;
// Simple optimization: allow the generation of nested nodes if there isn't a
// current exc handler.
if
(
exc_handlers
.
size
()
==
0
)
return
call
;
auto
name
=
nodeName
(
e
);
pushAssign
(
name
,
call
);
return
makeName
(
name
,
AST_TYPE
::
Load
);
}
AST_expr
*
applyComprehensionCall
(
AST_DictComp
*
node
,
AST_Name
*
name
)
{
AST_expr
*
applyComprehensionCall
(
AST_DictComp
*
node
,
AST_Name
*
name
)
{
AST_expr
*
key
=
remapExpr
(
node
->
key
);
AST_expr
*
key
=
remapExpr
(
node
->
key
);
AST_expr
*
value
=
remapExpr
(
node
->
value
);
AST_expr
*
value
=
remapExpr
(
node
->
value
);
...
@@ -179,7 +195,7 @@ private:
...
@@ -179,7 +195,7 @@ private:
push_back
(
j
);
push_back
(
j
);
curblock
=
test_block
;
curblock
=
test_block
;
AST_expr
*
test_call
=
remapExpr
(
makeCall
(
hasnext_attr
));
AST_expr
*
test_call
=
callNonzero
(
remapExpr
(
makeCall
(
hasnext_attr
)
));
CFGBlock
*
body_block
=
cfg
->
addBlock
();
CFGBlock
*
body_block
=
cfg
->
addBlock
();
body_block
->
info
=
"comprehension_body"
;
body_block
->
info
=
"comprehension_body"
;
...
@@ -204,7 +220,7 @@ private:
...
@@ -204,7 +220,7 @@ private:
pushAssign
(
c
->
target
,
makeName
(
next_name
,
AST_TYPE
::
Load
));
pushAssign
(
c
->
target
,
makeName
(
next_name
,
AST_TYPE
::
Load
));
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
AST_expr
*
remapped
=
remapExpr
(
if_condition
);
AST_expr
*
remapped
=
callNonzero
(
remapExpr
(
if_condition
)
);
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapped
;
br
->
test
=
remapped
;
push_back
(
br
);
push_back
(
br
);
...
@@ -284,7 +300,7 @@ private:
...
@@ -284,7 +300,7 @@ private:
AST_Branch
*
makeBranch
(
AST_expr
*
test
)
{
AST_Branch
*
makeBranch
(
AST_expr
*
test
)
{
AST_Branch
*
rtn
=
new
AST_Branch
();
AST_Branch
*
rtn
=
new
AST_Branch
();
rtn
->
test
=
test
;
rtn
->
test
=
callNonzero
(
test
)
;
rtn
->
col_offset
=
test
->
col_offset
;
rtn
->
col_offset
=
test
->
col_offset
;
rtn
->
lineno
=
test
->
lineno
;
rtn
->
lineno
=
test
->
lineno
;
return
rtn
;
return
rtn
;
...
@@ -520,7 +536,7 @@ private:
...
@@ -520,7 +536,7 @@ private:
pushAssign
(
name
,
val
);
pushAssign
(
name
,
val
);
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
_dup
(
val
);
br
->
test
=
callNonzero
(
_dup
(
val
)
);
push_back
(
br
);
push_back
(
br
);
CFGBlock
*
was_block
=
curblock
;
CFGBlock
*
was_block
=
curblock
;
...
@@ -637,7 +653,7 @@ private:
...
@@ -637,7 +653,7 @@ private:
pushAssign
(
name
,
val
);
pushAssign
(
name
,
val
);
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
makeName
(
name
,
AST_TYPE
::
Load
);
br
->
test
=
callNonzero
(
makeName
(
name
,
AST_TYPE
::
Load
)
);
push_back
(
br
);
push_back
(
br
);
CFGBlock
*
was_block
=
curblock
;
CFGBlock
*
was_block
=
curblock
;
...
@@ -725,6 +741,9 @@ private:
...
@@ -725,6 +741,9 @@ private:
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
for
(
AST_expr
*
if_condition
:
c
->
ifs
)
{
AST_If
*
if_block
=
new
AST_If
();
AST_If
*
if_block
=
new
AST_If
();
// Note: don't call callNonzero here, since we are generating
// AST inside a new functiondef which will go through the CFG
// process again.
if_block
->
test
=
if_condition
;
if_block
->
test
=
if_condition
;
insert_point
->
push_back
(
if_block
);
insert_point
->
push_back
(
if_block
);
...
@@ -751,13 +770,14 @@ private:
...
@@ -751,13 +770,14 @@ private:
AST_expr
*
remapIfExp
(
AST_IfExp
*
node
)
{
AST_expr
*
remapIfExp
(
AST_IfExp
*
node
)
{
std
::
string
rtn_name
=
nodeName
(
node
);
std
::
string
rtn_name
=
nodeName
(
node
);
CFGBlock
*
starting_block
=
curblock
;
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
col_offset
=
node
->
col_offset
;
br
->
col_offset
=
node
->
col_offset
;
br
->
lineno
=
node
->
lineno
;
br
->
lineno
=
node
->
lineno
;
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
push_back
(
br
);
CFGBlock
*
starting_block
=
curblock
;
CFGBlock
*
iftrue
=
cfg
->
addBlock
();
CFGBlock
*
iftrue
=
cfg
->
addBlock
();
iftrue
->
info
=
"iftrue"
;
iftrue
->
info
=
"iftrue"
;
br
->
iftrue
=
iftrue
;
br
->
iftrue
=
iftrue
;
...
@@ -1055,6 +1075,10 @@ public:
...
@@ -1055,6 +1075,10 @@ public:
#endif
#endif
curblock
->
push_back
(
node
);
curblock
->
push_back
(
node
);
return
;
return
;
}
else
if
(
asgn
->
value
->
type
==
AST_TYPE
::
Name
&&
ast_cast
<
AST_Name
>
(
asgn
->
value
)
->
id
[
0
]
==
'#'
)
{
// Assigning from one temporary name to another:
curblock
->
push_back
(
node
);
return
;
}
}
}
}
}
}
...
@@ -1246,7 +1270,7 @@ public:
...
@@ -1246,7 +1270,7 @@ public:
bool
visit_assert
(
AST_Assert
*
node
)
override
{
bool
visit_assert
(
AST_Assert
*
node
)
override
{
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
push_back
(
br
);
CFGBlock
*
iffalse
=
cfg
->
addBlock
();
CFGBlock
*
iffalse
=
cfg
->
addBlock
();
...
@@ -1498,7 +1522,7 @@ public:
...
@@ -1498,7 +1522,7 @@ public:
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
col_offset
=
node
->
col_offset
;
br
->
col_offset
=
node
->
col_offset
;
br
->
lineno
=
node
->
lineno
;
br
->
lineno
=
node
->
lineno
;
br
->
test
=
remapExpr
(
node
->
test
);
br
->
test
=
callNonzero
(
remapExpr
(
node
->
test
)
);
push_back
(
br
);
push_back
(
br
);
CFGBlock
*
starting_block
=
curblock
;
CFGBlock
*
starting_block
=
curblock
;
...
@@ -1827,7 +1851,7 @@ public:
...
@@ -1827,7 +1851,7 @@ public:
is_caught_here
->
args
.
push_back
(
makeNum
(
1
));
// flag: false_on_noncls
is_caught_here
->
args
.
push_back
(
makeNum
(
1
));
// flag: false_on_noncls
AST_Branch
*
br
=
new
AST_Branch
();
AST_Branch
*
br
=
new
AST_Branch
();
br
->
test
=
remapExpr
(
is_caught_here
);
br
->
test
=
callNonzero
(
remapExpr
(
is_caught_here
)
);
CFGBlock
*
exc_handle
=
cfg
->
addBlock
();
CFGBlock
*
exc_handle
=
cfg
->
addBlock
();
exc_next
=
cfg
->
addDeferredBlock
();
exc_next
=
cfg
->
addDeferredBlock
();
...
@@ -2153,8 +2177,18 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
...
@@ -2153,8 +2177,18 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
for
(
auto
b
:
rtn
->
blocks
)
for
(
auto
b
:
rtn
->
blocks
)
flatten
(
b
->
body
,
flattened
,
true
);
flatten
(
b
->
body
,
flattened
,
true
);
std
::
unordered_set
<
AST
*>
deduped
(
flattened
.
begin
(),
flattened
.
end
());
std
::
unordered_map
<
AST
*
,
int
>
deduped
;
assert
(
deduped
.
size
()
==
flattened
.
size
());
bool
no_dups
=
true
;
for
(
auto
e
:
flattened
)
{
deduped
[
e
]
++
;
if
(
deduped
[
e
]
==
2
)
{
printf
(
"Duplicated: "
);
print_ast
(
e
);
printf
(
"
\n
"
);
no_dups
=
false
;
}
}
assert
(
no_dups
);
// TODO make sure the result of Invoke nodes are not used on the exceptional path
// TODO make sure the result of Invoke nodes are not used on the exceptional path
#endif
#endif
...
...
src/runtime/objmodel.cpp
View file @
151d1c84
...
@@ -1631,6 +1631,8 @@ bool isUserDefined(BoxedClass* cls) {
...
@@ -1631,6 +1631,8 @@ bool isUserDefined(BoxedClass* cls) {
}
}
extern
"C"
bool
nonzero
(
Box
*
obj
)
{
extern
"C"
bool
nonzero
(
Box
*
obj
)
{
assert
(
gc
::
isValidGCObject
(
obj
));
static
StatCounter
slowpath_nonzero
(
"slowpath_nonzero"
);
static
StatCounter
slowpath_nonzero
(
"slowpath_nonzero"
);
std
::
unique_ptr
<
Rewriter
>
rewriter
(
std
::
unique_ptr
<
Rewriter
>
rewriter
(
...
@@ -1689,6 +1691,8 @@ extern "C" bool nonzero(Box* obj) {
...
@@ -1689,6 +1691,8 @@ extern "C" bool nonzero(Box* obj) {
// go through descriptor logic
// go through descriptor logic
Box
*
func
=
getclsattr_internal
(
obj
,
"__nonzero__"
,
NULL
);
Box
*
func
=
getclsattr_internal
(
obj
,
"__nonzero__"
,
NULL
);
if
(
!
func
)
func
=
getclsattr_internal
(
obj
,
"__len__"
,
NULL
);
if
(
func
==
NULL
)
{
if
(
func
==
NULL
)
{
ASSERT
(
isUserDefined
(
obj
->
cls
)
||
obj
->
cls
==
classobj_cls
,
"%s.__nonzero__"
,
ASSERT
(
isUserDefined
(
obj
->
cls
)
||
obj
->
cls
==
classobj_cls
,
"%s.__nonzero__"
,
...
@@ -1697,6 +1701,7 @@ extern "C" bool nonzero(Box* obj) {
...
@@ -1697,6 +1701,7 @@ extern "C" bool nonzero(Box* obj) {
}
}
Box
*
r
=
runtimeCall0
(
func
,
ArgPassSpec
(
0
));
Box
*
r
=
runtimeCall0
(
func
,
ArgPassSpec
(
0
));
// I believe this behavior is handled by the slot wrappers in CPython:
if
(
r
->
cls
==
bool_cls
)
{
if
(
r
->
cls
==
bool_cls
)
{
BoxedBool
*
b
=
static_cast
<
BoxedBool
*>
(
r
);
BoxedBool
*
b
=
static_cast
<
BoxedBool
*>
(
r
);
bool
rtn
=
b
->
n
;
bool
rtn
=
b
->
n
;
...
...
test/tests/boolops.py
View file @
151d1c84
...
@@ -34,4 +34,16 @@ if 0:
...
@@ -34,4 +34,16 @@ if 0:
print
bool
(
c
)
# this will fail
print
bool
(
c
)
# this will fail
print
1
and
c
# Note: nonzero isn't called on the second argument!
print
1
and
c
# Note: nonzero isn't called on the second argument!
print
C
(
True
)
or
1
# prints the object repr, not the nonzero repr
print
C
(
True
)
or
1
# prints the object repr, not the nonzero repr
print
c
and
1
print
# nonzero should fall back on __len__ if that exists but __nonzero__ doesn't:
class
D
(
object
):
def
__init__
(
self
,
n
):
self
.
n
=
n
def
__len__
(
self
):
print
"__len__"
return
self
.
n
for
i
in
xrange
(
0
,
3
):
print
i
,
bool
(
D
(
i
))
test/tests/exception_subclasscheck.py
View file @
151d1c84
...
@@ -3,6 +3,9 @@
...
@@ -3,6 +3,9 @@
# Exception-catching is supposed to go through __subclasscheck__
# Exception-catching is supposed to go through __subclasscheck__
class
MyException
(
Exception
):
pass
class
M
(
type
):
class
M
(
type
):
def
__instancecheck__
(
self
,
instance
):
def
__instancecheck__
(
self
,
instance
):
print
"instancecheck"
,
instance
print
"instancecheck"
,
instance
...
@@ -10,10 +13,19 @@ class M(type):
...
@@ -10,10 +13,19 @@ class M(type):
def
__subclasscheck__
(
self
,
sub
):
def
__subclasscheck__
(
self
,
sub
):
print
"subclasscheck"
,
sub
print
"subclasscheck"
,
sub
if
self
.
throw_on_subclasscheck
:
raise
MyException
()
return
True
return
True
class
E
(
Exception
):
class
E
(
Exception
):
__metaclass__
=
M
__metaclass__
=
M
throw_on_subclasscheck
=
False
class
F
(
Exception
):
__metaclass__
=
M
throw_on_subclasscheck
=
True
print
1
print
1
print
isinstance
(
E
(),
E
)
# does not print anything due to special-casing
print
isinstance
(
E
(),
E
)
# does not print anything due to special-casing
...
@@ -35,3 +47,12 @@ except E:
...
@@ -35,3 +47,12 @@ except E:
pass
pass
print
5
print
5
# Exceptions in __subclasscheck__ should get ignored:
try
:
1
/
0
except
F
:
print
"shouldn't get here"
except
ZeroDivisionError
:
print
"ok"
test/tests/nonzero_exceptions.py
0 → 100644
View file @
151d1c84
class
MyException
(
Exception
):
pass
class
C
(
object
):
def
__init__
(
self
,
x
):
self
.
x
=
x
def
__nonzero__
(
self
):
raise
MyException
(
self
.
x
)
def
__repr__
(
self
):
return
"<C %r>"
%
self
.
x
# Make sure that we can handle nonzero() throwing an exception wherever it occurs:
try
:
print
C
(
1
)
and
1
except
MyException
,
e
:
print
e
try
:
print
C
(
2
)
or
1
except
MyException
,
e
:
print
e
try
:
if
C
(
3
):
pass
except
MyException
,
e
:
print
e
try
:
while
C
(
4
):
pass
except
MyException
,
e
:
print
e
try
:
assert
C
(
5
)
except
MyException
,
e
:
print
e
try
:
print
[
1
for
i
in
range
(
5
)
if
C
(
6
)]
except
MyException
,
e
:
print
e
try
:
print
list
(
1
for
i
in
range
(
5
)
if
C
(
7
))
except
MyException
,
e
:
print
e
try
:
print
1
if
C
(
8
)
else
0
except
MyException
,
e
:
print
e
class
M
(
type
):
def
__instancecheck__
(
self
,
instance
):
print
"instancecheck"
,
instance
return
C
(
9
)
def
__subclasscheck__
(
self
,
sub
):
print
"subclasscheck"
,
sub
return
C
(
10
)
class
F
(
Exception
):
__metaclass__
=
M
try
:
try
:
1
/
0
except
C
(
"a"
)
or
1
:
print
"shouldn't get here"
print
"shouldn't get here 2"
except
MyException
,
e
:
print
e
class
E
(
object
):
def
__lt__
(
self
,
rhs
):
return
C
(
"false"
)
# This is ok because it doesn't evaluate the result of the comparison:
print
E
()
<
1
try
:
# This is not ok because it will!
print
E
()
<
1
<
1
except
MyException
,
e
:
print
e
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