-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathitem.go
196 lines (169 loc) · 4.11 KB
/
item.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) 2019, The Emergent Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package esg
import (
"fmt"
"strings"
)
// Item is one item within a rule
type Item struct { //git:add
// probability for choosing this item -- 0 if uniform random
Prob float32
// elements of the rule -- for non-Cond rules
Elems []Elem
// conditions for this item -- specified by ?
Cond Conds
// for conditional, this is the sub-rule that is run with sub-items
SubRule *Rule
// state update name=value to set for rule
State State
}
// String returns string rep
func (it *Item) String() string {
if it.Cond != nil {
return it.Cond.String() + it.SubRule.String()
}
sout := ""
if it.Prob > 0 {
sout = "%" + fmt.Sprintf("%g ", it.Prob)
}
for i := range it.Elems {
el := &it.Elems[i]
sout += el.String() + " "
}
return sout
}
// Gen generates expression according to the item
func (it *Item) Gen(rl *Rule, rls *Rules) {
if it.SubRule != nil {
it.State.Set(rls, "") // no value
it.SubRule.Gen(rls)
}
if len(it.Elems) > 0 {
it.State.Set(rls, it.Elems[0].Value)
for i := range it.Elems {
el := &it.Elems[i]
el.Gen(rl, rls)
}
}
}
// CondTrue evalutes whether the condition is true
func (it *Item) CondEval(rl *Rule, rls *Rules) bool {
return it.Cond.Eval(rls)
}
// Validate checks for config errors
func (it *Item) Validate(rl *Rule, rls *Rules) []error {
if it.Cond != nil {
ers := it.Cond.Validate(rl, it, rls)
if it.SubRule == nil {
ers = append(ers, fmt.Errorf("Rule: %v Item: %v IsCond but SubRule == nil", rl.Name, it.String()))
} else {
srs := it.SubRule.Validate(rls)
if len(srs) > 0 {
ers = append(ers, srs...)
}
}
return ers
}
var errs []error
for i := range it.Elems {
el := &it.Elems[i]
ers := el.Validate(it, rl, rls)
if len(ers) > 0 {
errs = append(errs, ers...)
}
}
return errs
}
/////////////////////////////////////////////////////////////////////
// Elem
// Elem is one elemenent in a concrete Item: either rule or token
type Elem struct { //git:add
// type of element: Rule, Token, or SubItems
El Elements
// value of the token: name of Rule or Token
Value string
}
// String returns string rep
func (el *Elem) String() string {
if el.El == TokenEl {
return "'" + el.Value + "'"
}
return el.Value
}
// Gen generates expression according to the element
func (el *Elem) Gen(rl *Rule, rls *Rules) {
switch el.El {
case RuleEl:
rl, _ := rls.Rule(el.Value)
rl.Gen(rls)
case TokenEl:
if rls.Trace {
fmt.Printf("Rule: %v added Token output: %v\n", rl.Name, el.Value)
}
rls.AddOutput(el.Value)
}
}
// Validate checks for config errors
func (el *Elem) Validate(it *Item, rl *Rule, rls *Rules) []error {
switch el.El {
case RuleEl:
_, err := rls.Rule(el.Value)
if err != nil {
return []error{err}
}
return nil
case TokenEl:
if el.Value == "" {
err := fmt.Errorf("Rule: %v Item: %v has empty Token element", rl.Name, it.String())
return []error{err}
}
}
return nil
}
// Elements are different types of elements
type Elements int32 //enums:enum
const (
// RuleEl means Value is name of a rule
RuleEl Elements = iota
// TokenEl means Value is a token to emit
TokenEl
)
/////////////////////////////////////////////////////////////////////
// State
// State holds the name=value state settings associated with rule or item
// as a string, string map
type State map[string]string
// Add adds give name, value to state
func (ss *State) Add(name, val string) {
if *ss == nil {
*ss = make(map[string]string)
}
(*ss)[name] = val
}
// Set sets state in rules States map, using given value for any items that have empty values
func (ss *State) Set(rls *Rules, val string) bool {
if len(*ss) == 0 {
return false
}
for k, v := range *ss {
if v == "" {
v = val
}
rls.States[k] = v
if rls.Trace {
fmt.Printf("Set State: %v = %v\n", k, v)
}
}
return true
}
// TrimQualifiers removes any :X qualifiers after state values
func (ss *State) TrimQualifiers() {
for k, v := range *ss {
ci := strings.Index(v, ":")
if ci > 0 {
(*ss)[k] = v[:ci]
}
}
}