68 lines
3.3 KiB
Markdown
68 lines
3.3 KiB
Markdown
# ODEN: A small TypeScript coding environment
|
|
|
|
This is just a silly little project which connects a JS interpreter with WebGL and init/update/draw loop in Rust.
|
|
You can think about this maybe like Pico-8 except not constrained, or LÖVE but with JS instead of lua.
|
|
|
|
## Why?
|
|
|
|
1. I want types and type hints and type checking for my little scripts, they're useful.
|
|
Lua doesn't have an equivalent of what TypeScript has, except maybe LUAU but that's incompatible with LÖVE, so what would the point be?
|
|
|
|
2. I want WebGL because I would like to be able to (easily) run things in multiple places.
|
|
I like that you can play Pico-8 games on the web.
|
|
Seems like it would be nice to make that work too.
|
|
|
|
## Why not?
|
|
|
|
1. No operator overloading in TypeScript.
|
|
I'm going to get irritated by this quickly I think.
|
|
QuickJS actually supports operator overloading but TypeScript doesn't and patching operator overloading into the type-checker looks very difficult.
|
|
|
|
## Details
|
|
|
|
### JavaScript
|
|
|
|
I'm using QuickJS, lightly patched, with my own bindings.
|
|
|
|
#### QuickJS
|
|
|
|
The easy alternative to QuickJS is to use Deno Core, which binds V8.
|
|
Unfortunately, Deno Core has kind of a wild architecture, where it goes through flatbuf for all its communications, and keeps the JavaScript engine at arm's length.
|
|
It doesn't expose things like "make a new native class."
|
|
And while it feels "possible" to use (see https://deno.com/blog/roll-your-own-javascript-runtime-pt2), it was not quite as easy to use for what I wanted to do as you might like.
|
|
|
|
QuickJS may be more or less abandoned by Fabrice Bellard, but also it does what I need it to.
|
|
|
|
(But it makes me sad: there are millions of dollars and uncountable engineering-hours in V8.
|
|
V8 is one of the best dynamic language runtimes ever constructed by man.
|
|
It would be really nice to be able to take advantage of it.)
|
|
|
|
#### Lightly Patched
|
|
|
|
See above about being abandoned: we have small patches in place to e.g. expose information about modules and whatnot.
|
|
|
|
#### My Own Bindings
|
|
|
|
The other bindings are maddeningly incomplete, and don't expose features I want to expose out of QuickJS.
|
|
|
|
### TypeScript
|
|
|
|
I'm using `deno_ast` to parse typescript at load time and "transpile" to javascript before loading.
|
|
`deno_ast` is built on swc, which I really really don't like very much, but my other options are:
|
|
|
|
1. Actually use the typescript compiler.
|
|
This is a neat idea but involves loading the compiler into QuickJS (which requires some patches to tsc since qjs is not node).
|
|
Also the typescript compiler is SLOW (especially when run in QJS) and finicky.
|
|
But this would be a full-fidelity option for sure.
|
|
|
|
2. Use tree-sitter to parse the typescript and strip the types out myself.
|
|
The tree-sitter parser is fast and gives me everything with full fidelity.
|
|
This *also* has the nice side-effect of letting me edit the source file in place, so source maps aren't a problem.
|
|
The downside is that finding every part of TS that has to be cut out to make JS is time consuming and error prone and I don't want to do it, particularly.
|
|
|
|
3. Parse Typescript myself.
|
|
I can write a parser, sure, doesn't bother me, but the syntax for typescript is not formally documented anywhere.
|
|
And it has the same problem as #2 when it comes time to emit JS.
|
|
|
|
So for now, I stick with `deno_ast`.
|
|
It does what I need it to do.
|