| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- package main
- import (
- "fmt"
- "math"
- "regexp"
- "strconv"
- "strings"
- )
- const (
- _name = `([A-Za-z_](\w|\.)*)`
- _nameOrInt = "(" + _name + `|\d+)`
- _index = "(" + _nameOrInt + "|:|" + _nameOrInt + ":|:" + _nameOrInt + "|" + _nameOrInt + ":" + _nameOrInt + ")"
- )
- var (
- nameExp = regexp.MustCompile("^" + _name + "$")
- nameWithIndexExp = regexp.MustCompile("^" + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
- )
- func isNumber(val value) bool {
- if _, ok := val.(*_number); ok {
- return true
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- }
- _, err := strconv.ParseFloat(s, 64)
- return err == nil
- }
- func toNumber(val value) float64 {
- if val, ok := val.(*_number); ok {
- return val.Value()
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- }
- if num, err := strconv.ParseFloat(s, 64); err == nil {
- return num
- }
- panic(fmt.Errorf("number: %s (%s)", errInvalidNumber, s))
- }
- func toInt(val value, envs []environ) int {
- if isName(val) {
- if newVal, err := getValue(val.String(), envs); err == nil {
- val = newVal
- if val, ok := val.(*_number); ok {
- num := val.Value()
- if num != math.Floor(num) {
- panic(fmt.Errorf("int: %s (%f)", errInvalidInteger, num))
- }
- return int(num)
- }
- }
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- }
- if num, err := strconv.ParseInt(s, 10, 64); err == nil {
- return int(num)
- }
- panic(fmt.Errorf("int: %s (%s)", errInvalidInteger, s))
- }
- func isBool(val value) bool {
- if _, ok := val.(*_bool); ok {
- return true
- }
- if val, ok := val.(*_number); ok && (val.Value() == 0 || val.Value() == 1) {
- return true
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- }
- return s == "false" || s == "true"
- }
- func toBool(val value) bool {
- if val, ok := val.(*_bool); ok {
- return val.Value()
- }
- if val, ok := val.(*_number); ok && (val.Value() == 0 || val.Value() == 1) {
- return val.Value() == 1
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- }
- if s == "false" || s == "true" {
- return s == "true"
- }
- panic(fmt.Errorf("bool: %s (%s)", errInvalidBool, s))
- }
- func isWord(val value) bool {
- if _, ok := val.(*_word); ok {
- return true
- }
- if val, ok := val.(*_number); ok && len(val.word) > 0 {
- return true
- }
- if val, ok := val.(*_bool); ok && len(val.word) > 0 {
- return true
- }
- s := val.String()
- return len(s) > 0 && s[0] == '"'
- }
- func toWord(val value) string {
- if val, ok := val.(*_word); ok {
- return val.Value()
- }
- if val, ok := val.(*_number); ok && len(val.word) > 0 {
- return val.word
- }
- if val, ok := val.(*_bool); ok && len(val.word) > 0 {
- return val.word
- }
- s := val.String()
- if len(s) > 0 && s[0] == '"' {
- return parseWord(s).Value()
- }
- panic(fmt.Errorf("word: %s (%s)", errInvalidWord, s))
- }
- func parseWord(s string) *_word {
- if len(s) > 0 && s[0] == '"' {
- s = s[1:]
- if len(s) > 0 {
- if s[0] == '[' {
- s = `\[` + s[1:]
- }
- if s[len(s)-1] == ']' {
- s = s[:len(s)-1]
- escape := len(s) - len(strings.TrimRight(s, `\`))
- if (escape & 1) == 0 {
- s += `\`
- }
- s += "]"
- }
- if s[len(s)-1] == '\\' {
- escape := len(s) - len(strings.TrimRight(s, `\`))
- if (escape & 1) == 1 {
- panic(fmt.Errorf("word: %s (%s)", errUnmatchedEscape, s))
- }
- }
- }
- }
- return &_word{word: s}
- }
- func escapeWord(s string) string {
- for i := 0; i < len(s); i++ {
- if s[i] == '\\' {
- s = s[:i] + s[i+1:]
- }
- }
- return s
- }
- func isName(val value) bool {
- s := val.String()
- return nameExp.MatchString(s)
- }
- func toName(val value) string {
- s := val.String()
- if nameExp.MatchString(s) {
- return s
- }
- panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
- }
- func isNameWithIndex(val value) bool {
- s := val.String()
- return nameWithIndexExp.MatchString(s)
- }
- func toNameWithIndex(val value) (string, []string) {
- s := val.String()
- if nameWithIndexExp.MatchString(s) {
- index := strings.Split(s, "[")
- name := index[0]
- if cnt := len(index) - 1; cnt > 0 {
- 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:]
- }
- panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
- }
- func isList(val value) bool {
- if _, ok := val.(*_list); ok {
- return true
- }
- s := val.String()
- return len(s) > 0 && s[0] == '['
- }
- func toList(val value) []string {
- if val, ok := val.(*_list); ok {
- return val.Value()
- }
- s := val.String()
- if len(s) > 0 && s[0] == '[' {
- return parseFunc(s, []environ{nil, nil, nil}).Value()
- }
- panic(fmt.Errorf("list: %s (%s)", errInvalidList, s))
- }
- func parseFunc(s string, envs []environ) *_list {
- list := parseList(s)
- if len(list) != 2 || !isList(&_unknown{s: list[0]}) || !isList(&_unknown{s: list[1]}) {
- return &_list{list: list}
- }
- param := parseList(list[0])
- for _, name := range param {
- if !isName(&_unknown{s: name}) {
- return &_list{list: list}
- }
- }
- local := environ{}
- if envs[1] != nil {
- for name, val := range envs[0] {
- local[name] = val
- }
- }
- return &_list{list: list, param: param, body: parseList(list[1]), env: local}
- }
- func isEmpty(val value) bool {
- if val, ok := val.(*_word); ok {
- return len(val.Value()) == 0
- }
- if val, ok := val.(*_list); ok {
- return len(val.Value()) == 0
- }
- s := val.String()
- return s == `"` || s == "[ ]"
- }
- func toValue(val value, envs []environ) value {
- if _, ok := val.(*_unknown); !ok {
- return val
- }
- s := val.String()
- if isNumber(val) {
- if isWord(val) {
- s = s[1:]
- }
- return &_number{num: toNumber(val), word: s}
- }
- if isBool(val) {
- if isWord(val) {
- s = s[1:]
- }
- return &_bool{b: toBool(val), word: s}
- }
- if isWord(val) {
- return parseWord(s)
- }
- if isList(val) {
- return parseFunc(s, envs)
- }
- panic(fmt.Errorf("value: %s (%s)", errValueExpected, s))
- }
- func opIsNumber(val1 value) *_bool {
- return &_bool{b: isNumber(val1)}
- }
- func opIsBool(val1 value) *_bool {
- return &_bool{b: isBool(val1)}
- }
- func opIsWord(val1 value) *_bool {
- return &_bool{b: isWord(val1)}
- }
- func opIsName(val1 value, envs []environ) *_bool {
- if !isName(val1) {
- return &_bool{b: false}
- }
- name := toName(val1)
- for _, env := range envs {
- _, ok := env[name]
- if ok {
- return &_bool{b: true}
- }
- }
- return &_bool{b: false}
- }
- func opIsList(val1 value) *_bool {
- return &_bool{b: isList(val1)}
- }
- func opIsEmpty(val1 value) *_bool {
- return &_bool{b: isEmpty(val1)}
- }
|