diff options
Diffstat (limited to '')
| -rw-r--r-- | ldebug.c | 9 | ||||
| -rw-r--r-- | lgc.c | 11 | ||||
| -rw-r--r-- | ltm.c | 22 | ||||
| -rw-r--r-- | lvm.c | 46 |
4 files changed, 40 insertions, 48 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldebug.c,v 2.149 2017/12/15 13:07:10 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 2.150 2017/12/20 14:58:05 roberto Exp roberto $ |
| 3 | ** Debug Interface | 3 | ** Debug Interface |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -737,8 +737,6 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { | |||
| 737 | const char *msg; | 737 | const char *msg; |
| 738 | va_list argp; | 738 | va_list argp; |
| 739 | luaC_checkGC(L); /* error message uses memory */ | 739 | luaC_checkGC(L); /* error message uses memory */ |
| 740 | if (isLuacode(ci)) | ||
| 741 | L->top = ci->top; /* prepare top */ | ||
| 742 | va_start(argp, fmt); | 740 | va_start(argp, fmt); |
| 743 | msg = luaO_pushvfstring(L, fmt, argp); /* format message */ | 741 | msg = luaO_pushvfstring(L, fmt, argp); /* format message */ |
| 744 | va_end(argp); | 742 | va_end(argp); |
| @@ -762,7 +760,6 @@ static int changedline (Proto *p, int oldpc, int newpc) { | |||
| 762 | 760 | ||
| 763 | 761 | ||
| 764 | void luaG_traceexec (lua_State *L) { | 762 | void luaG_traceexec (lua_State *L) { |
| 765 | ptrdiff_t oldtop = savestack(L, L->top); | ||
| 766 | CallInfo *ci = L->ci; | 763 | CallInfo *ci = L->ci; |
| 767 | lu_byte mask = L->hookmask; | 764 | lu_byte mask = L->hookmask; |
| 768 | int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); | 765 | int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); |
| @@ -774,7 +771,8 @@ void luaG_traceexec (lua_State *L) { | |||
| 774 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ | 771 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ |
| 775 | return; /* do not call hook again (VM yielded, so it did not move) */ | 772 | return; /* do not call hook again (VM yielded, so it did not move) */ |
| 776 | } | 773 | } |
| 777 | L->top = ci->top; /* prepare top */ | 774 | if (!isIT(*(ci->u.l.savedpc - 1))) |
| 775 | L->top = ci->top; /* prepare top */ | ||
| 778 | if (counthook) | 776 | if (counthook) |
| 779 | luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ | 777 | luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ |
| 780 | if (mask & LUA_MASKLINE) { | 778 | if (mask & LUA_MASKLINE) { |
| @@ -789,7 +787,6 @@ void luaG_traceexec (lua_State *L) { | |||
| 789 | } | 787 | } |
| 790 | L->oldpc = npc; | 788 | L->oldpc = npc; |
| 791 | } | 789 | } |
| 792 | L->top = restorestack(L, oldtop); | ||
| 793 | if (L->status == LUA_YIELD) { /* did hook yield? */ | 790 | if (L->status == LUA_YIELD) { /* did hook yield? */ |
| 794 | if (counthook) | 791 | if (counthook) |
| 795 | L->hookcount = 1; /* undo decrement to zero */ | 792 | L->hookcount = 1; /* undo decrement to zero */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.242 2017/12/08 17:28:25 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.243 2017/12/20 14:58:05 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -571,21 +571,16 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
| 571 | 571 | ||
| 572 | /* | 572 | /* |
| 573 | ** Traverse a thread, marking the elements in the stack up to its top | 573 | ** Traverse a thread, marking the elements in the stack up to its top |
| 574 | ** and cleaning the rest of the stack in the last traversal. | 574 | ** and cleaning the rest of the stack in the final traversal. |
| 575 | ** That ensures that the entire stack have valid (non-dead) objects. | 575 | ** That ensures that the entire stack have valid (non-dead) objects. |
| 576 | ** In an emergency collection running Lua code, 'L->top' may not be | ||
| 577 | ** update. In that case, traverse at least up to 'ci->top'. | ||
| 578 | */ | 576 | */ |
| 579 | static int traversethread (global_State *g, lua_State *th) { | 577 | static int traversethread (global_State *g, lua_State *th) { |
| 580 | StkId o = th->stack; | 578 | StkId o = th->stack; |
| 581 | StkId top = th->top; | ||
| 582 | if (o == NULL) | 579 | if (o == NULL) |
| 583 | return 1; /* stack not completely built yet */ | 580 | return 1; /* stack not completely built yet */ |
| 584 | lua_assert(g->gcstate == GCSatomic || | 581 | lua_assert(g->gcstate == GCSatomic || |
| 585 | th->openupval == NULL || isintwups(th)); | 582 | th->openupval == NULL || isintwups(th)); |
| 586 | if (g->gcemergency && isLuacode(th->ci) && top < th->ci->top) | 583 | for (; o < th->top; o++) /* mark live elements in the stack */ |
| 587 | top = th->ci->top; | ||
| 588 | for (; o < top; o++) /* mark live elements in the stack */ | ||
| 589 | markvalue(g, s2v(o)); | 584 | markvalue(g, s2v(o)); |
| 590 | if (g->gcstate == GCSatomic) { /* final traversal? */ | 585 | if (g->gcstate == GCSatomic) { /* final traversal? */ |
| 591 | StkId lim = th->stack + th->stacksize; /* real end of stack */ | 586 | StkId lim = th->stack + th->stacksize; /* real end of stack */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltm.c,v 2.54 2017/12/19 16:40:17 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.55 2017/12/20 14:58:05 roberto Exp roberto $ |
| 3 | ** Tag methods | 3 | ** Tag methods |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -101,7 +101,7 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) { | |||
| 101 | 101 | ||
| 102 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | 102 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, |
| 103 | const TValue *p2, const TValue *p3) { | 103 | const TValue *p2, const TValue *p3) { |
| 104 | StkId func = (isLuacode(L->ci)) ? L->ci->top : L->top; | 104 | StkId func = L->top; |
| 105 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 105 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
| 106 | setobj2s(L, func + 1, p1); /* 1st argument */ | 106 | setobj2s(L, func + 1, p1); /* 1st argument */ |
| 107 | setobj2s(L, func + 2, p2); /* 2nd argument */ | 107 | setobj2s(L, func + 2, p2); /* 2nd argument */ |
| @@ -115,8 +115,8 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | |||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | 117 | ||
| 118 | static void reallycallTMres (lua_State *L, const TValue *f, const TValue *p1, | 118 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, |
| 119 | const TValue *p2, StkId res) { | 119 | const TValue *p2, StkId res) { |
| 120 | ptrdiff_t result = savestack(L, res); | 120 | ptrdiff_t result = savestack(L, res); |
| 121 | StkId func = L->top; | 121 | StkId func = L->top; |
| 122 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 122 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
| @@ -133,29 +133,19 @@ static void reallycallTMres (lua_State *L, const TValue *f, const TValue *p1, | |||
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | 135 | ||
| 136 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | ||
| 137 | const TValue *p2, StkId res) { | ||
| 138 | if (isLuacode(L->ci)) | ||
| 139 | L->top = L->ci->top; /* prepare top */ | ||
| 140 | reallycallTMres(L, f, p1, p2, res); | ||
| 141 | } | ||
| 142 | |||
| 143 | |||
| 144 | static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, | 136 | static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 145 | StkId res, TMS event) { | 137 | StkId res, TMS event) { |
| 146 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ | 138 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ |
| 147 | if (ttisnil(tm)) | 139 | if (ttisnil(tm)) |
| 148 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ | 140 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ |
| 149 | if (ttisnil(tm)) return 0; | 141 | if (ttisnil(tm)) return 0; |
| 150 | reallycallTMres(L, tm, p1, p2, res); | 142 | luaT_callTMres(L, tm, p1, p2, res); |
| 151 | return 1; | 143 | return 1; |
| 152 | } | 144 | } |
| 153 | 145 | ||
| 154 | 146 | ||
| 155 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 147 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 156 | StkId res, TMS event) { | 148 | StkId res, TMS event) { |
| 157 | if (event != TM_CONCAT && isLuacode(L->ci)) | ||
| 158 | L->top = L->ci->top; /* prepare top */ | ||
| 159 | if (!callbinTM(L, p1, p2, res, event)) { | 149 | if (!callbinTM(L, p1, p2, res, event)) { |
| 160 | switch (event) { | 150 | switch (event) { |
| 161 | case TM_CONCAT: | 151 | case TM_CONCAT: |
| @@ -195,8 +185,6 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, | |||
| 195 | 185 | ||
| 196 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | 186 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 197 | TMS event) { | 187 | TMS event) { |
| 198 | if (isLuacode(L->ci)) | ||
| 199 | L->top = L->ci->top; /* prepare top */ | ||
| 200 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ | 188 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ |
| 201 | return !l_isfalse(s2v(L->top)); | 189 | return !l_isfalse(s2v(L->top)); |
| 202 | else if (event == TM_LE) { | 190 | else if (event == TM_LE) { |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.328 2017/12/20 14:58:05 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.329 2017/12/22 14:16:46 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -464,8 +464,6 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
| 464 | } | 464 | } |
| 465 | if (tm == NULL) /* no TM? */ | 465 | if (tm == NULL) /* no TM? */ |
| 466 | return 0; /* objects are different */ | 466 | return 0; /* objects are different */ |
| 467 | if (isLuacode(L->ci)) | ||
| 468 | L->top = L->ci->top; /* prepare top */ | ||
| 469 | luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ | 467 | luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ |
| 470 | return !l_isfalse(s2v(L->top)); | 468 | return !l_isfalse(s2v(L->top)); |
| 471 | } | 469 | } |
| @@ -780,20 +778,29 @@ void luaV_finishOp (lua_State *L) { | |||
| 780 | #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } | 778 | #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } |
| 781 | 779 | ||
| 782 | /* | 780 | /* |
| 783 | ** Whenever code can raise errors (including memory errors), the global | 781 | ** Correct global 'pc'. |
| 784 | ** 'pc' must be correct to report occasional errors. | ||
| 785 | */ | 782 | */ |
| 786 | #define savepc(L) (ci->u.l.savedpc = pc) | 783 | #define savepc(L) (ci->u.l.savedpc = pc) |
| 787 | 784 | ||
| 788 | 785 | ||
| 789 | /* | 786 | /* |
| 787 | ** Whenever code can raise errors, the global 'pc' and the global | ||
| 788 | ** 'top' must be correct to report occasional errors. | ||
| 789 | */ | ||
| 790 | #define savestate(L,ci) (savepc(L), L->top = ci->top) | ||
| 791 | |||
| 792 | |||
| 793 | /* | ||
| 790 | ** Protect code that, in general, can raise errors, reallocate the | 794 | ** Protect code that, in general, can raise errors, reallocate the |
| 791 | ** stack, and change the hooks. | 795 | ** stack, and change the hooks. |
| 792 | */ | 796 | */ |
| 793 | #define Protect(exp) (savepc(L), (exp), updatetrap(ci)) | 797 | #define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) |
| 798 | |||
| 799 | /* special version that does not change the top */ | ||
| 800 | #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) | ||
| 794 | 801 | ||
| 795 | /* | 802 | /* |
| 796 | ** Protect code that will return. | 803 | ** Protect code that will finish the loop (returns). |
| 797 | */ | 804 | */ |
| 798 | #define halfProtect(exp) (savepc(L), (exp)) | 805 | #define halfProtect(exp) (savepc(L), (exp)) |
| 799 | 806 | ||
| @@ -842,6 +849,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 842 | vmfetch(); | 849 | vmfetch(); |
| 843 | lua_assert(base == ci->func + 1); | 850 | lua_assert(base == ci->func + 1); |
| 844 | lua_assert(base <= L->top && L->top < L->stack + L->stacksize); | 851 | lua_assert(base <= L->top && L->top < L->stack + L->stacksize); |
| 852 | lua_assert(ci->top < L->stack + L->stacksize); | ||
| 845 | vmdispatch (GET_OPCODE(i)) { | 853 | vmdispatch (GET_OPCODE(i)) { |
| 846 | vmcase(OP_MOVE) { | 854 | vmcase(OP_MOVE) { |
| 847 | setobjs2s(L, ra, RB(i)); | 855 | setobjs2s(L, ra, RB(i)); |
| @@ -1000,10 +1008,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1000 | int b = GETARG_B(i); | 1008 | int b = GETARG_B(i); |
| 1001 | int c = GETARG_C(i); | 1009 | int c = GETARG_C(i); |
| 1002 | Table *t; | 1010 | Table *t; |
| 1003 | t = luaH_new(L); | 1011 | L->top = ci->top; /* correct top in case of GC */ |
| 1012 | t = luaH_new(L); /* memory allocation */ | ||
| 1004 | sethvalue2s(L, ra, t); | 1013 | sethvalue2s(L, ra, t); |
| 1005 | if (b != 0 || c != 0) | 1014 | if (b != 0 || c != 0) |
| 1006 | luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); | 1015 | luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ |
| 1007 | checkGC(L, ra + 1); | 1016 | checkGC(L, ra + 1); |
| 1008 | vmbreak; | 1017 | vmbreak; |
| 1009 | } | 1018 | } |
| @@ -1371,7 +1380,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1371 | int c = GETARG_C(i); | 1380 | int c = GETARG_C(i); |
| 1372 | StkId rb; | 1381 | StkId rb; |
| 1373 | L->top = base + c + 1; /* mark the end of concat operands */ | 1382 | L->top = base + c + 1; /* mark the end of concat operands */ |
| 1374 | Protect(luaV_concat(L, c - b + 1)); | 1383 | ProtectNT(luaV_concat(L, c - b + 1)); |
| 1375 | if (trap) { /* 'luaV_concat' may move the stack */ | 1384 | if (trap) { /* 'luaV_concat' may move the stack */ |
| 1376 | updatebase(ci); | 1385 | updatebase(ci); |
| 1377 | ra = RA(i); | 1386 | ra = RA(i); |
| @@ -1481,7 +1490,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1481 | if (b != 0) /* fixed number of arguments? */ | 1490 | if (b != 0) /* fixed number of arguments? */ |
| 1482 | L->top = ra + b; /* top signals number of arguments */ | 1491 | L->top = ra + b; /* top signals number of arguments */ |
| 1483 | /* else previous instruction set top */ | 1492 | /* else previous instruction set top */ |
| 1484 | Protect(luaD_call(L, ra, nresults)); | 1493 | ProtectNT(luaD_call(L, ra, nresults)); |
| 1485 | vmbreak; | 1494 | vmbreak; |
| 1486 | } | 1495 | } |
| 1487 | vmcase(OP_TAILCALL) { | 1496 | vmcase(OP_TAILCALL) { |
| @@ -1493,12 +1502,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1493 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | 1502 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |
| 1494 | if (!ttisfunction(vra)) { /* not a function? */ | 1503 | if (!ttisfunction(vra)) { /* not a function? */ |
| 1495 | /* try to get '__call' metamethod */ | 1504 | /* try to get '__call' metamethod */ |
| 1496 | Protect(ra = luaD_tryfuncTM(L, ra)); | 1505 | ProtectNT(ra = luaD_tryfuncTM(L, ra)); |
| 1497 | vra = s2v(ra); | 1506 | vra = s2v(ra); |
| 1498 | b++; /* there is now one extra argument */ | 1507 | b++; /* there is now one extra argument */ |
| 1499 | } | 1508 | } |
| 1500 | if (!ttisLclosure(vra)) { /* C function? */ | 1509 | if (!ttisLclosure(vra)) { /* C function? */ |
| 1501 | Protect(luaD_call(L, ra, LUA_MULTRET)); /* call it */ | 1510 | ProtectNT(luaD_call(L, ra, LUA_MULTRET)); /* call it */ |
| 1502 | /* next instruction will do the return */ | 1511 | /* next instruction will do the return */ |
| 1503 | } | 1512 | } |
| 1504 | else { /* tail call */ | 1513 | else { /* tail call */ |
| @@ -1568,7 +1577,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1568 | lua_Integer ilimit, initv; | 1577 | lua_Integer ilimit, initv; |
| 1569 | int stopnow; | 1578 | int stopnow; |
| 1570 | if (!forlimit(plimit, &ilimit, 1, &stopnow)) { | 1579 | if (!forlimit(plimit, &ilimit, 1, &stopnow)) { |
| 1571 | savepc(L); /* for the error message */ | 1580 | savestate(L, ci); /* for the error message */ |
| 1572 | luaG_runerror(L, "'for' limit must be a number"); | 1581 | luaG_runerror(L, "'for' limit must be a number"); |
| 1573 | } | 1582 | } |
| 1574 | initv = (stopnow ? 0 : ivalue(init)); | 1583 | initv = (stopnow ? 0 : ivalue(init)); |
| @@ -1618,7 +1627,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1618 | } | 1627 | } |
| 1619 | else { /* try making all values floats */ | 1628 | else { /* try making all values floats */ |
| 1620 | lua_Number ninit; lua_Number nlimit; lua_Number nstep; | 1629 | lua_Number ninit; lua_Number nlimit; lua_Number nstep; |
| 1621 | savepc(L); /* in case of errors */ | 1630 | savestate(L, ci); /* in case of errors */ |
| 1622 | if (!tonumber(plimit, &nlimit)) | 1631 | if (!tonumber(plimit, &nlimit)) |
| 1623 | luaG_runerror(L, "'for' limit must be a number"); | 1632 | luaG_runerror(L, "'for' limit must be a number"); |
| 1624 | setfltvalue(plimit, nlimit); | 1633 | setfltvalue(plimit, nlimit); |
| @@ -1659,7 +1668,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1659 | int c = GETARG_C(i); | 1668 | int c = GETARG_C(i); |
| 1660 | unsigned int last; | 1669 | unsigned int last; |
| 1661 | Table *h; | 1670 | Table *h; |
| 1662 | if (n == 0) n = cast_int(L->top - ra) - 1; | 1671 | if (n == 0) |
| 1672 | n = cast_int(L->top - ra) - 1; | ||
| 1673 | else | ||
| 1674 | L->top = ci->top; /* correct top in case of GC */ | ||
| 1663 | if (c == 0) { | 1675 | if (c == 0) { |
| 1664 | c = GETARG_Ax(*pc); pc++; | 1676 | c = GETARG_Ax(*pc); pc++; |
| 1665 | } | 1677 | } |
| @@ -1679,7 +1691,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1679 | Proto *p = cl->p->p[GETARG_Bx(i)]; | 1691 | Proto *p = cl->p->p[GETARG_Bx(i)]; |
| 1680 | LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ | 1692 | LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ |
| 1681 | if (ncl == NULL) { /* no match? */ | 1693 | if (ncl == NULL) { /* no match? */ |
| 1682 | savepc(L); /* in case of allocation errors */ | 1694 | savestate(L, ci); /* in case of allocation errors */ |
| 1683 | pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ | 1695 | pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ |
| 1684 | } | 1696 | } |
| 1685 | else | 1697 | else |
