Skip to content
This repository was archived by the owner on Apr 2, 2020. It is now read-only.

Commit 803a823

Browse files
Merge pull request RustPython#138 from RustPython/assignment
Assignment
2 parents d443c64 + a14b776 commit 803a823

File tree

6 files changed

+119
-23
lines changed

6 files changed

+119
-23
lines changed

parser/src/parser.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,40 @@ mod tests {
253253
)
254254
}
255255

256+
#[test]
257+
fn test_parse_tuples() {
258+
let source = String::from("a, b = 4, 5\n");
259+
260+
assert_eq!(
261+
parse_statement(&source),
262+
Ok(ast::LocatedStatement {
263+
location: ast::Location::new(1, 1),
264+
node: ast::Statement::Assign {
265+
targets: vec![ast::Expression::Tuple {
266+
elements: vec![
267+
ast::Expression::Identifier {
268+
name: "a".to_string()
269+
},
270+
ast::Expression::Identifier {
271+
name: "b".to_string()
272+
}
273+
]
274+
}],
275+
value: ast::Expression::Tuple {
276+
elements: vec![
277+
ast::Expression::Number {
278+
value: ast::Number::Integer { value: 4 }
279+
},
280+
ast::Expression::Number {
281+
value: ast::Number::Integer { value: 5 }
282+
}
283+
]
284+
}
285+
}
286+
})
287+
)
288+
}
289+
256290
#[test]
257291
fn test_parse_class() {
258292
let source = String::from("class Foo(A, B):\n def __init__(self):\n pass\n def method_with_default(self, arg='default'):\n pass\n");

parser/src/python.lalrpop

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,38 @@ SmallStatement: ast::LocatedStatement = {
4646
};
4747

4848
ExpressionStatement: ast::LocatedStatement = {
49-
<loc:@L> <e:TestList> <e2:AssignSuffix*> => {
50-
//match e2 {
51-
// None => ast::Statement::Expression { expression: e },
52-
// Some(e3) => ast::Statement::Expression { expression: e },
53-
//}
54-
if e2.len() > 0 {
55-
// Dealing with assignment here
56-
// TODO: for rhs in e2 {
57-
let rhs = e2.into_iter().next().unwrap();
58-
// ast::Expression::Tuple { elements: e2.into_iter().next().unwrap()
59-
let v = rhs.into_iter().next().unwrap();
60-
let lhs = ast::LocatedStatement {
61-
location: loc.clone(),
62-
node: ast::Statement::Assign { targets: e, value: v },
63-
};
64-
lhs
65-
} else {
66-
if e.len() > 1 {
67-
panic!("Not good?");
68-
// ast::Statement::Expression { expression: e[0] }
49+
<loc:@L> <expr:TestList> <suffix:AssignSuffix*> => {
50+
// Just an expression, no assignment:
51+
if suffix.is_empty() {
52+
if expr.len() > 1 {
53+
ast::LocatedStatement {
54+
location: loc.clone(),
55+
node: ast::Statement::Expression { expression: ast::Expression::Tuple { elements: expr } }
56+
}
6957
} else {
7058
ast::LocatedStatement {
7159
location: loc.clone(),
72-
node: ast::Statement::Expression { expression: e.into_iter().next().unwrap() },
60+
node: ast::Statement::Expression { expression: expr[0].clone() },
7361
}
7462
}
63+
} else {
64+
let mut targets = vec![if expr.len() > 1 {
65+
ast::Expression::Tuple { elements: expr }
66+
} else {
67+
expr[0].clone()
68+
}];
69+
let mut values : Vec<ast::Expression> = suffix.into_iter().map(|test_list| if test_list.len() > 1 { ast::Expression::Tuple { elements: test_list }} else { test_list[0].clone() }).collect();
70+
71+
while values.len() > 1 {
72+
targets.push(values.remove(0));
73+
}
74+
75+
let value = values[0].clone();
76+
77+
ast::LocatedStatement {
78+
location: loc.clone(),
79+
node: ast::Statement::Assign { targets, value },
80+
}
7581
}
7682
},
7783
<loc:@L> <e1:Test> <op:AugAssign> <e2:TestList> => {
@@ -120,7 +126,7 @@ FlowStatement: ast::LocatedStatement = {
120126
<loc:@L> "return" <t:TestList?> => {
121127
ast::LocatedStatement {
122128
location: loc,
123-
node: ast::Statement::Return { value: t},
129+
node: ast::Statement::Return { value: t },
124130
}
125131
},
126132
<loc:@L> "raise" <t:Test?> => {

tests/snippets/assignment.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
x = 1
2+
assert x == 1
3+
4+
x = 1, 2, 3
5+
assert x == (1, 2, 3)
6+
7+
x, y = 1, 2
8+
assert x == 1
9+
assert y == 2
10+
11+
x, y = (y, x)
12+
13+
assert x == 2
14+
assert y == 1
15+
16+
((x, y), z) = ((1, 2), 3)
17+
18+
assert (x, y, z) == (1, 2, 3)
19+
20+
q = (1, 2, 3)
21+
(x, y, z) = q
22+
assert y == q[1]
23+
24+
x = (a, b, c) = y = q
25+
26+
assert (a, b, c) == q
27+
assert x == q
28+
assert y == q

vm/src/bytecode.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ pub enum Instruction {
137137
PrintExpr,
138138
LoadBuildClass,
139139
StoreLocals,
140+
UnpackSequence {
141+
size: usize,
142+
},
140143
}
141144

142145
#[derive(Debug, Clone, PartialEq)]

vm/src/compile.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,10 @@ impl Compiler {
508508
ast::Statement::Assign { targets, value } => {
509509
self.compile_expression(value);
510510

511-
for target in targets {
511+
for (i, target) in targets.into_iter().enumerate() {
512+
if i + 1 != targets.len() {
513+
self.emit(Instruction::Duplicate);
514+
}
512515
self.compile_store(target);
513516
}
514517
}
@@ -548,6 +551,14 @@ impl Compiler {
548551
name: name.to_string(),
549552
});
550553
}
554+
ast::Expression::Tuple { elements } => {
555+
self.emit(Instruction::UnpackSequence {
556+
size: elements.len(),
557+
});
558+
for element in elements {
559+
self.compile_store(element);
560+
}
561+
}
551562
_ => {
552563
panic!("WTF: {:?}", target);
553564
}

vm/src/vm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::obj::objiter;
1717
use super::obj::objlist;
1818
use super::obj::objobject;
1919
use super::obj::objstr;
20+
use super::obj::objtuple;
2021
use super::obj::objtype;
2122
use super::objbool;
2223
use super::pyobject::{
@@ -1048,6 +1049,19 @@ impl VirtualMachine {
10481049
}
10491050
None
10501051
}
1052+
bytecode::Instruction::UnpackSequence { size } => {
1053+
let value = self.pop_value();
1054+
1055+
let elements = objtuple::get_elements(&value);
1056+
if elements.len() != *size {
1057+
panic!("Wrong number of values to unpack");
1058+
}
1059+
1060+
for element in elements.into_iter().rev() {
1061+
self.push_value(element);
1062+
}
1063+
None
1064+
}
10511065
}
10521066
}
10531067

0 commit comments

Comments
 (0)