pulumi/pkg/compiler/core/visitor.go

169 lines
4.7 KiB
Go
Raw Normal View History

// 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)
Custom types, round 1 This change overhauls the core of how types are used by the entire compiler. In particular, we now have an ast.Type, and have begun using its use where appropriate. An ast.Type is a union representing precisely one of the possible sources of types in the system: * Primitive type: any, bool, number, string, or service. * Stack type: a resolved reference to an actual concrete stack. * Schema type: a resolved reference to an actual concrete schema. * Unresolved reference: a textual reference that hasn't yet been resolved to a concrete artifact. * Uninstantiated reference: a reference that has been resolved to an uninstantiated stack, but hasn't been bound to a concrete result yet. Right now, this can point to a stack, however eventually we would imagine this supporting inter-stack schema references also. * Decorated type: either an array or a map; in the array case, there is a single inner element type; in the map case, there are two, the keys and values; in all cases, the type recurses to any of the possibilities listed here. All of the relevant AST nodes have been overhauled accordingly. In addition to this, we now have an ast.Schema type. It is loosely modeled on JSON Schema in its capabilities (http://json-schema.org/). Although we parse and perform some visitation and binding of these, there are mostly placeholders left in the code for the interesting aspects, such as registering symbols, resolving dependencies, and typechecking usage of schema types. This is part of the ongoing work behind marapongo/mu#9.
2016-12-06 23:49:47 +01:00
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.
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
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)
}
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
for _, name := range ast.StableClusters(w.Clusters) {
v.VisitCluster(name, w.Clusters[name])
}
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
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)
}
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
v.VisitSchemas(stack, &stack.Types)
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
for _, name := range ast.StableProperties(stack.Properties) {
v.VisitProperty(stack, nil, name, stack.Properties[name])
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
}
v.VisitServices(stack, &stack.Services)
if v.post != nil {
v.post.VisitStack(stack)
}
}
Custom types, round 1 This change overhauls the core of how types are used by the entire compiler. In particular, we now have an ast.Type, and have begun using its use where appropriate. An ast.Type is a union representing precisely one of the possible sources of types in the system: * Primitive type: any, bool, number, string, or service. * Stack type: a resolved reference to an actual concrete stack. * Schema type: a resolved reference to an actual concrete schema. * Unresolved reference: a textual reference that hasn't yet been resolved to a concrete artifact. * Uninstantiated reference: a reference that has been resolved to an uninstantiated stack, but hasn't been bound to a concrete result yet. Right now, this can point to a stack, however eventually we would imagine this supporting inter-stack schema references also. * Decorated type: either an array or a map; in the array case, there is a single inner element type; in the map case, there are two, the keys and values; in all cases, the type recurses to any of the possibilities listed here. All of the relevant AST nodes have been overhauled accordingly. In addition to this, we now have an ast.Schema type. It is loosely modeled on JSON Schema in its capabilities (http://json-schema.org/). Although we parse and perform some visitation and binding of these, there are mostly placeholders left in the code for the interesting aspects, such as registering symbols, resolving dependencies, and typechecking usage of schema types. This is part of the ongoing work behind marapongo/mu#9.
2016-12-06 23:49:47 +01:00
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])
}
Custom types, round 1 This change overhauls the core of how types are used by the entire compiler. In particular, we now have an ast.Type, and have begun using its use where appropriate. An ast.Type is a union representing precisely one of the possible sources of types in the system: * Primitive type: any, bool, number, string, or service. * Stack type: a resolved reference to an actual concrete stack. * Schema type: a resolved reference to an actual concrete schema. * Unresolved reference: a textual reference that hasn't yet been resolved to a concrete artifact. * Uninstantiated reference: a reference that has been resolved to an uninstantiated stack, but hasn't been bound to a concrete result yet. Right now, this can point to a stack, however eventually we would imagine this supporting inter-stack schema references also. * Decorated type: either an array or a map; in the array case, there is a single inner element type; in the map case, there are two, the keys and values; in all cases, the type recurses to any of the possibilities listed here. All of the relevant AST nodes have been overhauled accordingly. In addition to this, we now have an ast.Schema type. It is loosely modeled on JSON Schema in its capabilities (http://json-schema.org/). Although we parse and perform some visitation and binding of these, there are mostly placeholders left in the code for the interesting aspects, such as registering symbols, resolving dependencies, and typechecking usage of schema types. This is part of the ongoing work behind marapongo/mu#9.
2016-12-06 23:49:47 +01:00
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) {
Retain unrecognized service properties During unmarshaling, the default behavior of the stock Golang JSON marshaler, and consequently the YAML one we used which mimics its behavior, is to toss away unrecognized properties. This isn't what we want for two reasons: First, we want to issue errors/warnings on unrecognized fields to aid in diagnostics; we will set aside some extensible section for 3rd parties to use. This is not addressed in this change, however. Second, and more pertinent, is that we need to retain unrecognized fields for certain types like services, which are extensible by default. Until golang/go#6213 is addressed -- imminent, it seems -- we will have to do a somewhat hacky workaround to this problem. This change contains what I consider to be the "least bad" in that we won't introduce a lot of performance overhead, and just have to deal with the slight annoyance of the ast.Services node type containing both Public/Private *and* PublicUntyped/PrivateUntyped fields alongside one another. The marshaler dumps property bags into the *Untyped fields, and the parsetree analyzer expands them out into a structured ast.Service type. Subsequent passes can then ignore the *Untyped fields altogether. Note that this would cause some marshaling funkiness if we ever wanted to remarshal the mutated ASTs back into JSON/YAML. Since we don't do that right now, however, I've not made any attempt to keep the two pairs in synch. Post-parsetree analyzer, we literally just forget about the *Untyped guys.
2016-11-19 18:01:23 +01:00
if v.pre != nil {
v.pre.VisitProperty(parent, schema, name, prop)
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
}
if v.post != nil {
v.post.VisitProperty(parent, schema, name, prop)
Retain unrecognized service properties During unmarshaling, the default behavior of the stock Golang JSON marshaler, and consequently the YAML one we used which mimics its behavior, is to toss away unrecognized properties. This isn't what we want for two reasons: First, we want to issue errors/warnings on unrecognized fields to aid in diagnostics; we will set aside some extensible section for 3rd parties to use. This is not addressed in this change, however. Second, and more pertinent, is that we need to retain unrecognized fields for certain types like services, which are extensible by default. Until golang/go#6213 is addressed -- imminent, it seems -- we will have to do a somewhat hacky workaround to this problem. This change contains what I consider to be the "least bad" in that we won't introduce a lot of performance overhead, and just have to deal with the slight annoyance of the ast.Services node type containing both Public/Private *and* PublicUntyped/PrivateUntyped fields alongside one another. The marshaler dumps property bags into the *Untyped fields, and the parsetree analyzer expands them out into a structured ast.Service type. Subsequent passes can then ignore the *Untyped fields altogether. Note that this would cause some marshaling funkiness if we ever wanted to remarshal the mutated ASTs back into JSON/YAML. Since we don't do that right now, however, I've not made any attempt to keep the two pairs in synch. Post-parsetree analyzer, we literally just forget about the *Untyped guys.
2016-11-19 18:01:23 +01:00
}
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
}
Retain unrecognized service properties During unmarshaling, the default behavior of the stock Golang JSON marshaler, and consequently the YAML one we used which mimics its behavior, is to toss away unrecognized properties. This isn't what we want for two reasons: First, we want to issue errors/warnings on unrecognized fields to aid in diagnostics; we will set aside some extensible section for 3rd parties to use. This is not addressed in this change, however. Second, and more pertinent, is that we need to retain unrecognized fields for certain types like services, which are extensible by default. Until golang/go#6213 is addressed -- imminent, it seems -- we will have to do a somewhat hacky workaround to this problem. This change contains what I consider to be the "least bad" in that we won't introduce a lot of performance overhead, and just have to deal with the slight annoyance of the ast.Services node type containing both Public/Private *and* PublicUntyped/PrivateUntyped fields alongside one another. The marshaler dumps property bags into the *Untyped fields, and the parsetree analyzer expands them out into a structured ast.Service type. Subsequent passes can then ignore the *Untyped fields altogether. Note that this would cause some marshaling funkiness if we ever wanted to remarshal the mutated ASTs back into JSON/YAML. Since we don't do that right now, however, I've not made any attempt to keep the two pairs in synch. Post-parsetree analyzer, we literally just forget about the *Untyped guys.
2016-11-19 18:01:23 +01:00
func (v *inOrderVisitor) VisitServices(parent *ast.Stack, svcs *ast.Services) {
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
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])
Implement dependency versions This change implements dependency versions, including semantic analysis, per the checkin https://github.com/marapongo/mu/commit/83030685c3b8a3dbe96bd10ab055f029667a96b0. There's quite a bit in here but at a top-level this parses and validates dependency references of the form [[proto://]base.url]namespace/.../name[@version] and verifies that the components are correct, as well as binding them to symbols. These references can appear in two places at the moment: * Service types. * Cluster dependencies. As part of this change, a number of supporting changes have been made: * Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis. This allows us to share logic around the validation of common AST types. This also moves some of the logic around loading workspace.yaml files back to the parser, where it can be unified with the way we load Mu.yaml files. * New ast.Version and ast.VersionSpec types. The former represents a precise version -- either a specific semantic version or a short or long Git SHA hash -- and the latter represents a range -- either a Version, "latest", or a semantic range. * New ast.Ref and ast.RefParts types. The former is an unparsed string that is thought to contain a Ref, while the latter is a validated Ref that has been parsed into its components (Proto, Base, Name, and Version). * Added some type assertions to ensure certain structs implement certain interfaces, to speed up finding errors. (And remove the coercions that zero-fill vtbl slots.) * Be consistent about prefixing error types with Error or Warning. * Organize the core compiler driver's logic into three methods, FE, sema, and BE. * A bunch of tests for some of the above ... more to come in an upcoming change.
2016-11-23 01:58:23 +01:00
}
for _, name := range ast.StableServices(svcs.Public) {
v.VisitService(parent, svcs, name, true, svcs.Public[name])
}
Retain unrecognized service properties During unmarshaling, the default behavior of the stock Golang JSON marshaler, and consequently the YAML one we used which mimics its behavior, is to toss away unrecognized properties. This isn't what we want for two reasons: First, we want to issue errors/warnings on unrecognized fields to aid in diagnostics; we will set aside some extensible section for 3rd parties to use. This is not addressed in this change, however. Second, and more pertinent, is that we need to retain unrecognized fields for certain types like services, which are extensible by default. Until golang/go#6213 is addressed -- imminent, it seems -- we will have to do a somewhat hacky workaround to this problem. This change contains what I consider to be the "least bad" in that we won't introduce a lot of performance overhead, and just have to deal with the slight annoyance of the ast.Services node type containing both Public/Private *and* PublicUntyped/PrivateUntyped fields alongside one another. The marshaler dumps property bags into the *Untyped fields, and the parsetree analyzer expands them out into a structured ast.Service type. Subsequent passes can then ignore the *Untyped fields altogether. Note that this would cause some marshaling funkiness if we ever wanted to remarshal the mutated ASTs back into JSON/YAML. Since we don't do that right now, however, I've not made any attempt to keep the two pairs in synch. Post-parsetree analyzer, we literally just forget about the *Untyped guys.
2016-11-19 18:01:23 +01:00
if v.post != nil {
v.post.VisitServices(parent, svcs)
Retain unrecognized service properties During unmarshaling, the default behavior of the stock Golang JSON marshaler, and consequently the YAML one we used which mimics its behavior, is to toss away unrecognized properties. This isn't what we want for two reasons: First, we want to issue errors/warnings on unrecognized fields to aid in diagnostics; we will set aside some extensible section for 3rd parties to use. This is not addressed in this change, however. Second, and more pertinent, is that we need to retain unrecognized fields for certain types like services, which are extensible by default. Until golang/go#6213 is addressed -- imminent, it seems -- we will have to do a somewhat hacky workaround to this problem. This change contains what I consider to be the "least bad" in that we won't introduce a lot of performance overhead, and just have to deal with the slight annoyance of the ast.Services node type containing both Public/Private *and* PublicUntyped/PrivateUntyped fields alongside one another. The marshaler dumps property bags into the *Untyped fields, and the parsetree analyzer expands them out into a structured ast.Service type. Subsequent passes can then ignore the *Untyped fields altogether. Note that this would cause some marshaling funkiness if we ever wanted to remarshal the mutated ASTs back into JSON/YAML. Since we don't do that right now, however, I've not made any attempt to keep the two pairs in synch. Post-parsetree analyzer, we literally just forget about the *Untyped guys.
2016-11-19 18:01:23 +01:00
}
}
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)
}
}