esolang 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/esolang.rb +65 -0
- data/lib/interpreters/base_interpreter.rb +108 -0
- data/lib/interpreters/boolfuck_interpreter.rb +73 -0
- data/lib/interpreters/brainfuck_interpreter.rb +81 -0
- data/lib/interpreters/ook_interpreter.rb +70 -0
- data/lib/interpreters/paintfuck_interpreter.rb +102 -0
- data/lib/interpreters/smallfuck_interpreter.rb +57 -0
- data/lib/refinements/refinements.rb +58 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 48161d9cd63a90d101a9f5936464c053d2295b9ef7b500c95ad3cb2ff3049dc7
|
4
|
+
data.tar.gz: 4c570f8ff4b1de1c7c115572e1d3ab06a8d84015936a82ecfdcd98396b7fea24
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8777ec08eac7ae40588d31fb178b9ebee874f12fd9847eba36c52132312e9c96db43113e970fa0632be4c70bac9569b0d4bd6c5d96cd33093f1a5b3812e21bf9
|
7
|
+
data.tar.gz: e9033263c0ea899c52be1a33c968c2b3ca667bf3f6a35b14f70a6cb7e457b7a0e95e018b6cda2beed83b198f743adf735bde5bd0cb6742d367d2adbf10eead89
|
data/lib/esolang.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../lib/interpreters/boolfuck_interpreter.rb'
|
4
|
+
require_relative '../lib/interpreters/smallfuck_interpreter.rb'
|
5
|
+
require_relative '../lib/interpreters/paintfuck_interpreter.rb'
|
6
|
+
require_relative '../lib/interpreters/brainfuck_interpreter.rb'
|
7
|
+
require_relative '../lib/interpreters/ook_interpreter.rb'
|
8
|
+
|
9
|
+
require_relative '../lib/refinements/refinements.rb'
|
10
|
+
|
11
|
+
# The Esolang module provides methods to interpret esoteric programming languages.
|
12
|
+
#
|
13
|
+
# To use it you need to:
|
14
|
+
#
|
15
|
+
# ```ruby
|
16
|
+
# using Esolang::Refinements
|
17
|
+
# ```
|
18
|
+
module Esolang
|
19
|
+
# Interprets Boolfuck code.
|
20
|
+
#
|
21
|
+
# @param code [String] The Boolfuck code to interpret.
|
22
|
+
# @param input [String] The input for the Boolfuck program (optional).
|
23
|
+
# @return [String] The result of the Boolfuck interpretation.
|
24
|
+
def self.boolfuck(code, input = '')
|
25
|
+
Interpreters::Boolfuck.new(code, input).run
|
26
|
+
end
|
27
|
+
|
28
|
+
# Interprets Smallfuck code.
|
29
|
+
#
|
30
|
+
# @param code [String] The Smallfuck code to interpret.
|
31
|
+
# @param tape [String] The initial tape state for the Smallfuck program.
|
32
|
+
# @return [String] The result of the Smallfuck interpretation.
|
33
|
+
def self.smallfuck(code, tape)
|
34
|
+
Interpreters::Smallfuck.new(code, tape).run
|
35
|
+
end
|
36
|
+
|
37
|
+
# Interprets Paintfuck code.
|
38
|
+
#
|
39
|
+
# @param code [String] The Paintfuck code to interpret.
|
40
|
+
# @param iterations [Integer] The number of iterations for the Paintfuck program.
|
41
|
+
# @param width [Integer] The width of the Paintfuck canvas.
|
42
|
+
# @param height [Integer] The height of the Paintfuck canvas.
|
43
|
+
# @return [String] The result of the Paintfuck interpretation.
|
44
|
+
def self.paintfuck(code, iterations, width, height)
|
45
|
+
Interpreters::Paintfuck.new(code, iterations, width, height).run
|
46
|
+
end
|
47
|
+
|
48
|
+
# Interprets Brainfuck code.
|
49
|
+
#
|
50
|
+
# @param code [String] The Brainfuck code to interpret.
|
51
|
+
# @param input [String] The input for the Brainfuck program (optional).
|
52
|
+
# @return [String] The result of the Brainfuck interpretation.
|
53
|
+
def self.brainfuck(code, input = '')
|
54
|
+
Interpreters::Brainfuck.new(code, input).run
|
55
|
+
end
|
56
|
+
|
57
|
+
# Interprets Ook! code.
|
58
|
+
#
|
59
|
+
# @param code [String] The Ook! code to interpret.
|
60
|
+
# @param input [String] The input for the Ook! program (optional).
|
61
|
+
# @return [String] The result of the Ook! interpretation.
|
62
|
+
def self.ook(code, input = '')
|
63
|
+
Interpreters::Ook.new(code, input).run
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esolang
|
4
|
+
module Interpreters
|
5
|
+
# The BaseInterpreter class provides a common interface and basic functionality for
|
6
|
+
# interpreting esoteric programming languages.
|
7
|
+
class BaseInterpreter
|
8
|
+
# Initializes a new instance of the BaseInterpreter class.
|
9
|
+
#
|
10
|
+
# @param code [String] The code to interpret.
|
11
|
+
def initialize(code)
|
12
|
+
@code = code.chars
|
13
|
+
@code_pointer = 0
|
14
|
+
@loop_map = create_loop_map
|
15
|
+
@tape_pointer = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
# Executes the interpretation of the code. Subclasses must implement this method.
|
19
|
+
#
|
20
|
+
# @abstract Subclasses must implement the run method.
|
21
|
+
# @raise [NotImplementedError] Raised if the method is not implemented by subclasses.
|
22
|
+
def run
|
23
|
+
raise NotImplementedError, 'Subclasses must implement the run method'
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Moves the tape pointer to the right.
|
29
|
+
def move_right
|
30
|
+
@tape_pointer += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
# Moves the tape pointer to the left.
|
34
|
+
def move_left
|
35
|
+
@tape_pointer -= 1
|
36
|
+
end
|
37
|
+
|
38
|
+
# Reads input and writes it to the tape.
|
39
|
+
def input_to_tape
|
40
|
+
@input.empty? ? current_bit(0) : current_bit(@input.shift)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Reads the tape and appends the current bit to the output array.
|
44
|
+
def tape_to_output_array
|
45
|
+
@output << current_bit
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a map of loop indices for efficient loop navigation.
|
49
|
+
def create_loop_map
|
50
|
+
map = {}
|
51
|
+
stack = []
|
52
|
+
|
53
|
+
@code.each_with_index do |command, index|
|
54
|
+
case command
|
55
|
+
when '[' then stack << index
|
56
|
+
when ']'
|
57
|
+
if stack.empty?
|
58
|
+
raise StandardError, "Invalid code: No matching '[' for ']' at index #{index}"
|
59
|
+
else
|
60
|
+
map[stack.pop] = index
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
raise StandardError, "Invalid code: No matching ']' for '[' at index #{stack.last}" unless stack.empty?
|
66
|
+
|
67
|
+
map
|
68
|
+
end
|
69
|
+
|
70
|
+
# Jumps to the matching ']' if the current bit is zero.
|
71
|
+
def loop_begin
|
72
|
+
return unless current_bit.zero?
|
73
|
+
|
74
|
+
@code_pointer = @loop_map[@code_pointer]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Jumps back to the matching '[' if the current bit is non-zero.
|
78
|
+
def loop_end
|
79
|
+
return if current_bit.zero?
|
80
|
+
|
81
|
+
@code_pointer = @loop_map.key(@code_pointer)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Flips the current bit.
|
85
|
+
def flip
|
86
|
+
current_bit(current_bit ^ 1)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Retrieves the value of the current bit. Subclasses must implement this method.
|
90
|
+
#
|
91
|
+
# @abstract Subclasses must implement the current_bit method.
|
92
|
+
# @raise [NotImplementedError] Raised if the method is not implemented by subclasses.
|
93
|
+
def current_bit
|
94
|
+
raise NotImplementedError, 'Subclasses must implement the current_bit method'
|
95
|
+
end
|
96
|
+
|
97
|
+
# Checks if the interpreter is still running (code execution is not completed).
|
98
|
+
def running?
|
99
|
+
@code_pointer < @code.length
|
100
|
+
end
|
101
|
+
|
102
|
+
# Retrieves the current command in the code.
|
103
|
+
def command
|
104
|
+
@code[@code_pointer]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_interpreter'
|
4
|
+
|
5
|
+
module Esolang
|
6
|
+
module Interpreters
|
7
|
+
# The Boolfuck class represents an interpreter for the Boolfuck esoteric programming language.
|
8
|
+
class Boolfuck < BaseInterpreter
|
9
|
+
# Initializes a new instance of the Boolfuck interpreter.
|
10
|
+
#
|
11
|
+
# @param code [String] The Boolfuck code to interpret.
|
12
|
+
# @param input [String] The input for the Boolfuck program (optional).
|
13
|
+
def initialize(code, input = '')
|
14
|
+
super(code.gsub(/[^,\.;<>\+\[\]]/, ''))
|
15
|
+
@input = chars_to_bits(input)
|
16
|
+
@output = []
|
17
|
+
@tape = Hash.new(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Executes the interpretation of the Boolfuck code.
|
21
|
+
#
|
22
|
+
# @return [String] The result of the Boolfuck interpretation.
|
23
|
+
def run
|
24
|
+
while running? do
|
25
|
+
case command
|
26
|
+
when ',' then input_to_tape
|
27
|
+
when ';' then tape_to_output_array
|
28
|
+
when '>' then move_right
|
29
|
+
when '<' then move_left
|
30
|
+
when '+' then flip
|
31
|
+
when '[' then loop_begin
|
32
|
+
when ']' then loop_end
|
33
|
+
end
|
34
|
+
|
35
|
+
@code_pointer += 1
|
36
|
+
end
|
37
|
+
|
38
|
+
translate_output_bits_to_chars
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Converts characters to bits (0 or 1).
|
44
|
+
#
|
45
|
+
# @param chars [String] The characters to convert.
|
46
|
+
# @return [Array<Integer>] The array of bits.
|
47
|
+
def chars_to_bits(chars)
|
48
|
+
chars.chars.map { |char| [char.ord].pack("C*").unpack("b*")[0] }.join.chars.map(&:to_i)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Retrieves or updates the value of the current bit on the tape.
|
52
|
+
#
|
53
|
+
# @param new_value [Integer] The new value for the current bit (optional).
|
54
|
+
# @return [Integer] The value of the current bit.
|
55
|
+
def current_bit(new_value = nil)
|
56
|
+
@tape[@tape_pointer] = new_value unless new_value.nil?
|
57
|
+
|
58
|
+
@tape[@tape_pointer]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Translates the bits in the output array to characters.
|
62
|
+
#
|
63
|
+
# @return [String] The translated characters.
|
64
|
+
def translate_output_bits_to_chars
|
65
|
+
zeros_count_to_fill = (@output.length % 8).zero? ? 0 : 8 - (@output.length % 8)
|
66
|
+
|
67
|
+
@output.fill(0, @output.length, zeros_count_to_fill).each_slice(8).map do |byte|
|
68
|
+
byte.join.reverse.to_i(2).chr
|
69
|
+
end.join
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_interpreter'
|
4
|
+
|
5
|
+
module Esolang
|
6
|
+
module Interpreters
|
7
|
+
# The Brainfuck class represents an interpreter for the Brainfuck esoteric programming language.
|
8
|
+
class Brainfuck < BaseInterpreter
|
9
|
+
# Initializes a new instance of the Brainfuck interpreter.
|
10
|
+
#
|
11
|
+
# @param code [String] The Brainfuck code to interpret.
|
12
|
+
# @param input [String] The input for the Brainfuck program (optional).
|
13
|
+
def initialize(code, input = '')
|
14
|
+
# Added ? to valid chars for compatibility with Ook! But don't parse ? in Brainfuck
|
15
|
+
super(code.gsub(/[^\?,\.<>\+-\[\]]/, ''))
|
16
|
+
@input = chars_to_bytes(input)
|
17
|
+
@output = []
|
18
|
+
@tape = Hash.new(0)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Executes the interpretation of the Brainfuck code.
|
22
|
+
#
|
23
|
+
# @return [String] The result of the Brainfuck interpretation.
|
24
|
+
def run
|
25
|
+
while running? do
|
26
|
+
case command
|
27
|
+
when ',' then input_to_tape
|
28
|
+
when '.' then tape_to_output_array
|
29
|
+
when '>' then move_right
|
30
|
+
when '<' then move_left
|
31
|
+
when '+' then increment
|
32
|
+
when '-' then decrement
|
33
|
+
when '[' then loop_begin
|
34
|
+
when ']' then loop_end
|
35
|
+
end
|
36
|
+
|
37
|
+
@code_pointer += 1
|
38
|
+
end
|
39
|
+
|
40
|
+
translate_output_bytes_to_chars
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Increments the value of the current bit on the tape.
|
46
|
+
def increment
|
47
|
+
current_bit((current_bit + 1) % 256)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Decrements the value of the current bit on the tape.
|
51
|
+
def decrement
|
52
|
+
current_bit((current_bit - 1) % 256)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Converts characters to byte values.
|
56
|
+
#
|
57
|
+
# @param chars [String] The characters to convert.
|
58
|
+
# @return [Array<Integer>] The array of byte values.
|
59
|
+
def chars_to_bytes(chars)
|
60
|
+
chars.chars.map { |char| char.ord }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Retrieves or updates the value of the current bit on the tape.
|
64
|
+
#
|
65
|
+
# @param new_value [Integer] The new value for the current bit (optional).
|
66
|
+
# @return [Integer] The value of the current bit.
|
67
|
+
def current_bit(new_value = nil)
|
68
|
+
@tape[@tape_pointer] = new_value unless new_value.nil?
|
69
|
+
|
70
|
+
@tape[@tape_pointer]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Translates the byte values in the output array to characters.
|
74
|
+
#
|
75
|
+
# @return [String] The translated characters.
|
76
|
+
def translate_output_bytes_to_chars
|
77
|
+
@output.map { |char| char.chr }.join
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'brainfuck_interpreter'
|
4
|
+
|
5
|
+
module Esolang
|
6
|
+
module Interpreters
|
7
|
+
# The Ook class represents an interpreter for the Ook! esoteric programming language,
|
8
|
+
# which is translated to Brainfuck for execution.
|
9
|
+
class Ook < Brainfuck
|
10
|
+
# Initializes a new instance of the Ook interpreter.
|
11
|
+
#
|
12
|
+
# @param code [String] The Ook code to interpret.
|
13
|
+
# @param input [String] The input for the Ook program (optional).
|
14
|
+
def initialize(code, input = '')
|
15
|
+
super(translate_to_brainfuck(code), input)
|
16
|
+
@input = input
|
17
|
+
end
|
18
|
+
|
19
|
+
# Executes the interpretation of the Ook code.
|
20
|
+
#
|
21
|
+
# @return [String] The result of the Ook interpretation.
|
22
|
+
def run
|
23
|
+
while running? do
|
24
|
+
case command
|
25
|
+
when ',' then input_to_tape
|
26
|
+
when '.' then tape_to_output_array
|
27
|
+
when '>' then move_right
|
28
|
+
when '<' then move_left
|
29
|
+
when '+' then increment
|
30
|
+
when '-' then decrement
|
31
|
+
when '[' then loop_begin
|
32
|
+
when ']' then loop_end
|
33
|
+
when '?' then banana
|
34
|
+
end
|
35
|
+
|
36
|
+
@code_pointer += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
translate_output_bytes_to_chars
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Translates Ook! code to Brainfuck code.
|
45
|
+
#
|
46
|
+
# @param code [String] The Ook code to translate.
|
47
|
+
# @return [String] The translated Brainfuck code.
|
48
|
+
def translate_to_brainfuck(code)
|
49
|
+
code.gsub(/[^\.\!\?]/, '').chars.each_slice(2).map do |command|
|
50
|
+
case command.join
|
51
|
+
when ".?" then ">"
|
52
|
+
when "?." then "<"
|
53
|
+
when ".." then "+"
|
54
|
+
when "!!" then "-"
|
55
|
+
when "!." then "."
|
56
|
+
when ".!" then ","
|
57
|
+
when "!?" then "["
|
58
|
+
when "?!" then "]"
|
59
|
+
when "??" then "?"
|
60
|
+
end
|
61
|
+
end.join
|
62
|
+
end
|
63
|
+
|
64
|
+
# Prints a message indicating that the memory pointer got a banana.
|
65
|
+
def banana
|
66
|
+
puts "The memory pointer got a banana"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_interpreter'
|
4
|
+
|
5
|
+
module Esolang
|
6
|
+
module Interpreters
|
7
|
+
# The Paintfuck class represents an interpreter for the Paintfuck esoteric programming language.
|
8
|
+
class Paintfuck < BaseInterpreter
|
9
|
+
# Initializes a new instance of the Paintfuck interpreter.
|
10
|
+
#
|
11
|
+
# @param code [String] The Paintfuck code to interpret.
|
12
|
+
# @param iterations [Integer] The number of iterations for the Paintfuck program.
|
13
|
+
# @param width [Integer] The width of the Paintfuck canvas.
|
14
|
+
# @param height [Integer] The height of the Paintfuck canvas.
|
15
|
+
def initialize(code, iterations, width, height)
|
16
|
+
super(code.gsub(/[^nesw\*\[\]]/, ''))
|
17
|
+
@iterations = iterations
|
18
|
+
@width = width
|
19
|
+
@height = height
|
20
|
+
@data_grid = generate_zero_grid
|
21
|
+
@grid_pointer = [0, 0]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Executes the interpretation of the Paintfuck code.
|
25
|
+
#
|
26
|
+
# @return [String] The result of the Paintfuck interpretation.
|
27
|
+
def run
|
28
|
+
while running? do
|
29
|
+
case command
|
30
|
+
when 'n' then move_up
|
31
|
+
when 'e' then move_right
|
32
|
+
when 's' then move_down
|
33
|
+
when 'w' then move_left
|
34
|
+
when '*' then flip
|
35
|
+
when '[' then loop_begin
|
36
|
+
when ']' then loop_end
|
37
|
+
end
|
38
|
+
|
39
|
+
@code_pointer += 1
|
40
|
+
@iterations -= 1
|
41
|
+
end
|
42
|
+
|
43
|
+
output
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Moves the grid pointer up.
|
49
|
+
def move_up
|
50
|
+
@grid_pointer[0] = (@grid_pointer.first - 1 + @height) % @height
|
51
|
+
end
|
52
|
+
|
53
|
+
# Moves the grid pointer down.
|
54
|
+
def move_down
|
55
|
+
@grid_pointer[0] = (@grid_pointer.first + 1 + @height) % @height
|
56
|
+
end
|
57
|
+
|
58
|
+
# Moves the grid pointer right.
|
59
|
+
def move_right
|
60
|
+
@grid_pointer[1] = (@grid_pointer.last + 1 + @width) % @width
|
61
|
+
end
|
62
|
+
|
63
|
+
# Moves the grid pointer left.
|
64
|
+
def move_left
|
65
|
+
@grid_pointer[1] = (@grid_pointer.last - 1 + @width) % @width
|
66
|
+
end
|
67
|
+
|
68
|
+
# Retrieves or updates the value of the current bit on the Paintfuck canvas.
|
69
|
+
#
|
70
|
+
# @param new_value [Integer] The new value for the current bit (optional).
|
71
|
+
# @return [Integer] The value of the current bit.
|
72
|
+
def current_bit(new_value = nil)
|
73
|
+
@data_grid[@grid_pointer.first][@grid_pointer.last] = new_value unless new_value.nil?
|
74
|
+
|
75
|
+
@data_grid[@grid_pointer.first][@grid_pointer.last]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Retrieves the output of the Paintfuck program.
|
79
|
+
#
|
80
|
+
# @return [String] The Paintfuck canvas as a string.
|
81
|
+
def output
|
82
|
+
@data_grid
|
83
|
+
.map { |row| row.join }
|
84
|
+
.join("\r\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
# Generates a canvas grid filled with zeros.
|
88
|
+
#
|
89
|
+
# @return [Array<Array<Integer>>] The zero-filled grid.
|
90
|
+
def generate_zero_grid
|
91
|
+
(1..@height).map { [0] * @width }
|
92
|
+
end
|
93
|
+
|
94
|
+
# Checks if the interpreter is still running (code execution is not completed).
|
95
|
+
#
|
96
|
+
# @return [Boolean] Returns true if the interpreter is still running, otherwise false.
|
97
|
+
def running?
|
98
|
+
@iterations.positive? && super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_interpreter'
|
4
|
+
|
5
|
+
module Esolang
|
6
|
+
module Interpreters
|
7
|
+
# The Smallfuck class represents an interpreter for the Smallfuck esoteric programming language.
|
8
|
+
class Smallfuck < BaseInterpreter
|
9
|
+
# Initializes a new instance of the Smallfuck interpreter.
|
10
|
+
#
|
11
|
+
# @param code [String] The Smallfuck code to interpret.
|
12
|
+
# @param tape [String] The initial tape state for the Smallfuck program.
|
13
|
+
def initialize(code, tape)
|
14
|
+
super(code.gsub(/[^<>\*\[\]]/, ''))
|
15
|
+
@tape = tape.chars.map(&:to_i)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Executes the interpretation of the Smallfuck code.
|
19
|
+
#
|
20
|
+
# @return [String] The result of the Smallfuck interpretation.
|
21
|
+
def run
|
22
|
+
while running? do
|
23
|
+
case command
|
24
|
+
when '>' then move_right
|
25
|
+
when '<' then move_left
|
26
|
+
when '*' then flip
|
27
|
+
when '[' then loop_begin
|
28
|
+
when ']' then loop_end
|
29
|
+
end
|
30
|
+
@code_pointer += 1
|
31
|
+
end
|
32
|
+
@tape.join
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Checks if the interpreter is still running (code execution is not completed).
|
38
|
+
#
|
39
|
+
# @return [Boolean] Returns true if the interpreter is still running, otherwise false.
|
40
|
+
def running?
|
41
|
+
@tape_pointer < @tape.length &&
|
42
|
+
@tape_pointer >= 0 &&
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
# Retrieves or updates the value of the current bit on the tape.
|
47
|
+
#
|
48
|
+
# @param new_value [Integer] The new value for the current bit (optional).
|
49
|
+
# @return [Integer] The value of the current bit.
|
50
|
+
def current_bit(new_value = nil)
|
51
|
+
@tape[@tape_pointer] = new_value unless new_value.nil?
|
52
|
+
|
53
|
+
@tape[@tape_pointer]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esolang
|
4
|
+
# The Refinements module provides refinements for String class to enable
|
5
|
+
# direct interpretation of esoteric programming languages.
|
6
|
+
#
|
7
|
+
# To use these refinements, you need to include them using the `using` keyword:
|
8
|
+
#
|
9
|
+
# ```ruby
|
10
|
+
# require 'esolang'
|
11
|
+
# ```
|
12
|
+
module Refinements
|
13
|
+
# Refines the String class to provide a convenient method for interpreting Boolfuck code.
|
14
|
+
refine String do
|
15
|
+
# Interprets Boolfuck code directly on a String.
|
16
|
+
#
|
17
|
+
# @param input [String] The input for the Boolfuck program (optional).
|
18
|
+
# @return [String] The result of the Boolfuck interpretation.
|
19
|
+
def boolfuck(input = '')
|
20
|
+
Esolang::Interpreters::Boolfuck.new(self, input).run
|
21
|
+
end
|
22
|
+
|
23
|
+
# Interprets Smallfuck code directly on a String.
|
24
|
+
#
|
25
|
+
# @param tape [String] The initial tape state for the Smallfuck program.
|
26
|
+
# @return [String] The result of the Smallfuck interpretation.
|
27
|
+
def smallfuck(tape)
|
28
|
+
Esolang::Interpreters::Smallfuck.new(self, tape).run
|
29
|
+
end
|
30
|
+
|
31
|
+
# Interprets Paintfuck code directly on a String.
|
32
|
+
#
|
33
|
+
# @param iterations [Integer] The number of iterations for the Paintfuck program.
|
34
|
+
# @param width [Integer] The width of the Paintfuck canvas.
|
35
|
+
# @param height [Integer] The height of the Paintfuck canvas.
|
36
|
+
# @return [String] The result of the Paintfuck interpretation.
|
37
|
+
def paintfuck(iterations, width, height)
|
38
|
+
Esolang::Interpreters::Paintfuck.new(self, iterations, width, height).run
|
39
|
+
end
|
40
|
+
|
41
|
+
# Interprets Brainfuck code directly on a String.
|
42
|
+
#
|
43
|
+
# @param input [String] The input for the Brainfuck program (optional).
|
44
|
+
# @return [String] The result of the Brainfuck interpretation.
|
45
|
+
def brainfuck(input = '')
|
46
|
+
Esolang::Interpreters::Brainfuck.new(self, input).run
|
47
|
+
end
|
48
|
+
|
49
|
+
# Interprets Ook! code directly on a String.
|
50
|
+
#
|
51
|
+
# @param input [String] The input for the Ook! program (optional).
|
52
|
+
# @return [String] The result of the Ook! interpretation.
|
53
|
+
def ook(input = '')
|
54
|
+
Esolang::Interpreters::Ook.new(self, input).run
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: esolang
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Kipp
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |-
|
14
|
+
A gem for working with esoteric programming languages.
|
15
|
+
Usage: require 'esolang'; using Esolang::Refinements
|
16
|
+
Adds string refinements, usage: e.g. 'code_string'.boolfuck('user_input'). Alternative usage: e.g. Esolang.boolfuck(code, input)
|
17
|
+
email:
|
18
|
+
- daniel.kipp@gmail.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/esolang.rb
|
24
|
+
- lib/interpreters/base_interpreter.rb
|
25
|
+
- lib/interpreters/boolfuck_interpreter.rb
|
26
|
+
- lib/interpreters/brainfuck_interpreter.rb
|
27
|
+
- lib/interpreters/ook_interpreter.rb
|
28
|
+
- lib/interpreters/paintfuck_interpreter.rb
|
29
|
+
- lib/interpreters/smallfuck_interpreter.rb
|
30
|
+
- lib/refinements/refinements.rb
|
31
|
+
homepage:
|
32
|
+
licenses:
|
33
|
+
- MIT
|
34
|
+
metadata: {}
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubygems_version: 3.3.7
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: Interpreter gem for different Esolangs
|
54
|
+
test_files: []
|