-
-
Notifications
You must be signed in to change notification settings - Fork 559
/
expression.go
117 lines (101 loc) Β· 4.09 KB
/
expression.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package eval
import "reflect"
type (
// Expression built by the engine through the DSL functions.
Expression interface {
// EvalName is the qualified name of the DSL expression e.g. "service
// bottle".
EvalName() string
}
// A Root expression represents an entry point to the executed DSL: upon
// execution the DSL engine iterates over all root expressions and calls
// their WalkSets methods to iterate over the sub-expressions.
Root interface {
Expression
// WalkSets implements the visitor pattern: is is called by the engine so
// the DSL can control the order of execution. WalkSets calls back the
// engine via the given iterator as many times as needed providing the
// expression sets on each callback.
WalkSets(SetWalker)
// DependsOn returns the list of other DSL roots this root depends on. The
// engine uses this function to order the execution of the DSL roots.
DependsOn() []Root
// Packages returns the import path to the Go packages that make up the
// DSL. This is used to skip frames that point to files in these packages
// when computing the location of errors.
Packages() []string
}
// A Source expression embeds DSL to be executed after the process is loaded.
Source interface {
// DSL returns the DSL used to initialize the expression in a second pass.
DSL() func()
}
// A Preparer expression requires an additional pass after the DSL has
// executed and BEFORE it is validated (e.g. to flatten inheritance)
Preparer interface {
// Prepare is run by the engine right after the DSL has run. Prepare
// cannot fail, any potential failure should be returned by implementing
// Validator instead.
Prepare()
}
// A Validator expression can be validated.
Validator interface {
// Validate runs after Prepare if the expression is a Preparer. It returns
// nil if the expression contains no validation error. The Validate
// implementation may take advantage of ValidationErrors to report more
// than one errors at a time.
Validate() error
}
// A Finalizer expression requires an additional pass after the DSL has
// executed and has been validated (e.g. to merge generated expressions or
// initialize default values).
Finalizer interface {
// Finalize is run by the engine as the last step. Finalize cannot fail,
// any potential failure should be returned by implementing Validator
// instead.
Finalize()
}
// DSLFunc is a type that DSL expressions may embed to store DSL. It
// implements Source.
DSLFunc func()
// TopExpr is the type of Top.
TopExpr string
// ExpressionSet is a sequence of expressions processed in order. Each DSL
// implementation provides an arbitrary number of expression sets to the
// engine via iterators (see the Root interface WalkSets method).
//
// The items in the set may implement the Source, Preparer, Validator and/or
// Finalizer interfaces to enable the corresponding behaviors during DSL
// execution. The engine first runs the expression DSLs (for the ones that
// implement Source), then prepares them (for the ones that implement
// Preparer), then validates them (for the ones that implement Validator), and
// finalizes them (for the ones that implement Finalizer).
ExpressionSet []Expression
// SetWalker is the function signature used to iterate over expression sets
// with WalkSets.
SetWalker func(s ExpressionSet)
)
// Top is the expression returned by Current when the execution stack is empty.
const Top TopExpr = "top-level"
// DSL returns the DSL function.
func (f DSLFunc) DSL() func() {
return f
}
// EvalName is the name is the qualified name of the expression.
func (t TopExpr) EvalName() string { return string(t) }
// ToExpressionSet is a convenience function that accepts a slice of expressions
// and builds the corresponding ExpressionSet.
func ToExpressionSet(slice any) ExpressionSet {
if slice == nil {
return nil
}
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("ToExpressionSet() given a non-slice type") // bug
}
ret := make(ExpressionSet, s.Len())
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface().(Expression)
}
return ret
}