rpxem 0.0.2 → 0.0.7
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/.github/workflows/rspec.yml +15 -0
- data/.travis.yml +15 -0
- data/MIT-LICENSE.txt +2 -2
- data/README.md +13 -5
- data/Rakefile +4 -10
- data/bin/rpxem +14 -14
- data/lib/rpxem.rb +20 -20
- data/lib/rpxem/interpreter.rb +229 -232
- data/lib/rpxem/stack.rb +47 -47
- data/lib/rpxem/version.rb +1 -1
- data/rpxem.gemspec +14 -9
- data/spec/rpxem_helper.rb +13 -13
- data/spec/rpxem_spec.rb +201 -196
- metadata +45 -37
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c58c71a092aa80e4df9b4f619c9c452067e687a06ced3bc5e5791cecb3a2667f
|
4
|
+
data.tar.gz: 372a4a2e91c31414dd4f2b1b112b071430639dbf7428d89f7d1314e8b0ac03a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 65cb700a60db4f36fd91ee5b3c225d3d875360d471ceb743b4adb232a8a8a9959eaaf27123cb0fe603bd9c77f97f92ca4a1c0a2bf4c849ab4d7afba54b156ac6
|
7
|
+
data.tar.gz: 52deace08db6bd44366c50c1c0eebacc8f023a8d95648273c5b5bc2604e6ef73c322dc4a2874aae76aa09ef88801b4e2889e47583ced9d268d81ccc687c95822
|
data/.travis.yml
ADDED
data/MIT-LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2012 wktk
|
1
|
+
Copyright (c) 2012, 2018 wktk
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# RPxem
|
2
2
|
|
3
|
-
[](https://travis-ci.org/wktk/rpxem)
|
4
4
|
|
5
|
-
RPxem is a Ruby implementation of [Pxem],
|
5
|
+
RPxem is a Ruby implementation of [Pxem], an esoteric programming language that
|
6
6
|
enables you to create programs in 0-byte files.
|
7
|
-
|
7
|
+
|
8
|
+
[Pxem]: https://web.archive.org/web/20120605223423/http://cfs.maxn.jp/neta/pxem.php
|
8
9
|
|
9
10
|
## Installation
|
10
11
|
|
@@ -71,5 +72,12 @@ Hello, world!
|
|
71
72
|
|
72
73
|
## License
|
73
74
|
|
74
|
-
Copyright (c) 2012 wktk.
|
75
|
-
MIT License.
|
75
|
+
Copyright (c) 2012, 2018 wktk.
|
76
|
+
This software is distributed under the MIT License.
|
77
|
+
See `MIT-LICENSE.txt` for details.
|
78
|
+
|
79
|
+
|
80
|
+
## See also
|
81
|
+
|
82
|
+
- Original resource: https://web.archive.org/web/20120605223423/http://cfs.maxn.jp/neta/pxem.php
|
83
|
+
- Esolang wiki: https://esolangs.org/wiki/Pxem
|
data/Rakefile
CHANGED
@@ -1,12 +1,6 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
1
|
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
8
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
9
|
-
spec.rspec_opts = ['-cfs']
|
10
|
-
end
|
11
|
-
rescue LoadError => e
|
12
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task :default => :spec
|
data/bin/rpxem
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
if (!ARGV[0] || /^-/ =~ ARGV[0] && !File.exist?(ARGV[0]))
|
4
|
-
require 'rpxem/version'
|
5
|
-
puts "RPxem (#{RPxem::VERSION}) https://github.com/
|
6
|
-
puts 'Usage: rpxem path-to-pxem-file.pxe'
|
7
|
-
puts 'Report bugs to <https://github.com/wktk/rpxem/issues>.'
|
8
|
-
elsif (!File.exist?(ARGV[0]) || !source = open(ARGV[0]).read)
|
9
|
-
puts "Can't load file: #{ARGV[0]}"
|
10
|
-
puts "Try `rpxem --help' for more infomation."
|
11
|
-
else
|
12
|
-
require 'rpxem'
|
13
|
-
RPxem.run(File::basename(ARGV[0]), source)
|
14
|
-
end
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if (!ARGV[0] || /^-/ =~ ARGV[0] && !File.exist?(ARGV[0]))
|
4
|
+
require 'rpxem/version'
|
5
|
+
puts "RPxem (#{RPxem::VERSION}) https://github.com/wktk/rpxem"
|
6
|
+
puts 'Usage: rpxem path-to-pxem-file.pxe'
|
7
|
+
puts 'Report bugs to <https://github.com/wktk/rpxem/issues>.'
|
8
|
+
elsif (!File.exist?(ARGV[0]) || !source = open(ARGV[0]).read)
|
9
|
+
puts "Can't load file: #{ARGV[0]}"
|
10
|
+
puts "Try `rpxem --help' for more infomation."
|
11
|
+
else
|
12
|
+
require 'rpxem'
|
13
|
+
RPxem.run(File::basename(ARGV[0]), source)
|
14
|
+
end
|
data/lib/rpxem.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
require 'rpxem/interpreter'
|
2
|
-
require 'rpxem/version'
|
3
|
-
|
4
|
-
module RPxem
|
5
|
-
class << self
|
6
|
-
def new(options={})
|
7
|
-
RPxem::Interpreter.new(options)
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
def method_missing(name, *args, &block)
|
12
|
-
return super unless new.respond_to?(name)
|
13
|
-
new.__send__(name, *args, &block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def respond_to?(name)
|
17
|
-
new.respond_to?(name) || super(name)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
1
|
+
require 'rpxem/interpreter'
|
2
|
+
require 'rpxem/version'
|
3
|
+
|
4
|
+
module RPxem
|
5
|
+
class << self
|
6
|
+
def new(options={})
|
7
|
+
RPxem::Interpreter.new(options)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def method_missing(name, *args, &block)
|
12
|
+
return super unless new.respond_to?(name)
|
13
|
+
new.__send__(name, *args, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond_to?(name)
|
17
|
+
new.respond_to?(name) || super(name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rpxem/interpreter.rb
CHANGED
@@ -1,232 +1,229 @@
|
|
1
|
-
require 'rpxem/stack'
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@cursor
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
__send__(name)
|
31
|
-
@cursor += 1
|
32
|
-
else
|
33
|
-
buffer.unshift(char)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
return @stack
|
38
|
-
end
|
39
|
-
|
40
|
-
def default_mapping
|
41
|
-
{
|
42
|
-
# I/O
|
43
|
-
'p' => 'output_all',
|
44
|
-
'o' => 'output',
|
45
|
-
'n' => 'output_num',
|
46
|
-
'i' => 'input',
|
47
|
-
'_' => 'input_num',
|
48
|
-
|
49
|
-
# Stack
|
50
|
-
'c' => 'copy',
|
51
|
-
's' => 'throw_away',
|
52
|
-
'v' => 'reverse',
|
53
|
-
|
54
|
-
# File contents
|
55
|
-
'f' => 'read_file',
|
56
|
-
'e' => 'emurate',
|
57
|
-
|
58
|
-
# Rand
|
59
|
-
'r' => 'rand',
|
60
|
-
|
61
|
-
# Loop
|
62
|
-
'w' => 'w',
|
63
|
-
'x' => 'x',
|
64
|
-
'y' => 'y',
|
65
|
-
'z' => 'z',
|
66
|
-
'a' => 'a',
|
67
|
-
|
68
|
-
# Temporary area
|
69
|
-
't' => 'to_temp',
|
70
|
-
'm' => 'from_temp',
|
71
|
-
|
72
|
-
#
|
73
|
-
'd' => '
|
74
|
-
|
75
|
-
# Math
|
76
|
-
'+' => 'addition',
|
77
|
-
'-' => 'subtraction',
|
78
|
-
'!' => 'multiplication',
|
79
|
-
'$' => 'quotient',
|
80
|
-
'%' => 'surplus',
|
81
|
-
}
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
# .p:
|
87
|
-
def output_all
|
88
|
-
while output; end
|
89
|
-
end
|
90
|
-
|
91
|
-
# .o:
|
92
|
-
def output
|
93
|
-
putc @stack.pop unless @stack.empty?
|
94
|
-
end
|
95
|
-
|
96
|
-
# .n:
|
97
|
-
def output_num
|
98
|
-
print @stack.pop
|
99
|
-
end
|
100
|
-
|
101
|
-
# .i:
|
102
|
-
def input
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
1
|
+
require 'rpxem/stack'
|
2
|
+
require 'scanf'
|
3
|
+
|
4
|
+
module RPxem
|
5
|
+
class Interpreter
|
6
|
+
attr_accessor :mapping
|
7
|
+
attr_reader :stack, :temp
|
8
|
+
|
9
|
+
def initialize(mapping={})
|
10
|
+
@mapping = default_mapping().merge(mapping)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Open and execute a Pxem file
|
14
|
+
def open(file, stack=RPxem::Stack.new, temp=nil)
|
15
|
+
run(File.basename(file), File.open(file).read, stack, temp)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Execute a Pxem code
|
19
|
+
def run(filename, source='', stack=RPxem::Stack.new, temp=nil)
|
20
|
+
@filename, @source, @stack, @temp = filename.each_byte.to_a, source, stack, temp
|
21
|
+
buffer, @cursor, length = RPxem::Stack.new, 0, @filename.length
|
22
|
+
|
23
|
+
while (@cursor < length)
|
24
|
+
char = @filename[@cursor]
|
25
|
+
@cursor += 1
|
26
|
+
if (@cursor < length && 46 == char && name = @mapping[@filename[@cursor].chr.downcase])
|
27
|
+
@stack.push(*buffer)
|
28
|
+
buffer = RPxem::Stack.new
|
29
|
+
break if name == 'terminate'
|
30
|
+
__send__(name)
|
31
|
+
@cursor += 1
|
32
|
+
else
|
33
|
+
buffer.unshift(char)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
return @stack
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_mapping
|
41
|
+
{
|
42
|
+
# I/O
|
43
|
+
'p' => 'output_all',
|
44
|
+
'o' => 'output',
|
45
|
+
'n' => 'output_num',
|
46
|
+
'i' => 'input',
|
47
|
+
'_' => 'input_num',
|
48
|
+
|
49
|
+
# Stack
|
50
|
+
'c' => 'copy',
|
51
|
+
's' => 'throw_away',
|
52
|
+
'v' => 'reverse',
|
53
|
+
|
54
|
+
# File contents
|
55
|
+
'f' => 'read_file',
|
56
|
+
'e' => 'emurate',
|
57
|
+
|
58
|
+
# Rand
|
59
|
+
'r' => 'rand',
|
60
|
+
|
61
|
+
# Loop
|
62
|
+
'w' => 'w',
|
63
|
+
'x' => 'x',
|
64
|
+
'y' => 'y',
|
65
|
+
'z' => 'z',
|
66
|
+
'a' => 'a',
|
67
|
+
|
68
|
+
# Temporary area
|
69
|
+
't' => 'to_temp',
|
70
|
+
'm' => 'from_temp',
|
71
|
+
|
72
|
+
# Terminate execution
|
73
|
+
'd' => 'terminate',
|
74
|
+
|
75
|
+
# Math
|
76
|
+
'+' => 'addition',
|
77
|
+
'-' => 'subtraction',
|
78
|
+
'!' => 'multiplication',
|
79
|
+
'$' => 'quotient',
|
80
|
+
'%' => 'surplus',
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# .p:
|
87
|
+
def output_all
|
88
|
+
while output; end
|
89
|
+
end
|
90
|
+
|
91
|
+
# .o:
|
92
|
+
def output
|
93
|
+
putc @stack.pop unless @stack.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
# .n:
|
97
|
+
def output_num
|
98
|
+
print @stack.pop
|
99
|
+
end
|
100
|
+
|
101
|
+
# .i:
|
102
|
+
def input
|
103
|
+
stdin = STDIN.getc
|
104
|
+
@stack.push(stdin ? stdin.ord : -1)
|
105
|
+
end
|
106
|
+
|
107
|
+
# ._:
|
108
|
+
def input_num
|
109
|
+
@stack.push(*scanf('%d'))
|
110
|
+
end
|
111
|
+
|
112
|
+
# .c:
|
113
|
+
def copy
|
114
|
+
@stack.push(@stack.last) unless @stack.empty?
|
115
|
+
end
|
116
|
+
|
117
|
+
# .s:
|
118
|
+
def throw_away
|
119
|
+
@stack.pop
|
120
|
+
end
|
121
|
+
|
122
|
+
# .v:
|
123
|
+
def reverse
|
124
|
+
@stack.reverse!
|
125
|
+
end
|
126
|
+
|
127
|
+
# .f:
|
128
|
+
def read_file
|
129
|
+
@stack.push(*@source.each_byte.to_a.reverse)
|
130
|
+
end
|
131
|
+
|
132
|
+
# .e:
|
133
|
+
def emurate
|
134
|
+
@stack.push(*clone.run(@source, @source, @stack.clone))
|
135
|
+
end
|
136
|
+
|
137
|
+
# .r:
|
138
|
+
def rand
|
139
|
+
@stack.push((super * @stack.pop).to_i)
|
140
|
+
end
|
141
|
+
|
142
|
+
# .w:
|
143
|
+
def w
|
144
|
+
jump if (!@stack.empty? && 0 == @stack.pop)
|
145
|
+
end
|
146
|
+
|
147
|
+
# .x:
|
148
|
+
def x
|
149
|
+
jump if (2 <= @stack.size && @stack.pop >= @stack.pop)
|
150
|
+
end
|
151
|
+
|
152
|
+
# .y:
|
153
|
+
def y
|
154
|
+
jump if (2 <= @stack.size && @stack.pop <= @stack.pop)
|
155
|
+
end
|
156
|
+
|
157
|
+
# .z:
|
158
|
+
def z
|
159
|
+
jump if (2 <= @stack.size && @stack.pop == @stack.pop)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Jump forward to correspondent .a
|
163
|
+
def jump
|
164
|
+
count = 1
|
165
|
+
while (count.nonzero?)
|
166
|
+
@cursor += 1
|
167
|
+
if (46 == @filename[@cursor])
|
168
|
+
if (['w','x','y','z'].include? @filename[@cursor+1].chr.downcase)
|
169
|
+
count += 1
|
170
|
+
elsif ('a' == @filename[@cursor+1].chr.downcase)
|
171
|
+
count -= 1
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
@cursor += 1
|
176
|
+
end
|
177
|
+
|
178
|
+
# .a:
|
179
|
+
def a
|
180
|
+
@cursor -= 2
|
181
|
+
count = -1
|
182
|
+
while (count.nonzero?)
|
183
|
+
if (46 == @filename[@cursor])
|
184
|
+
if (['w','x','y','z'].include? @filename[@cursor+1].chr.downcase)
|
185
|
+
count += 1
|
186
|
+
elsif ('a' == @filename[@cursor+1].chr.downcase)
|
187
|
+
count -= 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
@cursor -= 1
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# .t:
|
195
|
+
def to_temp
|
196
|
+
@temp = @stack.pop
|
197
|
+
end
|
198
|
+
|
199
|
+
# .m:
|
200
|
+
def from_temp
|
201
|
+
@stack.push(@temp) if @temp
|
202
|
+
end
|
203
|
+
|
204
|
+
# .+:
|
205
|
+
def addition
|
206
|
+
@stack.push(@stack.pop + @stack.pop) if 2 <= @stack.size
|
207
|
+
end
|
208
|
+
|
209
|
+
# .-:
|
210
|
+
def subtraction
|
211
|
+
@stack.push((@stack.pop - @stack.pop).abs) if 2 <= @stack.size
|
212
|
+
end
|
213
|
+
|
214
|
+
# .!:
|
215
|
+
def multiplication
|
216
|
+
@stack.push(@stack.pop * @stack.pop) if 2 <= @stack.size
|
217
|
+
end
|
218
|
+
|
219
|
+
# .$:
|
220
|
+
def quotient
|
221
|
+
@stack.push((f=@stack.pop)>(s=@stack.pop)? f/s : s/f) if 2 <= @stack.size
|
222
|
+
end
|
223
|
+
|
224
|
+
# .%:
|
225
|
+
def surplus
|
226
|
+
@stack.push((f=@stack.pop)>(s=@stack.pop)? f%s : s%f) if 2 <= @stack.size
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|