This changes the way we represent identifiers slightly, and then lowers
the TypeScript representation to them. Prior to this change, identifiers
could be naked strings; after this change, identifiers are always first class
AST nodes -- so they can carry location information -- and tokens assume the
role of naked strings. This means some definition maps must now be keyed by
tokens and also means that some AST node properties that used to carry just
naked strings needed to be updated to carry first class AST nodes.
This is an initial cut at implementing variable declaration lowering.
The lowering is slightly different for module properties and local variables,
since the former requires that code go into the module initializer, while the
latter can mostly happen "inline" as the local variable is bound.
There are some incomplete parts in here -- like lowering type names -- that
are dependent on a few upcoming changes.
This change translates MuJS modules and their various top-level statements
into the corresponding MuPack/MuIL metadata. Notably, to ensure static analyzability,
MuIL doesn't permit arbitrary class, function, etc. definitions as statements. Instead,
they must occur at the top-level, and be recognized as such statically. That's the bulk
of this change. The individual nodes aren't necessarily mapped yet, however.
The way ECMAScript and Python work is that each file maps to a module. There
isn't really an "official" notion of a submodule; instead, directories on the
import path are conventionally used as submodule names. Aggregate submodules
can be achieved by convention with re-exports in ECMAScript, however this is an
informal notion. We could keep the current structured submodule notion and require
that all languages map to it, however, it is just as easy to have a flat list of
top-level modules indexed by name. This change rearranges the AST accordingly.
This adds a new test harness that will be used to run baseline-style
tests. Each subdirectory underneath tests/output will be interpreted as
a test case, each of which can contain an optional `messages.txt` file
which will be compared as the expected output against the compiler's error
and warning messages, and/or an optional `Mu.out.json` file which will be
compared as the expected output against the compiler's output tree.
There's just a single "empty" test case for now. I will start getting in
the habit of checking in a companion test for each AST kind we lower.
This adds two expressions we will need to support many type test patterns.
IsInst simply checks an expression for castability to a target type; it evaluates
to a boolean.
TypeOf fetches the runtime type of a given expression and evaluates to its name.
Right now, this is just a string token, rather than some richer RTTI object.
This is mostly boilerplate, mapping the following AST kinds: IfStatement,
ReturnStatement, ThrowStatement, Block, EmptyStatement, ExpressionStatement,
and LabeledStatement.
The stacks.md document used to describe the metadata format. Now that we've
moved away from the old model of YAML + Go templates, and created the MuPack/MuIL
format, this document needed to be overhauled.
It's pretty bare bones now, however it will eventually evolve into a document
describing how the Mu abstractions map down onto MuPack/MuIL concepts. For example,
it describes how subclassing mu.Stack creates a "stack", even though at the MuPack/MuIL
level it's just any old subclass.
Some say the world will end in fire,
Some say in ice.
From what I've tasted of desire
I hold with those who favor fire.
But if it had to perish twice,
I think I know enough of hate
To say that for destruction ice
Is also great
And would suffice.
This includes break, continue, and while, which are trivial. It also
includes do/while, which requires a simple rewrite during the lowering,
since MuIL only supports the one simple kind of loop.
This adds a few missing statement AST kinds:
* ReturnStatement to `return` from a function with an optional expression.
* ThrowStatement to `throw` an exception object.
* EmptyStatement to represent, well, a statement without anything to it.
This change refactors a few things:
* Eliminate the `mujs.il` package; instead, introduce `mujs.ast`.
* Split `mujs.ast` into many different files, to organize things a
little more cleanly into expressions, nodes, sources, and statements.
* Move most definitions from the `mujs.pack` package into `mujs.ast`,
into the definitions file. This ensures that all definitions are true
AST nodes, meaning they will preserve source location information.
This change adds a simple compiler module that hosts TypeScript and
compiles a program. The compile function takes a path and optional options
data structure; the path can be one of three things: 1) a path to a single `*.ts`
file, in which case it, and it alone, is compiled; 2) a path to a `tsconfig.json`
file, in which case it is loaded, parsed, and used to drive compilation just
like the `tsc` command line driver; or 3) a path to a directory containing a
`tsconfig.json` file, in which case it is discovered and used just like #2.
There is also a new command line driver that just blindly passes arguments to
this compiler API, and prints the results. Next up, this will begin lowering and
transforming the resulting TypeScript AST to MuPack and MuIL.
Note that I've reorganized the source code slightly, so that instead of just
`src/*`, we now have `lib/*` for the library, `cmd/*` for any CLI drivers, and,
soon, `test/*` for test cases.