crisp 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +10 -1
- data/Rakefile +1 -1
- data/bin/crisp +1 -1
- data/crisp.gemspec +7 -5
- data/examples/factorial.crisp +6 -0
- data/examples/fibonacci.crisp +0 -1
- data/examples/run.crisp +5 -0
- data/lib/crisp.rb +1 -1
- data/lib/crisp/chained_env.rb +10 -0
- data/lib/crisp/crisp.treetop +1 -1
- data/lib/crisp/env.rb +2 -0
- data/lib/crisp/errors.rb +3 -0
- data/lib/crisp/functions/core.rb +153 -6
- data/lib/crisp/nodes/block.rb +3 -7
- data/lib/crisp/nodes/operation.rb +8 -2
- data/lib/crisp/runtime.rb +3 -3
- data/spec/crisp/arithmetics_spec.rb +1 -1
- data/spec/crisp/basic_spec.rb +3 -3
- data/spec/crisp/core_spec.rb +136 -0
- data/spec/crisp/function_spec.rb +5 -4
- data/spec/crisp/native_call_invoker_spec.rb +10 -4
- data/spec/crisp/string_spec.rb +1 -1
- metadata +9 -7
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,16 @@
|
|
1
|
-
## 0.0.
|
1
|
+
## 0.0.9 (2011-xx-xx)
|
2
2
|
|
3
3
|
* ...
|
4
4
|
|
5
|
+
## 0.0.8 (2011-01-06)
|
6
|
+
|
7
|
+
* local bindings with let
|
8
|
+
* cond provides a kind of switch/case statemnts, including default path
|
9
|
+
* load lets you load crisp source files at runtime
|
10
|
+
* loops can be performed with loop/recur
|
11
|
+
* internal fixes and refactorings
|
12
|
+
* more examples
|
13
|
+
|
5
14
|
## 0.0.6/0.0.7 (2010-12-17)
|
6
15
|
|
7
16
|
* if else statements
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ begin
|
|
15
15
|
gem.homepage = "http://github.com/mgsnova/crisp"
|
16
16
|
gem.authors = ['Markus Gerdes']
|
17
17
|
gem.add_dependency 'treetop', '~> 1.4.9'
|
18
|
-
gem.add_development_dependency 'rspec', '~> 2.
|
18
|
+
gem.add_development_dependency 'rspec', '~> 2.4.0'
|
19
19
|
end
|
20
20
|
|
21
21
|
Jeweler::GemcutterTasks.new
|
data/bin/crisp
CHANGED
data/crisp.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{crisp}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.8"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Markus Gerdes"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-06}
|
13
13
|
s.default_executable = %q{crisp}
|
14
14
|
s.email = %q{github@mgsnova.de}
|
15
15
|
s.executables = ["crisp"]
|
@@ -25,7 +25,9 @@ Gem::Specification.new do |s|
|
|
25
25
|
"autotest/discover.rb",
|
26
26
|
"bin/crisp",
|
27
27
|
"crisp.gemspec",
|
28
|
+
"examples/factorial.crisp",
|
28
29
|
"examples/fibonacci.crisp",
|
30
|
+
"examples/run.crisp",
|
29
31
|
"lib/crisp.rb",
|
30
32
|
"lib/crisp/chained_env.rb",
|
31
33
|
"lib/crisp/crisp.treetop",
|
@@ -83,14 +85,14 @@ Gem::Specification.new do |s|
|
|
83
85
|
|
84
86
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
85
87
|
s.add_runtime_dependency(%q<treetop>, ["~> 1.4.9"])
|
86
|
-
s.add_development_dependency(%q<rspec>, ["~> 2.
|
88
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.4.0"])
|
87
89
|
else
|
88
90
|
s.add_dependency(%q<treetop>, ["~> 1.4.9"])
|
89
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
91
|
+
s.add_dependency(%q<rspec>, ["~> 2.4.0"])
|
90
92
|
end
|
91
93
|
else
|
92
94
|
s.add_dependency(%q<treetop>, ["~> 1.4.9"])
|
93
|
-
s.add_dependency(%q<rspec>, ["~> 2.
|
95
|
+
s.add_dependency(%q<rspec>, ["~> 2.4.0"])
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
data/examples/fibonacci.crisp
CHANGED
data/examples/run.crisp
ADDED
data/lib/crisp.rb
CHANGED
data/lib/crisp/chained_env.rb
CHANGED
@@ -29,5 +29,15 @@ module Crisp
|
|
29
29
|
def []=(key, val)
|
30
30
|
@second[key] = val
|
31
31
|
end
|
32
|
+
|
33
|
+
# returns global loop data of global/second env
|
34
|
+
def global_loop_data
|
35
|
+
@second.global_loop_data
|
36
|
+
end
|
37
|
+
|
38
|
+
# set global loop data to global/second env
|
39
|
+
def global_loop_data=(data)
|
40
|
+
@second.global_loop_data = data
|
41
|
+
end
|
32
42
|
end
|
33
43
|
end
|
data/lib/crisp/crisp.treetop
CHANGED
data/lib/crisp/env.rb
CHANGED
data/lib/crisp/errors.rb
CHANGED
data/lib/crisp/functions/core.rb
CHANGED
@@ -54,10 +54,6 @@ module Crisp
|
|
54
54
|
raise ArgumentError, "no argument list defined"
|
55
55
|
end
|
56
56
|
|
57
|
-
if args[1].class.name != "Crisp::Nodes::Operation"
|
58
|
-
raise ArgumentError, "no function body defined"
|
59
|
-
end
|
60
|
-
|
61
57
|
fn_arg_list = args[0].raw_elements
|
62
58
|
fn_operation = args[1]
|
63
59
|
|
@@ -72,7 +68,7 @@ module Crisp
|
|
72
68
|
|
73
69
|
chained_env = ChainedEnv.new(local_env, env)
|
74
70
|
|
75
|
-
fn_operation.
|
71
|
+
fn_operation.resolve_and_eval(chained_env)
|
76
72
|
end
|
77
73
|
end.bind('fn', current_env)
|
78
74
|
|
@@ -96,6 +92,127 @@ module Crisp
|
|
96
92
|
res ? res.resolve_and_eval(env) : res
|
97
93
|
end.bind('if', current_env)
|
98
94
|
|
95
|
+
# cond
|
96
|
+
# cond works like a switch/case statement, evaluating the first expression where the condition matches
|
97
|
+
#
|
98
|
+
# (cond
|
99
|
+
# false (println "should not be printed")
|
100
|
+
# true (println "should be printed"))
|
101
|
+
Function.new do
|
102
|
+
if args.size.odd?
|
103
|
+
raise ArgumentError, "argument list has to contain even list of arguments"
|
104
|
+
end
|
105
|
+
|
106
|
+
result = nil
|
107
|
+
|
108
|
+
args.each_with_index do |arg, idx|
|
109
|
+
next if idx.odd?
|
110
|
+
if (arg.class.name == 'Crisp::Nodes::SymbolLiteral' and arg.text_value == 'else') or
|
111
|
+
(![nil, false].include?(arg.resolve_and_eval(env)))
|
112
|
+
result = args[idx + 1].resolve_and_eval(env)
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
result
|
118
|
+
end.bind("cond", current_env)
|
119
|
+
|
120
|
+
# let
|
121
|
+
# create local binding only valid within let and evaluate expressions
|
122
|
+
#
|
123
|
+
# (let [x 1 y 2] (+ x y))
|
124
|
+
# => 3
|
125
|
+
Function.new do
|
126
|
+
if args[0].class.name != "Crisp::Nodes::ArrayLiteral"
|
127
|
+
raise ArgumentError, "no argument list defined"
|
128
|
+
end
|
129
|
+
|
130
|
+
if args[0].raw_elements.size.odd?
|
131
|
+
raise ArgumentError, "argument list has to contain even list of arguments"
|
132
|
+
end
|
133
|
+
|
134
|
+
local_env = Env.new
|
135
|
+
chained_env = ChainedEnv.new(local_env, env)
|
136
|
+
binding_array = args[0].raw_elements
|
137
|
+
|
138
|
+
binding_array.each_with_index do |key, idx|
|
139
|
+
next if idx.odd?
|
140
|
+
local_env[key.text_value] = binding_array[idx+1].resolve_and_eval(chained_env)
|
141
|
+
end
|
142
|
+
|
143
|
+
args[1..-1].map do |op|
|
144
|
+
op.resolve_and_eval(chained_env)
|
145
|
+
end.last
|
146
|
+
end.bind('let', current_env)
|
147
|
+
|
148
|
+
# loop
|
149
|
+
# create loop with a local binding, perform a loopjump using recur
|
150
|
+
#
|
151
|
+
# (loop [cnt 5 acc 1]
|
152
|
+
# (if (= 0 cnt)
|
153
|
+
# acc
|
154
|
+
# (recur (- cnt 1) (* acc cnt))))
|
155
|
+
# => 120
|
156
|
+
Function.new do
|
157
|
+
if env.global_loop_data
|
158
|
+
raise LoopError, "nested loops are not allowed"
|
159
|
+
end
|
160
|
+
|
161
|
+
if args[0].class.name != "Crisp::Nodes::ArrayLiteral"
|
162
|
+
raise ArgumentError, "no argument list defined"
|
163
|
+
end
|
164
|
+
|
165
|
+
if args[0].raw_elements.size.odd?
|
166
|
+
raise ArgumentError, "argument list has to contain even list of arguments"
|
167
|
+
end
|
168
|
+
|
169
|
+
local_env = Env.new
|
170
|
+
chained_env = ChainedEnv.new(local_env, env)
|
171
|
+
binding_array = args[0].raw_elements
|
172
|
+
argument_name_array = []
|
173
|
+
|
174
|
+
binding_array.each_with_index do |key, idx|
|
175
|
+
next if idx.odd?
|
176
|
+
local_env[key.text_value] = binding_array[idx+1].resolve_and_eval(chained_env)
|
177
|
+
argument_name_array << key.text_value
|
178
|
+
end
|
179
|
+
|
180
|
+
env.global_loop_data = {
|
181
|
+
:operations => args[1..-1],
|
182
|
+
:argument_names => argument_name_array
|
183
|
+
}
|
184
|
+
|
185
|
+
result = args[1..-1].map do |op|
|
186
|
+
op.resolve_and_eval(chained_env)
|
187
|
+
end.last
|
188
|
+
|
189
|
+
env.global_loop_data = nil
|
190
|
+
|
191
|
+
result
|
192
|
+
end.bind('loop', current_env)
|
193
|
+
|
194
|
+
# recur
|
195
|
+
# only used inside a loop. recur will trigger a new run of the loop
|
196
|
+
# see 'loop' for an example
|
197
|
+
Function.new do
|
198
|
+
if !env.global_loop_data
|
199
|
+
raise LoopError, "recur called outside loop"
|
200
|
+
end
|
201
|
+
|
202
|
+
validate_args_count(env.global_loop_data[:argument_names].size, args.size)
|
203
|
+
|
204
|
+
local_env = Env.new
|
205
|
+
chained_env = ChainedEnv.new(local_env, env)
|
206
|
+
|
207
|
+
env.global_loop_data[:argument_names].each_with_index do |key, idx|
|
208
|
+
local_env[key] = args[idx].resolve_and_eval(env)
|
209
|
+
end
|
210
|
+
|
211
|
+
env.global_loop_data[:operations].map do |op|
|
212
|
+
op.resolve_and_eval(chained_env)
|
213
|
+
end.last
|
214
|
+
end.bind('recur', current_env)
|
215
|
+
|
99
216
|
# .
|
100
217
|
# perform a native call on an object with optional arguments
|
101
218
|
#
|
@@ -103,12 +220,42 @@ module Crisp
|
|
103
220
|
# => "ABC"
|
104
221
|
Function.new do
|
105
222
|
meth = args[0].text_value.to_sym
|
106
|
-
target = args[1].
|
223
|
+
target = if args[1].class.name == "Crisp::Nodes::SymbolLiteral" and !env.has_key?(args[1].text_value)
|
224
|
+
Object.const_get(args[1].text_value)
|
225
|
+
else
|
226
|
+
args[1].resolve_and_eval(env)
|
227
|
+
end
|
107
228
|
values = args[2..-1].map { |arg| arg.resolve_and_eval(env) }
|
108
229
|
|
109
230
|
NativeCallInvoker.new(target, meth, values).invoke!
|
110
231
|
end.bind('.', current_env)
|
111
232
|
|
233
|
+
# load
|
234
|
+
# include content of another crisp source file
|
235
|
+
#
|
236
|
+
# (load "business_logic")
|
237
|
+
# => true
|
238
|
+
Function.new do
|
239
|
+
args_evaled.collect(&:to_s).each do |filename|
|
240
|
+
pwd = `pwd`.strip
|
241
|
+
file = if filename[0..1] == '/'
|
242
|
+
File.join(pwd, filename)
|
243
|
+
else
|
244
|
+
filename
|
245
|
+
end.sub(".crisp$", '') + '.crisp'
|
246
|
+
|
247
|
+
if !File.exists?(file)
|
248
|
+
raise Crisp::ArgumentError, "file #{file} not found"
|
249
|
+
end
|
250
|
+
|
251
|
+
filecontent = File.read(file)
|
252
|
+
ast = Crisp::Parser.new.parse(filecontent)
|
253
|
+
Crisp::Runtime.new(env).run(ast)
|
254
|
+
end
|
255
|
+
|
256
|
+
true
|
257
|
+
end.bind('load', current_env)
|
258
|
+
|
112
259
|
end
|
113
260
|
end
|
114
261
|
end
|
data/lib/crisp/nodes/block.rb
CHANGED
@@ -4,13 +4,9 @@ module Crisp
|
|
4
4
|
class Block < Base
|
5
5
|
# eval each element of the block and return the last result
|
6
6
|
def eval(env)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
last_result = op.resolve_and_eval(env)
|
11
|
-
end
|
12
|
-
|
13
|
-
last_result
|
7
|
+
elements.map do |op|
|
8
|
+
op.resolve_and_eval(env)
|
9
|
+
end.last
|
14
10
|
end
|
15
11
|
|
16
12
|
# a block resolves to itself
|
@@ -5,9 +5,9 @@ module Crisp
|
|
5
5
|
# get the function binded to the given function name and eval it (including arguments)
|
6
6
|
def eval(env)
|
7
7
|
if self.func_identifier.class.name == "Crisp::Nodes::Operation"
|
8
|
-
self.func_identifier.eval(env).eval(env,
|
8
|
+
self.func_identifier.eval(env).eval(env, raw_element_list)
|
9
9
|
else
|
10
|
-
env[self.func_identifier.text_value].eval(env,
|
10
|
+
env[self.func_identifier.text_value].eval(env, raw_element_list)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -15,6 +15,12 @@ module Crisp
|
|
15
15
|
def resolve(env)
|
16
16
|
self
|
17
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def raw_element_list
|
22
|
+
self.element_list.elements.collect(&:element)
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
data/lib/crisp/runtime.rb
CHANGED
@@ -6,9 +6,9 @@ module Crisp
|
|
6
6
|
# Run code by calling run with the output of the parser as argurment.
|
7
7
|
class Runtime
|
8
8
|
# create a new env and load all functions when creating a new runtime
|
9
|
-
def initialize
|
10
|
-
@env = Env.new
|
11
|
-
Functions.load(@env)
|
9
|
+
def initialize(env = nil)
|
10
|
+
@env = env || Env.new
|
11
|
+
Functions.load(@env) if !env
|
12
12
|
end
|
13
13
|
|
14
14
|
# run the parsed code (abstract syntax tree)
|
data/spec/crisp/basic_spec.rb
CHANGED
@@ -3,17 +3,17 @@ require 'spec_helper'
|
|
3
3
|
describe "the language" do
|
4
4
|
include Crisp::SpecHelper
|
5
5
|
|
6
|
-
it "does not bother
|
6
|
+
it "does not bother whitspace characters in expressions" do
|
7
7
|
evaluate(" \r\t\n (\r+\t 1\n2 \t(\n - 9\r\t \n 2)\r)\r\t ").should == 10
|
8
8
|
end
|
9
9
|
|
10
|
-
it "
|
10
|
+
it "raises a syntax error on invalid expressions" do
|
11
11
|
lambda do
|
12
12
|
evaluate("(()")
|
13
13
|
end.should raise_error(Crisp::SyntaxError, "syntax error at : 0")
|
14
14
|
end
|
15
15
|
|
16
|
-
it "
|
16
|
+
it "binds arrays to symbols" do
|
17
17
|
evaluate("(def bla [1 2 3])").size.should == 3
|
18
18
|
evaluate("(def bla [1 2 3])")[1].should == 2
|
19
19
|
evaluate("(def foo 5)(def bla [1 2 foo])")[2].should == 5
|
data/spec/crisp/core_spec.rb
CHANGED
@@ -80,4 +80,140 @@ describe "the core language features" do
|
|
80
80
|
it "resolves symbols in if statements" do
|
81
81
|
evaluate("(def foo 2)(if true foo)").should == 2
|
82
82
|
end
|
83
|
+
|
84
|
+
it "uses local binding with let" do
|
85
|
+
evaluate("(let [x 1] x)").should == 1
|
86
|
+
end
|
87
|
+
|
88
|
+
it "uses more complex local bindings with let" do
|
89
|
+
evaluate("(let [x 2 y x] (* x y))").should == 4
|
90
|
+
end
|
91
|
+
|
92
|
+
it "evaluates several expressions within local binding" do
|
93
|
+
evaluate("(let [x 2 y 3] (* x y) (+ x y))").should == 5
|
94
|
+
end
|
95
|
+
|
96
|
+
it "binds symbols to global binding within local binding" do
|
97
|
+
evaluate("(let [x 1 y 2] (def foo (+ x y))) foo").should == 3
|
98
|
+
end
|
99
|
+
|
100
|
+
it "overrides global binding within local binding" do
|
101
|
+
evaluate("(def x 1)(let [x 2] x)").should == 2
|
102
|
+
end
|
103
|
+
|
104
|
+
it "ensures that local binding is only valid within let" do
|
105
|
+
evaluate("(def x 1)(let [x 2] x) x").should == 1
|
106
|
+
end
|
107
|
+
|
108
|
+
it "can handle emtpy local binding" do
|
109
|
+
evaluate("(let [] 2)").should == 2
|
110
|
+
end
|
111
|
+
|
112
|
+
it "raises an error when calling let without correct argument" do
|
113
|
+
lambda do
|
114
|
+
evaluate("(let 2 2)")
|
115
|
+
end.should raise_error(Crisp::ArgumentError, "no argument list defined")
|
116
|
+
end
|
117
|
+
|
118
|
+
it "raises an error when calling let with odd binding list" do
|
119
|
+
lambda do
|
120
|
+
evaluate("(let [x 1 y] 2)")
|
121
|
+
end.should raise_error(Crisp::ArgumentError, "argument list has to contain even list of arguments")
|
122
|
+
end
|
123
|
+
|
124
|
+
it "raises an error if file to be load not there" do
|
125
|
+
lambda do
|
126
|
+
evaluate('(load "not_there")')
|
127
|
+
end.should raise_error(Crisp::ArgumentError, /file (.*) not found/)
|
128
|
+
|
129
|
+
lambda do
|
130
|
+
evaluate('(load "/not_there")')
|
131
|
+
end.should raise_error(Crisp::ArgumentError, "file /not_there.crisp not found")
|
132
|
+
end
|
133
|
+
|
134
|
+
it "loads other crisp files" do
|
135
|
+
File.open("/tmp/crisp_test_file.crisp", 'w') do |f|
|
136
|
+
f << "(def foo 123)"
|
137
|
+
end
|
138
|
+
|
139
|
+
evaluate('(load "/tmp/crisp_test_file")(+ 1 foo)').should == 124
|
140
|
+
end
|
141
|
+
|
142
|
+
it "uses the current environment when loading other crisp source files" do
|
143
|
+
File.open("/tmp/crisp_test_file.crisp", 'w') do |f|
|
144
|
+
f << "(def bla 123)"
|
145
|
+
end
|
146
|
+
|
147
|
+
lambda do
|
148
|
+
evaluate('(def bla 321)(load "/tmp/crisp_test_file")')
|
149
|
+
end.should raise_error(Crisp::EnvironmentError, "bla already binded")
|
150
|
+
end
|
151
|
+
|
152
|
+
it "raises an error if calling cond with wrong number of arguments" do
|
153
|
+
lambda do
|
154
|
+
evaluate("(cond false 1 true)")
|
155
|
+
end.should raise_error(Crisp::ArgumentError, "argument list has to contain even list of arguments")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "has cond statement" do
|
159
|
+
evaluate("(cond)").should == nil
|
160
|
+
evaluate("(cond false 1 false 2)").should == nil
|
161
|
+
evaluate("(cond true 3)").should == 3
|
162
|
+
evaluate("(cond true 3 false 2)").should == 3
|
163
|
+
evaluate("(cond false 3 true 2)").should == 2
|
164
|
+
evaluate("(cond (= 1 1) (+ 1 1))").should == 2
|
165
|
+
evaluate("(cond true 3 true 2 true 1)").should == 3
|
166
|
+
end
|
167
|
+
|
168
|
+
it "does not eval expressions for unmatched condition" do
|
169
|
+
evaluate("(cond false (def foo 1) true 2)(def foo 2) foo").should == 2
|
170
|
+
end
|
171
|
+
|
172
|
+
it "has a default condition in cond" do
|
173
|
+
evaluate("(cond false 1 true 2 else 3)").should == 2
|
174
|
+
evaluate("(cond true 1 true 2 else 3)").should == 1
|
175
|
+
evaluate("(cond false 1 else 2 true 3)").should == 2
|
176
|
+
end
|
177
|
+
|
178
|
+
it "raises an error when calling loop without correct argument" do
|
179
|
+
lambda do
|
180
|
+
evaluate("(loop 2 2)")
|
181
|
+
end.should raise_error(Crisp::ArgumentError, "no argument list defined")
|
182
|
+
end
|
183
|
+
|
184
|
+
it "raises an error when calling loop with odd binding list" do
|
185
|
+
lambda do
|
186
|
+
evaluate("(loop [x 1 y] 2)")
|
187
|
+
end.should raise_error(Crisp::ArgumentError, "argument list has to contain even list of arguments")
|
188
|
+
end
|
189
|
+
|
190
|
+
it "raises an error when calling recur outside a loop" do
|
191
|
+
lambda do
|
192
|
+
evaluate("(recur 1)")
|
193
|
+
end.should raise_error(Crisp::LoopError, "recur called outside loop")
|
194
|
+
end
|
195
|
+
|
196
|
+
it "raises an error when calling recur with wrong number of arguments" do
|
197
|
+
lambda do
|
198
|
+
evaluate("(loop [x 1] (recur 1 2))")
|
199
|
+
end.should raise_error(Crisp::ArgumentError, "wrong number of arguments for 'recur' (2 for 1)")
|
200
|
+
end
|
201
|
+
|
202
|
+
it "calculates factorials using loop recur" do
|
203
|
+
evaluate("
|
204
|
+
(def factorial
|
205
|
+
(fn [n]
|
206
|
+
(loop [cnt n acc 1]
|
207
|
+
(if (= 0 cnt)
|
208
|
+
acc
|
209
|
+
(recur (- cnt 1) (* acc cnt))))))
|
210
|
+
(factorial 5)
|
211
|
+
").should == 120
|
212
|
+
end
|
213
|
+
|
214
|
+
it "raises an error when nesting loops" do
|
215
|
+
lambda do
|
216
|
+
evaluate("(loop [x 1] (loop [a 1 b 2] (+ a b)))")
|
217
|
+
end.should raise_error(Crisp::LoopError, "nested loops are not allowed")
|
218
|
+
end
|
83
219
|
end
|
data/spec/crisp/function_spec.rb
CHANGED
@@ -15,10 +15,11 @@ describe "the languages functions" do
|
|
15
15
|
end.should raise_error(Crisp::ArgumentError, "no argument list defined")
|
16
16
|
end
|
17
17
|
|
18
|
-
it "does
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
it "does return primitive values as result" do
|
19
|
+
evaluate("((fn [] 1))").should == 1
|
20
|
+
evaluate('((fn [] "abc"))').should == 'abc'
|
21
|
+
evaluate('((fn [] [1 2 3]))').should == [1, 2, 3]
|
22
|
+
evaluate("((fn [x] x) 2)").should == 2
|
22
23
|
end
|
23
24
|
|
24
25
|
it "creates functions" do
|
@@ -3,21 +3,27 @@ require 'spec_helper'
|
|
3
3
|
describe "NativeCallInvoker functionality" do
|
4
4
|
include Crisp::SpecHelper
|
5
5
|
|
6
|
-
it "
|
6
|
+
it "executes ruby native String#reverse" do
|
7
7
|
evaluate('(. reverse "foobar")').should == 'raboof'
|
8
8
|
end
|
9
9
|
|
10
|
-
it "
|
10
|
+
it "executes ruby native Array#first" do
|
11
11
|
evaluate('(. first [1 2 3])').should == 1
|
12
12
|
end
|
13
13
|
|
14
|
-
it "
|
14
|
+
it "executes ruby native Array#first(n)" do
|
15
15
|
evaluate('(. first [1 2 3] 2)').should == [1,2]
|
16
16
|
end
|
17
17
|
|
18
|
-
it "
|
18
|
+
it "raises a named exception on invalid method" do
|
19
19
|
lambda do
|
20
20
|
evaluate('(. foo "bar")')
|
21
21
|
end.should raise_error(NoMethodError, %q{undefined method `foo' for "bar":String})
|
22
22
|
end
|
23
|
+
|
24
|
+
it "executes calls on Ruby classes" do
|
25
|
+
evaluate("(. new String)").should == ''
|
26
|
+
evaluate('(. new String "123")').should == '123'
|
27
|
+
evaluate("(. new Array 5 2)").should == [2, 2, 2, 2, 2]
|
28
|
+
end
|
23
29
|
end
|
data/spec/crisp/string_spec.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crisp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 8
|
10
|
+
version: 0.0.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Markus Gerdes
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-06 00:00:00 +01:00
|
19
19
|
default_executable: crisp
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -42,12 +42,12 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
45
|
+
hash: 31
|
46
46
|
segments:
|
47
47
|
- 2
|
48
|
-
-
|
48
|
+
- 4
|
49
49
|
- 0
|
50
|
-
version: 2.
|
50
|
+
version: 2.4.0
|
51
51
|
type: :development
|
52
52
|
version_requirements: *id002
|
53
53
|
description:
|
@@ -67,7 +67,9 @@ files:
|
|
67
67
|
- autotest/discover.rb
|
68
68
|
- bin/crisp
|
69
69
|
- crisp.gemspec
|
70
|
+
- examples/factorial.crisp
|
70
71
|
- examples/fibonacci.crisp
|
72
|
+
- examples/run.crisp
|
71
73
|
- lib/crisp.rb
|
72
74
|
- lib/crisp/chained_env.rb
|
73
75
|
- lib/crisp/crisp.treetop
|