alan-if / alan

ALAN IF compilers and interpreters
https://alanif.se
Other
19 stars 3 forks source link

Malformed EVENT Causes Terp to Freeze/Hang For Ever #20

Open tajmone opened 4 years ago

tajmone commented 4 years ago

I've encountered a bug related to EVENTs and RULEs.

When I've added the following code to a pre-existing adventure, the compiled game would hang forever on entering the level5 location:

WHEN hero AT Level5 =>
  SCHEDULE Level5Event AT Level5 AFTER 0.

EVENT Level5Event
  IF hero at Level5 THEN
    "$pA supernatural voice screams at you:
     $n""Mortal, are you worthy of using the StdLib?"""
    SCHEDULE Level5Event AT Level5 AFTER 0.
  ELSE
    CANCEL Level5Event.
  END IF.
END EVENT.

I wasn't able to provide a link to the full adventure because it was a WIP adventure that wasn't committed to any repository, but I'm positively sure that the above code was the sole culprit of the terp hanging.

Possibly this leads to a stall situation which is not being foreseen by the compiler.

tajmone commented 4 years ago

It looks like the problem is the line scheduling the event after 0:

SCHEDULE Level5Event AT Level5 AFTER 0.

which causing an infinite regression of the EVENT (it was a typo on my side, instead of 1 I wrote 0).

Should the compiler be able to catch similar infinite regressions?

In theory, there could be an EVENT that needs to be executed multiple times in the same turn (due to some conditional statements), but it sounds a bad idea anyways.

Even if an EVENT was allowed to schedule itself AFTER 0, the interpreter should enforce a recursion limit to prevent infinite hanging (e.g. a roof of 256 recursive schedules).

Does it make sense?

thoni56 commented 4 years ago

I think you are correct (I haven't created a test case yet...), scheduling an event After 0 is dangerous if it is an executing event that does it since that adds the event in the current iteration of events.

And prohibiting that is not the best solution either since an event could schedule itself conditionally to create a "multi-triggering" event, or you might schedule a series of events (I'm thinking a bomb event scheduling scrapnel-throwing events at nearby locations). So I'm not sure what the compiler can actually do. A warning perhaps?

But a limit in the interpreter is at least better than nothing, and should probably be implemented anyhow.

tajmone commented 4 years ago

Indeed, it's a puzzling issue. In itself, there's nothing syntactically wrong about, and there are legitimate uses for this.

But then, usually most applications that contemplate recursive calls do set a limit to prevent the machine hanging (or worst, crashing). So, if it's true that authors shouldn't be prevented from such cases, it's possibly also legitimate to implement on the interpreter some sort of safety mechanism to prevent unlimited looping.

I'm thinking, as a comparison, to various syntax parsers that allow nested constructs; they usually have a threshold that prevents recursing beyond a certain number of times (although this is usually due to true recursive functions, without tail recursion, which end up piling stack frames, which consumes memory very fast).