pulumi/pkg/compiler/core/visitor.go
joeduffy db80229899 Fix a few type binding mistakes
* Persue the default/optional checking if a property value == nil.

* Use the Interface() function to convert a reflect.Type to its underlying
  interface{} value.  This is required for typechecking to check out.

* Also, unrelated to the above, change type assertions to use nil rather than
  allocating real objects.  Although minimal, this incurs less GC pressure.
2016-12-09 13:12:57 -08:00

169 lines
4.7 KiB
Go

// Copyright 2016 Marapongo, Inc. All rights reserved.
package core
import (
"github.com/marapongo/mu/pkg/ast"
"github.com/marapongo/mu/pkg/diag"
)
// Visitor unifies all visitation patterns under a single interface.
type Visitor interface {
Phase
VisitWorkspace(w *ast.Workspace)
VisitCluster(name string, cluster *ast.Cluster)
VisitDependency(parent *ast.Workspace, ref ast.Ref, dep *ast.Dependency)
VisitStack(stack *ast.Stack)
VisitSchemas(parent *ast.Stack, schmas *ast.Schemas)
VisitSchema(pstack *ast.Stack, parent *ast.Schemas, name ast.Name, public bool, schema *ast.Schema)
VisitProperty(parent *ast.Stack, schema *ast.Schema, name string, prop *ast.Property)
VisitServices(parent *ast.Stack, svcs *ast.Services)
VisitService(pstack *ast.Stack, parent *ast.Services, name ast.Name, public bool, svc *ast.Service)
}
// NewInOrderVisitor wraps another Visitor and walks the tree in a deterministic order, deferring to another set of
// Visitor objects for pre- and/or post-actions. Either pre or post may be nil.
func NewInOrderVisitor(pre Visitor, post Visitor) Visitor {
return &inOrderVisitor{pre, post}
}
// inOrderVisitor simply implements the Visitor pattern as specified above.
//
// Note that we need to iterate all maps in a stable order (since Go's are unordered by default). Sadly, this
// is rather verbose due to Go's lack of generics, reflectionless Keys() functions, and so on.
type inOrderVisitor struct {
pre Visitor
post Visitor
}
var _ Visitor = (*inOrderVisitor)(nil) // compile-time assert that inOrderVisitor implements Visitor.
func (v *inOrderVisitor) Diag() diag.Sink {
if v.pre != nil {
return v.pre.Diag()
}
if v.post != nil {
return v.post.Diag()
}
return nil
}
func (v *inOrderVisitor) VisitWorkspace(w *ast.Workspace) {
if v.pre != nil {
v.pre.VisitWorkspace(w)
}
for _, name := range ast.StableClusters(w.Clusters) {
v.VisitCluster(name, w.Clusters[name])
}
for _, ref := range ast.StableDependencies(w.Dependencies) {
v.VisitDependency(w, ref, w.Dependencies[ref])
}
if v.post != nil {
v.post.VisitWorkspace(w)
}
}
func (v *inOrderVisitor) VisitCluster(name string, cluster *ast.Cluster) {
if v.pre != nil {
v.pre.VisitCluster(name, cluster)
}
if v.post != nil {
v.post.VisitCluster(name, cluster)
}
}
func (v *inOrderVisitor) VisitDependency(parent *ast.Workspace, ref ast.Ref, dep *ast.Dependency) {
if v.pre != nil {
v.pre.VisitDependency(parent, ref, dep)
}
if v.post != nil {
v.post.VisitDependency(parent, ref, dep)
}
}
func (v *inOrderVisitor) VisitStack(stack *ast.Stack) {
if v.pre != nil {
v.pre.VisitStack(stack)
}
v.VisitSchemas(stack, &stack.Types)
for _, name := range ast.StableProperties(stack.Properties) {
v.VisitProperty(stack, nil, name, stack.Properties[name])
}
v.VisitServices(stack, &stack.Services)
if v.post != nil {
v.post.VisitStack(stack)
}
}
func (v *inOrderVisitor) VisitSchemas(parent *ast.Stack, schemas *ast.Schemas) {
if v.pre != nil {
v.pre.VisitSchemas(parent, schemas)
}
for _, name := range ast.StableSchemas(schemas.Private) {
v.VisitSchema(parent, schemas, name, false, schemas.Private[name])
}
for _, name := range ast.StableSchemas(schemas.Public) {
v.VisitSchema(parent, schemas, name, true, schemas.Public[name])
}
if v.post != nil {
v.post.VisitSchemas(parent, schemas)
}
}
func (v *inOrderVisitor) VisitSchema(pstack *ast.Stack, parent *ast.Schemas, name ast.Name,
public bool, schema *ast.Schema) {
if v.pre != nil {
v.pre.VisitSchema(pstack, parent, name, public, schema)
}
for _, name := range ast.StableProperties(schema.Properties) {
v.VisitProperty(pstack, schema, name, schema.Properties[name])
}
if v.post != nil {
v.post.VisitSchema(pstack, parent, name, public, schema)
}
}
func (v *inOrderVisitor) VisitProperty(parent *ast.Stack, schema *ast.Schema, name string, prop *ast.Property) {
if v.pre != nil {
v.pre.VisitProperty(parent, schema, name, prop)
}
if v.post != nil {
v.post.VisitProperty(parent, schema, name, prop)
}
}
func (v *inOrderVisitor) VisitServices(parent *ast.Stack, svcs *ast.Services) {
if v.pre != nil {
v.pre.VisitServices(parent, svcs)
}
for _, name := range ast.StableServices(svcs.Private) {
v.VisitService(parent, svcs, name, false, svcs.Private[name])
}
for _, name := range ast.StableServices(svcs.Public) {
v.VisitService(parent, svcs, name, true, svcs.Public[name])
}
if v.post != nil {
v.post.VisitServices(parent, svcs)
}
}
func (v *inOrderVisitor) VisitService(pstack *ast.Stack, parent *ast.Services, name ast.Name,
public bool, svc *ast.Service) {
if v.pre != nil {
v.pre.VisitService(pstack, parent, name, public, svc)
}
if v.post != nil {
v.post.VisitService(pstack, parent, name, public, svc)
}
}