Commit graph

736 commits

Author SHA1 Message Date
joeduffy 7b5f9df917 Make updates work in the face of output properties
This change fixes up a few things so that updates correctly deal
with output properties.  This involves a few things:

    1) All outputs stored on the pre snapshot need to get propagated
       to the post snapshot during planning at various points.  This
       ensures that the diffing logic doesn't need to be special cased
       everywhere, including both the Lumi and the provider sides.

    2) Names are changed to "input" properties (using a new `lumi` tag
       option, `in`).  These are properties that providers are expected
       to know nothing about, which we must treat with care during diffs.

    3) We read back properties, via Get, after doing an Update just like
       we do after performing a Create.  This ensures that if an update
       has a cascading impact on other properties, it will be detected.

    4) Inspecting a change, prior to updating, must be done using the
       computed property set instead of the real one.  This is to avoid
       mutating the resource objects ahead of actually applying a plan,
       which would be wrong and misleading.
2017-06-01 10:09:52 -07:00
joeduffy b5df277815 Fix a few merges when this branch hit master 2017-06-01 08:51:33 -07:00
joeduffy 23493be8af Classify output properties as adds too 2017-06-01 08:39:48 -07:00
joeduffy e84c2d9388 Remember output properties in snapshot records
This change remembers which properties were computed as outputs,
or even just read back as default values, during a deployment.  This
information is required in the before/after comparison in order to
perform an intelligent diff that doesn't flag, for example, the absence
of "default" values in the after image as deletions (among other things).
As I was in here, I also cleaned up the way the provider interface
works, dealing with concrete resource types, making it feel a little
richer and less like we're doing in-memory RPC.
2017-06-01 08:39:48 -07:00
joeduffy 4d63e6d672 Add a few more RawResources: trues 2017-06-01 08:39:48 -07:00
joeduffy 08ca40c6c6 Unmap properties on the receive side
This change makes progress on a few things with respect to properly
receiving properties on the engine side, coming from the provider side,
of the RPC boundary.  The issues here are twofold:

    1. Properties need to get unmapped using a JSON-tag-sensitive
       marshaler, so that they are cased properly, etc.  For that, we
       have a new mapper.Unmap function (which is ultra lame -- see
       pulumi/lumi#138).

    2. We have the reverse problem with respect to resource IDs: on
       the send side, we must translate from URNs (which the engine
       knows about) and provider IDs (which the provider knows about);
       similarly, then, on the receive side, we must translate from
       provider IDs back into URNs.

As a result of these getting fixed, we can now properly marshal the
resulting properties back into the resource object during the plan
execution, alongside propagating and memoizing its ID.
2017-06-01 08:39:48 -07:00
joeduffy 87ad371107 Only flow logging to plugins if --logflow
The change to flow logging to plugins is nice, however, it can be
annoying because all writes to stderr are interepreted on the Lumi
side as errors.  After this change, we will only flow if
--logflow is passed, e.g. as in

    $ lumi --logtostderr --logflow -v=9 deploy ...
2017-06-01 08:37:56 -07:00
joeduffy 0a72d5360a Modify provider creates; use get for outs
This change modifies the existing resource provider RPC interface slightly.
Instead of the Create API returning the bag of output properties, we will
rely on the Get API to do so.  As a result, this change takes an initial
whack at implementing Get on all existing AWS resources.  The Get API needs
to return a fully populated structure containing all inputs and outputs.

Believe it or not, this is actually part of pulumi/lumi#90.

This was done because just returning output properties is insufficient.
Any input properties that weren't supplied may have default values, for
example, and it is wholly reasonable to expect Lumi scripts to depend on
those values in addition to output values.

This isn't fully functional in its current form, because doing this
change turned up many other related changes required to enable output
properties.  For instance, at the moment resource properties are defined
in terms of `resource.URN`s, and yet unfortunately the provider side
knows nothing of URNs (instead preferring to deal in `resource.ID`s).
I am going to handle that in a subsequent isolated change, since it will
have far-reaching implications beyond just modifying create and get.
2017-06-01 08:36:43 -07:00
joeduffy 7f98387820 Distinguish between computed and output properties
This change introduces the notion of a computed versus an output
property on resources.  Technically, output is a subset of computed,
however it is a special kind that we want to treat differently during
the evaluation of a deployment plan.  Specifically:

* An output property is any property that is populated by the resource
  provider, not code running in the Lumi type system.  Because these
  values aren't available during planning -- since we have not yet
  performed the deployment operations -- they will be latent values in
  our runtime and generally missing at the time of a plan.  This is no
  problem and we just want to avoid marshaling them in inopportune places.

* A computed property, on the other hand, is a different beast altogehter.
  Although true one of these is missing a value -- by virtue of the fact
  that they too are latent values, bottoming out in some manner on an
  output property -- they will appear in serializable input positions.
  Not only must we treat them differently during the RPC handshake and
  in the resource providers, but we also want to guarantee they are gone
  by the time we perform any CRUD operations on a resource.  They are
  purely a planning-time-only construct.
2017-06-01 08:36:43 -07:00
joeduffy e4462087a5 Add a @lumi.out decorator
This change adds a @lumi.out decorator and modifies LumIDL to emit it on
output properties of resource types.  There still isn't any runtime
awareness, however, this is an isolated change that will facilitate it.
2017-06-01 08:32:12 -07:00
joeduffy 706acb5fd8 Tolerate latent values in more places 2017-06-01 08:32:12 -07:00
joeduffy d79c41f620 Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.

In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways.  Namely,
operations against Latent<T>s generally produce new Latent<U>s.

During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values.  An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange.  As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values.  My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.

For now, using an unresolved Latent<T> in a conditional will lead
to an error.  See pulumi/lumi#67.  Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support.  That is a missing 1/3.

Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values.  Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-06-01 08:32:12 -07:00
Luke Hoban 9531483e19 Add tests for AWS DynamoDB Table provider 2017-05-31 17:06:16 -07:00
Luke Hoban 01af21a1e4 Support for multiple methods on route in aws.serverless.API
Also adds length property to String objects and a toLowerCase method to the String prototype.
2017-05-31 11:45:02 -07:00
Luke Hoban 715a26bfba Introduce aws.serverless package with API and Function
This new package is similar to the AWS Serverless Application Model, offering
higher-level interfaces to manage serverless resources. This will be a candidate
for moving into its own package in the future.

The FunctionX class has been moved into this module, and a new API class has
been added

The API class manages a collection of an API Gateway RestAPI, Stage and Deployment,
based on a collection of routes linked to Functions.  On changes to the API specification,
it updates the RestAPI, replaces the Deployment and updates the Stage to point to
the updated Deployment.

This change also reorganizes some of the intrinsics.
2017-05-31 11:45:02 -07:00
Luke Hoban 99499792b3 Serialize lambda environment variables in stable order
When serializing a closure, we serialize the lambda environment into the
aws.lambda.Function Environment property.  We need to serialize the lambda
environment in a stable order to ensure that we don't cause Lumi to require
updates to the aws.lambda.Function resource.
2017-05-31 11:40:22 -07:00
joeduffy ab6e2466c7 Flow logging information to plugins
This change flows --logtostderr and -v=x settings to any dynamically
loaded plugins so that running Lumi's command line with these flags
will also result in the plugins logging at the requested levels.  I've
found this handy for debugging purposes.
2017-05-30 10:19:33 -07:00
Luke Hoban 7f8b1e59c1 Support for lambdas (#158)
Resolves #137.

This is an initial pass for supporting JavaScript lambda syntax for defining an AWS Lambda Function.

A higher level API for defining AWS Lambda Function objects `aws.lambda.FunctionX` is added which accepts a Lumi lambda as an argument, and uses that lambda to generate the AWS Lambda Function code package.

LumiJS lambdas are serialized as the JavaScript text of the lambda body, along with a serialized version of the environment that is deserialized at runtime and used as the context for the body of the lambda.

Remaining work to further improve support for lambdas is being tracked in #173, #174, #175, and #177.
2017-05-25 16:55:14 -07:00
Luke Hoban 6015c96fda Add jsonStringify intrinsic
This will eventually be used as the implementation of JSON.stringify in LumiJS.
2017-05-25 12:19:58 -07:00
Luke Hoban b8d978b22c Move Intrinsic into eval/rt package
Unifies the notion of BuiltinFunctions with the existing Intrinsic.

Intrinsic is now only a wrapper type, used to indicate the need to lookup the symbol in the
eval pacakges table of registered intrinsics.  It does not carry the invoker function used
to eval the intrinsic.
2017-05-25 12:06:13 -07:00
Luke Hoban a625117e72 Add a length property to Array objects
Also adds a `lumi.runtime.printf` function for debugging Lumi scripts and fixes a couple issues with getter/setter references.
2017-05-25 12:06:13 -07:00
joeduffy 8f1fa79230 Rewrite eval test to be self-contained
The eval test in its current form depends on the Lumi standard library
as an external dependency.  This means that, in order to run the test,
you must first install the standard library.  Not only is this poor
practice, it is also interfering with our ability to get our new CI/CD
system up and running.  This change fixes all of that by mocking the one
standard library runtime function that we need in order to hook the intrinsic.
2017-05-24 12:50:28 -07:00
Joe Duffy f541853226 Merge pull request #157 from pulumi/intrinsic-fix
Fix a few intrinsics bugs
2017-05-23 08:05:19 -07:00
joeduffy 2bbc4739bd Add some intrinsics tests
This change adds some machinery to make it easier to write evaluator tests,
and also implements some tests for the lumi:runtime/dynamic:isFunction intrinsic.
2017-05-23 08:03:14 -07:00
Luke Hoban 35a41f9e4a Support Update on IAM Role and Lambda Function 2017-05-22 22:57:55 -07:00
joeduffy bad62854a9 Fix a few intrinsics bugs
During various refactorings pertaining to dynamic vs static invoke, the
intrinsics machinery broke in a few ways:

* MaybeIntrinsic needs to happen elsewhere.  Rather than doing it at binding
  time, we can do it when populating the properties in the first place,
  reusing the same property symbol from one access to the next.

* Last week, I refactored the intrinsics module to also have a dynamic sub-
  module.  The tokens in the Intrinsics map needed to also get updated.

* As a result of the tokens now containing member parts, we can't use
  tokens.Token.Name, since it is assumed to be a simple name; instead, we
  need to convert to tokens.ModuleMember, and then fetch Name.  To be honest,
  this is probably worth revisiting, since I think most people would expect
  Name to just work regardless of the Token kind.  The assert that it be
  Simple might be a little overly aggressive...

This checkin fixes these issues.  I'm not pushing to master just yet,
however, until there are some solid tests in here to prevent future breakage.
2017-05-22 16:16:53 -07:00
joeduffy 6e0d388c90 Make argument objects optional when no required properties
If a resource has no required properties, there's no need for an
argument object.  (In the extreme case, perhaps the resource has
*no* properties.)  This is a minor usability thing, but it's far
nicer to write code like

    let buck = new Bucket("images");

than it is to write code like

    let buck = new Bucket("images", {});
2017-05-22 14:08:32 -07:00
joeduffy 3bad4fde98 Disable storing output properties
The storing of output properties won't work correctly until pulumi/lumi#90
is completed.  The update logic sees properties that weren't supplied by the
developer and thinks this means an update is required; this is easy to fix
but better to just roll into the overall pending change that will land soon.
2017-05-22 13:20:57 -07:00
joeduffy 94786ee1a2 Add an ast.WalkChildren function
This adds a WalkChildren function that can be useful when you want to
walk an AST node's children, but not the node itself.
2017-05-22 11:06:12 -07:00
Luke Hoban 0f99762e2e Add AWS Elastic Beanstalk resource providers (#154)
Includes support for:
* Application
* ApplicationVersion
* Environment
2017-05-21 21:45:28 -07:00
joeduffy 423e84df6e Fix workspace tests 2017-05-19 08:24:44 -07:00
joeduffy 4108c51549 Reclassify Lumi under the Apache 2.0 license
This is part of pulumi/lumi#147.
2017-05-18 14:51:52 -07:00
joeduffy b7f3d447a1 Preserve the lumi prefix on our CLI tools
This change keeps the lumi prefix on our CLI tools.

As @lukehoban pointed out in person, as soon as we do pulumi/coconut#98,
most people (other than compiler authors themselves) won't actually be
typing the commands.  And, furthermore, the commands aren't all that bad.

Eventually I assume we'll want something like `lumi-js`, or
`lumi-js-compiler`, so that binaries are discovered dynamically in a way
that is extensible for future languages.  We can tackle this during #98.
2017-05-18 12:38:58 -07:00
joeduffy dafeb77dff Rename Coconut to Lumi
This is part of pulumi/coconut#147.

After it has landed, I will rename the repo on GitHub.
2017-05-18 11:38:28 -07:00
joeduffy ec27cfd22c Update object test to use new pointer constructor 2017-05-16 15:27:32 -07:00
joeduffy 8d6f4c0d69 Fix a minor error message typo 2017-05-15 17:50:13 -07:00
joeduffy 85b888d1fa Fix a misattributed diagnostics message 2017-05-15 17:49:30 -07:00
joeduffy 82e3624ea1 Implement property accessors
This change implements property accessors (getters and setters).

The approach is fairly basic, but is heavily inspired by the ECMAScript5
approach of attaching a getter/setter to any property slot (even if we don't
yet fully exploit this capability).  The evaluator then needs to track and
utilize the appropriate accessor functions when loading locations.

This change includes CocoJS support and makes a dent in pulumi/coconut#66.
2017-05-15 17:46:14 -07:00
joeduffy cac52ae572 Fix two minor comment issues 2017-05-15 06:30:17 -07:00
joeduffy 78dc0b4a47 Add some handy internal RTTI helpers (and some tests) 2017-05-13 21:17:49 -04:00
joeduffy eee0f3b717 Fix some golint warnings 2017-05-13 20:04:35 -04:00
joeduffy 71855c7c44 Split intrinsics
This change just refactors out the dynamic intrinsics functions, from the general
intrinsics file, in preparation for some new ones.
2017-05-13 19:22:52 -04:00
joeduffy ea7658f338 Guard against nil diffs 2017-05-08 14:52:17 -05:00
joeduffy d3c1d7057b Add some tests for stable property ordering 2017-05-06 16:22:06 -07:00
joeduffy 7d8aadeb1e Implement chronological stable object keys
We need a stable object key enumeration order and we might as well leverage
ECMAScript's definition for this.  As of ES6, key ordering is specified; see
https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys.

I haven't fully implemented the "numbers come first part" (we can do this as
soon as we have support for Object.keys()), but the chronological part works.
2017-05-06 16:09:49 -07:00
joeduffy 3e73a6b8ba Add an alloc.NewDynamic helper function 2017-05-06 15:39:39 -07:00
joeduffy fb3a6612f6 Fix a lambda lexical environment bug
This addresses a bug where we did not reconstruct the correct lexical
environment when restoring a lambda's captured context.  Namely, the local
variables scope "drifted" with respect to the evaluation scope slots.

This is an example program that triggered it:

    function mkeighty() {
        let eighty = 80;
        return () => eighty;
    }
    let group = new ec2.SecurityGroup(..., {
        ingress: [ ..., fromPort: mkeighty()(), ... ],
    });

I am going to work on turning this into a regression test with my next
checkin; there's a fair bit of test infrastructure "machinery" I need
to put in place, but the time has come to lay the foundation.
2017-05-04 16:38:46 -07:00
joeduffy 240cdb8f0f Implement lambdas in the runtime
This change completes implementing lambdas in the runtime, closing
out pulumi/coconut#62.  The change is mostly straightforward, with
most changes coming down to the fact that functions may now exist
that themselves aren't definitions (like class/module members).
The function stub machinery has also been updated to retain the
environment in which a lambda was created, effectively "capturing"
the lexically available variables.  Note that this is *not* dynamic
scoping, which will be a problem down the road when/if we want to
support Ruby.  My guess is we'll just have a completely different
DynamicallyScopedLambdaExpression opcode.
2017-05-04 14:03:51 -07:00
joeduffy fde88b7cf4 Permit Statements in SequenceExpressions
The previous shape of SequenceExpression only permitted expressions
in the sequence.  This is pretty common in most ILs, however, it usually
leads to complicated manual spilling in the event that a statement is needed.
This is often necessary when, for example, a compiler is deeply nested in some
expression production, and then realizes the code expansion requires a
statement (e.g., maybe a new local variable must be declared, etc).

Instead of requiring complicated code-gen, this change permits SequenceExpression
to contain an arbitrary mixture of expression/statement prelude nodes, terminating
with a single, final Expression which yields the actual expression value.  The
runtime bears the burden of implementing this which, frankly, is pretty trivial.
2017-05-04 10:54:07 -07:00
joeduffy 1e67162331 Fix a couple silly mistakes 2017-05-04 09:53:52 -07:00
joeduffy 4e5140251b Implement support for computed property initializers
I've tripped over pulumi/coconut#141 a few times now, particularly with
the sort of dynamic payloads required when creating lambdas and API gateways.
This change implements support for computed property initializers.
2017-05-01 17:11:57 -07:00
joeduffy 6902d7e1b2 Update AWS Lambdas to take archives, not assets 2017-05-01 09:38:23 -07:00
joeduffy 335ea01275 Implement archives
Our initial implementation of assets was intentionally naive, because
they were limited to single-file assets.  However, it turns out that for
real scenarios (like lambdas), we want to support multi-file assets.

In this change, we introduce the concept of an Archive.  An archive is
what the term classically means: a collection of files, addressed as one.
For now, we support three kinds: tarfile archives (*.tar), gzip-compressed
tarfile archives (*.tgz, *.tar), and normal zipfile archives (*.zip).

There is a fair bit of library support for manipulating Archives as a
logical collection of Assets.  I've gone to great length to avoid making
copies, however, sometimes it is unavoidable (for example, when sizes
are required in order to emit offsets).  This is also complicated by the
fact that the AWS libraries often want seekable streams, if not actual
raw contiguous []byte slices.
2017-04-30 12:37:24 -07:00
joeduffy 0e16aa5d93 Make resource names the first constructor parameter
This reverts back to the old style of having the resource name as its
first parameter in the generated package.  Stylistically, this reads a
little nicer, and also ensures we don't need to rewrite all our existing
samples/test cases, etc.
2017-04-29 15:58:34 -07:00
joeduffy fa24d436e3 Unpointerize some types
In a few places, an IDL type will be a pointer, but the resulting
RPC code would, ideally, be the naked type.  Namely, in both resource
and asset cases, they are required to be pointers in the IDL (because
they are by-pointer by nature), but the marshaled representations need
not be pointers.  This change depointerizes such types in the RPC
unless, of course, they are optional in which case pointers still make
sense.  This avoids some annoying dereferencing and is the kind of thing
we want to do sooner before seeing widespread use.
2017-04-29 15:38:56 -07:00
joeduffy fe93f5e76f Strongly type resource IDs in the IDL/RPC/Providers
This change simply uses the `resource.ID` type in all the places
where it belongs, rather than using `string`-typed resource IDs.
2017-04-29 13:27:39 -07:00
joeduffy b381d23393 Ensure all errors correlate back to the IDL source 2017-04-28 15:21:22 -07:00
joeduffy 6952fd55f0 Track named resources
This change adds some conditional output that depends on whether a
named resource was contained in a file or not.  This eliminates some
compiler errors in the generated code when using manually-named
resources.
2017-04-28 15:03:24 -07:00
joeduffy 7e057cd1b5 Permit maps in IDL 2017-04-28 15:03:09 -07:00
joeduffy 77fc639286 Don't mangle RPC package names 2017-04-28 12:42:31 -07:00
joeduffy 1489a73b18 Convert the AWS Lambda module to CIDLC 2017-04-28 12:27:19 -07:00
joeduffy 5ae168d23c Emit interface{} as just interface{} 2017-04-28 12:09:17 -07:00
joeduffy 40ac0a1d2b Support assets in the IDL 2017-04-28 12:07:49 -07:00
joeduffy f5c6af505a Properly fetch pointer elements 2017-04-28 11:46:35 -07:00
joeduffy 42ce8744ce Update the code-gen warning text 2017-04-28 11:35:33 -07:00
joeduffy 19577d67f0 Don't emit imports for zero-resource cases 2017-04-28 11:05:34 -07:00
joeduffy 75a897c23f Map interface{} RPC projections correctly
A property whose type is `interface{}` in the IDL ought to be projected
as a "JSON-like" map, just like it is on the Coconut package side of things,
which means a `map[string]interface{}`.
2017-04-28 10:58:27 -07:00
joeduffy 954d594e94 Rename --recurse to --recursive
My muscle memory kicked in (grep, et al), and then I realized the
name wasn't quite right.  This rights a wrong.
2017-04-28 10:37:05 -07:00
joeduffy af3949509a Implement CIDLC support for package imports
This change correctly implements package/module resolution in CIDLC.
For now, this only works for intra-package imports, which is sufficient
for now.  Eventually we will need to support this (see pulumi/coconut#138).
2017-04-28 10:31:18 -07:00
joeduffy 46227870e4 Implement a few CIDLC improvements
* Allow `interface{}` to mean "weakly typed property bag."

* Allow slices in IDL types.

* Permit the package base as an argument.
2017-04-27 15:40:51 -07:00
joeduffy dd032e0784 Make IsResource tolerant of types.Named types 2017-04-27 11:52:59 -07:00
joeduffy 47ef3f673b Rename PreviewUpdate (again)
Unfortunately, this wasn't a great name.  The old one stunk, but the
new one was misleading at best.  The thing is, this isn't about performing
an update -- it's about NOT doing an update, depending on its return value.
Further, it's not just previewing the changes, it is actively making a
decision on what to do in response to them.  InspectUpdate seems to convey
this and I've unified the InspectUpdate and Update routines to take a
ChangeRequest, instead of UpdateRequest, to help imply the desired behavior.
2017-04-27 11:18:49 -07:00
joeduffy 43bb3ec766 Reject non-pointer optional fields
This change rejects non-pointer optional fields in the IDL.  Although
there is no reason this couldn't work, technically speaking, it's almost
always certainly a mistake.  Better to issue an error about it; in the
future, we could consider making this a warning.
2017-04-27 11:03:13 -07:00
joeduffy 3f54c672be Fix/alter a few aspects of RPC code-generation
* Use --out-rpc, rather than --out-provider, since rpc/ is a peer to provider/.

* Use strongly typed tokens in more places.

* Append "rpc" to the generated RPC package names to avoid conflicts.

* Change the Check function to return []mapper.FieldError, rather than
  mapper.DecodeError, to make the common "no errors" case easier (and to eliminate
  boilerplate resulting in needing to conditionally construct a mapper.DecodeError).

* Rename the diffs argument to just diff, matching the existing convention.

* Automatically detect changes to "replaces" properties in the PreviewUpdate
  function.  This eliminates tons of boilerplate in the providers and handles the
  90% common case for resource recreation.  It's still possible to override the
  PreviewUpdate logic, of course, in case there is more sophisticated recreation
  logic necessary than just whether a property changed or not.

* Add some comments on some generated types.

* Generate property constants for the names as they will appear in weakly typed
  property bags.  Although the new RPC interfaces are almost entirely strongly
  typed, in the event that diffs must be inspected, this often devolves into using
  maps and so on.  It's much nicer to say `if diff.Changed(SecurityGroup_Description)`
  than `if diff.Changed("description")` (and catches more errors at compile-time).

* Fix resource ID generation logic to properly fetch the Underlying() type on
  named types (this would sometimes miss resources during property analysis, emitting
  for example `*VPC` instead of `*resource.ID`).
2017-04-27 10:36:22 -07:00
joeduffy 164d4db30a Implement CIDLC RPC code generation
This change implements the boilerplate RPC stub generation for CIDLC
resource providers.  This includes a lot of the marshaling goo required
to bridge between the gRPC plugin interfaces and the strongly typed
resource types and supporting marshalable structures.

This completes the major tasks of implementing CIDLC (pulumi/coconut#133),
and I have most of the AWS package running locally on it.  There are
undoubtedly bugs left to shake out, but no planned work items remain.
2017-04-27 07:33:00 -07:00
joeduffy 507a2609a7 Add an initial implementation of CIDLC
This is an initial implementation of the Coconut IDL Compiler (CIDLC).
This is described further in
https://github.com/pulumi/coconut/blob/master/docs/design/idl.md,
and the work is tracked by coconut/pulumi#133.

I've been kicking the tires with this locally enough to checkpoint the
current version.  There are quite a few loose ends not yet implemented,
most of them minor, with the exception of the RPC stub generation which
I need to flesh out more before committing.
2017-04-25 15:05:51 -07:00
joeduffy 8c58950639 Tolerate nils in output property marshaling 2017-04-25 14:04:22 -07:00
joeduffy 1edced2d4b Add the ability to convert structs to PropertyMaps 2017-04-21 15:27:32 -07:00
joeduffy d6abea728c Add outputs to the Create provider's return
In order to support output properties (pulumi/coconut#90), we need to
modify the Create gRPC interface for resource providers slightly.  In
addition to returning the ID, we need to also return any properties
computed by the AWS provider itself.  For instance, this includes ARNs
and IDs of various kinds.  This change simply propagates the resources
but we don't actually support reading the outputs just yet.
2017-04-21 14:15:06 -07:00
joeduffy aa44b46608 Lower instanceof in CocoJS; implement IsInst in CocoIL 2017-04-20 17:38:15 -07:00
joeduffy 0b6e262b46 Rename resource provider methods
This change renames two provider methods:

    * Read becomes Get.

    * UpdateImpact becomes PreviewUpdate.

These just read a whole lot nicer than the old names.
2017-04-20 14:09:00 -07:00
joeduffy 94e072c653 Add a TryLoadDynamicExpression IL opcode
This change introduces TryLoadDynamicExpression.  This is similar to
the existing LoadDynamicExpression opcode, except that it will return
null in response to a missing member (versus the default of raising
an exception).  This is to enable languages like JavaScript to encode
operations properly (which always yields undefined/nulls), while still
catering to languages like Python (which throw exceptions).
2017-04-19 16:49:59 -07:00
joeduffy 53e7bfbb86 Rearrange the way stderr/stdout is handled for plugins
The order of operations for stderr/stdout monitoring with plugins
managed to hide some important errors.  For example, if something
was written to stderr *before* the port was parsed from stdout, a
very possible scenario if the plugin fails before it has even
properly sarted, then we would silently drop the stderr on the floor
leaving behind no indication of what went wrong.  The new ordering
ensures that stderr is never ignored with some minor improvements
in the case that part of the port is parsed from stdout but it
ultimately ends in an error (e.g., if an EOF occurs prematurely).
2017-04-19 15:01:04 -07:00
joeduffy f429bc6a0c Use github.com/pkg/errors for errors
This change moves us over to the github.com/pkg/errors package to
encourage the addition of more context associated with failures.
2017-04-19 14:46:50 -07:00
joeduffy 958d67d444 Move NewCheckResponse into coconut/pkg/resource package 2017-04-19 14:25:49 -07:00
joeduffy 936d3f45e6 Fix another package name reference 2017-04-19 14:20:12 -07:00
joeduffy 98961b706a Permit package name hyphens in one more place
...missed one.
2017-04-19 11:34:36 -07:00
joeduffy 034fc3bf67 Permit dashes in package names
Right now, we reject dashes in package names.  I've hit this a few times and it annoys
me each time.  (It would seem to makes sense to permit hyphens in package names, given
that [almost?] every other package manager on Earth does...)

No more!  Hyphens welcome!
2017-04-19 10:53:14 -07:00
joeduffy 847d74c9f6 Implement rudimentary decorator support
This change introduces decorator support for CocoJS and the corresponding
IL/AST changes to store them on definition nodes.  Nothing consumes these
at the moment, however, I am looking at leveraging this to indicate that
certain program fragments are "code" and should be serialized specially
(in support of Functions-as-lambdas).
2017-04-18 16:53:26 -07:00
joeduffy da75f62865 Retry lambda creation until IAM role is available
Per Amazon's own documentation,
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role,
IAM roles may take "several seconds" to propagate.  In the meantime, we
are apt to get the dreaded "role defined for this function cannot be assumed"
error message.  In response, we'll do what the AWS documentation suggests:
wait a bit and retry.
2017-04-18 13:56:19 -07:00
joeduffy 973fccf09d Implement AWS Lambda resource provider
This change introduces a basic AWS Lambda resource provider.  It supports
C--D, but not -RU-, yet.
2017-04-18 11:02:04 -07:00
joeduffy e8d7ef620f Add a couple missing trace errs 2017-04-17 18:05:12 -07:00
joeduffy 30237bb28f Regen Glide lock; fix two govet mistakes 2017-04-17 17:04:00 -07:00
joeduffy b3f430186d Implement S3 bucket objects
This change includes a first basic whack at implementing S3 bucket
objects.  It leverages the assets infrastructure put in place in the
last commit, supporting uploads from text, files, or arbitrary URIs.

Most of the interesting object properties remain unsupported for now,
but with this we can upload and delete basic S3 objects, sufficient
for a lot of the lambda functions management we need to implement.
2017-04-17 13:34:19 -07:00
joeduffy 67248789b3 Introduce assets
This change introduces the basic concept of assets.  It is far from
fully featured, however, it is enough to start adding support for various
storage kinds that require access to I/O-backed data (files, etc).

The challenge is that Coconut is deterministic by design, and so you
cannot simply read a file in an ad-hoc manner and present the bytes to
a resource provider.  Instead, we will model "assets" as first class
entities whose data source is described to the system in a more declarative
manner, so that the system and resource providers can manage them.

There are three ways to create an asset at the moment:

1. A constant, in-memory string.
2. A path to a file on the local filesystem.
3. A URI, whose scheme is extensible.

Eventually, we want to support byte blobs, but due to our use of a
"JSON-like" type system, this isn't easily expressible just yet.

The URI scheme is extensible in that file://, http://, and https://
are supported "out of the box", but individual providers are free to
recognize their own schemes and support them.  For instance, copying
one S3 object to another will be supported simply by passing a URI
with the s3:// protocol in the usual way.

Many utility functions are yet to be written, but this is a start.
2017-04-17 13:00:26 -07:00
joeduffy 6b4cab557f Refactor glog init swizzle to a shared package 2017-04-13 05:27:45 -07:00
joeduffy ae1e43ce5d Refactor shared command bits into pkg/cmdutil
This paves the way for more Go-based command line tools that can
share some of the common utility functions around diagnostics and
exit codes.
2017-04-12 11:12:25 -07:00
joeduffy 860a0129d8 Permit dynamic to appear in more places (like binops) 2017-04-12 10:55:33 -07:00
joeduffy aa730b5913 Translate CocoPy subscripts
This change implements simple index-based CocoPy subscripts (and
not the more fully featured slicing ones).

Alongside this, we relax a binder-time check that all dynamic
access types must be strings.  The eval code already handles
numeric (array) accesses, so we will permit these to flow through.
2017-04-11 12:33:30 -07:00
joeduffy 9adfa6a18f Relax calling assertions
This permits non-nil `this` objects for dynamically loaded properties
of classes and modules, provided they are the prototype or module
object for the target function, respectively.
2017-04-11 11:53:06 -07:00
joeduffy ead6a107ee Implement record types and primary properties
This change emits all CocoJS interfaces as records.  This allows us to
safely construct instances of them from Python using anonymous properties,
essentially emulating object literals.

For example, given a CocoJs interface defined as such:

    interface Foo {
        x;
        y?;
        z;
    }

we can easily construct fresh instances using normal JS literals:

    let f = { x: 42, z: "bar" };

But, Python doesn't have the equivalent literal syntax, wedging us.
It's now possible to initialize an instance from CocoPy as follows:

    let f = Foo(x=42, z="bar")

This leverages the notion of records and primary properties, as
described in our CocoPack/CocoIL design documents.
2017-04-11 11:37:24 -07:00
joeduffy 1e5bf7e5bb Fix three evaluation bugs
* Pushing a class scope should permit subclasses (assertion).

* Returning nothing is legal for voids *and* dynamic (the latter was missing).

* The dynamic load readonly lval check is redundant; we check at the site of
  assignment and doing it here as well led to two errors per usage.
2017-04-11 09:10:22 -07:00
joeduffy 1299e4ade7 Require blocks in fewer places
Due to Python's ... interesting ... scoping rules, we want to avoid
forcing block scopes in certain places.  Instead, we will let arbitrary
statements take their place.  Of course, this could be a block, but it
very well could be a multi-statement (essentially a block that doesn't
imply a new lexical scope), or anything, really.
2017-04-10 10:06:27 -07:00
joeduffy 2c6ad1e331 Fix a handful of things
* Move checking the validity of a derived class with no constructor
  from evlauation to binding (verification).  Furthermore, make it
  a verification error instead of an assert, and make the checking
  complete (i.e., don't just check for the existence of a base class,
  also check for the existence of a ctor, recursively).

* Refactor the constructor accessor out of the evaluator and make it
  a method, Ctor, on the Function abstraction.

* Add a recursive Module population case to property initialization.

* Only treat the top-most frame in a module's initializer as belonging
  to the module scope.  This avoids interpreting block scopes within
  that initializer as belonging to the module scope.  Ultimately, it's
  up to the language compiler to decide where to place scopes, but this
  gives it more precise control over module scoping.

* Assert against unsupported named/star/keyword args in CocoPy.
2017-04-10 08:36:48 -07:00
joeduffy 346bcca77c Permit prototype invocation as "new"
If we encounter a dynamic invocation of a prototype object, we will
interpret it as an object allocation.  This corresponds to code like

    import ec2 from aws
    instance = ec2.Instance(...)

where the second line dynamically loads the prototype object for the
Instance class from the module object for the aws/ec2 module, and
invokes it.
2017-04-09 09:29:58 -07:00
joeduffy 3cb734cc98 Populate module objects with exports 2017-04-09 09:21:23 -07:00
joeduffy 3ef977e19c Support named imports
This change adds support for naming imports.  At the moment, this simply
makes the names dynamically accessible for languages that do dynamic loads
against module objects, versus strongly typed tokens.  The basic scheme
is to keep two objects per module: one that contains the globals and its
prototype parent that contains just the exports.  This ensures we can
share the same slots while attaining the desired information hiding
(e.g., when handing out an object for dynamic access, we give out this
parent objects, while when loading globals from within a module, we use
the childmost one that contains all private and exported variables).
2017-04-09 08:44:58 -07:00
joeduffy e96d4018ae Switch to imports as statements
The old model for imports was to use top-level declarations on the
enclosing module itself.  This was a laudible attempt to simplify
matters, but just doesn't work.

For one, the order of initialization doesn't precisely correspond
to the imports as they appear in the source code.  This could incur
some weird module initialization problems that lead to differing
behavior between a language and its Coconut variant.

But more pressing as we work on CocoPy support, it doesn't give
us an opportunity to dynamically bind names in a correct way.  For
example, "import aws" now needs to actually translate into a variable
declaration and assignment of sorts.  Furthermore, that variable name
should be visible in the environment block in which it occurs.

This change switches imports to act like statements.  For the most
part this doesn't change much compared to the old model.  The common
pattern of declaring imports at the top of a file will translate to
the imports happening at the top of the module's initializer.  This
has the effect of initializing the transitive closure just as it
happened previously.  But it enables alternative models, like imports
inside of functions, and -- per the above -- dynamic name binding.
2017-04-08 18:16:10 -07:00
joeduffy 54e89ad608 Permit localvar lookups that come up empty-handed
Previously, it was an error to look up a local that didn't exist.
Now it is common, thanks to dynamic lookups.  A few code-paths didn't
previously handle this adequately; now they do.
2017-04-08 17:04:43 -07:00
joeduffy f773000ef9 Implement dynamic loads from the environment¬
This rearranges the way dynamic loads work a bit.  Previously, they¬
required an object, and did a dynamic lookup in the object's property¬
map.  For real dynamic loads -- of the kind Python uses, obviously,¬
but also ECMAScript -- we need to search the "environment".

This change searches the environment by looking first in the lexical¬
scope in the current function.  If a variable exists, we will use it.¬
If that misses, we then look in the module scope.  If a variable exists¬
there, we will use it.  Otherwise, if the variable is used in a non-lval
position, an dynamic error will be raised ("name not declared").  If
an lval, however, we will lazily allocate a slot for it.

Note that Python doesn't use block scoping in the same way that most
languages do.  This behavior is simply achieved by Python not emitting
any lexically scoped blocks other than at the function level.

This doesn't perfectly achieve the scoping behavior, because we don't
yet bind every name in a way that they can be dynamically discovered.
The two obvious cases are class names and import names.  Those will be
covered in a subsequent commit.

Also note that we are getting lucky here that class static/instance
variables aren't accessible in Python or ECMAScript "ambiently" like
they are in some languages (e.g., C#, Java); as a result, we don't need
to introduce a class scope in the dynamic lookup.  Some day, when we
want to support such languages, we'll need to think about how to let
languages control the environment probe order; for instance, perhaps
the LoadDynamicExpression node can have an "environment" property.
2017-04-08 16:47:15 -07:00
joeduffy 9c1ea1f161 Fix some poor hygiene
A few linty things crept in; this addresses them.
2017-04-08 07:44:02 -07:00
joeduffy 843787f266 Emit more dynamic loads
This changes the CocoPy default load type from static to dynamic,
since we don't have enough information at compile-time to emit
fully qualified tokens.  Previously, Coconut only supported dynamic
loads with object targets, however we will need to support the full
scope search (class, module, global, etc).
2017-04-08 07:30:38 -07:00
joeduffy 2451005b7c Fix an assert and a message
This change makes node optional in the lookupBasicType function, which is
necessary in cases where diagnostics information isn't available (such as
with configuration application).  This eliminates an assert when you fat-
finger a configuration key.  The associated message was missing apostrophes.
2017-03-30 15:06:55 -07:00
joeduffy dccdcbd26b Shorten an error message 2017-03-23 08:15:10 -07:00
joeduffy 3d74eac67d Make major commands more pleasant
This change eliminates the need to constantly type in the environment
name when performing major commands like configuration, planning, and
deployment.  It's probably due to my age, however, I keep fat-fingering
simple commands in front of investors and I am embarrassed!

In the new model, there is a notion of a "current environment", and
I have modeled it kinda sorta just like Git's notion of "current branch."

By default, the current environment is set when you `init` something.
Otherwise, there is the `coco env select <env>` command to change it.
(Running this command w/out a new <env> will show you the current one.)

The major commands `config`, `plan`, `deploy`, and `destroy` will prefer
to use the current environment, unless it is overridden by using the
--env flag.  All of the `coco env <cmd> <env>` commands still require the
explicit passing of an environment which seems reasonable since they are,
after all, about manipulating environments.

As part of this, I've overhauled the aging workspace settings cruft,
which had fallen into disrepair since the initial prototype.
2017-03-21 19:23:32 -07:00
joeduffy 015730e9a9 Fix a bogus unchanged lookup
We need to look for the "old" resource, not the "new" one, when verifying
an assertion that a dependency that is seemingly unchanged actually is.
2017-03-15 16:46:07 -07:00
joeduffy 913201fc51 Add optional formatting to the diag.Message API 2017-03-15 12:16:56 -07:00
joeduffy 95f59273c8 Update copyright notices from 2016 to 2017 2017-03-14 19:26:14 -07:00
joeduffy 80d19d4f0b Use the object mapper to reduce provider boilerplate
This changes the object mapper infrastructure to offer more fine-grained
reporting of errors, and control over verification, during the mapping from
an untyped payload to a typed one.  As a result, we can eliminate a bit of
the explicit unmarshaling goo in the AWS providers (but not all of it; I'm
sure there is more we can, and should, be doing here...)
2017-03-12 14:13:44 -07:00
joeduffy 705880cb7f Add the ability to specify analyzers
This change adds the ability to specify analyzers in two ways:

1) By listing them in the project file, for example:

        analyzers:
            - acmecorp/security
            - acmecorp/gitflow

2) By explicitly listing them on the CLI, as a "one off":

        $ coco deploy <env> \
            --analyzer=acmecorp/security \
            --analyzer=acmecorp/gitflow

This closes out pulumi/coconut#119.
2017-03-11 10:07:34 -08:00
joeduffy b4b4d26844 Add pkg/util/rpcutil to cut down on some plugin boilerplate
This change eliminates some of the boilerplate required to create a
new plugin; mostly this is gRPC-related code.
2017-03-11 09:23:09 -08:00
joeduffy 45064d6299 Add basic analyzer support
This change introduces the basic requirements for analyzers, as per
pulumi/coconut#119.  In particular, an analyzer can implement either,
or both, of the RPC methods, Analyze and AnalyzeResource.  The former
is meant to check an overall deployment (e.g., to ensure it has been
signed off on) and the latter is to check individual resources (e.g.,
to ensure properties of them are correct, such as checking style,
security, etc. rules).  These run simultaneous to overall checking.

Analyzers are loaded as plugins just like providers are.  The difference
is mainly in their naming ("analyzer-" prefix, rather than "resource-"),
and the RPC methods that they support.

This isn't 100% functional since we need a way to specify at the CLI
that a particular analyzer should be run, in addition to a way of
recording which analyzers certain projects should use in their manifests.
2017-03-10 23:49:17 -08:00
joeduffy 807d355d5a Rename plugin prefix from coco-ressrv to coco-resource 2017-03-10 20:48:09 -08:00
joeduffy 384e347115 No more nuts! 2017-03-10 13:27:19 -08:00
joeduffy 3b3b56a836 Properly reap child processes
This change reaps child plugin processes before exiting.  It also hardens
some of the exit paths to avoid os.Exiting from the middle of a callstack.
2017-03-07 13:47:42 +00:00
joeduffy 86dc13ed5b More term rotations
This changes a few naming things:

* Rename "husk" to "environment" (`coco env` for short).

* Rename NutPack/NutIL to CocoPack/CocoIL.

* Rename the primary Nut.yaml/json project file to Coconut.yaml/json.

* Rename the compiled Nutpack.yaml/json file to Cocopack.yaml/json.

* Rename the package asset directory from nutpack/ to .coconut/.
2017-03-06 14:32:39 +00:00
joeduffy 6194a59798 Add a pre-pass to validate resources before creating/updating
This change adds a new Check RPC method on the provider interface,
permitting resource providers to perform arbitrary verification on
the values of properties.  This is useful for validating things
that might be difficult to express in the type system, and it runs
before *any* modifications are run (so failures can be caight early
before it's too late).  My favorite motivating example is verifying
that an AWS EC2 instance's AMI is available within the target region.

This resolves pulumi/coconut#107, although we aren't using this
in any resource providers just yet.  I'll add a work item now for that...
2017-03-02 18:15:38 -08:00
joeduffy adf852dd84 Fix an off by one (duhhh) 2017-03-02 17:15:13 -08:00
joeduffy 076d689a05 Rename Monikers to URNs
This change is mostly just a rename of Moniker to URN.  It does also
prefix resource URNs to have a standard URN namespace; in other words,
"urn🥥<name>", where <name> is the same as the prior Moniker.

This is a minor step that helps to prepare us for pulumi/coconut#109.
2017-03-02 17:10:10 -08:00
joeduffy 2ce75cb946 Make security group changes imply replacement 2017-03-02 16:16:18 -08:00
joeduffy 966969945b Add a resource.NewUniqueHex API (and use it)
This change adds a new resource.NewUniqueHex API, that simply generates
a unique hex string with the given prefix, with a specific count of
random bytes, and optionally capped to a maximum length.

This is used in the AWS SecurityGroup resource provider to avoid name
collisions, which is especially important during replacements (otherwise
we cannot possibly create a new instance before deleting the old one).

This resolves pulumi/coconut#108.
2017-03-02 16:02:41 -08:00
joeduffy 523c669a03 Track which updates triggered a replacement
This change tracks which updates triggered a replacement.  This enables
better output and diagnostics.  For example, we now colorize those
properties differently in the output.  This makes it easier to diagnose
why an unexpected resource might be getting deleted and recreated.
2017-03-02 15:24:39 -08:00
joeduffy f0d9b12a3c Don't emit logical step resources while checkpointing 2017-03-02 13:14:57 -08:00
joeduffy c633d0ceb0 Add "still waiting" messages to retries 2017-03-02 13:12:40 -08:00
joeduffy bd613a33e6 Make replacement first class
This change, part of pulumi/coconut#105, rearranges support for
resource replacement.  The old model didn't properly account for
the cascading updates and possible replacement of dependencies.

Namely, we need to model a replacement as a creation followed by
a deletion, inserted into the overall DAG correctly so that any
resources that must be updated are updated after the creation but
prior to the deletion.  This is done by inserting *three* nodes
into the graph per replacement: a physical creation step, a
physical deletion step, and a logical replacement step.  The logical
step simply makes it nicer in the output (the plan output shows
a single "replacement" rather than the fine-grained outputs, unless
they are requested with --show-replace-steps).  It also makes it
easier to fold all of the edges into a single linchpin node.

As part of this, the update step no longer gets to choose whether
to recreate the resource.  Instead, the engine takes care of
orchestrating the replacement through actual create and delete calls.
2017-03-02 09:52:08 -08:00
joeduffy df3c0dcb7d Display and colorize replacements distinctly 2017-03-01 13:34:29 -08:00
joeduffy fe0bb4a265 Support replacement IDs
This change introduces a new RPC function to the provider interface;
in pseudo-code:

    UpdateImpact(id ID, t Type, olds PropertyMap, news PropertyMap)
        (bool, PropertyMap, error)

Essentially, during the planning phase, we will consult each provider
about the nature of a proposed update.  This update includes a set of
old properties and the new ones and, if the resource provider will need
to replace the property as a result of the update, it will return true;
in general, the PropertyMap will eventually contain a list of all
properties that will be modified as a result of the operation (see below).

The planning phase reacts to this by propagating the change to dependent
resources, so that they know that the ID will change (and so that they
can recalculate their own state accordingly, possibly leading to a ripple
effect).  This ensures the overall DAG / schedule is ordered correctly.

This change is most of pulumi/coconut#105.  The only missing piece
is to generalize replacing the "ID" property with replacing arbitrary
properties; there are hooks in here for this, but until pulumi/coconut#90
is addressed, it doesn't make sense to make much progress on this.
2017-03-01 09:08:53 -08:00
joeduffy a4e806a07c Remember old moniker to ID mappings
For cerain update shapes, we will need to recover an ID of an already-deleted,
or soon-to-be-deleted resource; in those cases, we have a moniker but want to
serialize an ID.  This change implements support for remembering/recovering them.
2017-02-28 17:03:33 -08:00
joeduffy cf2788a254 Allow restarting from partial failures
This change fixes a couple issues that prevented restarting a
deployment after partial failure; this was due to the fact that
unchanged resources didn't propagate IDs from old to new.  This
is remedied by making unchanged a map from new to old, and making
ID propagation the first thing plan application does.
2017-02-28 16:09:56 -08:00
joeduffy 6a2edc9159 Ensure configuration round-trips in Huskfiles 2017-02-28 15:43:46 -08:00
joeduffy c77329129a Print more details when an unhandled exception occurs 2017-02-28 13:15:28 -08:00
joeduffy 7593dd3ce9 Permit dots in names
This is sometimes used for "internal" functionality; and, furthermore,
NPM-style modules can legally contain dots.
2017-02-28 12:07:18 -08:00
joeduffy 1c43abffec Fix some go vet issues 2017-02-28 11:02:33 -08:00
joeduffy 51fc9b1845 Fix a test break 2017-02-28 10:38:29 -08:00
joeduffy ce7f8d130e Change the error prefix from MU to COCO 2017-02-28 10:36:21 -08:00
joeduffy 7f0a97a4e3 Print configuration variables; etc.
This change does a few things:

* First and foremost, it tracks configuration variables that are
  initialized, and optionally prints them out as part of the
  prelude/header (based on --show-config), both in a dry-run (plan)
  and in an actual deployment (apply).

* It tidies up some of the colorization and messages, and includes
  nice banners like "Deploying changes:", etc.

* Fix an assertion.

* Issue a new error

      "One or more errors occurred while applying X's configuration"

  just to make it easier to distinguish configuration-specific
  failures from ordinary ones.

* Change config keys to tokens.Token, not tokens.ModuleMember,
  since it is legal for keys to represent class members (statics).
2017-02-28 10:32:24 -08:00
joeduffy d91b04d8f4 Support config maps
This change adds support for configuration maps.

This is a new feature that permits initialization code to come from markup,
after compilation, but before evaluation.  There is nothing special with this
code as it could have been authored by a user.  But it offers a convenient
way to specialize configuration settings per target husk, without needing
to write code to specialize each of those husks (which is needlessly complex).

For example, let's say we want to have two husks, one in AWS's us-west-1
region, and the other in us-east-2.  From the same source package, we can
just create two husks, let's say "prod-west" and "prod-east":

    prod-west.json:
    {
        "husk": "prod-west",
        "config": {
            "aws:config:region": "us-west-1"
        }
    }

    prod-east.json:
    {
        "husk": "prod-east",
        "config": {
            "aws:config:region": "us-east-2"
        }
    }

Now when we evaluate these packages, they will automatically poke the
right configuration variables in the AWS package *before* actually
evaluating the CocoJS package contents.  As a result, the static variable
"region" in the "aws:config" package will have the desired value.

This is obviously fairly general purpose, but will allow us to experiment
with different schemes and patterns.  Also, I need to whip up support
for secrets, but that is a task for another day (perhaps tomorrow).
2017-02-27 19:43:54 -08:00
joeduffy 9b55505463 Implement AWS security group updates 2017-02-27 13:33:08 -08:00
joeduffy eca5c38406 Fix a handful of update-related issues
* Delete husks if err == nil, not err != nil.

* Swizzle the formatting padding on array elements so that the
  diff modifier + or - binds more tightly to the [N] part.

* Print the un-doubly-indented padding for array element headers.

* Add some additional logging to step application (it helped).

* Remember unchanged resources even when glogging is off.
2017-02-27 11:27:36 -08:00
joeduffy 3bdbf17af2 Rename --show-sames to --show-unchanged
Per Eric's feedback.
2017-02-27 11:08:14 -08:00
joeduffy 09e328e3e6 Extract settings from the correct old/new snapshot 2017-02-27 11:02:39 -08:00
joeduffy afbd40c960 Add a --show-sames flag
This change adds a --show-sames flag to `coco husk deploy`.  This is
useful as I'm working on updates, to show what resources haven't changed
during a deployment.
2017-02-27 10:58:24 -08:00
joeduffy 88fa0b11ed Checkpoint deployments
This change checkpoints deployments properly.  That is, even in the
face of partial failure, we should keep the huskfile up to date.  This
accomplishes that by tracking the state during plan application.

There are still ways in which this can go wrong, however.  Please see
pulumi/coconut#101 for additional thoughts on what we might do here
in the future to make checkpointing more robust in the face of failure.
2017-02-27 10:26:44 -08:00
joeduffy 604370f58b Propagate IDs from old to new during updates 2017-02-26 13:36:30 -08:00
joeduffy d3ce3cd9c6 Implement a coco husk ls command
This command is handy for development, so I whipped up a quick implementation.
All it does is print all known husks with their associated deployment time
and resource count (if any, or "n/a" for initialized husks with no deployments).
2017-02-26 13:06:33 -08:00
joeduffy ace693290f Fix the directionality of delete edges 2017-02-26 12:05:49 -08:00
joeduffy 44783cffb7 Don't overwrite unmarshaled deployment info 2017-02-26 12:00:00 -08:00
joeduffy ff3f2232db Only use args if non-nil 2017-02-26 11:53:02 -08:00
joeduffy 1bdd24395c Recognize TextUnmarshaler and use it
This change recognizes TextUnmarshaler during object mapping, and
will defer to it when we have a string but are assigning to a
non-string target that implements the interface.
2017-02-26 11:51:38 -08:00
joeduffy 2f60a414c7 Reorganize deployment commands
As part of pulumi/coconut#94 -- adding targeting capabilities -- I've
decided to (yet again) reorganize the deployment commands a bit.  This
makes targets ("husks") more of a first class thing.

Namely, you must first initialize a husk before using it:

    $ coco husk init staging
    Coconut husk 'staging' initialized; ready for deployments

Eventually, this is when you will be given a choice to configure it.
Afterwards, you can perform deployments.  The first one is like a create,
but subsequent ones just figure out the right thing to do and do it:

    $ ... make some changes ...
    $ coco husk deploy staging
    ... standard deployment progress spew ...

Finally, should you want to teardown an entire environment:

    $ coco husk destroy staging
    ... standard deletion progress spew for all resources ...
    Coconut husk 'staging' has been destroyed!
2017-02-26 11:20:14 -08:00
joeduffy 2fec5f74d5 Make DeepEquals nullary logic match Diff 2017-02-25 18:24:12 -08:00
joeduffy 977b16b2cc Add basic targeting capability
This change partially implements pulumi/coconut#94, by adding the
ability to name targets during creation and reuse those names during
deletion and update.  This simplifies the management of deployment
records, checkpoints, and snapshots.

I've opted to call these things "husks" (perhaps going overboard with
joy after our recent renaming).  The basic idea is that for any
executable Nut that will be deployed, you have a nutpack/ directory
whose layout looks roughly as follows:

    nutpack/
        bin/
            Nutpack.json
            ... any other compiled artifacts ...
        husks/
            ... one snapshot per husk ...

For example, if we had a stage and prod husk, we would have:

    nutpack/
        bin/...
        husks/
            prod.json
            stage.json

In the prod.json and stage.json files, we'd have the most recent
deployment record for that environment.  These would presumably get
checked in and versioned along with the overall Nut, so that we
can use Git history for rollbacks, etc.

The create, update, and delete commands look in the right place for
these files automatically, so you don't need to manually supply them.
2017-02-25 09:24:52 -08:00
joeduffy fbb56ab5df Coconut! 2017-02-25 07:25:33 -08:00
joeduffy e0440ad312 Print step op labels 2017-02-24 17:44:54 -08:00
joeduffy b43c374905 Fix a few more things about updates
* Eliminate some superfluous "\n"s.

* Remove the redundant properties stored on AWS resources.

* Compute array diff lengths properly (+1).

* Display object property changes from null to non-null as
  adds; and from non-null to null as deletes.

* Fix a boolean expression from ||s to &&s.  (Bone-headed).
2017-02-24 17:02:02 -08:00
joeduffy 53cf9f8b60 Tidy up a few things
* Print a pretty message if the plan has nothing to do:

        "info: nothing to do -- resources are up to date"

* Add an extra validation step after reading in a snapshot,
  so that we detect more errors sooner.  For example, I've
  fed in the wrong file several times, and it just chugs
  along as though it were actually a snapshot.

* Skip printing nulls in most plan outputs.  These just
  clutter up the output.
2017-02-24 16:44:46 -08:00
joeduffy 877fa131eb Detect duplicate object names
This change detects duplicate object names (monikers) and issues a nice
error message with source context include.  For example:

    index.ts(260,22): error MU2006: Duplicate objects with the same name:
        prod::ec2instance:index::aws:ec2/securityGroup:SecurityGroup::group

The prior code asserted and failed abruptly, whereas this actually points
us to the offending line of code:

    let group1 = new aws.ec2.SecurityGroup("group", { ... });
    let group2 = new aws.ec2.SecurityGroup("group", { ... });
                 ^^^^^^^^^^^^^^^^^^^^^^^^^
2017-02-24 16:03:06 -08:00
joeduffy 14e3f19437 Implement name property in AWS provider/library 2017-02-24 15:41:56 -08:00
joeduffy c120f62964 Redo object monikers
This change overhauls the way we do object monikers.  The old mechanism,
generating monikers using graph paths, was far too brittle and prone to
collisions.  The new approach mixes some amount of "automatic scoping"
plus some "explicit naming."  Although there is some explicitness, this
is arguably a good thing, as the monikers will be relatable back to the
source more readily by developers inspecting the graph and resource state.

Each moniker has four parts:

    <Namespace>::<AllocModule>::<Type>::<Name>

wherein each element is the following:

    <Namespace>     The namespace being deployed into
    <AllocModule>   The module in which the object was allocated
    <Type>          The type of the resource
    <Name>          The assigned name of the resource

The <Namespace> is essentially the deployment target -- so "prod",
"stage", etc -- although it is more general purpose to allow for future
namespacing within a target (e.g., "prod/customer1", etc); for now
this is rudimentary, however, see marapongo/mu#94.

The <AllocModule> is the token for the code that contained the 'new'
that led to this object being created.  In the future, we may wish to
extend this to also track the module under evaluation.  (This is a nice
aspect of monikers; they can become arbitrarily complex, so long as
they are precise, and not prone to false positives/negatives.)

The <Name> warrants more discussion.  The resource provider is consulted
via a new gRPC method, Name, that fetches the name.  How the provider
does this is entirely up to it.  For some resource types, the resource
may have properties that developers must set (e.g., `new Bucket("foo")`);
for other providers, perhaps the resource intrinsically has a property
that explicitly and uniquely qualifies the object (e.g., AWS SecurityGroups,
via `new SecurityGroup({groupName: "my-sg"}`); and finally, it's conceivable
that a provider might auto-generate the name (e.g., such as an AWS Lambda
whose name could simply be a hash of the source code contents).

This should overall produce better results with respect to moniker
collisions, ability to match resources, and the usability of the system.
2017-02-24 14:50:02 -08:00
joeduffy 9dc75da159 Diff and colorize update outputs
This change implements detailed object diffing for puposes of displaying
(and colorizing) updated properties during an update deployment.
2017-02-23 19:03:22 -08:00
joeduffy c4d1f60a7e Eliminate a superfluous map allocation 2017-02-23 15:05:30 -08:00
joeduffy 86bfe5961d Implement updates
This change is a first whack at implementing updates.

Creation and deletion plans are pretty straightforward; we just take
a single graph, topologically sort it, and perform the operations in
the right order.  For creation, this is in dependency order (things
that are depended upon must be created before dependents); for deletion,
this is in reverse-dependency order (things that depend on others must
be deleted before dependencies).  These are just special cases of the more
general idea of performing DAG operations in dependency order.

Updates must work in terms of this more general notion.  For example:

* It is an error to delete a resource while another refers to it; thus,
  resources are deleted after deleting dependents, or after updating
  dependent properties that reference the resource to new values.

* It is an error to depend on a create a resource before it is created;
  thus, resources must be created before dependents are created, and/or
  before updates to existing resource properties that would cause them
  to refer to the new resource.

Of course, all of this is tangled up in a graph of dependencies.  As a
result, we must create a DAG of the dependencies between creates, updates,
and deletes, and then topologically sort this DAG, in order to determine
the proper order of update operations.

To do this, we slightly generalize the existing graph infrastructure,
while also specializing two kinds of graphs; the existing one becomes a
heapstate.ObjectGraph, while this new one is resource.planGraph (internal).
2017-02-23 14:56:23 -08:00
joeduffy 43432babc5 Wait for SecurityGroups to become active 2017-02-23 10:18:37 -08:00
joeduffy d9e6d8a207 Add a simple retry.Until package/function
This change introduces a simple retry package which will be used in
resource providers in order to perform waits, backoffs, etc.  It's
pretty basic right now but leverages the fancy new Golang context
support for deadlines and timeouts.  Soon we will layer AWS-specific
acceptors, etc. atop this more general purpose thing.
2017-02-22 19:16:46 -08:00
joeduffy f00b146481 Echo resource provider outputs
This change introduces a new informational message category to the
overall diagnostics infrastructure, and then wires up the resource
provider plugins stdout/stderr streams to it.  In particular, a
write to stdout implies an informational message, whereas a write to
stderr implies an error.  This is just a very simple and convenient
way for plugins to provide progress reporting; eventually we may
need something more complex, due to parallel evaluation of resource
graphs, however I hope we don't have to deviate too much from this.
2017-02-22 18:53:36 -08:00
joeduffy 8610a70ca4 Implement stable resource ordering
This change adds custom serialization and deserialization to preserve
the ordering of resources in snapshot files.  Unfortunately, because
Go maps are unordered, the results are scrambled (actually, it turns out,
Go will sort by the key).  An alternative would be to resort the results
after reading in the file, or storing as an array, but this would be a
change to the MuGL file format and is less clear than simply keying each
resource by its moniker as we are doing today.
2017-02-22 17:33:08 -08:00
joeduffy ae99e957f9 Fix a few messages and assertions 2017-02-22 14:43:08 -08:00
joeduffy 9c2013baf0 Implement resource snapshot deserialization 2017-02-22 14:32:03 -08:00
joeduffy 8d71771391 Repivot plan/apply commands; prepare for updates
This change repivots the plan/apply commands slightly.  This is largely
in preparation for performing deletes and updates of existing environments.

The old way was slightly confusing and made things appear more "magical"
than they actually are.  Namely, different things are needed for different
kinds of deployment operations, and trying to present them each underneath
a single pair of CLI commands just leads to weird modality and options.

The new way is to offer three commands: create, update, and delete.  Each
does what it says on the tin: create provisions a new environment, update
makes resource updates to an existing one, and delete tears down an existing
one entirely.  The arguments are what make this interesting: create demands
a MuPackage to evaluate (producing the new desired state snapshot), update
takes *both* an existing snapshot file plus a MuPackage to evaluate (producing
the new desired state snapshot to diff against the existing one), and delete
merely takes an existing snapshot file and no MuPackage, since all it must
do is tear down an existing known environment.

Replacing the plan functionality is the --dry-run (-n) flag that may be
passed to any of the above commands.  This will print out the plan without
actually performing any opterations.

All commands produce serializable resource files in the MuGL file format,
and attempt to do smart things with respect to backups, etc., to support the
intended "Git-oriented" workflow of the pure CLI dev experience.
2017-02-22 11:21:26 -08:00
joeduffy 26cac1af3a Move colors into a central location
Per Eric's suggestion, this moves the colors we use into a central
location so that it'll be easier someday down the road to reconfigure
and/or disable them, etc.  This does not include a --no-colors option
although we should really include this soon before it gets too hairy.
2017-02-21 18:49:51 -08:00
joeduffy d4911ad6f6 Implement snapshot MuGL
This change adds support for serializing snapshots in MuGL, per the
design document in docs/design/mugl.md.  At the moment, it is only
exposed from the `mu plan` command, which allows you to specify an
output location using `mu plan --output=file.json` (or `-o=file.json`
for short).  This serializes the snapshot with monikers, resources,
and so on.  Deserialization is not yet supported; that comes next.
2017-02-21 18:31:43 -08:00
joeduffy 0efb8bdd69 Fix a few things
* Specify MinCount/MaxCount when creating an EC2 instance.  These
  are required properties on the RunInstances API.

* Only attempt to unmarshal egressArray/ingressArray when non-nil.

* Remember the context object on the instanceProvider.

* Move the moniker and object maps into the shared context object.

* Marshal object monikers as the resource IDs to which they refer,
  since monikers are useless on "the other side" of the RPC boundary.
  This ensures that, for example, the AWS provider gets IDs it can use.

* Add some paranoia assertions.
2017-02-20 13:55:09 -08:00
joeduffy 81158d0fc2 Make property logic nil-sensitive
...and add some handy plugin-oriented logging.
2017-02-20 13:27:31 -08:00
joeduffy a9085ece0f Trace plugin STDOUT/STDERR 2017-02-20 12:34:15 -08:00
joeduffy f8cba5d752 Add interface members to prototypes
This change does two things:

First, and foremost, it adds interface members to prototypes.  This
ensures that interface members are available statically on all objects
of types that implement those interfaces.

Second, we permit dynamic loads through LoadLocationExpression when
the `this` object is `dynamic`.  This is a convenient shortcut compared
to creating different LoadDynamicExpressions when the `this` happens to
be of a dynamic type.
2017-02-20 12:20:59 -08:00
joeduffy 276b6c253d Implement a basic AWS resource provider
This commit includes a basic AWS resource provider.  Mostly it is just
scaffolding, however, it also includes prototype implementations for EC2
instance and security group resource creation operations.
2017-02-20 11:18:47 -08:00
joeduffy dbd1721ced Properly detect "missing file from PATH" os/exec errors 2017-02-19 12:23:26 -08:00
joeduffy 3618837092 Add plan apply progress reporting 2017-02-19 11:58:04 -08:00
joeduffy bfe659017f Implement the mu apply command
This change implements `mu apply`, by driving compilation, evaluation,
planning, and then walking the plan and evaluating it.  This is the bulk
of marapongo/mu#21, except that there's a ton of testing/hardening to
perform, in addition to things like progress reporting.
2017-02-19 11:41:05 -08:00
joeduffy 09c01dd942 Implement resource provider plugins
This change adds basic support for discovering, loading, binding to,
and invoking RPC methods on, resource provider plugins.

In a nutshell, we add a new context object that will share cached
state such as loaded plugins and connections to them.  It will be
a policy decision in server scenarios how much state to share and
between whom.  This context also controls per-resource context
allocation, which in the future will allow us to perform structured
cancellation and teardown amongst entire groups of requests.

Plugins are loaded based on their name, and can be found in one of
two ways: either simply by having them on your path (with a name of
"mu-ressrv-<pkg>", where "<pkg>" is the resource package name with
any "/"s replaced with "_"s); or by placing them in the standard
library installation location, which need not be on the path for this
to work (since we know precisely where to look).

If we find a protocol, we will load it as a child process.

The protocol for plugins is that they will choose a port on their
own -- to eliminate races that'd be involved should Mu attempt to
pre-pick one for them -- and then write that out as the first line
to STDOUT (terminated by a "\n").  This is the only STDERR/STDOUT
that Mu cares about; from there, the plugin is free to write all it
pleases (e.g., for logging, debugging purposes, etc).

Afterwards, we then bind our gRPC connection to that port, and create
a typed resource provider client.  The CRUD operations that get driven
by plan application are then simple wrappers atop the underlying gRPC
calls.  For now, we interpret all errors as catastrophic; in the near
future, we will probably want to introduce a "structured error"
mechanism in the gRPC interface for "transactional errors"; that is,
errors for which the server was able to recover to a safe checkpoint,
which can be interpreted as ResourceOK rather than ResourceUnknown.
2017-02-19 11:08:06 -08:00
joeduffy 6c25ff5cba Drive plan application
This moves us one step closer from planning to application (marapongo/mu#21).
Namely, we now drive the right resource provider operations in response to
the plan's steps.  Those providers, however, are still empty shells.
2017-02-18 11:54:24 -08:00
joeduffy 9621aa7201 Implement deletion plans
This change adds a flag to `plan` so that we can create deletion plans:

    $ mu plan --delete

This will have an equivalent in the `apply` command, achieving the ability
to delete entire sets of resources altogether (see marapongo/mu#58).
2017-02-18 10:33:36 -08:00
joeduffy 6f42e1134b Create object monikers
This change introduces object monikers.  These are unique, serializable
names that refer to resources created during the execution of a MuIL
program.  They are pretty darned ugly at the moment, but at least they
serve their desired purpose.  I suspect we will eventually want to use
more information (like edge "labels" (variable names and what not)),
but this should suffice for the time being.  The names right now are
particularly sensitive to simple refactorings.

This is enough for marapongo/mu#69 during the current sprint, although
I will keep the work item (in a later sprint) to think more about how
to make these more stable.  I'd prefer to do that with a bit of
experience under our belts first.
2017-02-18 10:22:04 -08:00
joeduffy d9ee2429da Begin resource modeling and planning
This change introduces a new package, pkg/resource, that will form
the foundation for actually performing deployment plans and applications.

It contains the following key abstractions:

* resource.Provider is a wrapper around the CRUD operations exposed by
  underlying resource plugins.  It will eventually defer to resource.Plugin,
  which itself defers -- over an RPC interface -- to the actual plugin, one
  per package exposing resources.  The provider will also understand how to
  load, cache, and overall manage the lifetime of each plugin.

* resource.Resource is the actual resource object.  This is created from
  the overall evaluation object graph, but is simplified.  It contains only
  serializable properties, for example.  Inter-resource references are
  translated into serializable monikers as part of creating the resource.

* resource.Moniker is a serializable string that uniquely identifies
  a resource in the Mu system.  This is in contrast to resource IDs, which
  are generated by resource providers and generally opaque to the Mu
  system.  See marapongo/mu#69 for more information about monikers and some
  of their challenges (namely, designing a stable algorithm).

* resource.Snapshot is a "snapshot" taken from a graph of resources.  This
  is a transitive closure of state representing one possible configuration
  of a given environment.  This is what plans are created from.  Eventually,
  two snapshots will be diffable, in order to perform incremental updates.
  One way of thinking about this is that a snapshot of the old world's state
  is advanced, one step at a time, until it reaches a desired snapshot of
  the new world's state.

* resource.Plan is a plan for carrying out desired CRUD operations on a target
  environment.  Each plan consists of zero-to-many Steps, each of which has
  a CRUD operation type, a resource target, and a next step.  This is an
  enumerator because it is possible the plan will evolve -- and introduce new
  steps -- as it is carried out (hence, the Next() method).  At the moment, this
  is linearized; eventually, we want to make this more "graph-like" so that we
  can exploit available parallelism within the dependencies.

There are tons of TODOs remaining.  However, the `mu plan` command is functioning
with these new changes -- including colorization FTW -- so I'm landing it now.

This is part of marapongo/mu#38 and marapongo/mu#41.
2017-02-17 12:31:48 -08:00
joeduffy 28a13a28cb Slightly prettify the plan command
This just makes it a little easier to see what's going on.
2017-02-16 17:32:13 -08:00
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 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 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 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 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 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 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 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 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 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 4a1a117d4e Create arrays of the right type; return the object 2017-02-12 13:42:53 -08:00
joeduffy 9375f38ba1 Don't store nulls 2017-02-12 13:36:34 -08:00
joeduffy bf6f6db089 Track all objects in MuGL
This change starts tracking all objects in our MuGL graph.  The reason is
that resources can be buried deep within a nest of objects, and unless we
do "on the fly" reachability analysis, we can't know a priori whether any
given object will be of interest or not.  So, we track 'em all.  For large
programs, this would obviously create space leak problems, so we'll
eventually, I assume, want to prune the graph at some point.

With this change, the EC2instance example produces a (gigantic) graph!
2017-02-12 13:11:53 -08:00
joeduffy 3f2f444bd7 Use the string *value*
This fixes a bug where we used the Stringer string, rather than the
underlying string literal value, when doing dynamic lookups.
2017-02-12 12:18:13 -08:00
joeduffy edb2fae7ba Register the local variable symbol, not its type 2017-02-12 11:49:19 -08:00
joeduffy d6405a7694 Dump eval state in sorted order
This eliminates some non-determinism in the output, due to Go's
randomized map enumeration order.
2017-02-12 10:21:37 -08:00
joeduffy 36b4a6f848 Implement stack traces
This change implements stack traces.  This is primarily so that we
can print out a full stack trace in the face of an unhandled exception,
and is done simply by recording the full trace during evaluation
alongside the existing local variable scopes.
2017-02-12 09:38:19 -08:00
joeduffy a16bb714e4 Implement dynamic loading
This change implements dynamic loads in the binder and evaluator.
2017-02-12 08:22:44 -08:00
joeduffy a8812bdbf0 Use strings for property keys
In dynamic scenarios, property keys could be arbitrary strings, including
invalid identifiers.  This change reflects that in the runtime representation
of objects and also in the object literal and overall indexing logic.
2017-02-11 15:45:37 -08:00
joeduffy b2d43e1c59 Permit dynamic to flow through to eval
This change "kicks the can" of dealing with `dynamic` down the road.
Namely, the binder will be permissive about letting dynamic objects
flow through to the evaluation phase.  At that point, the evaluator
will be responsible for performing duck typing, etc.
2017-02-11 08:39:45 -08:00
joeduffy 7a2d2b4cb1 Typecheck new expressions 2017-02-11 08:28:47 -08:00
joeduffy dc9f91c3cf Support dynamic object literals
This change introduces support for dynamic object literals.  If the
type of a literal is dynamic, then the property initializers for that
literal are naked strings; if the type of a literal is anything else,
however, we expect that the property names are full blown member tokens.
2017-02-11 08:20:06 -08:00
joeduffy 0802399a8c Distinguish between object and dynamic (fka any)
This change prepares to mimick the TypeScript behavior of `any` which,
it turns out, is closer to Python and Ruby duck typing than what we have
here.  It also introduces `object` to mean "the base of all types".

MuJS has been updated to map `any` to `dynamic`.

At this point, the conversion logic now distinguishes between NoConversion,
ImplicitConversion, and AutoCastConversion cases, the latter being a case
in which `dynamic` is the source and so a duck-type-style cast must occur.
Right now we do not honor the AutoCastConversion case anywhere, so we still
have not achieved the duck-typing semantics of the source language.

This is part of fixing marapongo/mu#79.
2017-02-10 16:44:18 -08:00
joeduffy fa69ed43f4 Tweak a couple error messages 2017-02-10 15:18:30 -08:00
joeduffy 11b7880547 Further reshuffle Protobufs; generate JavaScript code
After a bit more thinking, we will create new SDK packages for each
of the languages we wish to support writing resource providers in.
This is where the RPC goo will live, so I have created a new sdk/
directory, moved the Protobuf/gRPC definitions underneath sdk/proto/,
and put the generated code into sdk/go/ and sdk/js/.
2017-02-10 09:28:46 -08:00
joeduffy 6b60852c76 Generate Golang Protobuf/gRPC code
This change moves the RPC definitions to the pkg/murpc package,
underneath the proto folder.  This is to ensure that the resulting
Protobufs get a good package name "murpc" that is unique within the
overall toolchain.  It also includes a `generate.sh` script that
can be used to manually regenerate client/server code.  Finally,
we are actually checking in the generated files underneath pkg/murpc.
2017-02-10 09:08:06 -08:00
joeduffy 20452a99e1 Add Protobuf definitions for resource providers 2017-02-10 08:55:26 -08:00
joeduffy 6e472f8ab4 Colorize Mu output
This change adds colorization to the core Mu tool's output, similar
to what we added to MuJS in
cf6bbd460d.
2017-02-09 17:26:49 -08:00
joeduffy c333bf6f01 Tag an object moniker TODO with marapongo/mu#76 2017-02-09 16:02:45 -08:00