obtuse 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -0
- data/README.md +27 -16
- data/Rakefile +6 -0
- data/lib/obtuse.rb +2 -0
- data/lib/obtuse/ast/lambda.rb +11 -0
- data/lib/obtuse/evaluator.rb +205 -9
- data/lib/obtuse/parser.rb +11 -3
- data/lib/obtuse/transform.rb +5 -0
- data/lib/obtuse/version.rb +1 -1
- data/spec/examples_spec.rb +19 -0
- data/spec/obtuse_spec.rb +338 -21
- data/spec/spec_helper.rb +13 -4
- metadata +6 -2
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,29 +1,40 @@
|
|
1
|
-
# Obtuse
|
1
|
+
# Obtuse [![Build Status](https://travis-ci.org/utkarshkukreti/obtuse.png)](https://travis-ci.org/utkarshkukreti/obtuse)
|
2
2
|
|
3
|
-
|
3
|
+
Obtuse is a stack-oriented programming language, optimized for brevity.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
7
|
+
### Using Git (recommended)
|
8
8
|
|
9
|
-
|
9
|
+
```
|
10
|
+
$ git clone https://github.com/utkarshkukreti/obtuse.git
|
11
|
+
$ cd obtuse
|
12
|
+
$ bundle install
|
13
|
+
$ rake install
|
14
|
+
```
|
10
15
|
|
11
|
-
|
16
|
+
### Using RubyGems
|
12
17
|
|
13
|
-
|
18
|
+
```
|
19
|
+
$ gem install obtuse
|
20
|
+
```
|
14
21
|
|
15
|
-
|
22
|
+
## Usage
|
16
23
|
|
17
|
-
|
24
|
+
Run
|
18
25
|
|
19
|
-
|
26
|
+
```
|
27
|
+
$ obtuse
|
28
|
+
```
|
29
|
+
|
30
|
+
to start the interactive REPL.
|
31
|
+
|
32
|
+
## Documentation
|
33
|
+
|
34
|
+
Check out `spec/obtuse_spec.rb` for all functions and their outputs.
|
20
35
|
|
21
|
-
|
36
|
+
## License
|
22
37
|
|
23
|
-
|
38
|
+
The MIT License.
|
24
39
|
|
25
|
-
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
40
|
+
Copyright (c) 2012, Utkarsh Kukreti.
|
data/Rakefile
CHANGED
data/lib/obtuse.rb
CHANGED
data/lib/obtuse/evaluator.rb
CHANGED
@@ -1,26 +1,209 @@
|
|
1
1
|
module Obtuse
|
2
2
|
class Evaluator
|
3
|
-
|
3
|
+
attr_accessor :stdin
|
4
|
+
attr_reader :stack, :stash
|
4
5
|
|
5
6
|
def initialize
|
6
7
|
@stack = []
|
8
|
+
@stash = []
|
9
|
+
@stdin = $stdin
|
7
10
|
@parser = Parser.new
|
8
11
|
@transform = Transform.new
|
9
12
|
end
|
10
13
|
|
11
|
-
def eval(input)
|
12
|
-
|
14
|
+
def eval(input, parsed = false)
|
15
|
+
if parsed == false
|
16
|
+
input = @transform.apply(@parser.parse(input))
|
17
|
+
end
|
18
|
+
|
19
|
+
input.each do |atom|
|
13
20
|
case atom
|
14
|
-
when Integer, String
|
21
|
+
when Integer, String, Array, AST::Lambda
|
15
22
|
push atom
|
16
23
|
when :+, :-, :*, :/, :%, :^
|
17
24
|
atom = :** if atom == :^
|
18
|
-
|
19
|
-
if Integer === x && Integer === y
|
20
|
-
String === x && String === y
|
25
|
+
x, y = pop 2
|
26
|
+
if Integer === x && Integer === y
|
21
27
|
push x.send(atom, y)
|
28
|
+
elsif String === x && Integer === y
|
29
|
+
case atom
|
30
|
+
when :+
|
31
|
+
push x + y.to_s
|
32
|
+
when :*
|
33
|
+
push x * y
|
34
|
+
when :%
|
35
|
+
push x % y
|
36
|
+
end
|
37
|
+
elsif String === x && String === y
|
38
|
+
case atom
|
39
|
+
when :+
|
40
|
+
push x + y
|
41
|
+
when :-
|
42
|
+
push (x.chars.to_a - y.chars.to_a).join
|
43
|
+
when :*
|
44
|
+
push x.chars.to_a.join(y)
|
45
|
+
end
|
46
|
+
elsif String === x && Array === y
|
47
|
+
case atom
|
48
|
+
when :%
|
49
|
+
push x % y
|
50
|
+
end
|
51
|
+
elsif Array === x
|
52
|
+
case atom
|
53
|
+
when :+
|
54
|
+
push x + Array(y)
|
55
|
+
when :-
|
56
|
+
push x - Array(y)
|
57
|
+
when :*
|
58
|
+
if Integer === y
|
59
|
+
push x * y
|
60
|
+
elsif String === y
|
61
|
+
push x.join(y)
|
62
|
+
elsif Array === y
|
63
|
+
first = x.shift
|
64
|
+
push x.reduce([first]) {|fold, el| fold + y + [el] }
|
65
|
+
elsif AST::Lambda === y
|
66
|
+
push x.shift
|
67
|
+
x.each do |el|
|
68
|
+
push el
|
69
|
+
eval y.expression, true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
when :%
|
73
|
+
if AST::Lambda === y
|
74
|
+
stash
|
75
|
+
x.each do |el|
|
76
|
+
push el
|
77
|
+
eval y.expression, true
|
78
|
+
end
|
79
|
+
stack = @stack
|
80
|
+
unstash
|
81
|
+
push stack
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
end
|
86
|
+
when :"#"
|
87
|
+
x = pop
|
88
|
+
if Integer === x
|
89
|
+
push [*0...x]
|
90
|
+
elsif String === x || Array === x
|
91
|
+
push x.length
|
92
|
+
end
|
93
|
+
when :"$"
|
94
|
+
x = pop
|
95
|
+
if Integer === x
|
96
|
+
push @stack[-x - 1] if @stack[-x - 1]
|
97
|
+
elsif String === x
|
98
|
+
push x.chars.sort.join
|
99
|
+
elsif Array === x
|
100
|
+
push x.sort
|
101
|
+
elsif AST::Lambda === x
|
102
|
+
y = x
|
103
|
+
x = pop
|
104
|
+
case x
|
105
|
+
when String, Array
|
106
|
+
stash
|
107
|
+
array = String === x ? x.chars.to_a : x
|
108
|
+
array.sort_by! do |el|
|
109
|
+
@stack = []
|
110
|
+
push el
|
111
|
+
eval y.expression, true
|
112
|
+
@stack
|
113
|
+
end
|
114
|
+
unstash
|
115
|
+
push String === x ? array.join : array
|
116
|
+
end
|
117
|
+
end
|
118
|
+
when :~
|
119
|
+
x = pop
|
120
|
+
case x
|
121
|
+
when String
|
122
|
+
eval x
|
123
|
+
when Array
|
124
|
+
@stack += x
|
125
|
+
when AST::Lambda
|
126
|
+
eval x.expression, true
|
127
|
+
end
|
128
|
+
when :!
|
129
|
+
push truthy?(pop) ? 0 : 1
|
130
|
+
when :"@"
|
131
|
+
x, y, z = pop 3
|
132
|
+
push y; push z; push x
|
133
|
+
when :"."
|
134
|
+
x = peek
|
135
|
+
push x if x
|
136
|
+
when :";"
|
137
|
+
pop
|
138
|
+
when :"["
|
139
|
+
stash
|
140
|
+
when :"]"
|
141
|
+
stack = @stack
|
142
|
+
unstash
|
143
|
+
push stack
|
144
|
+
when :"=", :<, :>
|
145
|
+
atom = :== if atom == :"="
|
146
|
+
x, y = pop 2
|
147
|
+
if Integer === x && Integer === y ||
|
148
|
+
String === x && String === y ||
|
149
|
+
Array === x && Array === y
|
150
|
+
push x.send(atom, y) ? 1 : 0
|
151
|
+
end
|
152
|
+
when :"\\"
|
153
|
+
x, y = pop 2
|
154
|
+
push y; push x;
|
155
|
+
when :I
|
156
|
+
x, y, z = pop 3
|
157
|
+
if AST::Lambda === x
|
158
|
+
eval x.expression, true
|
159
|
+
if truthy?(pop)
|
160
|
+
AST::Lambda === y ? eval(y.expression, true) : push(y)
|
161
|
+
else
|
162
|
+
AST::Lambda === z ? eval(z.expression, true) : push(z)
|
163
|
+
end
|
22
164
|
else
|
165
|
+
if truthy?(x)
|
166
|
+
AST::Lambda === y ? eval(y.expression, true) : push(y)
|
167
|
+
else
|
168
|
+
AST::Lambda === z ? eval(z.expression, true) : push(z)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
when :W
|
172
|
+
x, y = pop 2
|
173
|
+
if AST::Lambda === x && AST::Lambda === y
|
174
|
+
loop do
|
175
|
+
eval x.expression, true
|
176
|
+
break unless truthy?(pop)
|
177
|
+
eval y.expression, true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
when :Ic
|
181
|
+
push pop.to_i.chr
|
182
|
+
when :Sg
|
183
|
+
x, y, z = pop 3
|
184
|
+
if (Integer === x || String === x) &&
|
185
|
+
(Integer === y || String === y) &&
|
186
|
+
(Integer === z || String === z)
|
187
|
+
push x.to_s.gsub(y.to_s, z.to_s)
|
23
188
|
end
|
189
|
+
when :Sl
|
190
|
+
push pop.to_s.downcase
|
191
|
+
when :Su
|
192
|
+
push pop.to_s.upcase
|
193
|
+
when :Sc
|
194
|
+
push pop.to_s.capitalize
|
195
|
+
when :So
|
196
|
+
push pop.to_s.ord
|
197
|
+
when :Si
|
198
|
+
x, y = pop 2
|
199
|
+
push x.to_s.include?(y.to_s) ? 1 : 0
|
200
|
+
when :St
|
201
|
+
x, y, z = pop 3
|
202
|
+
push x.to_s.tr(y.to_s, z.to_s)
|
203
|
+
when :Ra
|
204
|
+
push stdin.read.chomp
|
205
|
+
when :Rl
|
206
|
+
push stdin.gets.chomp
|
24
207
|
end
|
25
208
|
end
|
26
209
|
end
|
@@ -29,12 +212,25 @@ module Obtuse
|
|
29
212
|
@stack << object
|
30
213
|
end
|
31
214
|
|
32
|
-
def pop
|
33
|
-
@stack.pop
|
215
|
+
def pop(n = nil)
|
216
|
+
n ? @stack.pop(n) : @stack.pop
|
34
217
|
end
|
35
218
|
|
36
219
|
def peek
|
37
220
|
@stack.last
|
38
221
|
end
|
222
|
+
|
223
|
+
def stash
|
224
|
+
@stash << @stack
|
225
|
+
@stack = []
|
226
|
+
end
|
227
|
+
|
228
|
+
def unstash
|
229
|
+
@stack = @stash.pop
|
230
|
+
end
|
231
|
+
|
232
|
+
def truthy?(x)
|
233
|
+
!(x.nil? || x == 0 || x == "" || x == [])
|
234
|
+
end
|
39
235
|
end
|
40
236
|
end
|
data/lib/obtuse/parser.rb
CHANGED
@@ -4,9 +4,10 @@ module Obtuse
|
|
4
4
|
rule(:spaces?) { spaces.maybe }
|
5
5
|
rule(:digit) { match["0-9"] }
|
6
6
|
rule(:digits) { match["0-9"].repeat(1) }
|
7
|
+
rule(:minus) { str("-") }
|
7
8
|
|
8
9
|
rule :integer do
|
9
|
-
digits.as(:integer) >> spaces?
|
10
|
+
(minus.maybe >> digits).as(:integer) >> spaces?
|
10
11
|
end
|
11
12
|
|
12
13
|
rule :string do
|
@@ -15,12 +16,19 @@ module Obtuse
|
|
15
16
|
end
|
16
17
|
|
17
18
|
rule :function do
|
18
|
-
%w{+ - * / % ^
|
19
|
+
%w{+ - * / % ^ # $ ~ ! @ . ; [ ] = < > \\
|
20
|
+
W Ic I Sg Sl Su Sc So Si St Ra Rl}.
|
21
|
+
map { |name| str name }.reduce(:|).
|
19
22
|
as(:function) >> spaces?
|
20
23
|
end
|
21
24
|
|
25
|
+
rule :lambda do
|
26
|
+
str("{") >> spaces? >> expression.as(:expression).as(:lambda) >>
|
27
|
+
str("}") >> spaces?
|
28
|
+
end
|
29
|
+
|
22
30
|
rule :expression do
|
23
|
-
spaces? >> (string |
|
31
|
+
spaces? >> (integer | string | function | lambda).repeat >> spaces?
|
24
32
|
end
|
25
33
|
|
26
34
|
root :expression
|
data/lib/obtuse/transform.rb
CHANGED
data/lib/obtuse/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Obtuse do
|
4
|
+
describe "GCD" do
|
5
|
+
# From http://www.golfscript.com/golfscript/examples.html
|
6
|
+
e '13483 74205 {.}{.@\%}W;', 13483.gcd(74205)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "LCM" do
|
10
|
+
e '13483 74205 .@.@{.}{.@\%}W;\@*\/', 13483.lcm(74205)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Project Euler" do
|
14
|
+
describe "Problem #6: Find the difference between the sum of the squares" +
|
15
|
+
" of the first one hundred natural numbers and the square of the sum." do
|
16
|
+
e '101#{+}*2^101#{2^}%{+}*-', 25164150
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/obtuse_spec.rb
CHANGED
@@ -5,31 +5,348 @@ describe Obtuse do
|
|
5
5
|
Obtuse::VERSION.should be_a String
|
6
6
|
end
|
7
7
|
|
8
|
-
describe "
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
e "10 20 *", 200
|
15
|
-
e "2 3/", 0
|
16
|
-
e "10 20 /", 0
|
17
|
-
e "2 3%", 2
|
18
|
-
e "10 20 %", 10
|
19
|
-
e "2 3^", 8
|
20
|
-
e "10 20 ^", 10 ** 20
|
8
|
+
describe "Primitives" do
|
9
|
+
describe "Integer" do
|
10
|
+
e "2", 2
|
11
|
+
e "100", 100
|
12
|
+
e "-10", -10
|
13
|
+
end
|
21
14
|
|
22
|
-
|
23
|
-
|
15
|
+
describe "String" do
|
16
|
+
e %q{"a \n b \n c \t\td\na"}, "a \n b \n c \t\td\na"
|
17
|
+
end
|
24
18
|
end
|
25
19
|
|
26
|
-
describe "
|
27
|
-
|
20
|
+
describe "Functions" do
|
21
|
+
describe "+" do
|
22
|
+
describe "Integer Integer" do
|
23
|
+
e "2 1+", 3
|
24
|
+
e "10 20 +", 30
|
25
|
+
e "2 -3+", -1
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "String Integer" do
|
29
|
+
e %q{"foo: "42+}, "foo: 42"
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "String String" do
|
33
|
+
e '"foo""bar"+', "foobar"
|
34
|
+
e '"foo" "bar"+', "foobar"
|
35
|
+
e '"foo\\"" "bar"+', 'foo"bar'
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "Array Object" do
|
39
|
+
e %q{[1 2] 1 +}, [1, 2, 1]
|
40
|
+
e %q{[1 2] "1" +}, [1, 2, "1"]
|
41
|
+
e %q{[1] [] +}, [1]
|
42
|
+
e %q{[1 2] [3 4] +}, [1, 2, 3, 4]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "-" do
|
47
|
+
describe "Integer Integer" do
|
48
|
+
e "2 3-", -1
|
49
|
+
e "10 20 -", -10
|
50
|
+
e "-10 -20-", 10
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "String String" do
|
54
|
+
e %q{"aaa""a"-}, ""
|
55
|
+
e %q{"cabc""b"-}, "cac"
|
56
|
+
e %q{"cabc""cb"-}, "a"
|
57
|
+
e %q{"cabc""cab"-}, ""
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "Array Object" do
|
61
|
+
e %q{[1 2] 1 -}, [2]
|
62
|
+
e %q{[1 2] "1" -}, [1, 2]
|
63
|
+
e %q{[1] [] -}, [1]
|
64
|
+
e %q{[1 2 3 3 1 4 4] [3 4] -}, [1, 2, 1]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "*" do
|
69
|
+
describe "Integer Integer" do
|
70
|
+
e "2 3*", 6
|
71
|
+
e "10 20 *", 200
|
72
|
+
e "-5 5*", -25
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "(String | Array) Integer" do
|
76
|
+
e %q{"foobar "3*}, "foobar foobar foobar "
|
77
|
+
e %q{[1 2 3] 3*}, [1, 2, 3, 1, 2, 3, 1, 2, 3]
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "String String" do
|
81
|
+
e %q{"foobar" " 3 "*}, "f 3 o 3 o 3 b 3 a 3 r"
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "Array String" do
|
85
|
+
e %q{[1 2 3] ", "*}, "1, 2, 3"
|
86
|
+
e %q{[1 . 3] ", "*}, "1, 1, 3"
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "Array Array" do
|
90
|
+
e %q{[1 2 3] [1] *}, [1, 1, 2, 1, 3]
|
91
|
+
e %q{[1 2 3] [0 1] *}, [1, 0, 1, 2, 0, 1, 3]
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "Array Lambda (Fold)" do
|
95
|
+
e %q{[1 2 3] {+} *}, 6
|
96
|
+
e %q{[1 2 3] {-} *}, -4
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "/" do
|
101
|
+
describe "Integer Integer" do
|
102
|
+
e "2 3/", 0
|
103
|
+
e "10 20 /", 0
|
104
|
+
e "10 -2/", -5
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "%" do
|
109
|
+
describe "Integer Integer" do
|
110
|
+
e "2 3%", 2
|
111
|
+
e "10 20 %", 10
|
112
|
+
e "5 -3%", -1
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "String Integer" do
|
116
|
+
e %q{"%05d" 123%}, "00123"
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "String Array" do
|
120
|
+
e %q{"%02d %03d %04d"4#%}, "00 001 0002"
|
121
|
+
e %q{"%02d %03d %04d"[0 1 2 3 4 5]%}, "00 001 0002"
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "Array Lambda (Map)" do
|
125
|
+
e %q{[1 2 3 4] {..} %}, [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "^" do
|
130
|
+
describe "Integer Integer" do
|
131
|
+
e "2 3^", 8
|
132
|
+
e "10 20 ^", 10 ** 20
|
133
|
+
e "-3 3^", -27
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#" do
|
138
|
+
describe "Integer" do
|
139
|
+
e "3#", [0, 1, 2]
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "String" do
|
143
|
+
e %q{"foo bar"#}, 7
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "Array" do
|
147
|
+
e "10##", 10
|
148
|
+
e "[1 2]#", 2
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "$" do
|
153
|
+
describe "Integer" do
|
154
|
+
e %q{5 $}, [], stack: true
|
155
|
+
e %q{1 0 $}, [1, 1], stack: true
|
156
|
+
e %q{5#~ 3 $}, [0, 1, 2, 3, 4, 1], stack: true
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "String" do
|
160
|
+
e %q{"abcdcba"$}, "aabbccd"
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "Array" do
|
164
|
+
e %q{[1 4 3] $}, [1, 3, 4]
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "(String | Array) Lambda (Sort by)" do
|
168
|
+
e %q{"abca" {.} $}, "aabc"
|
169
|
+
e %q{[1 4 3] {-1 *} $}, [4, 3, 1]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "~" do
|
174
|
+
describe "String" do
|
175
|
+
e %q{"123"~}, 123
|
176
|
+
e %q{"1 2 3 + -"~}, -4
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "Array" do
|
180
|
+
e %q{4#~+++}, 6
|
181
|
+
e %q{[1 2]~+}, 3
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "Lambda" do
|
185
|
+
e '{1 1 +}~', 2
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "!" do
|
190
|
+
describe "" do
|
191
|
+
e "!", 1
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "Integer" do
|
195
|
+
e "1!", 0
|
196
|
+
e "0!", 1
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "String" do
|
200
|
+
e %q{""!}, 1
|
201
|
+
e %q{"foo"!}, 0
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "Array" do
|
205
|
+
e "1#!", 0
|
206
|
+
e "0#!", 1
|
207
|
+
e "[]!", 1
|
208
|
+
e "[1]!", 0
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "@" do
|
213
|
+
describe "Object Object Object" do
|
214
|
+
e %q{"abc" 10 4# @}, [10, [0, 1, 2, 3], "abc"], stack: true
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "." do
|
219
|
+
describe "" do
|
220
|
+
e %q{1 2 .}, [1, 2, 2], stack: true
|
221
|
+
e %q{.}, [], stack: true
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe ";" do
|
226
|
+
describe "" do
|
227
|
+
e %q{1 2;}, [1], stack: true
|
228
|
+
e %q{2;}, [], stack: true
|
229
|
+
e %q{;}, [], stack: true
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "[]" do
|
234
|
+
e %q{[1 . 2 . + . [1 . .]]}, [1, 1, 4, 4, [1, 1, 1]]
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "=" do
|
238
|
+
describe "Object Object" do
|
239
|
+
e %q{12 12 =}, 1
|
240
|
+
e %q{"foo" "foo " =}, 0
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "<" do
|
245
|
+
describe "Object Object" do
|
246
|
+
e %q{5 3 <}, 0
|
247
|
+
e %q{"bar" "foo" <}, 1
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe ">" do
|
252
|
+
describe "Object Object" do
|
253
|
+
e %q{5 3 >}, 1
|
254
|
+
e %q{"bar" "foo" >}, 0
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "\\" do
|
259
|
+
describe "Object Object" do
|
260
|
+
e %q{1 2 \\}, [2, 1], stack: true
|
261
|
+
e %q{[] [1] \\}, [[1], []], stack: true
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe "I" do
|
266
|
+
describe "Object Object Object" do
|
267
|
+
e '0 1 2 I', 2
|
268
|
+
e '1 1 2 I', 1
|
269
|
+
e '0 1 {...} {.}I', [0, 0, 0, 0], stack: true
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "W" do
|
274
|
+
describe "Lambda Lambda" do
|
275
|
+
e '3{.}{1-}W', 0
|
276
|
+
e '5{.}{1-.}W', [4, 3, 2, 1, 0, 0], stack: true
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
describe "Ic" do
|
281
|
+
describe "Integer" do
|
282
|
+
e "97 Ic", "a"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "Sg" do
|
287
|
+
describe "(Integer | String) (Integer | String) (Integer | String)" do
|
288
|
+
e %q{123 1 2 Sg}, "223"
|
289
|
+
e %q{"123" 1 "s" Sg}, "s23"
|
290
|
+
e %q{123 1 "s" Sg}, "s23"
|
291
|
+
e %q{"foo bar" "f" "b" Sg}, "boo bar"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "Sl" do
|
296
|
+
describe "String" do
|
297
|
+
e %q{"Foo Bar!" Sl}, "foo bar!"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
describe "Su" do
|
302
|
+
describe "String" do
|
303
|
+
e %q{"Foo Bar!" Su}, "FOO BAR!"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
describe "Sc" do
|
308
|
+
describe "String" do
|
309
|
+
e %q{"foo bar!" Sc}, "Foo bar!"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe "So" do
|
314
|
+
describe "String" do
|
315
|
+
e %q{"a" So}, 97
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe "Si" do
|
320
|
+
describe "(Integer | String) (Integer | String)" do
|
321
|
+
e %q{123 11 Si}, 0
|
322
|
+
e %q{123 "11" Si}, 0
|
323
|
+
e %q{"foo bar" "o b" Si}, 1
|
324
|
+
e %q{"444" 4 Si}, 1
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "St" do
|
329
|
+
describe "(Integer | String) (Integer | String) (Integer | String)" do
|
330
|
+
e %q{123 13 98 St}, "928"
|
331
|
+
e %q{"123" "13" 98 St}, "928"
|
332
|
+
e %q{"hello" "a-y" "b-z" St}, "ifmmp"
|
333
|
+
e %q{"hello" "^aeiou" 0 St}, "0e00o"
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe "Ra" do
|
338
|
+
e "Ra", "abc\nbcd", stdin: "abc\nbcd"
|
339
|
+
end
|
340
|
+
|
341
|
+
describe "Rl" do
|
342
|
+
e "Rl", "abc", stdin: "abc\nbcd"
|
343
|
+
end
|
28
344
|
end
|
29
345
|
|
30
|
-
describe "
|
31
|
-
e
|
32
|
-
e
|
33
|
-
e
|
346
|
+
describe "Mixture" do
|
347
|
+
e "1 2+3-", 0
|
348
|
+
e "5 1 4 5 2 3 4 +-+-+-", 0
|
349
|
+
e "1-2-3-+", 2
|
350
|
+
e "1-2- 3+", 6
|
34
351
|
end
|
35
352
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
1
|
require "bundler/setup"
|
2
2
|
require "simplecov"
|
3
3
|
SimpleCov.start do
|
4
|
-
add_group
|
4
|
+
add_group "Libraries", "/lib"
|
5
|
+
add_filter "/lib/obtuse/cli.rb"
|
5
6
|
end
|
6
7
|
require "obtuse"
|
7
8
|
|
8
9
|
RSpec.configure do |config|
|
9
|
-
def e(input, output)
|
10
|
-
|
10
|
+
def e(input, output, options = {})
|
11
|
+
stdin = options[:stdin]
|
12
|
+
stdin = String === stdin ? StringIO.new(stdin) : $stdin
|
13
|
+
|
14
|
+
it "should evaluate `#{input}` to `#{output}`" do
|
11
15
|
evaluator = Obtuse::Evaluator.new
|
16
|
+
evaluator.stdin = stdin
|
12
17
|
evaluator.eval(input)
|
13
|
-
|
18
|
+
if options[:stack]
|
19
|
+
evaluator.stack.should eq output
|
20
|
+
else
|
21
|
+
evaluator.peek.should eq output
|
22
|
+
end
|
14
23
|
end
|
15
24
|
end
|
16
25
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: obtuse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: parslet
|
@@ -101,6 +101,7 @@ extra_rdoc_files: []
|
|
101
101
|
files:
|
102
102
|
- .gitignore
|
103
103
|
- .rspec
|
104
|
+
- .travis.yml
|
104
105
|
- Gemfile
|
105
106
|
- Guardfile
|
106
107
|
- LICENSE.txt
|
@@ -108,12 +109,14 @@ files:
|
|
108
109
|
- Rakefile
|
109
110
|
- bin/obtuse
|
110
111
|
- lib/obtuse.rb
|
112
|
+
- lib/obtuse/ast/lambda.rb
|
111
113
|
- lib/obtuse/cli.rb
|
112
114
|
- lib/obtuse/evaluator.rb
|
113
115
|
- lib/obtuse/parser.rb
|
114
116
|
- lib/obtuse/transform.rb
|
115
117
|
- lib/obtuse/version.rb
|
116
118
|
- obtuse.gemspec
|
119
|
+
- spec/examples_spec.rb
|
117
120
|
- spec/obtuse_spec.rb
|
118
121
|
- spec/spec_helper.rb
|
119
122
|
homepage: https://github.com/utkarshkukreti/obtuse
|
@@ -141,6 +144,7 @@ signing_key:
|
|
141
144
|
specification_version: 3
|
142
145
|
summary: A Stack-oriented programming language, optimized for brevity.
|
143
146
|
test_files:
|
147
|
+
- spec/examples_spec.rb
|
144
148
|
- spec/obtuse_spec.rb
|
145
149
|
- spec/spec_helper.rb
|
146
150
|
has_rdoc:
|