aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/inputs/with.yue9
-rw-r--r--spec/outputs/codes_from_doc.lua33
-rw-r--r--spec/outputs/codes_from_doc_zh.lua33
-rw-r--r--spec/outputs/with.lua27
-rw-r--r--src/yuescript/yue_compiler.cpp132
5 files changed, 205 insertions, 29 deletions
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue
index 19b7be1..3fee48e 100644
--- a/spec/inputs/with.yue
+++ b/spec/inputs/with.yue
@@ -152,4 +152,13 @@ do
152 return with {} 152 return with {}
153 return [123] 153 return [123]
154 154
155do
156 f with item
157 if .id > 0
158 break .content
159
160 a = with tb
161 if .v
162 break .a
163
155nil 164nil
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua
index 177c33d..3ee20bb 100644
--- a/spec/outputs/codes_from_doc.lua
+++ b/spec/outputs/codes_from_doc.lua
@@ -694,6 +694,7 @@ local some_string = "Here is a string\n that has a line break in it."
694print("I am " .. tostring(math.random() * 100) .. "% sure.") 694print("I am " .. tostring(math.random() * 100) .. "% sure.")
695local integer = 1000000 695local integer = 1000000
696local hex = 0xEFBBBF 696local hex = 0xEFBBBF
697local binary = 19
697local my_function 698local my_function
698my_function = function() end 699my_function = function() end
699my_function() 700my_function()
@@ -2228,6 +2229,38 @@ local inventory = {
2228 } 2229 }
2229 } 2230 }
2230} 2231}
2232local map
2233map = function(arr, action)
2234 local _accum_0 = { }
2235 local _len_0 = 1
2236 for _index_0 = 1, #arr do
2237 local item = arr[_index_0]
2238 _accum_0[_len_0] = action(item)
2239 _len_0 = _len_0 + 1
2240 end
2241 return _accum_0
2242end
2243local filter
2244filter = function(arr, cond)
2245 local _accum_0 = { }
2246 local _len_0 = 1
2247 for _index_0 = 1, #arr do
2248 local item = arr[_index_0]
2249 if cond(item) then
2250 _accum_0[_len_0] = item
2251 _len_0 = _len_0 + 1
2252 end
2253 end
2254 return _accum_0
2255end
2256local reduce
2257reduce = function(arr, init, action)
2258 for _index_0 = 1, #arr do
2259 local item = arr[_index_0]
2260 init = action(init, item)
2261 end
2262 return init
2263end
2231print(reduce(filter(map({ 2264print(reduce(filter(map({
2232 1, 2265 1,
2233 2, 2266 2,
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index 6349010..52204b7 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -694,6 +694,7 @@ local some_string = "这是一个字符串\n 并包括一个换行。"
694print("我有" .. tostring(math.random() * 100) .. "%的把握。") 694print("我有" .. tostring(math.random() * 100) .. "%的把握。")
695local integer = 1000000 695local integer = 1000000
696local hex = 0xEFBBBF 696local hex = 0xEFBBBF
697local binary = 19
697local my_function 698local my_function
698my_function = function() end 699my_function = function() end
699my_function() 700my_function()
@@ -2222,6 +2223,38 @@ local inventory = {
2222 } 2223 }
2223 } 2224 }
2224} 2225}
2226local map
2227map = function(arr, action)
2228 local _accum_0 = { }
2229 local _len_0 = 1
2230 for _index_0 = 1, #arr do
2231 local item = arr[_index_0]
2232 _accum_0[_len_0] = action(item)
2233 _len_0 = _len_0 + 1
2234 end
2235 return _accum_0
2236end
2237local filter
2238filter = function(arr, cond)
2239 local _accum_0 = { }
2240 local _len_0 = 1
2241 for _index_0 = 1, #arr do
2242 local item = arr[_index_0]
2243 if cond(item) then
2244 _accum_0[_len_0] = item
2245 _len_0 = _len_0 + 1
2246 end
2247 end
2248 return _accum_0
2249end
2250local reduce
2251reduce = function(arr, init, action)
2252 for _index_0 = 1, #arr do
2253 local item = arr[_index_0]
2254 init = action(init, item)
2255 end
2256 return init
2257end
2225print(reduce(filter(map({ 2258print(reduce(filter(map({
2226 1, 2259 1,
2227 2, 2260 2,
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 1a795c1..20c5d44 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -187,4 +187,31 @@ do
187 return _with_0[123] 187 return _with_0[123]
188 end 188 end
189end 189end
190do
191 f((function()
192 local _with_0 = item
193 do
194 local _accum_0
195 while true do
196 if _with_0.id > 0 then
197 _accum_0 = _with_0.content
198 break
199 end
200 end
201 _with_0 = _accum_0
202 end
203 return _with_0
204 end)())
205 local a
206 local _with_0 = tb
207 local _accum_0
208 while true do
209 if _with_0.v then
210 _accum_0 = _with_0.a
211 break
212 end
213 end
214 _with_0 = _accum_0
215 a = _with_0
216end
190return nil 217return nil
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 60ed7ac..7abc929 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.28.2"sv; 81const std::string_view version = "0.28.3"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -2064,6 +2064,9 @@ private:
2064 } 2064 }
2065 2065
2066 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 2066 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
2067 if (assignment->action.is<SubBackcall_t>()) {
2068 YUEE("AST node mismatch", assignment->action);
2069 }
2067 checkAssignable(assignment->expList); 2070 checkAssignable(assignment->expList);
2068 BLOCK_START 2071 BLOCK_START
2069 auto assign = ast_cast<Assign_t>(assignment->action); 2072 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -8195,18 +8198,18 @@ private:
8195 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8198 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out);
8196 } 8199 }
8197 8200
8198 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8201 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
8199 switch (body->get_id()) { 8202 switch (bodyOrStmt->get_id()) {
8200 case id<Block_t>(): 8203 case id<Block_t>():
8201 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8204 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8202 break; 8205 break;
8203 case id<Statement_t>(): { 8206 case id<Statement_t>(): {
8204 auto newBlock = body->new_ptr<Block_t>(); 8207 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8205 newBlock->statements.push_back(body); 8208 newBlock->statements.push_back(bodyOrStmt);
8206 transformBlock(newBlock, out, usage, assignList); 8209 transformBlock(newBlock, out, usage, assignList);
8207 break; 8210 break;
8208 } 8211 }
8209 default: YUEE("AST node mismatch", body); break; 8212 default: YUEE("AST node mismatch", bodyOrStmt); break;
8210 } 8213 }
8211 } 8214 }
8212 8215
@@ -8477,12 +8480,17 @@ private:
8477 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 8480 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
8478 auto& lenAssign = out.emplace_back(clearBuf()); 8481 auto& lenAssign = out.emplace_back(clearBuf());
8479 transformForHead(forNode, out); 8482 transformForHead(forNode, out);
8480 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8483 if (hasBreakWithValue(breakLoopType)) {
8481 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body);
8482 expList->followStmt = followStmt.get();
8483 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList);
8484 if (!expList->followStmtProcessed) {
8485 lenAssign.clear(); 8484 lenAssign.clear();
8485 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common);
8486 } else {
8487 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8488 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body);
8489 expList->followStmt = followStmt.get();
8490 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList);
8491 if (!expList->followStmtProcessed) {
8492 lenAssign.clear();
8493 }
8486 } 8494 }
8487 popScope(); 8495 popScope();
8488 out.push_back(indent() + "end"s + nlr(forNode)); 8496 out.push_back(indent() + "end"s + nlr(forNode));
@@ -8584,12 +8592,17 @@ private:
8584 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 8592 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
8585 auto& lenAssign = out.emplace_back(clearBuf()); 8593 auto& lenAssign = out.emplace_back(clearBuf());
8586 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 8594 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8587 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8595 if (hasBreakWithValue(breakLoopType)) {
8588 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
8589 expList->followStmt = followStmt.get();
8590 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
8591 if (!expList->followStmtProcessed) {
8592 lenAssign.clear(); 8596 lenAssign.clear();
8597 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
8598 } else {
8599 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8600 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
8601 expList->followStmt = followStmt.get();
8602 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
8603 if (!expList->followStmtProcessed) {
8604 lenAssign.clear();
8605 }
8593 } 8606 }
8594 popScope(); 8607 popScope();
8595 out.push_back(indent() + "end"s + nlr(forEach)); 8608 out.push_back(indent() + "end"s + nlr(forEach));
@@ -9476,15 +9489,66 @@ private:
9476 } 9489 }
9477 } 9490 }
9478 _withVars.push(withVar); 9491 _withVars.push(withVar);
9492 std::string breakWithVar;
9493 if (assignList || returnValue) {
9494 auto breakLoopType = getBreakLoopType(with->body, withVar);
9495 if (hasBreakWithValue(breakLoopType)) {
9496 breakWithVar = withVar;
9497 }
9498 }
9479 if (with->eop) { 9499 if (with->eop) {
9480 auto ifNode = x->new_ptr<If_t>(); 9500 auto ifNode = x->new_ptr<If_t>();
9481 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 9501 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9482 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 9502 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9483 ifNode->nodes.push_back(with->body); 9503 ifNode->nodes.push_back(with->body);
9484 transformIf(ifNode, temp, ExpUsage::Common); 9504 if (breakWithVar.empty()) {
9505 transformIf(ifNode, temp, ExpUsage::Common);
9506 } else {
9507 auto simpleValue = x->new_ptr<SimpleValue_t>();
9508 simpleValue->value.set(ifNode);
9509 auto exp = newExp(simpleValue, x);
9510 auto expList = x->new_ptr<ExpList_t>();
9511 expList->exprs.push_back(exp);
9512 auto expListAssign = x->new_ptr<ExpListAssign_t>();
9513 expListAssign->expList.set(expList);
9514 auto stmt = x->new_ptr<Statement_t>();
9515 stmt->content.set(expListAssign);
9516 auto whileNode = toAst<While_t>("while true do break"s, x);
9517 auto block = x->new_ptr<Block_t>();
9518 block->statements.push_back(stmt);
9519 block->statements.push_back(whileNode->body);
9520 auto body = x->new_ptr<Body_t>();
9521 body->content.set(block);
9522 whileNode->body.set(block);
9523 auto sVal = x->new_ptr<SimpleValue_t>();
9524 sVal->value.set(whileNode);
9525 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9526 transformAssignment(asmt, temp);
9527 }
9485 } else { 9528 } else {
9486 bool transformed = false; 9529 bool transformed = false;
9487 if (!extraScope && assignList) { 9530 if (!breakWithVar.empty()) {
9531 auto whileNode = toAst<While_t>("while true do break"s, x);
9532 auto block = x->new_ptr<Block_t>();
9533 if (auto blk = with->body.as<Block_t>()) {
9534 block->statements.dup(blk->statements);
9535 } else {
9536 auto stmt = with->body.to<Statement_t>();
9537 block->statements.push_back(stmt);
9538 }
9539 auto breakLoop = whileNode->body.to<Statement_t>()->content.as<BreakLoop_t>();
9540 if (!(breakLoop && breakLoop->type.is<Break_t>())) {
9541 block->statements.push_back(whileNode->body);
9542 }
9543 auto body = x->new_ptr<Body_t>();
9544 body->content.set(block);
9545 whileNode->body.set(block);
9546 auto sVal = x->new_ptr<SimpleValue_t>();
9547 sVal->value.set(whileNode);
9548 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9549 transformAssignment(asmt, temp);
9550 transformed = true;
9551 } else if (!extraScope && assignList) {
9488 if (auto block = with->body.as<Block_t>()) { 9552 if (auto block = with->body.as<Block_t>()) {
9489 if (!block->statements.empty()) { 9553 if (!block->statements.empty()) {
9490 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 9554 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back());
@@ -10543,12 +10607,17 @@ private:
10543 auto condStr = transformCondExp(whileNode->condition, isUntil); 10607 auto condStr = transformCondExp(whileNode->condition, isUntil);
10544 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 10608 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10545 pushScope(); 10609 pushScope();
10546 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 10610 if (hasBreakWithValue(breakLoopType)) {
10547 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10548 assignLeft->followStmt = followStmt.get();
10549 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10550 if (!assignLeft->followStmtProcessed) {
10551 lenAssign.clear(); 10611 lenAssign.clear();
10612 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10613 } else {
10614 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
10615 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10616 assignLeft->followStmt = followStmt.get();
10617 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10618 if (!assignLeft->followStmtProcessed) {
10619 lenAssign.clear();
10620 }
10552 } 10621 }
10553 popScope(); 10622 popScope();
10554 temp.push_back(indent() + "end"s + nlr(whileNode)); 10623 temp.push_back(indent() + "end"s + nlr(whileNode));
@@ -10593,12 +10662,17 @@ private:
10593 auto condStr = transformCondExp(whileNode->condition, isUntil); 10662 auto condStr = transformCondExp(whileNode->condition, isUntil);
10594 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 10663 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10595 pushScope(); 10664 pushScope();
10596 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 10665 if (hasBreakWithValue(breakLoopType)) {
10597 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10598 assignLeft->followStmt = followStmt.get();
10599 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10600 if (!assignLeft->followStmtProcessed) {
10601 lenAssign.clear(); 10666 lenAssign.clear();
10667 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10668 } else {
10669 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
10670 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10671 assignLeft->followStmt = followStmt.get();
10672 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10673 if (!assignLeft->followStmtProcessed) {
10674 lenAssign.clear();
10675 }
10602 } 10676 }
10603 popScope(); 10677 popScope();
10604 temp.push_back(indent() + "end"s + nlr(whileNode)); 10678 temp.push_back(indent() + "end"s + nlr(whileNode));