Skip to content

Commit b8a81e8

Browse files
committed
Unpack to toplevel list of variables.
So ``` a, b, c = (1, 2, 3) ``` is properly assigned to variables a, b and c.
1 parent 20b51e8 commit b8a81e8

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

bant/frontend/elaboration_test.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ cc_library(
128128
EXPECT_EQ(result.first, result.second);
129129
}
130130

131-
TEST_F(ElaborationTest, IdentifiersAssignedInTuplesAreUsable) {
131+
TEST_F(ElaborationTest, UnpackIntoTuple) {
132132
auto result = ElabAndPrint(
133133
R"(
134134
(a, b) = (42, 123)
@@ -146,6 +146,23 @@ d = 170
146146
EXPECT_EQ(result.first, result.second);
147147
}
148148

149+
TEST_F(ElaborationTest, UnpackIntoToplevelListIsTreatedAsAssignmentToTuple) {
150+
// Essentially the same as tuple
151+
auto result = ElabAndPrint(
152+
R"(
153+
a, b = (42, 123)
154+
x, y = (a, b)
155+
d = x + y
156+
)",
157+
R"(
158+
(a, b) = (42, 123)
159+
(x, y) = (42, 123)
160+
d = 165
161+
)");
162+
163+
EXPECT_EQ(result.first, result.second);
164+
}
165+
149166
TEST_F(ElaborationTest, ConcatLists) {
150167
auto result = ElabAndPrint(
151168
R"(

bant/frontend/parser.cc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,18 @@ class Parser::Impl {
158158
node_arena_,
159159
ParseIdAssignRhs(Make<Identifier>(tok.text), after_id.text));
160160
break;
161+
case TokenType::kComma: { // toplevel unpack assignment
162+
List *started_list = Make<List>(List::Type::kTuple);
163+
started_list->Append(node_arena_, Make<Identifier>(tok.text));
164+
// List ends with assignment.
165+
Token assign;
166+
List *const lhs = ParseList(
167+
started_list, [&]() { return ParseOptionalIdentifier(); },
168+
TokenType::kAssign, &assign);
169+
statement_list->Append(node_arena_,
170+
ParseNodeAssignRhs(lhs, tok.text, assign.text));
171+
break;
172+
}
161173
case TokenType::kOpenParen:
162174
statement_list->Append(node_arena_, ParseFunCall(tok));
163175
break;
@@ -204,10 +216,10 @@ class Parser::Impl {
204216
}
205217

206218
// Parse expressions produced by element_parse up to and including end_tok
207-
// is reached.
219+
// is reached. If save_last_tok is non-null, last token will be stored there
208220
using ListElementParse = std::function<Node *()>;
209221
List *ParseList(List *result, const ListElementParse &element_parse,
210-
TokenType end_tok) {
222+
TokenType end_tok, Token *save_last_tok = nullptr) {
211223
LOG_ENTER();
212224
// Opening list-token (e.g. '[', '(', '{') already consumed.
213225
Token upcoming = scanner_->Peek();
@@ -223,7 +235,8 @@ class Parser::Impl {
223235
return result;
224236
}
225237
}
226-
scanner_->Next(); // consume end_tok
238+
const Token closing_list = scanner_->Next(); // consume end_tok
239+
if (save_last_tok) *save_last_tok = closing_list;
227240
return result;
228241
}
229242

bant/frontend/parser_test.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,15 @@ TEST_F(ParserTest, AssignmentToTuple) {
203203
Node *const expected = List({
204204
Assign(Tuple({Id("a"), Id("b")}), Tuple({Str("foo"), Str("bar")})),
205205
Assign(Tuple({Id("x"), Id("y")}), Call("foo", Tuple({}))),
206+
Assign(Tuple({Id("q"), Id("u")}), Tuple({Int(1), Int(2)})),
206207
Assign("A", Id("B")),
207208
Assign(Tuple({Id("c"), Id("d")}), Tuple({Int(1), Int(2)})),
208209
});
209210

210211
EXPECT_EQ(Print(expected), Print(Parse(R"(
211212
(a, b) = ("foo", "bar")
212213
(x, y) = foo()
214+
q, u = (1, 2) # Unpack
213215
A = B # scalar assignment, the following parenthesis are not a fun call
214216
(c, d) = (1, 2)
215217
#a = ((u, v) = foo()) # should this work ? Right now we only do toplevel.

0 commit comments

Comments
 (0)