We need to access the bound property values for a given stack, especially during code-generation. This information was present for services before, however not for stacks constructed via other means (e.g., the top-most one). This change adds a PropertyValues bag plus a corresponding BoundPropertyValues to the ast.Stack type.
121 lines
4.9 KiB
Go
121 lines
4.9 KiB
Go
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
package compiler
|
|
|
|
import (
|
|
"github.com/golang/glog"
|
|
|
|
"github.com/marapongo/mu/pkg/ast"
|
|
"github.com/marapongo/mu/pkg/compiler/core"
|
|
"github.com/marapongo/mu/pkg/diag"
|
|
"github.com/marapongo/mu/pkg/encoding"
|
|
"github.com/marapongo/mu/pkg/errors"
|
|
"github.com/marapongo/mu/pkg/util"
|
|
)
|
|
|
|
// Parse transforms a program's input text into a parse tree.
|
|
type Parser interface {
|
|
core.Phase
|
|
|
|
// ParseStack parses a Mufile from the given document. If an error occurs, the return value will be nil. It is
|
|
// expected that errors are conveyed using the diag.Sink interface.
|
|
ParseStack(doc *diag.Document, props ast.PropertyBag) *ast.Stack
|
|
// ParseWorkspace parses workspace settings from the given document. If an error occurs, the return value will be
|
|
// nil. It is expected that errors are conveyed using the diag.Sink interface.
|
|
ParseWorkspace(doc *diag.Document) *ast.Workspace
|
|
}
|
|
|
|
func NewParser(c Compiler) Parser {
|
|
return &parser{c}
|
|
}
|
|
|
|
type parser struct {
|
|
c Compiler
|
|
}
|
|
|
|
func (p *parser) Diag() diag.Sink {
|
|
return p.c.Diag()
|
|
}
|
|
|
|
func (p *parser) ParseWorkspace(doc *diag.Document) *ast.Workspace {
|
|
glog.Infof("Parsing workspace settings: %v (len(body)=%v)", doc.File, len(doc.Body))
|
|
if glog.V(2) {
|
|
defer glog.V(2).Infof("Parsing workspace settings '%v' completed w/ %v warnings and %v errors",
|
|
doc.File, p.Diag().Warnings(), p.Diag().Errors())
|
|
}
|
|
|
|
// We support many file formats. Detect the file extension and deserialize the contents.
|
|
var w ast.Workspace
|
|
marshaler, has := encoding.Marshalers[doc.Ext()]
|
|
util.AssertMF(has, "No marshaler registered for this workspace extension: %v", doc.Ext())
|
|
if err := marshaler.Unmarshal(doc.Body, &w); err != nil {
|
|
p.Diag().Errorf(errors.ErrorIllegalWorkspaceSyntax.At(doc), err)
|
|
// TODO[marapongo/mu#14]: issue an error per issue found in the file with line/col numbers.
|
|
return nil
|
|
}
|
|
glog.V(3).Infof("Workspace settings %v parsed: %v clusters; %v deps",
|
|
doc.File, len(w.Clusters), len(w.Dependencies))
|
|
|
|
// Remember that this workspace came from this document.
|
|
w.Doc = doc
|
|
|
|
// Now create a parse tree analyzer to walk the parse trees and ensure that all is well.
|
|
ptAnalyzer := NewPTAnalyzer(p.c)
|
|
ptAnalyzer.AnalyzeWorkspace(&w)
|
|
|
|
return &w
|
|
}
|
|
|
|
func (p *parser) ParseStack(doc *diag.Document, props ast.PropertyBag) *ast.Stack {
|
|
glog.Infof("Parsing Mufile: %v (len(body)=%v len(props)=%v)", doc.File, len(doc.Body), len(props))
|
|
if glog.V(7) {
|
|
for pk, pv := range props {
|
|
glog.V(7).Infof("Mufile %v property '%v'='%v'", doc.File, pk, pv)
|
|
}
|
|
}
|
|
if glog.V(2) {
|
|
defer glog.V(2).Infof("Parsing Mufile '%v' completed w/ %v warnings and %v errors",
|
|
doc.File, p.Diag().Warnings(), p.Diag().Errors())
|
|
}
|
|
|
|
// Expand templates in the document first and foremost.
|
|
// TODO[marapongo/mu#7]: the order of template expansion is not clear. The way we've done it right now (i.e.,
|
|
// performing it right here), we haven't yet type-checked the properties supplied to the stack. As a result,
|
|
// there is less compile-time safety. And furthermore, the properties are in a map rather than being stored
|
|
// in structured types. In other words, this is really just a fancy pre-processor, rather than being well-
|
|
// integrated into the type system. To do that, however, we'd need to delay processing of templates, which
|
|
// itself will mess with our ability to parse the document. This is an area of future thinking.
|
|
// TODO[marapongo/mu#7]: related to this, certain information (like cluster target) isn't even available yet!
|
|
// TODO[marapongo/mu#14]: when we produce precise line/column errors, we'll need to somehow trace back to pre-
|
|
// template expansion, otherwise the numbers may not make sense to the user.
|
|
rend, err := RenderTemplates(doc, p.c.Context().WithProps(props))
|
|
if err != nil {
|
|
p.Diag().Errorf(errors.ErrorBadTemplate.At(doc), err)
|
|
return nil
|
|
}
|
|
doc = rend
|
|
|
|
// We support many file formats. Detect the file extension and deserialize the contents.
|
|
var stack ast.Stack
|
|
marshaler, has := encoding.Marshalers[doc.Ext()]
|
|
util.AssertMF(has, "No marshaler registered for this Mufile extension: %v", doc.Ext())
|
|
if err := marshaler.Unmarshal(doc.Body, &stack); err != nil {
|
|
p.Diag().Errorf(errors.ErrorIllegalMufileSyntax.At(doc), err)
|
|
// TODO[marapongo/mu#14]: issue an error per issue found in the file with line/col numbers.
|
|
return nil
|
|
}
|
|
glog.V(3).Infof("Mufile %v stack parsed: %v name; %v publics; %v privates",
|
|
doc.File, stack.Name, len(stack.Services.PublicUntyped), len(stack.Services.PrivateUntyped))
|
|
|
|
// Remember that this stack came from this document (both template expanded and unexpanded forms).
|
|
stack.Doc = doc
|
|
|
|
// Remember the properties used to construct this stack.
|
|
stack.PropertyValues = props
|
|
|
|
// Now create a parse tree analyzer to walk the parse trees and ensure that all is well.
|
|
ptAnalyzer := NewPTAnalyzer(p.c)
|
|
ptAnalyzer.AnalyzeStack(&stack)
|
|
|
|
return &stack
|
|
}
|