// but callers can also feel free to just produce a slice of PathStep manually
// and convert to this type, which may be more appropriate in environments
// where memory pressure is a concern.
+//
+// Although a Path is technically mutable, by convention callers should not
+// mutate a path once it has been built and passed to some other subsystem.
+// Instead, use Copy and then mutate the copy before using it.
type Path []PathStep
// PathStep represents a single step down into a data structure, as part
return ret
}
+// IndexPath is a convenience method to start a new Path with an IndexStep.
+func IndexPath(v Value) Path {
+ return Path{}.Index(v)
+}
+
// GetAttr returns a new Path that is the reciever with a GetAttrStep appended
// to the end.
//
return ret
}
+// GetAttrPath is a convenience method to start a new Path with a GetAttrStep.
+func GetAttrPath(name string) Path {
+ return Path{}.GetAttr(name)
+}
+
// Apply applies each of the steps in turn to successive values starting with
// the given value, and returns the result. If any step returns an error,
// the whole operation returns an error.
// Apply returns the value resulting from indexing the given value with
// our key value.
func (s IndexStep) Apply(val Value) (Value, error) {
+ if val == NilVal || val.IsNull() {
+ return NilVal, errors.New("cannot index a null value")
+ }
+
switch s.Key.Type() {
case Number:
- if !val.Type().IsListType() {
+ if !(val.Type().IsListType() || val.Type().IsTupleType()) {
return NilVal, errors.New("not a list type")
}
case String:
// Apply returns the value of our named attribute from the given value, which
// must be of an object type that has a value of that name.
func (s GetAttrStep) Apply(val Value) (Value, error) {
+ if val == NilVal || val.IsNull() {
+ return NilVal, errors.New("cannot access attributes on a null value")
+ }
+
if !val.Type().IsObjectType() {
return NilVal, errors.New("not an object type")
}