Commit graph

432 commits

Author SHA1 Message Date
joeduffy 2849a3e64b Print descriptions as header comments 2017-01-16 14:45:32 -08:00
joeduffy 2adb334e6a Fix a bogus decoding case
The ObjectLiteral case should obviously call the decodeObjectLiteral
function, and not decodeArrayLiteral.
2017-01-16 12:27:30 -08:00
joeduffy 57d5538ec1 Fix IfStatement json metadata
The node name is "condition", not "expression".
2017-01-16 12:27:04 -08:00
joeduffy f226392051 Fix a bug with reexport-all
The prior code wasn't extracting the member part of the token name
when reexporting symbols, meaning the member was fully qualified.  For
example, when reexporting a class "C" from another module "other",
the resulting name was "other:C".  This is correct for the export node's
token -- so it can be resolved correctly to its source -- however,
clearly the identifier for the export should not contain the module
part.  This change strips it in the appropriate place.
2017-01-16 12:15:02 -08:00
joeduffy ae8284e86e Wrap variable initializers in an ExpressionStatement
The compiler was emitting incorrect variable initialization code,
resulting in a "=" BinaryOperatorExpression in a Statement position.
This fix wraps it in an ExpressionStatement so it results in valid IL.
2017-01-16 12:07:50 -08:00
joeduffy a2d847f1ef Use stable map enumeration
This change uses stable map enumeration so that output doesn't
change randomly based on hashing.
2017-01-16 12:02:33 -08:00
joeduffy b4a6c94a1b Print modifiers for class methods 2017-01-16 11:51:20 -08:00
joeduffy 2ee3671c36 Progress on the mu describe command
This change makes considerable progress on the `mu describe` command;
the only thing remaining to be implemented now is full IL printing.  It
now prints the full package/module structure.

For example, to print the set of exports from our scenarios/point test:

    $ mujs tools/mujs/tests/output/scenarios/point/ | mu describe - -e
    package "scenarios/point" {
	    dependencies []
	    module "index" {
		    class "Point" [public] {
			    method "add": (other: any): any
			    property "x" [public, readonly]: number
			    property "y" [public, readonly]: number
			    method ".ctor": (x: number, y: number): any
		    }
	    }
    }

This is just a pretty-printed, but is coming in handy with debugging.
2017-01-16 11:47:21 -08:00
joeduffy 3b0184cec3 Add a missing JSON annotation
The NewExpression AST node type was missing a JSON annotation on
its Type field, leading to decoding errors.

Now, with this, the full suite of MuJS test cases can be unmarshaled
into fully populated MuPack and MuIL structures.
2017-01-16 10:04:25 -08:00
joeduffy 908522aa0f Fix a problem with identifiers as expressions
MuIL doesn't support identifiers as expressions; instead, an explicit
LoadLocationExpression is required.  There was a problem in the current
MuJS translation process -- masked by TypeScript silently duck typing
from Identifier to Expression -- but our Mu decoding library discovered
it.  This fixes the problem by wrapping Identifiers used in Expression
positions in a proper LoadLocationExpression node.
2017-01-16 10:01:11 -08:00
joeduffy 96c7f4fa52 Mark some AST members as optional 2017-01-16 10:00:40 -08:00
joeduffy 1948380eb2 Add custom decoders to eliminate boilerplate
This change overhauls the approach to custom decoding.  Instead of decoding
the parts of the struct that are "trivial" in one pass, and then patching up
the structure afterwards with custom decoding, the decoder itself understands
the notion of custom decoder functions.

First, the general purpose logic has moved out of pkg/pack/encoding and into
a new package, pkg/util/mapper.  Most functions are now members of a new top-
level type, Mapper, which may be initialized with custom decoders.  This
is a map from target type to a function that can decode objects into it.

Second, the AST-specific decoding logic is rewritten to use it.  All AST nodes
are now supported, including definitions, statements, and expressions.  The
overall approach here is to simply define a custom decoder for any interface
type that will occur in a node field position.  The mapper, upon encountering
such a type, will consult the custom decoder map; if a decoder is found, it
will be used, otherwise an error results.  This decoder then needs to switch
on the type discriminated kind field that is present in the metadata, creating
a concrete struct of the right type, and then converting it to the desired
interface type.  Note that, subtly, interface types used only for "marker"
purposes don't require any custom decoding, because they do not appear in
field positions and therefore won't be encountered during the decoding process.
2017-01-16 09:41:26 -08:00
joeduffy 9939024ccd Begin decoding statements 2017-01-16 07:47:41 -08:00
joeduffy 3ef55ac6b3 Add AST type assertions and kind constants 2017-01-16 07:47:12 -08:00
joeduffy 99f60bf5c8 Clean up some decoding logic
This change splits up the decoding logic into multiple files, to
mirror the AST package structure that the functions correspond to.

Additionally, there is now less "loose" reflection and dynamic lookup
code scattered throughout; it is now consolidated into the decoder,
with a set of "generic" functions like `fieldObject`, `asString`, etc.
2017-01-16 06:46:56 -08:00
joeduffy fee6d94e1f Implement class member decoding
This change implements custom class member decoding.  As with module methods,
the function body AST nodes remain nil, as custom AST decoding isn't yet done.
2017-01-16 06:10:24 -08:00
joeduffy 14c040bc7f Implement custom decoding of ModuleMembers
This change begins to implement some of the AST custom decoding, beneath
the Package's Module map.  In particular, we now unmarshal "one level"
beyond this, populating each Module's ModuleMember map.  This includes
Classes, Exports, ModuleProperties, and ModuleMethods.  The Class AST's
Members have been marked "custom", in addition to Block's Statements,
because they required kind-directed decoding.  But Exports and
ModuleProperties can be decoded entirely using the tag-directed decoding
scheme.  Up next, custom decoding of ClassMembers.  At that point, all
definition-level decoding will be done, leaving MuIL's ASTs.
2017-01-15 14:57:42 -08:00
joeduffy 5f33292496 Move assertion/failure functions
This change just moves the assertion/failure functions from the pkg/util
package to pkg/util/contract, so things read a bit nicer (i.e.,
`contract.Assert(x)` versus `util.Assert(x)`).
2017-01-15 14:26:48 -08:00
joeduffy f0b9f157de Add tests for decoding more complex nested structures
This adds deeper nesting into our tests, plus a few more examples of
pointer-based data structures inside of those deeply nested structures.
2017-01-15 13:50:00 -08:00
joeduffy 1ad99bcea1 Fix a few AST marshaling things
This fixes a few things so that MuPackages now unmarshal:

* Mark Module.Members as requiring "custom" decoding.  This is required
  because that's the first point in the tree that leverages polymorphism.
  Everything "above" this unmarshals just fine (e.g., package+modules).

* As such, stop marking Package.Modules as "custom".

* Add the Kind field to the Node.  Although we won't use this for type
  discrimination in the same way, since Go gives us RTTI on the structs,
  it is required for unmarshaling (to avoid "unrecognized fields" errors)
  and it's probably handy to have around for logging, messages, etc.

* Mark Position.Line and Column with "json" annotations so that they
  unmarshal correctly.
2017-01-14 11:22:54 -08:00
joeduffy f90679a717 Also print module names from describe 2017-01-14 11:22:26 -08:00
joeduffy bd32867e81 Adjust pointers
This change adjusts pointers correctly when unmarshaling into target
pointer types.  This handles arrays and maps of pointer elements, in
addition to consolidating existing logic for marshaling into a
destination top-level pointer as well.
2017-01-14 11:21:27 -08:00
joeduffy d1188ed8c8 Add recursive struct unmarshaling 2017-01-14 10:06:55 -08:00
joeduffy c0c75d0f08 Split decoder logic out from MuPack-specific decode functions 2017-01-14 09:50:25 -08:00
joeduffy ab2d0ae6cb Implement tag-directed decoding
This change eliminates boilerplate decoding logic in all the different
data structures, and instead uses a new tag-directed decoding scheme.
This works a lot like the JSON deserializers, in that it recognizes the
`json:"name"` tags, except that we permit annotation of fields that
require custom deserialization, as `json:"name,custom"`.  The existing
`json:"name,omitempty"` tag is recognized for optional fields.
2017-01-14 09:42:05 -08:00
joeduffy 120f139812 Decode dependencies metadata 2017-01-14 07:58:21 -08:00
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