OSDN Git Service

Hulk did something
[bytom/vapor.git] / equity / compiler / stack.go
diff --git a/equity/compiler/stack.go b/equity/compiler/stack.go
new file mode 100644 (file)
index 0000000..c86e2b6
--- /dev/null
@@ -0,0 +1,154 @@
+package compiler
+
+type (
+       stack struct {
+               *stackEntry
+       }
+       stackEntry struct {
+               str  string
+               prev *stackEntry
+       }
+)
+
+func (stk stack) isEmpty() bool {
+       return stk.stackEntry == nil
+}
+
+func (stk stack) top() string {
+       if stk.isEmpty() {
+               return ""
+       }
+       return stk.str
+}
+
+func (stk stack) add(str string) stack {
+       e := &stackEntry{
+               str:  str,
+               prev: stk.stackEntry,
+       }
+       return stack{e}
+}
+
+func (stk stack) addFromStack(other stack) stack {
+       if other.isEmpty() {
+               return stk
+       }
+       res := stk.addFromStack(other.drop())
+       return res.add(other.top())
+}
+
+func (stk stack) drop() stack {
+       if !stk.isEmpty() {
+               stk = stack{stk.prev}
+       }
+       return stk
+}
+
+func (stk stack) dropN(n int) stack {
+       for n > 0 {
+               stk = stk.drop()
+               n--
+       }
+       return stk
+}
+
+func (stk stack) recurFind(str string) int {
+       if stk.isEmpty() {
+               return -1
+       }
+       if stk.str == str {
+               return 0
+       }
+       res := stk.drop().recurFind(str)
+       if res < 0 {
+               return res
+       }
+       return res + 1
+}
+
+func (stk stack) count() map[string]int {
+       if stk.isEmpty() {
+               return nil
+       }
+       stackCounts := make(map[string]int)
+       for {
+               stackCounts[stk.str]++
+               stk = stack{stk.prev}
+               if stk.stackEntry == nil {
+                       break
+               }
+       }
+       return stackCounts
+}
+
+func (stk stack) find(str string) int {
+       stackCounts := stk.count()
+       if stk.isEmpty() || stackCounts[str] == 0 {
+               return -1
+       }
+
+       var pos int
+       for {
+               if stk.str == str {
+                       if stackCounts[str] == 1 {
+                               break
+                       }
+                       stackCounts[str]--
+               }
+               stk = stack{stk.prev}
+               if stk.stackEntry == nil {
+                       break
+               }
+               pos++
+       }
+       return pos
+}
+
+func (stk stack) roll(n int) stack {
+       var x func(stack, int) (stack, string)
+       x = func(stk stack, n int) (stack, string) {
+               if n == 0 {
+                       return stk.drop(), stk.top()
+               }
+               stk2, entry := x(stk.drop(), n-1)
+               return stk2.add(stk.top()), entry
+       }
+       stk, entry := x(stk, n)
+       return stk.add(entry)
+}
+
+func (stk stack) swap() stack {
+       a := stk.top()
+       stk = stk.drop()
+       b := stk.top()
+       stk = stk.drop()
+       return stk.add(a).add(b)
+}
+
+func (stk stack) dup() stack {
+       return stk.add(stk.top())
+}
+
+func (stk stack) over() stack {
+       t := stk.drop().top()
+       return stk.add(t)
+}
+
+func (stk stack) pick(n int) stack {
+       t := stk.dropN(n).top()
+       return stk.add(t)
+}
+
+func (stk stack) String() string {
+       if stk.stackEntry == nil {
+               return "[]"
+       }
+       var x func(stk stack) string
+       x = func(stk stack) string {
+               if stk.stackEntry == nil {
+                       return ""
+               }
+               return x(stk.drop()) + " " + stk.stackEntry.str
+       }
+       return "[..." + x(stk) + "]"
+}