-- WebRacket --

The immediate problem is that (symbol->string w) needs to be unquoted:

(define (hello w)
  (define a (sxml->dom (hello/html w)))
  a)

(define (hello/html w)
  `(div (h2 "hello")
        (p ,(symbol->string w))))

;; I had initially included the following in `hello`
(define body (js-document-body))
(define more (hello 'Jens))
(js-append-child! body more)

I ran this and got:

I used:

racket ../webracket.rkt -b --ffi dom mf-hello.rkt 

For some reason - I'll figure that out tomorrow - the function sxml->dom fails spectacularly on presence of the symbol w in the input. I can see in the JavaScript console that an exception was thrown, but there were no error context. I'll fix look at sxml->dom tomorrow.
The function sxml->dom was written a long time ago - I suspect from before I implemented exceptions. I expect the solution is to throw proper exceptions for malformed inputs.

FWIW, here is the version I used to find out exactly where things went wrong:

(define (hello/html w)
  (js-log "hello/html")
  `(div (h2 "hello")
        (p (symbol->string w))))


(define (hello w)
  (js-log "hello")
  (js-log "1")
  (define t (hello/html w))
  (js-log "2")
  (js-log (format "~a" t))
  (define a (sxml->dom t))
  (js-log "3")
  a)

;; I had initially included the following in `hello`
(define body (js-document-body))
(js-log "A")
(define more (hello 'Jens))
(js-log "B")
(js-log more)
(js-append-child! body more)
(js-log "C")

I got this in the JavaScript console:

mf-hello.html:567 A
mf-hello.html:567 hello
mf-hello.html:567 1
mf-hello.html:567 hello/html
mf-hello.html:567 2
mf-hello.html:567 (div (h2 hello) (p (symbol->string w)))
mf-hello.html:1 Uncaught Exception {}

This is where I spotted the problem: (symbol->string w).

I pulled your repo and ran race-setup on it. I noticed two major problems:

  1. It complles too many things, especially WebRacket files. Perhaps you should consider a different file extension (.wrkt?) and then exclude those in the "info.rkt" file when you make a package.

I'll keep that in mind. I haven't tried using raco setup on the repo.
I usually do raco make webracket.rkt.

  1. The name js-eval shows up as undefined. My guess is that this is needed somewhere in my example but I was reluctant to read a 120k file. Question: Am i missing one of your packages that this relies on?

The js-... name means by convention that it is an FFI function.
To find what to include:

> cd ffi
> grep js-eval *ffi
dom.ffi:(define-foreign js-evaluate
standard.ffi:(define-foreign js-eval

So add --ffi standard to get js-eval.

The entry in standard.ffi is:

(define-foreign js-eval
  #:module "standard"
  #:name   "eval"
  (-> (string) (extern/raw)))

This means the argument is a string and that it returns an extern structure
with a reference to a JavaScript object.

Since JavaScript objects can't be back and forth to the WebAssembly VM,
such an object gets an id number - and the extern structure simply holds that id number.
On the JavaScript side, I have an hash table mapping these id numbers to JavaScript objects.

Similarly, I can't directly send a string from the WebAssembly side to JavaScript.
Here the strings is fasl-encoded in a byte array. The JavaScript side then decodes the string on the other side.

There are examples of how to use js-eval in test/test-ffi.rkt.

It turned out that sxml->dom called createElement via the FFI.
Here createElement throws an exception on the JavaScript side.
It complained about "symbol->string" not being a legal html tag.
[That is, the cause wasn't that w was a symbol as I thought yesterday.]

Now such JavaScript exceptions are handled on the WebAssembly
side by turning them into normal Racket exceptions. Thus, a program
can use with-handlers to catch them.

Doing that in sxml->dom led to this message in the JS console:

This is already an improvement.

However, I decided it were better that sxml->dom validated its input
before calling createElement. So after adding validation, sxml->dom
is no more robust - and the error messages better.

The main function sxml->dom now looks like this:

(define (sxml->dom exp)
  (match exp
    [(? string? s)
     (js-create-text-node s)]
    [(list '@ rest ...)
     (raise-sxml-stray-attribute-block-error exp)]
    [(list (? symbol? tag) rest ...)
     (define-values (attrs children)
       (match rest
         ['()
          (values '() '())]
         [(cons (list '@ attrs ...) children)
          (values attrs children)]
         [(cons (and maybe-attrs (cons '@ _)) _)
          (raise-sxml-attribute-block-error maybe-attrs exp)]
         [_
          (values '() rest)]))
     (define elem (create-element/with-context tag exp))
     (set-elem-attributes! elem attrs exp)
     (add-children! elem children)
     elem]
    [(list first _ ...)
     (raise-sxml-tag-error first exp)]
    [_
     (raise-sxml-shape-error exp)]))

All good, I got my first webracket program to run in the browser.
See below. Thanks for the quick responses.

2 Likes

Let me propose that you add a "worklist" page to your WebRacket page, perhaps with groups of tasks that others could do.

One of the first tasks should be to simplify how WebRacket programs get complied and run. The more people actually write WebRacket programs, the more feedback you get, including Issues or even PRs.

Thanks for the project and the effort.

1 Like

Let me propose that you add a "worklist" page to your WebRacket page, perhaps with groups of tasks that others could do.

I'll do that.

But I think, I need to improve this first:

One of the first tasks should be to simplify how WebRacket programs get complied and run.

/Jens Axel

Sorry for not spelling out what I had in mind with the "easy running" bullet.

Your project clearly calls for a #lang webracket implementation. The language's execution should include background compilation of, deployment, and even execution of the program in the browser. Such a language implementation would allow people to run it from the command line, from Emacs Mode, or from DrRacket.

A quicker alternative might be to equip DrRacket with run buttons via tool, similar to those that, say, a Scribble module comes with (render as html, render as pdf). While this approach narrows the available editing options, it might be a simpler task than creating #lang webracket though sooner or later you will want this anyway.