2016-11-15 20:30:34 +01:00
|
|
|
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
|
|
|
|
package compiler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/golang/glog"
|
|
|
|
|
|
|
|
"github.com/marapongo/mu/pkg/diag"
|
|
|
|
"github.com/marapongo/mu/pkg/errors"
|
|
|
|
"github.com/marapongo/mu/pkg/workspace"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Compiler provides an interface into the many phases of the Mu compilation process.
|
|
|
|
type Compiler interface {
|
2016-11-16 02:42:22 +01:00
|
|
|
// Context returns the current compiler context.
|
|
|
|
Context() *Context
|
|
|
|
|
2016-11-16 01:30:10 +01:00
|
|
|
// Diag fetches the diagnostics sink used by this compiler instance.
|
|
|
|
Diag() diag.Sink
|
2016-11-15 20:30:34 +01:00
|
|
|
|
|
|
|
// Build detects and compiles inputs from the given location, storing build artifacts in the given destination.
|
|
|
|
Build(inp string, outp string)
|
|
|
|
}
|
|
|
|
|
|
|
|
// compiler is the canonical implementation of the Mu compiler.
|
|
|
|
type compiler struct {
|
2016-11-16 02:42:22 +01:00
|
|
|
ctx *Context
|
2016-11-15 20:30:34 +01:00
|
|
|
opts Options
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewCompiler creates a new instance of the Mu compiler, with the given initialization settings.
|
|
|
|
func NewCompiler(opts Options) Compiler {
|
2016-11-16 02:42:22 +01:00
|
|
|
return &compiler{
|
|
|
|
ctx: &Context{},
|
|
|
|
opts: opts,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *compiler) Context() *Context {
|
|
|
|
return c.ctx
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
2016-11-16 01:30:10 +01:00
|
|
|
func (c *compiler) Diag() diag.Sink {
|
|
|
|
return c.opts.Diag
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *compiler) Build(inp string, outp string) {
|
2016-11-16 01:30:10 +01:00
|
|
|
glog.Infof("Building target '%v' (out='%v')", inp, outp)
|
|
|
|
if glog.V(2) {
|
|
|
|
defer func() {
|
|
|
|
glog.V(2).Infof("Building target '%v' completed w/ %v warnings and %v errors",
|
|
|
|
inp, c.Diag().Warnings(), c.Diag().Errors())
|
|
|
|
}()
|
|
|
|
}
|
2016-11-15 20:30:34 +01:00
|
|
|
|
|
|
|
// First find the root of the current package based on the location of its Mufile.
|
|
|
|
mufile, err := workspace.DetectMufile(inp)
|
|
|
|
if err != nil {
|
2016-11-16 01:30:10 +01:00
|
|
|
c.Diag().Errorf(errors.MissingMufile, inp)
|
2016-11-15 20:30:34 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-16 02:42:22 +01:00
|
|
|
// Read in the contents of the document and make it available to subsequent stages.
|
|
|
|
doc, err := diag.ReadDocument(mufile)
|
|
|
|
if err != nil {
|
|
|
|
c.Diag().Errorf(errors.CouldNotReadMufile.WithFile(mufile), err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-15 20:30:34 +01:00
|
|
|
// To build the Mu package, first parse the input file.
|
|
|
|
p := NewParser(c)
|
2016-11-16 02:42:22 +01:00
|
|
|
stack := p.Parse(doc)
|
|
|
|
if p.Diag().Errors() > 0 {
|
|
|
|
// If any errors happened during parsing, we cannot proceed; exit now.
|
2016-11-15 20:30:34 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-16 02:42:22 +01:00
|
|
|
// Do a pass over the parse tree to ensure that all is well.
|
|
|
|
ptAnalyzer := NewPTAnalyzer(c)
|
|
|
|
ptAnalyzer.Analyze(doc, stack)
|
|
|
|
if p.Diag().Errors() > 0 {
|
|
|
|
// If any errors happened during parse tree analysis, we cannot proceed; exit now.
|
|
|
|
return
|
|
|
|
}
|
2016-11-15 20:30:34 +01:00
|
|
|
|
2016-11-16 02:42:22 +01:00
|
|
|
// TODO: here are some steps still remaining during compilation:
|
|
|
|
// - read in dependencies (mu_modules or equivalent necessary).
|
|
|
|
// - binding.
|
|
|
|
// - decide if we need a "lower" form that includes bound nodes (likely yes).
|
|
|
|
// - semantic analysis (e.g., check that cloud targets aren't incompatible; argument checking; etc).
|
|
|
|
// - read in cluster targets information if present.
|
|
|
|
// - lower the ASTs to the provider's representation, and emit it.
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|