As soon as you add a 2nd layer of loops however, you reach Turing-completeness and suddenly the halting problem becomes unsolvable.
-------
So you don't need to deny jmp/loops. You just need to deny _nested_ loops. And... find that old paper I read like 15 years ago to figure out the details to discriminate halt/not-halt in the single-layer loop language.
while (state !== STOP):
read = TAPE[index]
[state, write, dir] = TABLE[read, state]
TAPE[index] = write
index = index + dirE.g. this Ruby program is undecidable:
gets
This one using a hypothetical gets guaranteed to eventually halt is still undecidable: while getsWithTimeout != "halt"
endFor (;;) { print(“hahaha you didn’t say the magic word!”); }
In another loop would also prevent termination without program shutdowns.
To clarify, when I said "for loop", I meant what is sometimes called a "counted for loop" (or simply "counted loop"): there is an (maximum, if you allow early exit) iteration count that is computed before executing the loop and can't increase later.
In C syntax, it is for (int i = 0, e = ...; i < e; ++i) { ... } and the body of the loop is not allowed to change the value of either i or e.
Edit: actually I may have been unclear. When I said "for loops are guaranteed to terminate", in the context of the discussion, I meant "if the only kind of loops you allow are (counted) for loops in a language where loop-free expressions are guaranteed to terminate, you get a language where all expressions are guarantee to terminate". So loops can contain other loops, as long as they are all of the "counted for loop" kind.