32960be0fb
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.
92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
package encoding
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/ast"
|
|
"github.com/marapongo/mu/pkg/util/contract"
|
|
"github.com/marapongo/mu/pkg/util/mapper"
|
|
)
|
|
|
|
func decodeModuleMember(m mapper.Mapper, tree mapper.Object) (ast.ModuleMember, error) {
|
|
k, err := mapper.FieldString(tree, reflect.TypeOf((*ast.ModuleMember)(nil)).Elem(), "kind", true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if k != nil {
|
|
kind := ast.NodeKind(*k)
|
|
switch kind {
|
|
case ast.ClassKind:
|
|
return decodeClass(m, tree)
|
|
case ast.ModulePropertyKind:
|
|
return decodeModuleProperty(m, tree)
|
|
case ast.ModuleMethodKind:
|
|
return decodeModuleMethod(m, tree)
|
|
default:
|
|
contract.Failf("Unrecognized ModuleMember kind: %v\n", kind)
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func decodeClass(m mapper.Mapper, tree mapper.Object) (*ast.Class, error) {
|
|
var class ast.Class
|
|
if err := m.Decode(tree, &class); err != nil {
|
|
return nil, err
|
|
}
|
|
return &class, nil
|
|
}
|
|
|
|
func decodeClassMember(m mapper.Mapper, tree mapper.Object) (ast.ClassMember, error) {
|
|
k, err := mapper.FieldString(tree, reflect.TypeOf((*ast.ClassMember)(nil)).Elem(), "kind", true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if k != nil {
|
|
kind := ast.NodeKind(*k)
|
|
switch kind {
|
|
case ast.ClassPropertyKind:
|
|
return decodeClassProperty(m, tree)
|
|
case ast.ClassMethodKind:
|
|
return decodeClassMethod(m, tree)
|
|
default:
|
|
contract.Failf("Unrecognized ClassMember kind: %v\n", kind)
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func decodeClassProperty(m mapper.Mapper, tree mapper.Object) (*ast.ClassProperty, error) {
|
|
var prop ast.ClassProperty
|
|
if err := m.Decode(tree, &prop); err != nil {
|
|
return nil, err
|
|
}
|
|
return &prop, nil
|
|
}
|
|
|
|
func decodeClassMethod(m mapper.Mapper, tree mapper.Object) (*ast.ClassMethod, error) {
|
|
var meth ast.ClassMethod
|
|
if err := m.Decode(tree, &meth); err != nil {
|
|
return nil, err
|
|
}
|
|
return &meth, nil
|
|
}
|
|
|
|
func decodeModuleProperty(m mapper.Mapper, tree mapper.Object) (*ast.ModuleProperty, error) {
|
|
var prop ast.ModuleProperty
|
|
if err := m.Decode(tree, &prop); err != nil {
|
|
return nil, err
|
|
}
|
|
return &prop, nil
|
|
}
|
|
|
|
func decodeModuleMethod(m mapper.Mapper, tree mapper.Object) (*ast.ModuleMethod, error) {
|
|
var meth ast.ModuleMethod
|
|
if err := m.Decode(tree, &meth); err != nil {
|
|
return nil, err
|
|
}
|
|
return &meth, nil
|
|
}
|