remko / waforth

Small but complete dynamic Forth Interpreter/Compiler for and in WebAssembly
https://mko.re/waforth
MIT License
499 stars 28 forks source link

KEY or async handling doesn't play nice when compiled #60

Open rlamorea opened 11 months ago

rlamorea commented 11 months ago

Maybe I'm trying to do too much, but I'm having a very difficult time getting either KEY or bind or bindAsync to work when inside a compiled word.

Example:

: testit
    ." ENTER A KEY "
     KEY
     ." KEY WAS " .
     ;

testit

What ends up happening is that the window.prompt dialog comes up before anything is emitted, so that prompt text is invisible until I enter a key into the prompt dialog, then it all gets dumped out.

The same thing happens with synchronous or asynchronous bindings -- once inside a compiled word, there is no way (seemingly) to get any sort of interactive session that takes users input inside a word definition.

I don't know if it would work to have a type of bind to an async function that would await its return -- and thereby stop the Forth execution until that is done? (Ideally after dumping any emitted content, though that is something that could be done inside the async function itself if necessary).

remko commented 11 months ago

Hi,

For starters, the web version only flushes output on newline, so the text won't have been sent to the console yet by the time you do a 'KEY'. This could be fixed by flushing any pending output when a KEY is done, which would be an easy fix.

However, even adding a CR to force the flush of the output buffer doesn't seem to solve the problem yet. I think that what's happening is that, although the output has been sent to the DOM, the DOM hasn't re-rendered yet by the time 'KEY' is executed, and the prompt modal is blocking re-rendering. If you try it in the standalone version (which uses real blocking calls for i/o), it works.

I don't think there is a synchronous way to force-redraw the document before opening the prompt.

So, I think the conclusion is that using a synchronous word such as 'KEY' doesn't work well in a browser. I think programs have to be written in a way that they receive input asynchronously.

Making KEY async, and awaiting the output would be nice, but WebAssembly doesn't support suspending execution, although there have been proposals in the past AFAICT (such as this one). An alternative would be to make WAForth itself suspendable and resumable, but this would make things very complicated.

remko commented 8 months ago

FYI, once JavaScript Promise-integration lands, this can be fixed.

rlamorea commented 8 months ago

Good to know. I hacked workaround for a simple online Forth sandbox in the meantime. https://github.com/rlamorea/runforth?tab=readme-ov-file

farvardin commented 8 months ago

I was going to open a similar issue until I've found this one.

It seems to be more complicated than I thought. I suppose disabling the JS alert and making the prompt inside the text area (console) wouldn't be sufficient?

I wanted to test a simple menu like that:


DEFER start 

: chapter01
KEY
DUP
114 = IF 
." You've gone to the right. THE END " EXIT
THEN
108 = IF ." You've gone to the left. THE END " EXIT
ELSE
 ." Try again "
 CR
 \ start
 THEN
;

:NONAME \ start
." This is a test " CR
." Do you want to go to the right (r) or to the left (l)? "
chapter01
; IS start

start