87 lines
2.3 KiB
Go
87 lines
2.3 KiB
Go
package interpreters
|
|
|
|
// Predicate is a function that specifies whether a certain description
|
|
// is active within another.
|
|
type Predicate func(inst *Instance) bool
|
|
|
|
// Always is a predicate that returns true for every call.
|
|
func Always(inst *Instance) bool {
|
|
return true
|
|
}
|
|
|
|
// Never is a predicate that returns false for every call.
|
|
func Never(inst *Instance) bool {
|
|
return false
|
|
}
|
|
|
|
// Description is the meta information about a data interpreter. A description
|
|
// is an immutable object that provides new descriptions with any modification.
|
|
type Description struct {
|
|
fields map[string]*entry
|
|
refinements map[string]*refinement
|
|
lastField *entry
|
|
}
|
|
|
|
var empty = newDescription()
|
|
|
|
// New returns an empty description.
|
|
func New() *Description {
|
|
return empty
|
|
}
|
|
|
|
func newDescription() *Description {
|
|
return &Description{
|
|
fields: make(map[string]*entry),
|
|
refinements: make(map[string]*refinement)}
|
|
}
|
|
|
|
func (desc *Description) clone() *Description {
|
|
cloned := newDescription()
|
|
|
|
for key, e := range desc.fields {
|
|
cloned.fields[key] = e
|
|
}
|
|
for key, r := range desc.refinements {
|
|
cloned.refinements[key] = r
|
|
}
|
|
|
|
return cloned
|
|
}
|
|
|
|
// For returns an instance of an interpreter with the given data slice
|
|
// as backing buffer.
|
|
func (desc *Description) For(data []byte) *Instance {
|
|
return &Instance{desc: desc, data: data}
|
|
}
|
|
|
|
// With extends the given description with a new field.
|
|
// The returned description is a new, separated object from the originating one.
|
|
func (desc *Description) With(key string, byteStart int, byteCount int) *Description {
|
|
cloned := desc.clone()
|
|
cloned.lastField = &entry{start: byteStart, count: byteCount}
|
|
cloned.fields[key] = cloned.lastField
|
|
|
|
return cloned
|
|
}
|
|
|
|
// As sets the value range for the previously added field.
|
|
func (desc *Description) As(fieldRange FieldRange) *Description {
|
|
if desc.lastField == nil {
|
|
panic("No field active")
|
|
}
|
|
desc.lastField.via = fieldRange
|
|
return desc
|
|
}
|
|
|
|
// Refining adds another description within the given one. The provided predicate
|
|
// determines whether the refined description is active.
|
|
func (desc *Description) Refining(key string, byteStart int, byteCount int, refined *Description, predicate Predicate) *Description {
|
|
cloned := desc.clone()
|
|
cloned.refinements[key] = &refinement{
|
|
entry: entry{start: byteStart, count: byteCount},
|
|
desc: refined,
|
|
predicate: predicate}
|
|
|
|
return cloned
|
|
}
|