2016-11-23 16:26:45 +01:00
|
|
|
// 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/diag"
|
|
|
|
"github.com/marapongo/mu/pkg/errors"
|
|
|
|
"github.com/marapongo/mu/pkg/util"
|
|
|
|
"github.com/marapongo/mu/pkg/workspace"
|
|
|
|
)
|
|
|
|
|
|
|
|
// buildDocumentSema runs the middle semantic analysis phases of the compiler.
|
|
|
|
func (c *compiler) buildDocumentSema(w workspace.W, stack *ast.Stack) {
|
|
|
|
// Perform semantic analysis on all stacks passes to validate, transform, and/or update the AST.
|
|
|
|
b := NewBinder(c)
|
|
|
|
c.bindStack(b, w, stack)
|
|
|
|
if !c.Diag().Success() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bindStack performs the two phases of binding plus dependency resolution for the given Stack.
|
|
|
|
func (c *compiler) bindStack(b Binder, w workspace.W, stack *ast.Stack) {
|
2016-12-01 20:14:05 +01:00
|
|
|
util.Assert(stack != nil)
|
|
|
|
|
2016-11-23 16:26:45 +01:00
|
|
|
// First prepare the AST for binding.
|
2016-12-02 00:39:58 +01:00
|
|
|
deprefs := b.PrepareStack(stack)
|
2016-11-23 16:26:45 +01:00
|
|
|
if !c.Diag().Success() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, resolve all dependencies discovered during this first pass.
|
2016-12-02 00:39:58 +01:00
|
|
|
depdocs := make(ast.DependencyDocuments)
|
|
|
|
for _, ref := range deprefs {
|
|
|
|
// Only resolve dependencies that are currently unknown. This will exlude built-in types that have already
|
|
|
|
// been bound to a stack during the first phase of binding. Note that we don't actually parse and perform
|
|
|
|
// template substitution here; instead, we remember the document and let the binder do this, since it has
|
|
|
|
// all of the information necessary to create a unique Stack per-PropertyBag used to instantiate it.
|
|
|
|
if doc := c.resolveDependency(w, stack, ref); doc != nil {
|
|
|
|
depdocs[ref] = doc
|
2016-11-23 16:26:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !c.Diag().Success() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-12-01 20:14:05 +01:00
|
|
|
// Complete the binding process.
|
2016-12-02 00:39:58 +01:00
|
|
|
deps := b.BindStack(stack, depdocs)
|
|
|
|
if !c.Diag().Success() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now ensure we bind all dependency stacks too.
|
|
|
|
for _, dep := range deps {
|
|
|
|
c.bindStack(b, w, dep)
|
|
|
|
}
|
2016-11-23 16:26:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// resolveDependency loads up the target dependency from the current workspace using the stack resolution rules.
|
2016-12-02 00:39:58 +01:00
|
|
|
func (c *compiler) resolveDependency(w workspace.W, stack *ast.Stack, ref ast.Ref) *diag.Document {
|
|
|
|
glog.V(3).Infof("Loading Stack %v dependency %v", stack.Name, ref)
|
2016-11-23 16:26:45 +01:00
|
|
|
|
|
|
|
// First, see if we've already loaded this dependency (anywhere in any Stacks). If yes, reuse it.
|
|
|
|
// TODO: check for version mismatches.
|
2016-11-25 21:58:29 +01:00
|
|
|
if doc, exists := c.deps[ref]; exists {
|
|
|
|
return doc
|
2016-11-23 16:26:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// There are many places a dependency could come from. Consult the workspace for a list of those paths. It will
|
|
|
|
// return a number of them, in preferred order, and we simply probe each one until we find something.
|
2016-12-02 00:39:58 +01:00
|
|
|
dep := ref.MustParse()
|
2016-11-23 16:26:45 +01:00
|
|
|
for _, loc := range w.DepCandidates(dep) {
|
|
|
|
// Try to read this location as a document.
|
|
|
|
isMufile := workspace.IsMufile(loc, c.Diag())
|
|
|
|
glog.V(5).Infof("Probing for dependency %v at %v: %v", dep, loc, isMufile)
|
|
|
|
|
|
|
|
if isMufile {
|
|
|
|
doc, err := diag.ReadDocument(loc)
|
|
|
|
if err != nil {
|
2016-11-23 16:44:03 +01:00
|
|
|
c.Diag().Errorf(errors.ErrorCouldNotReadMufile.AtFile(loc), err)
|
2016-11-23 16:26:45 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memoize this in the compiler's cache and return it.
|
2016-11-25 21:58:29 +01:00
|
|
|
c.deps[ref] = doc
|
|
|
|
return doc
|
2016-11-23 16:26:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we got to this spot, we could not find the dependency. Issue an error and bail out.
|
2016-12-02 00:39:58 +01:00
|
|
|
c.Diag().Errorf(errors.ErrorStackTypeNotFound.At(stack), ref)
|
2016-11-23 16:26:45 +01:00
|
|
|
return nil
|
|
|
|
}
|