From cdc3ec20443e5c9455359921801b2dabec7906a3 Mon Sep 17 00:00:00 2001
From: Julien Dessaux <julien.dessaux@adyxax.org>
Date: Mon, 4 Oct 2021 00:10:06 +0200
Subject: [PATCH] Implemented the funge stack

---
 src/stack.nim   |  69 +++++++++++++++++++++++++
 tests/stack.nim | 131 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 200 insertions(+)
 create mode 100644 src/stack.nim
 create mode 100644 tests/stack.nim

diff --git a/src/stack.nim b/src/stack.nim
new file mode 100644
index 0000000..2c6826d
--- /dev/null
+++ b/src/stack.nim
@@ -0,0 +1,69 @@
+type
+  Stack* = object
+    size, height: int
+    data: seq[int]
+    next: ref Stack
+
+func NewStack*(size: int = 32, next: ref Stack = nil): ref Stack =
+  result = new(Stack)
+  result.size = size
+  result.data.setlen(size)
+  result.next = next
+
+func Pop*(s: var Stack): int =
+  if s.height > 0:
+    dec s.height
+    return s.data[s.height]
+  return 0
+
+func Push*(s: var Stack, v: int) =
+  if s.height >= s.size:
+    s.size += 32
+    s.data.setlen(s.size)
+  s.data[s.height] = v
+  inc s.height
+
+func PopVector*(s: var Stack): (int, int) =
+  if s.height >= 2:
+    s.height -= 2
+    return (s.data[s.height], s.data[s.height+1])
+  elif s.height == 1:
+    s.height = 0
+    return (0, s.data[0])
+  else:
+    return (0, 0)
+
+func PushVector*(s: var Stack, v: tuple[x, y: int]) =
+  if s.height+1 >= s.size:
+    s.size += 32
+    s.data.setlen(s.size)
+  s.data[s.height] = v.x
+  inc s.height
+  s.data[s.height] = v.y
+  inc s.height
+
+func Clear*(s: var Stack) =
+  s.height = 0
+
+func Duplicate*(s: var Stack) =
+  if s.height > 0:
+    s.Push(s.data[s.height-1])
+  else:
+    s.PushVector((0, 0))
+
+func Swap*(s: var Stack) =
+  let a = s.Pop
+  let b = s.Pop
+  s.Push(a)
+  s.Push(b)
+
+func Transfert*(toss: var Stack, soss: var Stack, n: int) =
+  toss.height += n
+  for i in 1..min(soss.height, n):
+    toss.data[toss.height-i] = soss.data[soss.height-i]
+  soss.height -= n
+  if soss.height < 0:
+    soss.height = 0
+
+func Next*(s: Stack): ref Stack =
+  return s.next
diff --git a/tests/stack.nim b/tests/stack.nim
new file mode 100644
index 0000000..469c425
--- /dev/null
+++ b/tests/stack.nim
@@ -0,0 +1,131 @@
+import unittest
+
+include ../src/stack
+
+suite "Stack":
+  test "Pop":
+    var empty = NewStack()
+    check empty[].Pop() == 0
+    var simple = NewStack()
+    simple.data[0] = 1
+    simple.data[1] = 5
+    simple.height = 2
+    check simple[].Pop() == 5
+    check simple[].Pop() == 1
+    check simple[].Pop() == 0
+  test "Push":
+    var s = NewStack()
+    check s.height == 0
+    check s.data[0] == 0
+    check s.data[1] == 0
+    check s.data[2] == 0
+    s[].Push(5)
+    check s.height == 1
+    check s.data[0] == 5
+    check s.data[1] == 0
+    check s.data[2] == 0
+    s[].Push(-2)
+    check s.height == 2
+    check s.data[0] == 5
+    check s.data[1] == -2
+    check s.data[2] == 0
+  test "PopVector":
+    var empty = NewStack()
+    check empty[].PopVector() == (0, 0)
+    check empty.height == 0
+    var some = NewStack()
+    some[].Push(2)
+    check some[].PopVector() == (0, 2)
+    check some.height == 0
+    var full = NewStack()
+    full[].Push(1)
+    full[].Push(2)
+    full[].Push(3)
+    check full[].PopVector() == (2, 3)
+    check full.height == 1
+  test "PushVector":
+    var s = NewStack()
+    check s.height == 0
+    check s.data[0] == 0
+    check s.data[1] == 0
+    check s.data[2] == 0
+    s[].PushVector((5, -3))
+    check s.height == 2
+    check s.data[0] == 5
+    check s.data[1] == -3
+    check s.data[2] == 0
+  test "Clear":
+    var empty: Stack
+    empty.Clear()
+    check empty.height == 0
+    var some = NewStack()
+    some[].Push(1)
+    some[].Push(2)
+    some[].Clear()
+    check some.height == 0
+  test "Duplicate":
+    var empty = NewStack()
+    empty[].Duplicate()
+    check empty.height == 2
+    check empty.data[0] == 0
+    check empty.data[1] == 0
+    var some = NewStack()
+    some[].Push(2)
+    some[].Push(-4)
+    some[].Duplicate()
+    check some.height == 3
+    check some.data[0] == 2
+    check some.data[1] == -4
+    check some.data[2] == -4
+    check some.data[3] == 0
+  test "Swap":
+    var empty = NewStack()
+    empty[].Swap()
+    check empty.height == 2
+    check empty.data[0] == 0
+    check empty.data[1] == 0
+    var some = NewStack()
+    some[].Push(2)
+    some[].Push(-4)
+    some[].Push(7)
+    some[].Swap()
+    check some.height == 3
+    check some.data[0] == 2
+    check some.data[1] == 7
+    check some.data[2] == -4
+    check some.data[3] == 0
+  test "Transfert":
+    var empty = NewStack()
+    var empty2 = NewStack()
+    empty[].Transfert(empty2[], 4)
+    check empty.height == 4
+    check empty2.height == 0
+    check empty.data[0] == 0
+    check empty.data[1] == 0
+    check empty.data[2] == 0
+    check empty.data[3] == 0
+    empty = NewStack()
+    var some = NewStack()
+    some[].Push(2)
+    empty[].Transfert(some[], 3)
+    check empty.height == 3
+    check some.height == 0
+    check empty.data[0] == 0
+    check empty.data[1] == 0
+    check empty.data[2] == 2
+    empty = NewStack()
+    var full = NewStack()
+    full[].Push(1)
+    full[].Push(2)
+    full[].Push(3)
+    empty[].Transfert(full[], 2)
+    check empty.height == 2
+    check full.height == 1
+    check full.data[0] == 1
+    check empty.data[0] == 2
+    check empty.data[1] == 3
+  test "Next":
+    var empty = NewStack()
+    check empty[].Next() == nil
+    var some = NewStack(next=empty)
+    check some[].Next() == empty