pulumi/pkg/encoding/decode_statements.go
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

195 lines
5 KiB
Go

// Copyright 2017 Pulumi, Inc. All rights reserved.
package encoding
import (
"reflect"
"github.com/pulumi/coconut/pkg/compiler/ast"
"github.com/pulumi/coconut/pkg/util/contract"
"github.com/pulumi/coconut/pkg/util/mapper"
)
func decodeStatement(m mapper.Mapper, tree mapper.Object) (ast.Statement, error) {
k, err := mapper.FieldString(tree, reflect.TypeOf((*ast.Statement)(nil)).Elem(), "kind", true)
if err != nil {
return nil, err
}
if k != nil {
kind := ast.NodeKind(*k)
switch kind {
// Imports
case ast.ImportKind:
return decodeImport(m, tree)
// Blocks
case ast.BlockKind:
return decodeBlock(m, tree)
// Local variables
case ast.LocalVariableDeclarationKind:
return decodeLocalVariableDeclaration(m, tree)
// Try/catch/finally
case ast.TryCatchFinallyKind:
return decodeTryCatchFinally(m, tree)
// Branches
case ast.BreakStatementKind:
return decodeBreakStatement(m, tree)
case ast.ContinueStatementKind:
return decodeContinueStatement(m, tree)
case ast.IfStatementKind:
return decodeIfStatement(m, tree)
case ast.SwitchStatementKind:
return decodeSwitchStatement(m, tree)
case ast.LabeledStatementKind:
return decodeLabeledStatement(m, tree)
case ast.ReturnStatementKind:
return decodeReturnStatement(m, tree)
case ast.ThrowStatementKind:
return decodeThrowStatement(m, tree)
case ast.WhileStatementKind:
return decodeWhileStatement(m, tree)
case ast.ForStatementKind:
return decodeForStatement(m, tree)
// Miscellaneous
case ast.EmptyStatementKind:
return decodeEmptyStatement(m, tree)
case ast.MultiStatementKind:
return decodeMultiStatement(m, tree)
case ast.ExpressionStatementKind:
return decodeExpressionStatement(m, tree)
default:
contract.Failf("Unrecognized Statement kind: %v\n", kind)
}
}
return nil, nil
}
func decodeImport(m mapper.Mapper, tree mapper.Object) (*ast.Import, error) {
var imp ast.Import
if err := m.Decode(tree, &imp); err != nil {
return nil, err
}
return &imp, nil
}
func decodeBlock(m mapper.Mapper, tree mapper.Object) (*ast.Block, error) {
var block ast.Block
if err := m.Decode(tree, &block); err != nil {
return nil, err
}
return &block, nil
}
func decodeLocalVariableDeclaration(m mapper.Mapper, tree mapper.Object) (*ast.LocalVariableDeclaration, error) {
var local ast.LocalVariableDeclaration
if err := m.Decode(tree, &local); err != nil {
return nil, err
}
return &local, nil
}
func decodeTryCatchFinally(m mapper.Mapper, tree mapper.Object) (*ast.TryCatchFinally, error) {
return nil, nil
}
func decodeBreakStatement(m mapper.Mapper, tree mapper.Object) (*ast.BreakStatement, error) {
var stmt ast.BreakStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeContinueStatement(m mapper.Mapper, tree mapper.Object) (*ast.ContinueStatement, error) {
var stmt ast.ContinueStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeIfStatement(m mapper.Mapper, tree mapper.Object) (*ast.IfStatement, error) {
var stmt ast.IfStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeSwitchStatement(m mapper.Mapper, tree mapper.Object) (*ast.SwitchStatement, error) {
var stmt ast.SwitchStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeLabeledStatement(m mapper.Mapper, tree mapper.Object) (*ast.LabeledStatement, error) {
var stmt ast.LabeledStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeReturnStatement(m mapper.Mapper, tree mapper.Object) (*ast.ReturnStatement, error) {
var stmt ast.ReturnStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeThrowStatement(m mapper.Mapper, tree mapper.Object) (*ast.ThrowStatement, error) {
var stmt ast.ThrowStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeWhileStatement(m mapper.Mapper, tree mapper.Object) (*ast.WhileStatement, error) {
var stmt ast.WhileStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeForStatement(m mapper.Mapper, tree mapper.Object) (*ast.ForStatement, error) {
var stmt ast.ForStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeEmptyStatement(m mapper.Mapper, tree mapper.Object) (*ast.EmptyStatement, error) {
var stmt ast.EmptyStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeMultiStatement(m mapper.Mapper, tree mapper.Object) (*ast.MultiStatement, error) {
var stmt ast.MultiStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}
func decodeExpressionStatement(m mapper.Mapper, tree mapper.Object) (*ast.ExpressionStatement, error) {
var stmt ast.ExpressionStatement
if err := m.Decode(tree, &stmt); err != nil {
return nil, err
}
return &stmt, nil
}