├── examples
├── quine.alice
├── hw.alice
├── hw-ord.alice
├── is-prime.alice
├── fibonacci-loop.alice
└── fizzbuzz.alice
├── .gitignore
├── alice.sublime-project
├── interpreter.rb
├── point2d.rb
├── LICENSE
├── alice.rb
├── direction.rb
├── state.rb
├── mode.rb
└── README.md
/examples/quine.alice:
--------------------------------------------------------------------------------
1 | "!<@O&9h.
--------------------------------------------------------------------------------
/examples/hw.alice:
--------------------------------------------------------------------------------
1 | "!dlroW ,olleH"d&O`@
--------------------------------------------------------------------------------
/examples/hw-ord.alice:
--------------------------------------------------------------------------------
1 | /OH!lloo /
2 | @""edlr,W\
--------------------------------------------------------------------------------
/examples/is-prime.alice:
--------------------------------------------------------------------------------
1 | / \cdtn/ o @
2 | i
3 |
--------------------------------------------------------------------------------
/examples/fibonacci-loop.alice:
--------------------------------------------------------------------------------
1 | 1./ \!?+?~#
2 | O
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | mycode
2 |
3 | *.sublime-workspace
4 |
5 | *.nb
--------------------------------------------------------------------------------
/alice.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "path": "."
6 | }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/examples/fizzbuzz.alice:
--------------------------------------------------------------------------------
1 | h0!.3%=e!"Fizz/ o\>.5%="/?uoz o\>.'c-&@aO
2 | > \" /^ >.\B$z " /^
--------------------------------------------------------------------------------
/interpreter.rb:
--------------------------------------------------------------------------------
1 | #!ruby --encoding utf-8:utf-8
2 | # coding: utf-8
3 |
4 | require_relative 'alice'
5 |
6 | if ARGV.size == 0
7 | puts "Usage: ruby interpreter.rb source.alice [args ...]"
8 | else
9 | source = File.read(ARGV.shift)
10 |
11 | alice = Alice.new(source)
12 |
13 | begin
14 | alice.run
15 | rescue => e
16 | alice.state.print_debug_info
17 | $stderr.puts e.message
18 | $stderr.puts e.backtrace
19 | end
20 | end
--------------------------------------------------------------------------------
/point2d.rb:
--------------------------------------------------------------------------------
1 | class Point2D
2 | attr_accessor :x, :y
3 |
4 | def initialize(x, y)
5 | @x = x
6 | @y = y
7 | end
8 |
9 | def self.from_string(string)
10 | coords = string.split.map(&:to_i)
11 | Point2D.new(coords[0], coords[1])
12 | end
13 |
14 | def +(other)
15 | if other.is_a?(Point2D)
16 | return Point2D.new(@x+other.x, @y+other.y)
17 | end
18 | end
19 |
20 | def -(other)
21 | if other.is_a?(Point2D)
22 | return Point2D.new(@x-other.x, @y-other.y)
23 | end
24 | end
25 |
26 | def *(other)
27 | if other.is_a?(Numeric)
28 | return Point2D.new(@x*other, @y*other)
29 | end
30 | end
31 |
32 | def /(other)
33 | if other.is_a?(Numeric)
34 | return Point2D.new(@x/other, @y/other)
35 | end
36 | end
37 |
38 | def coerce(other)
39 | return self, other
40 | end
41 |
42 | def to_s
43 | "#{@x} #{@y}"
44 | end
45 |
46 | def pretty
47 | "(%d,%d)" % [@x, @y]
48 | end
49 | end
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Martin Ender
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/alice.rb:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | Encoding.default_internal = Encoding::UTF_8
4 | Encoding.default_external = Encoding::UTF_8
5 |
6 | require_relative 'state'
7 |
8 | # Add stable sorting methods to Enumerable
9 | module Enumerable
10 | def stable_sort
11 | sort_by.with_index { |x, idx| [x, idx] }
12 | end
13 |
14 | def stable_sort_by
15 | sort_by.with_index { |x, idx| [yield(x), idx] }
16 | end
17 | end
18 |
19 | # Add convenience method for .chr(Encoding::UTF_8)
20 | class Integer
21 | def chr_utf_8
22 | chr(Encoding::UTF_8)
23 | end
24 | end
25 |
26 | class Alice
27 | attr_accessor :state
28 |
29 | class ProgramError < Exception; end
30 |
31 |
32 | def self.run(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1)
33 | new(src, in_str, out_str, args, max_ticks).run
34 | end
35 |
36 | def initialize(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1)
37 | @state = State.new(src, in_str, out_str, args, max_ticks)
38 | end
39 |
40 | def run
41 | ticks_exceeded = false
42 |
43 | loop do
44 | next while !@state.mode.move
45 |
46 | cell = @state.cell
47 | processed = false
48 | if @state.string_mode
49 | case cell
50 | when "'".ord
51 | @state.mode.raw_move
52 | @state.current_string << @state.cell
53 | @state.ip -= @state.dir.vec
54 | processed = true
55 | when '"'.ord
56 | @state.string_mode = false
57 | else
58 | @state.current_string << cell
59 | processed = true
60 | end
61 | elsif cell == '"'.ord
62 | @state.string_mode = true
63 | @state.current_string = []
64 | processed = true
65 | end
66 |
67 | if !processed
68 | iterator = @state.get_iterator
69 | case iterator
70 | when Integer
71 | iterator.times { @state.mode.process cell.chr_utf_8 }
72 | when String
73 | iterator.each_char do |c|
74 | @state.push c
75 | @state.mode.process cell.chr_utf_8
76 | end
77 | end
78 | end
79 |
80 | @state.tick += 1
81 | ticks_exceeded = @state.max_ticks > -1 && @state.tick >= @state.max_ticks
82 | break if @state.done || ticks_exceeded
83 | end
84 |
85 | ticks_exceeded
86 | end
87 |
88 | private
89 |
90 | def error msg
91 | raise msg
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/direction.rb:
--------------------------------------------------------------------------------
1 | require_relative 'point2d'
2 |
3 | class North
4 | def right() East.new end
5 | def left() West.new end
6 | def reverse() South.new end
7 | def vec() Point2D.new(0,-1) end
8 |
9 | def reflect(mirror)
10 | case mirror
11 | when '/'; SouthWest.new
12 | when '\\'; SouthEast.new
13 | when '_'; South.new
14 | when '|'; North.new
15 | end
16 | end
17 |
18 | def ==(other) other.is_a?(North) end
19 | def coerce(other) return self, other end
20 | end
21 |
22 | class NorthEast
23 | def right() SouthEast.new end
24 | def left() NorthWest.new end
25 | def reverse() SouthWest.new end
26 | def vec() Point2D.new(1,-1) end
27 |
28 | def reflect(mirror)
29 | case mirror
30 | when '/'; South.new
31 | when '\\'; East.new
32 | when '_'; SouthEast.new
33 | when '|'; NorthWest.new
34 | end
35 | end
36 |
37 | def ==(other) other.is_a?(NorthEast) end
38 | def coerce(other) return self, other end
39 | end
40 |
41 | class East
42 | def right() South.new end
43 | def left() North.new end
44 | def reverse() West.new end
45 | def vec() Point2D.new(1,0) end
46 |
47 | def reflect(mirror)
48 | case mirror
49 | when '/'; SouthEast.new
50 | when '\\'; NorthEast.new
51 | when '_'; East.new
52 | when '|'; West.new
53 | end
54 | end
55 |
56 | def ==(other) other.is_a?(East) end
57 | def coerce(other) return self, other end
58 | end
59 |
60 | class SouthEast
61 | def right() SouthWest.new end
62 | def left() NorthEast.new end
63 | def reverse() NorthWest.new end
64 | def vec() Point2D.new(1,1) end
65 |
66 | def reflect(mirror)
67 | case mirror
68 | when '/'; East.new
69 | when '\\'; North.new
70 | when '_'; NorthEast.new
71 | when '|'; SouthWest.new
72 | end
73 | end
74 |
75 | def ==(other) other.is_a?(SouthEast) end
76 | def coerce(other) return self, other end
77 | end
78 |
79 | class South
80 | def right() West.new end
81 | def left() East.new end
82 | def reverse() North.new end
83 | def vec() Point2D.new(0,1) end
84 |
85 | def reflect(mirror)
86 | case mirror
87 | when '/'; NorthEast.new
88 | when '\\'; NorthWest.new
89 | when '_'; North.new
90 | when '|'; South.new
91 | end
92 | end
93 |
94 | def ==(other) other.is_a?(South) end
95 | def coerce(other) return self, other end
96 | end
97 |
98 | class SouthWest
99 | def right() NorthWest.new end
100 | def left() SouthEast.new end
101 | def reverse() NorthEast.new end
102 | def vec() Point2D.new(-1,1) end
103 |
104 | def reflect(mirror)
105 | case mirror
106 | when '/'; North.new
107 | when '\\'; West.new
108 | when '_'; NorthWest.new
109 | when '|'; SouthEast.new
110 | end
111 | end
112 |
113 | def ==(other) other.is_a?(SouthWest) end
114 | def coerce(other) return self, other end
115 | end
116 |
117 | class West
118 | def right() North.new end
119 | def left() South.new end
120 | def reverse() East.new end
121 | def vec() Point2D.new(-1,0) end
122 |
123 | def reflect(mirror)
124 | case mirror
125 | when '/'; NorthWest.new
126 | when '\\'; SouthWest.new
127 | when '_'; West.new
128 | when '|'; East.new
129 | end
130 | end
131 |
132 | def ==(other) other.is_a?(West) end
133 | def coerce(other) return self, other end
134 | end
135 |
136 | class NorthWest
137 | def right() NorthEast.new end
138 | def left() SouthWest.new end
139 | def reverse() SouthEast.new end
140 | def vec() Point2D.new(-1,-1) end
141 |
142 | def reflect(mirror)
143 | case mirror
144 | when '/'; West.new
145 | when '\\'; South.new
146 | when '_'; SouthWest.new
147 | when '|'; NorthEast.new
148 | end
149 | end
150 |
151 | def ==(other) other.is_a?(NorthWest) end
152 | def coerce(other) return self, other end
153 | end
154 |
--------------------------------------------------------------------------------
/state.rb:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | require_relative 'mode'
4 | require_relative 'point2d'
5 | require_relative 'direction'
6 |
7 | class State
8 | # I'm sorry.
9 | attr_accessor :in_str, :out_str, :args, :max_ticks,
10 | :grid, :height, :width,
11 | :ip, :dir, :storage_offset,
12 | :stack, :tape, :rp, :mp, :string_mode, :current_string,
13 | :tick, :done,
14 | :mode
15 |
16 | def initialize(src, in_str=$stdin, out_str=$stdout, args=ARGV, max_ticks=-1)
17 | @in_str = in_str
18 | @out_str = out_str
19 | @out_str.binmode # Put the output stream in binary mode so that
20 | # we can write non-UTF-8 bytes.
21 | @args = args
22 |
23 | @max_ticks = max_ticks
24 |
25 | @grid = parse(src)
26 | @height = @grid.size
27 | @width = @height == 0 ? 0 : @grid[0].size
28 |
29 | @ip = Point2D.new(-1, 0) # Instruction pointer
30 | @dir = East.new
31 | @storage_offset = Point2D.new(0, 0) # Will be used when source modification grows the
32 | # to the West or to the North.
33 | @stack = []
34 | @tape = Hash.new(-1)
35 | @mp = 0 # Memory pointer
36 | @rp = 0 # Register pointer
37 | @string_mode = false
38 | @current_string = []
39 | @return_stack = []
40 | @iterator_queue = []
41 |
42 | @tick = 0
43 | @done = false
44 |
45 | @cardinal = Cardinal.new(self)
46 | @ordinal = Ordinal.new(self)
47 |
48 | set_cardinal
49 | end
50 |
51 | def x
52 | @ip.x
53 | end
54 |
55 | def y
56 | @ip.y
57 | end
58 |
59 | def jump x, y
60 | @ip.x = x
61 | @ip.y = y
62 | end
63 |
64 | def cell(coords=@ip)
65 | offset = coords + @storage_offset
66 | line = offset.y < 0 ? [] : @grid[offset.y] || []
67 | offset.x < 0 ? -1 : line[offset.x] || -1
68 | end
69 |
70 | def put_cell(coords, value)
71 | offset = coords + @storage_offset
72 |
73 | # Grow grid if necessary
74 | if offset.x >= @width
75 | @width = offset.x+1
76 | @grid.each{|l| l.fill(-1, l.length...@width)}
77 | end
78 |
79 | if offset.x < 0
80 | @width -= offset.x
81 | @storage_offset.x -= offset.x
82 | @grid.map{|l| l.unshift(*[-1]*(-offset.x))}
83 | offset.x = 0
84 | end
85 |
86 | if offset.y >= @height
87 | @height = offset.y+1
88 | while @grid.size < height
89 | @grid << [-1]*@width
90 | end
91 | end
92 |
93 | if offset.y < 0
94 | @height -= offset.y
95 | @storage_offset.y -= offset.y
96 | while @grid.size < height
97 | @grid.unshift([-1]*@width)
98 | end
99 | offset.y = 0
100 | end
101 |
102 | @grid[offset.y][offset.x] = value
103 |
104 | # Shrink the grid if possible
105 | if value == 0 && on_boundary(coords)
106 | while @height > 0 && @grid[0]-[-1] == []
107 | @grid.shift
108 | @height -= 1
109 | end
110 |
111 | while @height > 0 && @grid[-1]-[-1] == []
112 | @grid.pop
113 | @height -= 1
114 | end
115 |
116 | while @width > 0 && @grid.transpose[0]-[-1] == []
117 | @grid.map(&:shift)
118 | @width -= 1
119 | end
120 |
121 | while @width > 0 && @grid.transpose[-1]-[-1] == []
122 | @grid.map(&:pop)
123 | @width -= 1
124 | end
125 | end
126 | end
127 |
128 | def min_x
129 | -@storage_offset.x
130 | end
131 |
132 | def min_y
133 | -@storage_offset.y
134 | end
135 |
136 | def max_x
137 | @width - @storage_offset.x - 1
138 | end
139 |
140 | def max_y
141 | @height - @storage_offset.y - 1
142 | end
143 |
144 | def on_boundary(coords=@ip)
145 | coords.x == min_x || coords.y == min_y || coords.x == max_x || coords.y == max_y
146 | end
147 |
148 | def wrap
149 | @ip += @storage_offset
150 | case @dir
151 | when East
152 | @ip.x = 0 if @ip.x >= @width
153 | when West
154 | @ip.x = @width-1 if @ip.x < 0
155 | when South
156 | @ip.y = 0 if @ip.y >= @height
157 | when North
158 | @ip.y = @height-1 if @ip.y < 0
159 | end
160 | @ip -= @storage_offset
161 | end
162 |
163 | def set_cardinal
164 | @mode = @cardinal
165 | @other_mode = @ordinal
166 | end
167 |
168 | def set_ordinal
169 | @mode = @ordinal
170 | @other_mode = @cardinal
171 | end
172 |
173 | def toggle_mode
174 | @mode, @other_mode = @other_mode, @mode
175 | end
176 |
177 | def push val
178 | @stack << val
179 | end
180 |
181 | def pop
182 | @stack.pop
183 | end
184 |
185 | def push_return(coords=@ip)
186 | @return_stack.push([coords.x, coords.y])
187 | end
188 |
189 | def pop_return
190 | @return_stack.pop || [@ip.x, @ip.y]
191 | end
192 |
193 | def peek_return
194 | @return_stack[-1] || [@ip.x, @ip.y]
195 | end
196 |
197 | def get_iterator
198 | @iterator_queue.shift || 1
199 | end
200 |
201 | def add_iterator iter
202 | @iterator_queue << iter
203 | end
204 |
205 | def skip_next
206 | @iterator_queue.unshift(0)
207 | end
208 |
209 | def read_register
210 | chars = []
211 | i = @rp
212 | while is_char?(@tape[i])
213 | chars << @tape[i]
214 | i += 1
215 | end
216 | chars.map(&:chr_utf_8).join
217 | end
218 |
219 | def print_debug_info
220 | $stderr.puts "Mode: #{@mode.class}"
221 | print_grid
222 | print_iterators
223 | print_stack
224 | print_tape
225 | print_register
226 | print_args
227 | print_tick
228 | end
229 |
230 | def print_grid
231 | $stderr.puts 'Grid:'
232 | $stderr.puts ' '*(@ip.x+@storage_offset.x)+'v'
233 | @grid.each_with_index do |line, i|
234 | line.each {|c| $stderr << (is_char?(c) && (c == 10 || c >= 32) ? c : 32).chr_utf_8}
235 | $stderr << ' <' if i == @ip.y + @storage_offset.y
236 | $stderr.puts
237 | end
238 | $stderr.puts
239 | $stderr.puts "Top left coordinate: #{(@storage_offset*-1).pretty}"
240 | $stderr.puts "IP: #{@ip.pretty}"
241 | $stderr.puts "Direction: #{@dir.class}"
242 | $stderr.puts "Return address stack: ... (0,0)#{@return_stack.map{|p|' ('+p[0].to_s+','+p[1].to_s+')'}.join}"
243 | $stderr.puts
244 | end
245 |
246 | def print_iterators
247 | $stderr.puts 'Iterators:'
248 | $stderr.puts "<< #{@iterator_queue.empty? ? '(1)' : @iterator_queue.map(&:inspect).join(' ')} <<"
249 | $stderr.puts
250 | end
251 |
252 | def print_tape
253 | $stderr.puts 'Tape:'
254 | min, max = [@mp, @rp, *@tape.keys].minmax
255 | width = 0
256 | rp_str = "OTH:"
257 | tape_str = " ..."
258 | mp_str = "CTH:"
259 | (min-1 .. max+1).map do |i|
260 | s = @tape[i].to_s
261 | tape_str << ' ' << s
262 | rp_str << ' ' << (i == @rp ? 'v'*s.size + " (#{i})" : ' '*s.size)
263 | mp_str << ' ' << (i == @mp ? '^'*s.size + " (#{i})" : ' '*s.size)
264 | end
265 | tape_str << ' ...'
266 | $stderr.puts rp_str
267 | $stderr.puts tape_str
268 | $stderr.puts mp_str
269 | $stderr.puts
270 | end
271 |
272 | def print_stack
273 | $stderr.puts 'Stack:'
274 | $stderr.puts "[...#{@stack.map{|e|' '+e.inspect}.join}]"
275 | $stderr.puts
276 | end
277 |
278 | def print_register
279 | $stderr.puts 'Register:'
280 | $stderr.puts read_register
281 | $stderr.puts
282 | end
283 |
284 | def print_args
285 | $stderr.puts 'Remaining arguments:'
286 | $stderr.puts @args.inspect
287 | $stderr.puts
288 | end
289 |
290 | def print_tick
291 | $stderr.puts "Tick: #{@tick}"
292 | $stderr.puts
293 | end
294 |
295 | private
296 |
297 | def is_char? val
298 | val && (val >= 0 && val <= 0xD7FF || val >= 0xE000 && val <= 0x10FFFF)
299 | end
300 |
301 | def parse(src)
302 | lines = src.split($/, -1)
303 |
304 | grid = lines.map{|l| l.chars.map(&:ord)}
305 |
306 | width = [*grid.map(&:size), 1].max
307 |
308 | grid.each{|l| l.fill(32, l.length...width)}
309 | end
310 | end
311 |
--------------------------------------------------------------------------------
/mode.rb:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 |
3 | require_relative 'point2d'
4 | require_relative 'direction'
5 |
6 | require 'prime'
7 | require 'date'
8 |
9 | class Mode
10 | # List of operators which should not be ignored while in string mode.
11 | STRING_CMDS = "\"'\\/_|"
12 |
13 | def initialize(state)
14 | @state = state
15 | end
16 |
17 | def is_char? val
18 | val && (val >= 0 && val <= 0xD7FF || val >= 0xE000 && val <= 0x10FFFF)
19 | end
20 |
21 | def process
22 | raise NotImplementedError
23 | end
24 |
25 | # Returns true when the resulting cell is a command.
26 | def move
27 | raw_move if @state.cell == "'".ord
28 | raw_move
29 |
30 | cell = @state.cell
31 | case cell
32 | when '/'.ord, '\\'.ord
33 | @state.dir = @state.dir.reflect cell.chr_utf_8
34 | @state.toggle_mode
35 | return false
36 | when '_'.ord, '|'.ord
37 | @state.dir = @state.dir.reflect cell.chr_utf_8
38 | return false
39 | end
40 |
41 | return true if @state.string_mode
42 |
43 | @state.print_debug_info if cell == '`'.ord
44 |
45 | is_char?(cell) && self.class::OPERATORS.has_key?(cell.chr_utf_8)
46 | end
47 |
48 | # Moves the IP a single cell without regard for mirrors, walls or no-ops.
49 | # Does respect grid boundaries.
50 | def raw_move
51 | raise NotImplementedError
52 | end
53 |
54 | def push val
55 | @state.push val
56 | end
57 |
58 | def pop
59 | raise NotImplementedError
60 | end
61 |
62 | def push_return
63 | @state.push_return
64 | end
65 |
66 | def pop_return
67 | @state.pop_return
68 | end
69 |
70 | def peek_return
71 | @state.peek_return
72 | end
73 |
74 | def peek
75 | val = pop
76 | push val
77 | val
78 | end
79 | end
80 |
81 | class Cardinal < Mode
82 | OPERATORS = {
83 | '@' => :terminate,
84 |
85 | '<' => :move_west,
86 | '>' => :move_east,
87 | '^' => :move_north,
88 | 'v' => :move_south,
89 |
90 | '{' => :turn_left,
91 | '}' => :turn_right,
92 |
93 | '#' => :trampoline,
94 | '$' => :cond_trampoline,
95 | '=' => :cond_sign,
96 | '&' => :repeat_iterator,
97 |
98 | '~' => :swap,
99 | '.' => :dup,
100 | ';' => :discard,
101 | ',' => :rotate_stack,
102 |
103 | '0' => :digit, '1' => :digit, '2' => :digit, '3' => :digit, '4' => :digit, '5' => :digit, '6' => :digit, '7' => :digit, '8' => :digit, '9' => :digit,
104 | '+' => :add,
105 | '-' => :sub,
106 | '*' => :mul,
107 | ':' => :div,
108 | '%' => :mod,
109 |
110 | '!' => :store_tape,
111 | '?' => :load_tape,
112 | '[' => :mp_left,
113 | ']' => :mp_right,
114 | '(' => :search_left,
115 | ')' => :search_right,
116 |
117 | '"' => :leave_string_mode,
118 | "'" => :escape,
119 |
120 | 'I' => :input,
121 | 'O' => :output,
122 | 'i' => :raw_input,
123 | 'o' => :raw_output,
124 |
125 | 'A' => :bitand,
126 | 'B' => :divisors,
127 | 'C' => :binomial,
128 | 'D' => :deduplicate,
129 | 'E' => :power,
130 | 'F' => :divides,
131 | 'G' => :gcd,
132 | 'H' => :abs,
133 | 'J' => :jump_raw,
134 | 'K' => :return_raw,
135 | 'L' => :lcm,
136 | 'M' => :argc,
137 | 'N' => :bitnot,
138 | 'P' => :factorial,
139 | 'Q' => :convert,
140 | 'R' => :negate,
141 | 'S' => :replace_divisors,
142 | 'T' => :sleep,
143 | 'U' => :random,
144 | 'V' => :bitor,
145 | 'W' => :discard_return,
146 | 'X' => :bitxor,
147 | 'Y' => :unpack,
148 | 'Z' => :pack,
149 |
150 | 'a' => :const_10,
151 | 'b' => :random_swap,
152 | 'c' => :prime_factors,
153 | 'd' => :stack_depth,
154 | 'e' => :const_m1,
155 | 'f' => :prime_factor_pairs,
156 | 'g' => :get_cell,
157 | 'h' => :inc,
158 | 'j' => :jump,
159 | 'k' => :return,
160 | 'l' => :clear_bits,
161 | 'm' => :floor,
162 | 'n' => :not,
163 | 'p' => :put_cell,
164 | 'q' => :get_mp,
165 | 'r' => :range,
166 | 's' => :sortswap,
167 | 't' => :dec,
168 | 'u' => :set_bits,
169 | 'w' => :push_return,
170 | 'x' => :extract_bit,
171 | 'y' => :bitif,
172 | 'z' => :drop_small_factors,
173 | }
174 |
175 | OPERATORS.default = :nop
176 |
177 | def raw_move
178 | @state.ip += @state.dir.vec
179 | @state.wrap
180 | end
181 |
182 | def pop
183 | val = nil
184 |
185 | loop do
186 | val = @state.pop
187 | if val.is_a?(String)
188 | found = false
189 | val.scan(/(?:\A|(?!\G))-?\d+/) { push $&.to_i; found = true }
190 | next if !found
191 | val = @state.pop
192 | end
193 |
194 | break
195 | end
196 |
197 | val || 0
198 | end
199 |
200 | def process cmd
201 | opcode = OPERATORS[cmd]
202 |
203 | case opcode
204 | when :nop
205 | raise "No-op reached process(). This shouldn't happen."
206 |
207 | when :terminate
208 | @state.done = true
209 |
210 | when :move_east
211 | @state.dir = East.new
212 | when :move_west
213 | @state.dir = West.new
214 | when :move_south
215 | @state.dir = South.new
216 | when :move_north
217 | @state.dir = North.new
218 | when :turn_left
219 | @state.dir = @state.dir.left
220 | when :turn_right
221 | @state.dir = @state.dir.right
222 | when :trampoline
223 | @state.skip_next
224 | when :cond_trampoline
225 | @state.skip_next if pop == 0
226 | when :cond_sign
227 | val = pop
228 | if val < 0
229 | @state.dir = @state.dir.left
230 | elsif val > 0
231 | @state.dir = @state.dir.right
232 | end
233 | when :repeat_iterator
234 | @state.add_iterator pop
235 |
236 | when :jump
237 | push_return
238 | y = pop
239 | x = pop
240 | @state.jump(x,y)
241 | when :return
242 | @state.jump(*pop_return)
243 | when :jump_raw
244 | y = pop
245 | x = pop
246 | @state.jump(x,y)
247 | when :return_raw
248 | @state.jump(*peek_return)
249 | when :push_return
250 | push_return
251 | when :discard_return
252 | pop_return
253 |
254 | when :get_cell
255 | y = pop
256 | x = pop
257 | push @state.cell(Point2D.new(x,y))
258 | when :put_cell
259 | y = pop
260 | x = pop
261 | v = pop
262 | @state.put_cell(Point2D.new(x,y), v)
263 |
264 | when :store_tape
265 | @state.tape[@state.mp] = pop
266 | when :load_tape
267 | push (@state.tape[@state.mp] || -1)
268 | when :mp_left
269 | @state.mp -= 1
270 | when :mp_right
271 | @state.mp += 1
272 | when :search_left
273 | val = pop
274 | (@state.mp-1).downto([*@state.tape.keys, 0].min-1).each do |i|
275 | if @state.tape[i] == val
276 | @state.mp = i
277 | break
278 | end
279 | end
280 | when :search_right
281 | val = pop
282 | (@state.mp+1..[*@state.tape.keys, 0].max+1).each do |i|
283 | if @state.tape[i] == val
284 | @state.mp = i
285 | break
286 | end
287 | end
288 | when :get_mp
289 | push @state.mp
290 |
291 | when :leave_string_mode
292 | @state.stack += @state.current_string
293 | when :escape
294 | old_ip = @state.ip
295 | raw_move
296 | push @state.cell
297 | @state.ip = old_ip
298 |
299 | when :input
300 | char = @state.in_str.getc
301 | while char && char.scrub('') == ''
302 | char = @state.in_str.getc
303 | end
304 |
305 | push(char ? char.ord : -1)
306 | when :output
307 | # Will throw an error when value isn't a valid code point
308 | val = pop
309 | if is_char?(val)
310 | val.chr_utf_8.unpack('C*').each{|c| @state.out_str.putc c }
311 | end
312 | when :raw_input
313 | push(@state.in_str.getbyte || -1)
314 | when :raw_output
315 | @state.out_str.putc pop
316 | when :argc
317 | push @state.args.size
318 |
319 | when :digit
320 | push cmd.to_i
321 | when :add
322 | push(pop + pop)
323 | when :sub
324 | y = pop
325 | push(pop - y)
326 | when :mul
327 | push(pop * pop)
328 | when :div
329 | y = pop
330 | push(pop / y)
331 | when :mod
332 | y = pop
333 | push(pop % y)
334 | when :inc
335 | push(pop+1)
336 | when :dec
337 | push(pop-1)
338 | when :abs
339 | push(pop.abs)
340 | when :power
341 | y = pop
342 | x = pop
343 | if y < 0
344 | # Compute integer root of the absolute base, preserving sign of base
345 | if x < 0
346 | r = 0
347 | # If I'm ever not lazy I'll replace this with a binary search...
348 | r -= 1 while (-r)**-y < -x
349 | push r
350 | else
351 | r = 0
352 | # If I'm ever not lazy I'll replace this with a binary search...
353 | r += 1 until r**-y > x
354 | push (r-1)
355 | end
356 | else
357 | push x**y
358 | end
359 | when :bitand
360 | push(pop & pop)
361 | when :bitnot
362 | push(~pop)
363 | when :bitor
364 | push(pop | pop)
365 | when :bitxor
366 | push(pop ^ pop)
367 | when :bitif
368 | z = pop
369 | y = pop
370 | x = pop
371 | push(x&y | ~x&z)
372 | when :clear_bits
373 | x = pop
374 | if x > 0
375 | msb = Math.log2(x).floor
376 | elsif x < -1
377 | msb = Math.log2(~x).floor
378 | else
379 | msb = 0
380 | end
381 | push (x & -(2**msb))
382 | when :set_bits
383 | x = pop
384 | if x > 0
385 | msb = Math.log2(x).floor
386 | elsif x < -1
387 | msb = Math.log2(~x).floor
388 | else
389 | msb = 0
390 | end
391 | push (x | (2**msb-1))
392 | when :extract_bit
393 | y = pop
394 | x = pop
395 | if y >= 0
396 | push x[y]
397 | else
398 | if x > 0
399 | msb = Math.log2(x).floor
400 | elsif x < -1
401 | msb = Math.log2(~x).floor
402 | else
403 | msb = -1
404 | end
405 | push x[msb+y+1]
406 | end
407 |
408 | when :factorial
409 | val = pop
410 | if val >= 0
411 | push (1..val).reduce(1, :*)
412 | else
413 | push (val..-1).reduce(1, :*)
414 | end
415 | when :binomial
416 | k = pop
417 | n = pop
418 |
419 | k = n-k if n > 0 && k > n/2
420 |
421 | if k < 0
422 | push 0
423 | else
424 | prod = 1
425 | (1..k).each do |i|
426 | prod *= n
427 | prod /= i
428 | n -= 1
429 | end
430 | push prod
431 | end
432 | when :negate
433 | push -pop
434 | when :prime_factors
435 | n = pop
436 | if n == 0
437 | push 0
438 | else
439 | Prime.prime_division(n).each{ |p,n| n.times{ push p } }
440 | end
441 | when :prime_factor_pairs
442 | n = pop
443 | if n == 0
444 | push 0
445 | push 1
446 | else
447 | Prime.prime_division(n).flatten.each{ |x| push x }
448 | end
449 | when :deduplicate
450 | n = pop
451 | if n == 0
452 | push 0
453 | else
454 | push Prime.int_from_prime_division(Prime.prime_division(n).map{ |p,n| [p,1]})
455 | end
456 | when :divides
457 | y = pop
458 | x = pop
459 | if y != 0 && x % y == 0
460 | push y
461 | else
462 | push 0
463 | end
464 | when :gcd
465 | push (pop.gcd pop)
466 | when :lcm
467 | push (pop.lcm pop)
468 | when :floor
469 | y = pop.abs
470 | x = pop
471 | push (x/y)*y
472 | when :replace_divisors
473 | z = pop
474 | y = pop
475 | x = pop
476 | if x == 0
477 | push 0
478 | elsif y == 1 || y == -1
479 | if z == y
480 | push x
481 | elsif z == 0
482 | push 0
483 | else
484 | loop { next }
485 | end
486 | else
487 | order = 0
488 | while x%y == 0
489 | order += 1
490 | x /= y
491 | end
492 | x *= z**order
493 | push x
494 | end
495 | when :divisors
496 | n = pop
497 | sgn = n <=> 0
498 | n = n.abs
499 | k = 1
500 | small_divs = []
501 | large_divs = []
502 | while k*k <= n
503 | if n%k == 0
504 | small_divs << k
505 | large_divs << n/k if k*k != n
506 | end
507 | k += 1
508 | end
509 | (small_divs + large_divs.reverse).each {|k| push k*sgn}
510 |
511 | when :drop_small_factors
512 | k = pop
513 | n = pop
514 |
515 | if n.abs > 1
516 | factors = Prime.prime_division(n.abs)
517 | n_dropped = 0
518 | while !factors.empty? && factors[0][0] <= k.abs
519 | pr, m = factors.shift
520 | n_dropped += m
521 | end
522 | n = Prime.int_from_prime_division(factors) * (n <=> 0)
523 | if k < 0 && n_dropped.odd?
524 | n *= -1
525 | end
526 | end
527 |
528 | push n
529 |
530 | when :pack
531 | y = pop
532 | x = pop
533 |
534 | # Map integers to naturals
535 | sgn = x <=> 0
536 | x = x*sgn*2 + [0, sgn].min
537 |
538 | sgn = y <=> 0
539 | y = y*sgn*2 + [0, sgn].min
540 |
541 | # Map two naturals to one
542 | z = (x+y)*(x+y+1)/2 + y
543 |
544 | # Map the natural back to an integer
545 | z = (-1)**z * ((z+1)/2)
546 |
547 | push z
548 |
549 | when :unpack
550 | z = pop
551 |
552 | # Map the integer to a positive natural
553 | sgn = z <=> 0
554 | z = z*sgn*2 + [0, sgn].min
555 |
556 | # Map the natural to two
557 | y = z
558 | x = 0
559 | while x < y
560 | x += 1
561 | y -= x
562 | end
563 | x -= y
564 |
565 | # Map the naturals back to integers
566 | x = (-1)**x * ((x+1)/2)
567 | y = (-1)**y * ((y+1)/2)
568 |
569 | push x
570 | push y
571 |
572 | when :not
573 | push (pop == 0 ? 1 : 0)
574 |
575 | when :range
576 | val = pop
577 | if val >= 0
578 | 0.upto(val) {|i| push i}
579 | else
580 | (-val).downto(0) {|i| push i}
581 | end
582 |
583 | when :random
584 | val = pop
585 | if val > 0
586 | push rand val
587 | elsif val == 0
588 | push 0
589 | else
590 | push -(rand val)
591 | end
592 | when :random_swap
593 | top = pop
594 | second = pop
595 | top, second = [top, second].shuffle
596 | push second
597 | push top
598 |
599 | when :sortswap
600 | top = pop
601 | second = pop
602 |
603 | top, second = second, top if top < second
604 |
605 | push second
606 | push top
607 |
608 | when :swap
609 | top = pop
610 | second = pop
611 | push top
612 | push second
613 | when :dup
614 | top = pop
615 | push top
616 | push top
617 | when :discard
618 | pop
619 | when :stack_depth
620 | push @state.stack.size
621 | when :rotate_stack
622 | n = pop
623 | if n > 0
624 | push(@state.stack.delete_at(-n-1) || 0)
625 | elsif n < 0
626 | top = @state.stack.pop || 0 # Do this manually to prevent type conversion
627 | @state.stack = [0]*[-n-@state.stack.size, 0].max + @state.stack
628 | @state.stack.insert(n-1, top)
629 | end
630 | when :convert
631 | n = pop
632 | n.times.map{pop}.reverse.each{|v| push v}
633 | when :sleep
634 | sleep [0, pop/1000.0].max
635 | when :const_10
636 | push 10
637 | when :const_m1
638 | push -1
639 |
640 | end
641 | end
642 | end
643 |
644 | class Ordinal < Mode
645 | OPERATORS = {
646 | '@' => :terminate,
647 |
648 | '0' => :digit, '1' => :digit, '2' => :digit, '3' => :digit, '4' => :digit, '5' => :digit, '6' => :digit, '7' => :digit, '8' => :digit, '9' => :digit,
649 | '+' => :superimpose,
650 | '-' => :drop,
651 | '*' => :concat,
652 | ':' => :occurrences,
653 | '%' => :split,
654 |
655 | '<' => :ensure_west,
656 | '>' => :ensure_east,
657 | '^' => :ensure_north,
658 | 'v' => :ensure_south,
659 |
660 | '{' => :turn_left,
661 | '}' => :turn_right,
662 |
663 | '#' => :trampoline,
664 | '$' => :cond_trampoline,
665 | '=' => :cond_cmp,
666 | '&' => :fold_iterator,
667 |
668 | '~' => :swap,
669 | '.' => :dup,
670 | ';' => :discard,
671 | ',' => :permute_stack,
672 |
673 | '!' => :store_register,
674 | '?' => :load_register,
675 | '[' => :register_left,
676 | ']' => :register_right,
677 | '(' => :search_left,
678 | ')' => :search_right,
679 |
680 | '"' => :leave_string_mode,
681 | "'" => :escape,
682 |
683 | 'I' => :input,
684 | 'O' => :output,
685 | 'i' => :raw_input,
686 | 'o' => :raw_output,
687 |
688 | 'A' => :intersection,
689 | 'B' => :substrings,
690 | 'C' => :subsequences,
691 | 'D' => :deduplicate,
692 | 'E' => :riffle,
693 | 'F' => :find,
694 | 'G' => :longest_common_substring,
695 | 'H' => :trim,
696 | 'J' => :jump_raw,
697 | 'K' => :return_raw,
698 | 'L' => :shortest_common_superstring,
699 | 'M' => :argv,
700 | 'N' => :complement,
701 | 'P' => :permutations,
702 | 'Q' => :reverse_stack,
703 | 'R' => :reverse,
704 | 'S' => :replace,
705 | 'T' => :datetime,
706 | 'U' => :random_choice,
707 | 'V' => :union,
708 | 'W' => :discard_return,
709 | 'X' => :symdifference,
710 | 'Y' => :unzip,
711 | 'Z' => :zip,
712 |
713 | 'a' => :const_lf,
714 | 'b' => :shuffle,
715 | 'c' => :characters,
716 | 'd' => :push_joined_stack,
717 | 'e' => :const_empty,
718 | 'f' => :runs,
719 | 'g' => :get_diagonal,
720 | 'h' => :head,
721 | 'j' => :jump,
722 | 'k' => :return,
723 | 'l' => :lower_case,
724 | 'm' => :truncate_to_shorter,
725 | 'u' => :upper_case,
726 | 'n' => :not,
727 | 'p' => :put_diagonal,
728 | 'q' => :join_tape,
729 | 'r' => :expand_ranges,
730 | 's' => :sort,
731 | 't' => :tail,
732 | 'w' => :push_return,
733 | 'x' => :permute,
734 | 'y' => :transliterate,
735 | 'z' => :discard_up_to,
736 |
737 | #'(' => ,
738 | #')' => ,
739 |
740 | #'!' => ,
741 | #'$' => ,
742 | #'&' => ,
743 | #',' => ,
744 | #'.' => ,
745 | #';' => ,
746 | #'=' => ,
747 | #'?' => ,
748 | #'`' => ,
749 |
750 | #'A' => ,
751 | # ...
752 | #'Z' => ,
753 | #'a' => ,
754 | # ...
755 | #'z' => ,
756 | }
757 |
758 | OPERATORS.default = :nop
759 |
760 | def raw_move
761 | if @state.width == 1 || @state.height == 1
762 | return
763 | end
764 |
765 | new_pos = @state.ip + @state.dir.vec + @state.storage_offset
766 | @state.dir = @state.dir.reflect('|') if new_pos.x < 0 || new_pos.x >= @state.width
767 | @state.dir = @state.dir.reflect('_') if new_pos.y < 0 || new_pos.y >= @state.height
768 |
769 | @state.ip += @state.dir.vec
770 | end
771 |
772 | def pop
773 | val = @state.pop
774 |
775 | val ? val.to_s : ''
776 | end
777 |
778 | def scan_source label
779 | ip_dir = @state.dir
780 | grid = @state.grid
781 | while !ip_dir.is_a? NorthEast
782 | grid = grid.transpose.reverse
783 | ip_dir = ip_dir.left
784 | end
785 |
786 | height = grid.size
787 | width = height == 0 ? 0 : grid[0].size
788 |
789 | positions = []
790 |
791 | (0..width+height-2).map do |d|
792 | min_x = [0,d-height+1].max
793 | max_x = [width-1,d].min
794 | line = (min_x..max_x).map do |x|
795 | y = d - x
796 | grid[y][x].chr_utf_8
797 | end.join
798 |
799 | line.scan(/(?=#{Regexp.escape(label)})/) do
800 | x = min_x + $`.size + label.size - 1
801 | y = d-x
802 | positions << [x,y]
803 | end
804 | end
805 |
806 | ip_dir = @state.dir
807 | while !ip_dir.is_a? NorthEast
808 | ip_dir = ip_dir.left
809 | positions.map! {|x, y| [grid.size - y - 1, x]}
810 | grid = grid.reverse.transpose
811 | end
812 |
813 | positions
814 | end
815 |
816 | def process cmd
817 | opcode = OPERATORS[cmd]
818 |
819 | case opcode
820 | when :nop
821 | raise "No-op reached process(). This shouldn't happen."
822 |
823 | when :terminate
824 | @state.done = true
825 |
826 | when :ensure_west
827 | @state.dir = @state.dir.reflect '|' if @state.dir.vec.x > 0
828 | when :ensure_east
829 | @state.dir = @state.dir.reflect '|' if @state.dir.vec.x < 0
830 | when :ensure_north
831 | @state.dir = @state.dir.reflect '_' if @state.dir.vec.y > 0
832 | when :ensure_south
833 | @state.dir = @state.dir.reflect '_' if @state.dir.vec.y < 0
834 | when :turn_left
835 | @state.dir = @state.dir.left
836 | when :turn_right
837 | @state.dir = @state.dir.right
838 | when :trampoline
839 | @state.skip_next
840 | when :cond_trampoline
841 | @state.skip_next if pop == ''
842 | when :cond_cmp
843 | top = pop
844 | second = pop
845 | if top > second
846 | @state.dir = @state.dir.left
847 | elsif top < second
848 | @state.dir = @state.dir.right
849 | end
850 | when :fold_iterator
851 | @state.add_iterator pop
852 |
853 | when :jump
854 | label = pop
855 | positions = scan_source(label)
856 | if !positions.empty?
857 | push_return
858 | @state.jump(*positions[0])
859 | end
860 | when :return
861 | @state.jump(*pop_return)
862 | when :jump_raw
863 | label = pop
864 | positions = scan_source(label)
865 | @state.jump(*positions[0]) if !positions.empty?
866 | when :return_raw
867 | @state.jump(*peek_return)
868 | when :push_return
869 | push_return
870 | when :discard_return
871 | pop_return
872 |
873 | when :get_diagonal
874 | label = pop
875 | positions = scan_source(label)
876 | if !positions.empty?
877 | cursor = Point2D.new(*positions[0]) + @state.dir.vec
878 | string = ''
879 | while is_char? @state.cell(cursor)
880 | string << @state.cell(cursor)
881 | cursor += @state.dir.vec
882 | end
883 | push string
884 | end
885 | when :put_diagonal
886 | label = pop
887 | value = pop
888 | positions = scan_source(label)
889 | if !positions.empty?
890 | cursor = Point2D.new(*positions[0]) + @state.dir.vec
891 | value.each_char {|c|
892 | @state.put_cell(cursor, c.ord)
893 | cursor += @state.dir.vec
894 | }
895 | end
896 |
897 | when :store_register
898 | i = @state.rp
899 | pop.each_char do |c|
900 | @state.tape[i] = c.ord
901 | i += 1
902 | end
903 | @state.tape[i] = -1
904 | when :load_register
905 | push @state.read_register
906 | when :register_left
907 | @state.rp -= 1 while is_char? @state.tape[@state.rp-1]
908 | @state.rp -= 1
909 | @state.rp -= 1 while is_char? @state.tape[@state.rp-1]
910 | when :register_right
911 | @state.rp += 1 while is_char? @state.tape[@state.rp]
912 | @state.rp += 1
913 | when :search_left
914 | needle = pop
915 | string = ""
916 |
917 | cursor = @state.rp-1
918 | cursor -= 1 while is_char? @state.tape[cursor-1]
919 |
920 | (cursor-2).downto([*@state.tape.keys, 0].min-1).each do |i|
921 | if is_char?(@state.tape[i])
922 | string << @state.tape[i]
923 | elsif string.reverse[needle]
924 | @state.rp = i+1
925 | break
926 | else
927 | string = ""
928 | end
929 | end
930 | when :search_right
931 | needle = pop
932 | string = ""
933 |
934 | cursor = @state.rp
935 | cursor += 1 while is_char? @state.tape[cursor]
936 |
937 | (cursor+1..[*@state.tape.keys, 0].max+1).each do |i|
938 | if is_char?(@state.tape[i])
939 | string << @state.tape[i]
940 | elsif string[needle]
941 | @state.rp = i - string.size
942 | break
943 | else
944 | string = ""
945 | end
946 | end
947 | when :join_tape
948 | push @state.tape.keys.sort.map{|i| @state.tape[i]}.select{|v| is_char?(v)}.map(&:chr_utf_8).join
949 |
950 | when :leave_string_mode
951 | push @state.current_string.select{|c| is_char? c }.map(&:chr_utf_8).join
952 | when :escape
953 | old_ip = @state.ip
954 | old_dir = @state.dir
955 | raw_move
956 | if is_char?(@state.cell)
957 | push @state.cell.chr_utf_8
958 | else
959 | push ''
960 | end
961 | @state.ip = old_ip
962 | @state.dir = old_dir
963 |
964 | when :digit
965 | push(pop + cmd)
966 |
967 | when :input
968 | line = @state.in_str.gets
969 | push(line ? line.scrub('').chomp : '')
970 | when :output
971 | pop.unpack('C*').each{|c| @state.out_str.putc c }
972 | @state.out_str.puts
973 | when :raw_input
974 | str = @state.in_str.read
975 | push(str ? str.scrub('') : '')
976 | when :raw_output
977 | pop.unpack('C*').each{|c| @state.out_str.putc c }
978 | when :argv
979 | arg = ARGV.shift || ""
980 | push(arg.dup.force_encoding(Encoding::UTF_8).scrub(''))
981 |
982 | when :superimpose
983 | top = pop
984 | second = pop
985 | result = ""
986 | [top.size, second.size].max.times do |i|
987 | result << [top[i] || 0.chr_utf_8, second[i] || 0.chr_utf_8].max
988 | end
989 | push result
990 |
991 | when :concat
992 | top = pop
993 | second = pop
994 | push(second + top)
995 | when :drop
996 | y = pop
997 | x = pop
998 | result = x.chars
999 | x.scan(/(?=#{Regexp.escape(y)})/) do
1000 | y.size.times do |i|
1001 | result[$`.size + i] = 0
1002 | end
1003 | end
1004 |
1005 | push (result-[0]).join
1006 | when :riffle
1007 | sep = pop
1008 | push(pop.chars * sep)
1009 | when :occurrences
1010 | sep = pop
1011 | pop.scan(/#{Regexp.escape(sep)}/){ push sep }
1012 | when :split
1013 | sep = pop
1014 | @state.stack += pop.split(sep, -1)
1015 | when :replace
1016 | target = pop
1017 | needle = pop
1018 | haystack = pop
1019 | push haystack.gsub(needle, target)
1020 | when :trim
1021 | push pop.gsub(/\A[ \n\t]+|[ \n\t]+\z/, '')
1022 | when :transliterate
1023 | target = pop
1024 | source = pop
1025 | string = pop
1026 | if !string.empty?
1027 | if target.empty?
1028 | source.each_char {|c| string.gsub!(c, '')}
1029 | else
1030 | max_char_count = string.chars.uniq.map{|c| string.count c}.max
1031 | source *= max_char_count
1032 | target *= source.size / target.size + 1
1033 | string = string.chars.map{ |c|
1034 | if (i = source.index c)
1035 | d = target[i]
1036 | source[i] = ''
1037 | target[i] = ''
1038 | d
1039 | else
1040 | c
1041 | end
1042 | }.join
1043 | end
1044 | end
1045 | push string
1046 | when :discard_up_to
1047 | y = pop
1048 | x = pop
1049 |
1050 | i = x.index y
1051 | x[0,i+y.size] = '' if i
1052 |
1053 | push x
1054 |
1055 | when :find
1056 | needle = pop
1057 | haystack = pop
1058 | push(haystack[needle] || '')
1059 | when :truncate_to_shorter
1060 | top = pop
1061 | second = pop
1062 | length = [top.size, second.size].min
1063 | push second[0,length]
1064 | push top[0,length]
1065 | when :zip
1066 | top = pop.chars
1067 | second = pop.chars
1068 | result = []
1069 | while !top.empty? || !second.empty?
1070 | result << (second.shift || '')
1071 | result << (top.shift || '')
1072 | end
1073 | push result * ''
1074 | when :unzip
1075 | str = pop
1076 | left = ''
1077 | right = ''
1078 | str.scan(/(.)(.|\z)/m) do
1079 | left << $1
1080 | right << $2
1081 | end
1082 | push left
1083 | push right
1084 |
1085 | when :shortest_common_superstring
1086 | top = pop
1087 | second = pop
1088 | len = [top.size, second.size].min
1089 | len.downto(0) do |i|
1090 | if second[-i,i] == top[0,i]
1091 | push second+top[i..-1]
1092 | break
1093 | end
1094 | end
1095 | when :longest_common_substring
1096 | top = pop
1097 | second = pop
1098 | second.size.downto(0) do |l|
1099 | if l == 0
1100 | push ""
1101 | else
1102 | shared = second.chars.each_cons(l).select {|s| top[s.join]}
1103 | if !shared.empty?
1104 | shared.uniq.each{|s| push s.join}
1105 | break
1106 | end
1107 | end
1108 | end
1109 |
1110 | when :intersection
1111 | second = pop
1112 | first = pop
1113 | result = first.chars.select {|c|
1114 | test = second[c]
1115 | second[c] = '' if test
1116 | test
1117 | }
1118 | push result.join
1119 | when :union
1120 | second = pop
1121 | first = pop
1122 | first.each_char {|c| second[c] = '' if second[c]}
1123 | push(first + second)
1124 | when :symdifference
1125 | second = pop
1126 | first = pop
1127 |
1128 | temp_second = second.clone
1129 |
1130 | first.each_char {|c| second[c] = '' if second[c]}
1131 | temp_second.each_char {|c| first[c] = '' if first[c]}
1132 |
1133 | push first+second
1134 | when :complement
1135 | second = pop
1136 | first = pop
1137 | second.each_char {|c| first[c] = '' if first[c]}
1138 |
1139 | push first
1140 |
1141 | when :deduplicate
1142 | push pop.chars.uniq.join
1143 |
1144 | when :sort
1145 | push pop.chars.sort.join
1146 |
1147 | when :shuffle
1148 | push pop.chars.shuffle.join
1149 | when :random_choice
1150 | push pop.chars.sample || ''
1151 |
1152 | when :characters
1153 | @state.stack += pop.chars
1154 | when :runs
1155 | pop.scan(/(.)\1*/m){push $&}
1156 | when :head
1157 | str = pop
1158 | if str == ''
1159 | push ''
1160 | push ''
1161 | else
1162 | push str[0]
1163 | push str[1..-1]
1164 | end
1165 | when :tail
1166 | str = pop
1167 | if str == ''
1168 | push ''
1169 | push ''
1170 | else
1171 | push str[0..-2]
1172 | push str[-1]
1173 | end
1174 |
1175 | when :lower_case
1176 | push pop.downcase
1177 | when :upper_case
1178 | push pop.upcase
1179 | when :swap_case
1180 | push pop.swapcase
1181 |
1182 | when :not
1183 | push(pop == '' ? 'Jabberwocky' : '')
1184 |
1185 | when :reverse
1186 | push pop.reverse
1187 | when :permutations
1188 | @state.stack += pop.chars.permutation.map{|p| p.join}.to_a
1189 | when :subsequences
1190 | str = pop.chars
1191 | (0..str.size).each do |l|
1192 | str.combination(l).each {|s| push s.join}
1193 | end
1194 | when :substrings
1195 | str = pop.chars
1196 | (1..str.size).each do |l|
1197 | str.each_cons(l).each {|s| push s.join}
1198 | end
1199 | when :permute
1200 | top = pop
1201 | second = pop
1202 | push (0...second.size).stable_sort_by{|i|
1203 | c = top[i]
1204 | c ? c.ord : 1114112 # Value greater than any code point, so that trailing
1205 | # characters remain in place.
1206 | }.map{|i| second[i]}.join
1207 |
1208 | when :expand_ranges
1209 | val = pop
1210 | push val.chars.map(&:ord).each_cons(2).map{ |a,b|
1211 | if a > b
1212 | (b..a).drop(1).to_a.reverse.select{|c|is_char? c}.map(&:chr_utf_8).join
1213 | else
1214 | (a...b).to_a.select{|c|is_char? c}.map(&:chr_utf_8).join
1215 | end
1216 | }.join + (val[-1] || '')
1217 |
1218 |
1219 | when :swap
1220 | top = pop
1221 | second = pop
1222 | push top
1223 | push second
1224 | when :dup
1225 | top = pop
1226 | push top.clone
1227 | push top.clone
1228 | when :discard
1229 | pop
1230 | when :push_joined_stack
1231 | push @state.stack.join
1232 | when :reverse_stack
1233 | @state.stack.reverse!.map!{|x|x.to_s}
1234 | when :permute_stack
1235 | top = pop
1236 | max_size = [@state.stack.size, top.size].max
1237 | @state.stack = (-max_size..-1).stable_sort_by{|i|
1238 | c = top[i]
1239 | c ? c.ord : -1 # Value less than any code point, so that leading
1240 | # stack elements remain in place.
1241 | }.map{|i| @state.stack[i] || ''}
1242 |
1243 | when :datetime
1244 | push DateTime.now.strftime '%Y-%m-%dT%H:%M:%S.%L%:z'
1245 | when :const_lf
1246 | push "\n"
1247 | when :const_empty
1248 | push ""
1249 |
1250 | end
1251 | end
1252 | end
1253 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Alice
2 |
3 | "...the slithy toves did gyre and gimble in the wabe." — Lewis Carroll
4 |
5 | Alice is a two-dimensional, stack-based, recreational programming language. It was designed as a feature-rich [Fungeoid](https://esolangs.org/wiki/Fungeoid) with many useful (and some not so useful) commands which make it comparably usable for a 2D language. To this end, depending on whether the instruction pointer moves orthogonally or diagonally, Alice operates either in an integer mode or in a string mode, which allows every operator to be overloaded with two different commands.
6 |
7 | ## Language concepts
8 |
9 | This section introduces some general concepts about Alice's programming model.
10 |
11 | One quick definition up front: Alice considers an integer value to be a *character* if it is in one of the inclusive ranges [0, 55295] or [57344, 1114111], which is the entire range of Unicode code points.
12 |
13 | ### Source code and grid
14 |
15 | The source file is assumed to be encoded as UTF-8 (as are the standard input and output strings of an Alice program). And linefeeds (0x0A) are considered to be the only line separators. If the lines aren't all of the same length, the shorter ones are padded on the right with spaces (0x20). If the file is empty it is treated as a file containing a single space.
16 |
17 | Each character is then converted to its Unicode code point and the resulting values are placed on an infinite 2D grid. The first character of the source file goes at coordinate **(0,0)**, the **x** coordinate increases along lines (to the right) and the **y** coordinate increases across lines (downwards). Any cells not covered by the (padded) source file are filled with `-1`.
18 |
19 | For example the following source file...
20 |
21 | ABC
22 | D
23 | EF
24 |
25 | ...would lead to the following initial grid:
26 |
27 | x ... -2 -1 0 1 2 3 4 ...
28 | y
29 | ...
30 | -2 -1 -1 -1 -1 -1 -1 -1
31 | -1 -1 -1 -1 -1 -1 -1 -1
32 | 0 -1 -1 65 66 67 -1 -1
33 | 1 -1 -1 68 32 32 -1 -1
34 | 2 -1 -1 69 70 32 -1 -1
35 | 3 -1 -1 -1 -1 -1 -1 -1
36 | 4 -1 -1 -1 -1 -1 -1 -1
37 | ...
38 |
39 | While it's possible to access the entire unbounded grid over the course of program execution, in the following *"the grid"* will refer to the smallest rectangle that contains all values which aren't `-1`. There will always be a finite number of such cells, so this is well-defined. However, the grid *may* grow or shrink during program execution if the grid values are modified such that the bounding box of non-`-1` cells changes.
40 |
41 | Characters and their character codes will be used interchangeably when it comes to cells in the remainder of this document. So a cell containing the value `65` might also be referred to as a cell containing `A`.
42 |
43 | There are a few different types of grid cells. Their exact meanings will be explained below, but we'll define them here:
44 |
45 | - **No-ops:** Spaces (0x20), backticks (`` ` ``, 0x60) and every value which is *not* in the printable ASCII range (0x20 to 0x7E) is considered a no-op. They generally don't do anything (except backticks) and are treated specially during movement.
46 | - **Geometry:** `_` and `|` are **walls** and `/` and `\` are **mirrors**. In particular, these are not considered to be commands (as in most other Fungeoids) but have a special status and are considered to be part of the "geometry" of the grid.
47 | - **Commands:** Every other printable ASCII character is considered to be a command. `'` and `"` have a somewhat special status among these, but we'll get to those when we talk about movement.
48 |
49 | ### Cardinal and Ordinal mode
50 |
51 | Alice's defining feature is that it can operate in two different modes:
52 |
53 | - If the instruction pointer is moving horizontally or vertically, Alice operates in **Cardinal mode**. In this mode, Alice treats all data as integers and can perform operations related to arithmetic, number theory, combinatorics etc.
54 | - If the instruction pointer is moving diagonally, Alice operates in **Ordinal mode**. In this mode, Alice treats all data as strings and can perform operations related to string processing, array manipulation and set theory (treating strings as lists or multisets of characters).
55 |
56 | Alice switches between the two modes by stepping through *mirrors* (of course). Consequently, the two modes were designed to feel somewhat like two parallel universes, where many things look and feel the same but are actually subtly (or not so subtly) different. Every command (except for some very basic stack manipulation) has two different meanings in the two modes, movement works somewhat differently and memory is interpreted in a different way.
57 |
58 | The parallels between Cardinal and Ordinal mode were designed with a few themes in mind. For example, Ordinal-mode commands which work with substrings are often paired with similar Cardinal-mode commands that work with divisors, bitwise commands are paired set-theoretic commands and so on.
59 |
60 | ### Memory model
61 |
62 | Alice's memory model spans three types of storage.
63 |
64 | #### Data types
65 |
66 | There are two data types in Alice: arbitrary-precision signed integers and strings. A string is simply a list of characters (as defined above).
67 |
68 | #### Grid
69 |
70 | We've already seen the grid as the way the source code is interpreted. However, the grid can be written to and read from (even outside of the bounds of the initial grid), which means that it doubles as memory storage. Each cell can hold a single integer.
71 |
72 | #### Stack
73 |
74 | As a stack-based language, Alice's primary memory storage is a single [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)). The stack can hold both integers and strings. However, Cardinal mode and Ordinal mode only know about one of these types. So when they try pop a value, Alice might implicitly convert the value to the appropriate type. The rules for this conversion are as follows.
75 |
76 | If a string is popped in Cardinal mode, Alice finds all integers in this string. Integers are substrings consisting only of ASCII digits, optionally prefixed by a `-`. However, if the `-` immediately follows an earlier integer, it is ignored. An example might help: in `ab12,-34cd`, Alice would find the integers `12` and `-34`. But in `ab12-34cd` it would find the integers `12` and `34` instead. All of these integers are pushed to the stack (from left to right), and then Alice tries to pop a value again. Note that if the string on top of the stack contains no integers, it will simply be discarded and Alice pops the next value instead (which may again be a string which would repeat the process).
77 |
78 | If Alice tries to pop from an empty stack in Cardinal mode, a zero is returned instead. Likewise, commands which work with the stack without popping treat it as if there as in infinite amount of zeros at the bottom.
79 |
80 | If an integer is popped in Ordinal mode, Alice simply converts that integer to its usual decimal string representation.
81 |
82 | If Alice tries to pop from an empty stack in Ordinal mode, an empty string is returned instead. Likewise, commands which work with the stack without popping treat it as if there as in infinite amount of empty strings at the bottom.
83 |
84 | Note that there are few stack manipulation commands which reorder the stack *without* popping any values. Consequently, these don't cause any type conversion. This will be pointed out explicitly in the command reference, where applicable.
85 |
86 | #### Tape
87 |
88 | As a secondary memory storage, Alice has an infinite tape of integers. As opposed to a tape-based language like [Brainfuck](http://esolangs.org/wiki/Brainfuck), Alice's tape is more used like an unlimited amount of registers. Data can be copied to and from the tape but cannot be manipulated directly on the tape. The tape is initially filled with the value `-1` in every cell.
89 |
90 | There are two independent tape heads (or memory pointers), one for Cardinal mode and one for Ordinal mode. When the current mode is clear from the context, the corresponding one will just be referred to as "the tape head". Initially, both tape heads point at the cell at index zero.
91 |
92 | Cardinal and Ordinal mode treat the data on the tape differently. Whereas Cardinal mode just considers each cell as a separate integer, Ordinal mode treats the tape as a tape of words.
93 |
94 | **Words** are defines as consecutive runs of cells that correspond to characters, terminated by a cell that *isn't* a character. Therefore negative values and values greater than **1114111** are considered word terminators. If there are two adjacent non-character cells, the latter represents an empty word.
95 |
96 | ### Additional state
97 |
98 | Apart from the the memory storages above, there are a few more pieces of program state in Alice, which are described in this section.
99 |
100 | #### Instruction pointer
101 |
102 | Control flow in Alice is governed by an instruction pointer (**IP**), which has a position on the grid as well as a direction. To avoid confusion with directions relative to the IP, we'll use *north* (**-y**), *east* (**+x**), *south* (**+y**) and *west* (**-x**) to refer to absolute directions on the grid.
103 |
104 | #### Return address stack
105 |
106 | Alice has an internal stack of grid coordinates which are used as return addresses. These allow you to implement reusable subroutines relatively conveniently. Note that all of this is only by convention. Alice has no concept of scope, and there is nothing stopping the IP from leaving a subroutine "on its own" without making use of the return address stack. The stack is merely a convenience so that the programmer does not have to keep track of where to resume execution of the code manually.
107 |
108 | The return address stack is initially empty and can hold pairs of integers, i.e. (x,y) coodinates on the grid. Note in particular that the return address stack stores no information about the IP's direction.
109 |
110 | If a command attempts to pop from this stack when it's empty, the current position of the IP will be returned instead (which essentially makes "return" commands on an empty stack no-ops).
111 |
112 | #### Iterator queue
113 |
114 | While normally each command in Alice is executed once when the IP passes over it, Alice has **iterators** which let you execute a command multiple times in a row.
115 |
116 | There is an internal [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)), which can hold integers and strings and which is initially empty. If the queue is empty, the default iterator is **1**. The detailed semantics of these iterators are explained below in the section on [executing commands](#commands).
117 |
118 | ### Movement
119 |
120 | The IP is initially at coordinate (-1,0), i.e. left of the first character of the program, moving east. Because the IP always moves before a command is executed, this effectively means the program starts at coordinate (0,0), as you'd expect.
121 |
122 | Alice is executed in "ticks" where each tick consists of a move, followed by executing a command. A move consists of one or more steps and essentially scans the grid for the next command in the direction of the IP. However, grid geometry (i.e. walls, mirrors or boundaries) may change the direction of the IP and even the mode while it moves.
123 |
124 | There is a special case if the IP is initially on a cell containing `'`. If this is the case, the IP will move one step, completely ignoring the contents of the next cell (whether they are no-op, geometry or command, even another `'`), before starting its usual scan for the next command. This is because `'` is an "escaping" command which also consumes the next cell.
125 |
126 | If the IP encounters the special command `"` on its search, it will activate **string mode**, which is described in more detail below. Activating string mode is not considered a command (although deactivating it is).
127 |
128 | #### No-ops
129 |
130 | The IP skips over all no-ops while it searches for the next command. However, there is one special no-op here: the backtick, `` ` ``. Whenever the IP passes over a backtick, Alice prints debug information about all relevant program state to the standard error stream. The exact representation is up to the interpreter, but it should contain all of Alice's state. Interpreters with interactive debuggers may instead choose to interpret backticks as breakpoints.
131 |
132 | #### Walls
133 |
134 | These are simplest: if the IP encounters `_` or `|` during a move, its direction gets reflected as you'd expect. In Cardinal mode, `_` is ignored for horizontal movement and `|` reverses the direction (and vice-versa for vertical movement). In Ordinal mode, they change the direction by 90 degrees, e.g. `_` changes southeast movement to northeast etc.
135 |
136 | #### Mirrors
137 |
138 | Mirrors, `/` and `\`, are a staple in 2D languages, but in Alice they work a bit differently than you probably expect. First of all, in Alice the IP moves *through* mirrors and doesn't get reflected at them. But secondly, Alice acknowledges that the characters `/` and `\` are rarely displayed at 45 degree angles, so having them cause 90 degree reflections is somewhat unfitting. The angles in many fonts are actually closer to 67.5 degrees, and therefore mirrors reflect between orthogonal and diagonal movement in Alice.
139 |
140 | Unfortunately, this may look slightly confusing in the source code at first, because most fonts (even monospaced ones) also don't have square character cells. Therefore, here are 16 diagrams which visualise every possible way the IP can enter a mirror:
141 |
142 | [![Movement through mirrors][mirrors]][mirrors]
143 | Click for larger version
144 |
145 | If this reflection seems weird (especially the acute-angled cases), imagine holding a long straight stick with one end to the surface of a mirror. The IP comes in along that stick and when it hits the surface of the mirror it goes "into" the mirror and continues along the reflection of the stick.
146 |
147 | Note that this always changes orthogonal movement to diagonal movement and vice versa. Therefore, mirrors always toggle between Cardinal mode and Ordinal mode, and they are also the *only* way in the language to switch between modes.
148 |
149 | [mirrors]: https://i.stack.imgur.com/YHx0d.png
150 |
151 | #### Boundaries
152 |
153 | While the IP is moving it may happen that it tries to move to a cell outside of the grid (i.e. beyond the bounding box of non-background cells in the unbounded grid).
154 |
155 | How Alice handles this situation depends on whether we are in Cardinal mode and Ordinal mode.
156 |
157 | Cardinal mode uses wrapping boundaries like many other Fungeoids. If the IP is out of bounds after a step, it moves to the beginning of the line (which may be a row or column) along which it is currently moving instead. Note that this means that if the IP moves alongside the grid (instead of away from it or towards it), it will be stuck outside the grid forever. This situation can be caused by some of the control flow commands, or if the grid shrinks while the IP moves along its edge.
158 |
159 | Ordinal mode uses solid boundaries instead, which act similarly to walls. If the IP would move out of bounds with the current step, its direction will instead be reflected on the boundary before taking the step. If the IP would move through a corner of the grid, its direction gets reversed.
160 |
161 | If the grid is only one cell tall or wide, it is not possible for the IP to take any diagonal steps so the IP will remain in place. If the current cell is a command, that command would get executed over and over again (but setting this up is quite non-trivial and should be considered a tremendous edge case). If the IP manages to end up out of bounds by more than one cell (which is also a very unlikely edge case), it will be stuck there forever.
162 |
163 | ### Commands
164 |
165 | Once movement ends and the IP has found a command, that command will be executed. When a command needs to be executed, Alice first dequeues an iterator from the iterator queue. Remember that if the queue is empty, the default iterator is **1** (which in effect means that the command is simply executed once as you'd expect).
166 |
167 | How the command is executed depends on the iterator:
168 |
169 | - **Repetition:** If the iterator is a positive integer **N**, the command is executed **N** times (without moving the IP in between, unless the command itself causes movement). For non-positive integers, the command isn't executed at all.
170 | - **Folding:** If the iterator is a string, Alice goes through each character in the string from left to right and then a) pushes that character to the stack and b) executes the current command once. Note that if the iterator is an empty string this also means that the command isn't executed at all.
171 |
172 | The iterator queue will normally contain at most one value, which lets you execute the next command multiple times. However, if that next command itself adds iterators to the queue, it's possible to have multiple iterators queued up at once.
173 |
174 | Some commands can put a **0** at the front of the queue (so it's not a strict queue), in order to skip the next command.
175 |
176 | ### String mode
177 |
178 | Finally, there is string mode, which can be entered and exited with the special `"` command. In string mode, Alice no longer executes any of the usual commands but instead remembers each cell value it passes over until string mode ends again. However, a few characters retain their special meaning:
179 |
180 | - `'` still escapes the next cell. The `'` itself is not added to the string, but the subsequent cell is, even if it's a special character.
181 | - Mirrors and walls (i.e. any of `/\_|`) still redirect the IP without being added to the string, unless they are escaped with `'`. In particular, this means that it's possible to switch between Cardinal and Ordinal mode while string mode is active.
182 | - `"` ends string mode (unless it's escaped) and processes the list of integers that has been recorded.
183 |
184 | Remember that entering string mode is not considered a command for the purpose of iterators, but leaving string mode is. The consequences are that leaving string mode dequeues an iterator (and therefore may process the string several times), and how the string is processed depends on whether we're in Cardinal or Ordinal mode at the time of leaving string mode.
185 |
186 | If string mode ends in Cardinal mode, the resulting command pushes each of the recorded integers once to the stack.
187 |
188 | If string mode ends in Ordinal mode, the resulting command discards all integers that aren't valid characters and pushes the remainder as a single string to the stack.
189 |
190 | ### Labels
191 |
192 | While Cardinal mode uses integer coordinate pairs to address cells in the grid (e.g. to manipulate the grid or for certain control flow commands), Ordinal mode has no concept of integers. Instead, Ordinal mode uses **labels** to refer to positions on the grid.
193 |
194 | A label is just a string that appears somewhere on the grid, but since Ordinal mode operates along diagonals, labels are also searched for along diagonals. When a command tries to find a certain label, it effectively rotates the grid by a multiple of 45 degrees so that the IP points east, and then searches for the label in normal (left-to-right, top-to-bottom) reading order. To make it explicit, the following four grids show in which order the grid is scanned depending on the IP's current direction:
195 |
196 | Direction: SE SW NW NE
197 |
198 | Scanning gdba pnkg jmop acfj
199 | order: khec olhd filn beim
200 | nlif mieb cehk dhlo
201 | pomj jfca abdg gknp
202 |
203 | Note that labels cannot span multiple lines. For example, it would not be possible to find the label `cde` in any of the above grids. Alice will only search the strings `a`, `bc`, `def`, `ghij`, `klm`, `no` and `p` for the label. Commands will either refer to the cell after the label (along its diagonal), or to the one directly before that (so in general, the end of the label is the relevant reference point). The exact usage of the label is described below for the relevant commands.
204 |
205 | ## Command reference
206 |
207 | This section lists all the commands available in Alice, roughly grouped into a few related categories. For the sake of completeness, the non-commands `` ` `` (which is a special no-op), `/\_|` (which are mirrors and walls) and the special commands `'` and `"` are listed here again, but remember that they are treated differently for the purposes of movement.
208 |
209 | If the reference says "Pop **n**" in Cardinal mode, **n** is always an integer. In Ordinal mode, it's always a string. See the section [on the stack](#stack) for details of potentially required type conversions. In general, **n** will be used as the variable of single integer parameters, and **x**, **y**, **z** if there are several. Similarly, **s** will be used for a single string parameter, and **a**, **b**, **c** if there are several. There are some exceptions, where other variables are more conventional, like using **n** and **k** in the context of combinatorics.
210 |
211 | When the reference refers to pushing individual characters to the stack, this refers to strings containing only that character.
212 |
213 | ### Debugging
214 |
215 | Cmd | Cardinal | Ordinal
216 | --- | -------- | -------
217 | `` ` `` | **Debug.** Special no-op: prints debug information to the standard error stream. | **Debug.** Same as Cardinal.
218 |
219 | ### Control flow
220 |
221 | Cmd | Cardinal | Ordinal
222 | --- | -------- | -------
223 | `@` | **End.** Terminate the program. | **End.** Terminate the program.
224 | `/` | **Mirror.** Reflect the IP through 67.5 degrees, switch between modes. See section [on mirrors](#mirrors) for details. | **Mirror.** Same as Cardinal.
225 | `\` | **Mirror.** Reflect the IP through -67.5 degrees, switch between modes. See section [on mirrors](#mirrors) for details. | **Mirror.** Same as Cardinal.
226 | `_` | **Wall.** Reflect the IP through 0 degrees. See section [on walls](#walls) for details. | **Wall.** Same as Cardinal.
227 | `\|` | **Wall.** Reflect the IP through 90 degrees. See section [on walls](#walls) for details. | **Wall.** Same as Cardinal.
228 | `<` | **Move west.** Set the IP direction to west. | **Half-wall west.** Set the horizontal component of the IP direction to west.
229 | `>` | **Move east.** Set the IP direction to east. | **Half-wall east.** Set the horizontal component of the IP direction to east.
230 | `^` | **Move north.** Set the IP direction to north. | **Half-wall north.** Set the vertical component of the IP direction to north.
231 | `v` | **Move south.** Set the IP direction to south. | **Half-wall south.** Set the vertical component of the IP direction to south.
232 | `{` | **Turn left.** Rotate the IP direction left by 90 degrees. | **Turn left.** Rotate the IP direction left by 90 degrees.
233 | `}` | **Turn right.** Rotate the IP direction right by 90 degrees. | **Turn right.** Rotate the IP direction right by 90 degrees.
234 | `=` | **Sign junction.** Pop **n**. Act like `{` if **n** is negative, like `}` if **n** is positive. Has no further effect if **n = 0**. | **Compare junction.** Pop **b**. Pop **a**. Act like `{` if **a < b**, act like `}` if **a > b**. Has no further effect if **a = b**. Comparisons are based on the lexicographic ordering of the strings.
235 | `#` | **Skip.** Skip the next command. This is implemented by adding a **0** to the *front* of the iterator queue. | **Skip.** Same as Cardinal. (Technically, this one uses **""** as the iterator, but **""** and **0** are functionally equivalent as iterators.)
236 | `$` | **Skip if 0.** Pop **n**. Act like `#` if **n = 0**, do nothing otherwise. | **Skip if empty.** Pop **s**. Act like `#` if **s = ""**, do nothing otherwise.
237 | `j` | **Jump.** Pop **y**. Pop **x**. Push the current IP address to the return address stack. Jump to **(x,y)**.\* | **Jump.** Pop **s**. Search the grid for the label **s**. If the label is not found, do nothing. Otherwise, push the current IP address to the return address stack and jump to the last cell of the label. See the section [on labels](#labels) for details.\*
238 | `J` | **Raw jump.** Same as `j`, but does not push the current IP to the return address stack.\* | **Raw jump.** Same as `j`, but does not push the current IP to the return address stack.\*
239 | `k` | **Return.** Pop an address from the return address stack and jump there.\* | **Return.** Same as Cardinal.
240 | `K` | **Raw return.** Peek at the top of the return address stack and jump there.\* | **Raw return.** Same as Cardinal.
241 | `w` | **Push return address.** Push the current IP address to the return address stack (without jumping anywhere). | **Push return address.** Same as Cardinal.
242 | `W` | **Discard return address.** Pop and discard the top of the return address stack. | **Discard return address.** Same as Cardinal.
243 | `&` | **Repeat.** Pop **n**. Add **n** to the iterator queue. | **Fold.** Pop **s**. Add **s** to the iterator queue.
244 |
245 | \* Remember that the IP will then move *before* the next command is executed.
246 |
247 | ### Literals and constants
248 |
249 | Cmd | Cardinal | Ordinal
250 | --- | -------- | -------
251 | `"` | **Toggle string mode.** Only exiting string mode is considered a command, and pushes all the recorded integers to the stack. See the section [on string mode](#string-mode) for details. | **Toggle string mode.** Only exiting string mode is considered a command, and pushes all recorded integers that are valid characters as a single string to the stack. See the section [on string mode](#string-mode) for details.
252 | `'` | **Escape.** Pushes the value of the next grid cell to the stack.† | **Escape.** If the next grid cell holds a valid character, that character is pushed to the stack. Otherwise, an empty string is pushed.†
253 | `0-9` | **Digit.** Pushes the corresponding digit to the stack. | **Digit.** Pop **s**. Append the corresponding digit as a character to **s** and push the result.
254 | `a` | **Ten.** Push **10**. | **Linefeed.** Push a single linefeed character (0x0A).
255 | `e` | **Minus one.** Push **-1**. | **Empty string.** Push **""**.
256 |
257 | † The next cell will be skipped by the subsequent move, but not as part of the command. This distinction is important when working with iterators.
258 |
259 | ### Input and output
260 |
261 | Cmd | Cardinal | Ordinal
262 | --- | -------- | -------
263 | `i` | **Read byte.** Read a single byte from the standard input stream and push it. Push `-1` at EOF instead. | **Read all.** Read the entire UTF-8-encoded standard input stream (until EOF is encountered) and push it as a single string.‡
264 | `I` | **Read character.** Read a single UTF-8-encoded character from the standard input stream and push its code point. Push `-1` at EOF instead.‡ | **Read line.** Read one UTF-8-encoded line from the standard input stream (i.e. up to the first linefeed, 0x0A) and push it as a single string. The linefeed is consumed but not included in the resulting string.‡
265 | `o` | **Write byte.** Pop **n**. Write its 8 least significant bits as a byte to the standard output stream. | **Write string.** Pop **s**. Write it as a UTF-8-encoded string to the standard output stream.
266 | `O` | **Write character.** Pop **n**. If **n** is a valid character, write it to the standard output stream using UTF-8 encoding. | **Write line.** Pop **s**. Write it as a UTF-8-encoded string to the standard output stream, followed by a linefeed (0x0A).
267 | `M` | **ARGC.** Push the number of remaining command-line arguments.§ | **ARGV.** Push the first unread command-line argument, or **""** if all arguments have been read.§ The arguments are assumed to be encoded in UTF-8. Any bytes that do not form a valid UTF-8 character will be skipped.
268 |
269 | ‡ This will skip any bytes that do not form a valid UTF-8 character.
270 | § These do not include any parts of the command that are necessary to invoke the program itself (including its file name).
271 |
272 | ### Grid manipulation
273 |
274 |
275 | Cmd | Cardinal | Ordinal
276 | --- | -------- | -------
277 | `g` | **Get cell.** Pop **y**. Pop **x**. Get the value in the grid cell at **(x,y)** and push it. | **Get diagonal.** Pop **s**. Scan the grid for the label **s**. If the label was found, start reading characters after the end of the label (along the same diagonal) until a non-character value is found. Push the string formed by those characters to the stack. See the section [on labels](#labels) for details.
278 | `p` | **Put cell.** Pop **y**. Pop **x**. Pop **v**. Set the value in the grid cell at **(x,y)** to **v**. | **Put diagonal.** Pop **s**. Pop **v**. Scan the grid for the label **s**. If it is found, write **v** onto the grid, one character per cell, starting at the cell after the label (on the same diagonal). If **v** is longer than the remainder of the diagonal, this will write over the edge of the grid and thereby extend the bounding box of the grid. See the section [on labels](#labels) for details.
279 |
280 | ### Stack manipulation
281 |
282 | Cmd | Cardinal | Ordinal
283 | --- | -------- | -------
284 | `,` | **Rotate stack.** Pop **n**. If **n** is positive, move the element which is **n** elements below the top to the top. If **n** is negative, move the top stack element down the stack by **n** positions. These operations do not pop and push elements and therefore don't convert any data types. | **Permute stack.** Pop **s**. Use as a permutation to reorder the stack. This is done by aligning the string character-by-character with the stack elements, so that the last element corresponds to the top of the stack (and the first character corresponds to the **n**th element from the top, where **n** is the length of **s**). Then the string is sorted stably, while keeping each stack element paired with its corresponding character. Hence, the stack elements perform the reordering that is required to sort **s**. The reordered stack elements are not popped in the process, so this does not convert any data types.
285 | `~` | **Swap.** Pop **y**. Pop **x**. Push **y**. Push **x**. | **Swap.** Pop **b**. Pop **a**. Push **b**. Push **a**.
286 | `.` | **Duplicate.** Pop **n**. Push **n** twice. | **Duplicate.** Pop **s**. Push **s** twice.
287 | `;` | **Discard.** Pop one integer and discard it. | **Discard.** Pop one string and discard it.
288 | `Q` | **Convert.** Pop **n**. Pop **n** values and push them again, so that their order *remains the same*. This can be used to force conversion of stack elements from the top such that there are at least **n** integers on top of the stack (as opposed to strings). | **Reverse stack.** Pop all stack elements and push them again, so that their order is *reversed*. This also forces conversion to strings, although there are no cases where an explicit conversion to strings can change the behaviour of a program.
289 | `d` | **Depth.** Push the number of elements currently in the stack (without popping or converting any of them). | **Join stack.** Make a copy of each stack element, convert it to a string, join them all together (so that the top element is at the end) and push the result. This does not affect any of the existing stack elements.
290 |
291 | ### Tape manipulation
292 |
293 | Cmd | Cardinal | Ordinal
294 | --- | -------- | -------
295 | `!` | **Store.** Pop **n**. Store it in the current tape cell. | **Store.** Pop **s**. Store it as a word on the tape. In particular, store its characters on the tape, starting at the position of the tape head and going right. The cell right after the end of **s** gets set to **-1** to ensure that there is a word terminator.
296 | `?` | **Load.** Push the value in the current tape cell to the stack. | **Load.** Read a word from the tape cell by taking the longest run of characters from the position of the tape head to the right and push it to the stack.
297 | `[` | **Move left.** Move the tape head one cell to the left. | **Move left.** Move the tape head one word to the left. Specifically, move the tape head left as long as that cell holds a character (to move the tape head to the beginning of the current word) — this part will usually be skipped. Then move it one more cell to the left (to move it onto the previous word terminator). Then move it left again as long as that cell holds a character (to move the tape head to the beginning of the previous word).
298 | `]` | **Move right.** Move the tape head one cell to the right. | **Move right.** Move the tape head one word to the right. Specifically, move the tape head right as long as the current cell holds a character (to move the tape head to the terminator of the current word). Then move it one more cell to the right (to move it onto the beginning of the next word).
299 | `(` | **Search left.** Pop **n**. Search for **n** left of the tape head (excluding the current cell itself). If it is found, move the tape head to the nearest occurrence. Note that **-1** can always be found in the infinite stretches of unwritten tape to either side of the modified part. | **Search left.** Pop **s**. Search for a word containing **s** as a substring left of the currently pointed to word (excluding that word itself). If such a word is found, move the tape head to its beginning.
300 | `)` | **Search right.** Pop **n**. Search for **n** right of the tape head (excluding the current cell itself). If it is found, move the tape head to the nearest occurrence. Note that **-1** can always be found in the infinite stretches of unwritten tape to either side of the modified part. | **Search right.** Pop **s**. Search for a word containing **s** as a substring right of the currently pointed to word (excluding that word itself). If such a word is found, move the tape head to its beginning.
301 | `q` | **Tape head.** Push the current *position* of the tape head. | **Join tape.** Join all words on the tape into a single string and push it.
302 |
303 | ### Basic arithmetic and string operations
304 |
305 | Cmd | Cardinal | Ordinal
306 | --- | -------- | -------
307 | `+` | **Add**. Pop **y**. Pop **x**. Push **x + y**. | **Superimpose.** Pop **b**. Pop **a**. Add null characters to the end of the shorter string until they are the same length. Then form a new string by taking the character with the larger code point at each position, and push that string.
308 | `-` | **Subtract.** Pop **y**. Pop **x**. Push **x - y**. | **Remove.** Pop **b**. Pop **a**. Remove all occurrences of **b** from **a** and push the result. If there are overlapping occurrences, the characters from all those occurrences will be removed (e.g. operands **"abcbcbd"** and **"bcb"** would yield **"ad"**).
309 | `*` | **Multiply.** Pop **y**. Pop **x**. Push **x * y**. | **Concatenate.** Pop **b**. Pop **a**. Push the concatenation of **a** and **b**.
310 | `:` | **Divide.** Pop **y**. Pop **x**. Push **x / y**. Results are rounded towards negative infinity. Terminates the program with an error if **y = 0**. | **Occurrences.** Pop **b**. Pop **a**. Push all *non-overlapping* occurrences of **b** in **a** (e.g. operands **"abcbcbcbd"** and **"bcb"** would push **"bcb"** only twice).
311 | `%` | **Modulo.** Pop **y**. Pop **x**. Push **x % y** (modulo). The sign of the result matches the sign of **y**, such that **(x / y) * y + x % y = x** is guaranteed. Terminates the program with an error if **y = 0**. | **Split.** Pop **b**. Pop **a**. Split **a** into chunks separated by occurrences of **b** and push those chunks.
312 | `E` | **Power/Root.** Pop **y**. Pop **x**. If **y** is non-negative, push **xy**. If **x = y = 0**, push **1**. If **y** is negative and **x** is non-negative, this computes **x1/-y**, rounded towards negative infinity. If both **x** and **y** are negative, this computes **-(-x)1/-y**, rounded towards negative infinity. | **Riffle.** Pop **b**. Pop **a**. Insert **b** between every pair of characters in **a** and push the result.
313 | `H` | **Abs.** Pop **n**. Push **\|n\|**. | **Trim.** Pop **s**. Remove all tabs (0x09), linefeeds (0x0A) and spaces (0x20) from both ends of the string.
314 | `R` | **Negate.** Pop **n**. Push **-n**. | **Reverse.** Pop **s**. Reverse **s** and push the result.
315 | `h` | **Increment.** Pop **n**. Push **n+1**. | **Head.** Pop **s**. Push the first character of **s**, then push the remainder of **s**. If **s == ""**, push **""** twice.
316 | `t` | **Decrement.** Pop **n**. Push **n-1**. | **Tail.** Pop **s**. Push the everything except the last character of **s**, then push the last character of **s**. If **s == ""**, push **""** twice.
317 | `m` | **Floor.** Pop **y**. Pop **x**. Push the greatest multiple of **y** which is not greater than **x**. | **Truncate.** Pop **b**. Pop **a**. Remove characters from the end of the longer string until they have the same length. Push **a**. Push **b**.
318 | `n` | **Logical Not.** Pop **y**. Push **1** if **y = 0**, push **0** otherwise. | **Logical Not.** Pop **s**. Push **"Jabberwocky"** if **s = ""**, push **""** otherwise.
319 | `Y` | **Unpack.** Pop **n**. Map **n** (bijectively) to two integers **x** and **y**. Push **x**. Push **y**. This is the inverse operation of `Z`. For details of the bijection, see the footnote.‖ | **Unzip.** Pop **s**. Create two empty strings **a** and **b**. Append the characters from **s** to **a** and **b** in an alternating manner, starting with **a**. Push **a**. Push **b**.
320 | `Z` | **Pack.** Pop **y**. Pop **x**. Map **x** and **y** (bijectively) to a single integer **n**. Push **n**. This is the inverse operation of `Y`. For details of the bijection, see the footnote.‖ | **Zip.** Pop **b**. Pop **a**. Interleave **a** and **b** by taking characters from then in an alternating manner, starting with **a**. If one string is shorter than the other, the remaining characters of the other one are simply appended. For example **a = "abc"** and **b = "012345"** will yield **"a0b1c2345"**. Push the result.
321 |
322 | ‖ The details of the bijection are likely irrelevant for most use cases. The main point is that it lets the user encode two integers in one and extract the two integers again later on. By applying the pack command repeatedly, entire lists or trees of integers can be stored in a single number (although not in a particularly memory-efficient way). The mapping computed by the pack operation is a bijective function **ℤ2 → ℤ** (i.e. a one-to-one mapping). First, the integers **{..., -2, -1, 0, 1, 2, ...}** are mapped to the natural numbers (including zero) like **{..., 3, 1, 0, 2, 4, ...}** (in other words, negative integers are mapped to odd naturals and non-negative integers are mapped to even naturals). The two natural numbers are then mapped to one via the [Cantor pairing function](https://en.wikipedia.org/wiki/Pairing_function), which writes the naturals along the diagonals of the first quadrant of the integer grid. Specifically, **{(0,0), (1,0), (0,1), (2,0), (1,1), (0,2), (3,0), ...}** are mapped to **{0, 1, 2, 3, 4, 5, 6, ...}**. The resulting natural number is then mapped back to the integers using the inverse of the earlier bijection. The unpack command computes exactly the inverse of this mapping.
323 |
324 | ### Bitwise arithmetic, multiset operations and character transformation
325 |
326 |
327 | Cmd | Cardinal | Ordinal
328 | --- | -------- | -------
329 | `A` | **And.** Pop **y**. Pop **x**. Push the bitwise *AND* of **x** and **y**. | **Intersection.** Pop **b**. Pop **a**. Compute the multiset intersection of **a** and **b** (accounting for multiplicities). Specifically, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists, and remove it from **a** otherwise. Push what remains of **a**.
330 | `N` | **Not.** Pop **n**. Push the bitwise *NOT* of **n**. Equivalent to **-n-1**. | **Complement.** Pop **b**. Pop **a**. Compute the multiset complement of **b** in **a**, or alternatively the multiset difference **b \ a** (accounting for multiplicities). Specifically, iterate through the characters of **b** and remove the leftmost copy of each character from **a** if it exists. Push what remains of **a**.
331 | `V` | **Or.** Pop **y**. Pop **x**. Push the bitwise *OR* of **x** and **y**. | **Union.** Pop **b**. Pop **a**. Compute the multiset union of **a** and **b** (accounting for multiplicities). Specifically, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists. Concatenate **a** and what remains of **b** and push the result.
332 | `X` | **Xor.** Pop **y**. Pop **x**. Push the bitwise *XOR* of **x** and **y**. | **Symmetric difference.** Pop **b**. Pop **a**. Compute the symmetric multiset difference of **a** and **b** (accounting for multiplicities). Specifically, make a copy of **b**, called **b'**, iterate through the characters of **a** and remove the leftmost copy of each character from **b** if it exists. Then iterate through **b'** and remove the leftmost copy of each character from **a** if it exists. Concatenate what remains of **a** and **b** and push the result.
333 | `y` | **If-then-else.** Pop **z**. Pop **y**. Pop **x**. Push the bitwise if-then-else of **x**, **y** and **z**. Specifically, push **(x AND y) OR (NOT x AND z)**. | **Transliterate.** Pop **c**. Pop **b**. Pop **a**. Transliterate **a** by mapping **b** to **c** and push the result. The details of this operation are somewhat involved and can be found in the footnote.¶
334 | `l` | **Clear lower bits.** Pop **n**. Set all of its bits except the most-significant bit to **0**. Push the result. | **Lower case.** Pop **s**. Convert letters in **s** to lower case. Whether and how this works for Unicode letters outside the ASCII range, and whether the user's locale is respected is implementation-defined.
335 | `u` | **Set lower bits.** Pop **n**. Set all of its bits except the most-significant bit to **1**. Push the result. | **Upper case.** Pop **s**. Convert letters in **s** to upper case. Whether and how this works for Unicode letters outside the ASCII range, and whether the user's locale is respected is implementation-defined.
336 |
337 | ¶ Here is how a transliteration is computed. If **c** is empty, remove all copies of the characters in **b** from **a**. Otherwise, repeat **b** often enough so that no character occurs more often in **a** than in **b**. Then repeat **c** often enough so that it is no shorter than **b**. Now create a mapping of each character in **b** to the character in the same position in **c**. Finally, go through the characters in **a**. If the character exists in **b**, replace it with a character from **c** using the leftmost mapping, and then remove that mapping (so that the next copy of this character uses the next mapping and so on). If the character did not exist in **b**, leave it unchanged in **a**. Here is an example: **a = "ABACABADA"**, **b = "ABCA"**, **c = "0123456"**. First, we need to repeat **b** three times so that it contains at least as many **"A"s** as **a**, so we get **b = "ABCAABCAABCA"**. Then we need to repeat **c** twice so that it's at least as long as **b**, so we get **c = "01234560123456"**. This creates the following list of mappings: **[A → 0, B → 1, C → 2, A → 3, A → 4, B → 5, C → 6, A → 0, A → 1, B → 2, C → 3, A → 4]**. Finally, we go through **a** and replace the **i**th occurrence of a character with the **i**th applicable mapping in this list, if it exists. So we end up with **"0132450D1"**. This operation may seem very weird, but it's mostly just a generalisation of several useful character transformation tasks. When both **b** and **c** are the same length, and the characters in **b** are unique, this simply performs a character-by-character transliteration as you might be familiar with from languages like Ruby or sed. To replace digits with their parity, you can use **b = "0123456789"**, **c = "01"**. To fill a string **c** character by character into gaps indicated by underscores in **a**, use **b = "\_"**.
338 |
339 | ### Number theory and advanced string operations
340 |
341 |
342 | Cmd | Cardinal | Ordinal
343 | --- | -------- | -------
344 | `B` | **Divisors.** Pop **n**. Push all divisors of **n**, in order from smallest to largest. If **n** is negative, all divisors will be pushed negatively as well (still ordered by their absolute magnitude). If **n = 0**, push nothing. | **Substrings.** Pop **s**. Push all non-empty contiguous substrings of **s**, from shortest to longest and from left to right.
345 | `D` | **Deduplicate prime factors.** Pop **n**. As long as **p2** divides **n** for some prime **p**, divide **n** by **p** (that is, remove all "extraneous" copies of prime factors), and push the result. If **n = 0**, push **0**. | **Deduplicate characters.** Pop **s**. For each character, discard all but its first occurrence in **s**. Push the result.
346 | `F` | **Divides.** Pop **y**. Pop **x**. If **y ≠ 0** and **y** divides **x**, push **y**. Otherwise, push **0**. | **Contains.** Pop **b**. Pop **a**. If **a** contains **b** as a substring, push **b**. Otherwise, push **""**.
347 | `G` | **GCD.** Pop **y**. Pop **x**. Push the greatest common divisor of **x** and **y**. If **x = y = 0**, push **0**. The result is always non-negative. | **LCS.** Pop **b**. Pop **a**. Push the longest substring that occurs in both **a** and **b**. If there are multiple common substrings of the maximal length, each such substring is pushed once (even if it appears multiple times), sorted by its first occurrence in **a**. Note that the empty string is always a common substring of **a** and **b**.
348 | `L` | **LCM.** Pop **y**. Pop **x**. Push the least common multiple of **x** and **y**. The result is always non-negative. | **SCS.** Pop **b**. Pop **a**. Push the shortest possible string which starts with **a** and ends with **b**.
349 | `S` | **Replace divisor.** Pop **z**. Pop **y**. Pop **x**. Determine how often **y** divides **x**, i.e. find the largest **n** for which **yn** divides **x**. Divide **x** by **yn** and then multiply it by **zn**. Push the result. There are several special cases: If **x = 0**, push **0**. If **y = z = ±1**, push **x**. If **y = ±1** and **z = 0**, push **0**. In all other cases, where **y = ±1**, enter an infinite loop. | **Replace substring.** Pop **c**. Pop **b**. Pop **a**. Replace each non-overlapping occurrence of **b** in **a** with **c**. Push the result.
350 | `c` | **Prime factors.** Pop **n**. Push the individual prime factors of **n** from smallest to largest (repeating each prime factor as necessary). Special cases: If **n = 0**, push **0**. If **n = 1**, push nothing. If **n < 0** push **-1** followed by the result for **-n**. | **Characters.** Pop **s**. Push the individual characters of **s** separately.
351 | `f` | **Prime-exponent pairs.** Pop **n**. Push the prime factors of **n** as pairs of prime and exponent. Special cases: if **n = 0**, push **0, 1**. If **n = 1**, push nothing. If **n < 0**, push **-1, 1** followed by the result for **-n**. | **Runs.** Pop **s**. Split **s** between any pair of different adjacent characters (or split **s** into runs of equal characters) and push the individual chunks. Do nothing if **s** is empty.
352 | `z` | **Drop small factors.** Pop **y**. Pop **x**. For each prime **p** less than or equal to **y**, divide **x** by **p** as long as possible and push the result. For **y < 0** also uses negative primes **p** so that the sign of **x** is flipped for each removed prime factor. If **x = 0**, push **0**. | **Drop.** Pop **b**. Pop **a**. If **a** contains **b** as a substring, discard everything in **a** up to and including the first occurrence of **b**. Push **a**.
353 |
354 | ### Combinatorics
355 |
356 | Cmd | Cardinal | Ordinal
357 | --- | -------- | -------
358 | `C` | **Binomial.** Pop **k**. Pop **n**. Push the binomial coefficient **n-choose-k**. Specifically, if **n > 0** and **k > n/2**, replace **k** with **n-k**. Then if **k < 0**, push **0**. If **k = 0**, push **1**. If **k > 0**, multiply the numbers from **n** down to **n-k+1** and divide them by the numbers from **1** to **k**. | **Subsequences.** Pop **s**. Push all (not necessarily contiguous) subsequences of **s** from shortest to longest. Each subsequence should be thought of as a subset of the positions in **s** that are retained, while all others are dropped. The order of subsequences for a given length are such that the corresponding lists of retained positions would be canonically ordered.
359 | `P` | **Factorial.** Pop **n**. Push **n!**. For negative **n**, multiplies the numbers from **n** up to **-1**, so that we get **(-n)!** for even **n** and **-(-n)!** for odd **n**. | **Permutations.** Pop **s**. Push all permutations of **s**, such that if each character was replaced by its index in **s**, the permutations would be canonically ordered. If **s** contains duplicate characters, there will be duplicate permutations.
360 |
361 | ### Order, randomness and time
362 |
363 | Cmd | Cardinal | Ordinal
364 | --- | -------- | -------
365 | `T` | **Sleep.** Pop **n**. Pause execution for **n** milliseconds. Does nothing if **n** is negative. | **Date and time.** Push the current date and time in the format **"YYYY-MM-DDTHH:MM:SS.mmm±AA:BB"** where **T** is an actual **"T"** and **±AA:BB** indicates the system's time zone.
366 | `U` | **Random integer.** Pop **n**. If **n > 0**, push a uniformly random integer in **[0,n)**. If **n < 0**, push a uniformly random integer in **(n,0]**. If **n = 0**, push **0**. | **Random choice.** Pop **s**. Push a character chosen randomly with uniform distribution from **s**. If **s** contains duplicate characters, these will have a higher probability of being drawn. If **s** is the empty string, push the empty string again.
367 | `b` | **Random swap.** Pop **y**. Pop **x**. With 50% probability, swap **x** and **y**. Push **x**, push **y**. | **Shuffle.** Pop **s**. Shuffle **s** with a uniform distribution of possible resulting strings. Push the result.
368 | `r` | **Range.** Pop **n**. If **n ≥ 0**, push all integers from **0** to **n**, inclusive. If **n < 0**, push all integers from **-n** to **0**, inclusive. | **Range expansion.** Pop **s**. First, reduce all consecutive runs of equal characters to a single copy of that character. Then, for each pair of adjacent characters **a** and **b**, insert all intermediate characters between them. Push the result. For example, **"aebbfbbbda"** becomes **"abcdedcbcdefedcbcdcba"**.
369 | `s` | **Sort swap.** Pop **y**. Pop **x**. If **x > y**, swap **x** and **y**. Push **x**, push **y**. | **Sort.** Pop **s**. Sort the characters in **s**. Push **s**.
370 | `x` | **Extract bit.** Pop **y**. Pop **x**. Extract the **y**th bit from the binary representation of **x**. If **y** is negative, return the **(m+y+1)**th bit, where **m** is the position of the most significant bit of **x**. For **x < -1**, the most-significant bit is the most-significant zero. For **x = -1**, or **x = 0**, **m = -1**. And if **-y > m+1**, this returns **0**. | **Permute string.** Pop **b**. Pop **a**. Reorder **a** according to **b**, similar to the `,` command. This is done by aligning the strings character-by-character. If **a** is shorter than **b**, the last characters of **b** are paired with empty strings. If **b** is shorter than **a**, the remaining characters in **a** will be unaffected. Then **b** is sorted stably, while keeping each of its characters paired with the corresponding character from **a**. Then join the characters (and possibly empty strings) from **a** back together and push the result. Hence, the characters in **a** are reordered by the same permutation that would sort **b**.
371 |
372 |
373 | ## Reference implementation
374 |
375 | This repository also contains a reference implementation of the language in Ruby.
376 |
377 | To run a program, simply invoke the interpreter with the source code's file name as a command-line argument, e.g.
378 |
379 | $ ruby ./interpreter.rb ./examples/hw.alice [args ...]
380 |
--------------------------------------------------------------------------------