lang: Initial implementation of the mgmt language
This is an initial implementation of the mgmt language. It is a declarative (immutable) functional, reactive, domain specific programming language. It is intended to be a language that is: * safe * powerful * easy to reason about With these properties, we hope this language, and the mgmt engine will allow you to model the real-time systems that you'd like to automate. This also includes a number of other associated changes. Sorry for the large size of this patch.
This commit is contained in:
126
lang/interfaces/ast.go
Normal file
126
lang/interfaces/ast.go
Normal file
@@ -0,0 +1,126 @@
|
||||
// Mgmt
|
||||
// Copyright (C) 2013-2018+ James Shubin and the project contributors
|
||||
// Written by James Shubin <james@shubin.ca> and the project contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"github.com/purpleidea/mgmt/lang/types"
|
||||
"github.com/purpleidea/mgmt/pgraph"
|
||||
"github.com/purpleidea/mgmt/resources"
|
||||
)
|
||||
|
||||
const (
|
||||
// Debug enables debugging for some commonly used debug information.
|
||||
Debug = false
|
||||
)
|
||||
|
||||
// Stmt represents a statement node in the language. A stmt could be a resource,
|
||||
// a `bind` statement, or even an `if` statement. (Different from an `if`
|
||||
// expression.)
|
||||
type Stmt interface {
|
||||
Interpolate() (Stmt, error) // return expanded form of AST as a new AST
|
||||
SetScope(*Scope) error // set the scope here and propagate it downwards
|
||||
Unify() ([]Invariant, error) // TODO: is this named correctly?
|
||||
Graph() (*pgraph.Graph, error)
|
||||
Output() (*Output, error)
|
||||
}
|
||||
|
||||
// Expr represents an expression in the language. Expr implementations must have
|
||||
// their method receivers implemented as pointer receivers so that they can be
|
||||
// easily copied and moved around. Expr also implements pgraph.Vertex so that
|
||||
// these can be stored as pointers in our graph data structure.
|
||||
type Expr interface {
|
||||
pgraph.Vertex // must implement this since we store these in our graphs
|
||||
Interpolate() (Expr, error) // return expanded form of AST as a new AST
|
||||
SetScope(*Scope) error // set the scope here and propagate it downwards
|
||||
SetType(*types.Type) error // sets the type definitively, errors if incompatible
|
||||
Type() (*types.Type, error)
|
||||
Unify() ([]Invariant, error) // TODO: is this named correctly?
|
||||
Graph() (*pgraph.Graph, error)
|
||||
Func() (Func, error) // a function that represents this reactively
|
||||
SetValue(types.Value) error
|
||||
Value() (types.Value, error)
|
||||
}
|
||||
|
||||
// Scope represents a mapping between a variables identifier and the
|
||||
// corresponding expression it is bound to. Local scopes in this language exist
|
||||
// and are formed by nesting within if statements. Child scopes can shadow
|
||||
// variables in parent scopes, which is another way of saying they can redefine
|
||||
// previously used variables as long as the new binding happens within a child
|
||||
// scope. This is useful so that someone in the top scope can't prevent a child
|
||||
// module from ever using that variable name again. It might be worth revisiting
|
||||
// this point in the future if we find it adds even greater code safety. Please
|
||||
// report any bugs you have written that would have been prevented by this.
|
||||
type Scope struct {
|
||||
Variables map[string]Expr
|
||||
//Functions map[string]??? // TODO: do we want a separate namespace for user defined functions?
|
||||
}
|
||||
|
||||
// Empty returns the zero, empty value for the scope, with all the internal
|
||||
// lists initialized appropriately.
|
||||
func (obj *Scope) Empty() *Scope {
|
||||
return &Scope{
|
||||
Variables: make(map[string]Expr),
|
||||
//Functions: ???,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy makes a copy of the Scope struct. This ensures that if the internal map
|
||||
// is changed, it doesn't affect other copies of the Scope. It does *not* copy
|
||||
// or change the Expr pointers contained within, since these are references, and
|
||||
// we need those to be consistently pointing to the same things after copying.
|
||||
func (obj *Scope) Copy() *Scope {
|
||||
variables := make(map[string]Expr)
|
||||
if obj != nil { // allow copying nil scopes
|
||||
for k, v := range obj.Variables { // copy
|
||||
variables[k] = v // we don't copy the expr's!
|
||||
}
|
||||
}
|
||||
return &Scope{
|
||||
Variables: variables,
|
||||
}
|
||||
}
|
||||
|
||||
// Edge is the data structure representing a compiled edge that is used in the
|
||||
// lang to express a dependency between two resources and optionally send/recv.
|
||||
type Edge struct {
|
||||
Kind1 string // kind of resource
|
||||
Name1 string // name of resource
|
||||
Send string // name of field used for send/recv (optional)
|
||||
|
||||
Kind2 string // kind of resource
|
||||
Name2 string // name of resource
|
||||
Recv string // name of field used for send/recv (optional)
|
||||
|
||||
Notify bool // is there a notification being sent?
|
||||
}
|
||||
|
||||
// Output is a collection of data returned by a Stmt.
|
||||
type Output struct { // returned by Stmt
|
||||
Resources []resources.Res
|
||||
Edges []*Edge
|
||||
//Exported []*Exports // TODO: add exported resources
|
||||
}
|
||||
|
||||
// Empty returns the zero, empty value for the output, with all the internal
|
||||
// lists initialized appropriately.
|
||||
func (obj *Output) Empty() *Output {
|
||||
return &Output{
|
||||
Resources: []resources.Res{},
|
||||
Edges: []*Edge{},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user