fish.rb 1.0.0
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 +15 -0
- data/.gitignore +1 -0
- data/README.md +23 -0
- data/Rakefile +24 -0
- data/examples/fibonacci.fsh +2 -0
- data/examples/hello.fsh +2 -0
- data/examples/quine.fsh +1 -0
- data/fish.rb +194 -0
- metadata +55 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MjA2MGU2ZDJlODdkMmMyMjY4NzUxMTQ0ZGU2YzIwYTY1ODNiNzdmNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2M3MTYyYWY0MDkyZjA4YzU1MWYwNzM3NzJiY2NmYjRlZTk2ZmQ4Nw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjFiMjE3ZGNlMGViMzRiNGZmNGY1ZWIwYmI0M2ViNjg2NGZmZjE1OWI2N2Zm
|
10
|
+
Y2Q3NjA2N2UxYmU1YTdmMmIwZDEyYzQyMTFhZGM0NjY5YTk3ZjVlYjg2MTk4
|
11
|
+
OTMzZjA0NmExY2ZjYTY4YTNlNjRiNjljZTY0OTkwMzlhNDM0Nzg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWI3NzgxYzI1Mzk4ZDhiOTBhZTI5ODFkMjNmY2Y4MThlYWQ3NDlhMGQ5NDIw
|
14
|
+
NTIzZDk2MmU1NmU4NTJlY2I5OGE1NDk1M2NlMjU3Zjc3MTdlYWM2MjQxMWI4
|
15
|
+
YzI3NDcyODNkNjcwY2VjNmMzOTA3N2M2ODg0ZGU5OGMwMjA2YmY=
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/pkg
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
fish.rb
|
2
|
+
=======
|
3
|
+
|
4
|
+
A [fish](http://esolangs.org/wiki/Fish) interpreter in ruby.
|
5
|
+
|
6
|
+
There is a slew of examples in the examples directory.
|
7
|
+
|
8
|
+
Todo
|
9
|
+
----
|
10
|
+
|
11
|
+
Things are mostly done, it needs some thorough testing
|
12
|
+
|
13
|
+
|
14
|
+
Thoughts
|
15
|
+
--------
|
16
|
+
|
17
|
+
Something that would be fun to implment is jit. While a straight
|
18
|
+
compiler would be very dificult due to reflection I don't think
|
19
|
+
jit would be to hard if implemented the way rubinius does thiers.
|
20
|
+
It would take a lot of time though, so it is doubtful it will happen.
|
21
|
+
|
22
|
+
If you have trouble with fish.rb for whatever reason just open an issue.
|
23
|
+
I love it when poeple use my software so give it a go.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Created by GitVers - Fill the commented stuff out yourself
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
|
6
|
+
spec = Gem::Specification.new do |gem|
|
7
|
+
gem.name = File.basename(`git rev-parse --show-toplevel`).chop
|
8
|
+
gem.version = `gitver version`
|
9
|
+
|
10
|
+
gem.author = `git config --get user.name`
|
11
|
+
gem.email = `git config --get user.email`
|
12
|
+
gem.homepage = "https://github.com/zerocool/fish.rb"
|
13
|
+
gem.summary = "A fish interpreter"
|
14
|
+
gem.description = "Ruby fish interpreter for the newer multi-stack version of fish"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($\)
|
17
|
+
|
18
|
+
gem.bindir = "./"
|
19
|
+
gem.executables = ["fish.rb"]
|
20
|
+
end
|
21
|
+
|
22
|
+
Gem::PackageTask.new(spec) do |pkg|
|
23
|
+
pkg.gem_spec = spec
|
24
|
+
end
|
data/examples/hello.fsh
ADDED
data/examples/quine.fsh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
"ar00g!;oooooooooo|
|
data/fish.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
class CodeBox
|
7
|
+
def initialize lines
|
8
|
+
@data = {}
|
9
|
+
lines.each_with_index do |line, y_idx|
|
10
|
+
x_idx = 0
|
11
|
+
line.each_char do |c|
|
12
|
+
@data[[x_idx, y_idx]] = c
|
13
|
+
x_idx += 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.[] x, y; @data[[x, y]] end
|
18
|
+
def self.at pt; self[pt[0], pt[1]] end
|
19
|
+
def self.set pt, what; @data[[pt[0], pt[1]]] = what end
|
20
|
+
|
21
|
+
def self.r pt
|
22
|
+
a = @data.select { |k, v| k[1] == pt[1] }
|
23
|
+
xs = (a.keys.collect { |k| k[0] }).sort
|
24
|
+
tmp = xs.select { |v| v > pt[0] }
|
25
|
+
pt.replace [(tmp == [] ? xs.min : tmp.min), pt[1]]
|
26
|
+
at pt
|
27
|
+
end
|
28
|
+
def self.l pt
|
29
|
+
a = @data.select { |k, v| k[1] == pt[1] }
|
30
|
+
xs = (a.keys.collect { |k| k[0] }).sort
|
31
|
+
tmp = xs.select { |v| v < pt[0] }
|
32
|
+
pt.replace [(tmp == [] ? xs.max : tmp.max), pt[1]]
|
33
|
+
at pt
|
34
|
+
end
|
35
|
+
def self.d pt
|
36
|
+
a = @data.select { |k, v| k[0] == pt[0] }
|
37
|
+
ys = (a.keys.collect { |k| k[1] }).sort
|
38
|
+
tmp = ys.select { |v| v > pt[1] }
|
39
|
+
pt.replace [pt[0], (tmp == [] ? ys.min : tmp.min)]
|
40
|
+
at pt
|
41
|
+
end
|
42
|
+
def self.u pt
|
43
|
+
a = @data.select { |k, v| k[0] == pt[0] }
|
44
|
+
ys = (a.keys.collect { |k| k[1] }).sort
|
45
|
+
tmp = ys.select { |v| v < pt[1] }
|
46
|
+
pt.replace [pt[0], (tmp == [] ? ys.max : tmp.max)]
|
47
|
+
at pt
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end # class CodeBox
|
51
|
+
|
52
|
+
class Stack
|
53
|
+
attr_accessor :data
|
54
|
+
def initialize data
|
55
|
+
@data = data
|
56
|
+
|
57
|
+
def self.pop cnt
|
58
|
+
if cnt > @data.length; abort 'something smells fishy... (stack error)' end
|
59
|
+
@data.pop cnt
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.safe_single_pop; @data.pop end
|
63
|
+
def self.push value; @data << value end
|
64
|
+
|
65
|
+
@reg = nil
|
66
|
+
def self.reg
|
67
|
+
if @reg.is_nil?
|
68
|
+
@reg = self.pop 1
|
69
|
+
else
|
70
|
+
self.push @reg
|
71
|
+
@reg = nil
|
72
|
+
ret
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end # class Stack
|
77
|
+
|
78
|
+
class Interpreter
|
79
|
+
@@prng = Random.new
|
80
|
+
@@stdout = $stdout
|
81
|
+
|
82
|
+
@@mirrors = {
|
83
|
+
'_' => { 'r' => 'r', 'l' => 'l', 'u' => 'd', 'd' => 'u' },
|
84
|
+
'|' => { 'r' => 'l', 'l' => 'r', 'u' => 'u', 'd' => 'd' },
|
85
|
+
'/' => { 'r' => 'u', 'l' => 'd', 'u' => 'r', 'd' => 'l' },
|
86
|
+
'\\' => { 'r' => 'd', 'l' => 'u', 'u' => 'l', 'd' => 'r' },
|
87
|
+
'#' => { 'r' => 'l', 'l' => 'r', 'u' => 'd', 'd' => 'u' },
|
88
|
+
}
|
89
|
+
|
90
|
+
@@div_chk = lambda do |d|
|
91
|
+
abort 'something smells fishy... (division by zero)' unless d != 0
|
92
|
+
end
|
93
|
+
|
94
|
+
@@ops = {
|
95
|
+
# control flow
|
96
|
+
'>' => lambda { |pt, dir, stks, box, cntl| dir.replace 'r' },
|
97
|
+
'<' => lambda { |pt, dir, stks, box, cntl| dir.replace 'l' },
|
98
|
+
'v' => lambda { |pt, dir, stks, box, cntl| dir.replace 'd' },
|
99
|
+
'^' => lambda { |pt, dir, stks, box, cntl| dir.replace 'u' },
|
100
|
+
'x' => lambda { |pt, dir, stks, box, cntl| dir.replace 'rlud'[@@prng.rand 4] },
|
101
|
+
'!' => lambda { |pt, dir, stks, box, cntl| box.send dir, pt },
|
102
|
+
'?' => lambda { |pt, dir, stks, box, cntl| v = stks[-1].safe_single_pop; box.send dir, pt unless !v.nil? and v != 0 },
|
103
|
+
'.' => lambda { |pt, dir, stks, box, cntl| pt.replace stks[-1].pop 2 },
|
104
|
+
# operators
|
105
|
+
'+' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x + y },
|
106
|
+
'-' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x - y },
|
107
|
+
'*' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push x * y },
|
108
|
+
',' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; @@div_chk.call y; stks[-1].push x.to_f / y.to_f },
|
109
|
+
'%' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; @@div_chk.call y; stks[-1].push x % y },
|
110
|
+
'=' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x == y ? 1 : 0) },
|
111
|
+
')' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x > y ? 1 : 0) },
|
112
|
+
'(' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push (x < y ? 1 : 0) },
|
113
|
+
# strings
|
114
|
+
'\'' => lambda { |pt, dir, stks, box, cntl| while ((a = box.send dir, pt) != '\'') do; stks[-1].push a.ord end },
|
115
|
+
'"' => lambda { |pt, dir, stks, box, cntl| while ((a = box.send dir, pt) != '"') do; stks[-1].push a.ord end },
|
116
|
+
# stack manipulation
|
117
|
+
':' => lambda { |pt, dir, stks, box, cntl| stks[-1].push stks[-1].data[-1] },
|
118
|
+
'~' => lambda { |pt, dir, stks, box, cntl| stks[-1].pop 1 },
|
119
|
+
'$' => lambda { |pt, dir, stks, box, cntl| x, y = stks[-1].pop 2; stks[-1].push y; stks[-1].push x },
|
120
|
+
'@' => lambda { |pt, dir, stks, box, cntl| x, y, z = stks[-1].pop 3; stks[-1].push z; stks[-1].push x; stks[-1].push y },
|
121
|
+
'}' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.rotate! 1 },
|
122
|
+
'{' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.rotate! -1 },
|
123
|
+
'r' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.reverse! },
|
124
|
+
'l' => lambda { |pt, dir, stks, box, cntl| stks[-1].push stks[-1].data.length },
|
125
|
+
'[' => lambda { |pt, dir, stks, box, cntl| stks << (Stack.new stks[-1].pop stks[-1].pop 1) },
|
126
|
+
']' => lambda { |pt, dir, stks, box, cntl| stks[-1].data.concat stks.pop.data },
|
127
|
+
# io
|
128
|
+
'o' => lambda { |pt, dir, stks, box, cntl| @@stdout.write (stks[-1].pop 1)[0].round.chr },
|
129
|
+
'n' => lambda { |pt, dir, stks, box, cntl| @@stdout.write (stks[-1].pop 1)[0].to_s },
|
130
|
+
'i' => lambda { |pt, dir, stks, box, cntl| stks[-1].push (cntl[:ibuf].empty? ? -1 : cntl[:ibuf][0].ord); cntl[:ibuf] = cntl[:ibuf][1..-1] unless cntl[:ibuf].length < 2 },
|
131
|
+
# reflection
|
132
|
+
'g' => lambda { |pt, dir, stks, box, cntl| stks[-1].push (box.at stks[-1].pop 2).ord },
|
133
|
+
'p' => lambda { |pt, dir, stks, box, cntl| box.set (stks[-1].pop 2), (stks[-1].pop 1) },
|
134
|
+
# miscellaneous
|
135
|
+
'&' => lambda { |pt, dir, stks, box, cntl| stks[-1].reg },
|
136
|
+
';' => lambda { |pt, dir, stks, box, cntl| cntl[:done] = true },
|
137
|
+
' ' => lambda { |pt, dir, stks, box, cntl| }
|
138
|
+
}
|
139
|
+
|
140
|
+
@@mirrors.each do |k, v|
|
141
|
+
@@ops.merge! k => lambda { |pt, dir, stks, box, cntl| dir.replace v[dir] }
|
142
|
+
end
|
143
|
+
|
144
|
+
(0..9).to_a.each do |v|
|
145
|
+
@@ops.merge! v.to_s => lambda { |pt, dir, stks, box, cntl| stks[-1].push v }
|
146
|
+
end
|
147
|
+
|
148
|
+
('a'..'f').to_a.each do |v|
|
149
|
+
@@ops.merge! v => lambda { |pt, dir, stks, box, cntl| stks[-1].push (v.ord - 0x57) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def initialize lines, options
|
153
|
+
@box = CodeBox.new lines.collect { |line| line.chomp.chomp }
|
154
|
+
|
155
|
+
@pt = [0, 0]
|
156
|
+
@dir = 'r'
|
157
|
+
@stks = []
|
158
|
+
@stks << (Stack.new [])
|
159
|
+
@cntl = {
|
160
|
+
:ibuf => options[:stdin],
|
161
|
+
:done => false,
|
162
|
+
}
|
163
|
+
|
164
|
+
|
165
|
+
op = @box.at @pt
|
166
|
+
while !@cntl[:done] do
|
167
|
+
op = ' ' if op.nil?
|
168
|
+
if options[:debug] >= 3; puts op end
|
169
|
+
func = @@ops[op]
|
170
|
+
abort 'something smells fishy... (invalid instruction)' if func.nil?
|
171
|
+
func.call @pt, @dir, @stks, @box, @cntl
|
172
|
+
op = @box.send @dir, @pt
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end # class Interpreter
|
176
|
+
|
177
|
+
|
178
|
+
options = {}
|
179
|
+
optparse = OptionParser.new do |opts|
|
180
|
+
opts.banner = "fish.rb <options> <files>"
|
181
|
+
|
182
|
+
opts.on '-h', '--help', 'Display help' do; puts opts; exit end
|
183
|
+
options[:debug] = 0
|
184
|
+
opts.on '-d [level]', '--debug [level]', 'Print debug messages (max of 3, defaults to 1)' do |opt|
|
185
|
+
options[:debug] = opt.to_i || options[:debug] = 1
|
186
|
+
end
|
187
|
+
options[:stdin] = ""
|
188
|
+
opts.on '-s str', '--stdin str', 'Stdin for fish script' do |opt|; options[:stdin] = opt end
|
189
|
+
opts.on '-r file', '--redir-stdout file', 'Redirect fish stdout to file' do |opt|
|
190
|
+
options[:stdout] = File.open opt, 'w'
|
191
|
+
end
|
192
|
+
end.parse!
|
193
|
+
|
194
|
+
Interpreter.new (IO.readlines ARGV.shift), options
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fish.rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ! 'floomby
|
8
|
+
|
9
|
+
'
|
10
|
+
autorequire:
|
11
|
+
bindir: ./
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-07-09 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: Ruby fish interpreter for the newer multi-stack version of fish
|
16
|
+
email: ! 'floomby@nmt.edu
|
17
|
+
|
18
|
+
'
|
19
|
+
executables:
|
20
|
+
- fish.rb
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- ./fish.rb
|
25
|
+
- .gitignore
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- examples/fibonacci.fsh
|
29
|
+
- examples/hello.fsh
|
30
|
+
- examples/quine.fsh
|
31
|
+
- fish.rb
|
32
|
+
homepage: https://github.com/zerocool/fish.rb
|
33
|
+
licenses: []
|
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
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 2.2.2
|
52
|
+
signing_key:
|
53
|
+
specification_version: 4
|
54
|
+
summary: A fish interpreter
|
55
|
+
test_files: []
|