atlas-engineer / nyxt

Nyxt - the hacker's browser.
https://nyxt-browser.com/
9.8k stars 409 forks source link

Analysis of how we use and run `parenscript` #2505

Open aadcg opened 2 years ago

aadcg commented 2 years ago

Firstly, an overview.

There are always 2 steps:

  1. compilation from CL to JS (handled by ps:ps and others);
  2. evaluating the generated JS code (ffi-buffer-evaluate-javascript or ffi-buffer-evaluate-javascript-async).

Unfortunately, the macros from renderer-script.lisp conflate both. There should be a single macro to handle step 2 (peval, which should be renamed to ps-eval btw).

Regarding the former, we could just use regular CL functions defined with defun. Example:

(defun adder (a)
  (ps:ps (defun add (b) (+ (ps:lisp a) b))))

(adder 4)
"function add(b) {
    return 4 + b;
};"

But, arguably, it is confusing to define functions that output valid JS code as a string with defun. Perhaps it should be defined with defps. The computer doesn't care, humans do. defps would simply be:

(defmacro defps (script-name args &body script-body)
  `(defun ,script-name ,args (ps:ps ,@script-body)))

(There's also ps:ps*, another method to compile to JS).

Notice that once JS functions are evaluated (step 2) they will belong to the JS environment and they can be referenced with (ps:ps (add 4)) ("add(4);"). Still, we can't control the way the renderer garbage collects the environment (I assume).

Actions:

aartaka commented 2 years ago

I don't agree! We need:

  1. Lisp function that will call JS with Lisp arguments (define-parenscript).
  2. A way to quickly evaluate JS code, preferably with Lisp syntax (peval).
  3. A way to locally define fancy names for JS-with-Lisp-args functions locally (pflet).
    • Follows from 1 by the logic of "if we have global, we need local too".
  4. A way to easily bind JS objects to Lisp object (partially implemented in dom.lisp, but we need a general mechanism) with accessors and setf/writers equivalently working in both Lisp and JS worlds.
  5. A way to translate JS code to Lisp code (there's cl-uglify-js partially doing that).
  6. ...

Which represents another vision: the vision of fuzing Lisp and JS, as a desire to add a nice syntax and data model to an otherwise unescapably dominant JavaScript.

aartaka commented 2 years ago

Oh, and we also need a way to generically interact with our interfaces, for those renderers that we might need to support and that don't have JS (#2433 is probably a better place for this point).

aadcg commented 2 years ago

Lisp function that will call JS with Lisp arguments (define-parenscript).

How does that differ from peval? Besides, have you wondered why most of the entities defined with define-parenscript take no arguments?

aartaka commented 2 years ago

Lisp function that will call JS with Lisp arguments (define-parenscript).

How does that differ from peval?

It assigns it to a certain globally accessible name and abstracts away the details (as any function does), for one :)

Besides, have you wondered why most of the entities defined with define-parenscript take no arguments?

I haven't :P

aadcg commented 2 years ago

I believe you haven't understood my points. We're conflating two different things: generating JS, and evaluating it. I'll draft a PR soon.

aartaka commented 2 years ago

I've understood your points, and I'm answering to those: we need to conflate those, exactly because we can't put JS in a can and ignore it until we require it. We need to dynamically interop with JS, in all its grotesque ubiquity.

aadcg commented 2 years ago

Let's not forget about this comment.