e96d4018ae
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.
195 lines
5 KiB
Go
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
|
|
}
|