Commit graph

881 commits

Author SHA1 Message Date
joeduffy 3a04e7e72b Adjust this on PropertyValues too 2017-02-16 16:59:11 -08:00
joeduffy 394bec544a Adjust prototype pointers; bind super correctly
This change fixes two aspects of binding names to objects.  First, we need
to adjust pointers from prototype functions, since they will have the wrong
"this" (it points to the prototype instance and not the actual object).
Second, we need to bind `super` accesses using the correct prototype object.
2017-02-16 15:55:28 -08:00
joeduffy 110ecdc734 Emit Tokens in Symbol Stringer.String functions
It's generally more useful to have the fully qualified symbol token in logs,
error messages, etc.  So this is a better default than name.
2017-02-16 15:53:55 -08:00
joeduffy 6db3d0b687 Install AWS to its proper directory 2017-02-16 08:26:09 -08:00
joeduffy 092fe384c8 Fix intrinsic token 2017-02-16 08:23:04 -08:00
joeduffy 231d697181 Flip the order of comparison for static cast checking 2017-02-16 07:38:10 -08:00
joeduffy 79569b9044 Rename serialized name from "alternative" to "alternate" 2017-02-16 07:37:40 -08:00
joeduffy af45bfd53f Fix up a few things
* Improve some logging and assertions.

* Initialize the prototype map (it was always empty before).

* Actually memoize the prototype objects in this map.

* During class initialization, ensure the base class is also initialized.

* Trigger class initialization anytime a property or function is loaded
  from that class.  Similarly, trigger module initialization on loads too.

* Treat For/ForIn/ForOfStatements as legal parents for local variables.
  This ensures for loops at the top-level in a module have their variables
  treated as locals, rather than module properties.  Add a test also.

* Track source locations for more nodes.

* Mark auto-generated constructors as public so that they may be called.

* Fix the naming of class init methods; it should be ".init", not ".ctor".

* Clone the loop test cases into both function and module top-level variants.
2017-02-16 06:48:39 -08:00
joeduffy c6f77ae3d6 Implement for loops
This change introduces a for loop node to the AST, for much the same
reasons we elevated switch nodes to the AST, and lowers MuJS for loops.
2017-02-16 05:38:01 -08:00
joeduffy 563fad29ec Add 1st class switch support
One guiding principle for what makes it into the MuIL AST is that
the gap between source language and AST should not be too great; the
projection of switch statements from MuJS into MuIL clearly violated
that principle, particularly considering that the logic wasn't even
right due to the incorrect emulation of conditional breaks.

Instead of digging deeper into the hole, I've encoded switch logic
in the AST, and implemented support in the evaluator.
2017-02-16 04:58:04 -08:00
joeduffy 6dcdf9e884 Fix a few flubs
* Add a TODO as a reminder to implement number toString formatting.

* Change the Loreley delimiters to something obscure ("<{%" and "%}>")
  to avoid conflicting with actual characters we might use in messages.
  Also, make the assertions more descriptive should Loreley fail.

* Rip out a debug.PrintStack() in verbose logging.

* Check the underlying pointer's object type for +=, not the pointer type.
2017-02-16 04:15:07 -08:00
joeduffy b16590d6c3 Implement some ECMAScript runtime helpers
This change implements some key ECMAScript runtime helpers, straight from
the specification: https://tc39.github.io/ecma262/.  The goal here is to get
a runtime intrinsic for ECMAScript-style toString to work.
2017-02-15 20:09:03 -08:00
joeduffy 84c3f0f9bc Support string concatenation with += operator 2017-02-15 18:51:37 -08:00
joeduffy 71a22509d7 Only bind non-nil function types 2017-02-15 18:44:30 -08:00
joeduffy a6aa17e2b7 Make variable types required
This change requires variable types in the MuIL.  It is up to the MetaMu
compiler to pick a default if it so chooses (object, dynamic, etc.)
2017-02-15 18:42:24 -08:00
joeduffy 20d9c3e9ca Add verbose AST walk tracing 2017-02-15 18:28:13 -08:00
joeduffy 64554621cf Implement switch statements 2017-02-15 18:19:24 -08:00
joeduffy 2af011d6ab Implement TypeOf expressions 2017-02-15 15:58:46 -08:00
joeduffy bd8faf313f Implement parenthesized expressions 2017-02-15 15:52:56 -08:00
joeduffy af983183d9 Fix a couple asserts
These asserts need to use Object.hasOwnProperty, rather than simply
looking up the property; otherwise, if we have a function whose name
happens to match a built-in ECMAScript property name -- like
toString -- then the assert will fire!
2017-02-15 15:47:20 -08:00
joeduffy 2898747db4 Implement intrinsic function machinery
This change implements intrinsic function support in the runtime.

The basic idea is to swap out references to MuIL functions with
runtime-implemented functionality, for operations that cannot be
expressed in the MuIL-subset.  For example, this change includes
two such cases: 1) a mu.runtime.isFunction(obj) function to check if
the target object is a function; and 2) a
mu.runtime.dynamicInvoke(obj,obj,obj[]) function to dynamically
invoke a target object.

These will be used most immediately to implement ECMAScript toString
functionality in the MuJS runtime library, however it will also come
in handy shortly to implement things like printf (marapongo/mu#86),
string and array functions (marapongo/mu#80), and, eventually, the
ECMAScript-specific operators and behavior (marapongo/mu#61).
2017-02-15 15:35:52 -08:00
joeduffy 42ef7914ea Look up base types during static member binding 2017-02-15 13:06:54 -08:00
joeduffy 33384d1deb Do not bind alias definitions 2017-02-15 12:57:36 -08:00
joeduffy 6719a6070a Generalize default modules
This change generalizes the support for default modules (added as
part of marapongo/mu#57), to use an "alias" table.  This is just a
table of alternative module names to the real defining module name.
The default module is now just represented as a mapping from the
special default module token, ".default", to the actual defining
module.  This generalization was necessary to support Node.js-style
alternative names for modules, like "lib" mapping to "lib/index".
2017-02-15 12:53:36 -08:00
joeduffy f22514fc74 Strengthen the super test
This change adds runtime verification of the super test's expected
behavior.  This has proven useful in testing out some of the recent
runtime/interpreter logic around super, etc.  Most likely we will
start testing all of the MuJS tests as real MuIL/etc. tests soon.
2017-02-15 12:47:20 -08:00
joeduffy 5b29215195 Implement a MuJS standard library
This change introduces a MuJS standard library.  This will allow us
to support an increasing amount of ECMAScript functionality without
needing to do it in the runtime or the compiler.

The basic idea is as follows.

In the TypeScript compiler, all uses of ECMAScript standard types and
functions get bound to the TypeScript library headers.  These headers
are in the node_modules/typescript/lib/ directory, and there is one
per ECMAScript "standard" (lib.d.ts for ECMAScript 5, lib.es2015.d.ts
for ECMAScript 6, lib.es5016.d.ts for ECMAScript 7, and so on).  Note
that these libraries are "header only", since the functionality for
these are of course supplied by whatever runtime (V8, Chakra, etc)
actually executes the resulting JavaScript code.

In our case, we have no such luxury.  So instead, we intercept these
bindings and transform them into bindings to a MuJS standard library.
This library is just a MuIL library written in MuJS code.  Only the
set of operations expressable in basic MuIL can be used to implement
these.  In select few cases, we will need runtime intrinsics, but those
will not be specific to MuJS and will go into the basic Mu library and
shared among all MetaMu compilers.

At this point, the MuJS standard library only contains the ECMAScript
Error type, so that we can represent throwing errors in MuJS/MuIL.
2017-02-15 11:57:25 -08:00
joeduffy a40db0e6a0 Permit throwing anything
Previously, I had thought we would ask MetaMu compilers to map their
own exception/error types to ours.  That causes some complexity, however,
in that the exception types in each language (if they even exist) are
"different".  So we would need to wrap things, etc., which seems cumbersome.

Partly I had done this after having been burned on the CLR by permitting
throws of any types; e.g., C++/CLI could throw integers, which would rip
through C# code unknowingly, because all C# throws had to derive from the
Exception base class.  This actually caused some security issues!

But, we're in a different place, and a different time.  The first three
languages I envision supporting -- ECMAScript, Python, and Ruby -- each
permit you to throw anything.  And the only other languages I am seriously
contemplating right now -- Go -- doesn't even have exceptions.

So this change backs off and is less opinionated about what is thrown.
Instead, we track stack traces, etc., in the unwind information, and happily
propagate whatever object is thrown.
2017-02-15 10:04:33 -08:00
joeduffy 973dfe1f22 Map class names to their prototype objects 2017-02-15 08:57:28 -08:00
joeduffy 25d626ed50 Implement prototype chaining
This change more accurately implements ECMAScript prototype chains.
This includes using the prototype chain to lookup properties when
necessary, and copying them down upon writes.

This still isn't 100% faithful -- for example, classes and
constructor functions should be represented as real objects with
the prototype link -- so that examples like those found here will
work: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor.
I've updated marapongo/mu#70 with additional details about this.

I'm sure we'll be forced to fix this as we encounter more "dynamic"
JavaScript.  (In fact, it would be interesting to start running the
pre-ES6 output of TypeScript through the compiler as test cases.)

See http://www.ecma-international.org/ecma-262/6.0/#sec-objects
for additional details on the prototype chaining semantics.
2017-02-14 16:12:01 -08:00
joeduffy 1e62872ef3 Simplify property initialization
The complexity of the last round of property initialization code was
starting to bug me.  I've switched away from lazily initializing them
and now eagerly initialize at the proper times: module initialization,
class initialization (for statics), and object allocation (for instances).
This includes the logic around readonly and freezing.  The code is a
lot simpler now and actually enforces some invariants that we'd like to
enforce, like not silently adding new properties when a supposedly static
member load is happening (all such accesses should be dynamic ones).
2017-02-14 08:40:20 -08:00
joeduffy 722e963f89 Rename tempmark to visiting and mark to visited
Better variable names, per Eric's code review feedback.
2017-02-13 14:41:20 -08:00
joeduffy b47445490b Implement a very rudimentary plan command
This simply topologically sorts the resulting MuGL graph and, in
a super lame way, prints out the resources and their properties.
2017-02-13 14:26:46 -08:00
joeduffy 7befbe151b Properly enforce readonly properties
This change accurately enforces readonly properties.  Namely, they
should not be written to anywhere outside of the respective initializer,
but writes must be allowed within them.  This means the module initializer
for module properties, the class initializer for statics, and the object
constructor for instance properties.
2017-02-13 13:29:05 -08:00
joeduffy 971fdfbf8d Fall back to dynamic on object too
We already fall back to dynamic loads when the type is `dynamic`, however
we also need to do that when it is the weakly typed `object` also.
2017-02-13 11:59:06 -08:00
joeduffy 295db4faac Push and pop class/module context during evaluation
Now that some name lookups are context-sensitive (namely, whether
or not we should use the export or member table for inter vs. intra
module token references), we need to faithfully track the context.
2017-02-13 11:58:10 -08:00
joeduffy a2653093db Make export binding more robust
This changes the way we discover the kind of export in the case of
an export declaration.  This might be exporting a module member, as in

    let x = 42;
    export { x as y };

or it could be exporting an entire module previously imported, as in

    import * as other from "other";
    export { other };

In each case, we must emit a proper fully qualified token.

Our logic for detecting these cases was a bit busted previously.  We
now rely on real symbolic information rather than doing hokey name lookups.
2017-02-13 11:37:23 -08:00
joeduffy a668db2e2c Properly chase exports
This change fixes up some issues in the big export refactoring;
namely, we need to chase down references one link at a time during
binding, before they settle.  This is because an export might depend
on another export, which might depend on ...
2017-02-13 10:54:11 -08:00
joeduffy 1568b88e4e Move Mu library files back to root
This change moves the Mu library files back to the root.  Until
marapongo/mu#57 allows us to choose a different index file, via
package.json's "main" attribute, the default module logic won't
work properly with the files underneath src/.
2017-02-13 10:02:40 -08:00
joeduffy 32960be0fb Use export tables
This change redoes the way module exports are represented.  The old
mechanism -- although laudible for its attempt at consistency -- was
wrong.  For example, consider this case:

    let v = 42;
    export { v };

The old code would silently add *two* members, both with the name "v",
one of which would be dropped since the entries in the map collided.

It would be easy enough just to detect collisions, and update the
above to mark "v" as public, when the export was encountered.  That
doesn't work either, as the following two examples demonstrate:

    let v = 42;
    export { v as w };
    let x = w; // error!

This demonstrates:

    * Exporting "v" with a different name, "w" to consumers of the
      module.  In particular, it should not be possible for module
      consumers to access the member through the name "v".

    * An inability to access the exported name "w" from within the
      module itself.  This is solely for external consumption.

Because of this, we will use an export table approach.  The exports
live alongside the members, and we are smart about when to consult
the export table, versus the member table, during name binding.
2017-02-13 09:56:25 -08:00
joeduffy a09a49b94a Regenerate test baselines w/ line numbering change 2017-02-13 07:55:40 -08:00
joeduffy b1f96964ac Implement array l-values
This commit implements array l-values (for dynamic loads only, since we do
not yet ever produce static ones).  Note that there are some ECMAScript
compliance noteworthies about this change, which are captured in comments.

Namely, we are emulating ECMAScript's ability to index into an array
anywhere (except for negative numbers, which is a problem).  This is in
contrast to the usual approach of throwing an error on out-of-bounds access,
which will crop up when we move on to other languages like Python.  And yet we
are usuing a real array as the backing store, which can cause problems with
some real ECMAScript programs that use sparse arrays and expect the "bag of
properties" approach to keep memory usage reasonable.

The work item marapongo/mu#70 tracks this among other things.
2017-02-13 07:23:00 -08:00
joeduffy 1af9cd720b Use 1-based column numbers 2017-02-13 06:44:48 -08:00
joeduffy f0181d8933 Emit more array types; permit more dynamic conversions
This change plucks array element types out of more AST nodes, tightening
up the MuIL that MuJS produces.  It also adds a few cases where we should
be emitting "object", and permits more dynamic conversions (which are
technically unsafe, but necessary for the sort of duck typing we anticipate).
2017-02-13 06:39:50 -08:00
joeduffy d82adefd38 Implement casts 2017-02-13 05:56:39 -08:00
joeduffy 55deb13100 Implement static properties in the runtime 2017-02-13 05:45:28 -08:00
joeduffy aec1dccd5d Tidy up property initializers
This change fixes a few things about property initializers:

* Instance properties on classes need an object (`this`) for initialization.
  Previously, this wasn't being passed, which leads to a verification error.

* Static properties on classes should go into the `.init` function, not the
  `.ctor` function.

* Synthesized constructors need to invoke `super()` when there is a base
  class.  It's legal for this call to be missing from the source program
  when the base's constructor has no args.

* All initializers happen immediately after such a call to `super()`, to
  achieve the intended initialization order.  Therefore, for an existing
  constructor, we must search for the insertion point manually.

* Also add a superclass case to the existing property tests.
2017-02-13 04:56:20 -08:00
joeduffy 4b05735374 Add some missing source node info 2017-02-13 04:13:22 -08:00
joeduffy de7d8c7a90 Tolerate duplicate objects
In select few cases (right now, just nulls and boolean true/false),
we use predefined object constants to avoid allocating wastefully.
In the future, it's possible we will do this for other types, like
interned strings.  So, the graph generator should tolerate this.
2017-02-13 04:00:33 -08:00
joeduffy 9d157a25c6 Issue a warning if there is no default module 2017-02-13 03:58:31 -08:00
joeduffy 2fd4355cf6 Add some array accesses to basic/arrays tests 2017-02-13 03:45:23 -08:00