diff --git a/pkg/compiler/ast/expressions.go b/pkg/compiler/ast/expressions.go index 016124dbb..51478b9d7 100644 --- a/pkg/compiler/ast/expressions.go +++ b/pkg/compiler/ast/expressions.go @@ -104,8 +104,8 @@ const ObjectLiteralKind NodeKind = "ObjectLiteral" // ObjectLiteralProperty initializes a single object literal property. type ObjectLiteralProperty struct { NodeValue - Name *Identifier `json:"name"` // the property to initialize. - Value Expression `json:"value"` // the expression whose value to store into the property. + Property *ClassMemberToken `json:"property"` // the property to initialize. + Value Expression `json:"value"` // the expression whose value to store into the property. } var _ Node = (*ObjectLiteralProperty)(nil) diff --git a/pkg/compiler/ast/nodes.go b/pkg/compiler/ast/nodes.go index 1fb52680b..ed012493f 100644 --- a/pkg/compiler/ast/nodes.go +++ b/pkg/compiler/ast/nodes.go @@ -78,6 +78,14 @@ type Token struct { const TokenKind NodeKind = "Token" +// ClassMemberToken represents a real string class member token associated with its source location context. +type ClassMemberToken struct { + NodeValue + Tok tokens.ClassMember `json:"tok"` +} + +const ClassMemberTokenKind NodeKind = "ClassMemberToken" + // ModuleToken represents a real string type token associated with its source location context. type ModuleToken struct { NodeValue diff --git a/pkg/compiler/ast/walk.go b/pkg/compiler/ast/walk.go index 3c38bb8b7..14980c103 100644 --- a/pkg/compiler/ast/walk.go +++ b/pkg/compiler/ast/walk.go @@ -129,7 +129,7 @@ func Walk(v Visitor, node Node) { } } case *ObjectLiteralProperty: - Walk(v, n.Name) + Walk(v, n.Property) Walk(v, n.Value) case *LoadLocationExpression: if n.Object != nil { diff --git a/pkg/compiler/binder/binder.go b/pkg/compiler/binder/binder.go index 057850b90..12fbad8ff 100644 --- a/pkg/compiler/binder/binder.go +++ b/pkg/compiler/binder/binder.go @@ -187,7 +187,7 @@ func (b *binder) lookupSymbolToken(node ast.Node, tok tokens.Token, require bool if clmnm == "" { sym = member } else if class, isclass := member.(*symbols.Class); isclass { - if clmember, has := class.Members[clmnm]; has { + if clmember, has := class.Clmembers[clmnm]; has { // The member was found; validate that it's got the right accessibility. b.checkClassVisibility(node, class, clmember) sym = clmember @@ -211,6 +211,7 @@ func (b *binder) lookupSymbolToken(node ast.Node, tok tokens.Token, require bool glog.V(5).Info("Failed to bind qualified token; %v: '%v'", extra, tok) if require { // If requested, issue an error. + // TODO: edit distance checking to help suggest a fix. b.Diag().Errorf(errors.ErrorSymbolNotFound.At(node), tok, extra) } } @@ -283,7 +284,7 @@ func (b *binder) requireFunctionType(node ast.Function) *symbols.FunctionType { // registerFunctionType understands how to turn any function node into a type, and adds it to the type table. This // works for any kind of function-like AST node: module property, class property, or lambda. -func (b *binder) registerFunctionType(node ast.Function) { +func (b *binder) registerFunctionType(node ast.Function) *symbols.FunctionType { // Make a function type and inject it into the type table. var params []symbols.Type np := node.GetParameters() @@ -316,6 +317,8 @@ func (b *binder) registerFunctionType(node ast.Function) { glog.V(7).Infof("Registered function type: '%v' => %v", node.GetName().Ident, tysym.Name()) } b.types[node] = tysym + + return tysym } // requireVariableType fetches the non-nil registered type for a given variable. @@ -325,7 +328,7 @@ func (b *binder) requireVariableType(node ast.Variable) symbols.Type { // registerVariableType understands how to turn any variable node into a type, and adds it to the type table. This // works for any kind of variable-like AST node: module property, class property, parameter, or local variable. -func (b *binder) registerVariableType(node ast.Variable) { +func (b *binder) registerVariableType(node ast.Variable) symbols.Type { var tysym symbols.Type // If there is an explicit node type, use it. @@ -343,4 +346,6 @@ func (b *binder) registerVariableType(node ast.Variable) { glog.V(7).Infof("Registered variable type: '%v' => %v", node.GetName().Ident, tysym.Name()) } b.types[node] = tysym + + return tysym } diff --git a/pkg/compiler/binder/class.go b/pkg/compiler/binder/class.go index 5992bffab..d8e8e3054 100644 --- a/pkg/compiler/binder/class.go +++ b/pkg/compiler/binder/class.go @@ -38,7 +38,7 @@ func (b *binder) bindClass(node *ast.Class, parent *symbols.Module) *symbols.Cla // Next, bind each member at the symbolic level; in particular, we do not yet bind bodies of methods. if node.Members != nil { for memtok, member := range *node.Members { - class.Members[memtok] = b.bindClassMember(member, class) + class.Clmembers[memtok] = b.bindClassMember(member, class) } } @@ -61,19 +61,19 @@ func (b *binder) bindClassProperty(node *ast.ClassProperty, parent *symbols.Clas glog.V(3).Infof("Binding class '%v' property '%v'", parent.Name(), node.Name.Ident) // Look up this node's type and inject it into the type table. - b.registerVariableType(node) - return symbols.NewClassPropertySym(node, parent) + ty := b.registerVariableType(node) + return symbols.NewClassPropertySym(node, parent, ty) } func (b *binder) bindClassMethod(node *ast.ClassMethod, parent *symbols.Class) *symbols.ClassMethod { glog.V(3).Infof("Binding class '%v' method '%v'", parent.Name(), node.Name.Ident) // Make a function type out of this method and inject it into the type table. - b.registerFunctionType(node) + ty := b.registerFunctionType(node) // Note that we don't actually bind the body of this method yet. Until we have gone ahead and injected *all* // top-level symbols into the type table, we would potentially encounter missing intra-module symbols. - return symbols.NewClassMethodSym(node, parent) + return symbols.NewClassMethodSym(node, parent, ty) } func (b *binder) bindClassMethodBody(method *symbols.ClassMethod) { diff --git a/pkg/compiler/binder/func.go b/pkg/compiler/binder/func.go new file mode 100644 index 000000000..fa81d493d --- /dev/null +++ b/pkg/compiler/binder/func.go @@ -0,0 +1,29 @@ +// Copyright 2016 Marapongo, Inc. All rights reserved. + +package binder + +import ( + "github.com/marapongo/mu/pkg/compiler/ast" + "github.com/marapongo/mu/pkg/compiler/symbols" +) + +// bindFunctionBody binds a function body, including a scope, its parameters, and its expressions and statements. +func (b *binder) bindFunctionBody(node ast.Function) { + // Enter a new scope, bind the parameters, and then bind the body using a visitor. + scope := b.scope.Push() + defer scope.Pop() + params := node.GetParameters() + if params != nil { + for _, param := range *params { + // Register this variable's type and associate its name with the identifier. + b.registerVariableType(param) + b.scope.TryRegister(param, symbols.NewLocalVariableSym(param)) + } + } + + body := node.GetBody() + if body != nil { + v := newASTBinder(b, node) + ast.Walk(v, body) + } +} diff --git a/pkg/compiler/binder/module.go b/pkg/compiler/binder/module.go index 00868afdc..812f619bf 100644 --- a/pkg/compiler/binder/module.go +++ b/pkg/compiler/binder/module.go @@ -74,19 +74,19 @@ func (b *binder) bindModuleProperty(node *ast.ModuleProperty, parent *symbols.Mo glog.V(3).Infof("Binding module '%v' property '%v'", parent.Name(), node.Name.Ident) // Look up this node's type and inject it into the type table. - b.registerVariableType(node) - return symbols.NewModulePropertySym(node, parent) + ty := b.registerVariableType(node) + return symbols.NewModulePropertySym(node, parent, ty) } func (b *binder) bindModuleMethod(node *ast.ModuleMethod, parent *symbols.Module) *symbols.ModuleMethod { glog.V(3).Infof("Binding module '%v' method '%v'", parent.Name(), node.Name.Ident) // Make a function type out of this method and inject it into the type table. - b.registerFunctionType(node) + ty := b.registerFunctionType(node) // Note that we don't actually bind the body of this method yet. Until we have gone ahead and injected *all* // top-level symbols into the type table, we would potentially encounter missing intra-module symbols. - return symbols.NewModuleMethodSym(node, parent) + return symbols.NewModuleMethodSym(node, parent, ty) } func (b *binder) bindModuleBodies(module *symbols.Module) { @@ -102,7 +102,7 @@ func (b *binder) bindModuleBodies(module *symbols.Module) { case *symbols.ModuleMethod: b.bindModuleMethodBody(m) case *symbols.Class: - for _, cmember := range m.Members { + for _, cmember := range m.Clmembers { switch cm := cmember.(type) { case *symbols.ClassMethod: b.bindClassMethodBody(cm) diff --git a/pkg/compiler/binder/function.go b/pkg/compiler/binder/stmtexpr.go similarity index 89% rename from pkg/compiler/binder/function.go rename to pkg/compiler/binder/stmtexpr.go index f46172820..551f0a5e3 100644 --- a/pkg/compiler/binder/function.go +++ b/pkg/compiler/binder/stmtexpr.go @@ -11,27 +11,6 @@ import ( "github.com/marapongo/mu/pkg/util/contract" ) -// bindFunctionBody binds a function body, including a scope, its parameters, and its expressions and statements. -func (b *binder) bindFunctionBody(node ast.Function) { - // Enter a new scope, bind the parameters, and then bind the body using a visitor. - scope := b.scope.Push() - defer scope.Pop() - params := node.GetParameters() - if params != nil { - for _, param := range *params { - // Register this variable's type and associate its name with the identifier. - b.registerVariableType(param) - b.scope.TryRegister(param, symbols.NewLocalVariableSym(param)) - } - } - - body := node.GetBody() - if body != nil { - v := newASTBinder(b, node) - ast.Walk(v, body) - } -} - // astBinder is an AST visitor implementation that understands how to deal with all sorts of node types. It // does not visit children, however, as it relies on the depth-first order walk supplied by the AST package. The // overall purpose of this is to perform validation, and record types and symbols that're needed during evaluation. @@ -243,8 +222,39 @@ func (a *astBinder) checkObjectLiteral(node *ast.ObjectLiteral) { if node.Type == nil { a.b.registerExprType(node, types.Any) } else { - a.b.registerExprType(node, a.b.bindType(node.Type)) - // TODO: ensure the properties, if any, actually exist on the target object. + ty := a.b.bindType(node.Type) + a.b.registerExprType(node, ty) + + // Only permit object literals for records and interfaces. Classes have constructors. + if !ty.Record() && !ty.Interface() { + a.b.Diag().Errorf(errors.ErrorIllegalObjectLiteralType.At(node.Type), ty) + } else { + // Ensure that all required properties have been supplied, and that they are of the right type. + props := make(map[tokens.ClassMemberName]bool) + if node.Properties != nil { + for _, init := range *node.Properties { + sym := a.b.requireClassMember(init.Property, ty, init.Property.Tok) + if sym != nil { + switch s := sym.(type) { + case *symbols.ClassProperty, *symbols.ClassMethod: + a.checkExprType(init.Value, s.Type()) + default: + contract.Failf("Unrecognized class member symbol: %v", sym) + } + props[init.Property.Tok.Name()] = true // record that we've seen this one. + } + } + } + + // Issue an error about any missing required properties. + for name, member := range ty.Members() { + if _, has := props[name]; !has { + if !member.Optional() && member.Default() == nil { + a.b.Diag().Errorf(errors.ErrorMissingRequiredProperty.At(node), name) + } + } + } + } } } diff --git a/pkg/compiler/errors/binder.go b/pkg/compiler/errors/binder.go index 100f88393..545b96825 100644 --- a/pkg/compiler/errors/binder.go +++ b/pkg/compiler/errors/binder.go @@ -146,3 +146,8 @@ var ErrorUnknownJumpLabel = &diag.Diag{ ID: 525, Message: "Unknown label '%v' used in the %v statement", } + +var ErrorIllegalObjectLiteralType = &diag.Diag{ + ID: 526, + Message: "The type '%v' may not be used as an object literal type; only records and interfaces are permitted", +} diff --git a/pkg/compiler/symbols/class.go b/pkg/compiler/symbols/class.go index 7c095262f..db8bdd214 100644 --- a/pkg/compiler/symbols/class.go +++ b/pkg/compiler/symbols/class.go @@ -14,7 +14,7 @@ type Class struct { Parent *Module Extends Type Implements Types - Members ClassMemberMap + Clmembers ClassMemberMap } var _ Symbol = (*Class)(nil) @@ -22,8 +22,6 @@ var _ Type = (*Class)(nil) var _ ModuleMember = (*Class)(nil) func (node *Class) symbol() {} -func (node *Class) typesym() {} -func (node *Class) moduleMember() {} func (node *Class) Name() tokens.Name { return node.Node.Name.Ident } func (node *Class) Token() tokens.Token { return tokens.Token( @@ -34,13 +32,15 @@ func (node *Class) Token() tokens.Token { ) } func (node *Class) Tree() diag.Diagable { return node.Node } -func (node *Class) String() string { return string(node.Name()) } +func (node *Class) moduleMember() {} func (node *Class) MemberNode() ast.ModuleMember { return node.Node } - -func (node *Class) Sealed() bool { return node.Node.Sealed != nil && *node.Node.Sealed } -func (node *Class) Abstract() bool { return node.Node.Abstract != nil && *node.Node.Abstract } -func (node *Class) Record() bool { return node.Node.Record != nil && *node.Node.Record } -func (node *Class) Interface() bool { return node.Node.Interface != nil && *node.Node.Interface } +func (node *Class) typesym() {} +func (node *Class) Members() ClassMemberMap { return node.Clmembers } +func (node *Class) Sealed() bool { return node.Node.Sealed != nil && *node.Node.Sealed } +func (node *Class) Abstract() bool { return node.Node.Abstract != nil && *node.Node.Abstract } +func (node *Class) Record() bool { return node.Node.Record != nil && *node.Node.Record } +func (node *Class) Interface() bool { return node.Node.Interface != nil && *node.Node.Interface } +func (node *Class) String() string { return string(node.Name()) } // NewClassSym returns a new Class symbol with the given node, parent, extends, and implements, and empty members. func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types) *Class { @@ -49,7 +49,7 @@ func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types Parent: parent, Extends: extends, Implements: implements, - Members: make(ClassMemberMap), + Clmembers: make(ClassMemberMap), } } @@ -57,23 +57,29 @@ func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types type ClassMember interface { Symbol classMember() + Optional() bool + Default() *interface{} + Type() Type MemberNode() ast.ClassMember } // ClassMemberMap is a map from a class member's name to its associated symbol. type ClassMemberMap map[tokens.ClassMemberName]ClassMember +// noClassMembers is a permanently empty class member map for efficient returning of empty ones. +var noClassMembers = make(ClassMemberMap) + // ClassProperty is a fully bound module property symbol. type ClassProperty struct { Node *ast.ClassProperty Parent *Class + Typ Type } var _ Symbol = (*ClassProperty)(nil) var _ ClassMember = (*ClassProperty)(nil) func (node *ClassProperty) symbol() {} -func (node *ClassProperty) classMember() {} func (node *ClassProperty) Name() tokens.Name { return node.Node.Name.Ident } func (node *ClassProperty) Token() tokens.Token { return tokens.Token( @@ -84,14 +90,19 @@ func (node *ClassProperty) Token() tokens.Token { ) } func (node *ClassProperty) Tree() diag.Diagable { return node.Node } -func (node *ClassProperty) String() string { return string(node.Name()) } +func (node *ClassProperty) classMember() {} +func (node *ClassProperty) Optional() bool { return node.Node.Optional != nil && *node.Node.Optional } +func (node *ClassProperty) Default() *interface{} { return node.Node.Default } +func (node *ClassProperty) Type() Type { return node.Typ } func (node *ClassProperty) MemberNode() ast.ClassMember { return node.Node } +func (node *ClassProperty) String() string { return string(node.Name()) } // NewClassPropertySym returns a new ClassProperty symbol with the given node and parent. -func NewClassPropertySym(node *ast.ClassProperty, parent *Class) *ClassProperty { +func NewClassPropertySym(node *ast.ClassProperty, parent *Class, typ Type) *ClassProperty { return &ClassProperty{ Node: node, Parent: parent, + Typ: typ, } } @@ -99,13 +110,13 @@ func NewClassPropertySym(node *ast.ClassProperty, parent *Class) *ClassProperty type ClassMethod struct { Node *ast.ClassMethod Parent *Class + Typ *FunctionType } var _ Symbol = (*ClassMethod)(nil) var _ ClassMember = (*ClassMethod)(nil) func (node *ClassMethod) symbol() {} -func (node *ClassMethod) classMember() {} func (node *ClassMethod) Name() tokens.Name { return node.Node.Name.Ident } func (node *ClassMethod) Token() tokens.Token { return tokens.Token( @@ -116,13 +127,18 @@ func (node *ClassMethod) Token() tokens.Token { ) } func (node *ClassMethod) Tree() diag.Diagable { return node.Node } -func (node *ClassMethod) String() string { return string(node.Name()) } +func (node *ClassMethod) classMember() {} +func (node *ClassMethod) Optional() bool { return true } +func (node *ClassMethod) Default() *interface{} { return nil } +func (node *ClassMethod) Type() Type { return node.Typ } func (node *ClassMethod) MemberNode() ast.ClassMember { return node.Node } +func (node *ClassMethod) String() string { return string(node.Name()) } // NewClassMethodSym returns a new ClassMethod symbol with the given node and parent. -func NewClassMethodSym(node *ast.ClassMethod, parent *Class) *ClassMethod { +func NewClassMethodSym(node *ast.ClassMethod, parent *Class, typ *FunctionType) *ClassMethod { return &ClassMethod{ Node: node, Parent: parent, + Typ: typ, } } diff --git a/pkg/compiler/symbols/module.go b/pkg/compiler/symbols/module.go index cd4243f50..465819567 100644 --- a/pkg/compiler/symbols/module.go +++ b/pkg/compiler/symbols/module.go @@ -65,7 +65,6 @@ var _ Symbol = (*Export)(nil) var _ ModuleMember = (*Export)(nil) func (node *Export) symbol() {} -func (node *Export) moduleMember() {} func (node *Export) Name() tokens.Name { return node.Node.Name.Ident } func (node *Export) Token() tokens.Token { return tokens.Token( @@ -76,8 +75,9 @@ func (node *Export) Token() tokens.Token { ) } func (node *Export) Tree() diag.Diagable { return node.Node } -func (node *Export) String() string { return string(node.Name()) } +func (node *Export) moduleMember() {} func (node *Export) MemberNode() ast.ModuleMember { return node.Node } +func (node *Export) String() string { return string(node.Name()) } // NewExportSym returns a new Export symbol with the given node, parent, and referent symbol. func NewExportSym(node *ast.Export, parent *Module, referent Symbol) *Export { @@ -92,13 +92,13 @@ func NewExportSym(node *ast.Export, parent *Module, referent Symbol) *Export { type ModuleProperty struct { Node *ast.ModuleProperty Parent *Module + Type Type } var _ Symbol = (*ModuleProperty)(nil) var _ ModuleMember = (*ModuleProperty)(nil) func (node *ModuleProperty) symbol() {} -func (node *ModuleProperty) moduleMember() {} func (node *ModuleProperty) Name() tokens.Name { return node.Node.Name.Ident } func (node *ModuleProperty) Token() tokens.Token { return tokens.Token( @@ -109,14 +109,16 @@ func (node *ModuleProperty) Token() tokens.Token { ) } func (node *ModuleProperty) Tree() diag.Diagable { return node.Node } -func (node *ModuleProperty) String() string { return string(node.Name()) } +func (node *ModuleProperty) moduleMember() {} func (node *ModuleProperty) MemberNode() ast.ModuleMember { return node.Node } +func (node *ModuleProperty) String() string { return string(node.Name()) } // NewModulePropertySym returns a new ModuleProperty symbol with the given node and parent. -func NewModulePropertySym(node *ast.ModuleProperty, parent *Module) *ModuleProperty { +func NewModulePropertySym(node *ast.ModuleProperty, parent *Module, typ Type) *ModuleProperty { return &ModuleProperty{ Node: node, Parent: parent, + Type: typ, } } @@ -124,13 +126,13 @@ func NewModulePropertySym(node *ast.ModuleProperty, parent *Module) *ModulePrope type ModuleMethod struct { Node *ast.ModuleMethod Parent *Module + Type *FunctionType } var _ Symbol = (*ModuleMethod)(nil) var _ ModuleMember = (*ModuleMethod)(nil) func (node *ModuleMethod) symbol() {} -func (node *ModuleMethod) moduleMember() {} func (node *ModuleMethod) Name() tokens.Name { return node.Node.Name.Ident } func (node *ModuleMethod) Token() tokens.Token { return tokens.Token( @@ -141,13 +143,15 @@ func (node *ModuleMethod) Token() tokens.Token { ) } func (node *ModuleMethod) Tree() diag.Diagable { return node.Node } -func (node *ModuleMethod) String() string { return string(node.Name()) } +func (node *ModuleMethod) moduleMember() {} func (node *ModuleMethod) MemberNode() ast.ModuleMember { return node.Node } +func (node *ModuleMethod) String() string { return string(node.Name()) } // NewModuleMethodSym returns a new ModuleMethod symbol with the given node and parent. -func NewModuleMethodSym(node *ast.ModuleMethod, parent *Module) *ModuleMethod { +func NewModuleMethodSym(node *ast.ModuleMethod, parent *Module, typ *FunctionType) *ModuleMethod { return &ModuleMethod{ Node: node, Parent: parent, + Type: typ, } } diff --git a/pkg/compiler/symbols/type.go b/pkg/compiler/symbols/type.go index f14f5a453..cedd765a5 100644 --- a/pkg/compiler/symbols/type.go +++ b/pkg/compiler/symbols/type.go @@ -13,6 +13,9 @@ import ( type Type interface { Symbol typesym() + Members() ClassMemberMap // this type's members. + Record() bool // true if this is a record type. + Interface() bool // true if this is an interface type. } // Types is a list of type symbols. @@ -26,12 +29,15 @@ type PrimitiveType struct { var _ Symbol = (*PrimitiveType)(nil) var _ Type = (*PrimitiveType)(nil) -func (node *PrimitiveType) symbol() {} -func (node *PrimitiveType) typesym() {} -func (node *PrimitiveType) Name() tokens.Name { return tokens.Name(node.Nm) } -func (node *PrimitiveType) Token() tokens.Token { return tokens.Token(node.Nm) } -func (node *PrimitiveType) Tree() diag.Diagable { return nil } -func (node *PrimitiveType) String() string { return string(node.Name()) } +func (node *PrimitiveType) symbol() {} +func (node *PrimitiveType) Name() tokens.Name { return tokens.Name(node.Nm) } +func (node *PrimitiveType) Token() tokens.Token { return tokens.Token(node.Nm) } +func (node *PrimitiveType) Tree() diag.Diagable { return nil } +func (node *PrimitiveType) typesym() {} +func (node *PrimitiveType) Members() ClassMemberMap { return noClassMembers } +func (node *PrimitiveType) Record() bool { return false } +func (node *PrimitiveType) Interface() bool { return false } +func (node *PrimitiveType) String() string { return string(node.Name()) } func NewPrimitiveType(nm tokens.TypeName) *PrimitiveType { return &PrimitiveType{nm} @@ -47,12 +53,15 @@ type PointerType struct { var _ Symbol = (*PointerType)(nil) var _ Type = (*PointerType)(nil) -func (node *PointerType) symbol() {} -func (node *PointerType) typesym() {} -func (node *PointerType) Name() tokens.Name { return tokens.Name(node.Nm) } -func (node *PointerType) Token() tokens.Token { return tokens.Token(node.Tok) } -func (node *PointerType) Tree() diag.Diagable { return nil } -func (node *PointerType) String() string { return string(node.Name()) } +func (node *PointerType) symbol() {} +func (node *PointerType) Name() tokens.Name { return tokens.Name(node.Nm) } +func (node *PointerType) Token() tokens.Token { return tokens.Token(node.Tok) } +func (node *PointerType) Tree() diag.Diagable { return nil } +func (node *PointerType) typesym() {} +func (node *PointerType) Members() ClassMemberMap { return noClassMembers } +func (node *PointerType) Record() bool { return false } +func (node *PointerType) Interface() bool { return false } +func (node *PointerType) String() string { return string(node.Name()) } func NewPointerType(elem Type) *PointerType { nm := newPointerTypeName(elem) @@ -85,12 +94,15 @@ type ArrayType struct { var _ Symbol = (*ArrayType)(nil) var _ Type = (*ArrayType)(nil) -func (node *ArrayType) symbol() {} -func (node *ArrayType) typesym() {} -func (node *ArrayType) Name() tokens.Name { return tokens.Name(node.Nm) } -func (node *ArrayType) Token() tokens.Token { return tokens.Token(node.Tok) } -func (node *ArrayType) Tree() diag.Diagable { return nil } -func (node *ArrayType) String() string { return string(node.Name()) } +func (node *ArrayType) symbol() {} +func (node *ArrayType) Name() tokens.Name { return tokens.Name(node.Nm) } +func (node *ArrayType) Token() tokens.Token { return tokens.Token(node.Tok) } +func (node *ArrayType) Tree() diag.Diagable { return nil } +func (node *ArrayType) typesym() {} +func (node *ArrayType) Members() ClassMemberMap { return noClassMembers } +func (node *ArrayType) Record() bool { return false } +func (node *ArrayType) Interface() bool { return false } +func (node *ArrayType) String() string { return string(node.Name()) } func NewArrayType(elem Type) *ArrayType { nm := newArrayTypeName(elem) @@ -124,12 +136,15 @@ type MapType struct { var _ Symbol = (*MapType)(nil) var _ Type = (*MapType)(nil) -func (node *MapType) symbol() {} -func (node *MapType) typesym() {} -func (node *MapType) Name() tokens.Name { return tokens.Name(node.Nm) } -func (node *MapType) Token() tokens.Token { return tokens.Token(node.Tok) } -func (node *MapType) Tree() diag.Diagable { return nil } -func (node *MapType) String() string { return string(node.Name()) } +func (node *MapType) symbol() {} +func (node *MapType) Name() tokens.Name { return tokens.Name(node.Nm) } +func (node *MapType) Token() tokens.Token { return tokens.Token(node.Tok) } +func (node *MapType) Tree() diag.Diagable { return nil } +func (node *MapType) typesym() {} +func (node *MapType) Members() ClassMemberMap { return noClassMembers } +func (node *MapType) Record() bool { return false } +func (node *MapType) Interface() bool { return false } +func (node *MapType) String() string { return string(node.Name()) } func NewMapType(key Type, elem Type) *MapType { nm := newMapTypeName(key, elem) @@ -164,12 +179,15 @@ type FunctionType struct { var _ Symbol = (*FunctionType)(nil) var _ Type = (*FunctionType)(nil) -func (node *FunctionType) symbol() {} -func (node *FunctionType) typesym() {} -func (node *FunctionType) Name() tokens.Name { return tokens.Name(node.Nm) } -func (node *FunctionType) Token() tokens.Token { return tokens.Token(node.Tok) } -func (node *FunctionType) Tree() diag.Diagable { return nil } -func (node *FunctionType) String() string { return string(node.Name()) } +func (node *FunctionType) symbol() {} +func (node *FunctionType) Name() tokens.Name { return tokens.Name(node.Nm) } +func (node *FunctionType) Token() tokens.Token { return tokens.Token(node.Tok) } +func (node *FunctionType) Tree() diag.Diagable { return nil } +func (node *FunctionType) typesym() {} +func (node *FunctionType) Members() ClassMemberMap { return noClassMembers } +func (node *FunctionType) Record() bool { return false } +func (node *FunctionType) Interface() bool { return false } +func (node *FunctionType) String() string { return string(node.Name()) } func NewFunctionType(params []Type, ret Type) *FunctionType { nm := newFunctionTypeName(params, ret) diff --git a/tools/mujs/lib/ast/expressions.ts b/tools/mujs/lib/ast/expressions.ts index 374f2f18b..49fd74589 100644 --- a/tools/mujs/lib/ast/expressions.ts +++ b/tools/mujs/lib/ast/expressions.ts @@ -1,7 +1,7 @@ // Copyright 2016 Marapongo, Inc. All rights reserved. import {LocalVariable} from "./definitions"; -import {Identifier, Node, TypeToken} from "./nodes"; +import {ClassMemberToken, Identifier, Node, TypeToken} from "./nodes"; import * as statements from "./statements"; import * as symbols from "../symbols"; @@ -66,9 +66,9 @@ export type ObjectLiteralKind = "ObjectLiteral"; // An object literal property initializer. export interface ObjectLiteralProperty extends Node { - kind: ObjectLiteralPropertyKind; - name: Identifier; // the property being initialized. - value: Expression; // the expression value to store into the property. + kind: ObjectLiteralPropertyKind; + property: ClassMemberToken; // the property being initialized. + value: Expression; // the expression value to store into the property. } export const objectLiteralPropertyKind = "ObjectLiteralProperty"; export type ObjectLiteralPropertyKind = "ObjectLiteralProperty"; diff --git a/tools/mujs/lib/ast/nodes.ts b/tools/mujs/lib/ast/nodes.ts index 1605af01b..69987e9c4 100644 --- a/tools/mujs/lib/ast/nodes.ts +++ b/tools/mujs/lib/ast/nodes.ts @@ -20,6 +20,7 @@ export interface Node { export type NodeKind = IdentifierKind | TokenKind | + ClassMemberTokenKind | ModuleTokenKind | TypeTokenKind | @@ -82,6 +83,13 @@ export interface Token extends Node { export const tokenKind = "Token"; export type TokenKind = "Token"; +export interface ClassMemberToken extends Node { + kind: ClassMemberTokenKind; + tok: symbols.ClassMemberToken; +} +export const classMemberTokenKind = "ClassMemberToken"; +export type ClassMemberTokenKind = "ClassMemberToken"; + export interface ModuleToken extends Node { kind: ModuleTokenKind; tok: symbols.ModuleToken; diff --git a/tools/mujs/lib/compiler/transform.ts b/tools/mujs/lib/compiler/transform.ts index f208ebddb..44aa8472d 100644 --- a/tools/mujs/lib/compiler/transform.ts +++ b/tools/mujs/lib/compiler/transform.ts @@ -1781,10 +1781,14 @@ export class Transformer { } private transformObjectLiteralPropertyAssignment(node: ts.PropertyAssignment): ast.ObjectLiteralProperty { + let pname: ast.Identifier = this.transformPropertyName(node.name); return this.withLocation(node, { - kind: ast.objectLiteralPropertyKind, - name: this.transformPropertyName(node.name), - value: this.transformExpression(node.initializer), + kind: ast.objectLiteralPropertyKind, + property: { + kind: ast.classMemberTokenKind, + tok: pname.ident, + }, + value: this.transformExpression(node.initializer), }); } @@ -1792,9 +1796,12 @@ export class Transformer { node: ts.ShorthandPropertyAssignment): ast.ObjectLiteralProperty { let name: ast.Identifier = this.transformIdentifier(node.name); return this.withLocation(node, { - kind: ast.objectLiteralPropertyKind, - name: name, - value: this.withLocation(node.name, { + kind: ast.objectLiteralPropertyKind, + property: { + kind: ast.classMemberTokenKind, + tok: name.ident, + }, + value: this.withLocation(node.name, { kind: ast.loadLocationExpressionKind, name: name, }), diff --git a/tools/mujs/lib/symbols/index.ts b/tools/mujs/lib/symbols/index.ts index 5f36a428a..e10668855 100644 --- a/tools/mujs/lib/symbols/index.ts +++ b/tools/mujs/lib/symbols/index.ts @@ -1,11 +1,13 @@ // Copyright 2016 Marapongo, Inc. All rights reserved. // Tokens. -export type Token = string; // a valid symbol token. -export type ModuleToken = Token; // a symbol token that resolves to a module. -export type TypeToken = Token; // a symbol token that resolves to a type. -export type VariableToken = Token; // a symbol token that resolves to a variable. -export type FunctionToken = Token; // a symbol token that resolves to a function. +export type Token = string; // a valid symbol token. +export type ModuleToken = Token; // a symbol token that resolves to a module. +export type ModuleMemberToken = Token; // a symbol token that resolves to a module member. +export type ClassMemberToken = Token; // a symbol token that resolves to a class member. +export type TypeToken = Token; // a symbol token that resolves to a type. +export type VariableToken = Token; // a symbol token that resolves to a variable. +export type FunctionToken = Token; // a symbol token that resolves to a function. export const moduleSep = ":"; // a character delimiting module / member names (e.g., "module:member"). export const selfModule: ModuleToken = "."; // a self-referential token for the current module.