JohnEarnest / ok

An open-source interpreter for the K5 programming language.
MIT License
588 stars 72 forks source link

repl.js - Error: EAGAIN at Object.fs.readSync #6

Closed refset closed 9 years ago

refset commented 9 years ago

I'm struggling to run the interactive examples. Getting the following error...

jeremy@T:~/ok$ node repl.js examples/hangman.k
_____ > fs.js:554
  var r = binding.read(fd, buffer, offset, length, position);
                  ^
Error: EAGAIN, resource temporarily unavailable
    at Error (native)
    at Object.fs.readSync (fs.js:554:19)
    at readchar (/home/jeremy/ok/repl.js:15:5)
    at readline (/home/jeremy/ok/repl.js:19:34)
    at read (/home/jeremy/ok/repl.js:23:22)
    at applyverb (/home/jeremy/ok/oK.js:430:33)
    at run (/home/jeremy/ok/oK.js:567:10)
    at run (/home/jeremy/ok/oK.js:565:15)
    at run (/home/jeremy/ok/oK.js:550:6)
    at call (/home/jeremy/ok/oK.js:542:10)

Looks like you are already familiar with it...? I'm using node v0.12.0 on Ubuntu 12.04

JohnEarnest commented 9 years ago

I'm not sure if there's a way to do blocking reads from stdin using Node which works portably on different operating systems. I would guess that the hack I'm using worked in 0.11 and has been broken again in 0.12. I'm open to suggestions, but this sort of thing really doesn't seem to be a priority for the Node devs.

refset commented 9 years ago

Ah that's frustrating, but thanks for the prompt reply. I'll try to think something up.

refset commented 9 years ago

getline in this gist works synchronously for me. I have tried dropping it in directly in place of readline which seems to work initially:

  0:`
hellohello
"hellohello;"

But then this excerpt from tictac.k (which I don't fully understand) doesn't work:

  .[{0+." ",0:`};();:]
8
(1
 "number expected, found nil.")

Any thoughts?

JohnEarnest commented 9 years ago

It looks like the input string in your first example has an extraneous trailing semicolon.

The second code fragment is using the "error trap" triadic form of .. Error trap will catch any runtime exceptions that occur while executing a piece of code and give you back a tuple with either your desired output or the error message trapped, not unlike a try...catch in curly bracket languages. My code applies the second argument (an empty list) to an anonymous function which takes no arguments. In this function I read a line from stdin, prepend a space with " ", (to ensure it's a list of characters rather than a single char), parse it with monadic . (this could fail, hence the error trap) and then attempt to add 0 (this will fail if the result of the parse isn't a number, again handled by error trap). I admit this is a somewhat clumsy approach!

A trailing semicolon in input will confuse the parser a bit and that process will fail. I just glanced at that gist and I don't immediately see the problem. Could be something on my end, maybe? I'll look into it further when I have some time.

JohnEarnest commented 9 years ago

I updated to node v0.12.0 and I can't replicate the problem you're experiencing using OSX 10.10.1, which at least means the comment in that gist is misleading. Let's try applying the salient part of that example to the current implementation of oK's CLI repl- attempt to open and read synchronously from /dev/stdin on platforms where it exists. Modify the beginning of the script as follows:

var fd = process.stdin.fd;
var usingDevice = false;

function readchar() {
    var buff = new Buffer(1);
    fs.readSync(fd, buff, 0, 1);
    return String.fromCharCode(buff[0]);
}
function readline() {
    try { fd = fs.openSync('/dev/stdin', 'rs'); usingDevice = true; } catch (e) {}
    var r=""; while(true) { var c = readchar(); if (c == "\n") { break; } r += c; }
    if (usingDevice) { fs.closeSync(fd); } return r;
}

Please give this a try and let me know if it works for you on Ubuntu.

refset commented 9 years ago

Bingo! Thanks for explaining the triadic eval and adapting readline. I'm very impressed by it all :)

PR created: https://github.com/JohnEarnest/ok/pull/7

A separate browser repl issue I'm having is getting `0: working in either Chrome or FF. Have you tested the read function recently or any of the interactive examples for that matter? tictac.k really makes my fan spin.

JohnEarnest commented 9 years ago

Great! Pull request merged. Thanks for letting me know about this problem and helping me track down a workaround.

Monadic 0: interactive input doesn't work in the browser repl- this is pretty difficult issue to fix. It boils down to a fundamental problem with the way the JS input and threading model works. The oK interpreter needs to block for input, but while JS code is running the browser can't respond to input events.

It is possible to get this working, but I would need to completely rewrite the interpreter in something like a continuation-passing style in order to pause and resume execution in response to an input event callback. I think this would add a great deal of complexity and make the code much harder to understand, so I'm not too keen on the idea. A simple, easy to understand K interpreter is my core goal with this project. I've looked into Web Workers and they don't seem sufficient for this kind of use case either. I don't think I'll be able to support this functionality in the near future.

Printing with `0: should work fine, though. For example: http://johnearnest.github.io/ok/index.html?run=%20%600%3A%20%22Hello%2C%20World!%22%3B

Does that seem broken on your browser?

refset commented 9 years ago

Aha, my mistake, I meant `0:`` after all! But yes, it completely makes sense that it wouldn't work given the blocking nature of your interpreter. I will try to highlight this with a PR for the readme soon, along with a few other minor edits I'd recommend.

I'll close this issue for now, thanks for the discussion.

refset commented 9 years ago

Oops sorry, I made a mistake: https://github.com/jez0990/ok/commit/6eeb15937937c0428f3bc7da48eeb8b29517f020

I'm not experienced with git workflow enough to know what to do!

JohnEarnest commented 9 years ago

Let's take the easy route. I corrected the typo in my repo. Back out the change in your fork and then merge in my upstream changes. Then you'll be up to date and back in sync.

refset commented 9 years ago

Cool. Cheers!

refset commented 9 years ago

It is possible to get this working, but I would need to completely rewrite the interpreter in something like a continuation-passing style in order to pause and resume execution in response to an input event callback.

I was just thinking about changing all your functions into es6 generators and littering the code with yield* ...does that sound insane?

JohnEarnest commented 9 years ago

I have considered ES6 generators. In the future I may try rewriting oK to use them, but at this time I don't think they are sufficiently well supported by most browsers to depend upon. I encourage you to experiment in your own fork if you think this idea is interesting.