hcl/zcl/structure.go
Martin Atkins dfafa6fc00 Flesh out interface for evaluating expressions
Expressions can now be evaluated within an "EvalContext", which provides
the variable and function scopes. The JSON implementation of this
currently ignores the context entirely and just returns literal values,
since we've not yet implemented the template language parser that would
be needed for the JSON parser to properly support expressions.
2017-05-20 15:17:56 -07:00

135 lines
4.6 KiB
Go

package zcl
import (
"github.com/apparentlymart/go-cty/cty"
)
// File is the top-level node that results from parsing a ZCL file.
type File struct {
Body Body
Bytes []byte
// Nav is used to integrate with the "zcled" editor integration package,
// and with diagnostic information formatters. It is not for direct use
// by a calling application.
Nav interface{}
}
// Block represents a nested block within a Body.
type Block struct {
Type string
Labels []string
Body Body
DefRange Range // Range that can be considered the "definition" for seeking in an editor
TypeRange Range // Range for the block type declaration specifically.
LabelRanges []Range // Ranges for the label values specifically.
}
// Blocks is a sequence of Block.
type Blocks []*Block
// Body is a container for attributes and blocks. It serves as the primary
// unit of heirarchical structure within configuration.
//
// The content of a body cannot be meaningfully intepreted without a schema,
// so Body represents the raw body content and has methods that allow the
// content to be extracted in terms of a given schema.
type Body interface {
// Content verifies that the entire body content conforms to the given
// schema and then returns it, and/or returns diagnostics. The returned
// body content is valid if non-nil, regardless of whether Diagnostics
// are provided, but diagnostics should still be eventually shown to
// the user.
Content(schema *BodySchema) (*BodyContent, Diagnostics)
// PartialContent is like Content except that it permits the configuration
// to contain additional blocks or attributes not specified in the
// schema. If any are present, the returned Body is non-nil and contains
// the remaining items from the body that were not selected by the schema.
PartialContent(schema *BodySchema) (*BodyContent, Body, Diagnostics)
// JustAttributes attempts to interpret all of the contents of the body
// as attributes, allowing for the contents to be accessed without a priori
// knowledge of the structure.
//
// The behavior of this method depends on the body's source language.
// Some languages, like JSON, can't distinguish between attributes and
// blocks without schema hints, but for languages that _can_ error
// diagnostics will be generated if any blocks are present in the body.
//
// Diagnostics may be produced for other reasons too, such as duplicate
// declarations of the same attribute.
JustAttributes() (map[string]*Attribute, Diagnostics)
}
// BodyContent is the result of applying a BodySchema to a Body.
type BodyContent struct {
Attributes map[string]*Attribute
Blocks Blocks
}
// Attribute represents an attribute from within a body.
type Attribute struct {
Name string
Expr Expression
Range Range
NameRange Range
ExprRange Range
}
// Expression is a literal value or an expression provided in the
// configuration, which can be evaluated within a scope to produce a value.
type Expression interface {
// Value returns the value resulting from evaluating the expression
// in the given evaluation context.
//
// The context may be nil, in which case the expression may contain
// only constants and diagnostics will be produced for any non-constant
// sub-expressions. (The exact definition of this depends on the source
// language.)
//
// The context may instead be set but have either its Variables or
// Functions maps set to nil, in which case only use of these features
// will return diagnostics.
//
// Different diagnostics are provided depending on whether the given
// context maps are nil or empty. In the former case, the message
// tells the user that variables/functions are not permitted at all,
// while in the latter case usage will produce a "not found" error for
// the specific symbol in question.
Value(ctx *EvalContext) (cty.Value, Diagnostics)
// TODO: A "Variables" method that returns a description of all of the
// variables used in the expression, so callers can populate the scope
// only with variables that are actually used.
}
// OfType filters the receiving block sequence by block type name,
// returning a new block sequence including only the blocks of the
// requested type.
func (els Blocks) OfType(typeName string) Blocks {
ret := make(Blocks, 0)
for _, el := range els {
if el.Type == typeName {
ret = append(ret, el)
}
}
return ret
}
// ByType transforms the receiving block sequence into a map from type
// name to block sequences of only that type.
func (els Blocks) ByType() map[string]Blocks {
ret := make(map[string]Blocks)
for _, el := range els {
ty := el.Type
if ret[ty] == nil {
ret[ty] = make(Blocks, 0, 1)
}
ret[ty] = append(ret[ty], el)
}
return ret
}