package varsimport ()typeelemstruct {variableVarassocers []interface{}indices []interface{}setValueinterface{}}func ( *elem) ( interface{}) error {varerror := // Evaluate the actual new value from inside out. See comments in // MakeElement for how element assignment works.for := len(.assocers) - 1; >= 0; -- { , = vals.Assoc(.assocers[], .indices[], )if != nil {return } } = .variable.Set()// TODO(xiaq): Remember the set value for use in Get. .setValue = return}func ( *elem) () interface{} {// TODO(xiaq): This is only called from fixNilVariables. We don't want to // waste time accessing the variable, so we simply return the value that was // set.return .setValue}// MakeElement returns a variable, that when set, simulates the mutation of an// element.func ( Var, []interface{}) (Var, error) {// Assignment of indexed variables actually assigns the variable, with // the right hand being a nested series of Assocs. As the simplest // example, `a[0] = x` is equivalent to `a = (assoc $a 0 x)`. A more // complex example is that `a[0][1][2] = x` is equivalent to // `a = (assoc $a 0 (assoc $a[0] 1 (assoc $a[0][1] 2 x)))`. // Note that in each assoc form, the first two arguments can be // determined now, while the last argument is only known when the // right-hand-side is known. So here we evaluate the first two arguments // of each assoc form and put them in two slices, assocers and indices. // In the previous example, the two slices will contain: // // assocers: $a $a[0] $a[0][1] // indices: 0 1 2 // // When the right-hand side of the assignment becomes available, the new // value for $a is evaluated by doing Assoc from inside out. := make([]interface{}, len()) := .Get() [0] = for , := range [:len()-1] { := [] , := vals.Index(, )if != nil {returnnil, } [+1] = }return &elem{, , , nil}, nil}// DelElement deletes an element. It uses a similar process to MakeElement,// except that the last level of container needs to be Dissoc-able instead of// Assoc-able.func ( Var, []interface{}) error {varerror// In "del a[0][1][2]", // // indices: 0 1 2 // assocers: $a $a[0] // dissocer: $a[0][1] := make([]interface{}, len()-1) := .Get()for , := range [:len()-1] { [] = varerror , = vals.Index(, )if != nil {return } } := vals.Dissoc(, [len()-1])if == nil {returnelemErr{len(), "value does not support element removal"} }for := len() - 1; >= 0; -- { , = vals.Assoc([], [], )if != nil {return } }return .Set()}typeelemErrstruct {levelintmsgstring}func ( elemErr) () string {return .msg}// HeadOfElement gets the underlying head variable of an element variable, or// nil if the argument is not an element variable.func ( Var) Var {if , := .(*elem); {return .variable }returnnil}// ElementErrorLevel returns the level of an error returned by MakeElement or// DelElement. Level 0 represents that the error is about the variable itself.// If the argument was not returned from MakeVariable, -1 is returned.func ( error) int {if , := .(elemErr); {return .level }return -1}
The pages are generated with Goldsv0.2.8-preview. (GOOS=darwin GOARCH=arm64)