@@ -998,13 +998,48 @@ static void forStmt(Compiler* compiler){
998998 | |
999999 +---------------------------------------------------------------------------------+
10001000 */
1001+ bool isForeach = false;
1002+ int iterReg = -1 ;
1003+ int stateReg = -1 ;
1004+
10011005 beginScope (compiler );
10021006 consume (compiler , TOKEN_LEFT_PAREN , "Expect '(' after 'for'." );
10031007
10041008 if (match (compiler , TOKEN_SEMICOLON )){
10051009 // No initializer
10061010 }else if (match (compiler , TOKEN_VAR )){
1007- varDecl (compiler );
1011+ Token varName = compiler -> parser .cur ;
1012+ consume (compiler , TOKEN_IDENTIFIER , "Expect variable name." );
1013+
1014+ if (match (compiler , TOKEN_COLON )){
1015+ isForeach = true;
1016+ iterReg = getFreeReg (compiler );
1017+ reserveReg (compiler , 2 );
1018+ stateReg = iterReg + 1 ;
1019+
1020+ ExprDesc iterExpr ;
1021+ expression (compiler , & iterExpr );
1022+ expr2Reg (compiler , & iterExpr , iterReg );
1023+ freeExpr (compiler , & iterExpr );
1024+
1025+ emitABC (compiler , OP_LOADNULL , stateReg , 0 , 0 );
1026+
1027+ addLocal (compiler , varName );
1028+ defineVar (compiler , 0 );
1029+ consume (compiler , TOKEN_RIGHT_PAREN , "Expect ')' after foreach variable." );
1030+ }else {
1031+ addLocal (compiler , varName );
1032+ int reg = compiler -> locals [compiler -> localCnt - 1 ].reg ;
1033+ if (match (compiler , TOKEN_ASSIGN )){
1034+ ExprDesc initExpr ;
1035+ expression (compiler , & initExpr );
1036+ expr2Reg (compiler , & initExpr , reg );
1037+ }else {
1038+ emitABC (compiler , OP_LOADNULL , reg , 0 , 0 );
1039+ }
1040+ defineVar (compiler , 0 );
1041+ consume (compiler , TOKEN_SEMICOLON , "Expect ';' after loop initializer." );
1042+ }
10081043 }else {
10091044 ExprDesc initExpr ;
10101045 expression (compiler , & initExpr );
@@ -1024,36 +1059,57 @@ static void forStmt(Compiler* compiler){
10241059 loop -> breakCnt = 0 ;
10251060
10261061 int exitJmp = -1 ;
1027- if (!match (compiler , TOKEN_SEMICOLON )){
1028- ExprDesc condition ;
1029- expression (compiler , & condition );
1030- consume (compiler , TOKEN_SEMICOLON , "Expect ';' after loop condition." );
1031-
1032- expr2NextReg (compiler , & condition );
1033- exitJmp = emitJmpIfFalse (compiler , condition .data .loc .index );
1034- freeExpr (compiler , & condition );
1062+ if (isForeach ){
1063+ reserveReg (compiler , 1 );
1064+ int condReg = getFreeReg (compiler ) - 1 ;
1065+ emitABC (compiler , OP_FOREACH , condReg , iterReg , 0 );
1066+ exitJmp = emitJmpIfFalse (compiler , condReg );
1067+ freeRegs (compiler , 1 );
1068+ }else {
1069+ if (!match (compiler , TOKEN_SEMICOLON )){
1070+ ExprDesc condition ;
1071+ expression (compiler , & condition );
1072+ consume (compiler , TOKEN_SEMICOLON , "Expect ';' after loop condition." );
1073+
1074+ expr2NextReg (compiler , & condition );
1075+ exitJmp = emitJmpIfFalse (compiler , condition .data .loc .index );
1076+ freeExpr (compiler , & condition );
1077+ }
10351078 }
1079+
1080+ int bodyJmp = -1 ;
1081+ int incStart = -1 ;
10361082
1037- int bodyJmp = emitJmp (compiler ); //
1038- int incStart = compiler -> func -> chunk .count ;
1039- loop -> start = incStart ;
1083+ if (!isForeach ){
1084+ int bodyJmp = emitJmp (compiler );
1085+ int incStart = compiler -> func -> chunk .count ;
1086+ loop -> start = incStart ;
10401087
1041- if (!match (compiler , TOKEN_RIGHT_PAREN )){
1042- ExprDesc incExpr ;
1043- expression (compiler , & incExpr );
1044- freeExpr (compiler , & incExpr );
1045- consume (compiler , TOKEN_RIGHT_PAREN , "Expect ')' after loop increment." );
1088+ if (!match (compiler , TOKEN_RIGHT_PAREN )){
1089+ ExprDesc incExpr ;
1090+ expression (compiler , & incExpr );
1091+ freeExpr (compiler , & incExpr );
1092+ consume (compiler , TOKEN_RIGHT_PAREN , "Expect ')' after loop increment." );
1093+ }
1094+
1095+ int loopJmpIndex = emitJmp (compiler );
1096+ int loopOffset = loopStart - loopJmpIndex - 1 ;
1097+ compiler -> func -> chunk .code [loopJmpIndex ] = CREATE_AsBx (OP_JMP , 0 , loopOffset );
1098+ patchJump (compiler , bodyJmp );
10461099 }
10471100
1048- int loopJmpIndex = emitJmp (compiler );
1049- int loopOffset = loopStart - loopJmpIndex - 1 ;
1050- compiler -> func -> chunk .code [loopJmpIndex ] = CREATE_AsBx (OP_JMP , 0 , loopOffset );
1051- patchJump (compiler , bodyJmp );
1101+
10521102 stmt (compiler );
10531103
1054- int incJmp = emitJmp (compiler );
1055- int incOffset = incStart - incJmp - 1 ;
1056- compiler -> func -> chunk .code [incJmp ] = CREATE_AsBx (OP_JMP , 0 , incOffset );
1104+ if (isForeach ){
1105+ emitLoop (compiler , loopStart );
1106+ }else {
1107+ int incJmp = emitJmp (compiler );
1108+ int incOffset = incStart - incJmp - 1 ;
1109+ compiler -> func -> chunk .code [incJmp ] = CREATE_AsBx (OP_JMP , 0 , incOffset );
1110+ }
1111+
1112+
10571113 if (exitJmp != -1 ){
10581114 patchJump (compiler , exitJmp );
10591115 }
@@ -1757,6 +1813,7 @@ static void handleString(Compiler* compiler, ExprDesc* expr, bool canAssign){
17571813 emitABC (compiler , OP_ADD , resReg , resReg , tmpExpr .data .loc .index );
17581814 freeRegs (compiler , 1 );
17591815 }
1816+ advance (compiler );
17601817 }else {
17611818 consume (compiler , TOKEN_INTERPOLATION_START , "Expect string or interpolation." );
17621819 expression (compiler , & tmpExpr );
0 commit comments