Browse Source

ADD. 完善类型系统并改进性能

RegMs If 4 years ago
parent
commit
f4b557a5ff
10 changed files with 590 additions and 523 deletions
  1. 78 69
      bind.go
  2. 8 11
      ctrl.go
  3. 27 26
      in
  4. 19 22
      io.go
  5. 58 78
      list.go
  6. 38 51
      math.go
  7. BIN
      mua
  8. 133 164
      mua.go
  9. 61 0
      scan.go
  10. 168 102
      type.go

+ 78 - 69
bind.go

@@ -4,115 +4,120 @@ import (
 	"bufio"
 	"bufio"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
-	"strconv"
 	"strings"
 	"strings"
 )
 )
 
 
-func assign(s string, index []string, val string) string {
+func assign(s string, index []string, val string, envs []environ) string {
 	if len(index) == 0 {
 	if len(index) == 0 {
 		return val
 		return val
 	}
 	}
-	list, i := parseList(s), toInt(index[0])
-	return spliceList(list, i, 1, assign(indexOfList(list, i), index[1:], val))
+	list, _ := parseList(s)
+	i := toInt(value{word: index[0]}, envs)
+	return spliceList(list, i, 1, assign(indexOfList(list, i), index[1:], val, envs))
 }
 }
 
 
-func setValue(s string, val value) (value, error) {
-	if !isNameWithIndex(s) {
-		return value{}, fmt.Errorf("setvalue: %s (%s)", errInvalidName, s)
+func setValue(s string, val value, envs []environ) (value, error) {
+	if !isNameWithIndex(value{word: s}) {
+		return value{}, fmt.Errorf("set: %s (%s)", errInvalidName, s)
 	}
 	}
-	name, index := toNameWithIndex(s)
+	name, index := toNameWithIndex(value{word: s})
 	_, ok := reserved[name]
 	_, ok := reserved[name]
 	if ok {
 	if ok {
-		return value{}, fmt.Errorf("setvalue: %s (%s)", errNameReserved, name)
+		return value{}, fmt.Errorf("set: %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:]
+	oldVal, ok := envs[0][name]
+	if ok {
+		delete(envs[0], name)
+		if len(index) > 0 {
+			val = value{word: assign(toString(oldVal), index, toString(val), envs)}
 		}
 		}
-		val = value{val: assign(oldVal.val, index, val.val)}
+	} else if len(index) > 0 {
+		return value{}, fmt.Errorf("set: %s (%s)", errNameNotFound, name)
 	}
 	}
-	val = toValue(val)
-	env[len(env)-1][name] = val
+	val = toValue(val, envs[0])
+	envs[0][name] = val
 	return val, nil
 	return val, nil
 }
 }
 
 
-func getValue(s string) (value, error) {
-	if !isNameWithIndex(s) {
-		return value{}, fmt.Errorf("getvalue: %s (%s)", errInvalidName, s)
+func getValue(s string, envs []environ) (value, error) {
+	if !isNameWithIndex(value{word: s}) {
+		return value{}, fmt.Errorf("get: %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]
+	name, index := toNameWithIndex(value{word: s})
+	for _, env := range envs {
+		val, ok := env[name]
 		if ok {
 		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 len(index) > 0 {
+				val = value{word: toString(val)}
+				for _, i := range index {
+					list, _ := parseList(val.word)
+					r := strings.Split(i, ":")
+					if len(r) == 1 {
+						val = value{word: indexOfList(list, toInt(value{word: r[0]}, envs))}
+						if !isList(val) {
+							val.word = `"` + val.word
+						}
+					} else {
+						num1, num2 := 0, len(list)
+						if r[0] != "" {
+							num1 = toInt(value{word: r[0]}, envs)
+						}
+						if r[1] != "" {
+							num2 = toInt(value{word: r[1]}, envs)
+						}
+						val = value{word: rangeOfList(list, num1, num2)}
 					}
 					}
-					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 val, nil
 		}
 		}
 	}
 	}
-	return value{}, fmt.Errorf("getvalue: %s (%s)", errNameNotFound, name)
+	return value{}, fmt.Errorf("get: %s (%s)", errNameNotFound, name)
 }
 }
 
 
-func opMake(val1, val2 value) value {
-	val, err := setValue(val1.val, val2)
+func opMake(val1, val2 value, envs []environ) value {
+	val, err := setValue(val1.word, val2, envs)
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
 	return val
 	return val
 }
 }
 
 
-func opThing(val1 value) value {
-	val, err := getValue(val1.val)
+func opThing(val1 value, envs []environ) value {
+	val, err := getValue(val1.word, envs)
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
 	return val
 	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
+func opErase(val1 value, envs []environ) value {
+	name := toName(val1)
+	for _, env := range envs {
+		val, ok := env[name]
+		if ok {
+			delete(env, name)
+			return val
+		}
 	}
 	}
 	panic(fmt.Errorf("erase: %s (%s)", errNameNotFound, name))
 	panic(fmt.Errorf("erase: %s (%s)", errNameNotFound, name))
 }
 }
 
 
-func opExport(val1 value) value {
-	name := toName(val1.val)
-	val, ok := env[len(env)-1][name]
+func opExport(val1 value, envs []environ) value {
+	name := toName(val1)
+	val, ok := envs[0][name]
 	if ok {
 	if ok {
-		env[1][name] = val
+		envs[2][name] = val
 		return val
 		return val
 	}
 	}
 	panic(fmt.Errorf("export: %s (%s)", errNameNotFound, name))
 	panic(fmt.Errorf("export: %s (%s)", errNameNotFound, name))
 }
 }
 
 
-func opSave(val1 value) value {
-	name := toName(val1.val)
+func opSave(val1 value, env environ) value {
+	name := toName(val1)
 	s := ""
 	s := ""
-	for name, val := range env[len(env)-1] {
-		s += `make "` + name + " " + val.val + "\n"
+	for name, val := range env {
+		s += `make "` + name + " " + val.word + "\n"
 	}
 	}
 	err := ioutil.WriteFile(name, []byte(s), 0666)
 	err := ioutil.WriteFile(name, []byte(s), 0666)
 	if err != nil {
 	if err != nil {
@@ -121,25 +126,29 @@ func opSave(val1 value) value {
 	return val1
 	return val1
 }
 }
 
 
-func opLoad(val1 value) value {
-	name := toName(val1.val)
+func opLoad(val1 value, env environ) value {
+	name := toName(val1)
 	s, err := ioutil.ReadFile(name)
 	s, err := ioutil.ReadFile(name)
 	if err != nil {
 	if err != nil {
 		panic(fmt.Errorf("load: %s (%s)", errFileError, name))
 		panic(fmt.Errorf("load: %s (%s)", errFileError, name))
 	}
 	}
-	interpret(bufio.NewScanner(strings.NewReader(string(s))))
-	return value{val: "true"}
+	scanner := bufio.NewScanner(strings.NewReader(string(s)))
+	scanner.Split(splitFunc)
+	interpret(&scanProvider{isList: false, scanner: scanner}, []environ{env, nil, nil})
+	return value{tp: typeBool, b: true}
 }
 }
 
 
-func opErAll() value {
-	env[len(env)-1] = make(environ)
-	return value{val: "true"}
+func opErAll(env environ) value {
+	for name := range env {
+		delete(env, name)
+	}
+	return value{tp: typeBool, b: true}
 }
 }
 
 
-func opPoAll() value {
+func opPoAll(env environ) value {
 	list := []string{}
 	list := []string{}
-	for name := range env[len(env)-1] {
+	for name := range env {
 		list = append(list, name)
 		list = append(list, name)
 	}
 	}
-	return value{val: makeList(list)}
+	return value{word: makeList(list)}
 }
 }

+ 8 - 11
ctrl.go

@@ -1,22 +1,19 @@
 package main
 package main
 
 
 import (
 import (
-	"bufio"
 	"fmt"
 	"fmt"
-	"strings"
 )
 )
 
 
-func opRun(val1 value) (value, bool) {
-	if !isList(val1.val) {
-		panic(fmt.Errorf("run: %s (%s)", errListExpected, val1.val))
+func opRun(val1 value, envs []environ) (value, bool) {
+	if !isList(val1) {
+		panic(fmt.Errorf("run: %s", errListExpected))
 	}
 	}
-	return interpret(bufio.NewScanner(strings.NewReader(val1.val[1 : len(val1.val)-1])))
+	return interpret(&scanProvider{isList: true, list: val1.split[1 : len(val1.split)-1]}, envs)
 }
 }
 
 
-func opIf(val1, val2, val3 value) (value, bool) {
-	b1 := toBool(val1.val)
-	if b1 {
-		return opRun(val2)
+func opIf(val1, val2, val3 value, envs []environ) (value, bool) {
+	if toBool(val1) {
+		return opRun(val2, envs)
 	}
 	}
-	return opRun(val3)
+	return opRun(val3, envs)
 }
 }

+ 27 - 26
in

@@ -1,3 +1,25 @@
+make "rev_func [
+  [f]
+  [
+    [
+      [a b]
+      [f :b :a]
+    ]
+  ]
+]
+make "rev_sub rev_func [[x y] [sub :x :y]]
+print rev_sub 2 5
+print rev_sub 26.5 10.3
+make "rev_ge rev_func [[x y] [or gt :x :y eq :x :y]]
+print rev_ge 3 7
+print rev_ge "abc "aBc
+print rev_ge 8 8
+make "rev_imply rev_func [[x y] [or not :x :y]]
+print rev_imply false false
+print rev_imply false true
+print rev_imply true false
+print rev_imply true true
+
 print "abcd12
 print "abcd12
 make "a 16
 make "a 16
 print :a
 print :a
@@ -24,28 +46,6 @@ make "x "t
 make "y "x
 make "y "x
 print :::y
 print :::y
 
 
-make "rev_func [
-  [f]
-  [
-    [
-      [a b]
-      [f :b :a]
-    ]
-  ]
-]
-make "rev_sub rev_func [[x y] [sub :x :y]]
-print rev_sub 2 5
-print rev_sub 26.5 10.3
-make "rev_ge rev_func [[x y] [or gt :x :y eq :x :y]]
-print rev_ge 3 7
-print rev_ge "abc "aBc
-print rev_ge 8 8
-make "rev_imply rev_func [[x y] [or not :x :y]]
-print rev_imply false false
-print rev_imply false true
-print rev_imply true false
-print rev_imply true true
-
 make "arr [ [ a b ] c ]
 make "arr [ [ a b ] c ]
 print :arr[0]
 print :arr[0]
 print :arr[1]
 print :arr[1]
@@ -98,8 +98,9 @@ make "pow [[a b] [
 
 
 print pow 2 18
 print pow 2 18
 
 
-print readlist
-a b c 1 2 3
+print make "ts readlist
+[1 ] c 1 \\\\[2 3\\]
+print islist :ts[1]
 
 
 make "reverse_list [
 make "reverse_list [
   [list]
   [list]
@@ -118,7 +119,7 @@ make "fib_wrap [
       [x]
       [x]
       [
       [
         if lt :x 2 [return 1] []
         if lt :x 2 [return 1] []
-        return add fib sub :x 1 fib sub :x 2
+        add fib sub :x 1 fib sub :x 2
       ]
       ]
     ]
     ]
     fib :x
     fib :x
@@ -134,7 +135,7 @@ print fib_wrap 5
 print fib_wrap 6
 print fib_wrap 6
 print fib_wrap 7
 print fib_wrap 7
 print fib_wrap 8
 print fib_wrap 8
-print fib_wrap 9
+print fib_wrap 20
 
 
 make "f [[x] [
 make "f [[x] [
   make "g [[y] [return add :x :y]]
   make "g [[y] [return add :x :y]]

+ 19 - 22
io.go

@@ -1,12 +1,11 @@
 package main
 package main
 
 
 import (
 import (
-	"bufio"
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 )
 )
 
 
-func opRead(scanner *bufio.Scanner) value {
+func opRead(scanner *scanProvider) value {
 	s := "\n"
 	s := "\n"
 	for s == "\n" && scanner.Scan() {
 	for s == "\n" && scanner.Scan() {
 		s = scanner.Text()
 		s = scanner.Text()
@@ -14,32 +13,31 @@ func opRead(scanner *bufio.Scanner) value {
 	if s == "\n" {
 	if s == "\n" {
 		panic(fmt.Errorf("read: %s", errUnexpectedEndOfInput))
 		panic(fmt.Errorf("read: %s", errUnexpectedEndOfInput))
 	}
 	}
-	return value{val: `"` + s}
+	return value{word: `"` + s}
 }
 }
 
 
 func opPrint(val1 value) value {
 func opPrint(val1 value) value {
-	s := escapeValue(val1.val)
-	if s != "" {
-		if s[0] == '"' {
-			fmt.Println(s[1:])
-		} else if s[0] == '[' {
-			list, space := strings.Split(s, " "), false
-			for i := 0; i < len(list); i++ {
-				if space && list[i] != "]" {
-					fmt.Print(" ")
-				}
-				fmt.Print(list[i])
-				space = list[i] != "["
+	if val1.tp == typeNumber {
+		fmt.Println(val1.num)
+	} else if val1.tp == typeWord {
+		fmt.Println(escapeWord(val1.word[1:]))
+	} else if val1.tp == typeList {
+		list, space := strings.Split(makeList(val1.list), " "), false
+		for i := 0; i < len(list); i++ {
+			if space && list[i] != "]" {
+				fmt.Print(" ")
 			}
 			}
-			fmt.Println()
-		} else {
-			fmt.Println(s)
+			fmt.Print(escapeWord(list[i]))
+			space = list[i] != "["
 		}
 		}
+		fmt.Println()
+	} else {
+		fmt.Println(val1.b)
 	}
 	}
 	return val1
 	return val1
 }
 }
 
 
-func opReadList(scanner *bufio.Scanner) value {
+func opReadList(scanner *scanProvider) value {
 	list, line := []string{}, false
 	list, line := []string{}, false
 	for scanner.Scan() {
 	for scanner.Scan() {
 		s := scanner.Text()
 		s := scanner.Text()
@@ -47,10 +45,9 @@ func opReadList(scanner *bufio.Scanner) value {
 			break
 			break
 		}
 		}
 		line = true
 		line = true
-		// todo
 		if s != "\n" {
 		if s != "\n" {
-			list = append(list, s)
+			list = append(list, parseWord(`"` + s).word[1:])
 		}
 		}
 	}
 	}
-	return value{val: "[ " + strings.Join(list, " ") + " ]"}
+	return value{word: makeList(list)}
 }
 }

+ 58 - 78
list.go

@@ -5,9 +5,9 @@ import (
 	"strings"
 	"strings"
 )
 )
 
 
-func parseList(s string) []string {
-	if !isList(s) {
-		panic(fmt.Errorf("parselist: %s (%s)", errListExpected, s))
+func parseList(s string) ([]string, []string) {
+	if !isList(value{word: s}) {
+		panic(fmt.Errorf("list: %s (%s)", errListExpected, s))
 	}
 	}
 	list, bracketCnt, start, resList := strings.Split(s, " "), 0, 1, []string{}
 	list, bracketCnt, start, resList := strings.Split(s, " "), 0, 1, []string{}
 	for i := 1; i < len(list)-1; i++ {
 	for i := 1; i < len(list)-1; i++ {
@@ -22,7 +22,7 @@ func parseList(s string) []string {
 			start = i + 1
 			start = i + 1
 		}
 		}
 	}
 	}
-	return resList
+	return resList, list
 }
 }
 
 
 func makeList(list []string) string {
 func makeList(list []string) string {
@@ -31,24 +31,24 @@ func makeList(list []string) string {
 
 
 func indexOfList(list []string, index int) string {
 func indexOfList(list []string, index int) string {
 	if index < 0 || index >= len(list) {
 	if index < 0 || index >= len(list) {
-		panic(fmt.Errorf("indexoflist: %s", errIndexOutOfBound))
+		panic(fmt.Errorf("list: %s (%d / %d)", errIndexOutOfBound, index, len(list)))
 	}
 	}
 	return list[index]
 	return list[index]
 }
 }
 
 
 func rangeOfList(list []string, index1, index2 int) string {
 func rangeOfList(list []string, index1, index2 int) string {
 	if index1 < 0 || index1 > len(list) || index2 < 0 || index2 > len(list) {
 	if index1 < 0 || index1 > len(list) || index2 < 0 || index2 > len(list) {
-		panic(fmt.Errorf("rangeoflist: %s", errIndexOutOfBound))
+		panic(fmt.Errorf("list: %s (%d : %d / %d)", errIndexOutOfBound, index1, index2, len(list)))
 	}
 	}
 	if index1 > index2 {
 	if index1 > index2 {
-		panic(fmt.Errorf("rangelist: %s", errIllegalRange))
+		panic(fmt.Errorf("list: %s (%d : %d)", errIllegalRange, index1, index2))
 	}
 	}
 	return makeList(list[index1:index2])
 	return makeList(list[index1:index2])
 }
 }
 
 
 func spliceList(list []string, index int, cnt int, val ...string) string {
 func spliceList(list []string, index int, cnt int, val ...string) string {
 	if index < 0 || index > len(list) {
 	if index < 0 || index > len(list) {
-		panic(fmt.Errorf("splicelist: %s", errIndexOutOfBound))
+		panic(fmt.Errorf("list: %s (%d / %d)", errIndexOutOfBound, index, len(list)))
 	}
 	}
 	if index+cnt > len(list) {
 	if index+cnt > len(list) {
 		cnt = len(list) - index
 		cnt = len(list) - index
@@ -57,111 +57,91 @@ func spliceList(list []string, index int, cnt int, val ...string) string {
 }
 }
 
 
 func opWord(val1, val2 value) value {
 func opWord(val1, val2 value) value {
-	if !isWord(val1.val) {
-		panic(fmt.Errorf("word: %s (%s)", errWordExpceted, val1.val))
+	if !isWord(val1) || isList(val2) {
+		panic(fmt.Errorf("word: %s", errWordExpceted))
 	}
 	}
-	if isWord(val2.val) {
-		return value{val: val1.val + val2.val[1:]}
-	}
-	if isNumber(val2.val) || isBool(val2.val) {
-		return value{val: val1.val + val2.val}
-	}
-	panic(fmt.Errorf("word: %s (%s)", errWordExpceted, val2.val))
+	return value{tp: typeWord, word: val1.word + toString(val2)}
 }
 }
 
 
 func opSentence(val1, val2 value) value {
 func opSentence(val1, val2 value) value {
-	list1, list2 := []string{val1.val}, []string{val2.val}
-	if isWord(val1.val) {
-		list1 = []string{val1.val[1:]}
-	} else if isList(val1.val) {
-		list1 = parseList(val1.val)
-	}
-	if isWord(val2.val) {
-		list2 = []string{val2.val[1:]}
-	} else if isList(val2.val) {
-		list2 = parseList(val2.val)
-	}
-	return value{val: makeList(append(list1, list2...))}
+	list1, list2 := []string{toString(val1)}, []string{toString(val2)}
+	if isList(val1) {
+		list1 = val1.list
+	}
+	if isList(val2) {
+		list2 = val2.list
+	}
+	return value{word: makeList(append(list1, list2...))}
 }
 }
 
 
 func opList(val1, val2 value) value {
 func opList(val1, val2 value) value {
-	if isWord(val1.val) {
-		val1.val = val1.val[1:]
-	}
-	if isWord(val2.val) {
-		val2.val = val2.val[1:]
-	}
-	return value{val: makeList([]string{val1.val, val2.val})}
+	return value{word: makeList([]string{toString(val1), toString(val2)})}
 }
 }
 
 
 func opJoin(val1, val2 value) value {
 func opJoin(val1, val2 value) value {
-	if !isList(val1.val) {
-		panic(fmt.Errorf("join: %s (%s)", errListExpected, val1.val))
-	}
-	if isWord(val2.val) {
-		val2.val = val2.val[1:]
+	if !isList(val1) {
+		fmt.Println(val1, val2)
+		panic(fmt.Errorf("join: %s", errListExpected))
 	}
 	}
-	return value{val: makeList(append(parseList(val1.val), val2.val))}
+	return value{word: makeList(append(val1.list, toString(val2)))}
 }
 }
 
 
 func opFirst(val1 value) value {
 func opFirst(val1 value) value {
-	if !isWord(val1.val) && !isList(val1.val) {
-		panic(fmt.Errorf("first: %s (%s)", errWordOrListExpected, val1.val))
+	if !isWord(val1) && !isList(val1) {
+		panic(fmt.Errorf("first: %s", errWordOrListExpected))
 	}
 	}
-	if isEmpty(val1.val) {
-		panic(fmt.Errorf("first: %s (%s)", errEmptyWordOrList, val1.val))
+	if isEmpty(val1) {
+		panic(fmt.Errorf("first: %s", errEmptyWordOrList))
 	}
 	}
-	if isWord(val1.val) {
-		return value{val: val1.val[:2]}
+	if isWord(val1) {
+		return value{word: val1.word[:2]}
 	}
 	}
-	list1 := parseList(val1.val)
-	if !isList(list1[0]) {
-		list1[0] = `"` + list1[0]
+	val := value{word: val1.list[0]}
+	if !isList(val) {
+		val.word = `"` + val.word
 	}
 	}
-	return value{val: list1[0]}
+	return val
 }
 }
 
 
 func opLast(val1 value) value {
 func opLast(val1 value) value {
-	if !isWord(val1.val) && !isList(val1.val) {
-		panic(fmt.Errorf("last: %s (%s)", errWordOrListExpected, val1.val))
+	if !isWord(val1) && !isList(val1) {
+		panic(fmt.Errorf("last: %s", errWordOrListExpected))
 	}
 	}
-	if isEmpty(val1.val) {
-		panic(fmt.Errorf("last: %s (%s)", errEmptyWordOrList, val1.val))
+	if isEmpty(val1) {
+		panic(fmt.Errorf("last: %s", errEmptyWordOrList))
 	}
 	}
-	if isWord(val1.val) {
-		return value{val: `"` + val1.val[len(val1.val)-1:]}
+	if isWord(val1) {
+		return value{word: `"` + val1.word[len(val1.word)-1:]}
 	}
 	}
-	list1 := parseList(val1.val)
-	if !isList(list1[len(list1)-1]) {
-		list1[len(list1)-1] = `"` + list1[len(list1)-1]
+	val := value{word: val1.list[len(val1.list)-1]}
+	if !isList(val) {
+		val.word = `"` + val.word
 	}
 	}
-	return value{val: list1[len(list1)-1]}
+	return val
 }
 }
 
 
 func opButFirst(val1 value) value {
 func opButFirst(val1 value) value {
-	if !isWord(val1.val) && !isList(val1.val) {
-		panic(fmt.Errorf("butfirst: %s (%s)", errWordOrListExpected, val1.val))
+	if !isWord(val1) && !isList(val1) {
+		panic(fmt.Errorf("butfirst: %s", errWordOrListExpected))
 	}
 	}
-	if isEmpty(val1.val) {
-		panic(fmt.Errorf("butfirst: %s (%s)", errEmptyWordOrList, val1.val))
+	if isEmpty(val1) {
+		panic(fmt.Errorf("butfirst: %s", errEmptyWordOrList))
 	}
 	}
-	if isWord(val1.val) {
-		return value{val: `"` + val1.val[2:]}
+	if isWord(val1) {
+		return value{word: `"` + val1.word[2:]}
 	}
 	}
-	list1 := parseList(val1.val)
-	return value{val: makeList(list1[1:])}
+	return value{word: makeList(val1.list[1:])}
 }
 }
 
 
 func opButLast(val1 value) value {
 func opButLast(val1 value) value {
-	if !isWord(val1.val) && !isList(val1.val) {
-		panic(fmt.Errorf("butlast: %s (%s)", errWordOrListExpected, val1.val))
+	if !isWord(val1) && !isList(val1) {
+		panic(fmt.Errorf("butlast: %s", errWordOrListExpected))
 	}
 	}
-	if isEmpty(val1.val) {
-		panic(fmt.Errorf("butlast: %s (%s)", errEmptyWordOrList, val1.val))
+	if isEmpty(val1) {
+		panic(fmt.Errorf("butlast: %s", errEmptyWordOrList))
 	}
 	}
-	if isWord(val1.val) {
-		return value{val: val1.val[:len(val1.val)-1]}
+	if isWord(val1) {
+		return value{word: val1.word[:len(val1.word)-1]}
 	}
 	}
-	list1 := parseList(val1.val)
-	return value{val: makeList(list1[:len(list1)-1])}
+	return value{word: makeList(val1.list[:len(val1.list)-1])}
 }
 }

+ 38 - 51
math.go

@@ -4,112 +4,99 @@ import (
 	"fmt"
 	"fmt"
 	"math"
 	"math"
 	"math/rand"
 	"math/rand"
-	"strconv"
 )
 )
 
 
 func opAdd(val1, val2 value) value {
 func opAdd(val1, val2 value) value {
-	num1, num2 := toNumber(val1.val), toNumber(val2.val)
-	return value{val: strconv.FormatFloat(num1+num2, 'g', -1, 64)}
+	return value{tp: typeNumber, num: toNumber(val1) + toNumber(val2)}
 }
 }
 
 
 func opSub(val1, val2 value) value {
 func opSub(val1, val2 value) value {
-	num1, num2 := toNumber(val1.val), toNumber(val2.val)
-	return value{val: strconv.FormatFloat(num1-num2, 'g', -1, 64)}
+	return value{tp: typeNumber, num: toNumber(val1) - toNumber(val2)}
 }
 }
 
 
 func opMul(val1, val2 value) value {
 func opMul(val1, val2 value) value {
-	num1, num2 := toNumber(val1.val), toNumber(val2.val)
-	return value{val: strconv.FormatFloat(num1*num2, 'g', -1, 64)}
+	return value{tp: typeNumber, num: toNumber(val1) * toNumber(val2)}
 }
 }
 
 
 func opDiv(val1, val2 value) value {
 func opDiv(val1, val2 value) value {
-	num1, num2 := toNumber(val1.val), toNumber(val2.val)
+	num1, num2 := toNumber(val1), toNumber(val2)
 	if num2 == 0 {
 	if num2 == 0 {
-		panic(fmt.Errorf("div: %s (%s / %s)", errDivisionByZero, val1.val, val2.val))
+		panic(fmt.Errorf("div: %s (%f / %f)", errDivisionByZero, num1, num2))
 	}
 	}
-	return value{val: strconv.FormatFloat(num1/num2, 'g', -1, 64)}
+	return value{tp: typeNumber, num: num1 / num2}
 }
 }
 
 
 func opMod(val1, val2 value) value {
 func opMod(val1, val2 value) value {
-	num1, num2 := toNumber(val1.val), toNumber(val2.val)
+	num1, num2 := toNumber(val1), toNumber(val2)
 	if num2 == 0 {
 	if num2 == 0 {
-		panic(fmt.Errorf("mod: %s (%s %% %s)", errDivisionByZero, val1.val, val2.val))
+		panic(fmt.Errorf("mod: %s (%f %% %f)", errDivisionByZero, num1, num2))
 	}
 	}
-	return value{val: strconv.FormatFloat(math.Mod(num1, num2), 'g', -1, 64)}
+	return value{tp: typeNumber, num: math.Mod(num1, num2)}
 }
 }
 
 
 func opEq(val1, val2 value) value {
 func opEq(val1, val2 value) value {
-	if isNumber(val1.val) && isNumber(val2.val) {
-		num1, num2 := toNumber(val1.val), toNumber(val2.val)
-		return value{val: strconv.FormatBool(num1 == num2)}
+	if isNumber(val1) && isNumber(val2) {
+		return value{tp: typeBool, b: toNumber(val1) == toNumber(val2)}
 	}
 	}
-	if isBool(val1.val) && isBool(val2.val) {
-		b1, b2 := toBool(val1.val), toBool(val2.val)
-		return value{val: strconv.FormatBool(b1 == b2)}
+	if isBool(val1) && isBool(val2) {
+		return value{tp: typeBool, b: toBool(val1) == toBool(val2)}
 	}
 	}
-	if isWord(val1.val) && isWord(val2.val) {
-		return value{val: strconv.FormatBool(escapeValue(val1.val) == escapeValue(val2.val))}
+	if isWord(val1) && isWord(val2) {
+		return value{tp: typeBool, b: escapeWord(val1.word) == escapeWord(val2.word)}
 	}
 	}
-	panic(fmt.Errorf("eq: %s (%s, %s)", errIllegalOperandType, val1.val, val2.val))
+	panic(fmt.Errorf("eq: %s", errIllegalOperandType))
 }
 }
 
 
 func opGt(val1, val2 value) value {
 func opGt(val1, val2 value) value {
-	if isNumber(val1.val) && isNumber(val2.val) {
-		num1, num2 := toNumber(val1.val), toNumber(val2.val)
-		return value{val: strconv.FormatBool(num1 > num2)}
+	if isNumber(val1) && isNumber(val2) {
+		return value{tp: typeBool, b: toNumber(val1) > toNumber(val2)}
 	}
 	}
-	if isBool(val1.val) && isBool(val2.val) {
-		b1, b2 := toBool(val1.val), toBool(val2.val)
-		return value{val: strconv.FormatBool(b1 || !b2)}
+	if isBool(val1) && isBool(val2) {
+		return value{tp: typeBool, b: toBool(val1) || !toBool(val2)}
 	}
 	}
-	if isWord(val1.val) && isWord(val2.val) {
-		return value{val: strconv.FormatBool(escapeValue(val1.val) > escapeValue(val2.val))}
+	if isWord(val1) && isWord(val2) {
+		return value{tp: typeBool, b: escapeWord(val1.word) > escapeWord(val2.word)}
 	}
 	}
-	panic(fmt.Errorf("gt: %s (%s, %s)", errIllegalOperandType, val1.val, val2.val))
+	panic(fmt.Errorf("gt: %s", errIllegalOperandType))
 }
 }
 
 
 func opLt(val1, val2 value) value {
 func opLt(val1, val2 value) value {
-	if isNumber(val1.val) && isNumber(val2.val) {
-		num1, num2 := toNumber(val1.val), toNumber(val2.val)
-		return value{val: strconv.FormatBool(num1 < num2)}
+	if isNumber(val1) && isNumber(val2) {
+		return value{tp: typeBool, b: toNumber(val1) < toNumber(val2)}
 	}
 	}
-	if isBool(val1.val) && isBool(val2.val) {
-		b1, b2 := toBool(val1.val), toBool(val2.val)
-		return value{val: strconv.FormatBool(!b1 || b2)}
+	if isBool(val1) && isBool(val2) {
+		return value{tp: typeBool, b: !toBool(val1) || toBool(val2)}
 	}
 	}
-	if isWord(val1.val) && isWord(val2.val) {
-		return value{val: strconv.FormatBool(escapeValue(val1.val) < escapeValue(val2.val))}
+	if isWord(val1) && isWord(val2) {
+		return value{tp: typeBool, b: escapeWord(val1.word) < escapeWord(val2.word)}
 	}
 	}
-	panic(fmt.Errorf("lt: %s (%s, %s)", errIllegalOperandType, val1.val, val2.val))
+	panic(fmt.Errorf("lt: %s", errIllegalOperandType))
 }
 }
 
 
 func opAnd(val1, val2 value) value {
 func opAnd(val1, val2 value) value {
-	b1, b2 := toBool(val1.val), toBool(val2.val)
-	return value{val: strconv.FormatBool(b1 && b2)}
+	return value{tp: typeBool, b: toBool(val1) && toBool(val2)}
 }
 }
 
 
 func opOr(val1, val2 value) value {
 func opOr(val1, val2 value) value {
-	b1, b2 := toBool(val1.val), toBool(val2.val)
-	return value{val: strconv.FormatBool(b1 || b2)}
+	return value{tp: typeBool, b: toBool(val1) || toBool(val2)}
 }
 }
 
 
 func opNot(val1 value) value {
 func opNot(val1 value) value {
-	b1 := toBool(val1.val)
-	return value{val: strconv.FormatBool(!b1)}
+	return value{tp: typeBool, b: !toBool(val1)}
 }
 }
 
 
 func opRandom(val1 value) value {
 func opRandom(val1 value) value {
-	return value{val: strconv.FormatFloat(toNumber(val1.val)*rand.Float64(), 'g', -1, 64)}
+	return value{tp: typeNumber, num: toNumber(val1) * rand.Float64()}
 }
 }
 
 
 func opInt(val1 value) value {
 func opInt(val1 value) value {
-	return value{val: strconv.FormatFloat(math.Floor(toNumber(val1.val)), 'g', -1, 64)}
+	return value{tp: typeNumber, num: math.Floor(toNumber(val1))}
 }
 }
 
 
 func opSqrt(val1 value) value {
 func opSqrt(val1 value) value {
-	num1 := toNumber(val1.val)
+	num1 := toNumber(val1)
 	if num1 < 0 {
 	if num1 < 0 {
-		panic(fmt.Errorf("sqrt: %s (%s)", errNegativeSquareRoot, val1.val))
+		panic(fmt.Errorf("sqrt: %s (%f)", errNegativeSquareRoot, num1))
 	}
 	}
-	return value{val: strconv.FormatFloat(math.Sqrt(num1), 'g', -1, 64)}
+	return value{tp: typeNumber, num: math.Sqrt(num1)}
 }
 }

BIN
mua


+ 133 - 164
mua.go

@@ -7,8 +7,6 @@ import (
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"time"
 	"time"
-	"unicode"
-	"unicode/utf8"
 )
 )
 
 
 var reserved = map[string]int{
 var reserved = map[string]int{
@@ -24,58 +22,35 @@ var reserved = map[string]int{
 
 
 type environ map[string]value
 type environ map[string]value
 type value struct {
 type value struct {
-	val   string
+	tp    int
+	num   float64
+	word  string
 	list  []string
 	list  []string
+	split []string
 	param []string
 	param []string
+	body  []string
 	env   environ
 	env   environ
+	b     bool
 }
 }
 
 
-var env []environ
-var stack []value
-
-func interpret(scanner *bufio.Scanner) (val value, returned bool) {
-	stackTop, returned := len(stack), false
-	scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
-		start := 0
-		for start < len(data) {
-			r, width := utf8.DecodeRune(data[start:])
-			if r == '\n' {
-				return start + width, data[start : start+width], nil
-			}
-			if !unicode.IsSpace(r) {
-				break
-			}
-			start += width
-		}
-		for i := start; i < len(data); {
-			r, width := utf8.DecodeRune(data[i:])
-			if r == '\n' {
-				return i, data[start:i], nil
-			}
-			if unicode.IsSpace(r) {
-				return i + width, data[start:i], nil
-			}
-			i += width
-		}
-		if atEOF && len(data) > start {
-			return len(data), data[start:], nil
-		}
-		return start, nil, nil
-	})
+func interpret(scanner *scanProvider, envs []environ) (val value, returned bool) {
+	stack, returned := []value{}, false
 	for !returned && scanner.Scan() {
 	for !returned && scanner.Scan() {
 		// for _, v := range stack {
 		// for _, v := range stack {
-		// 	fmt.Println(v.val)
+		// 	fmt.Println(toString(v))
 		// }
 		// }
 		// fmt.Println()
 		// fmt.Println()
+		// fmt.Println(envs[0])
+		// fmt.Println()
 		s := scanner.Text()
 		s := scanner.Text()
 		if s == "\n" {
 		if s == "\n" {
 			continue
 			continue
 		}
 		}
 		if s[0] == ':' {
 		if s[0] == ':' {
 			leading := len(s) - len(strings.TrimLeft(s, ":"))
 			leading := len(s) - len(strings.TrimLeft(s, ":"))
-			val := toValue(value{val: `"` + s[leading:]})
+			val := toValue(value{word: `"` + s[leading:]}, envs[0])
 			for i := 0; i < leading; i++ {
 			for i := 0; i < leading; i++ {
-				val = opThing(val)
+				val = toValue(opThing(val, envs), envs[0])
 			}
 			}
 			stack = append(stack, val)
 			stack = append(stack, val)
 		} else if s[0] == '[' {
 		} else if s[0] == '[' {
@@ -83,7 +58,7 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
 			for {
 			for {
 				leading := len(s) - len(strings.TrimLeft(s, "["))
 				leading := len(s) - len(strings.TrimLeft(s, "["))
 				trailing := len(s) - len(strings.TrimRight(s, "]"))
 				trailing := len(s) - len(strings.TrimRight(s, "]"))
-				escape := len(s) - len(strings.TrimRight(strings.TrimRight(s, "]"), "\\")) - trailing
+				escape := len(s) - len(strings.TrimRight(strings.TrimRight(s, "]"), `\`)) - trailing
 				trailing -= escape & 1
 				trailing -= escape & 1
 				s = s[leading : len(s)-trailing]
 				s = s[leading : len(s)-trailing]
 				for i := 0; i < leading; i++ {
 				for i := 0; i < leading; i++ {
@@ -110,133 +85,128 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
 					panic(fmt.Errorf("list: %s", errUnmatchedBracket))
 					panic(fmt.Errorf("list: %s", errUnmatchedBracket))
 				}
 				}
 			}
 			}
-			stack = append(stack, value{val: strings.Join(list, " ")})
-		} else if s[0] >= '0' && s[0] <= '9' || s[0] == '-' {
-			toNumber(s)
-			stack = append(stack, value{val: s})
+			stack = append(stack, value{word: strings.Join(list, " ")})
 		} else {
 		} else {
-			stack = append(stack, value{val: s})
+			stack = append(stack, value{word: s})
 		}
 		}
 		for !returned {
 		for !returned {
 			updated := false
 			updated := false
-			for i := len(stack) - 1; i >= stackTop; i-- {
-				if !isNameWithIndex(`"` + stack[i].val) {
+			for i := len(stack) - 1; i >= 0; i-- {
+				if !isName(value{word: `"` + stack[i].word}) {
 					continue
 					continue
 				}
 				}
-				paramCnt, ok := reserved[stack[i].val]
+				paramCnt, ok := reserved[stack[i].word]
 				if ok {
 				if ok {
-					if paramCnt == len(stack)-1-i {
-						for j := i + 1; j < len(stack); j++ {
-							stack[j] = toValue(stack[j])
-						}
-						switch stack[i].val {
-						case "make":
-							stack[i] = opMake(stack[i+1], stack[i+2])
-						case "thing":
-							stack[i] = opThing(stack[i+1])
-						case "print":
-							stack[i] = opPrint(stack[i+1])
-						case "read":
-							stack[i] = opRead(scanner)
-						case "add":
-							stack[i] = opAdd(stack[i+1], stack[i+2])
-						case "sub":
-							stack[i] = opSub(stack[i+1], stack[i+2])
-						case "mul":
-							stack[i] = opMul(stack[i+1], stack[i+2])
-						case "div":
-							stack[i] = opDiv(stack[i+1], stack[i+2])
-						case "mod":
-							stack[i] = opMod(stack[i+1], stack[i+2])
-						case "erase":
-							stack[i] = opErase(stack[i+1])
-						case "isname":
-							stack[i] = opIsName(stack[i+1])
-						case "run":
-							stack[i], returned = opRun(stack[i+1])
-						case "eq":
-							stack[i] = opEq(stack[i+1], stack[i+2])
-						case "gt":
-							stack[i] = opGt(stack[i+1], stack[i+2])
-						case "lt":
-							stack[i] = opLt(stack[i+1], stack[i+2])
-						case "and":
-							stack[i] = opAnd(stack[i+1], stack[i+2])
-						case "or":
-							stack[i] = opOr(stack[i+1], stack[i+2])
-						case "not":
-							stack[i] = opNot(stack[i+1])
-						case "if":
-							stack[i], returned = opIf(stack[i+1], stack[i+2], stack[i+3])
-						case "isnumber":
-							stack[i] = opIsNumber(stack[i+1])
-						case "isword":
-							stack[i] = opIsWord(stack[i+1])
-						case "islist":
-							stack[i] = opIsList(stack[i+1])
-						case "isbool":
-							stack[i] = opIsBool(stack[i+1])
-						case "isempty":
-							stack[i] = opIsEmpty(stack[i+1])
-						case "return":
-							stack[i], returned = stack[i+1], true
-						case "export":
-							stack[i] = opExport(stack[i+1])
-						case "readlist":
-							stack[i] = opReadList(scanner)
-						case "word":
-							stack[i] = opWord(stack[i+1], stack[i+2])
-						case "sentence":
-							stack[i] = opSentence(stack[i+1], stack[i+2])
-						case "list":
-							stack[i] = opList(stack[i+1], stack[i+2])
-						case "join":
-							stack[i] = opJoin(stack[i+1], stack[i+2])
-						case "first":
-							stack[i] = opFirst(stack[i+1])
-						case "last":
-							stack[i] = opLast(stack[i+1])
-						case "butfirst":
-							stack[i] = opButFirst(stack[i+1])
-						case "butlast":
-							stack[i] = opButLast(stack[i+1])
-						case "random":
-							stack[i] = opRandom(stack[i+1])
-						case "int":
-							stack[i] = opInt(stack[i+1])
-						case "sqrt":
-							stack[i] = opSqrt(stack[i+1])
-						case "save":
-							stack[i] = opSave(stack[i+1])
-						case "load":
-							stack[i] = opLoad(stack[i+1])
-						case "erall":
-							stack[i] = opErAll()
-						case "poall":
-							stack[i] = opPoAll()
-						}
-						stack = stack[:i+1]
-						updated = true
+					if paramCnt > len(stack)-1-i {
+						break
 					}
 					}
-					break
+					for j := i + 1; j < len(stack); j++ {
+						stack[j] = toValue(stack[j], envs[0])
+					}
+					switch stack[i].word {
+					case "make":
+						stack[i] = opMake(stack[i+1], stack[i+2], envs)
+					case "thing":
+						stack[i] = opThing(stack[i+1], envs)
+					case "print":
+						stack[i] = opPrint(stack[i+1])
+					case "read":
+						stack[i] = opRead(scanner)
+					case "add":
+						stack[i] = opAdd(stack[i+1], stack[i+2])
+					case "sub":
+						stack[i] = opSub(stack[i+1], stack[i+2])
+					case "mul":
+						stack[i] = opMul(stack[i+1], stack[i+2])
+					case "div":
+						stack[i] = opDiv(stack[i+1], stack[i+2])
+					case "mod":
+						stack[i] = opMod(stack[i+1], stack[i+2])
+					case "erase":
+						stack[i] = opErase(stack[i+1], envs)
+					case "isname":
+						stack[i] = opIsName(stack[i+1])
+					case "run":
+						stack[i], returned = opRun(stack[i+1], envs)
+					case "eq":
+						stack[i] = opEq(stack[i+1], stack[i+2])
+					case "gt":
+						stack[i] = opGt(stack[i+1], stack[i+2])
+					case "lt":
+						stack[i] = opLt(stack[i+1], stack[i+2])
+					case "and":
+						stack[i] = opAnd(stack[i+1], stack[i+2])
+					case "or":
+						stack[i] = opOr(stack[i+1], stack[i+2])
+					case "not":
+						stack[i] = opNot(stack[i+1])
+					case "if":
+						stack[i], returned = opIf(stack[i+1], stack[i+2], stack[i+3], envs)
+					case "isnumber":
+						stack[i] = opIsNumber(stack[i+1])
+					case "isword":
+						stack[i] = opIsWord(stack[i+1])
+					case "islist":
+						stack[i] = opIsList(stack[i+1])
+					case "isbool":
+						stack[i] = opIsBool(stack[i+1])
+					case "isempty":
+						stack[i] = opIsEmpty(stack[i+1])
+					case "return":
+						stack[i], returned = stack[i+1], true
+					case "export":
+						stack[i] = opExport(stack[i+1], envs)
+					case "readlist":
+						stack[i] = opReadList(scanner)
+					case "word":
+						stack[i] = opWord(stack[i+1], stack[i+2])
+					case "sentence":
+						stack[i] = opSentence(stack[i+1], stack[i+2])
+					case "list":
+						stack[i] = opList(stack[i+1], stack[i+2])
+					case "join":
+						stack[i] = opJoin(stack[i+1], stack[i+2])
+					case "first":
+						stack[i] = opFirst(stack[i+1])
+					case "last":
+						stack[i] = opLast(stack[i+1])
+					case "butfirst":
+						stack[i] = opButFirst(stack[i+1])
+					case "butlast":
+						stack[i] = opButLast(stack[i+1])
+					case "random":
+						stack[i] = opRandom(stack[i+1])
+					case "int":
+						stack[i] = opInt(stack[i+1])
+					case "sqrt":
+						stack[i] = opSqrt(stack[i+1])
+					case "save":
+						stack[i] = opSave(stack[i+1], envs[0])
+					case "load":
+						stack[i] = opLoad(stack[i+1], envs[0])
+					case "erall":
+						stack[i] = opErAll(envs[0])
+					case "poall":
+						stack[i] = opPoAll(envs[0])
+					}
+					stack = stack[:i+1]
+					updated = true
 				}
 				}
-				val, _ := getValue(`"` + stack[i].val)
+				val, _ := getValue(`"`+stack[i].word, envs)
 				if val.param != nil {
 				if val.param != nil {
-					if len(val.param) == len(stack)-1-i {
-						for j := i + 1; j < len(stack); j++ {
-							stack[j] = toValue(stack[j])
-						}
-						local := environ{stack[i].val: val}
-						for j, name := range val.param {
-							local[name] = stack[i+1+j]
-						}
-						env = append(env, val.env, local)
-						stack[i], _ = opRun(value{val: val.list[1]})
-						env = env[:len(env)-2]
-						stack = stack[:i+1]
-						updated = true
+					if len(val.param) > len(stack)-1-i {
+						break
 					}
 					}
-					break
+					for j := i + 1; j < len(stack); j++ {
+						stack[j] = toValue(stack[j], envs[0])
+					}
+					local := environ{stack[i].word: val}
+					for j, name := range val.param {
+						local[name] = stack[i+1+j]
+					}
+					stack[i], _ = opRun(value{tp: typeList, split: val.body}, []environ{local, val.env, envs[2]})
+					stack = stack[:i+1]
+					updated = true
 				}
 				}
 			}
 			}
 			if !updated {
 			if !updated {
@@ -244,26 +214,25 @@ func interpret(scanner *bufio.Scanner) (val value, returned bool) {
 			}
 			}
 		}
 		}
 	}
 	}
-	if len(stack) == stackTop {
-		stack = append(stack, value{val: "[ ]"})
+	if len(stack) == 0 {
+		val = value{tp: typeList, list: []string{}, split: []string{"[", "]"}}
+		return
 	}
 	}
-	val = toValue(stack[len(stack)-1])
-	stack = stack[:stackTop]
+	val = toValue(stack[len(stack)-1], envs[0])
 	return
 	return
 }
 }
 
 
 func main() {
 func main() {
 	rand.Seed(time.Now().UnixNano())
 	rand.Seed(time.Now().UnixNano())
-	env = append(env, nil, map[string]value{"pi": {val: "3.14159"}})
-
+	env := map[string]value{"pi": {tp: typeNumber, num: 3.14159}}
 	if len(os.Args) > 1 {
 	if len(os.Args) > 1 {
 		file, err := os.Open(os.Args[1])
 		file, err := os.Open(os.Args[1])
 		if err != nil {
 		if err != nil {
-			panic(fmt.Errorf("mua: %s (%s)", errFileError, os.Args[1]))
+			panic(fmt.Errorf("script: %s (%s)", errFileError, os.Args[1]))
 		}
 		}
 		os.Stdin = file
 		os.Stdin = file
 	}
 	}
-
 	scanner := bufio.NewScanner(os.Stdin)
 	scanner := bufio.NewScanner(os.Stdin)
-	interpret(scanner)
+	scanner.Split(splitFunc)
+	interpret(&scanProvider{isList: false, scanner: scanner}, []environ{env, nil, env})
 }
 }

+ 61 - 0
scan.go

@@ -0,0 +1,61 @@
+package main
+
+import (
+	"bufio"
+	"unicode"
+	"unicode/utf8"
+)
+
+type scanProvider struct {
+	isList  bool
+	text    string
+	list    []string
+	scanner *bufio.Scanner
+}
+
+func (ip *scanProvider) Scan() bool {
+	if ip.isList {
+		if len(ip.list) == 0 {
+			return false
+		}
+		ip.text = ip.list[0]
+		ip.list = ip.list[1:]
+		return true
+	}
+	return ip.scanner.Scan()
+}
+
+func (ip *scanProvider) Text() string {
+	if ip.isList {
+		return ip.text
+	}
+	return ip.scanner.Text()
+}
+
+func splitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
+	start := 0
+	for start < len(data) {
+		r, width := utf8.DecodeRune(data[start:])
+		if r == '\n' {
+			return start + width, data[start : start+width], nil
+		}
+		if !unicode.IsSpace(r) {
+			break
+		}
+		start += width
+	}
+	for i := start; i < len(data); {
+		r, width := utf8.DecodeRune(data[i:])
+		if r == '\n' {
+			return i, data[start:i], nil
+		}
+		if unicode.IsSpace(r) {
+			return i + width, data[start:i], nil
+		}
+		i += width
+	}
+	if atEOF && len(data) > start {
+		return len(data), data[start:], nil
+	}
+	return start, nil, nil
+}

+ 168 - 102
type.go

@@ -2,37 +2,49 @@ package main
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"math"
 	"regexp"
 	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 )
 )
 
 
-const _name, _nameOrInt = `([A-Za-z]\w*)`, "(" + _name + `|\d+)`
-const _index = "(" + _nameOrInt + "|:|" + _nameOrInt + ":|:" + _nameOrInt + "|" + _nameOrInt + ":" + _nameOrInt + ")"
+const (
+	typeUnknown = iota
+	typeNumber
+	typeWord
+	typeList
+	typeBool
+)
+
+const (
+	_name      = `([A-Za-z]\w*)`
+	_nameOrInt = "(" + _name + `|\d+)`
+	_index     = "(" + _nameOrInt + "|:|" + _nameOrInt + ":|:" + _nameOrInt + "|" + _nameOrInt + ":" + _nameOrInt + ")"
+)
 
 
 var nameExp = regexp.MustCompile(`^"` + _name + "$")
 var nameExp = regexp.MustCompile(`^"` + _name + "$")
 var nameWithIndexExp = regexp.MustCompile(`^"` + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
 var nameWithIndexExp = regexp.MustCompile(`^"` + _name + `((\[` + _index + `])*\[` + _index + `\\])?$`)
 
 
-func isName(s string) bool {
-	return nameExp.MatchString(s)
+func isName(val value) bool {
+	return nameExp.MatchString(val.word)
 }
 }
 
 
-func toName(s string) string {
-	if !isName(s) {
-		panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
+func toName(val value) string {
+	if !isName(val) {
+		panic(fmt.Errorf("name: %s", errInvalidName))
 	}
 	}
-	return s[1:]
+	return val.word[1:]
 }
 }
 
 
-func isNameWithIndex(s string) bool {
-	return nameWithIndexExp.MatchString(s)
+func isNameWithIndex(val value) bool {
+	return nameWithIndexExp.MatchString(val.word)
 }
 }
 
 
-func toNameWithIndex(s string) (string, []string) {
-	if !isNameWithIndex(s) {
-		panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
+func toNameWithIndex(val value) (string, []string) {
+	if !isNameWithIndex(val) {
+		panic(fmt.Errorf("name: %s", errInvalidName))
 	}
 	}
-	index := strings.Split(s, "[")
+	index := strings.Split(val.word, "[")
 	name, cnt := index[0][1:], len(index)-1
 	name, cnt := index[0][1:], len(index)-1
 	for i := 1; i < cnt; i++ {
 	for i := 1; i < cnt; i++ {
 		index[i] = index[i][:len(index[i])-1]
 		index[i] = index[i][:len(index[i])-1]
@@ -41,154 +53,208 @@ func toNameWithIndex(s string) (string, []string) {
 	return name, index[1:]
 	return name, index[1:]
 }
 }
 
 
-func isNumber(s string) bool {
-	if s != "" && s[0] == '"' {
-		s = s[1:]
+func isNumber(val value) bool {
+	if val.tp == typeNumber {
+		return true
+	}
+	if isWord(val) {
+		val.word = val.word[1:]
 	}
 	}
-	_, err := strconv.ParseFloat(s, 64)
+	_, err := strconv.ParseFloat(val.word, 64)
 	return err == nil
 	return err == nil
 }
 }
 
 
-func toNumber(s string) float64 {
-	if s != "" && s[0] == '"' {
-		s = s[1:]
+func toNumber(val value) float64 {
+	if val.tp == typeNumber {
+		return val.num
 	}
 	}
-	val, err := strconv.ParseFloat(s, 64)
+	if isWord(val) {
+		val.word = val.word[1:]
+	}
+	num, err := strconv.ParseFloat(val.word, 64)
 	if err != nil {
 	if err != nil {
-		panic(fmt.Errorf("number: %s (%s)", errInvalidNumber, s))
+		panic(fmt.Errorf("number: %s", errInvalidNumber))
 	}
 	}
-	return val
+	return num
 }
 }
 
 
-func toInt(s string) int {
-	if isName(`"` + s) {
-		val, err := getValue(`"` + s)
+func toInt(val value, envs []environ) int {
+	if isName(value{word: `"` + val.word}) {
+		newVal, err := getValue(`"`+val.word, envs)
 		if err == nil {
 		if err == nil {
-			s = val.val
+			val = newVal
+			if val.tp == typeNumber {
+				if val.num != math.Floor(val.num) {
+					panic(fmt.Errorf("int: %s", errInvalidInteger))
+				}
+				return int(val.num)
+			}
 		}
 		}
 	}
 	}
-	if s != "" && s[0] == '"' {
-		s = s[1:]
+	if isWord(val) {
+		val.word = val.word[1:]
 	}
 	}
-	val, err := strconv.ParseInt(s, 10, 64)
+	num, err := strconv.ParseInt(val.word, 10, 64)
 	if err != nil {
 	if err != nil {
-		panic(fmt.Errorf("int: %s (%s)", errInvalidInteger, s))
+		panic(fmt.Errorf("int: %s", errInvalidInteger))
 	}
 	}
-	return int(val)
-}
-
-func isWord(s string) bool {
-	return s != "" && s[0] == '"'
+	return int(num)
 }
 }
 
 
-func isList(s string) bool {
-	return s != "" && s[0] == '['
+func isWord(val value) bool {
+	if val.tp == typeWord {
+		return true
+	}
+	return val.word != "" && val.word[0] == '"'
 }
 }
 
 
-func isBool(s string) bool {
-	if s != "" && s[0] == '"' {
-		s = s[1:]
+func parseWord(s string) value {
+	if len(s) > 1 {
+		if s[1] == '[' {
+			s = `"\[` + s[2:]
+		}
+		if s[len(s)-1] == ']' {
+			s = s[:len(s)-1]
+			escape := len(s) - len(strings.TrimRight(s, `\`))
+			if (escape & 1) == 0 {
+				s += `\`
+			}
+			s += "]"
+		}
 	}
 	}
-	_, err := strconv.ParseBool(s)
-	return err == nil
+	return value{tp: typeWord, word: s}
 }
 }
 
 
-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))
+func escapeWord(s string) string {
+	for i := 0; i < len(s); i++ {
+		if s[i] == '\\' {
+			s = s[:i] + s[i+1:]
+		}
 	}
 	}
-	return val
+	return s
 }
 }
 
 
-func isEmpty(s string) bool {
-	return s == `"` || s == "[ ]"
+func isList(val value) bool {
+	if val.tp == typeList {
+		return true
+	}
+	return val.word != "" && val.word[0] == '['
 }
 }
 
 
-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}
+func parseFunc(s string, env environ) value {
+	list, split := parseList(s)
+	if len(list) != 2 || !isList(value{word: list[0]}) || !isList(value{word: list[1]}) {
+		return value{tp: typeList, list: list, split: split}
 	}
 	}
-	param := parseList(list[0])
+	param, _ := parseList(list[0])
 	for _, name := range param {
 	for _, name := range param {
-		if !isName(`"` + name) {
-			return value{val: s, list: list}
+		if !isName(value{word: `"` + name}) {
+			return value{tp: typeList, list: list, split: split}
 		}
 		}
 	}
 	}
-	local := make(environ)
-	for name, val := range env[len(env)-1] {
+	local := environ{}
+	for name, val := range env {
 		local[name] = val
 		local[name] = val
 	}
 	}
-	return value{val: s, list: list, param: param, env: local}
+	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 isValue(s string) bool {
-	return isNumber(s) || isWord(s) || isList(s) || isBool(s)
+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
 }
 }
 
 
-func toValue(val value) value {
-	if !isValue(val.val) {
-		panic(fmt.Errorf("mua: %s (%s)", errValueExpected, val.val))
+func isEmpty(val value) bool {
+	if val.tp == typeWord {
+		return val.word == `"`
 	}
 	}
-	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 val.tp == typeList {
+		return len(val.list) == 0
 	}
 	}
-	if isList(val.val) {
-		if val.list == nil {
-			return parseFunc(val.val)
-		}
+	panic(fmt.Errorf("empty: %s", errWordOrListExpected))
+}
+
+func toValue(val value, env environ) value {
+	if val.tp != typeUnknown {
 		return val
 		return val
 	}
 	}
-	return val
+	if isNumber(val) {
+		return value{tp: typeNumber, num: toNumber(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))
 }
 }
 
 
-func escapeValue(s string) string {
-	for i := 0; i < len(s); i++ {
-		if s[i] == '\\' {
-			s = s[:i] + s[i+1:]
-		}
+func toString(val value) string {
+	if val.tp == typeNumber {
+		return strconv.FormatFloat(val.num, 'g', -1, 64)
 	}
 	}
-	return s
+	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 {
 func opIsName(val1 value) value {
-	return value{val: strconv.FormatBool(isName(val1.val))}
+	return value{tp: typeBool, b: isName(val1)}
 }
 }
 
 
 func opIsNumber(val1 value) value {
 func opIsNumber(val1 value) value {
-	return value{val: strconv.FormatBool(isNumber(val1.val))}
+	return value{tp: typeBool, b: isNumber(val1)}
 }
 }
 
 
 func opIsWord(val1 value) value {
 func opIsWord(val1 value) value {
-	return value{val: strconv.FormatBool(isWord(val1.val))}
+	return value{tp: typeBool, b: isWord(val1)}
 }
 }
 
 
 func opIsList(val1 value) value {
 func opIsList(val1 value) value {
-	return value{val: strconv.FormatBool(isList(val1.val))}
+	return value{tp: typeBool, b: isList(val1)}
 }
 }
 
 
 func opIsBool(val1 value) value {
 func opIsBool(val1 value) value {
-	return value{val: strconv.FormatBool(isBool(val1.val))}
+	return value{tp: typeBool, b: isBool(val1)}
 }
 }
 
 
 func opIsEmpty(val1 value) value {
 func opIsEmpty(val1 value) value {
-	return value{val: strconv.FormatBool(isEmpty(val1.val))}
+	return value{tp: typeBool, b: isEmpty(val1)}
 }
 }