|
|
@@ -11,9 +11,9 @@ import (
|
|
|
const (
|
|
|
typeUnknown = iota
|
|
|
typeNumber
|
|
|
+ typeBool
|
|
|
typeWord
|
|
|
typeList
|
|
|
- typeBool
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
@@ -25,34 +25,6 @@ const (
|
|
|
var nameExp = regexp.MustCompile(`^"` + _name + "$")
|
|
|
var nameWithIndexExp = regexp.MustCompile(`^"` + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
|
|
|
|
|
|
-func isName(val value) bool {
|
|
|
- return nameExp.MatchString(val.word)
|
|
|
-}
|
|
|
-
|
|
|
-func toName(val value) string {
|
|
|
- if !isName(val) {
|
|
|
- panic(fmt.Errorf("name: %s", errInvalidName))
|
|
|
- }
|
|
|
- return val.word[1:]
|
|
|
-}
|
|
|
-
|
|
|
-func isNameWithIndex(val value) bool {
|
|
|
- return nameWithIndexExp.MatchString(val.word)
|
|
|
-}
|
|
|
-
|
|
|
-func toNameWithIndex(val value) (string, []string) {
|
|
|
- if !isNameWithIndex(val) {
|
|
|
- panic(fmt.Errorf("name: %s", errInvalidName))
|
|
|
- }
|
|
|
- index := strings.Split(val.word, "[")
|
|
|
- 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(val value) bool {
|
|
|
if val.tp == typeNumber {
|
|
|
return true
|
|
|
@@ -101,6 +73,35 @@ func toInt(val value, envs []environ) int {
|
|
|
return int(num)
|
|
|
}
|
|
|
|
|
|
+func isBool(val value) bool {
|
|
|
+ if val.tp == typeBool {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if isWord(val) {
|
|
|
+ val.word = val.word[1:]
|
|
|
+ }
|
|
|
+ return val.word == "true" || val.word == "false"
|
|
|
+}
|
|
|
+
|
|
|
+func toBool(val value) bool {
|
|
|
+ if val.tp == typeBool {
|
|
|
+ return val.b
|
|
|
+ }
|
|
|
+ if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
|
|
|
+ return val.num == 1
|
|
|
+ }
|
|
|
+ if isWord(val) {
|
|
|
+ val.word = val.word[1:]
|
|
|
+ }
|
|
|
+ if val.word != "true" && val.word != "false" {
|
|
|
+ panic(fmt.Errorf("bool: %s", errInvalidBool))
|
|
|
+ }
|
|
|
+ return val.word == "true"
|
|
|
+}
|
|
|
+
|
|
|
func isWord(val value) bool {
|
|
|
if val.tp == typeWord {
|
|
|
return true
|
|
|
@@ -134,6 +135,34 @@ func escapeWord(s string) string {
|
|
|
return s
|
|
|
}
|
|
|
|
|
|
+func isName(val value) bool {
|
|
|
+ return nameExp.MatchString(val.word)
|
|
|
+}
|
|
|
+
|
|
|
+func toName(val value) string {
|
|
|
+ if !isName(val) {
|
|
|
+ panic(fmt.Errorf("name: %s", errInvalidName))
|
|
|
+ }
|
|
|
+ return val.word[1:]
|
|
|
+}
|
|
|
+
|
|
|
+func isNameWithIndex(val value) bool {
|
|
|
+ return nameWithIndexExp.MatchString(val.word)
|
|
|
+}
|
|
|
+
|
|
|
+func toNameWithIndex(val value) (string, []string) {
|
|
|
+ if !isNameWithIndex(val) {
|
|
|
+ panic(fmt.Errorf("name: %s", errInvalidName))
|
|
|
+ }
|
|
|
+ index := strings.Split(val.word, "[")
|
|
|
+ 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 isList(val value) bool {
|
|
|
if val.tp == typeList {
|
|
|
return true
|
|
|
@@ -142,52 +171,21 @@ func isList(val value) bool {
|
|
|
}
|
|
|
|
|
|
func parseFunc(s string, env environ) value {
|
|
|
- list, split := parseList(s)
|
|
|
+ list := parseList(s)
|
|
|
if len(list) != 2 || !isList(value{word: list[0]}) || !isList(value{word: list[1]}) {
|
|
|
- return value{tp: typeList, list: list, split: split}
|
|
|
+ return value{tp: typeList, list: list}
|
|
|
}
|
|
|
- param, _ := parseList(list[0])
|
|
|
+ param := parseList(list[0])
|
|
|
for _, name := range param {
|
|
|
if !isName(value{word: `"` + name}) {
|
|
|
- return value{tp: typeList, list: list, split: split}
|
|
|
+ return value{tp: typeList, list: list}
|
|
|
}
|
|
|
}
|
|
|
local := environ{}
|
|
|
for name, val := range env {
|
|
|
local[name] = val
|
|
|
}
|
|
|
- return value{tp: typeList, list: list, split: split, param: param, body: strings.Split(list[1], " "), env: local}
|
|
|
-}
|
|
|
-
|
|
|
-func isBool(val value) bool {
|
|
|
- if val.tp == typeBool {
|
|
|
- return true
|
|
|
- }
|
|
|
- if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
|
|
|
- return true
|
|
|
- }
|
|
|
- if isWord(val) {
|
|
|
- val.word = val.word[1:]
|
|
|
- }
|
|
|
- _, err := strconv.ParseBool(val.word)
|
|
|
- return err == nil
|
|
|
-}
|
|
|
-
|
|
|
-func toBool(val value) bool {
|
|
|
- if val.tp == typeBool {
|
|
|
- return val.b
|
|
|
- }
|
|
|
- if val.tp == typeNumber && (val.num == 0 || val.num == 1) {
|
|
|
- return val.num == 1
|
|
|
- }
|
|
|
- if isWord(val) {
|
|
|
- val.word = val.word[1:]
|
|
|
- }
|
|
|
- b, err := strconv.ParseBool(val.word)
|
|
|
- if err != nil {
|
|
|
- panic(fmt.Errorf("bool: %s", errInvalidBool))
|
|
|
- }
|
|
|
- return b
|
|
|
+ return value{tp: typeList, list: list, param: param, body: parseList(list[1]), env: local}
|
|
|
}
|
|
|
|
|
|
func isEmpty(val value) bool {
|
|
|
@@ -207,15 +205,15 @@ func toValue(val value, env environ) value {
|
|
|
if isNumber(val) {
|
|
|
return value{tp: typeNumber, num: toNumber(val)}
|
|
|
}
|
|
|
+ if isBool(val) {
|
|
|
+ return value{tp: typeBool, b: toBool(val)}
|
|
|
+ }
|
|
|
if isWord(val) {
|
|
|
return parseWord(val.word)
|
|
|
}
|
|
|
if isList(val) {
|
|
|
return parseFunc(val.word, env)
|
|
|
}
|
|
|
- if isBool(val) {
|
|
|
- return value{tp: typeBool, b: toBool(val)}
|
|
|
- }
|
|
|
panic(fmt.Errorf("value: %s", errValueExpected))
|
|
|
}
|
|
|
|
|
|
@@ -223,36 +221,36 @@ func toString(val value) string {
|
|
|
if val.tp == typeNumber {
|
|
|
return strconv.FormatFloat(val.num, 'g', -1, 64)
|
|
|
}
|
|
|
+ if val.tp == typeBool {
|
|
|
+ return strconv.FormatBool(val.b)
|
|
|
+ }
|
|
|
if val.tp == typeWord {
|
|
|
return val.word[1:]
|
|
|
}
|
|
|
if val.tp == typeList {
|
|
|
return makeList(val.list)
|
|
|
}
|
|
|
- if val.tp == typeBool {
|
|
|
- return strconv.FormatBool(val.b)
|
|
|
- }
|
|
|
panic(fmt.Errorf("string: %s", errValueExpected))
|
|
|
}
|
|
|
|
|
|
-func opIsName(val1 value) value {
|
|
|
- return value{tp: typeBool, b: isName(val1)}
|
|
|
-}
|
|
|
-
|
|
|
func opIsNumber(val1 value) value {
|
|
|
return value{tp: typeBool, b: isNumber(val1)}
|
|
|
}
|
|
|
|
|
|
+func opIsBool(val1 value) value {
|
|
|
+ return value{tp: typeBool, b: isBool(val1)}
|
|
|
+}
|
|
|
+
|
|
|
func opIsWord(val1 value) value {
|
|
|
return value{tp: typeBool, b: isWord(val1)}
|
|
|
}
|
|
|
|
|
|
-func opIsList(val1 value) value {
|
|
|
- return value{tp: typeBool, b: isList(val1)}
|
|
|
+func opIsName(val1 value) value {
|
|
|
+ return value{tp: typeBool, b: isName(val1)}
|
|
|
}
|
|
|
|
|
|
-func opIsBool(val1 value) value {
|
|
|
- return value{tp: typeBool, b: isBool(val1)}
|
|
|
+func opIsList(val1 value) value {
|
|
|
+ return value{tp: typeBool, b: isList(val1)}
|
|
|
}
|
|
|
|
|
|
func opIsEmpty(val1 value) value {
|