aya-lang / aya

Pocket sized programs
MIT License
54 stars 3 forks source link

Aya JavaScript Runtime #112

Open nick-paul opened 1 week ago

nick-paul commented 1 week ago

TL;DR: This PR creates a JS build of aya using maven (#106) and TeaVM. You can try the demo here. The editor can be used directly in documentation or examples

The demos above come in two parts:

  1. The Aya JavaScript Runtime (this PR): Compile aya.js, a library that exposes a function aya.runIsolated(string) that takes aya source code and produces a result.
  2. The Editor: The editor (and the rest of the demo site) is implemented in plain JS and markdown. The code lives here for now.

Even though the editor is not directly a part of this PR, it has many cool features so lets cover that first.

The Editor

Features

You can write and run aya code directly in your browser. The editor is based off of CodeMirror and has a bunch of cool features already such as

Syntax highlighting & standard library support:

Screenshot from 2024-11-05 22-25-34

Documentation on hover:

Screenshot from 2024-11-05 22-30-56

Linting:

Screenshot from 2024-11-05 22-26-59

Dark Mode:

Screenshot from 2024-11-05 22-27-27

Editor Details

The editor is implemented as a react component using CodeMirror. For the demo, the editor is embedded in a docusaurus project.

Aya Runtime (This PR)

The aya runtime is a custom aya library built using TeaVM. The aya.js runtime is relatively lightweight and loads quickly. However, execution is pretty slow if you are doing anything serious and I have already run into a few bugs (see below).

What works in the JS runtime:

What does not work yet:

Virtual IO and Filesystem

In order to build this runtime, I had to remove any system, I/O, or filesystem dependencies from the build. My solution was to create an abstract class for filesystem and I/O operations. The standard desktop implementation uses an implementation that exposes the standard file and IO functions. The web version uses an implementation that creates a virtual filesystem and I/O. Full disclosure: this solution is a messy hack at the moment and needs to be cleaned up and thoroughly tested before merging.

The other benefit of using a virtual filesystem is that we can expose library functions to allow JavaScript to create and read files. Currently aya.js exposes a function addFile that takes a path and a string and creates a file available to aya. This is how the standard library is loaded.

To load the standard library, there is an aya script that reads all standard library files and writes them to a JSON object (aya-stdlib.js). The JSON object is read in by the JavaScript host which calls aya.addFile on each item.

Maven

Warning: This uses an old version of #106 and also need to be cleaned up. I was just focued on getting anything working for the first pass. I configured maven to build the JS runtime separate from the desktop runtime using build profiles. Use the following to build the JS version:

mvn install -Pweb

Known Bugs

Overall, I'm pretty happy with how well everything works. There are some strange new bugs with TeaVM that break some of the examples though:

This should throw an index error but returns NaN:

aya(JS)> [1 2 3].[100]
NaN

aya(Java)> [1 2 3].[100]  
Invalid index 100 for list [ 1 2 3 ]

Runtime exception with J

aya(JS)> [ 1 ] [ ] J
java.lang.RuntimeException: (JavaScript) TypeError: c is undefined

aya(Java)> [ 1 ] [ ] J
[ 1 ]

Runtime exception using .= on strings

aya(JS)> [1 2 3] [3 2 3] .=
[ 0 1 1 ] .# OK

aya(JS)> "abc" "dbc" .=  
java.lang.RuntimeException: (JavaScript) TypeError: c.jF is not a function

aya(Java)> "abc" "dbc" .=  
[ 0 1 1 ]

TODO