Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async transpile #12

Closed
apowers313 opened this issue Nov 27, 2020 · 6 comments
Closed

async transpile #12

apowers313 opened this issue Nov 27, 2020 · 6 comments

Comments

@apowers313
Copy link

apowers313 commented Nov 27, 2020

In order to ensure functions exist when added as a magic as discussed in n-riesco/ijavascript#43, I need to resolve the function name using the inspect function of the NEL session. Inspect uses callbacks, but transpile is synchronous.

Any objections to wrapping the transpile call in Promise.resolve() to make it indifferent as to whether the transpiler is synchronous or asynchronous? The try / catch could be replaced with .then / .catch to the same effect.

It doesn't look like _runNow expects to be synchronous, so I don't think this would break anything else.

@n-riesco
Copy link
Owner

IJavascript code is ES5 and Promises are optional. If you're not familiar with this old style of coding (and since this is small change), I don't mind implementing the PR myself.

I will relax this requirement in the next major-version release (I'm waiting on zeromq to resolve their issues with v6).


BTW, I think that the need to run inspectis suggesting that addCmd should be run inside the Node.js session (please, let me know if it's unclear what I mean).

Wasn't your plan to define $$.addMagic() inside the Node.js session?

If you do that, your transpile function would simply transpile code like %addMagic %mymagic myfunction into $$.addMagic("%mymagic", myfunction); and %mymagic x y z into $$.runMagic("%mymagic","x y z"), or $$.magics["%mymagic"]("x y z"), or however you decide to store it.

@apowers313
Copy link
Author

Yea, if you don’t mind I’ll take you up in that offer — I’m pretty rust when it comes to ES5.


I looked into hanging addcmd off of $$, but it would require more work than I originally understood. In order to make the magics look the same as IPython’s (one of my design goals), they have to be located in the transpiler. Getting from $$.addcmd() to the transpiler context would require implementing new messages between the server and nel.js. In my opinion, that’s a lot more work for not much value. I’ll stick with %addcmd for now and think about adding $$ support in phase 2.

@n-riesco
Copy link
Owner

Getting from $$.addcmd() to the transpiler context would require implementing new messages between the server and nel.js.

What do you mean by server?


I'll go ahead with the PR, so that you can experiment with your current approach.

n-riesco added a commit that referenced this issue Nov 29, 2020
* To allow asynchronous transpilation, Server#transpile now accepts
  functions that return a Promise.

Closes #12
@apowers313
Copy link
Author

What do you mean by server?

Sorry, I'm not quite sure what nomenclature to use.

Quick architecture diagram:
image

I was trying to say that $$.addcmd() would live in the red server box on the far right; but transpile runs on the other side of process.send() in the NEL Session. Adding a command through $$.addcmd() would require some IPC and data marshalling to send the new command and it's function back to the transpiler.

@n-riesco
Copy link
Owner

n-riesco commented Dec 6, 2020

Thx for the neat diagram!

Now that I'm clear what you mean by server, I'm still convinced #12 (comment) applies. I guess the best way to see what I meant is with a very "bare-bone" example implementing %addcmd and %cd in the session server (I haven't tested the code, but i reckon this approach could work):

var Kernel = require("jp-kernel");

var config = {
    cwd: process.cwd(),
    hideUndefined: true,
    protocolVersion: "5.1",
};

config.startupCallback = function startupCallback() {
    // set `$$.magics = {}` in the session server to store the functions implementing magics
    // and set the magics `%addcmd` and `%cd`
    var code = "$$.magics = {};";
    code += "$$.magics['%addcmd'] = function(label, cmd) { return $$.magics[label] = eval(cmd); };";
    code += "$$.magics['%cd'] = function(path) { return process.chdir(path); };";

    this.session.execute(code, {
        onSuccess: function() {
            log("startupCallback: '" + code + "' run successfuly");
        },
        onError: function() {
            log("startupCallback: '" + code + "' failed to run");
        },
    });
};


config.transpile = function(code) {
    // handle magic `%addcmd label cmd`
    if (code.startsWith("%addcmd ")) {
        var line = code.slice(8).trim(); // skip "%addcmd "
        var pos = line.indexOf(' ');
        if (pos === -1) {
                throw new Error("%addmd: syntax error: missing label or cmd");
        }
        var label = JSON.stringify(line.slice(0, pos));
        var cmd = JSON.stringify(line.slice(pos));
 
        // transpile into code to set the magic handler in the session server
        return "$$.magic['%addcmd'](" + label + ", " + cmd + ");";
    }
   
    // handle other magics starting with %
    if (code.startsWith("%")) {
        var pos = line.indexOf(' ');
        if (pos === -1) {
            // magic has no arguments
            return "$$.magic[" + JSON.stringify(line) + "]()";
        }
        var label = JSON.stringify(line.slice(0, pos));
        var arg = JSON.stringify(line.slice(pos).trim());
        return ""$$.magic[" + label + "](" + arg + ");";
    }

    // not a magic, no transpilation needed
    return code;
};

// any other options, e.g. `kernel.handlers.is_complete_request`
// ...

// launch the kernel
var kernel = new Kernel(config);

// Interpret a SIGINT signal as a request to interrupt the kernel
process.on("SIGINT", function() {
    log("Interrupting kernel");
    kernel.restart(); // TODO(NR) Implement kernel interruption
});

@apowers313
Copy link
Author

I like it. I'm going to try some variation of that -- thanks for the tip. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants