--- /dev/null
+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) + "]"
+}