rasel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|