Bladeren bron

ADD. 实现list下标访问

RegMs If 4 jaren geleden
bovenliggende
commit
f2737912a8
5 gewijzigde bestanden met toevoegingen van 166 en 44 verwijderingen
  1. 38 2
      bind.go
  2. 4 2
      error.go
  3. 69 23
      in
  4. 18 17
      list.go
  5. 37 0
      type.go

+ 38 - 2
bind.go

@@ -4,6 +4,7 @@ import (
 	"bufio"
 	"fmt"
 	"os"
+	"strconv"
 	"strings"
 )
 
@@ -42,12 +43,30 @@ func getFunc(name string) value {
 	return value{}
 }
 
+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 opMake(val1, val2 value) value {
-	name := toName(val1.val)
+	name, index := toNameWithIndex(val1.val)
 	_, ok := reserved[name]
 	if ok {
 		panic(fmt.Errorf("make: %s (%s)", errNameReserved, name))
 	}
+	val, ok := env[len(env)-1][name]
+	if !ok && len(index) > 0 {
+		panic(fmt.Errorf("make: %s (%s)", errNameNotFound, name))
+	}
+	if len(index) > 0 {
+		if isWord(val2.val) {
+			val2.val = val2.val[1:]
+		}
+		val2 = value{val: assign(val.val, index, val2.val)}
+	}
 	if isList(val2.val) && val2.list == nil {
 		val2 = parseFunc(val2.val)
 	}
@@ -56,11 +75,28 @@ func opMake(val1, val2 value) value {
 }
 
 func opThing(val1 value) value {
-	name := toName(val1.val)
+	name, index := toNameWithIndex(val1.val)
 	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
 		}
 	}

+ 4 - 2
error.go

@@ -1,10 +1,12 @@
 package main
 
+const errInvalidName = "invalid name"
+
 const errInvalidNumber = "invalid number"
 
-const errInvalidBool = "invalid bool"
+const errInvalidInteger = "invalid integer"
 
-const errInvalidName = "invalid name"
+const errInvalidBool = "invalid bool"
 
 const errUnmatchedBracket = "unmatched bracket"
 

+ 69 - 23
in

@@ -1,3 +1,31 @@
+make "fun [
+  [f]
+  [
+    return [
+      [a b]
+      [f :a :b]
+    ]
+  ]
+]
+make "adder fun [[x y] [add :x :y]]
+print adder 2 3
+
+make "arr [ [ a b ] c ]
+print :arr[0]
+print :arr[1]
+print :arr[0][0]
+print :arr[0][1]
+make "arr[0][1] "d
+print :arr[0]
+print :arr[0][1]
+make "arr[1] [ add :a :d ]
+print :arr
+print arr 2 3
+make "arr[0][1] [ e [ f ] ]
+print :arr[0][1]
+print :arr[0][1][0]
+print :arr[0][1][1][0]
+
 print word "hello "world
 print word "hello TRUE
 print word "hello -134.5
@@ -34,18 +62,36 @@ print pow 2 18
 print readlist
 a b c 1 2 3
 
-make "fib_out [
-    [x]
-    [
-        print :fib_out
-        make "fib [
-            [x]
-            [if lt :x 2 [1] [add fib sub :x 1 fib sub :x 2]]
-        ]
-        fib :x
+make "reverse_list [
+  [list]
+  [if isempty :list [] [join reverse_list butfirst :list first :list]]
+]
+print reverse_list [a [b c d] [e f] g]
+
+make "fib_wrap [
+  [x]
+  [
+    make "fib [
+      [x]
+      [
+        if lt :x 2 [return 1] []
+        return add fib sub :x 1 fib sub :x 2
+      ]
     ]
+    fib :x
+  ]
 ]
-print fib_out 20
+
+print fib_wrap 0
+print fib_wrap 1
+print fib_wrap 2
+print fib_wrap 3
+print fib_wrap 4
+print fib_wrap 5
+print fib_wrap 6
+print fib_wrap 7
+print fib_wrap 8
+print fib_wrap 9
 
 make "f [[x] [
   make "g [[y] [return add :x :y]]
@@ -72,8 +118,8 @@ make "f3 curry_two :f2 42
 print f3 233
 
 make "fun [
-    [x]
-    [[[y] [make "x add :x :y]]]
+  [x]
+  [[[y] [make "x add :x :y]]]
 ]
 make "adder fun 5
 print adder 1
@@ -97,11 +143,11 @@ print :e
 make "prt [
   [a]
   [
-      make "b [
-          []
-          [print :a]
-      ]
-      return :b
+    make "b [
+      []
+      [print :a]
+    ]
+    return :b
   ]
 ]
 make "c prt "hello
@@ -110,12 +156,12 @@ c
 make "x 2
 print :x
 make "test [
-    []
-    [
-        make "x 1
-        export "x
-        print :x
-    ]
+  []
+  [
+    make "x 1
+    export "x
+    print :x
+  ]
 ]
 test
 print :x

+ 18 - 17
list.go

@@ -29,22 +29,14 @@ func parseList(s string) []string {
 	return resList
 }
 
-func indexOfList(s string, index int) string {
-	if !isList(s) {
-		panic(fmt.Errorf("indexoflist: %s (%s)", errListExpected, s))
-	}
-	list := parseList(s)
+func indexOfList(list []string, index int) string {
 	if index < 0 || index >= len(list) {
 		panic(fmt.Errorf("indexoflist: %s", errIndexOutOfBound))
 	}
 	return list[index]
 }
 
-func rangeOfList(s string, index1, index2 int) string {
-	if !isList(s) {
-		panic(fmt.Errorf("rangeoflist: %s (%s)", errListExpected, s))
-	}
-	list := parseList(s)
+func rangeOfList(list []string, index1, index2 int) string {
 	if index1 < 0 || index1 > len(list) || index2 < 0 || index2 > len(list) {
 		panic(fmt.Errorf("rangeoflist: %s", errIndexOutOfBound))
 	}
@@ -54,11 +46,7 @@ func rangeOfList(s string, index1, index2 int) string {
 	return strings.Join(wrapList(list[index1:index2]), " ")
 }
 
-func spliceList(s string, index int, cnt int, val ...string) string {
-	if !isList(s) {
-		panic(fmt.Errorf("splicelist: %s (%s)", errListExpected, s))
-	}
-	list := parseList(s)
+func spliceList(list []string, index int, cnt int, val ...string) string {
 	if index < 0 || index > len(list) {
 		panic(fmt.Errorf("splicelist: %s", errIndexOutOfBound))
 	}
@@ -83,16 +71,26 @@ func opWord(val1, val2 value) value {
 
 func opSentence(val1, val2 value) value {
 	list1, list2 := []string{val1.val}, []string{val2.val}
-	if isList(val1.val) {
+	if isWord(val1.val) {
+		list1 = []string{val1.val[1:]}
+	} else if isList(val1.val) {
 		list1 = parseList(val1.val)
 	}
-	if isList(val2.val) {
+	if isWord(val2.val) {
+		list2 = []string{val2.val[1:]}
+	} else if isList(val2.val) {
 		list2 = parseList(val2.val)
 	}
 	return value{val: strings.Join(wrapList(append(list1, list2...)), " ")}
 }
 
 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: strings.Join(wrapList([]string{val1.val, val2.val}), " ")}
 }
 
@@ -100,6 +98,9 @@ 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:]
+	}
 	return value{val: strings.Join(wrapList(append(parseList(val1.val), val2.val)), " ")}
 }
 

+ 37 - 0
type.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"regexp"
 	"strconv"
+	"strings"
 )
 
 func isName(s string) bool {
@@ -18,6 +19,23 @@ func toName(s string) string {
 	return s[1:]
 }
 
+func isNameWithIndex(s string) bool {
+	reg := regexp.MustCompile(`^"[A-Za-z]\w*(\[(\d+|:|\d+:|:\d+|\d+:\d+)\])*$`)
+	return reg.MatchString(s)
+}
+
+func toNameWithIndex(s string) (string, []string) {
+	if !isNameWithIndex(s) {
+		panic(fmt.Errorf("name: %s (%s)", errInvalidName, s))
+	}
+	index := strings.Split(s, "[")
+	name := index[0][1:]
+	for i := 1; i < len(index); i++ {
+		index[i] = index[i][:len(index[i])-1]
+	}
+	return name, index[1:]
+}
+
 func isNumber(s string) bool {
 	if s != "" && s[0] == '"' {
 		s = s[1:]
@@ -37,6 +55,25 @@ func toNumber(s string) float64 {
 	return val
 }
 
+func isInt(s string) bool {
+	if s != "" && s[0] == '"' {
+		s = s[1:]
+	}
+	_, err := strconv.ParseInt(s, 10, 64)
+	return err == nil
+}
+
+func toInt(s string) int {
+	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] == '"'
 }