Add string instructions
This commit is contained in:
parent
3e820407f3
commit
3f5c2fd8a7
@ -7,7 +7,6 @@
|
||||
[propeller.push.instructions.code]
|
||||
[propeller.push.instructions.input-output]
|
||||
[propeller.push.instructions.numeric]
|
||||
[propeller.push.instructions.random]
|
||||
[propeller.push.instructions.polymorphic]
|
||||
[propeller.push.instructions.string]
|
||||
[propeller.push.instructions.vector]))
|
||||
@ -23,7 +22,7 @@
|
||||
(print "Best program: ") (prn (genome/plushy->push (:plushy best)))
|
||||
(println "Best total error:" (:total-error best))
|
||||
(println "Best errors:" (:errors best))
|
||||
(println "Best behaviors:" (map clojure.string/trim (:behaviors best)))
|
||||
(println "Best behaviors:" (:behaviors best))
|
||||
(println "Genotypic diversity:"
|
||||
(float (/ (count (distinct (map :plushy pop))) (count pop))))
|
||||
(println "Average genome length:"
|
||||
@ -45,7 +44,7 @@
|
||||
instructions
|
||||
max-initial-plushy-size)))]
|
||||
(let [evaluated-pop (sort-by :total-error
|
||||
(#?(:clj pmap
|
||||
(#?(:clj pmap
|
||||
:cljs map)
|
||||
(partial error-function argmap) population))
|
||||
best-individual (first evaluated-pop)]
|
||||
@ -60,7 +59,9 @@
|
||||
(println "Test cases failed."))
|
||||
(#?(:clj shutdown-agents)))
|
||||
;;
|
||||
(>= generation max-generations) nil
|
||||
(>= generation max-generations)
|
||||
nil
|
||||
;;
|
||||
:else (recur (inc generation)
|
||||
(if (:elitism argmap)
|
||||
(conj (repeatedly (dec population-size)
|
||||
|
@ -76,13 +76,15 @@
|
||||
(:step-limit argmap))
|
||||
:output))
|
||||
inputs)
|
||||
parsed-outputs (map (fn [output]
|
||||
(try (read-string output)
|
||||
(catch Exception e 1000.0)))
|
||||
outputs)
|
||||
errors (map (fn [correct-output output]
|
||||
(let [parsed-output (try (read-string output)
|
||||
(catch Exception e 1000.0))]
|
||||
(min 1000.0 (math/abs (- correct-output parsed-output)))))
|
||||
(min 1000.0 (math/abs (- correct-output output))))
|
||||
correct-outputs
|
||||
outputs)]
|
||||
parsed-outputs)]
|
||||
(assoc individual
|
||||
:behaviors outputs
|
||||
:behaviors parsed-outputs
|
||||
:errors errors
|
||||
:total-error (apply +' errors)))))
|
||||
|
@ -55,14 +55,14 @@
|
||||
|
||||
;; Pushes FALSE if the top FLOAT is 0.0, and TRUE otherwise
|
||||
(def-instruction
|
||||
:boolean_fromfloat
|
||||
:boolean_from_float
|
||||
^{:stacks #{:boolean :float}}
|
||||
(fn [state]
|
||||
(make-instruction state #(not (zero? %)) [:float] :boolean)))
|
||||
|
||||
;; Pushes FALSE if the top INTEGER is 0, and TRUE otherwise
|
||||
(def-instruction
|
||||
:boolean_frominteger
|
||||
:boolean_from_integer
|
||||
^{:stacks #{:boolean :integer}}
|
||||
(fn [state]
|
||||
(make-instruction state #(not (zero? %)) [:integer] :boolean)))
|
||||
|
@ -11,14 +11,14 @@
|
||||
|
||||
;; Pushes TRUE onto the BOOLEAN stack if the popped character is a letter
|
||||
(def-instruction
|
||||
:char_isletter
|
||||
:char_is_letter
|
||||
^{:stacks #{:boolean :char}}
|
||||
(fn [state]
|
||||
(make-instruction state char/is-letter [:char] :boolean)))
|
||||
|
||||
;; Pushes TRUE onto the BOOLEAN stack if the popped character is a digit
|
||||
(def-instruction
|
||||
:char_isdigit
|
||||
:char_is_digit
|
||||
^{:stacks #{:boolean :char}}
|
||||
(fn [state]
|
||||
(make-instruction state char/is-digit [:char] :boolean)))
|
||||
@ -26,7 +26,7 @@
|
||||
;; Pushes TRUE onto the BOOLEAN stack if the popped character is whitespace
|
||||
;; (newline, space, or tab)
|
||||
(def-instruction
|
||||
:char_iswhitespace
|
||||
:char_is_whitespace
|
||||
^{:stacks #{:boolean :char}}
|
||||
(fn [state]
|
||||
(make-instruction state char/is-whitespace [:char] :boolean)))
|
||||
@ -36,7 +36,7 @@
|
||||
;; 128 will be reduced modulo 128. For instance, 248.45 will result in x being
|
||||
;; pushed.
|
||||
(def-instruction
|
||||
:char_fromfloat
|
||||
:char_from_float
|
||||
^{:stacks #{:char :float}}
|
||||
(fn [state]
|
||||
(make-instruction state #(char (mod (long %) 128)) [:float] :char)))
|
||||
@ -45,7 +45,7 @@
|
||||
;; value onto the CHAR stack. Integers larger than 128 will be reduced modulo
|
||||
;; 128. For instance, 248 will result in x being pushed
|
||||
(def-instruction
|
||||
:char_frominteger
|
||||
:char_from_integer
|
||||
^{:stacks #{:char :integer}}
|
||||
(fn [state]
|
||||
(make-instruction state #(char (mod % 128)) [:integer] :char)))
|
||||
@ -54,7 +54,7 @@
|
||||
;; onto the CHAR stack, in order. For instance, "hello" will result in the
|
||||
;; top of the CHAR stack being \h \e \l \l \o
|
||||
(def-instruction
|
||||
:char_allfromstring
|
||||
:char_all_from_string
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(if (state/empty-stack? state :string)
|
||||
|
@ -5,16 +5,6 @@
|
||||
[propeller.push.utils.macros :refer [def-instruction
|
||||
generate-instructions]]))
|
||||
|
||||
;; =============================================================================
|
||||
;; Polymorphic Instructions
|
||||
;; =============================================================================
|
||||
|
||||
(def _noop
|
||||
^{:stacks #{}}
|
||||
(fn [stack state] state))
|
||||
|
||||
(generate-instructions [:exec :code] [_noop])
|
||||
|
||||
;; =============================================================================
|
||||
;; CODE Instructions
|
||||
;; =============================================================================
|
||||
@ -46,7 +36,7 @@
|
||||
;; is pushed onto the EXEC stack for subsequent execution. If the integers are
|
||||
;; not equal, then the current index will still be pushed onto the INTEGER stack
|
||||
;; but two items will be pushed onto the EXEC stack - first a recursive call to
|
||||
;; :exec_do*range (with the same code and destination index, but with a current
|
||||
;; :exec_do_range (with the same code and destination index, but with a current
|
||||
;; index that has been either incremented or decremented by 1 to be closer to
|
||||
;; the destination index) and then the body code. Note that the range is
|
||||
;; inclusive of both endpoints; a call with integer arguments 3 and 5 will cause
|
||||
@ -54,7 +44,7 @@
|
||||
;; 4, and 5. Note also that one can specify a loop that "counts down" by
|
||||
;; providing a destination index that is less than the specified current index.
|
||||
(def-instruction
|
||||
:exec_do*range
|
||||
:exec_do_range
|
||||
^{:stacks #{:exec :integer}}
|
||||
(fn [state]
|
||||
(if (or (state/empty-stack? state :exec)
|
||||
@ -76,7 +66,7 @@
|
||||
:exec
|
||||
(list (+' current-index increment)
|
||||
destination-index
|
||||
:exec_do*range
|
||||
:exec_do_range
|
||||
to-do)))]
|
||||
(state/push-to-stack
|
||||
(state/push-to-stack continuation :integer current-index) :exec to-do)))))
|
||||
@ -86,7 +76,7 @@
|
||||
;; total number of iterations) onto the INTEGER stack prior to each execution
|
||||
;; of the loop body. If the top INTEGER argument is <= 0, this becomes a NOOP
|
||||
(def-instruction
|
||||
:exec_do*count
|
||||
:exec_do_count
|
||||
^{:stacks #{:exec :integer}}
|
||||
(fn [state]
|
||||
(if (or (state/empty-stack? state :integer)
|
||||
@ -98,12 +88,12 @@
|
||||
popped-state (state/pop-stack (state/pop-stack state :exec) :integer)]
|
||||
(state/push-to-stack popped-state :exec (list 0
|
||||
(dec index)
|
||||
:exec_do*range
|
||||
:exec_do_range
|
||||
to-do))))))
|
||||
|
||||
;; Like :exec_do*count, but does not push the loop counter onto the INTEGER stack
|
||||
;; Like :exec_do_count, but does not push the loop counter onto the INTEGER stack
|
||||
(def-instruction
|
||||
:exec_do*times
|
||||
:exec_do_times
|
||||
^{:stacks #{:exec :integer}}
|
||||
(fn [state]
|
||||
(if (or (state/empty-stack? state :integer)
|
||||
@ -116,7 +106,7 @@
|
||||
popped-state (state/pop-stack (state/pop-stack state :exec) :integer)]
|
||||
(state/push-to-stack popped-state :exec (list 0
|
||||
(dec index)
|
||||
:exec_do*range
|
||||
:exec_do_range
|
||||
to-do-with-pop))))))
|
||||
|
||||
;; If the top BOOLEAN is TRUE, removes the the second item on the EXEC stack,
|
||||
@ -159,7 +149,7 @@
|
||||
;; the BOOLEAN stack is true. Differs from :exec_while in that it executes
|
||||
;; the top instruction at least once
|
||||
(def-instruction
|
||||
:exec_do*while
|
||||
:exec_do_while
|
||||
^{:stacks #{:boolean :exec}}
|
||||
(fn [state]
|
||||
(if (state/empty-stack? state :exec)
|
||||
|
@ -84,7 +84,7 @@
|
||||
(make-instruction state min [stack stack] stack)))
|
||||
|
||||
;; Pushes 1 / 1.0 if the top BOOLEAN is TRUE, or 0 / 0.0 if FALSE
|
||||
(def _fromboolean
|
||||
(def _from_boolean
|
||||
^{:stacks #{:boolean}}
|
||||
(fn [stack state]
|
||||
(make-instruction state
|
||||
@ -93,14 +93,14 @@
|
||||
stack)))
|
||||
|
||||
;; Pushes the ASCII value of the top CHAR
|
||||
(def _fromchar
|
||||
(def _from_char
|
||||
^{:stacks #{:char}}
|
||||
(fn [stack state]
|
||||
(make-instruction state (if (= stack :integer) int float) [:char] stack)))
|
||||
|
||||
;; Pushes the value of the top STRING, if it can be parsed as a number.
|
||||
;; Otherwise, acts as a NOOP
|
||||
(def _fromstring
|
||||
(def _from_string
|
||||
^{:stacks #{:string}}
|
||||
(fn [stack state]
|
||||
(make-instruction state
|
||||
@ -125,7 +125,7 @@
|
||||
(generate-instructions
|
||||
[:float :integer]
|
||||
[_gt _gte _lt _lte _add _subtract _mult _quot _mod _max _min _inc _dec
|
||||
_fromboolean _fromchar _fromstring])
|
||||
_from_boolean _from_char _from_string])
|
||||
|
||||
;; =============================================================================
|
||||
;; FLOAT Instructions only
|
||||
@ -154,7 +154,7 @@
|
||||
|
||||
;; Pushes the floating point version of the top INTEGER
|
||||
(def-instruction
|
||||
:float_frominteger
|
||||
:float_from_integer
|
||||
^{:stacks #{:float :integer}}
|
||||
(fn [state]
|
||||
(make-instruction state float [:integer] :float)))
|
||||
@ -165,7 +165,7 @@
|
||||
|
||||
;; Pushes the result of truncating the top FLOAT towards negative infinity
|
||||
(def-instruction
|
||||
:integer_fromfloat
|
||||
:integer_from_float
|
||||
^{:stacks #{:float :integer}}
|
||||
(fn [state]
|
||||
(make-instruction state int [:float] :integer)))
|
||||
|
@ -26,7 +26,7 @@
|
||||
;; number n is determined by the top INTEGER. For n = 0, equivalent to POP.
|
||||
;; For n = 1, equivalent to NOOP. For n = 2, equivalent to DUP. Negative values
|
||||
;; of n are treated as 0
|
||||
(def _duptimes
|
||||
(def _dup_times
|
||||
^{:stacks #{:integer}}
|
||||
(fn [stack state]
|
||||
(if (or (and (= stack :integer)
|
||||
@ -46,7 +46,7 @@
|
||||
;; Duplicates the top n items on the stack, one time each. The number n is
|
||||
;; determined by the top INTEGER. If n <= 0, no items will be duplicated. If
|
||||
;; fewer than n items are on the stack, the entire stack will be duplicated.
|
||||
(def _dupitems
|
||||
(def _dup_items
|
||||
^{:stacks #{:integer}}
|
||||
(fn [stack state]
|
||||
(if (state/empty-stack? state :integer)
|
||||
@ -114,7 +114,7 @@
|
||||
state)))
|
||||
|
||||
;; Pushes the given stack's depth onto the INTEGER stack
|
||||
(def _stackdepth
|
||||
(def _stack_depth
|
||||
^{:stacks #{:integer}}
|
||||
(fn [stack state]
|
||||
(let [stack-depth (count (get state stack))]
|
||||
@ -152,7 +152,7 @@
|
||||
|
||||
;; Pushes a copy of an indexed item from deep in the stack, without removing it.
|
||||
;; The top INTEGER is used to determine how deep to yankdup from
|
||||
(def _yankdup
|
||||
(def _yank_dup
|
||||
^{:stacks #{:integer}}
|
||||
(fn [stack state]
|
||||
(if (or (and (= stack :integer)
|
||||
@ -171,5 +171,5 @@
|
||||
(generate-instructions
|
||||
[:boolean :char :code :exec :float :integer :string
|
||||
:vector_boolean :vector_float :vector_integer :vector_string]
|
||||
[_dup _duptimes _dupitems _empty _eq _flush _pop _rot _shove
|
||||
_stackdepth _swap _yank _yankdup])
|
||||
[_dup _dup_times _dup_items _empty _eq _flush _pop _rot _shove
|
||||
_stack_depth _swap _yank _yank_dup])
|
||||
|
@ -1,7 +0,0 @@
|
||||
(ns propeller.push.instructions.random
|
||||
(:require [propeller.push.state :as state]
|
||||
[propeller.push.utils.helpers :refer [make-instruction]]
|
||||
[propeller.push.utils.macros :refer [def-instruction
|
||||
generate-instructions]]))
|
||||
|
||||
|
@ -1,47 +1,297 @@
|
||||
(ns propeller.push.instructions.string
|
||||
(:require [propeller.push.utils.helpers :refer [make-instruction]]
|
||||
[propeller.push.utils.macros :refer [def-instruction]]))
|
||||
(:require [clojure.string :as string]
|
||||
[propeller.utils :as utils]
|
||||
[propeller.push.utils.helpers :refer [make-instruction]]
|
||||
[propeller.push.utils.macros :refer [def-instruction]]
|
||||
[propeller.push.state :as state]))
|
||||
|
||||
;; =============================================================================
|
||||
;; STRING Instructions
|
||||
;; =============================================================================
|
||||
|
||||
;; Pushes the butlast of the top STRING (i.e. the string without its last letter)
|
||||
(def-instruction
|
||||
:string_=
|
||||
^{:stacks #{:boolean :string}}
|
||||
:string_butlast
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state = [:string :string] :boolean)))
|
||||
(make-instruction state #(apply str (butlast %)) [:string] :string)))
|
||||
|
||||
;; Pushes the concatenation of the top two STRINGs (second + first)
|
||||
(def-instruction
|
||||
:string_concat
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(apply str (concat %1 %2)) [:string :string] :string)))
|
||||
(make-instruction state str [:string :string] :string)))
|
||||
|
||||
;; Pushes the concatenation of the top STRING and the top CHAR (STRING + CHAR)
|
||||
(def-instruction
|
||||
:string_conj_char
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state str [:string :char] :string)))
|
||||
|
||||
;; Pushes TRUE if the top STRING is a substring of the second STRING, and FALSE
|
||||
;; otherwise
|
||||
(def-instruction
|
||||
:string_contains
|
||||
^{:stacks #{:boolean :string}}
|
||||
(fn [state]
|
||||
(make-instruction state string/includes? [:string :string] :boolean)))
|
||||
|
||||
;; Pushes TRUE if the top CHAR is contained in the top STRING, and FALSE
|
||||
;; otherwise
|
||||
(def-instruction
|
||||
:string_contains_char
|
||||
^{:stacks #{:boolean :char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(string/includes? %2 (str %1)) [:char :string] :boolean)))
|
||||
|
||||
;; Pushes the top STRING with n characters dropped, where n is taken from the
|
||||
;; top of the INTEGER stack
|
||||
(def-instruction
|
||||
:string_drop
|
||||
^{:stacks #{:integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(apply str (drop %1 %2)) [:integer :string] :string)))
|
||||
|
||||
;; Pushes TRUE if the top STRING is the empty string
|
||||
(def-instruction
|
||||
:string_includes?
|
||||
:string_empty_string
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state empty? [:string] :boolean)))
|
||||
|
||||
;; Pushes the first CHAR of the top STRING
|
||||
(def-instruction
|
||||
:string_first
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state first [:string] :char)))
|
||||
|
||||
;; Pushes the STRING version of the top BOOLEAN, e.g. "true"
|
||||
(def-instruction
|
||||
:string_from_boolean
|
||||
^{:stacks #{:boolean :string}}
|
||||
(fn [state]
|
||||
(make-instruction state clojure.string/includes? [:string :string] :boolean)))
|
||||
(make-instruction state str [:boolean] :string)))
|
||||
|
||||
;; Pushes the STRING version of the top CHAR, e.g. "a"
|
||||
(def-instruction
|
||||
:string_from_char
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state str [:char] :string)))
|
||||
|
||||
;; Pushes the STRING version of the top FLOAT e.g. "2.05"
|
||||
(def-instruction
|
||||
:string_from_float
|
||||
^{:stacks #{:float :string}}
|
||||
(fn [state]
|
||||
(make-instruction state str [:float] :string)))
|
||||
|
||||
;; Pushes the STRING version of the top INTEGER, e.g. "3"
|
||||
(def-instruction
|
||||
:string_from_integer
|
||||
^{:stacks #{:integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state str [:integer] :string)))
|
||||
|
||||
;; Pushes the index of the top CHAR in the top STRING onto the INTEGER stack.
|
||||
;; If the top CHAR is not present in the top string, acts as a NOOP
|
||||
(def-instruction
|
||||
:string_indexof_char
|
||||
^{:stacks #{:char :integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state string/index-of [:string :char] :integer)))
|
||||
|
||||
;; Iterates over the top STRING using code on the EXEC stack
|
||||
(def-instruction
|
||||
:string_iterate
|
||||
^{:stacks #{:char :exec :string}}
|
||||
(fn [state]
|
||||
(if (or (empty? (:string state))
|
||||
(empty? (:exec state)))
|
||||
state
|
||||
(let [top-item (state/peek-stack state :string)
|
||||
popped-state (state/pop-stack state :string)]
|
||||
(cond
|
||||
(empty? top-item)
|
||||
(state/pop-stack popped-state :exec)
|
||||
;;
|
||||
(empty? (rest top-item))
|
||||
(state/push-to-stack popped-state :char (first top-item))
|
||||
;;
|
||||
:else
|
||||
(-> popped-state
|
||||
(state/push-to-stack :exec :string_iterate)
|
||||
(state/push-to-stack :exec (apply str (rest top-item)))
|
||||
(state/push-to-stack :exec (state/peek-stack state :exec))
|
||||
(state/push-to-stack :char (first top-item))))))))
|
||||
|
||||
;; Pushes the last CHAR of the top STRING
|
||||
(def-instruction
|
||||
:string_last
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state last [:string] :char)))
|
||||
|
||||
;; Pushes the length of the top STRING onto the INTEGER stack
|
||||
(def-instruction
|
||||
:string_length
|
||||
^{:stacks #{:integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state count [:string] :integer)))
|
||||
|
||||
;; Pushes the nth CHAR of the top STRING, where n is taken from the top of the
|
||||
;; INTEGER stack. If n exceeds the length of the string, it is reduced modulo
|
||||
;; the length of the string
|
||||
(def-instruction
|
||||
:string_nth
|
||||
^{:stacks #{:char :integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(nth %2 (mod %1 (count %2))) [:integer :string] :char)))
|
||||
|
||||
;; Pushes the number of times the top CHAR occurs in the top STRING onto the
|
||||
;; INTEGER stack
|
||||
(def-instruction
|
||||
:string_occurencesof_char
|
||||
^{:stacks #{:char :integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
(fn [char string]
|
||||
(count (filter #(= char %) string)))
|
||||
[:char :string]
|
||||
:integer)))
|
||||
|
||||
;; Splits the top string into substrings of length 1 (i.e. into its component
|
||||
;; characters) and pushes them back onto the STRING stack in the same order
|
||||
(def-instruction
|
||||
:string_parse_to_chars
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(if (state/empty-stack? state :string)
|
||||
state
|
||||
(let [top-string (state/peek-stack state :string)
|
||||
char-list (string/split top-string #"")
|
||||
popped-state (state/pop-stack state :string)]
|
||||
(state/push-to-stack-many popped-state :string char-list)))))
|
||||
|
||||
;; Pushes the top STRING, with all occurrences of the top CHAR removed
|
||||
(def-instruction
|
||||
:string_remove_char
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
(fn [char string]
|
||||
(apply str (filter #(not= char %) string)))
|
||||
[:char :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the third topmost STRING on stack, with all occurences of the second
|
||||
;; topmost STRING replaced by the top STRING
|
||||
(def-instruction
|
||||
:string_replace
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
#(string/replace %1 %2 %3)
|
||||
[:string :string :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the top STRING, with all occurences of the second topmost CHAR
|
||||
;; replaced with the top CHAR
|
||||
(def-instruction
|
||||
:string_replace_char
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
#(string/replace %3 %1 %2)
|
||||
[:char :char :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the third topmost STRING on stack, with the first occurence of the
|
||||
;; second topmost STRING replaced by the top STRING
|
||||
(def-instruction
|
||||
:string_replace_first
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
#(string/replace-first %1 %2 %3)
|
||||
[:string :string :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the top STRING, with the first occurence of the second topmost CHAR
|
||||
;; replaced with the top CHAR
|
||||
(def-instruction
|
||||
:string_replace_first_char
|
||||
^{:stacks #{:char :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
#(string/replace-first %3 %1 %2)
|
||||
[:char :char :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the rest of the top STRING (i.e. the string without its first letter)
|
||||
(def-instruction
|
||||
:string_rest
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(apply str (rest %)) [:string] :string)))
|
||||
|
||||
;; Pushes the reverse of the top STRING
|
||||
(def-instruction
|
||||
:string_reverse
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(make-instruction state #(apply str (reverse %)) [:string] :string)))
|
||||
|
||||
;; Pushes the top STRING, with the letter at index n (where n is taken from the
|
||||
;; INTEGER stack) replaced with the top CHAR. If n is out of bounds, it is
|
||||
;; reduced modulo the length of the string
|
||||
(def-instruction
|
||||
:string_set_char
|
||||
^{:stacks #{:char :integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
#(let [index (mod %2 (count %3))
|
||||
beginning (take index %3)
|
||||
end (drop (inc index) %3)]
|
||||
(apply str (concat beginning (list %1) end)))
|
||||
[:char :integer :string]
|
||||
:string)))
|
||||
|
||||
;; Splits the top STRING on whitespace, and pushes back the resulting components
|
||||
;; in the same order
|
||||
(def-instruction
|
||||
:string_split
|
||||
^{:stacks #{:string}}
|
||||
(fn [state]
|
||||
(if (state/empty-stack? state :string)
|
||||
state
|
||||
(let [top-item (state/peek-stack state :string)
|
||||
top-item-trimmed (string/trim top-item)
|
||||
string-list (string/split top-item-trimmed #"\s+")
|
||||
popped-state (state/pop-stack state :string)]
|
||||
(state/push-to-stack-many popped-state :string string-list)))))
|
||||
|
||||
;; Pushes the substring of the top STRING, with beginning and end indices
|
||||
;; determined by the second topmost and topmost INTEGERs respectively. If an
|
||||
;; index is out of bounds, the beginning/end of the string is used instead
|
||||
(def-instruction
|
||||
:string_substr
|
||||
^{:stacks #{:integer :string}}
|
||||
(fn [state]
|
||||
(make-instruction state
|
||||
(fn [start stop string]
|
||||
(let [length (count string)
|
||||
start (min length (max 0 start))
|
||||
stop (min length (max start stop))]
|
||||
(subs string start stop)))
|
||||
[:integer :integer :string]
|
||||
:string)))
|
||||
|
||||
;; Pushes the substring of the top STRING consisting of its first n letters,
|
||||
;; where n is determined by the top INTEGER
|
||||
(def-instruction
|
||||
:string_take
|
||||
^{:stacks #{:integer :string}}
|
||||
|
@ -64,6 +64,30 @@
|
||||
(let [lit-stack (get-vector-literal-type stack)]
|
||||
(make-instruction state #(utils/indexof %1 %2) [lit-stack stack] :integer))))
|
||||
|
||||
;; Iterates over the vector using the code on the exec stack
|
||||
(def _iterate
|
||||
^{:stacks #{:elem :integer}}
|
||||
(fn [stack state]
|
||||
(let [lit-stack (get-vector-literal-type stack)]
|
||||
(if (or (state/empty-stack? state :exec)
|
||||
(state/empty-stack? state stack))
|
||||
state
|
||||
(let [vect (state/peek-stack state stack)
|
||||
popped-state (state/pop-stack state stack)]
|
||||
(cond
|
||||
(empty? vect)
|
||||
(state/pop-stack popped-state :exec)
|
||||
;;
|
||||
(empty? (rest vect))
|
||||
(state/push-to-stack popped-state lit-stack (first vect))
|
||||
;;
|
||||
:else
|
||||
(-> popped-state
|
||||
(state/push-to-stack :exec (keyword (str (name stack) "_iterate")))
|
||||
(state/push-to-stack :exec (vec (rest vect)))
|
||||
(state/push-to-stack :exec (state/peek-stack state :exec))
|
||||
(state/push-to-stack lit-stack (first vect)))))))))
|
||||
|
||||
;; Pushes the last item of the top element of the vector stack onto the
|
||||
;; approrpiately-typed literal stack
|
||||
(def _last
|
||||
@ -195,9 +219,9 @@
|
||||
(fn [stack state]
|
||||
(make-instruction state #(vec (take %1 %2)) [:integer stack] stack)))
|
||||
|
||||
;; 4 types x 20 functions = 80 instructions
|
||||
;; 4 types x 21 functions = 84 instructions
|
||||
(generate-instructions
|
||||
[:vector_boolean :vector_float :vector_integer :vector_string]
|
||||
[_butlast _concat _conj _contains _emptyvector _first _indexof _last
|
||||
_length _nth _occurrencesof _pushall _remove _replace _replacefirst
|
||||
[_butlast _concat _conj _contains _emptyvector _first _indexof _iterate
|
||||
_last _length _nth _occurrencesof _pushall _remove _replace _replacefirst
|
||||
_rest _reverse _set _subvec _take])
|
||||
|
Loading…
x
Reference in New Issue
Block a user