[gambit-list] Q: Understanding -target js

Marc Feeley feeley at iro.umontreal.ca
Thu Jan 20 15:08:21 EST 2022


> On Jan 20, 2022, at 2:07 PM, Jörg F. Wittenberger <Joerg.Wittenberger at softeyes.net> wrote:
> 
> With the "silent" release of 4.9.4 I'm intrigued to learn how to
> actually use the alternative compile backend choice.
> 
> Initially confining myself to the `js` backend with HTML output.
> 
> 1) A simple `(display "Hello World!")` gave no result.
> 
>   Where does content written to standard-{output,error}-port end up?

The JavaScript backend implements the following:

#1 - The (current-output-port) is attached to the JavaScript console, which is viewable using your browser’s developer tools.  So that’s where `display`, `write`, `newline`, `pretty-print`, will show their output by default.

For example this will show “Hello World!” in the JavaScript console:

    $ cat hw.scm
    (display "Hello World!\n")
    $ gsc -target js -exe -o hw.html hw.scm
    $ open hw.html

#2 - The (repl-output-port) is attached to a “simulated console” implemented using the JavaScript `prompt` function, which shows up as a dialog box.  So if you call `pp` or `(display … (repl-output-port))` the output will be scheduled to be shown in this dialog box… but the dialog box will only appear when the program reads from this console (which is normally the case in a Read-Eval-Print-Loop).

For example this will show “Hello World!” in the dialog box:

    $ cat hw.scm
    (display "Hello World!\n" (repl-output-port))
    (read) ;; dummy read to allow "simulated console" to be displayed
    $ gsc -target js -exe -o hw.html hw.scm
    $ open hw.html

You can call `(##repl-debug-main)` in the program to initiate the Gambit REPL that interacts with this simulated console:

    $ cat hw.scm
    (##repl-debug-main)
    $ gsc -target js -exe -o hw.html hw.scm
    $ open hw.html

and this redirects the `(current-input-port)` and `(current-output-port)` to the simulated console so that I/O appears where most programmers expect it to go (in the REPL’s console).  At any time you can use the `##stdout-port` to send output to the JavaScript console: (display "Hello!\n" ##stdout-port) .

> 
> 2) Raising an error or `(##repl)` give me a more or less nice REPL.

See previous point #2.

> Unfortunately the source code does not look like a good starting point
> to learn how that REPL is implemented.
> 
>   Attached my current "Hello World!" using `##inline-host-statement`
>   to call into JavaScript.  (Deduced from digging into gambit source.)

This is another option which uses `##inline-host-statement` to interface to the JavaScript `alert`:

    $ cat hw.scm
    (define (alert msg) (##inline-host-statement "alert(@scm2host@(@1@));" msg))
    (alert "Hello World!\n")
    $ gsc -target js -exe -o hw.html hw.scm
    $ open hw.html

Note that the `##inline-host-statement` can take parameters, which are accessible with `@1@`, `@2@`, etc in the string of code.  Also note that the conversion from the Scheme object representation to the JavaScript object representation is not automatic.  That’s why there’s an explicit call to the `@scm2host@` function.  There’s a `@host2scm@` function also to convert in the other direction.  The `@…@` notation is a way to automatically add to the identifier the identifier prefix that is currently being used by the Gambit JavaScript backend (it is `_` currently).

> 
>   I ran into https://github.com/udem-dlteam/els2021-presentation which
>   explains inline syntax but this syntax seems not to work with 4.9.4
>   unless there is a trick I missed.
> 

Yet another option which simplifies the Scheme code it to use the `_six/js` module.  This module provides a JavaScript FFI that is based on an infix syntax and the data conversions are done automatically.  Here’s an example:

    $ cat hw.scm
    (import (_six js))
    (define (console-log msg) \console.log(`msg))
    (console-log "hello world")
    $ gsc -target js -c -o js.js ~~lib/_six/js.sld
    $ gsc -target js -c -o six-expand.js ~~lib/_six/six-expand.scm
    $ gsc -target js -exe -o index.html -nopreload js.js six-expand.js hw.scm
    $ open index.html

>   Is there example code out there (or anything better) to learn how
>   working code manipulating DOM could roughly work?
> 

Marc-André Bélanger is working on a DOM module.  He’s usually listening to the Gambit gitter chat if you want to drop by.  A good place to start is the paper we wrote on the SIX JS FFI: http://www.iro.umontreal.ca/~feeley/papers/BelangerFeeleyELS21.pdf

>   Any documentation on ##inline-host-* , @scm2host@ and friends would
>   also be very welcome.

Sorry… no official documentation.  Part of the reason is that I think there will soon be a refactoring of all the FFI stuff (in all the backends) and `##inline-host-*` will probably be renamed `host-eval`, `host-exec` and `host-decl`.  We need to experiment some more before it becomes official.

> 
> 3) Figuring out what is or is not supported per backend could become a
> nightmare.  Right now I found `open-tcp-server` to return #!void,
> `open-tcp-client` to complain about wrong number of arguments.  Both
> are not really helpful to understand that this documented procedure is
> not yet implemented.
> 
>   My own solution to the recurring situation is to have (very few) all
>   upper case acronyms defined which are easy to spot visually or via
>   grep.  NYIE in this case, which is a procedure accepting any number
>   of arguments and raises a not-yet-implemented-exception.
> 
>   I don't expect a book of unimplemented features, am I missing
>   something?

I agree that the Universal Backend doesn’t have the same level of polish as the C backend.  The recent focus has been on experimentation and seeing what features can/should be implemented.  What you suggest is certainly doable given enough time.  Don’t hesitate to send in pull-requests or contribute to any part of Gambit that you feel needs improving… we are always looking for contributors!

Marc




More information about the Gambit-list mailing list