rasel 0.0.1
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/LICENSE +21 -0
- data/bin/rasel +5 -0
- data/lib/rasel.rb +96 -0
- data/rasel.gemspec +18 -0
- data/test.rb +165 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cae44ed33f59f745a94923f22d89396ab952da24
|
4
|
+
data.tar.gz: 9eb3e3ee26db600781c4086cacfa7455a44dbdd2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c18aa154e357e510ad159b108ed639454f30bcafe5b3cd9ef9d9b7002c2464632851180be9edf8d83424e1418f3f6058f2043c9291b020fb12b5bf7f388715ce
|
7
|
+
data.tar.gz: 0c4160519d76732eb8487a05582e6a22a7bbb6ed2487bfdc4f40676129ce410afae3fa99019ba6a899574c2aac053e4e9a29dbbe7294a5879c46caeb5db1995d
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 Victor Maslov
|
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.
|
data/bin/rasel
ADDED
data/lib/rasel.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
Encoding::default_internal = Encoding::default_external = "ASCII-8BIT"
|
2
|
+
END { RubyProf::FlatPrinter.new(RubyProf.stop).print STDERR, min_percent: 1 } if ENV["PROFILE"]
|
3
|
+
|
4
|
+
def RASEL source, stdout = StringIO.new, stdin = STDIN
|
5
|
+
lines = source.tap{ |_| fail "empty source" if _.empty? }.gsub(/ +$/,"").split(?\n)
|
6
|
+
code = lines.map{ |_| _.ljust(lines.map(&:size).max).bytes }
|
7
|
+
stack = []
|
8
|
+
pop = ->{ stack.pop || 0r }
|
9
|
+
dx, dy = 1, 0
|
10
|
+
x, y = -1, 0
|
11
|
+
|
12
|
+
history = {}
|
13
|
+
move = lambda do
|
14
|
+
y = (y + dy) % code.size
|
15
|
+
x = (x + dx) % code[y].size
|
16
|
+
next unless ENV.key?("DEBUG_HISTORY") && code[y][x] == 32
|
17
|
+
history[[x, y]] ||= 0
|
18
|
+
history[[x, y]] += 1
|
19
|
+
end
|
20
|
+
time = Time.now
|
21
|
+
thread = Thread.new do
|
22
|
+
loop do
|
23
|
+
unless Time.now < time + 1
|
24
|
+
time += 1
|
25
|
+
p history.sort_by(&:last).last(10)
|
26
|
+
end
|
27
|
+
sleep 0.1
|
28
|
+
end
|
29
|
+
end if ENV.key? "DEBUG_HISTORY"
|
30
|
+
if ENV["PROFILE"]
|
31
|
+
require "ruby-prof"
|
32
|
+
RubyProf.start
|
33
|
+
end
|
34
|
+
|
35
|
+
reverse = ->{ dy, dx = -dy, -dx }
|
36
|
+
stringmode = false
|
37
|
+
error = Proc.new{ return Struct.new(:stdout, :stack, :exitcode).new stdout, stack, 255 }
|
38
|
+
loop do
|
39
|
+
move[]
|
40
|
+
byte = code[y][x]
|
41
|
+
char = byte.chr
|
42
|
+
STDERR.puts [char, stringmode, (stack.last Integer ENV["DEBUG"] rescue stack)].inspect if ENV.key? "DEBUG"
|
43
|
+
next stack.push byte if stringmode && char != ?"
|
44
|
+
return Struct.new(:stdout, :stack, :exitcode).new stdout, stack, (
|
45
|
+
t = pop[]
|
46
|
+
1 != t.denominator || t < 0 || t > 255 ? 255 : t.to_i
|
47
|
+
) if char == ?@
|
48
|
+
case char
|
49
|
+
when ?\s
|
50
|
+
|
51
|
+
when ?0..?9, ?A..?Z ; stack.push char.to_i(36).to_r
|
52
|
+
when ?" ; stringmode ^= true
|
53
|
+
when ?# ; move[]
|
54
|
+
when ?$ ; pop[]
|
55
|
+
when ?: ; stack.concat [pop[]] * 2
|
56
|
+
when ?- ; stack.push -(pop[] - pop[])
|
57
|
+
when ?\\ ; stack.concat [pop[], pop[]]
|
58
|
+
when ?/ ; b, a = pop[], pop[]; stack.push (b.zero? ? 0 : a / b)
|
59
|
+
when ?% ; b, a = pop[], pop[]; stack.push (b.zero? ? 0 : a % b)
|
60
|
+
when ?v ; dx, dy = 0, 1
|
61
|
+
when ?> ; dx, dy = 1, 0
|
62
|
+
when ?^ ; dx, dy = 0, -1
|
63
|
+
when ?< ; dx, dy = -1, 0
|
64
|
+
when ?? ; move[] if pop[] > 0
|
65
|
+
when ?a
|
66
|
+
t = pop[]
|
67
|
+
error[] if 0 > t || 1 != t.denominator
|
68
|
+
stack.push t.zero? ? 0 : stack[-t] || 0
|
69
|
+
when ?. ; stdout.print "#{_ = pop[]; 1 != _.denominator ? _.to_f : _.to_i} "
|
70
|
+
when ?, ; stdout.print "#{_ = pop[]; 1 != _.denominator ? error[] : _ < 0 || _ > 255 ? error[] : _.to_i.chr}"
|
71
|
+
when ?~ ; if c = stdin.getbyte then stack.push c else reverse[] end
|
72
|
+
when ?&
|
73
|
+
getc = ->{ stdin.getc or (reverse[]; throw nil) }
|
74
|
+
catch nil do
|
75
|
+
nil until (?0..?9).include? c = getc[]
|
76
|
+
while (?0..?9).include? cc = getc[] ; c << cc end
|
77
|
+
stdin.ungetbyte cc
|
78
|
+
stack.push c.to_i
|
79
|
+
end
|
80
|
+
when ?j
|
81
|
+
t = pop[]
|
82
|
+
error[] if 1 != t.denominator
|
83
|
+
if 0 < t
|
84
|
+
y = (y + dy * t.to_i) % code.size
|
85
|
+
x = (x + dx * t.to_i) % code[y].size
|
86
|
+
else
|
87
|
+
reverse[]
|
88
|
+
y = (y - dy * t.to_i) % code.size
|
89
|
+
x = (x - dx * t.to_i) % code[y].size
|
90
|
+
reverse[]
|
91
|
+
end
|
92
|
+
|
93
|
+
else ; error[]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/rasel.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "rasel"
|
3
|
+
spec.version = "0.0.1"
|
4
|
+
spec.summary = "Random Access Stack Esoteric Language"
|
5
|
+
|
6
|
+
spec.author = "Victor Maslov aka Nakilon"
|
7
|
+
spec.email = "nakilon@gmail.com"
|
8
|
+
spec.license = "MIT"
|
9
|
+
spec.metadata = {"source_code_uri" => "https://github.com/nakilon/rasel"}
|
10
|
+
|
11
|
+
spec.add_development_dependency "minitest-around"
|
12
|
+
spec.add_development_dependency "ruby-prof" unless ENV["CI"]
|
13
|
+
|
14
|
+
spec.bindir = "bin"
|
15
|
+
spec.executable = "rasel"
|
16
|
+
spec.test_file = "test.rb"
|
17
|
+
spec.files = %w{ LICENSE rasel.gemspec lib/rasel.rb bin/rasel }
|
18
|
+
end
|
data/test.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "minitest/around/spec"
|
3
|
+
require "timeout"
|
4
|
+
|
5
|
+
require_relative "lib/rasel"
|
6
|
+
|
7
|
+
# TODO: assert that all RASEL() return with 0 exit code unless the opposite is expected
|
8
|
+
|
9
|
+
describe "tests" do
|
10
|
+
around{ |test| Timeout.timeout(1){ test.call } }
|
11
|
+
def assert_stack expectation, *args
|
12
|
+
result = RASEL *args
|
13
|
+
assert_equal expectation.map(&:to_r), [*result.stack, result.exitcode]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "executable" do
|
17
|
+
it "hello world" do
|
18
|
+
require "open3"
|
19
|
+
require "tempfile"
|
20
|
+
begin
|
21
|
+
file = Tempfile.new "temp.rasel"
|
22
|
+
file.write 'A"!dlroW ,olleH">:?@,Hj'
|
23
|
+
file.flush
|
24
|
+
string, status = Open3.capture2e "./bin/rasel #{file.path}"
|
25
|
+
ensure
|
26
|
+
file.close
|
27
|
+
file.unlink
|
28
|
+
end
|
29
|
+
assert_equal [0, "Hello, World!\n"], [status.exitstatus, string]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "non-instructional" do
|
34
|
+
it "trim spaces and empty lines" do
|
35
|
+
assert_stack [64, 32, 118],
|
36
|
+
" v @\n" +
|
37
|
+
"\n" +
|
38
|
+
" > v\n" +
|
39
|
+
" \"\n" +
|
40
|
+
"\n \n\n"
|
41
|
+
assert_stack [1, 2],
|
42
|
+
' v@ '"\n"\
|
43
|
+
' 2 '"\n"\
|
44
|
+
' @ '"\n"\
|
45
|
+
'@v># '"\n"\
|
46
|
+
' >1v '"\n"\
|
47
|
+
' # '"\n"\
|
48
|
+
' '
|
49
|
+
end
|
50
|
+
it "exit status code 255 on invalid character" do
|
51
|
+
assert_equal 255, RASEL("Ы").exitcode
|
52
|
+
end
|
53
|
+
it "print to STDOUT" do
|
54
|
+
# TODO: mock
|
55
|
+
begin
|
56
|
+
STDOUT, stdout = StringIO.new, STDOUT
|
57
|
+
RASEL ",@", STDOUT
|
58
|
+
ensure
|
59
|
+
STDOUT, stdout = stdout, STDOUT
|
60
|
+
end
|
61
|
+
assert_equal ?\0, stdout.string
|
62
|
+
end
|
63
|
+
it "print to StringIO" do
|
64
|
+
string = StringIO.new
|
65
|
+
RASEL ",@", string
|
66
|
+
assert_equal ?\0, string.string
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "instructional" do
|
71
|
+
|
72
|
+
describe "old" do
|
73
|
+
it '"' do assert_stack ["@".ord], '"@' end
|
74
|
+
it '#' do assert_stack [1], '##1@' end
|
75
|
+
it '#"Ы' do assert_stack [64, 208, 171, 35, 64], '#@"@Ы' end
|
76
|
+
it '#><^vЫ' do
|
77
|
+
assert_stack [1, 2, 3],
|
78
|
+
<<~HEREDOC
|
79
|
+
1v@
|
80
|
+
v>2\#
|
81
|
+
>3v
|
82
|
+
\#
|
83
|
+
Ы
|
84
|
+
HEREDOC
|
85
|
+
end
|
86
|
+
it "0..9, A..Z" do assert_stack [*0..35], "#{[*0..9].join}#{[*?A..?Z].join}@" end
|
87
|
+
it "$" do assert_stack [1], "$12$@" end
|
88
|
+
it ":" do assert_stack [0, 0, 1, 1], ":1:@" end
|
89
|
+
it ?\\ do assert_stack [0, 1, 0], "\\1\\@" end
|
90
|
+
it "><^v" do
|
91
|
+
assert_stack [1, 2, 3, 4],
|
92
|
+
<<~HEREDOC
|
93
|
+
<@^1
|
94
|
+
3v>
|
95
|
+
5425
|
96
|
+
HEREDOC
|
97
|
+
end
|
98
|
+
it "-" do assert_stack [-90000, 0], "--"+"9-"*10000+"0@" end
|
99
|
+
it "/" do assert_stack [0, 0, 0.5, 1, 2], "//10/12/22/21/@" end
|
100
|
+
it "%" do assert_stack [0, 0, 1, 0, 0], "%%10%12%22%21%@" end
|
101
|
+
it "/-" do assert_equal [-0.5], RASEL("1-2/0@").stack end
|
102
|
+
it "%-" do assert_equal [1], RASEL("1-2%0@").stack end
|
103
|
+
it ".-" do assert_equal "0 10 255 0 ", RASEL(".A."+"5-"*51+"-..@").stdout.string end
|
104
|
+
it ",-" do assert_equal "\x00\x0A\xFF\x00".b, RASEL(",A,"+"5-"*51+"-,,@").stdout.string end
|
105
|
+
it ".- negative float" do assert_equal "-0.3333333333333333 ", RASEL("13/-.@").stdout.string end
|
106
|
+
it ",- errors" do
|
107
|
+
assert_equal 255, RASEL("1-,@").exitcode
|
108
|
+
assert_equal 255, RASEL("GG*,@").exitcode
|
109
|
+
assert_equal 255, RASEL("12/,@").exitcode
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "changed" do
|
114
|
+
it "@" do
|
115
|
+
assert_equal 0, RASEL("@").exitcode
|
116
|
+
assert_equal 2, RASEL("2@").exitcode
|
117
|
+
assert_equal 255, RASEL("2-@").exitcode
|
118
|
+
assert_equal 255, RASEL("12/@").exitcode
|
119
|
+
end
|
120
|
+
it "~" do
|
121
|
+
assert_stack [2], "~1@2", StringIO.new, StringIO.new
|
122
|
+
assert_stack [0, 10, 255, 0], "~~~~@", StringIO.new,
|
123
|
+
StringIO.new.tap{ |s| [0, 10, 255, 0].reverse_each &s.method(:ungetbyte) }
|
124
|
+
end
|
125
|
+
it "&" do
|
126
|
+
assert_stack [2], "&1@2", StringIO.new, StringIO.new
|
127
|
+
[0, 10, 255].each do |c|
|
128
|
+
assert_stack [12, 34, c], "&&~@", StringIO.new,
|
129
|
+
StringIO.new.tap{ |s| "#{c.chr}-12#{c.chr}-34#{c.chr}".bytes.reverse_each &s.method(:ungetbyte) }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
[
|
133
|
+
[[1], ""],
|
134
|
+
[[0], "1"],
|
135
|
+
[[1], "1-"],
|
136
|
+
[[0], "12/"],
|
137
|
+
[[1], "12/-"],
|
138
|
+
].each do |expectation, code|
|
139
|
+
it "? #{code}" do
|
140
|
+
assert_stack expectation, "#{code}?1@"
|
141
|
+
assert_stack expectation, "v#{code}?1@".chars.zip.transpose.join(?\n)
|
142
|
+
assert_stack expectation, "<@1?#{code.reverse}"
|
143
|
+
assert_stack expectation, "^@1?#{code.reverse}".chars.zip.transpose.join(?\n)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe "new" do
|
149
|
+
# TODO: non-instructional-like tests about jumping over spaces on the edges
|
150
|
+
it "j" do assert_stack [1], "j1@" end
|
151
|
+
it 'j"' do assert_stack [5, 6], '3j2"456@' end
|
152
|
+
it "j-" do assert_stack [2, 3], "6-j123@" end
|
153
|
+
it "exit status code 255 on non-integer jump" do
|
154
|
+
assert_equal 255, RASEL("12/j@").exitcode
|
155
|
+
end
|
156
|
+
it "a:." do assert_equal "2 0 0 ", RASEL("21a:.a:.a:.@").stdout.string end
|
157
|
+
it "exit status code 255 on negative 'take at' argument" do
|
158
|
+
assert_equal 255, RASEL("1-a@").exitcode
|
159
|
+
assert_equal 255, RASEL("12/a@").exitcode
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rasel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Maslov aka Nakilon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest-around
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ruby-prof
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
42
|
+
email: nakilon@gmail.com
|
43
|
+
executables:
|
44
|
+
- rasel
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- bin/rasel
|
50
|
+
- lib/rasel.rb
|
51
|
+
- rasel.gemspec
|
52
|
+
- test.rb
|
53
|
+
homepage:
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata:
|
57
|
+
source_code_uri: https://github.com/nakilon/rasel
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.5.2.3
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Random Access Stack Esoteric Language
|
78
|
+
test_files:
|
79
|
+
- test.rb
|