From 6dac92f15fec57e44842d7c331b52f0301bf87de Mon Sep 17 00:00:00 2001
From: Lee Spector <lspector@hampshire.edu>
Date: Thu, 22 Apr 2021 20:21:24 -0400
Subject: [PATCH] Add deep_dup instructions

---
 .../push/instructions/polymorphic.cljc        | 20 ++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/propeller/push/instructions/polymorphic.cljc b/src/propeller/push/instructions/polymorphic.cljc
index 3c0a8aa..100992f 100755
--- a/src/propeller/push/instructions/polymorphic.cljc
+++ b/src/propeller/push/instructions/polymorphic.cljc
@@ -188,9 +188,27 @@
         (state/push-to-stack popped-state stack indexed-item))
       state)))
 
+;; Pushes a copy of an indexed item from deep in the stack, without removing it.
+;; The top INTEGER is used to determine the index from the BOTTOM of the stack.
+(def _deep_dup
+  ^{:stacks #{:integer}
+    :name "_deep_dup"}
+  (fn [stack state]
+    (if (or (and (= stack :integer)
+                 (<= 2 (count (:integer state))))
+            (and (not= stack :integer)
+                 (not (state/empty-stack? state :integer))
+                 (not (state/empty-stack? state stack))))
+      (let [index-raw (state/peek-stack state :integer)
+            popped-state (state/pop-stack state :integer)
+            index (max 0 (min index-raw (dec (count (get popped-state stack)))))
+            indexed-item (nth (reverse (get popped-state stack)) index)]
+        (state/push-to-stack popped-state stack indexed-item))
+      state)))
+
 ;; 11 types x 13 functions = 143 instructions
 (generate-instructions
   [:boolean :char :code :exec :float :integer :string
    :vector_boolean :vector_float :vector_integer :vector_string]
   [_dup _dup_times _dup_items _empty _eq _flush _pop _rot _shove
-   _stack_depth _swap _yank _yank_dup])
+   _stack_depth _swap _yank _yank_dup _deep_dup])