rprb 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.
data/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Public Domain
2
+
3
+ No warranties
4
+
5
+ You know the drill
data/README ADDED
@@ -0,0 +1,53 @@
1
+ ##
2
+ ## Intro/sample script for rprb (aka Reverse Polish RuBy)
3
+ ##
4
+
5
+ { Kernel swap puts drop } :say sto
6
+ { "Enter to continue..." say gets drop } :pause sto
7
+
8
+ # basic RPN stuff
9
+ 1 1 + p
10
+ 2 * p
11
+ pause
12
+
13
+ # basic Ruby stuff
14
+ zero? p
15
+ 0 zero? p
16
+ Array.new 1 push p
17
+ clr
18
+ pause
19
+
20
+ # obviously, lines starting with # are ignored, but also..
21
+ <<proc { puts "hi!" }
22
+ call
23
+ pause
24
+
25
+ # like Lisp, we have a "read" function
26
+ "1 1 +" read p
27
+ # which is equivalent to
28
+ { 1 1 + } p
29
+ pause
30
+
31
+ # and an "eval" function to evaluate the results
32
+ eval p clr
33
+ pause
34
+
35
+ # and an "evaln" function to evaluate n times
36
+ { 1 1 + } 5 dupn 5 evaln p clr
37
+
38
+ # we have registers..
39
+ 1 :a sto p
40
+ :a rcl p
41
+
42
+ # registers store our functions
43
+ :drop rcl p
44
+ { dup2 + } :fib sto
45
+ 0 1 fib p
46
+
47
+ # exen executes multiple times
48
+ :fib 5 exen
49
+
50
+ # which is equivalent to
51
+ :fib rcl 5 evaln
52
+
53
+ # and a bunch of other stuff
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'rprb'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require_gem 'rprb'
6
+ end
7
+
8
+ dc = RpRb::DC.new
9
+ while gets
10
+ dc.eval dc.read($_.chomp)
11
+ end
12
+
13
+ # vim:ft=ruby
@@ -0,0 +1,64 @@
1
+ # This code is release by the authors into the Public Domain
2
+
3
+ # stream: expr+
4
+ # expr: block | atom | comment
5
+ # string_literal: duh
6
+ # block: { stream }
7
+ # atom: \S+ | string_literal
8
+ # comment: # anything endl
9
+ # endl: \n
10
+ #
11
+
12
+ require 'rubygems'
13
+ require 'packrat/grammar'
14
+
15
+ module RpRb
16
+ Grammar = Packrat::Grammar.new do
17
+ start_symbol :Stream
18
+
19
+ S = hidden(/\s*/)
20
+ FS = hidden(/\s\s*/)
21
+
22
+ prod :Stream, [mult(:Expression), ast(:Stream)]
23
+
24
+ prod :StringLiteral, [/"(?:[^"]|\\")*"/, lift(0)]
25
+
26
+ prod :Block, [hidden('{'), S, :Stream, S, hidden('}'), ast(:Block)]
27
+
28
+ prod :Atom, [any(:StringLiteral, /[^{} \t]+/), lift(0)]
29
+
30
+ rule :Expression, [S, any(:Block, :Atom), S, ast(:Expression)]
31
+ end
32
+
33
+ Parser = Grammar.interpreting_parser
34
+
35
+ class Reader
36
+ def read(string)
37
+ to_stream(Parser.parse_string(string))
38
+ end
39
+
40
+ include RpRb::Grammar::ASTs
41
+
42
+ def to_stream(ast)
43
+ case ast
44
+ when Stream
45
+ ast.children[0].collect { |child| to_stream(child) }
46
+ when Expression, Block
47
+ to_stream ast.children[0]
48
+ else
49
+ ast
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ if __FILE__ == $0
56
+ require 'pp'
57
+
58
+ while gets
59
+ puts "Parser output:"
60
+ pp RpRb::Parser.parse_string($_.chomp)
61
+ puts "Reader output:"
62
+ pp RpRb::Reader.new.read($_.chomp)
63
+ end
64
+ end
@@ -0,0 +1,189 @@
1
+ # This code is release by the authors into the Public Domain
2
+
3
+ module Enumerable
4
+ def collect_with_index
5
+ result = []
6
+ each_with_index { |elem, i|
7
+ result << yield(elem, i)
8
+ }
9
+ result
10
+ end
11
+ end
12
+
13
+ #class Rational
14
+ # def inspect
15
+ # to_s
16
+ # end
17
+ #end
18
+
19
+ def trythese(*procs)
20
+ if procs.length == 0
21
+ raise "Ahhg!"
22
+ else
23
+ begin
24
+ procs[0].call
25
+ rescue Exception => error
26
+ #puts "ERROR: " + error
27
+ trythese(*procs[1..-1])
28
+ end
29
+ end
30
+ end
31
+
32
+ require 'expr'
33
+
34
+ module RpRb
35
+ class DC
36
+ def initialize
37
+ @reader = Reader.new
38
+
39
+ @stack = []
40
+
41
+ @registers = {
42
+ :eval => proc { |x| eval x },
43
+ :read => proc { |x| read x },
44
+
45
+ :p => proc { ||
46
+ puts "___"
47
+ puts @stack.collect_with_index { |entry, i| "%3d: %s" % [i, entry.inspect] }.reverse.join("\n")
48
+ puts "---"
49
+ :noval
50
+ },
51
+
52
+ :pick => proc { |n| @stack[n] },
53
+ :del => proc { |n| @stack.slice!(n); :noval },
54
+ :sto => proc { |val, sym| @registers[sym] = val; :noval },
55
+ :rcl => proc { |sym| @registers[sym] },
56
+ :if => proc { |den, elz, test| if test; den; else; elz; end },
57
+ :len => proc { || @stack.length },
58
+
59
+ :push => proc { |array, elem| array.push elem; array },
60
+
61
+ :while => proc { |expr, cond| loop { eval(cond); break unless @stack.shift; eval(expr) }; :noval },
62
+ :evaln => proc { |expr, n| n.times { eval(expr) }; :noval },
63
+ :loop => proc { |expr, times| times.times { |i| @stack.unshift(i); eval(expr) }; :noval },
64
+ :each => proc { |enumerable, expr| enumerable.each { |elem| @stack.unshift(elem); eval(expr) }; :noval },
65
+
66
+ :array => proc { |length| @stack.slice!(0, length).reverse },
67
+
68
+ :regs => proc { || @registers.keys },
69
+ }
70
+
71
+
72
+ [
73
+ read('{ Array.new } :"[]" sto'),
74
+ read('0 array :control sto'),
75
+ read('{ false true 2 pick if 1 del } :not sto'),
76
+ read('{ :control rcl swap unshift :control sto } :save sto'),
77
+ read('{ :control rcl 0 slice! } :restore sto'),
78
+ read('{ 1 pick 2 del } :swap sto'),
79
+ read('{ 0 del } :drop sto'),
80
+ read('{ 0 pick } :dup sto'),
81
+ read('{ {drop} swap evaln } :dropn sto'),
82
+ read('{ 2 dropn } :drop2 sto'),
83
+ read('{ 2 dupn } :dup2 sto'),
84
+ read('{ len dropn } :clr sto'),
85
+ read('{ rcl eval } :exe sto'),
86
+ read('{ swap rcl swap evaln } :exen sto'),
87
+ read('{ 1 - } :dec sto'),
88
+ read('{ 1 + } :inc sto'),
89
+ read('{ -1 * } :neg sto'),
90
+ read('{ 1.0 swap / } :inv sto'),
91
+ read('{ restore dup save } :peek sto'),
92
+ read('{ restore drop save } :poke sto'),
93
+ read('{ save {peek 1 - pick} peek evaln restore drop } :dupn sto'),
94
+ read('0 array :nop sto'),
95
+ read('{ swap dup length save swap each restore array } :map sto'),
96
+ read('{ File swap open save peek readlines restore close drop } :slurp sto'),
97
+ read('{ slurp {chomp} map {read} map {eval} each } :load sto'),
98
+ read('{ inc dup pick swap del } :take sto'),
99
+ read('{ len {+} swap dec evaln } :sum sto'),
100
+ ].each { |stream| eval(stream) }
101
+ end
102
+
103
+ def stack
104
+ @stack.dup
105
+ end
106
+
107
+ def read(val)
108
+ @reader.read val
109
+ end
110
+
111
+ def eval(tokens)
112
+ #puts "Eval-ing #{tokens.inspect}"
113
+ tokens.each { |token|
114
+ #puts "processing token #{token.inspect}..."
115
+ result = trythese(
116
+ *[
117
+ proc { execute(token.intern) },
118
+ proc { parse_code(token) },
119
+ proc { Kernel.eval(token) },
120
+ proc { puts("Error, nothing left to do"); :noval },
121
+ ]
122
+ )
123
+
124
+ unless result == :noval
125
+ @stack.unshift result
126
+ end
127
+ }
128
+
129
+ :noval
130
+ end
131
+
132
+ def parse_code(stream)
133
+ if stream.is_a? Array
134
+ stream
135
+ else
136
+ raise "#{stream.inspect} isn't code!"
137
+ end
138
+ end
139
+
140
+ def execute(fn)
141
+ # check if /fn/ names a register
142
+ if @registers.include? fn
143
+ case @registers[fn]
144
+ when Proc, Method
145
+ values = @stack.slice!(0, @registers[fn].arity).reverse
146
+ return @registers[fn].call(*values)
147
+ else
148
+ return eval(@registers[fn])
149
+ end
150
+ end
151
+
152
+ # check if /fn/ is a valid function call for an item on the stack
153
+ @stack.each_with_index { |src, arity|
154
+ begin
155
+ if fn == :call and (src.is_a?(Proc) or src.is_a?(Method)) and (src.arity == arity or src.arity == -1)
156
+ values = @stack.slice!(0, arity + 1).reverse
157
+ return values[0].call(*values[1..-1])
158
+ elsif src.respond_to?(fn) and (src.method(fn).arity == arity or src.method(fn).arity == -1)
159
+ values = @stack.slice!(0, arity + 1).reverse
160
+ return values[0].send(fn, *values[1..-1])
161
+ end
162
+ rescue ArgumentsError
163
+ end
164
+ }
165
+
166
+ # check if /fn/ is a valid method of Kernel or Math
167
+ [Kernel, Math].each { |src|
168
+ begin
169
+ if src.respond_to? fn
170
+ values = @stack.slice!(0, src.method(fn).arity).reverse
171
+ return src.send(fn, *values)
172
+ end
173
+ rescue
174
+ end
175
+ }
176
+
177
+ raise "Couldn't execute function on stack item, DC, Kernel, or Math"
178
+ end
179
+ end
180
+ end
181
+
182
+ if __FILE__ == $0
183
+ dc = RpRb::DC.new
184
+ while gets
185
+ dc.eval dc.read($_.chomp)
186
+ end
187
+ end
188
+
189
+ # vim:ts=4:sw=4
@@ -0,0 +1,199 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ include RpRb
5
+
6
+ class DCTest < Test::Unit::TestCase
7
+ def setup
8
+ @dc = DC.new
9
+ end
10
+
11
+ def e(arg)
12
+ @dc.eval arg
13
+ end
14
+
15
+ def r(arg)
16
+ @dc.read arg
17
+ end
18
+
19
+ def re(arg)
20
+ e r(arg)
21
+ end
22
+
23
+ def s
24
+ @dc.stack
25
+ end
26
+
27
+ def test_basic_eval
28
+ re('nil nil')
29
+ assert_equal [nil, nil], s
30
+
31
+ re('clr 1 2 3')
32
+ assert_equal [3, 2, 1], s
33
+ end
34
+
35
+ def test_basic_method_calling
36
+ re('1 2 +')
37
+ assert_equal [3], s
38
+
39
+ re 'clr 1 2 3 4 4 array 5 push'
40
+ assert_equal [[1, 2, 3, 4, 5]], s
41
+ end
42
+
43
+ def test_basic_Math_method_calling
44
+ re('0 sin 0 cos')
45
+ assert_equal [1.0, 0.0], s
46
+ end
47
+
48
+ def test_proc_calling
49
+ re '"proc{|arg|1+arg}" eval 1 call'
50
+ assert_equal [2], s
51
+
52
+ re 'clr Math.method(:sin) 0 call'
53
+ assert_equal [0.0], s
54
+ end
55
+
56
+ def test_basic_dc_methods
57
+ re('0 dup')
58
+ assert_equal [0, 0], s
59
+
60
+ re('nil dup')
61
+ assert_equal [nil, nil, 0, 0], s
62
+
63
+ re('drop2 drop')
64
+ assert_equal [0], s
65
+
66
+ re('1 2')
67
+ assert_equal [2, 1, 0], s
68
+
69
+ re('drop dup2')
70
+ assert_equal [1, 0, 1, 0], s
71
+
72
+ re('drop2')
73
+ assert_equal [1, 0], s
74
+
75
+ re 'swap'
76
+ assert_equal [0, 1], s
77
+
78
+ re '1 pick'
79
+ assert_equal [1, 0, 1], s
80
+
81
+ re 'neg'
82
+ assert_equal [-1, 0, 1], s
83
+
84
+ re 'inc'
85
+ assert_equal [0, 0, 1], s
86
+
87
+ re 'dec'
88
+ assert_equal [-1, 0, 1], s
89
+
90
+ re 'len'
91
+ assert_equal [3, -1, 0, 1], s
92
+
93
+ re '[]'
94
+ assert_equal [[], 3, -1, 0, 1], s
95
+ end
96
+
97
+ def test_variables
98
+ re('0 1 :a sto')
99
+ assert_equal [0], s
100
+
101
+ re(':a rcl')
102
+ assert_equal [1, 0], s
103
+ end
104
+
105
+ def test_if
106
+ re('1 2 true if')
107
+ assert_equal [1], s
108
+
109
+ re('clr 1 2 false if')
110
+ assert_equal [2], s
111
+ end
112
+
113
+ def test_not
114
+ re 'false not'
115
+ assert_equal [true], s
116
+
117
+ re 'clr true not'
118
+ assert_equal [false], s
119
+
120
+ re 'clr nil not'
121
+ assert_equal [true], s
122
+
123
+ re 'clr 0 not'
124
+ assert_equal [false], s
125
+ end
126
+
127
+ def test_while
128
+ re '{ 1 } { len 5 == not } while'
129
+ assert_equal [1, 1, 1, 1, 1], s
130
+ end
131
+
132
+ def test_array
133
+ re '1 2 3 4 4 array'
134
+ assert_equal [[1, 2, 3, 4]], s
135
+ end
136
+
137
+ def test_evaln
138
+ re '{ 1 } 5 evaln'
139
+ assert_equal [1, 1, 1, 1, 1], s
140
+
141
+ re '3 dropn { dup2 + } 3 evaln'
142
+ assert_equal [5, 3, 2, 1, 1], s
143
+ end
144
+
145
+ def test_stored_procedures
146
+ re('{ dup2 + } :fib sto 1 1')
147
+ assert_equal [1, 1], s
148
+ re('fib fib')
149
+ assert_equal [3, 2, 1, 1], s
150
+ re(':fib rcl eval')
151
+ assert_equal [5, 3, 2, 1, 1], s
152
+ re(':fib rcl 2 evaln')
153
+ assert_equal [13, 8, 5, 3, 2, 1, 1], s
154
+ end
155
+
156
+ def test_save_restore
157
+ re '1 save 2 save restore save :control rcl'
158
+ assert_equal [[2, 1]], s
159
+
160
+ re('clr Array.new :control sto 1 save :control rcl')
161
+ assert_equal [[1]], s
162
+
163
+ re 'clr restore'
164
+ assert_equal [1], s
165
+
166
+ re 'clr :control rcl'
167
+ assert_equal [[]], s
168
+ end
169
+
170
+ def test_each
171
+ re '1 2 3 4 5 5 array { 2 * } each'
172
+ assert_equal [10, 8, 6, 4, 2], s
173
+ end
174
+
175
+ def test_map
176
+ re('1 2 3 4 5 5 array { 2 * } map')
177
+ assert_equal [[2, 4, 6, 8, 10]], s
178
+
179
+ re 'clr 1 2 3 4 5 5 array { neg } map'
180
+ assert_equal [[-1, -2, -3, -4, -5]], s
181
+ end
182
+
183
+ def test_load
184
+ require 'tempfile'
185
+ thefile = nil
186
+ Tempfile.open("tc_evaluator") { |file|
187
+ thefile = file
188
+ file.write <<-END
189
+ { dup2 + } :fib sto
190
+ { 1 1 } :blah sto
191
+ END
192
+ }
193
+
194
+ re %Q{"#{thefile.path}" load}
195
+ re 'blah :fib 3 exen'
196
+ assert_equal [5, 3, 2, 1, 1], s
197
+ thefile.delete
198
+ end
199
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ class MiscTest < Test::Unit::TestCase
5
+ def test_collect_with_index
6
+ assert_equal [0, 1, 2, 3], [1, 2, 3, 4].collect_with_index { |a, i| i }
7
+ end
8
+ end
@@ -0,0 +1,27 @@
1
+ require 'test/unit'
2
+ require 'rprb'
3
+
4
+ include RpRb
5
+
6
+ class ReaderTest < Test::Unit::TestCase
7
+ def setup
8
+ @reader = Reader.new
9
+ end
10
+
11
+ def r(arg)
12
+ @reader.read arg
13
+ end
14
+
15
+ def test_read
16
+ assert_equal ['1'], @reader.read("1")
17
+ assert_equal [['1']], @reader.read("{ 1 }")
18
+ assert_equal [['1']], @reader.read("{1}")
19
+
20
+ assert_equal ['1', ['1']], @reader.read('1 {1}')
21
+
22
+ assert_equal [[]], @reader.read('{ }')
23
+
24
+ assert_equal ['"1 2 3"'], r('"1 2 3"')
25
+ assert_equal ['"proc {}"'], r('"proc {}"')
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) << File.join(File.dirname(__FILE__), '../lib')
2
+
3
+ require 'tc_misc'
4
+ require 'tc_reader'
5
+ require 'tc_evaluator'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rprb
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Jimmy Thrasher and Justin Dubs
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2006-10-11 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rockit
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 7
29
+ segments:
30
+ - 0
31
+ - 7
32
+ - 2
33
+ version: 0.7.2
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description:
37
+ email:
38
+ executables:
39
+ - rprb
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - lib/rprb.rb
46
+ - lib/expr.rb
47
+ - bin/rprb
48
+ - test/ts_all.rb
49
+ - test/tc_evaluator.rb
50
+ - test/tc_reader.rb
51
+ - test/tc_misc.rb
52
+ - README
53
+ - LICENSE
54
+ has_rdoc: true
55
+ homepage:
56
+ licenses: []
57
+
58
+ post_install_message:
59
+ rdoc_options: []
60
+
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Provides Ruby in RPN style, ostensibly for a dc replacement
88
+ test_files:
89
+ - test/ts_all.rb
90
+ - test/tc_evaluator.rb
91
+ - test/tc_reader.rb
92
+ - test/tc_misc.rb