package main import ( "bufio" "fmt" "os" "strconv" "strings" ) func assign(s string, index []string, val string) string { if len(index) == 0 { return val } list, i := parseList(s), toInt(index[0]) return spliceList(list, i, 1, assign(indexOfList(list, i), index[1:], val)) } func setValue(s string, val value) (value, error) { if !isNameWithIndex(s) { return value{}, fmt.Errorf("setvalue: %s (%s)", errInvalidName, s) } name, index := toNameWithIndex(s) _, ok := reserved[name] if ok { return value{}, fmt.Errorf("setvalue: %s (%s)", errNameReserved, name) } oldVal, ok := env[len(env)-1][name] if !ok && len(index) > 0 { return value{}, fmt.Errorf("setvalue: %s (%s)", errNameNotFound, name) } if len(index) > 0 { if isWord(val.val) { val.val = val.val[1:] } val = value{val: assign(oldVal.val, index, val.val)} } val = toValue(val) env[len(env)-1][name] = val return val, nil } func getValue(s string) (value, error) { if !isNameWithIndex(s) { return value{}, fmt.Errorf("getvalue: %s (%s)", errInvalidName, s) } name, index := toNameWithIndex(s) envs := []int{len(env) - 1, len(env) - 2, 1} for _, id := range envs { val, ok := env[id][name] if ok { for _, i := range index { list, r := parseList(val.val), strings.Split(i, ":") if len(r) == 1 { val = value{val: indexOfList(list, toInt(r[0]))} if !isList(val.val) { val.val = `"` + val.val } } else { if r[0] == "" { r[0] = "0" } if r[1] == "" { r[1] = strconv.FormatInt(int64(len(list)), 10) } val = value{val: rangeOfList(list, toInt(r[0]), toInt(r[1]))} } } return val, nil } } return value{}, fmt.Errorf("getvalue: %s (%s)", errNameNotFound, name) } func opMake(val1, val2 value) value { val, err := setValue(val1.val, val2) if err != nil { panic(err) } return val } func opThing(val1 value) value { val, err := getValue(val1.val) if err != nil { panic(err) } return val } func opErase(val1 value) value { name := toName(val1.val) val, ok := env[len(env)-1][name] if ok { delete(env[len(env)-1], name) return val } panic(fmt.Errorf("erase: %s (%s)", errNameNotFound, name)) } func opExport(val1 value) value { name := toName(val1.val) val, ok := env[len(env)-1][name] if ok { env[1][name] = val return val } panic(fmt.Errorf("export: %s (%s)", errNameNotFound, name)) } func opSave(val1 value) value { name := toName(val1.val) s := "" for name, val := range env[len(env)-1] { s += `make "` + name + " " + val.val + "\n" } err := os.WriteFile(name, []byte(s), 0666) if err != nil { panic(fmt.Errorf("save: %s (%s)", errFileError, name)) } return val1 } func opLoad(val1 value) value { name := toName(val1.val) s, err := os.ReadFile(name) if err != nil { panic(fmt.Errorf("load: %s (%s)", errFileError, name)) } interpret(bufio.NewScanner(strings.NewReader(string(s)))) return value{val: "true"} } func opErAll() value { env[len(env)-1] = make(environ) return value{val: "true"} } func opPoAll() value { list := []string{} for name := range env[len(env)-1] { list = append(list, name) } return value{val: makeList(list)} }