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
5bbd4c50
Commit
5bbd4c50
authored
Apr 17, 2014
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Wow, I guess augassign is quite a bit more complicated than I thought
parent
d498e5ca
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
274 additions
and
94 deletions
+274
-94
src/analysis/function_analysis.cpp
src/analysis/function_analysis.cpp
+0
-22
src/analysis/type_analysis.cpp
src/analysis/type_analysis.cpp
+45
-32
src/codegen/compvars.cpp
src/codegen/compvars.cpp
+9
-0
src/codegen/irgen/irgenerator.cpp
src/codegen/irgen/irgenerator.cpp
+23
-24
src/codegen/patchpoints.cpp
src/codegen/patchpoints.cpp
+1
-1
src/codegen/runtime_hooks.cpp
src/codegen/runtime_hooks.cpp
+1
-1
src/codegen/runtime_hooks.h
src/codegen/runtime_hooks.h
+1
-1
src/core/ast.cpp
src/core/ast.cpp
+22
-0
src/core/ast.h
src/core/ast.h
+16
-0
src/core/cfg.cpp
src/core/cfg.cpp
+74
-9
src/runtime/inline/link_forcer.cpp
src/runtime/inline/link_forcer.cpp
+1
-1
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+1
-1
src/runtime/objmodel.h
src/runtime/objmodel.h
+1
-1
test/tests/augassign.py
test/tests/augassign.py
+15
-0
test/tests/augassign_analysis.py
test/tests/augassign_analysis.py
+64
-1
No files found.
src/analysis/function_analysis.cpp
View file @
5bbd4c50
...
@@ -72,23 +72,6 @@ class LivenessBBVisitor : public NoopASTVisitor {
...
@@ -72,23 +72,6 @@ class LivenessBBVisitor : public NoopASTVisitor {
}
}
return
true
;
return
true
;
}
}
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
AST
*
target
=
node
->
target
;
switch
(
target
->
type
)
{
case
AST_TYPE
:
:
Name
:
{
AST_Name
*
n
=
static_cast
<
AST_Name
*>
(
target
);
_doLoad
(
n
->
id
);
_doStore
(
n
->
id
);
break
;
}
default:
RELEASE_ASSERT
(
0
,
"%d"
,
target
->
type
);
}
node
->
value
->
accept
(
this
);
return
true
;
}
};
};
bool
LivenessAnalysis
::
isLiveAtEnd
(
const
std
::
string
&
name
,
CFGBlock
*
block
)
{
bool
LivenessAnalysis
::
isLiveAtEnd
(
const
std
::
string
&
name
,
CFGBlock
*
block
)
{
...
@@ -227,11 +210,6 @@ class DefinednessVisitor : public ASTVisitor {
...
@@ -227,11 +210,6 @@ class DefinednessVisitor : public ASTVisitor {
return
true
;
return
true
;
}
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
_doSet
(
node
->
target
);
return
true
;
}
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
if
(
node
->
kwarg
)
_doSet
(
node
->
kwarg
);
if
(
node
->
kwarg
)
_doSet
(
node
->
kwarg
);
if
(
node
->
vararg
.
size
())
_doSet
(
node
->
vararg
);
if
(
node
->
vararg
.
size
())
_doSet
(
node
->
vararg
);
...
...
src/analysis/type_analysis.cpp
View file @
5bbd4c50
...
@@ -158,7 +158,6 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -158,7 +158,6 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
virtual
void
*
visit_attribute
(
AST_Attribute
*
node
)
{
virtual
void
*
visit_attribute
(
AST_Attribute
*
node
)
{
CompilerType
*
t
=
getType
(
node
->
value
);
CompilerType
*
t
=
getType
(
node
->
value
);
assert
(
node
->
ctx_type
==
AST_TYPE
::
Load
);
CompilerType
*
rtn
=
t
->
getattrType
(
&
node
->
attr
,
false
);
CompilerType
*
rtn
=
t
->
getattrType
(
&
node
->
attr
,
false
);
//if (speculation != TypeAnalysis::NONE && (node->attr == "x" || node->attr == "y" || node->attr == "z")) {
//if (speculation != TypeAnalysis::NONE && (node->attr == "x" || node->attr == "y" || node->attr == "z")) {
...
@@ -184,6 +183,31 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -184,6 +183,31 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
return
rtn
;
return
rtn
;
}
}
virtual
void
*
visit_augbinop
(
AST_AugBinOp
*
node
)
{
CompilerType
*
left
=
getType
(
node
->
left
);
CompilerType
*
right
=
getType
(
node
->
right
);
// TODO this isn't the exact behavior
std
::
string
name
=
getOpName
(
node
->
op_type
);
name
=
"__i"
+
name
.
substr
(
2
);
CompilerType
*
attr_type
=
left
->
getattrType
(
&
name
,
true
);
if
(
attr_type
==
UNDEF
)
attr_type
=
UNKNOWN
;
std
::
vector
<
CompilerType
*>
arg_types
;
arg_types
.
push_back
(
right
);
CompilerType
*
rtn
=
attr_type
->
callType
(
arg_types
);
if
(
left
==
right
&&
(
left
==
INT
||
left
==
FLOAT
))
{
ASSERT
((
rtn
==
left
||
rtn
==
UNKNOWN
)
&&
"not strictly required but probably something worth looking into"
,
"%s %s %s -> %s"
,
left
->
debugName
().
c_str
(),
name
.
c_str
(),
right
->
debugName
().
c_str
(),
rtn
->
debugName
().
c_str
());
}
ASSERT
(
rtn
!=
UNDEF
,
"need to implement the actual semantics here for %s.%s"
,
left
->
debugName
().
c_str
(),
name
.
c_str
());
return
rtn
;
}
virtual
void
*
visit_binop
(
AST_BinOp
*
node
)
{
virtual
void
*
visit_binop
(
AST_BinOp
*
node
)
{
CompilerType
*
left
=
getType
(
node
->
left
);
CompilerType
*
left
=
getType
(
node
->
left
);
CompilerType
*
right
=
getType
(
node
->
right
);
CompilerType
*
right
=
getType
(
node
->
right
);
...
@@ -192,14 +216,19 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -192,14 +216,19 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
std
::
string
name
=
getOpName
(
node
->
op_type
);
std
::
string
name
=
getOpName
(
node
->
op_type
);
CompilerType
*
attr_type
=
left
->
getattrType
(
&
name
,
true
);
CompilerType
*
attr_type
=
left
->
getattrType
(
&
name
,
true
);
if
(
attr_type
==
UNDEF
)
attr_type
=
UNKNOWN
;
std
::
vector
<
CompilerType
*>
arg_types
;
std
::
vector
<
CompilerType
*>
arg_types
;
arg_types
.
push_back
(
right
);
arg_types
.
push_back
(
right
);
CompilerType
*
rtn
=
attr_type
->
callType
(
arg_types
);
CompilerType
*
rtn
=
attr_type
->
callType
(
arg_types
);
if
(
left
==
right
&&
(
left
==
INT
||
left
==
FLOAT
))
{
if
(
left
==
right
&&
(
left
==
INT
||
left
==
FLOAT
))
{
ASSERT
((
rtn
==
left
||
rtn
==
UN
DEF
)
&&
"not strictly required but probably something worth looking into"
,
"%s %s"
,
name
.
c_str
(),
rtn
->
debugName
().
c_str
());
ASSERT
((
rtn
==
left
||
rtn
==
UN
KNOWN
)
&&
"not strictly required but probably something worth looking into"
,
"%s %s %s -> %s"
,
left
->
debugName
().
c_str
(),
name
.
c_str
(),
right
->
debugName
()
.
c_str
(),
rtn
->
debugName
().
c_str
());
}
}
ASSERT
(
rtn
!=
UNDEF
,
"need to implement the actual semantics here for %s.%s"
,
left
->
debugName
().
c_str
(),
name
.
c_str
());
return
rtn
;
return
rtn
;
}
}
...
@@ -254,6 +283,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -254,6 +283,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
}
}
std
::
string
name
=
getOpName
(
node
->
ops
[
0
]);
std
::
string
name
=
getOpName
(
node
->
ops
[
0
]);
CompilerType
*
attr_type
=
left
->
getattrType
(
&
name
,
true
);
CompilerType
*
attr_type
=
left
->
getattrType
(
&
name
,
true
);
if
(
attr_type
==
UNDEF
)
attr_type
=
UNKNOWN
;
std
::
vector
<
CompilerType
*>
arg_types
;
std
::
vector
<
CompilerType
*>
arg_types
;
arg_types
.
push_back
(
right
);
arg_types
.
push_back
(
right
);
return
attr_type
->
callType
(
arg_types
);
return
attr_type
->
callType
(
arg_types
);
...
@@ -297,10 +330,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -297,10 +330,10 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
CompilerType
*
&
t
=
sym_table
[
node
->
id
];
CompilerType
*
&
t
=
sym_table
[
node
->
id
];
if
(
t
==
NULL
)
{
if
(
t
==
NULL
)
{
if
(
VERBOSITY
()
>=
2
)
{
//
if (VERBOSITY() >= 2) {
printf
(
"%s is undefined!
\n
"
,
node
->
id
.
c_str
());
//
printf("%s is undefined!\n", node->id.c_str());
raise
(
SIGTRAP
);
//
raise(SIGTRAP);
}
//
}
t
=
UNDEF
;
t
=
UNDEF
;
}
}
return
t
;
return
t
;
...
@@ -362,31 +395,6 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...
@@ -362,31 +395,6 @@ class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
}
}
}
}
virtual
void
visit_augassign
(
AST_AugAssign
*
node
)
{
CompilerType
*
t
=
getType
(
node
->
target
);
CompilerType
*
v
=
getType
(
node
->
value
);
// TODO this isn't the right behavior
std
::
string
name
=
getOpName
(
node
->
op_type
);
name
=
"__i"
+
name
.
substr
(
2
);
CompilerType
*
attr_type
=
t
->
getattrType
(
&
name
,
true
);
ASSERT
(
attr_type
!=
UNDEF
,
"need to implement the actual semantics here"
);
std
::
vector
<
CompilerType
*>
arg_types
;
arg_types
.
push_back
(
v
);
CompilerType
*
rtn
=
attr_type
->
callType
(
arg_types
);
if
(
VERBOSITY
()
>=
2
)
printf
(
"%s aug= %s -> %s
\n
"
,
t
->
debugName
().
c_str
(),
v
->
debugName
().
c_str
(),
rtn
->
debugName
().
c_str
());
if
(
t
==
INT
&&
v
==
INT
)
assert
(
rtn
==
INT
);
if
(
t
==
FLOAT
&&
v
==
FLOAT
)
assert
(
rtn
==
FLOAT
);
_doSet
(
node
->
target
,
rtn
);
}
virtual
void
visit_branch
(
AST_Branch
*
node
)
{
virtual
void
visit_branch
(
AST_Branch
*
node
)
{
if
(
EXPAND_UNNEEDED
)
{
if
(
EXPAND_UNNEEDED
)
{
getType
(
node
->
test
);
getType
(
node
->
test
);
...
@@ -483,9 +491,14 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
...
@@ -483,9 +491,14 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
return
true
;
return
true
;
}
}
if
(
lhs
==
UNDEF
||
rhs
==
UNDEF
)
if
(
lhs
==
UNDEF
)
return
false
;
return
false
;
if
(
rhs
==
UNDEF
)
{
rhs
=
lhs
;
return
true
;
}
if
(
lhs
==
rhs
)
if
(
lhs
==
rhs
)
return
false
;
return
false
;
if
(
rhs
==
UNKNOWN
)
if
(
rhs
==
UNKNOWN
)
...
...
src/codegen/compvars.cpp
View file @
5bbd4c50
...
@@ -1081,6 +1081,15 @@ class StrConstantType : public ValuedCompilerType<std::string*> {
...
@@ -1081,6 +1081,15 @@ class StrConstantType : public ValuedCompilerType<std::string*> {
return
rtn
;
return
rtn
;
}
}
virtual
CompilerVariable
*
dup
(
VAR
*
var
,
DupCache
&
cache
)
{
CompilerVariable
*
&
rtn
=
cache
[
var
];
if
(
rtn
==
NULL
)
{
rtn
=
new
VAR
(
this
,
var
->
getValue
(),
var
->
isGrabbed
());
}
return
rtn
;
}
};
};
ValuedCompilerType
<
std
::
string
*>
*
STR_CONSTANT
=
new
StrConstantType
();
ValuedCompilerType
<
std
::
string
*>
*
STR_CONSTANT
=
new
StrConstantType
();
...
...
src/codegen/irgen/irgenerator.cpp
View file @
5bbd4c50
...
@@ -218,7 +218,6 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -218,7 +218,6 @@ class IRGeneratorImpl : public IRGenerator {
CompilerVariable
*
evalAttribute
(
AST_Attribute
*
node
)
{
CompilerVariable
*
evalAttribute
(
AST_Attribute
*
node
)
{
assert
(
state
!=
PARTIAL
);
assert
(
state
!=
PARTIAL
);
assert
(
node
->
ctx_type
==
AST_TYPE
::
Load
);
CompilerVariable
*
value
=
evalExpr
(
node
->
value
);
CompilerVariable
*
value
=
evalExpr
(
node
->
value
);
...
@@ -237,7 +236,7 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -237,7 +236,7 @@ class IRGeneratorImpl : public IRGenerator {
}
}
enum
BinExpType
{
enum
BinExpType
{
Aug
Assign
,
Aug
BinOp
,
BinOp
,
BinOp
,
Compare
,
Compare
,
};
};
...
@@ -257,7 +256,7 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -257,7 +256,7 @@ class IRGeneratorImpl : public IRGenerator {
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
div_i64_i64
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
div_i64_i64
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
}
else
if
(
type
==
AST_TYPE
::
Pow
)
{
}
else
if
(
type
==
AST_TYPE
::
Pow
)
{
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
pow_i64_i64
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
pow_i64_i64
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
}
else
if
(
exp_type
==
BinOp
||
exp_type
==
Aug
Assign
)
{
}
else
if
(
exp_type
==
BinOp
||
exp_type
==
Aug
BinOp
)
{
llvm
::
Instruction
::
BinaryOps
binopcode
;
llvm
::
Instruction
::
BinaryOps
binopcode
;
switch
(
type
)
{
switch
(
type
)
{
case
AST_TYPE
:
:
Add
:
case
AST_TYPE
:
:
Add
:
...
@@ -347,7 +346,7 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -347,7 +346,7 @@ class IRGeneratorImpl : public IRGenerator {
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
div_float_float
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
div_float_float
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
}
else
if
(
type
==
AST_TYPE
::
Pow
)
{
}
else
if
(
type
==
AST_TYPE
::
Pow
)
{
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
pow_float_float
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
v
=
emitter
.
getBuilder
()
->
CreateCall2
(
g
.
funcs
.
pow_float_float
,
converted_left
->
getValue
(),
converted_right
->
getValue
());
}
else
if
(
exp_type
==
BinOp
||
exp_type
==
Aug
Assign
)
{
}
else
if
(
exp_type
==
BinOp
||
exp_type
==
Aug
BinOp
)
{
llvm
::
Instruction
::
BinaryOps
binopcode
;
llvm
::
Instruction
::
BinaryOps
binopcode
;
switch
(
type
)
{
switch
(
type
)
{
case
AST_TYPE
:
:
Add
:
case
AST_TYPE
:
:
Add
:
...
@@ -428,9 +427,9 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -428,9 +427,9 @@ class IRGeneratorImpl : public IRGenerator {
if
(
exp_type
==
BinOp
)
{
if
(
exp_type
==
BinOp
)
{
rt_func
=
g
.
funcs
.
binop
;
rt_func
=
g
.
funcs
.
binop
;
rt_func_addr
=
(
void
*
)
binop
;
rt_func_addr
=
(
void
*
)
binop
;
}
else
if
(
exp_type
==
Aug
Assign
)
{
}
else
if
(
exp_type
==
Aug
BinOp
)
{
rt_func
=
g
.
funcs
.
aug
assign
;
rt_func
=
g
.
funcs
.
aug
binop
;
rt_func_addr
=
(
void
*
)
aug
assign
;
rt_func_addr
=
(
void
*
)
aug
binop
;
}
else
{
}
else
{
rt_func
=
g
.
funcs
.
compare
;
rt_func
=
g
.
funcs
.
compare
;
rt_func_addr
=
(
void
*
)
compare
;
rt_func_addr
=
(
void
*
)
compare
;
...
@@ -471,6 +470,20 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -471,6 +470,20 @@ class IRGeneratorImpl : public IRGenerator {
return
rtn
;
return
rtn
;
}
}
CompilerVariable
*
evalAugBinOp
(
AST_AugBinOp
*
node
)
{
assert
(
state
!=
PARTIAL
);
CompilerVariable
*
left
=
evalExpr
(
node
->
left
);
CompilerVariable
*
right
=
evalExpr
(
node
->
right
);
assert
(
node
->
op_type
!=
AST_TYPE
::
Is
&&
node
->
op_type
!=
AST_TYPE
::
IsNot
&&
"not tested yet"
);
CompilerVariable
*
rtn
=
this
->
_evalBinExp
(
left
,
right
,
node
->
op_type
,
AugBinOp
);
left
->
decvref
(
emitter
);
right
->
decvref
(
emitter
);
return
rtn
;
}
CompilerVariable
*
evalCompare
(
AST_Compare
*
node
)
{
CompilerVariable
*
evalCompare
(
AST_Compare
*
node
)
{
assert
(
state
!=
PARTIAL
);
assert
(
state
!=
PARTIAL
);
...
@@ -790,6 +803,9 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -790,6 +803,9 @@ class IRGeneratorImpl : public IRGenerator {
case
AST_TYPE
:
:
Attribute
:
case
AST_TYPE
:
:
Attribute
:
rtn
=
evalAttribute
(
static_cast
<
AST_Attribute
*>
(
node
));
rtn
=
evalAttribute
(
static_cast
<
AST_Attribute
*>
(
node
));
break
;
break
;
case
AST_TYPE
:
:
AugBinOp
:
rtn
=
evalAugBinOp
(
static_cast
<
AST_AugBinOp
*>
(
node
));
break
;
case
AST_TYPE
:
:
BinOp
:
case
AST_TYPE
:
:
BinOp
:
rtn
=
evalBinOp
(
static_cast
<
AST_BinOp
*>
(
node
));
rtn
=
evalBinOp
(
static_cast
<
AST_BinOp
*>
(
node
));
break
;
break
;
...
@@ -1097,20 +1113,6 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -1097,20 +1113,6 @@ class IRGeneratorImpl : public IRGenerator {
val
->
decvref
(
emitter
);
val
->
decvref
(
emitter
);
}
}
void
doAugAssign
(
AST_AugAssign
*
node
)
{
CompilerVariable
*
target
=
evalExpr
(
node
->
target
);
CompilerVariable
*
val
=
evalExpr
(
node
->
value
);
if
(
state
==
PARTIAL
)
return
;
CompilerVariable
*
rtn
=
this
->
_evalBinExp
(
target
,
val
,
node
->
op_type
,
AugAssign
);
target
->
decvref
(
emitter
);
val
->
decvref
(
emitter
);
_doSet
(
node
->
target
,
rtn
);
rtn
->
decvref
(
emitter
);
}
void
doClassDef
(
AST_ClassDef
*
node
)
{
void
doClassDef
(
AST_ClassDef
*
node
)
{
if
(
state
==
PARTIAL
)
if
(
state
==
PARTIAL
)
return
;
return
;
...
@@ -1453,9 +1455,6 @@ class IRGeneratorImpl : public IRGenerator {
...
@@ -1453,9 +1455,6 @@ class IRGeneratorImpl : public IRGenerator {
case
AST_TYPE
:
:
Assign
:
case
AST_TYPE
:
:
Assign
:
doAssign
(
static_cast
<
AST_Assign
*>
(
node
));
doAssign
(
static_cast
<
AST_Assign
*>
(
node
));
break
;
break
;
case
AST_TYPE
:
:
AugAssign
:
doAugAssign
(
static_cast
<
AST_AugAssign
*>
(
node
));
break
;
case
AST_TYPE
:
:
ClassDef
:
case
AST_TYPE
:
:
ClassDef
:
doClassDef
(
static_cast
<
AST_ClassDef
*>
(
node
));
doClassDef
(
static_cast
<
AST_ClassDef
*>
(
node
));
break
;
break
;
...
...
src/codegen/patchpoints.cpp
View file @
5bbd4c50
...
@@ -140,7 +140,7 @@ PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction *parent_cf) {
...
@@ -140,7 +140,7 @@ PatchpointSetupInfo* createGetGlobalPatchpoint(CompiledFunction *parent_cf) {
}
}
PatchpointSetupInfo
*
createBinexpPatchpoint
(
CompiledFunction
*
parent_cf
)
{
PatchpointSetupInfo
*
createBinexpPatchpoint
(
CompiledFunction
*
parent_cf
)
{
return
PatchpointSetupInfo
::
initialize
(
true
,
4
,
1
60
,
parent_cf
,
Binexp
);
return
PatchpointSetupInfo
::
initialize
(
true
,
4
,
1
96
,
parent_cf
,
Binexp
);
}
}
PatchpointSetupInfo
*
createNonzeroPatchpoint
(
CompiledFunction
*
parent_cf
)
{
PatchpointSetupInfo
*
createNonzeroPatchpoint
(
CompiledFunction
*
parent_cf
)
{
...
...
src/codegen/runtime_hooks.cpp
View file @
5bbd4c50
...
@@ -151,7 +151,7 @@ void initGlobalFuncs(GlobalState &g) {
...
@@ -151,7 +151,7 @@ void initGlobalFuncs(GlobalState &g) {
GET
(
getGlobal
);
GET
(
getGlobal
);
GET
(
binop
);
GET
(
binop
);
GET
(
compare
);
GET
(
compare
);
GET
(
aug
assign
);
GET
(
aug
binop
);
GET
(
nonzero
);
GET
(
nonzero
);
GET
(
print
);
GET
(
print
);
GET
(
unboxedLen
);
GET
(
unboxedLen
);
...
...
src/codegen/runtime_hooks.h
View file @
5bbd4c50
...
@@ -21,7 +21,7 @@ struct GlobalFuncs {
...
@@ -21,7 +21,7 @@ struct GlobalFuncs {
llvm
::
Value
*
printf
,
*
my_assert
,
*
malloc
,
*
free
;
llvm
::
Value
*
printf
,
*
my_assert
,
*
malloc
,
*
free
;
llvm
::
Value
*
boxInt
,
*
unboxInt
,
*
boxFloat
,
*
unboxFloat
,
*
boxStringPtr
,
*
boxCLFunction
,
*
unboxCLFunction
,
*
boxInstanceMethod
,
*
boxBool
,
*
unboxBool
,
*
createTuple
,
*
createDict
,
*
createList
,
*
createSlice
,
*
createClass
;
llvm
::
Value
*
boxInt
,
*
unboxInt
,
*
boxFloat
,
*
unboxFloat
,
*
boxStringPtr
,
*
boxCLFunction
,
*
unboxCLFunction
,
*
boxInstanceMethod
,
*
boxBool
,
*
unboxBool
,
*
createTuple
,
*
createDict
,
*
createList
,
*
createSlice
,
*
createClass
;
llvm
::
Value
*
getattr
,
*
setattr
,
*
print
,
*
nonzero
,
*
binop
,
*
compare
,
*
aug
assign
,
*
unboxedLen
,
*
getitem
,
*
getclsattr
,
*
getGlobal
,
*
setitem
,
*
unaryop
,
*
import
;
llvm
::
Value
*
getattr
,
*
setattr
,
*
print
,
*
nonzero
,
*
binop
,
*
compare
,
*
aug
binop
,
*
unboxedLen
,
*
getitem
,
*
getclsattr
,
*
getGlobal
,
*
setitem
,
*
unaryop
,
*
import
;
llvm
::
Value
*
checkUnpackingLength
,
*
raiseAttributeError
,
*
raiseAttributeErrorStr
,
*
raiseNotIterableError
,
*
assertNameDefined
;
llvm
::
Value
*
checkUnpackingLength
,
*
raiseAttributeError
,
*
raiseAttributeErrorStr
,
*
raiseNotIterableError
,
*
assertNameDefined
;
llvm
::
Value
*
printFloat
,
*
listAppendInternal
;
llvm
::
Value
*
printFloat
,
*
listAppendInternal
;
llvm
::
Value
*
dump
;
llvm
::
Value
*
dump
;
...
...
src/core/ast.cpp
View file @
5bbd4c50
...
@@ -217,6 +217,18 @@ void AST_AugAssign::accept_stmt(StmtVisitor *v) {
...
@@ -217,6 +217,18 @@ void AST_AugAssign::accept_stmt(StmtVisitor *v) {
v
->
visit_augassign
(
this
);
v
->
visit_augassign
(
this
);
}
}
void
AST_AugBinOp
::
accept
(
ASTVisitor
*
v
)
{
bool
skip
=
v
->
visit_augbinop
(
this
);
if
(
skip
)
return
;
left
->
accept
(
v
);
right
->
accept
(
v
);
}
void
*
AST_AugBinOp
::
accept_expr
(
ExprVisitor
*
v
)
{
return
v
->
visit_augbinop
(
this
);
}
void
AST_Attribute
::
accept
(
ASTVisitor
*
v
)
{
void
AST_Attribute
::
accept
(
ASTVisitor
*
v
)
{
bool
skip
=
v
->
visit_attribute
(
this
);
bool
skip
=
v
->
visit_attribute
(
this
);
if
(
skip
)
return
;
if
(
skip
)
return
;
...
@@ -726,6 +738,14 @@ bool PrintVisitor::visit_augassign(AST_AugAssign *node) {
...
@@ -726,6 +738,14 @@ bool PrintVisitor::visit_augassign(AST_AugAssign *node) {
return
true
;
return
true
;
}
}
bool
PrintVisitor
::
visit_augbinop
(
AST_AugBinOp
*
node
)
{
node
->
left
->
accept
(
this
);
printf
(
"="
);
printOp
(
node
->
op_type
);
node
->
right
->
accept
(
this
);
return
true
;
}
bool
PrintVisitor
::
visit_attribute
(
AST_Attribute
*
node
)
{
bool
PrintVisitor
::
visit_attribute
(
AST_Attribute
*
node
)
{
node
->
value
->
accept
(
this
);
node
->
value
->
accept
(
this
);
putchar
(
'.'
);
putchar
(
'.'
);
...
@@ -996,6 +1016,7 @@ bool PrintVisitor::visit_module(AST_Module *node) {
...
@@ -996,6 +1016,7 @@ bool PrintVisitor::visit_module(AST_Module *node) {
bool
PrintVisitor
::
visit_name
(
AST_Name
*
node
)
{
bool
PrintVisitor
::
visit_name
(
AST_Name
*
node
)
{
printf
(
"%s"
,
node
->
id
.
c_str
());
printf
(
"%s"
,
node
->
id
.
c_str
());
//printf("%s(%d)", node->id.c_str(), node->ctx_type);
return
false
;
return
false
;
}
}
...
@@ -1179,6 +1200,7 @@ class FlattenVisitor : public ASTVisitor {
...
@@ -1179,6 +1200,7 @@ class FlattenVisitor : public ASTVisitor {
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_augbinop
(
AST_AugBinOp
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
output
->
push_back
(
node
);
return
false
;
}
...
...
src/core/ast.h
View file @
5bbd4c50
...
@@ -119,6 +119,7 @@ namespace AST_TYPE {
...
@@ -119,6 +119,7 @@ namespace AST_TYPE {
Branch
=
200
,
Branch
=
200
,
Jump
=
201
,
Jump
=
201
,
ClsAttribute
=
202
,
ClsAttribute
=
202
,
AugBinOp
=
203
,
};
};
};
};
...
@@ -197,6 +198,17 @@ class AST_AugAssign : public AST_stmt {
...
@@ -197,6 +198,17 @@ class AST_AugAssign : public AST_stmt {
AST_AugAssign
()
:
AST_stmt
(
AST_TYPE
::
AugAssign
)
{}
AST_AugAssign
()
:
AST_stmt
(
AST_TYPE
::
AugAssign
)
{}
};
};
class
AST_AugBinOp
:
public
AST_expr
{
public:
AST_TYPE
::
AST_TYPE
op_type
;
AST_expr
*
left
,
*
right
;
virtual
void
accept
(
ASTVisitor
*
v
);
virtual
void
*
accept_expr
(
ExprVisitor
*
v
);
AST_AugBinOp
()
:
AST_expr
(
AST_TYPE
::
AugBinOp
)
{}
};
class
AST_Attribute
:
public
AST_expr
{
class
AST_Attribute
:
public
AST_expr
{
public:
public:
AST_expr
*
value
;
AST_expr
*
value
;
...
@@ -630,6 +642,7 @@ class ASTVisitor {
...
@@ -630,6 +642,7 @@ class ASTVisitor {
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_augbinop
(
AST_AugBinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
assert
(
0
);
abort
();
}
...
@@ -679,6 +692,7 @@ class NoopASTVisitor : public ASTVisitor {
...
@@ -679,6 +692,7 @@ class NoopASTVisitor : public ASTVisitor {
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
return
false
;
}
virtual
bool
visit_arguments
(
AST_arguments
*
node
)
{
return
false
;
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
return
false
;
}
virtual
bool
visit_assign
(
AST_Assign
*
node
)
{
return
false
;
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
return
false
;
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
return
false
;
}
virtual
bool
visit_augbinop
(
AST_AugBinOp
*
node
)
{
return
false
;
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
return
false
;
}
virtual
bool
visit_attribute
(
AST_Attribute
*
node
)
{
return
false
;
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
return
false
;
}
virtual
bool
visit_binop
(
AST_BinOp
*
node
)
{
return
false
;
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
return
false
;
}
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
)
{
return
false
;
}
...
@@ -724,6 +738,7 @@ class ExprVisitor {
...
@@ -724,6 +738,7 @@ class ExprVisitor {
public:
public:
virtual
~
ExprVisitor
()
{}
virtual
~
ExprVisitor
()
{}
virtual
void
*
visit_augbinop
(
AST_AugBinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_attribute
(
AST_Attribute
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_attribute
(
AST_Attribute
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_binop
(
AST_BinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_binop
(
AST_BinOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_boolop
(
AST_BoolOp
*
node
)
{
assert
(
0
);
abort
();
}
virtual
void
*
visit_boolop
(
AST_BoolOp
*
node
)
{
assert
(
0
);
abort
();
}
...
@@ -783,6 +798,7 @@ class PrintVisitor : public ASTVisitor {
...
@@ -783,6 +798,7 @@ class PrintVisitor : public ASTVisitor {
virtual
bool
visit_arguments
(
AST_arguments
*
node
);
virtual
bool
visit_arguments
(
AST_arguments
*
node
);
virtual
bool
visit_assign
(
AST_Assign
*
node
);
virtual
bool
visit_assign
(
AST_Assign
*
node
);
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
);
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
);
virtual
bool
visit_augbinop
(
AST_AugBinOp
*
node
);
virtual
bool
visit_attribute
(
AST_Attribute
*
node
);
virtual
bool
visit_attribute
(
AST_Attribute
*
node
);
virtual
bool
visit_binop
(
AST_BinOp
*
node
);
virtual
bool
visit_binop
(
AST_BinOp
*
node
);
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
);
virtual
bool
visit_boolop
(
AST_BoolOp
*
node
);
...
...
src/core/cfg.cpp
View file @
5bbd4c50
...
@@ -198,7 +198,7 @@ class CFGVisitor : public ASTVisitor {
...
@@ -198,7 +198,7 @@ class CFGVisitor : public ASTVisitor {
std
::
string
nodeName
(
AST
_expr
*
node
)
{
std
::
string
nodeName
(
AST
*
node
)
{
char
buf
[
40
];
char
buf
[
40
];
snprintf
(
buf
,
40
,
"#%p"
,
node
);
snprintf
(
buf
,
40
,
"#%p"
,
node
);
return
std
::
string
(
buf
);
return
std
::
string
(
buf
);
...
@@ -670,7 +670,7 @@ class CFGVisitor : public ASTVisitor {
...
@@ -670,7 +670,7 @@ class CFGVisitor : public ASTVisitor {
AST_Assign
*
remapped
=
new
AST_Assign
();
AST_Assign
*
remapped
=
new
AST_Assign
();
remapped
->
lineno
=
node
->
lineno
;
remapped
->
lineno
=
node
->
lineno
;
remapped
->
col_offset
=
node
->
col_offset
;
remapped
->
col_offset
=
node
->
col_offset
;
remapped
->
value
=
remapExpr
(
node
->
value
);
remapped
->
value
=
remapExpr
(
node
->
value
,
false
);
// TODO bad that it's reusing the AST nodes?
// TODO bad that it's reusing the AST nodes?
remapped
->
targets
=
node
->
targets
;
remapped
->
targets
=
node
->
targets
;
push_back
(
remapped
);
push_back
(
remapped
);
...
@@ -678,14 +678,79 @@ class CFGVisitor : public ASTVisitor {
...
@@ -678,14 +678,79 @@ class CFGVisitor : public ASTVisitor {
}
}
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
virtual
bool
visit_augassign
(
AST_AugAssign
*
node
)
{
AST_AugAssign
*
remapped
=
new
AST_AugAssign
();
// augassign is pretty tricky; "x" += "y" mostly textually maps to
remapped
->
lineno
=
node
->
lineno
;
// "x" = "x" =+ "y" (using "=+" to represent an augbinop)
remapped
->
col_offset
=
node
->
col_offset
;
// except that "x" only gets evaluated once. So it's something like
remapped
->
value
=
remapExpr
(
node
->
value
);
// "target", val = eval("x")
// "target" = val =+ "y"
// where "target" is handled specially, because it can't just be a name;
// it has to be a name-only version of the target type (ex subscript, attribute).
// So for "f().x += g()", it has to translate to
// "c = f(); y = c.x; z = g(); c.x = y =+ z"
//
// Even if the target is a simple name, it can be complicated, because the
// value can change the name. For "x += f()", have to translate to
// "y = x; z = f(); x = y =+ z"
AST_expr
*
remapped_target
;
AST_expr
*
remapped_lhs
;
// TODO bad that it's reusing the AST nodes?
// TODO bad that it's reusing the AST nodes?
remapped
->
target
=
node
->
target
;
switch
(
node
->
target
->
type
)
{
remapped
->
op_type
=
node
->
op_type
;
case
AST_TYPE
:
:
Name
:
{
push_back
(
remapped
);
AST_Name
*
n
=
static_cast
<
AST_Name
*>
(
node
->
target
);
assert
(
n
->
ctx_type
==
AST_TYPE
::
Store
);
push_back
(
makeAssign
(
nodeName
(
node
),
makeName
(
n
->
id
,
AST_TYPE
::
Load
)));
remapped_target
=
n
;
remapped_lhs
=
makeName
(
nodeName
(
node
),
AST_TYPE
::
Load
);
break
;
}
case
AST_TYPE
:
:
Subscript
:
{
AST_Subscript
*
s
=
static_cast
<
AST_Subscript
*>
(
node
->
target
);
assert
(
s
->
ctx_type
==
AST_TYPE
::
Store
);
AST_Subscript
*
s_target
=
new
AST_Subscript
();
s_target
->
value
=
remapExpr
(
s
->
value
);
s_target
->
slice
=
remapExpr
(
s
->
slice
);
s_target
->
ctx_type
=
AST_TYPE
::
Store
;
remapped_target
=
s_target
;
AST_Subscript
*
s_lhs
=
new
AST_Subscript
();
s_lhs
->
value
=
s_target
->
value
;
s_lhs
->
slice
=
s_target
->
slice
;
s_lhs
->
ctx_type
=
AST_TYPE
::
Load
;
remapped_lhs
=
remapExpr
(
s_lhs
);
break
;
}
case
AST_TYPE
:
:
Attribute
:
{
AST_Attribute
*
a
=
static_cast
<
AST_Attribute
*>
(
node
->
target
);
assert
(
a
->
ctx_type
==
AST_TYPE
::
Store
);
AST_Attribute
*
a_target
=
new
AST_Attribute
();
a_target
->
value
=
remapExpr
(
a
->
value
);
a_target
->
attr
=
a
->
attr
;
a_target
->
ctx_type
=
AST_TYPE
::
Store
;
remapped_target
=
a_target
;
AST_Attribute
*
a_lhs
=
new
AST_Attribute
();
a_lhs
->
value
=
a_target
->
value
;
a_lhs
->
attr
=
a
->
attr
;
a_lhs
->
ctx_type
=
AST_TYPE
::
Load
;
remapped_lhs
=
remapExpr
(
a_lhs
);
break
;
}
default:
RELEASE_ASSERT
(
0
,
"%d"
,
node
->
target
->
type
);
}
AST_AugBinOp
*
binop
=
new
AST_AugBinOp
();
binop
->
op_type
=
node
->
op_type
;
binop
->
left
=
remapped_lhs
;
binop
->
right
=
remapExpr
(
node
->
value
);
AST_stmt
*
assign
=
makeAssign
(
remapped_target
,
binop
);
push_back
(
assign
);
return
true
;
return
true
;
}
}
...
...
src/runtime/inline/link_forcer.cpp
View file @
5bbd4c50
...
@@ -62,7 +62,7 @@ void force() {
...
@@ -62,7 +62,7 @@ void force() {
FORCE
(
nonzero
);
FORCE
(
nonzero
);
FORCE
(
binop
);
FORCE
(
binop
);
FORCE
(
compare
);
FORCE
(
compare
);
FORCE
(
aug
assign
);
FORCE
(
aug
binop
);
FORCE
(
unboxedLen
);
FORCE
(
unboxedLen
);
FORCE
(
getitem
);
FORCE
(
getitem
);
FORCE
(
getclsattr
);
FORCE
(
getclsattr
);
...
...
src/runtime/objmodel.cpp
View file @
5bbd4c50
...
@@ -1661,7 +1661,7 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
...
@@ -1661,7 +1661,7 @@ extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
return
rtn
;
return
rtn
;
}
}
extern
"C"
Box
*
aug
assign
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
)
{
extern
"C"
Box
*
aug
binop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
)
{
static
StatCounter
slowpath_binop
(
"slowpath_binop"
);
static
StatCounter
slowpath_binop
(
"slowpath_binop"
);
slowpath_binop
.
log
();
slowpath_binop
.
log
();
//static StatCounter nopatch_binop("nopatch_binop");
//static StatCounter nopatch_binop("nopatch_binop");
...
...
src/runtime/objmodel.h
View file @
5bbd4c50
...
@@ -54,7 +54,7 @@ extern "C" void dump(Box* obj);
...
@@ -54,7 +54,7 @@ extern "C" void dump(Box* obj);
//extern "C" Box* trap();
//extern "C" Box* trap();
extern
"C"
i64
unboxedLen
(
Box
*
obj
);
extern
"C"
i64
unboxedLen
(
Box
*
obj
);
extern
"C"
Box
*
binop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
);
extern
"C"
Box
*
binop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
);
extern
"C"
Box
*
aug
assign
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
);
extern
"C"
Box
*
aug
binop
(
Box
*
lhs
,
Box
*
rhs
,
int
op_type
);
extern
"C"
Box
*
getGlobal
(
BoxedModule
*
m
,
std
::
string
*
name
,
bool
from_global
);
extern
"C"
Box
*
getGlobal
(
BoxedModule
*
m
,
std
::
string
*
name
,
bool
from_global
);
extern
"C"
Box
*
getitem
(
Box
*
value
,
Box
*
slice
);
extern
"C"
Box
*
getitem
(
Box
*
value
,
Box
*
slice
);
extern
"C"
void
setitem
(
Box
*
target
,
Box
*
slice
,
Box
*
value
);
extern
"C"
void
setitem
(
Box
*
target
,
Box
*
slice
,
Box
*
value
);
...
...
test/tests/augassign.py
View file @
5bbd4c50
...
@@ -28,5 +28,20 @@ l = l + l
...
@@ -28,5 +28,20 @@ l = l + l
print
l
print
l
print
l2
print
l2
def
f2
():
# It is *not* ok to translate "expr += y" into "name = expr; name += y"
l
=
range
(
10
)
l
[
0
]
+=
5
print
l
[
0
]
class
C
(
object
):
pass
c
=
C
()
c
.
x
=
1
c
.
x
+=
2
print
c
.
x
f2
()
print
f
(
4
,
2
)
print
f
(
4
,
2
)
print
f
(
4.1
,
2.3
)
print
f
(
4.1
,
2.3
)
test/tests/augassign_analysis.py
View file @
5bbd4c50
...
@@ -48,7 +48,70 @@ def f5():
...
@@ -48,7 +48,70 @@ def f5():
f5
()
f5
()
def
f6
():
def
f6
():
x
=
-
100
x
+=
[
x
for
x
in
[
50
,
51
,
52
]][
0
]
print
x
# Prints "-50"
f6
()
def
f7
():
global
c
class
C
(
object
):
pass
c
=
C
()
c
.
x
=
0
def
inner1
():
global
c
print
"inner1"
c
.
x
=
25
return
c
def
inner2
():
global
c
print
"inner2"
c
.
x
=
50
return
1
inner1
().
x
+=
inner2
()
print
c
.
x
# prints "26"
f7
()
def
f8
():
global
l
l
=
[
0
]
def
inner1
():
global
l
print
"inner1"
l
[
0
]
=
25
return
l
def
inner2
():
global
l
print
"inner2"
l
[
0
]
=
50
return
1
inner1
()[
0
]
+=
inner2
()
print
l
[
0
]
# prints "26"
f8
()
x
=
9
def
f9
():
global
x
def
inner
():
global
x
x
=
5
return
1
x
+=
inner
()
print
x
f9
()
def
f10
():
# This should error: the lhs is evaluated first
# This should error: the lhs is evaluated first
x
+=
[
x
for
x
in
xrange
(
5
)][
0
]
x
+=
[
x
for
x
in
xrange
(
5
)][
0
]
print
x
print
x
f
6
()
f
10
()
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