Commit graph

406 commits

Author SHA1 Message Date
joeduffy d334ea322b Add custom decoding for MuPack metadata
This adds basic custom decoding for the MuPack metadata section of
the incoming JSON/YAML.  Because of the type discriminated union nature
of the incoming payload, we cannot rely on the simple built-in JSON/YAML
unmarshaling behavior.  Note that for the metadata section -- what is
in this checkin -- we could have, but the IL AST nodes are problematic.
(To know what kind of structure to creat requires inspecting the "kind"
field of the IL.)  We will use a reflection-driven walk of the target
structure plus a weakly typed deserialized map[string]interface{}, as
is fairly customary in Go for scenarios like this (though good libaries
seem to be lacking in this area...).
2017-01-14 07:40:13 -08:00
joeduffy cc16e85266 Add the scaffolding for a new mu describe command
This command will simply pretty-print the contents of a MuPackage.
My plan is to use it for my own development and debugging purposes,
however, I suspect it will be generally useful (since MuIL can be
quite verbose).  Again, just scaffolding, but I'll flesh it out
incrementally as more of the goo in here starts working...
2017-01-13 15:00:20 -08:00
joeduffy e7dbfa59c3 Create MuPack and MuIL packages in our Go toolset
This change carries over all of the metadata shapes in the MuPack
and MuIL file formats to our Go toolset.  This includes creating a
proper discriminated AST type tree along with correct annotations
so that the metadata will serialize and deserialize correctly.
2017-01-13 14:32:10 -08:00
joeduffy 517f0c9197 Add an | undefined to make this clearer
(I wish TypeScript required this.)
2017-01-13 12:17:44 -08:00
joeduffy b6e65ddcea Mimic TypeScript's logic for export modules
This depends on an internal API, and so has been tagged with
marapongo/mu#52.
2017-01-13 12:07:45 -08:00
joeduffy 179796d26f Use the same "heuristic" as TypeScript for public modules 2017-01-13 11:15:15 -08:00
joeduffy 2db55b5df2 Do a bit of house-cleaning 2017-01-13 10:42:50 -08:00
joeduffy 3c8990f720 Add basic type mapping
This change adds basic type mapping using bound node information for the
primitive types (string, number, bool, void, any).
2017-01-13 08:23:22 -08:00
joeduffy 048557ca79 Delimit package/module names from members
This change removes some ambiguity that existed in MuIL tokens given the
simplistic naming scheme of only using "/" as a delimiter.  We could have
resolved this ambiguity through successive name bindings, but I prefer a
more deterministic approach.  A module member token now delimits the
package/module name from the member name by a ":" character, as in
"aws/ec2:VM".  Furthermore, when reexporting elements from the current
package/module, we will use the self-referential "." character, as in
".:VM".
2017-01-13 07:44:51 -08:00
joeduffy 2097ab2f19 Skip EmptyStatements in module initializers
This change skips emitting EmptyStatements into module initializers.
This serves no purpose and can in fact lead to us creating module
initializers that are nothing but a set of EmptyStatements, slowing
down initialization of them with no purpose.
2017-01-13 07:22:38 -08:00
joeduffy 8b1a814d17 Bind all module export clauses
This completes support for module imports and exports.

Many forms of exports are supported, and are all now tested, for example:

    // Export individual declarations as we go:
    export class C {}
    export interface I {}
    export let x = 42;

    // Export individual declarations explicitly:
    class D {}
    interface J {}
    let w = 42;
    export {D, J, w};

    // Rename exports:
    export {D as E, J as K, w as x};

    // Re-export members from other modules:
    export {A, B, c} from "other";

    // Rename re-exports:
    export {A as M, B as N, c as o} from "other";

    // Re-export entire module as a submodule:
    import * as other from "other";
    export {other};
2017-01-13 07:08:49 -08:00
joeduffy b13ad61d89 Implement reexport renames
This implements renaming exports during reexporting, by recognizing the
propertyName Identifier and using it accordingly in the member map and
corresponding ast.Export object.  There is also a new test for this.
2017-01-13 05:49:02 -08:00
joeduffy 6804681940 Mark reexports as definitions
This fixes a bug where we didn't consider reexports (ast.Export nodes)
definitions, and thus stuck them into the statements section of a module
initializer rather than the definitions section.

It also adds test cases for reexporting, both `export {a,b,c} from "module"`
and `export * from "module"` kinds.
2017-01-13 05:38:52 -08:00
joeduffy 7247fcbb56 Add real module resolution
This change adds true understanding and dependency resolution for
modules.  This requires consulting the bound node tree and TypeChecker
object associated with the TypeScript program AST.  This introduces a
so-called ModuleReference, which is just a wrapper around a TypeScript
import string, enabling us to continuously look up information about
a module's symbol (from the SourceFile map).  It only lowers to a MuIL
ModuleToken for serialization at which point all information required
to load that dependency is expected to have been pre-arranged according
to our package manager resolution process (see deps.md).

As part of this, we can implement the `export * from "module"` export
form.

This is a huge step forward for marapongo/mu#46.
2017-01-12 20:51:29 -08:00
joeduffy 9df12235a6 Add a MuIL export node; transform simple re-exports
This change first and foremost adds a MuIL export node (ast.Export);
this is for re-exporting members of other modules, potentially under
a different name.

This works by simply by associating a name with a fully qualified token
name that, when binding, can be re-resolved to the real target.  This
should be sufficient for expressing everything we need from MuJS.

In addition to that, there is an initial cut at basic re-exports; this
is the form where you would say:

    export { some, nifty as cool, stuff } from "module";

In this example, we end up with two Export nodes: one maps "some" to
"some/module", "cool" to "some/nifty", and "stuff" to "some/stuff".

Note that we have not yet implemented two other variants.

First, we will want to support the "export all" variety, e.g.

    export * from "module";

Instead of supporting wildcards in MuIL -- which would result in the
odd attribute that you couldn't know the totality of a module's exports
without also examining its dependencies (possibly recursively) -- we
will require the compiler to map the "*" to a concrete list of Export nodes.

Second, we also want to support named exports from the current module.
That is to say, export clauses without `from "module"` parts.  E.g.

    let some = ...;
    let nifty = ...;
    let stuff = ...;
    export { some, nifty as cool, stuff };

This is less important because you can always export members using the
more familiar `export <decl>` syntax (which is already recognized by MuJS).
But of course, we will want to support it eventually.  It is slightly more
complex, because we will need to use static typing to resolve the exported
members to their types -- e.g., variable, class, interface -- and in fact
this could lead us to re-exporting whole modules in their entirety.

Both of these two will require marapongo/mu#46.  Since so much is piling up
behind this, I will likely begin biting this off soon.  I also believe that
we may want re-export nodes, Export, to carry a specifier that indicates whether
the target is a class, variable, or sub-module.
2017-01-12 15:51:49 -08:00
joeduffy 49d0c2613a Transform the delete operator
This change does a rudimentary mapping of the delete operator.  I say
"rudimentary" because it's not entirely correct, ECMAScript-wise: delete
actually removes a property entirely from an object, whereas this change
simply transforms `delete <expr>` into `<expr> = null`.  Deciding what to
do with `delete` will be handled when we tackle the overall "unsupported
operators" bug, marapongo/mu#50, later on.  For `delete` specifically,
it's not clear we will want to allow deletion of properties on strongly
typed instances, however for untyped objects we can probably do this, and
then detect errors when downcasting to types requiring those properties.
2017-01-12 15:06:50 -08:00
joeduffy 5374a2e3fa Add a example web crawler Mu blueprint
This adds an example web crawler blueprinted, derived from the AOSA
book's asynchronous I/O coroutines example.
2017-01-12 14:59:18 -08:00
joeduffy bb009cab7e Use a notYetImplemented helper function
This rearranges the various "NYI" spots in the code to defer to a
notYetImplemented helper function.  This ensures we have decent
diagnostics associated with failures, like source line numbers.
2017-01-12 14:58:14 -08:00
joeduffy a1b0dff4ab Add a log message about unsupported operators
This change logs a message for unsupported operators, until marapongo/mu#50
can be implemented.  During debugging, this might come in handy some day.
2017-01-12 13:44:54 -08:00
joeduffy 24c4f48b81 Transform object literal expressions 2017-01-12 13:38:54 -08:00
joeduffy 1572816861 Map array literals 2017-01-12 13:00:40 -08:00
joeduffy 454fd07802 Map ===, !==, >>>, and >>>= operators
This change maps the ECMAScript operators ===, !==, >>>, and >>>= to
the MuIL operators ==, !=, >>, and >>=, respectively.  This isn't
entirely correct, however, we will most likely emulate these using
runtime helpers down the line; marapongo/mu#50 tracks this issue.
2017-01-12 12:53:33 -08:00
joeduffy c28cd6305e Map type aliases
TypeScript type aliases simply turn into MuIL classes with the base
class being the aliased type.  In theory, MuIL conversions will support
the kind of conversions offered by aliases (or at least get sufficiently
close).  We will need to tackle this in part by marapongo/mu#46.

In addition, while I was in there, I cleaned up the type token emission
to emit "any" (rather than "TODO") and to use a single, central function
for all ts.TypeNodes.  This will also get cleaned up by marapongo/mu#46.
2017-01-12 12:46:36 -08:00
joeduffy 3c76092d46 Discard import declarations
At the moment, we do not emit bound node information yet.  (See
marapongo/mu#46).  When that day comes we will need to decide whether
import declarations are needed or, as I suspect, they can continue to
be discarded safely because all dependency information is available
on the bound nodes themselves.  I'm leaving in a TODO in there just as
a reminder to resolve this at that time.
2017-01-12 12:21:17 -08:00
joeduffy c3027f6822 Map MuJS interface types to MuIL
This change maps MuJS interface types to MuIL, including property and
method declarations.  The mapping is fairly straightforward, and similar
to the existing class lowering, except for some minor AST differences in
the TypeScript representations.  We emit interface types as classes with
the interface bit set, and all method declarations being abstract.
2017-01-12 12:12:29 -08:00
joeduffy 069ab369e9 Improve line-by-line error reporting in test failures
This change improves the line-by-line error reports when a test fails,
both in the diagnostics messages and AST tree baseline comparisons.
Previously, the test would fail at the first occurrence of a mismatch,
often with little information about the context.  In this change, the
test will now fail with a full dump of the comparison.

For instance, here is the before for a test failure in a new case I'm adding:

     AssertionError: Expected tree line #1 to match
           + expected - actual

                 -     "name": "iface_1",
                 +     "name": "class_1",

In comparison, here is what the test failure looks like now:

      AssertionError: Expected trees to match; 6 did not
      + expected - actual

      -1:     "name": "iface_1",
      -10:                 "I": {
      -14:                         "ident": "I",
      -19:                                 "column": 10
      -23:                                 "column": 11
      -29:                     "interface": true,
      +1:     "name": "class_1",
      +10:                 "C": {
      +14:                         "ident": "C",
      +19:                                 "column": 6
      +23:                                 "column": 7
      +29:                     "abstract": false,
2017-01-12 12:06:15 -08:00
joeduffy 3f81e2f15f Add proper errors for Mufile validation 2017-01-12 08:10:43 -08:00
joeduffy a93841dab2 Add real diagnostics
This change adds a set of true diagnostics constructs, underneath the
new `diag` module.

This includes projecting Mu-specific errors as real diagnostics in a
way that is unified with TypeScript errors.  The only difference, of
course, is that Mu errors tend to happen in later passes.  But this is
not necessarily always the case.

As part of this, I've rearranged the compiler passes to present a
simpler interface to users of the compiler API (currently just the CLI
and test harness, but it's just a library, so anybody can use it).

Namely, there are three phases:

    1. Compilation is the overall process of taking an input path
       and driving the entire compilation process, yielding a set of
       diagnostics and, ideally, a final MuPackage at the end of it.

    2. Script compilation is the process of driving the front-end
       compiler -- in this case TypeScript -- yielding a set of Mu
       diagnostics and, if that went well, the script's AST.

    3. Transformation is the process of taking the script output and
       lowering it into the final MuPackage form.

Most people will deal with 1, blissfully unaware of the presence of
independent 2 and 3 phases.  We choose to keep them distinct for
white box testing and for future scenarios we have yet to envision.
2017-01-11 12:11:46 -08:00
joeduffy b3247a37cd Ensure locations are propagated everywhere
There were a few places where we didn't propagage source locations
correctly.  This fixes that.  Part of the issue was we didn't have
good helper methods to propagate "ranges" (e.g., a sequence of
statements or expressions), so this change adds those.

This change also establishes a new naming convention; the addLocation*
methods adds a newly allocated location based on translating a TypeScript
AST node, whereas the copyLocation* methods copy them directly from
other MuIL nodes.  Thus, there are now four methods: addLocation,
addLocationRange, copyLocation, and copyLocationRange.
2017-01-11 08:31:03 -08:00
joeduffy 6c3826659c Map call expressions 2017-01-11 08:17:13 -08:00
joeduffy 2d5ec61aeb Map new expressions
This change adds a new AST node kind to represent "new" expressions.
Originally I had thought we could simply represent these as calls to
a constructor, however, there is a sizeable semantic difference and so
it's better for this node kind to be distinct; for example, we will
most likely permit allocation of objects without explicit constructors.

In addition, I've added a "complex" scenario test, which is just a
Point class.  It has a constructor, two properties, and an instance
method that performs arithmetic and allocates a new instance.  It works!
2017-01-11 08:06:11 -08:00
joeduffy 00e0c00ac9 Fix "this" capture in callbacks 2017-01-11 07:50:31 -08:00
joeduffy c964a0fa8d Use explicit type coercions
This uses explicit type coercions when creating interface types with
object literals.  This helps the compiler catch some additional errors,
such as mistyped property names (of which we had two instances, for
load location expressions ("key" vs "name")).
2017-01-11 07:43:00 -08:00
joeduffy 86a67869af Map property access expressions 2017-01-11 07:38:51 -08:00
joeduffy f413b1d2db Add basic class property mapping 2017-01-11 07:25:22 -08:00
joeduffy dbce1d5170 Rearrange some VariableLike and FunctionLike code sharing
The old way we shared code between VariableLike and FunctionLike cases --
across module, class, and locals -- was slightly confusing, and required a
lot of dynamic object property copying, etc.  This change is a little bit
easier on the eyes, correctly handles variable initializers more uniformly,
and prepares us for class properties (the next change to land).
2017-01-11 07:16:56 -08:00
joeduffy 7db6f12d6f Translate member access expressions
This change maps MuJS access expressions to the MuPack/MuIL forms.

As part of this, I've changed the representation in the AST.  It doesn't
make much sense to distinguish between variable, member, and function access.
Instead, all accesses will be uniform, and will evaluate to the proper type.
2017-01-10 16:39:50 -08:00
joeduffy 82657c7cdb Add basic class lowering
This change introduces basic class lowering into MuPack/MuIL.  There are
a handful of things not yet supported (like extends/implements and properties),
however, simple methods and variables are supported.
2017-01-10 16:13:28 -08:00
joeduffy fc1899e1ee Translate and lower function definitions
This change introduces lowering for function definitions and parameters.
This includes a few tests for both exported and unexported module-level
function definitions.  Class members will come shortly...
2017-01-10 15:29:14 -08:00
joeduffy 780d3d31b1 Emit accessibility in module properties
This change properly retains and emits the desired accessibility for
module properties, based on whether a property has been exported or not.
It also updates the existing export property test baseline and adds
another one for unexported module properties.
2017-01-10 14:41:52 -08:00
joeduffy 3c1fdf6d88 Use relative paths in AST source location
This change uses paths relative to the compilation root context path,
so that they aren't absolute and therefore aren't tied to a specific
machine.  This fixes marapongo/mu#42, and cleans up our test baselines.
2017-01-10 14:34:46 -08:00
joeduffy 35fce68e37 Refactor transformation into a class
The transformation now needs some context information throughout its
execution, so it makes sense to turn it into a class.
2017-01-10 14:27:26 -08:00
joeduffy aa51bda2d0 Shorten module names
Per marapongo/mu#42, this change shortens module names to be more "Mu-like"
and to reflect the relative module paths.  There is still awkwardness if there
are any "up and over" references, i.e. using "..", but this handles the 95%
case.  We still don't mark entrypoints, but this gets us one step closer.
2017-01-10 13:55:07 -08:00
joeduffy 4ed118e8fa Add basic Mu metadata parsing support
This change adds discovery of Mu metadata in the form of a Mu.json file.
This allows us to eliminate the "TODO" in place of a real package name in
the output ASTs, so our baselines are adjusted accordingly.  This is part
of marapongo/mu#42 -- implementation of real module and package names.
2017-01-10 12:42:42 -08:00
joeduffy 57e8a6aa67 Do a line-by-line comparison for AST checking
This changes the test harness to do a line-by-line comparison, rather than
full text comparison, for AST checking.  This is a bit nicer to diagnose, because
failures will specifically point out the line that deviates, rather than dumping
the (possibly huge) string containing the full expected/actual ASTs.
2017-01-10 12:40:59 -08:00
joeduffy f2f6826f5b Add a test for exporting a module property 2017-01-10 08:20:01 -08:00
joeduffy 7017828ae5 Add a baseline for the empty test
This adds a baseline for the empty module test, and it passes.
Unfortunately, because module names are absolute file paths, this
baseline file has my machine's specific path embedded in it.  I want
to lock these in so they are passing as I make progress.  Sometime
later this morning I'll fix the module naming to be "relative" and
more Mu-friendly, and this issue will go away.
2017-01-10 08:15:34 -08:00
joeduffy a2b02381fc Use the module's fileName as its name
For now we will use the module's fileName as its name.  This matches
the ECMAScript semantics, however, we will eventually want to do a pass
to normalize these names into more "Mu-friendly" module names.
2017-01-10 08:14:02 -08:00
joeduffy 641fb5bd21 Fix a few TSLint errors 2017-01-10 08:13:39 -08:00
joeduffy 27eef9903b Use JSON object maps instead of ES6 Maps
This change uses JSON object maps in the AST, rather than ES6 Maps,
so that the resulting data structure is easily serializable.
2017-01-10 07:57:22 -08:00