| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- package main
- import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
- )
- const _name, _nameOrInt = `([A-Za-z]\w*)`, "(" + _name + `|\d+)`
- const _index = "(" + _nameOrInt + "|:|" + _nameOrInt + ":|:" + _nameOrInt + "|" + _nameOrInt + ":" + _nameOrInt + ")"
- var nameExp = regexp.MustCompile(`^"` + _name + "$")
- var nameWithIndexExp = regexp.MustCompile(`^"` + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
- func isName(s string) bool {
- return nameExp.MatchString(s)
- }
- func toName(s string) string {
- if !isName(s) {
- panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
- }
- return s[1:]
- }
- func isNameWithIndex(s string) bool {
- return nameWithIndexExp.MatchString(s)
- }
- func toNameWithIndex(s string) (string, []string) {
- if !isNameWithIndex(s) {
- panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
- }
- index := strings.Split(s, "[")
- name, cnt := index[0][1:], len(index)-1
- for i := 1; i < cnt; i++ {
- index[i] = index[i][:len(index[i])-1]
- }
- index[cnt] = index[cnt][:len(index[cnt])-2]
- return name, index[1:]
- }
- func isNumber(s string) bool {
- if s != "" && s[0] == '"' {
- s = s[1:]
- }
- _, err := strconv.ParseFloat(s, 64)
- return err == nil
- }
- func toNumber(s string) float64 {
- if s != "" && s[0] == '"' {
- s = s[1:]
- }
- val, err := strconv.ParseFloat(s, 64)
- if err != nil {
- panic(fmt.Errorf("number: %s (%s)", errInvalidNumber, s))
- }
- return val
- }
- func toInt(s string) int {
- if isName(`"` + s) {
- val, err := getValue(`"` + s)
- if err == nil {
- s = val.val
- }
- }
- if s != "" && s[0] == '"' {
- s = s[1:]
- }
- val, err := strconv.ParseInt(s, 10, 64)
- if err != nil {
- panic(fmt.Errorf("int: %s (%s)", errInvalidInteger, s))
- }
- return int(val)
- }
- func isWord(s string) bool {
- return s != "" && s[0] == '"'
- }
- func isList(s string) bool {
- return s != "" && s[0] == '['
- }
- func isBool(s string) bool {
- if s != "" && s[0] == '"' {
- s = s[1:]
- }
- _, err := strconv.ParseBool(s)
- return err == nil
- }
- func toBool(s string) bool {
- if s != "" && s[0] == '"' {
- s = s[1:]
- }
- val, err := strconv.ParseBool(s)
- if err != nil {
- panic(fmt.Errorf("bool: %s (%s)", errInvalidBool, s))
- }
- return val
- }
- func isEmpty(s string) bool {
- return s == `"` || s == "[ ]"
- }
- func parseFunc(s string) value {
- if !isList(s) {
- return value{val: s}
- }
- list := parseList(s)
- if len(list) != 2 || !isList(list[0]) || !isList(list[1]) {
- return value{val: s, list: list}
- }
- param := parseList(list[0])
- for _, name := range param {
- if !isName(`"` + name) {
- return value{val: s, list: list}
- }
- }
- local := make(environ)
- for name, val := range env[len(env)-1] {
- local[name] = val
- }
- return value{val: s, list: list, param: param, env: local}
- }
- func isValue(s string) bool {
- return isNumber(s) || isWord(s) || isList(s) || isBool(s)
- }
- func toValue(val value) value {
- if !isValue(val.val) {
- panic(fmt.Errorf("mua: %s (%s)", errValueExpected, val.val))
- }
- if isWord(val.val) {
- if val.val[1] == '[' {
- val.val = val.val[:1] + "\\" + val.val[1:]
- }
- if val.val[len(val.val)-1] == ']' {
- val.val = val.val[:len(val.val)-1]
- escape := len(val.val) - len(strings.TrimRight(val.val, "\\"))
- if (escape & 1) == 0 {
- val.val += "\\"
- }
- val.val += "]"
- }
- return val
- }
- if isList(val.val) {
- if val.list == nil {
- return parseFunc(val.val)
- }
- return val
- }
- return val
- }
- func escapeValue(s string) string {
- for i := 0; i < len(s); i++ {
- if s[i] == '\\' {
- s = s[:i] + s[i+1:]
- }
- }
- return s
- }
- func opIsName(val1 value) value {
- return value{val: strconv.FormatBool(isName(val1.val))}
- }
- func opIsNumber(val1 value) value {
- return value{val: strconv.FormatBool(isNumber(val1.val))}
- }
- func opIsWord(val1 value) value {
- return value{val: strconv.FormatBool(isWord(val1.val))}
- }
- func opIsList(val1 value) value {
- return value{val: strconv.FormatBool(isList(val1.val))}
- }
- func opIsBool(val1 value) value {
- return value{val: strconv.FormatBool(isBool(val1.val))}
- }
- func opIsEmpty(val1 value) value {
- return value{val: strconv.FormatBool(isEmpty(val1.val))}
- }
|