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.
This commit is contained in:
parent
45a16b725f
commit
e96d4018ae
|
@ -188,22 +188,9 @@ func printModules(pkg *pack.Package, printSymbols bool, printExports bool, print
|
|||
|
||||
// Now, if requested, print the tokens.
|
||||
if printSymbols || printExports {
|
||||
if mod.Imports != nil || mod.Members != nil {
|
||||
if mod.Exports != nil || mod.Members != nil {
|
||||
fmt.Printf("\n")
|
||||
|
||||
if mod.Imports != nil {
|
||||
// Print the imports.
|
||||
fmt.Printf("%vimports [", indent+tab)
|
||||
if mod.Imports != nil && len(*mod.Imports) > 0 {
|
||||
fmt.Printf("\n")
|
||||
for _, imp := range *mod.Imports {
|
||||
fmt.Printf("%v\"%v\"\n", indent+tab+tab, imp.Tok)
|
||||
}
|
||||
fmt.Printf("%v", indent+tab)
|
||||
}
|
||||
fmt.Printf("]\n")
|
||||
}
|
||||
|
||||
exports := make(map[tokens.Token]bool)
|
||||
if mod.Exports != nil {
|
||||
// Print the exports.
|
||||
|
|
|
@ -31,9 +31,8 @@ func (node *DefinitionNode) GetDescription() *string { return node.Description }
|
|||
// Module contains members, including variables, functions, and/or classes.
|
||||
type Module struct {
|
||||
DefinitionNode
|
||||
Imports *[]*ModuleToken `json:"imports,omitempty"` // the imported modules consumed by this module.
|
||||
Exports *ModuleExports `json:"exports,omitempty"` // the exported symbols available for use by consuming modules.
|
||||
Members *ModuleMembers `json:"members,omitempty"` // the inner members of this module, private for its own use.
|
||||
Exports *ModuleExports `json:"exports,omitempty"` // the exported symbols available for use by consuming modules.
|
||||
Members *ModuleMembers `json:"members,omitempty"` // the inner members of this module, private for its own use.
|
||||
}
|
||||
|
||||
var _ Node = (*Module)(nil)
|
||||
|
|
|
@ -14,6 +14,21 @@ type StatementNode struct {
|
|||
|
||||
func (node *StatementNode) statement() {}
|
||||
|
||||
/* Imports */
|
||||
|
||||
// Import is mostly used to trigger the side-effect of importing another module. It is also used to make bound modules
|
||||
// or module member names available in the context of the importing module or function.
|
||||
type Import struct {
|
||||
StatementNode
|
||||
Referent *Token `json:"referent"` // the module or member token to import.
|
||||
Name *Identifier `json:"identifier,omitempty"` // the name that token is bound to (if any).
|
||||
}
|
||||
|
||||
var _ Node = (*Import)(nil)
|
||||
var _ Statement = (*Import)(nil)
|
||||
|
||||
const ImportKind NodeKind = "Import"
|
||||
|
||||
/* Blocks */
|
||||
|
||||
type Block struct {
|
||||
|
|
|
@ -79,6 +79,11 @@ func Walk(v Visitor, node Node) {
|
|||
// No children, nothing to do.
|
||||
|
||||
// Statements
|
||||
case *Import:
|
||||
Walk(v, n.Referent)
|
||||
if n.Name != nil {
|
||||
Walk(v, n.Name)
|
||||
}
|
||||
case *Block:
|
||||
for _, stmt := range n.Statements {
|
||||
Walk(v, stmt)
|
||||
|
|
|
@ -8,9 +8,7 @@ import (
|
|||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pulumi/coconut/pkg/compiler/ast"
|
||||
"github.com/pulumi/coconut/pkg/compiler/errors"
|
||||
"github.com/pulumi/coconut/pkg/compiler/symbols"
|
||||
"github.com/pulumi/coconut/pkg/tokens"
|
||||
"github.com/pulumi/coconut/pkg/util/contract"
|
||||
)
|
||||
|
||||
|
@ -112,29 +110,10 @@ func (b *binder) bindModuleExports(module *symbols.Module) {
|
|||
}
|
||||
|
||||
func (b *binder) bindModuleDefinitions(module *symbols.Module) {
|
||||
// Now we can bind module imports.
|
||||
b.bindModuleImports(module)
|
||||
|
||||
// And finish binding the members themselves.
|
||||
b.bindModuleMemberDefinitions(module)
|
||||
}
|
||||
|
||||
// bindModuleImports binds module import tokens to their symbols. This is done as a second pass just in case there are
|
||||
// inter-module dependencies.
|
||||
func (b *binder) bindModuleImports(module *symbols.Module) {
|
||||
// Now bind all imports to concrete symbols: these are simple token bindings.
|
||||
if module.Node.Imports != nil {
|
||||
for _, imptok := range *module.Node.Imports {
|
||||
if !tokens.Token(imptok.Tok).HasModule() {
|
||||
b.Diag().Errorf(errors.ErrorMalformedToken.At(imptok),
|
||||
"Module", imptok.Tok, "missing module part")
|
||||
} else if imp := b.ctx.LookupModule(imptok); imp != nil {
|
||||
module.Imports = append(module.Imports, imp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bindModuleMemberDefinitions finishes binding module members, by doing lookups sensitive to the definition pass.
|
||||
func (b *binder) bindModuleMemberDefinitions(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' member defns", module.Token())
|
||||
|
|
|
@ -118,10 +118,12 @@ func (b *binder) resolveDep(dep pack.PackageURL) *symbols.ResolvedPackage {
|
|||
b.Diag().Errorf(errors.ErrorCouldNotReadPackage.AtFile(loc), err)
|
||||
return nil
|
||||
}
|
||||
pkg := b.reader.ReadPackage(doc)
|
||||
|
||||
// Now perform the binding and return it.
|
||||
return b.resolveBindPackage(pkg, dep)
|
||||
if pkg := b.reader.ReadPackage(doc); pkg != nil {
|
||||
// Now perform the binding and return it.
|
||||
return b.resolveBindPackage(pkg, dep)
|
||||
}
|
||||
contract.Assert(!b.Diag().Success())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,6 +136,17 @@ func (a *astBinder) isLValue(expr ast.Expression) bool {
|
|||
|
||||
// Statements
|
||||
|
||||
func (a *astBinder) checkImport(node *ast.Import) {
|
||||
imptok := node.Referent
|
||||
if !tokens.Token(imptok.Tok).HasModule() {
|
||||
a.b.Diag().Errorf(errors.ErrorMalformedToken.At(imptok),
|
||||
"Module", imptok.Tok, "missing module part")
|
||||
} else {
|
||||
// Just perform a lookup to ensure the symbol exists (and error out if not).
|
||||
a.b.ctx.LookupSymbol(imptok, imptok.Tok, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *astBinder) visitBlock(node *ast.Block) {
|
||||
// Entering a new block requires a fresh lexical scope.
|
||||
a.b.ctx.Scope.Push(false)
|
||||
|
|
|
@ -13,7 +13,6 @@ type Module struct {
|
|||
Node *ast.Module
|
||||
Parent *Package
|
||||
Tok tokens.Module
|
||||
Imports Modules
|
||||
Exports ModuleExportMap
|
||||
Members ModuleMemberMap
|
||||
}
|
||||
|
@ -43,7 +42,6 @@ func NewModuleSym(node *ast.Module, parent *Package) *Module {
|
|||
Node: node,
|
||||
Parent: parent,
|
||||
Tok: tokens.NewModuleToken(parent.Tok, tokens.ModuleName(node.Name.Ident)),
|
||||
Imports: make(Modules, 0),
|
||||
Exports: make(ModuleExportMap),
|
||||
Members: make(ModuleMemberMap),
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ func decodeStatement(m mapper.Mapper, tree mapper.Object) (ast.Statement, error)
|
|||
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)
|
||||
|
@ -65,6 +69,14 @@ func decodeStatement(m mapper.Mapper, tree mapper.Object) (ast.Statement, error)
|
|||
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 {
|
||||
|
|
|
@ -348,11 +348,6 @@ func (e *evaluator) ensureModuleInit(mod *symbols.Module) {
|
|||
e.modinits[mod] = true // set true before running, in case of cycles.
|
||||
|
||||
if !already {
|
||||
// First ensure all imported module initializers are run, in the order in which they were given.
|
||||
for _, imp := range mod.Imports {
|
||||
e.ensureModuleInit(imp)
|
||||
}
|
||||
|
||||
// Populate all properties in this module, even if they will be empty for now.
|
||||
var readonlines []*rt.Pointer
|
||||
globals := e.getModuleGlobals(mod)
|
||||
|
@ -665,6 +660,8 @@ func (e *evaluator) evalStatement(node ast.Statement) *rt.Unwind {
|
|||
|
||||
// Simply switch on the node type and dispatch to the specific function, returning the rt.Unwind info.
|
||||
switch n := node.(type) {
|
||||
case *ast.Import:
|
||||
return e.evalImport(n)
|
||||
case *ast.Block:
|
||||
return e.evalBlock(n)
|
||||
case *ast.LocalVariableDeclaration:
|
||||
|
@ -701,6 +698,23 @@ func (e *evaluator) evalStatement(node ast.Statement) *rt.Unwind {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *evaluator) evalImport(node *ast.Import) *rt.Unwind {
|
||||
// Ensure the target module has been initialized.
|
||||
contract.Assertf(node.Name == nil, "Dynamically bound import names not yet supported")
|
||||
imptok := node.Referent
|
||||
sym := e.ctx.LookupSymbol(imptok, imptok.Tok, true)
|
||||
contract.Assert(sym != nil)
|
||||
switch s := sym.(type) {
|
||||
case *symbols.Module:
|
||||
e.ensureModuleInit(s)
|
||||
case symbols.ModuleMember:
|
||||
e.ensureModuleInit(s.MemberParent())
|
||||
default:
|
||||
contract.Failf("Unrecognized import symbol: %v", reflect.TypeOf(sym))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *evaluator) evalBlock(node *ast.Block) *rt.Unwind {
|
||||
// Push a scope at the start, and pop it at afterwards; both for the symbol context and local variable values.
|
||||
e.pushScope(nil)
|
||||
|
|
|
@ -19,7 +19,6 @@ export interface Definition extends Node {
|
|||
// A module contains members, including variables, functions, and/or classes.
|
||||
export interface Module extends Definition {
|
||||
kind: ModuleKind;
|
||||
imports?: ModuleToken[]; // an ordered list of import modules to initialize.
|
||||
exports?: ModuleExports; // a list of exported members, keyed by name.
|
||||
members?: ModuleMembers; // a list of members, keyed by their simple name.
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export type NodeKind =
|
|||
definitions.ClassMethodKind |
|
||||
definitions.ModuleMethodKind |
|
||||
|
||||
statements.ImportKind |
|
||||
statements.BlockKind |
|
||||
statements.LocalVariableDeclarationKind |
|
||||
statements.TryCatchFinallyKind |
|
||||
|
|
|
@ -2,10 +2,20 @@
|
|||
|
||||
import {LocalVariable} from "./definitions";
|
||||
import {Expression} from "./expressions";
|
||||
import {Identifier, Node} from "./nodes";
|
||||
import {Identifier, Node, Token} from "./nodes";
|
||||
|
||||
export interface Statement extends Node {}
|
||||
|
||||
/** Imports **/
|
||||
|
||||
export interface Import extends Statement {
|
||||
kind: ImportKind;
|
||||
referent: Token;
|
||||
name?: Identifier;
|
||||
}
|
||||
export const importKind = "Import";
|
||||
export type ImportKind = "Import";
|
||||
|
||||
/** Blocks **/
|
||||
|
||||
export interface Block extends Statement {
|
||||
|
|
|
@ -210,7 +210,6 @@ export class Transformer {
|
|||
private currentModuleMembers: ast.ModuleMembers | undefined;
|
||||
private currentModuleExports: ast.ModuleExports | undefined;
|
||||
private currentModuleImports: Map<string, ModuleReference>;
|
||||
private currentModuleImportTokens: ast.ModuleToken[];
|
||||
private currentClassToken: tokens.TypeToken | undefined;
|
||||
private currentSuperClassToken: tokens.TypeToken | undefined;
|
||||
private currentPackageDependencies: Set<tokens.PackageToken>;
|
||||
|
@ -1019,7 +1018,6 @@ export class Transformer {
|
|||
let priorModuleMembers: ast.ModuleMembers | undefined = this.currentModuleMembers;
|
||||
let priorModuleExports: ast.ModuleExports | undefined = this.currentModuleExports;
|
||||
let priorModuleImports: Map<string, ModuleReference> | undefined = this.currentModuleImports;
|
||||
let priorModuleImportTokens: ast.ModuleToken[] | undefined = this.currentModuleImportTokens;
|
||||
let priorTempLocalCounter: number = this.currentTempLocalCounter;
|
||||
try {
|
||||
// Prepare self-referential module information.
|
||||
|
@ -1034,7 +1032,6 @@ export class Transformer {
|
|||
this.currentModuleMembers = {};
|
||||
this.currentModuleExports = {};
|
||||
this.currentModuleImports = new Map<string, ModuleReference>();
|
||||
this.currentModuleImportTokens = []; // to track the imports, in order.
|
||||
this.currentTempLocalCounter = 0;
|
||||
|
||||
// Any top-level non-definition statements will pile up into the module initializer.
|
||||
|
@ -1115,7 +1112,6 @@ export class Transformer {
|
|||
return this.withLocation(node, <ast.Module>{
|
||||
kind: ast.moduleKind,
|
||||
name: ident(this.getModuleName(modtok)),
|
||||
imports: this.currentModuleImportTokens,
|
||||
exports: this.currentModuleExports,
|
||||
members: this.currentModuleMembers,
|
||||
});
|
||||
|
@ -1126,7 +1122,6 @@ export class Transformer {
|
|||
this.currentModuleMembers = priorModuleMembers;
|
||||
this.currentModuleExports = priorModuleExports;
|
||||
this.currentModuleImports = priorModuleImports;
|
||||
this.currentModuleImportTokens = priorModuleImportTokens;
|
||||
this.currentTempLocalCounter = priorTempLocalCounter;
|
||||
}
|
||||
}
|
||||
|
@ -1145,8 +1140,6 @@ export class Transformer {
|
|||
return [ this.transformExportAssignment(<ts.ExportAssignment>node) ];
|
||||
case ts.SyntaxKind.ExportDeclaration:
|
||||
return this.transformExportDeclaration(<ts.ExportDeclaration>node);
|
||||
case ts.SyntaxKind.ImportDeclaration:
|
||||
return [ await this.transformImportDeclaration(<ts.ImportDeclaration>node) ];
|
||||
|
||||
// Handle declarations; each of these results in a definition.
|
||||
case ts.SyntaxKind.ClassDeclaration:
|
||||
|
@ -1320,7 +1313,7 @@ export class Transformer {
|
|||
return exports;
|
||||
}
|
||||
|
||||
private async transformImportDeclaration(node: ts.ImportDeclaration): Promise<ModuleElement> {
|
||||
private async transformImportDeclaration(node: ts.ImportDeclaration): Promise<ast.Statement> {
|
||||
// An import declaration is erased in the output AST, however, we must keep track of the set of known import
|
||||
// names so that we can easily look them up by name later on (e.g., in the case of reexporting whole modules).
|
||||
if (node.importClause) {
|
||||
|
@ -1329,10 +1322,6 @@ export class Transformer {
|
|||
contract.assert(node.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral);
|
||||
let importModule: ModuleReference =
|
||||
this.resolveModuleReferenceByName((<ts.StringLiteral>node.moduleSpecifier).text);
|
||||
let importModuleToken: ast.ModuleToken = this.withLocation(node.moduleSpecifier, <ast.ModuleToken>{
|
||||
kind: ast.moduleTokenKind,
|
||||
tok: await this.createModuleToken(importModule),
|
||||
});
|
||||
|
||||
// Figure out what kind of import statement this is (there are many, see below).
|
||||
let name: ts.Identifier | undefined;
|
||||
|
@ -1384,8 +1373,15 @@ export class Transformer {
|
|||
}
|
||||
|
||||
// Now keep track of the import.
|
||||
this.currentModuleImportTokens.push(importModuleToken);
|
||||
return <ast.Import>{
|
||||
kind: ast.importKind,
|
||||
referent: this.withLocation(node.moduleSpecifier, <ast.Token>{
|
||||
kind: ast.tokenKind,
|
||||
tok: await this.createModuleToken(importModule),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return <ast.EmptyStatement>{ kind: ast.emptyStatementKind };
|
||||
}
|
||||
|
||||
|
@ -1436,6 +1432,8 @@ export class Transformer {
|
|||
return this.transformWhileStatement(<ts.WhileStatement>node);
|
||||
|
||||
// Miscellaneous statements:
|
||||
case ts.SyntaxKind.ImportDeclaration:
|
||||
return this.transformImportDeclaration(<ts.ImportDeclaration>node);
|
||||
case ts.SyntaxKind.Block:
|
||||
return this.transformBlock(<ts.Block>node);
|
||||
case ts.SyntaxKind.DebuggerStatement:
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"a1": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"a": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
".main": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
".main": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"loops": {
|
||||
|
@ -348,11 +347,11 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 9,
|
||||
"column": 14
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 9,
|
||||
"column": 16
|
||||
"column": 17
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -364,7 +363,7 @@
|
|||
},
|
||||
"end": {
|
||||
"line": 9,
|
||||
"column": 16
|
||||
"column": 17
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -406,7 +405,7 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 9,
|
||||
"column": 18
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 11,
|
||||
|
@ -844,11 +843,11 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 15,
|
||||
"column": 18
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 15,
|
||||
"column": 19
|
||||
"column": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -860,7 +859,7 @@
|
|||
},
|
||||
"end": {
|
||||
"line": 15,
|
||||
"column": 19
|
||||
"column": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -946,7 +945,7 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 15,
|
||||
"column": 21
|
||||
"column": 22
|
||||
},
|
||||
"end": {
|
||||
"line": 17,
|
||||
|
@ -1461,11 +1460,11 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 29,
|
||||
"column": 10
|
||||
"column": 11
|
||||
},
|
||||
"end": {
|
||||
"line": 29,
|
||||
"column": 12
|
||||
"column": 13
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1477,7 +1476,7 @@
|
|||
},
|
||||
"end": {
|
||||
"line": 29,
|
||||
"column": 12
|
||||
"column": 13
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1519,7 +1518,7 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 29,
|
||||
"column": 14
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 31,
|
||||
|
@ -1905,11 +1904,11 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 35,
|
||||
"column": 14
|
||||
"column": 15
|
||||
},
|
||||
"end": {
|
||||
"line": 35,
|
||||
"column": 15
|
||||
"column": 16
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1921,7 +1920,7 @@
|
|||
},
|
||||
"end": {
|
||||
"line": 35,
|
||||
"column": 15
|
||||
"column": 16
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2007,7 +2006,7 @@
|
|||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 35,
|
||||
"column": 17
|
||||
"column": 18
|
||||
},
|
||||
"end": {
|
||||
"line": 37,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"C": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"au": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"modprop": {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"B": {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"C": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"default": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "other"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"D": {
|
||||
"kind": "Export",
|
||||
|
@ -354,23 +353,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [
|
||||
{
|
||||
"kind": "ModuleToken",
|
||||
"tok": "export:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 24
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 33
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"exports": {
|
||||
"other": {
|
||||
"kind": "Export",
|
||||
|
@ -654,6 +636,24 @@
|
|||
"body": {
|
||||
"kind": "Block",
|
||||
"statements": [
|
||||
{
|
||||
"kind": "Import",
|
||||
"referent": {
|
||||
"kind": "Token",
|
||||
"tok": "export:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 24
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 33
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ExpressionStatement",
|
||||
"expression": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"foo": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "other"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"foo": {
|
||||
"kind": "Export",
|
||||
|
@ -130,38 +129,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [
|
||||
{
|
||||
"kind": "ModuleToken",
|
||||
"tok": "modules/func_cross_call:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 28
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ModuleToken",
|
||||
"tok": "modules/func_cross_call:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 24
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 33
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"exports": {},
|
||||
"members": {
|
||||
".init": {
|
||||
|
@ -173,6 +140,42 @@
|
|||
"body": {
|
||||
"kind": "Block",
|
||||
"statements": [
|
||||
{
|
||||
"kind": "Import",
|
||||
"referent": {
|
||||
"kind": "Token",
|
||||
"tok": "modules/func_cross_call:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 1,
|
||||
"column": 19
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"column": 28
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Import",
|
||||
"referent": {
|
||||
"kind": "Token",
|
||||
"tok": "modules/func_cross_call:other",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
"line": 2,
|
||||
"column": 24
|
||||
},
|
||||
"end": {
|
||||
"line": 2,
|
||||
"column": 33
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ExpressionStatement",
|
||||
"expression": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"foo": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"default": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"I": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"I": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"A": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "other"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
@ -354,7 +353,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "other"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
@ -354,7 +353,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "other"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"C": {
|
||||
"kind": "Export",
|
||||
|
@ -354,7 +353,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"D": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {},
|
||||
"members": {
|
||||
"x": {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"x": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
"kind": "Identifier",
|
||||
"ident": "index"
|
||||
},
|
||||
"imports": [],
|
||||
"exports": {
|
||||
"Point": {
|
||||
"kind": "Export",
|
||||
|
|
|
@ -94,10 +94,8 @@ class Definition(Node):
|
|||
|
||||
class Module(Definition):
|
||||
"""A module contains members, including variables, functions, and/or classes."""
|
||||
def __init__(self, name, imports=None, exports=None, members=None, loc=None):
|
||||
def __init__(self, name, exports=None, members=None, loc=None):
|
||||
assert isinstance(name, Identifier)
|
||||
assert (imports is None or
|
||||
(isinstance(imports, list) and all(isinstance(node, ModuleToken) for node in imports)))
|
||||
assert (exports is None or
|
||||
(isinstance(exports, dict) and
|
||||
all(isinstance(key, basestring) for key in exports.keys()) and
|
||||
|
@ -107,7 +105,6 @@ class Module(Definition):
|
|||
all(isinstance(key, basestring) for key in members.keys()) and
|
||||
all(isinstance(value, ModuleMember) for value in members.values())))
|
||||
super(Module, self).__init__("Module", name, loc=loc)
|
||||
self.imports = imports
|
||||
self.exports = exports
|
||||
self.members = members
|
||||
|
||||
|
@ -263,6 +260,16 @@ class Statement(Node):
|
|||
assert isinstance(kind, basestring)
|
||||
super(Statement, self).__init__(kind, loc)
|
||||
|
||||
# ...Imports
|
||||
|
||||
class Import(Statement):
|
||||
def __init__(self, referent, name=None, loc=None):
|
||||
assert isinstance(referent, Token)
|
||||
assert name is None or isinstance(name, Identifier)
|
||||
super(Import, self).__init__("Import", loc)
|
||||
self.referent = referent
|
||||
self.name = name
|
||||
|
||||
# ...Blocks
|
||||
|
||||
class Block(Statement):
|
||||
|
|
|
@ -111,7 +111,6 @@ class Transformer:
|
|||
assert self.ctx, "Transform passes require a context object"
|
||||
members = dict()
|
||||
initstmts = list()
|
||||
imports = set()
|
||||
modtok = self.current_module_token()
|
||||
|
||||
# Auto-generate the special __name__ variable and populate it in the initializer.
|
||||
|
@ -137,8 +136,6 @@ class Transformer:
|
|||
elif isinstance(stmt, py_ast.ClassDef):
|
||||
clazz = self.transform_ClassDef(stmt)
|
||||
members[clazz.name.ident] = clazz
|
||||
elif isinstance(stmt, py_ast.Import):
|
||||
imports |= self.transform_Import(stmt)
|
||||
else:
|
||||
# For all other statement nodes, simply accumulate them for the module initializer.
|
||||
initstmt = self.transform_stmt(stmt)
|
||||
|
@ -168,7 +165,7 @@ class Transformer:
|
|||
tok = modtok + tokens.delim + name
|
||||
exports[name] = ast.Export(self.ident(name), ast.Token(tok))
|
||||
|
||||
return ast.Module(self.ident(self.ctx.mod.name), list(imports), exports, members)
|
||||
return ast.Module(self.ident(self.ctx.mod.name), exports, members)
|
||||
|
||||
# ...Statements
|
||||
|
||||
|
@ -201,9 +198,9 @@ class Transformer:
|
|||
elif isinstance(node, py_ast.If):
|
||||
stmt = self.transform_If(node)
|
||||
elif isinstance(node, py_ast.Import):
|
||||
assert False, "TODO: imports in non-top-level positions not yet supported"
|
||||
stmt = self.transform_Import(node)
|
||||
elif isinstance(node, py_ast.ImportFrom):
|
||||
assert False, "TODO: imports in non-top-level positions not yet supported"
|
||||
stmt = self.transform_ImportFrom(node)
|
||||
elif isinstance(node, py_ast.Nonlocal):
|
||||
stmt = self.transform_Nonlocal(node)
|
||||
elif isinstance(node, py_ast.Pass):
|
||||
|
@ -331,26 +328,29 @@ class Transformer:
|
|||
|
||||
def transform_Import(self, node):
|
||||
"""Transforms an import clause into a set of AST nodes representing the imported module tokens."""
|
||||
# TODO: support imports inside of non-top-level scopes.
|
||||
# TODO: come up with a way to determine intra-project references.
|
||||
imports = set()
|
||||
imports = list()
|
||||
for namenode in node.names:
|
||||
# Python module names are dot-delimited; we need to translate into "/" delimited names.
|
||||
name = namenode.name.replace(".", tokens.name_delim)
|
||||
tok = namenode.name.replace(".", tokens.name_delim)
|
||||
|
||||
# Now transform the module name into a qualified package/module token.
|
||||
# TODO: this heuristic isn't perfect; I think we should load up the target package and read its manifest
|
||||
# to figure out the precise package naming, etc. (since packages can be multi-part too).
|
||||
delimix = name.find(tokens.name_delim)
|
||||
delimix = tok.find(tokens.name_delim)
|
||||
if delimix == -1:
|
||||
# If just the package, we will use the default module.
|
||||
name = name + tokens.delim + tokens.mod_default
|
||||
tok = tok + tokens.delim + tokens.mod_default
|
||||
else:
|
||||
# Otherwise, use the first part as the package, and the remainder as the module.
|
||||
name = name[:delimix] + tokens.delim + name[delimix+1:]
|
||||
tok = tok[:delimix] + tokens.delim + tok[delimix+1:]
|
||||
|
||||
imports.add(ast.ModuleToken(name, loc=self.loc_from(namenode)))
|
||||
return imports
|
||||
toknode = ast.Token(tok, loc=self.loc_from(namenode))
|
||||
imports.append(ast.Import(toknode, loc=self.loc_from(node)))
|
||||
|
||||
if len(imports) > 0:
|
||||
return ast.MultiStatement(imports)
|
||||
return imports[0]
|
||||
|
||||
def transform_ImportFrom(self, node):
|
||||
# TODO: to support this, we will need a way of binding names back to the imported names. Furthermore, we
|
||||
|
|
Loading…
Reference in a new issue