rubylisp 0.2.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +129 -2
  3. data/bin/rubylisp +87 -12
  4. data/lib/rubylisp/atom.rb +25 -6
  5. data/lib/rubylisp/boolean.rb +9 -6
  6. data/lib/rubylisp/builtins.rb +19 -18
  7. data/lib/rubylisp/character.rb +14 -275
  8. data/lib/rubylisp/class_object.rb +56 -0
  9. data/lib/rubylisp/cons_cell.rb +56 -25
  10. data/lib/rubylisp/debug.rb +15 -19
  11. data/lib/rubylisp/environment.rb +27 -0
  12. data/lib/rubylisp/environment_frame.rb +31 -6
  13. data/lib/rubylisp/eof_object.rb +26 -0
  14. data/lib/rubylisp/exception.rb +61 -61
  15. data/lib/rubylisp/ext.rb +32 -6
  16. data/lib/rubylisp/ffi_new.rb +2 -1
  17. data/lib/rubylisp/ffi_send.rb +15 -5
  18. data/lib/rubylisp/frame.rb +5 -164
  19. data/lib/rubylisp/function.rb +4 -3
  20. data/lib/rubylisp/macro.rb +13 -8
  21. data/lib/rubylisp/{object.rb → native_object.rb} +0 -15
  22. data/lib/rubylisp/number.rb +5 -0
  23. data/lib/rubylisp/parser.rb +81 -52
  24. data/lib/rubylisp/port.rb +27 -0
  25. data/lib/rubylisp/prim_alist.rb +115 -0
  26. data/lib/rubylisp/prim_assignment.rb +61 -0
  27. data/lib/rubylisp/prim_character.rb +273 -0
  28. data/lib/rubylisp/{ffi_class.rb → prim_class_object.rb} +16 -69
  29. data/lib/rubylisp/prim_environment.rb +203 -0
  30. data/lib/rubylisp/prim_equivalence.rb +93 -0
  31. data/lib/rubylisp/prim_frame.rb +166 -0
  32. data/lib/rubylisp/prim_io.rb +266 -0
  33. data/lib/rubylisp/prim_list_support.rb +496 -0
  34. data/lib/rubylisp/{logical.rb → prim_logical.rb} +9 -14
  35. data/lib/rubylisp/prim_math.rb +397 -0
  36. data/lib/rubylisp/prim_native_object.rb +21 -0
  37. data/lib/rubylisp/prim_relational.rb +42 -0
  38. data/lib/rubylisp/{special_forms.rb → prim_special_forms.rb} +98 -85
  39. data/lib/rubylisp/prim_string.rb +792 -0
  40. data/lib/rubylisp/prim_system.rb +55 -0
  41. data/lib/rubylisp/prim_type_checks.rb +58 -0
  42. data/lib/rubylisp/prim_vector.rb +497 -0
  43. data/lib/rubylisp/primitive.rb +51 -6
  44. data/lib/rubylisp/string.rb +4 -803
  45. data/lib/rubylisp/symbol.rb +0 -1
  46. data/lib/rubylisp/tokenizer.rb +161 -137
  47. data/lib/rubylisp/vector.rb +10 -31
  48. data/lib/rubylisp.rb +1 -0
  49. metadata +46 -17
  50. data/lib/rubylisp/alist.rb +0 -230
  51. data/lib/rubylisp/assignment.rb +0 -65
  52. data/lib/rubylisp/equivalence.rb +0 -118
  53. data/lib/rubylisp/io.rb +0 -74
  54. data/lib/rubylisp/list_support.rb +0 -526
  55. data/lib/rubylisp/math.rb +0 -405
  56. data/lib/rubylisp/relational.rb +0 -46
  57. data/lib/rubylisp/system.rb +0 -20
  58. data/lib/rubylisp/testing.rb +0 -136
  59. data/lib/rubylisp/type_checks.rb +0 -60
@@ -1,809 +1,6 @@
1
1
  module Lisp
2
2
 
3
3
  class String < Atom
4
-
5
- def self.register
6
- Primitive.register("str") {|args, env| Lisp::String::str_impl(args, env) }
7
- Primitive.register("string?") {|args, env| Lisp::String::stringp_impl(args, env) }
8
- Primitive.register("make-string") {|args, env| Lisp::String::make_string_impl(args, env) }
9
- Primitive.register("string") {|args, env| Lisp::String::string_impl(args, env) }
10
- Primitive.register("list->string") {|args, env| Lisp::String::list_string_impl(args, env) }
11
- Primitive.register("string->list") {|args, env| Lisp::String::string_list_impl(args, env) }
12
- Primitive.register("string-copy") {|args, env| Lisp::String::string_copy_impl(args, env) }
13
- Primitive.register("string-length") {|args, env| Lisp::String::string_length_impl(args, env) }
14
- Primitive.register("string-null?") {|args, env| Lisp::String::string_nullp_impl(args, env) }
15
- Primitive.register("string-ref") {|args, env| Lisp::String::string_ref_impl(args, env) }
16
- Primitive.register("string-set!") {|args, env| Lisp::String::string_set_impl(args, env) }
17
-
18
- Primitive.register("string=?") {|args, env| Lisp::String::string_eq_impl(args, env) }
19
- Primitive.register("substring=?") {|args, env| Lisp::String::substring_eq_impl(args, env) }
20
- Primitive.register("string-ci=?") {|args, env| Lisp::String::string_ci_eq_impl(args, env) }
21
- Primitive.register("substring-ci=?") {|args, env| Lisp::String::substring_ci_eq_impl(args, env) }
22
-
23
- Primitive.register("string<?") {|args, env| Lisp::String::string_lt_impl(args, env) }
24
- Primitive.register("substring<?") {|args, env| Lisp::String::substring_lt_impl(args, env) }
25
- Primitive.register("string-ci<?") {|args, env| Lisp::String::string_ci_lt_impl(args, env) }
26
- Primitive.register("substring-ci<?") {|args, env| Lisp::String::substring_ci_lt_impl(args, env) }
27
-
28
- Primitive.register("string>?") {|args, env| Lisp::String::string_gt_impl(args, env) }
29
- Primitive.register("substring>?") {|args, env| Lisp::String::substring_gt_impl(args, env) }
30
- Primitive.register("string-ci>?") {|args, env| Lisp::String::string_ci_gt_impl(args, env) }
31
- Primitive.register("substring-ci>?") {|args, env| Lisp::String::substring_ci_gt_impl(args, env) }
32
-
33
- Primitive.register("string<=?") {|args, env| Lisp::String::string_lte_impl(args, env) }
34
- Primitive.register("substring<=?") {|args, env| Lisp::String::substring_lte_impl(args, env) }
35
- Primitive.register("string-ci<=?") {|args, env| Lisp::String::string_ci_lte_impl(args, env) }
36
- Primitive.register("substring-ci<=?") {|args, env| Lisp::String::substring_ci_lte_impl(args, env) }
37
-
38
- Primitive.register("string>=?") {|args, env| Lisp::String::string_gte_impl(args, env) }
39
- Primitive.register("substring>=?") {|args, env| Lisp::String::substring_gte_impl(args, env) }
40
- Primitive.register("string-ci>=?") {|args, env| Lisp::String::string_ci_gte_impl(args, env) }
41
- Primitive.register("substring-ci>=?") {|args, env| Lisp::String::substring_ci_gte_impl(args, env) }
42
-
43
- Primitive.register("string-compare") {|args, env| Lisp::String::string_compare_impl(args, env) }
44
- Primitive.register("string-compare-ci") {|args, env| Lisp::String::string_compare_ci_impl(args, env) }
45
-
46
- Primitive.register("string-hash") {|args, env| Lisp::String::string_hash_impl(args, env) }
47
- Primitive.register("string-hash-mod") {|args, env| Lisp::String::string_hash_mod_impl(args, env) }
48
-
49
- Primitive.register("string-capitalized?") {|args, env| Lisp::String::string_capitalizedp_impl(args, env) }
50
- Primitive.register("substring-capitalized?") {|args, env| Lisp::String::substring_capitalizedp_impl(args, env) }
51
- Primitive.register("string-upper-case?") {|args, env| Lisp::String::string_upperp_impl(args, env) }
52
- Primitive.register("substring-upper-case?") {|args, env| Lisp::String::substring_upperp_impl(args, env) }
53
- Primitive.register("string-lower-case?") {|args, env| Lisp::String::string_lowerp_impl(args, env) }
54
- Primitive.register("substring-lower-case?") {|args, env| Lisp::String::substring_lowerp_impl(args, env) }
55
-
56
- Primitive.register("string-capitalize") {|args, env| Lisp::String::string_capitalize_impl(args, env) }
57
- Primitive.register("string-capitalize!") {|args, env| Lisp::String::string_capitalize_bang_impl(args, env) }
58
- Primitive.register("substring-capitalize!") {|args, env| Lisp::String::substring_capitalize_bang_impl(args, env) }
59
- Primitive.register("string-downcase") {|args, env| Lisp::String::string_downcase_impl(args, env) }
60
- Primitive.register("string-downcase!") {|args, env| Lisp::String::string_downcase_bang_impl(args, env) }
61
- Primitive.register("substring-downcase!") {|args, env| Lisp::String::substring_downcase_bang_impl(args, env) }
62
- Primitive.register("string-upcase") {|args, env| Lisp::String::string_upcase_impl(args, env) }
63
- Primitive.register("string-upcase!") {|args, env| Lisp::String::string_upcase_bang_impl(args, env) }
64
- Primitive.register("substring-upcase!") {|args, env| Lisp::String::substring_upcase_bang_impl(args, env) }
65
-
66
- Primitive.register("string-append") {|args, env| Lisp::String::string_append_impl(args, env) }
67
- Primitive.register("substring") {|args, env| Lisp::String::substring_impl(args, env) }
68
- Primitive.register("string-head") {|args, env| Lisp::String::string_head_impl(args, env) }
69
- Primitive.register("string-tail") {|args, env| Lisp::String::string_tail_impl(args, env) }
70
-
71
- Primitive.register("string-pad-left") {|args, env| Lisp::String::string_pad_left_impl(args, env) }
72
- Primitive.register("string-pad-right") {|args, env| Lisp::String::string_pad_right_impl(args, env) }
73
-
74
- Primitive.register("string-trim") {|args, env| Lisp::String::string_trim_impl(args, env) }
75
- Primitive.register("string-trim-right") {|args, env| Lisp::String::string_trim_right_impl(args, env) }
76
- Primitive.register("string-trim-left") {|args, env| Lisp::String::string_trim_left_impl(args, env) }
77
- end
78
-
79
- def self.str_impl(args, env)
80
- strings = args.to_a.map {|e| e.evaluate(env).to_s}
81
- String.with_value(strings.join)
82
- end
83
-
84
-
85
- def self.stringp_impl(args, env)
86
- return Lisp::Debug.process_error("string? requires 1 argument", env) unless args.length == 1
87
- return Lisp::Boolean.with_value(args.car.evaluate(env).string?)
88
- end
89
-
90
-
91
- def self.make_string_impl(args, env)
92
- return Lisp::Debug.process_error("make-string need requires at least 1 argument", env) unless args.length > 0
93
- return Lisp::Debug.process_error("make-string accepts at most 2 arguments, but was passed #{args.length}", env) if args.length > 2
94
- k_arg = args.car.evaluate(env)
95
- return Lisp::Debug.process_error("make-string requires an integer as it's first argument.", env) unless k_arg.integer?
96
- k = k_arg.value
97
- c = if args.length == 2
98
- c_arg = args.cadr.evaluate(env)
99
- return Lisp::Debug.process_error("make-string requires a character as it's second argument, but received #{c_arg}.", env) unless c_arg.character?
100
- c_arg.value
101
- else
102
- " "
103
- end
104
- self.with_value(c * k)
105
- end
106
-
107
-
108
- def self.string_impl(args, env)
109
- chars = args.to_a.map do |a|
110
- ea = a.evaluate(env)
111
- return Lisp::Debug.process_error("string requires character args, but was passed #{ea}.", env) unless ea.character?
112
- ea.value
113
- end
114
- self.with_value(chars.join)
115
- end
116
-
117
-
118
- def self.list_string_impl(args, env)
119
- return Lisp::Debug.process_error("list->string requires 1 argument, but received #{args.length}", env) unless args.length == 1
120
- list_of_chars = args.car.evaluate(env)
121
- return Lisp::Debug.process_error("list->string requires a list argument, but received #{str_arg}", env) unless list_of_chars.list?
122
- chars = list_of_chars.to_a.map do |a|
123
- ea = a.evaluate(env)
124
- return Lisp::Debug.process_error("string requires a list of characters, but it contained #{ea}.", env) unless ea.character?
125
- ea.value
126
- end
127
- self.with_value(chars.join)
128
- end
129
-
130
-
131
- def self.string_list_impl(args, env)
132
- return Lisp::Debug.process_error("string->list requires 1 argument, but received #{args.length}", env) unless args.length == 1
133
- str_arg = args.car.evaluate(env)
134
- return Lisp::Debug.process_error("string->list requires a string argument, but received #{str_arg}", env) unless str_arg.string?
135
- chars = str_arg.value.each_char.map {|c| Lisp::Character.find_character_for_chr(c) }
136
- Lisp::ConsCell.array_to_list(chars)
137
- end
138
-
139
-
140
- def self.string_copy_impl(args, env)
141
- return Lisp::Debug.process_error("string-copy requires 1 argument, but received #{args.length}", env) unless args.length == 1
142
- str_arg = args.car.evaluate(env)
143
- return Lisp::Debug.process_error("string-copy requires a string argument, but received #{str_arg}", env) unless str_arg.string?
144
- self.with_value(str_arg.value)
145
- end
146
-
147
-
148
- def self.string_length_impl(args, env)
149
- return Lisp::Debug.process_error("string-length requires 1 argument, but received #{args.length}", env) unless args.length == 1
150
- str_arg = args.car.evaluate(env)
151
- return Lisp::Debug.process_error("string-length requires a string argument, but received #{str_arg}", env) unless str_arg.string?
152
- Lisp::Number.with_value(str_arg.value.length)
153
- end
154
-
155
-
156
- def self.string_nullp_impl(args, env)
157
- return Lisp::Debug.process_error("string-length requires 1 argument, but received #{args.length}", env) unless args.length == 1
158
- str_arg = args.car.evaluate(env)
159
- return Lisp::Debug.process_error("string-length requires a string argument, but received #{str_arg}", env) unless str_arg.string?
160
- Lisp::Boolean.with_value(str_arg.value.length == 0)
161
- end
162
-
163
-
164
- def self.string_ref_impl(args, env)
165
- return Lisp::Debug.process_error("string-ref requires 2 arguments, but received #{args.length}", env) unless args.length == 2
166
- str_arg = args.car.evaluate(env)
167
- return Lisp::Debug.process_error("string-ref requires a string as it's first argument, but received #{arg.car}", env) unless str_arg.string?
168
- str = str_arg.value
169
- k_arg = args.cadr.evaluate(env)
170
- return Lisp::Debug.process_error("string-ref requires it's second argument to be an integer, but received #{k_arg}", env) unless k_arg.integer?
171
- k = k_arg.value
172
- return Lisp::FALSE if k < 0 || k >= str.length
173
- Lisp::Character.find_character_for_chr(str[k])
174
- end
175
-
176
-
177
- def self.string_set_impl(args, env)
178
- return Lisp::Debug.process_error("string-set! needs 3 arguments, but received #{args.length}", env) unless args.length == 3
179
- str_arg = args.car.evaluate(env)
180
- return Lisp::Debug.process_error("string-set! needs a string as it's first argument, but received #{str_arg}", env) unless str_arg.string?
181
- str = str_arg.value
182
- k_arg = args.cadr.evaluate(env)
183
- return Lisp::Debug.process_error("string-set! requires an integer as it's second argument, but received #{k_arg}", env) unless k_arg.integer?
184
- k = k_arg.value
185
- return Lisp::FALSE if k < 0 || k >= str.length
186
- replacement_arg = args.caddr.evaluate(env)
187
- return Lisp::Debug.process_error("string-set! requires a character as it's third argument, but received #{replacement_arg}", env) unless replacement_arg.character?
188
- replacement = replacement_arg.value
189
- str[k] = replacement
190
- self.with_value(str)
191
- end
192
-
193
-
194
- def self.get_substring(func, str, start_index, end_index)
195
- return Lisp::Debug.process_error("#{func} requires a string, but received #{str}", env) unless str.string?
196
- s = str.value
197
- return Lisp::Debug.process_error("#{func} requires an integer start index, but received #{start_index}", env) unless start_index.integer?
198
- si = start_index.value
199
- return Lisp::Debug.process_error("#{func} received an invalid substring start index: #{si}", env) if si < 0 || si > s.length
200
- return Lisp::Debug.process_error("#{func} requires an integer end index, but received #{end_index}", env) unless end_index.integer?
201
- ei = end_index.value
202
- return Lisp::Debug.process_error("#{func} received an invalid substring end index: #{ei}", env) if ei < 0 || ei > s.length
203
- s[si...ei]
204
- end
205
-
206
-
207
- def self.extract_substrings(func, args, env)
208
- return Lisp::Debug.process_error("#{func} requires 6 arguments, but received #{args.length}", env) unless args.length == 6
209
- substr1 = get_substring(func, args.nth(1).evaluate(env), args.nth(2).evaluate(env), args.nth(3).evaluate(env))
210
- substr2 = get_substring(func, args.nth(4).evaluate(env), args.nth(5).evaluate(env), args.nth(6).evaluate(env))
211
- return [substr1, substr2]
212
- end
213
-
214
-
215
- def self.get_string(func, str)
216
- return Lisp::Debug.process_error("#{func} requires a string, but received #{str}", env) unless str.string?
217
- str.value
218
- end
219
-
220
-
221
- def self.extract_strings(func, args, env)
222
- return Lisp::Debug.process_error("#{func} requires 2 arguments, but received #{args.length}", env) unless args.length == 2
223
- str1 = get_string(func, args.nth(1).evaluate(env))
224
- str2 = get_string(func, args.nth(2).evaluate(env))
225
- return [str1, str2]
226
- end
227
-
228
-
229
- def self.string_eq_impl(args, env)
230
- str1, str2 = extract_strings("string=?", args, env)
231
- Lisp::Boolean.with_value(str1 == str2)
232
- end
233
-
234
-
235
- def self.substring_eq_impl(args, env)
236
- substr1, substr2 = extract_substrings("substring=?", args, env)
237
- Lisp::Boolean.with_value(substr1 == substr2)
238
- end
239
-
240
-
241
- def self.string_ci_eq_impl(args, env)
242
- str1, str2 = extract_strings("string-ci=?", args, env)
243
- Lisp::Boolean.with_value(str1.downcase == str2.downcase)
244
- end
245
-
246
-
247
- def self.substring_ci_eq_impl(args, env)
248
- substr1, substr2 = extract_substrings("substring-ci=?", args, env)
249
- Lisp::Boolean.with_value(substr1.downcase == substr2.downcase)
250
- end
251
-
252
-
253
- def self.string_lt_impl(args, env)
254
- str1, str2 = extract_strings("string<?", args, env)
255
- Lisp::Boolean.with_value(str1 < str2)
256
- end
257
-
258
-
259
- def self.substring_lt_impl(args, env)
260
- substr1, substr2 = extract_substrings("substring<?", args, env)
261
- Lisp::Boolean.with_value(substr1 < substr2)
262
- end
263
-
264
-
265
- def self.string_ci_lt_impl(args, env)
266
- str1, str2 = extract_strings("string-ci<?", args, env)
267
- Lisp::Boolean.with_value(str1.downcase < str2.downcase)
268
- end
269
-
270
-
271
- def self.substring_ci_lt_impl(args, env)
272
- substr1, substr2 = extract_substrings("substring-ci<?", args, env)
273
- Lisp::Boolean.with_value(substr1.downcase < substr2.downcase)
274
- end
275
-
276
-
277
- def self.string_gt_impl(args, env)
278
- str1, str2 = extract_strings("string>?", args, env)
279
- Lisp::Boolean.with_value(str1 > str2)
280
- end
281
-
282
-
283
- def self.substring_gt_impl(args, env)
284
- substr1, substr2 = extract_substrings("substring>?", args, env)
285
- Lisp::Boolean.with_value(substr1 > substr2)
286
- end
287
-
288
-
289
- def self.string_ci_gt_impl(args, env)
290
- str1, str2 = extract_strings("string-ci>?", args, env)
291
- Lisp::Boolean.with_value(str1.downcase > str2.downcase)
292
- end
293
-
294
-
295
- def self.substring_ci_gt_impl(args, env)
296
- substr1, substr2 = extract_substrings("substring-ci>?", args, env)
297
- Lisp::Boolean.with_value(substr1.downcase > substr2.downcase)
298
- end
299
-
300
-
301
- def self.string_lte_impl(args, env)
302
- str1, str2 = extract_strings("string<=?", args, env)
303
- Lisp::Boolean.with_value(str1 <= str2)
304
- end
305
-
306
-
307
- def self.substring_lte_impl(args, env)
308
- substr1, substr2 = extract_substrings("substring<=?", args, env)
309
- Lisp::Boolean.with_value(substr1 <= substr2)
310
- end
311
-
312
-
313
- def self.string_ci_lte_impl(args, env)
314
- str1, str2 = extract_strings("string-ci<=?", args, env)
315
- Lisp::Boolean.with_value(str1.downcase <= str2.downcase)
316
- end
317
-
318
-
319
- def self.substring_ci_lte_impl(args, env)
320
- substr1, substr2 = extract_substrings("substring-ci<=?", args, env)
321
- Lisp::Boolean.with_value(substr1.downcase <= substr2.downcase)
322
- end
323
-
324
-
325
- def self.string_gte_impl(args, env)
326
- str1, str2 = extract_strings("string>=?", args, env)
327
- Lisp::Boolean.with_value(str1 >= str2)
328
- end
329
-
330
-
331
- def self.substring_gte_impl(args, env)
332
- substr1, substr2 = extract_substrings("substring>=?", args, env)
333
- Lisp::Boolean.with_value(substr1 >= substr2)
334
- end
335
-
336
-
337
- def self.string_ci_gte_impl(args, env)
338
- str1, str2 = extract_strings("string-ci>=?", args, env)
339
- Lisp::Boolean.with_value(str1.downcase >= str2.downcase)
340
- end
341
-
342
-
343
- def self.substring_ci_gte_impl(args, env)
344
- substr1, substr2 = extract_substrings("substring-ci>=?", args, env)
345
- Lisp::Boolean.with_value(substr1.downcase >= substr2.downcase)
346
- end
347
-
348
-
349
- def self.string_compare_impl(args, env)
350
- return Lisp::Debug.process_error("string-compare requires 5 arguments, but received #{args.length}", env) unless args.length == 5
351
- str1 = get_string("string-compare", args.nth(1).evaluate(env))
352
- str2 = get_string("string-compare", args.nth(2).evaluate(env))
353
- f_number = case str1 <=> str2
354
- when -1
355
- 4
356
- when 0
357
- 3
358
- when 1
359
- 5
360
- end
361
- f = args.nth(f_number).evaluate(env)
362
- return Lisp::Debug.process_error("string-compare requires functions for argument #{f_number}, but received #{f}", env) unless f.function?
363
- f.apply_to(Lisp::ConsCell.cons, env)
364
- end
365
-
366
-
367
- def self.string_compare_ci_impl(args, env)
368
- return Lisp::Debug.process_error("string-compare-ci requires 5 arguments, but received #{args.length}", env) unless args.length == 5
369
- str1 = get_string("string-compare-ci", args.nth(1).evaluate(env))
370
- str2 = get_string("string-compare-ci", args.nth(2).evaluate(env))
371
- f_number = case str1.downcase <=> str2.downcase
372
- when -1
373
- 4
374
- when 0
375
- 3
376
- when 1
377
- 5
378
- end
379
- f = args.nth(f_number).evaluate(env)
380
- return Lisp::Debug.process_error("string-compare-ci requires functions for argument #{f_number}, but received #{f}", env) unless f.function?
381
- f.apply_to(Lisp::ConsCell.cons, env)
382
- end
383
-
384
-
385
- def self.string_hash_impl(args, env)
386
- str = get_string("string-hash", args.nth(1).evaluate(env))
387
- Lisp::Number.with_value(str.hash)
388
- end
389
-
390
-
391
- def self.string_hash_mod_impl(args, env)
392
- str = get_string("string-hash-mod", args.nth(1).evaluate(env))
393
- k_arg = args.cadr.evaluate(env)
394
- return Lisp::Debug.process_error("string-hash-mod requires it's second argument to be an integer, but received #{k_arg}", env) unless k_arg.integer?
395
- k = k_arg.value
396
- Lisp::Number.with_value(str.hash % k)
397
- end
398
-
399
-
400
- # str is assumed to be a single word
401
- def self.uppercase?(str)
402
- (str =~ /^[[:upper:]]*$/) == 0
403
- end
404
-
405
-
406
- def self.lowercase?(str)
407
- (str =~ /^[[:lower:]]*$/) == 0
408
- end
409
-
410
-
411
- def self.capitalized?(str)
412
- first = str[0]
413
- rest = str[1..-1]
414
- return false unless first =~ /[[:upper:]]/
415
- lowercase?(rest)
416
- end
417
-
418
-
419
- def self.split_into_words(str)
420
- str.split(/[^[[:alpha:]]]+/)
421
- end
422
-
423
-
424
- def self.string_capitalizedp_impl(args, env)
425
- str = get_string("string-capitalized?", args.nth(1).evaluate(env))
426
- words = split_into_words(str)
427
- Lisp::Boolean.with_value(capitalized?(words[0])&& words[1..-1].all? {|w| capitalized?(w) || lowercase?(w)})
428
- end
429
-
430
-
431
- def self.substring_capitalizedp_impl(args, env)
432
- str = get_substring("substring-capitalized?", args.nth(1).evaluate(env), args.nth(2).evaluate(env), args.nth(3).evaluate(env))
433
- words = split_into_words(str)
434
- Lisp::Boolean.with_value(capitalized?(words[0]) && words[1..-1].all? {|w| capitalized?(w) || lowercase?(w)})
435
- end
436
-
437
-
438
- def self.string_upperp_impl(args, env)
439
- str = get_string("string-upper-case?", args.nth(1).evaluate(env))
440
- words = split_into_words(str)
441
- Lisp::Boolean.with_value(words.all? {|w| uppercase?(w)})
442
- end
443
-
444
-
445
- def self.substring_upperp_impl(args, env)
446
- str = get_substring("substring-upper-case?", args.nth(1).evaluate(env), args.nth(2).evaluate(env), args.nth(3).evaluate(env))
447
- words = split_into_words(str)
448
- Lisp::Boolean.with_value(words.all? {|w| uppercase?(w)})
449
- end
450
-
451
-
452
- def self.string_lowerp_impl(args, env)
453
- str = get_string("string-lower-case?", args.nth(1).evaluate(env))
454
- words = split_into_words(str)
455
- Lisp::Boolean.with_value(words.all? {|w| lowercase?(w)})
456
- end
457
-
458
-
459
- def self.substring_lowerp_impl(args, env)
460
- str = get_substring("substring-lower-case?", args.nth(1).evaluate(env), args.nth(2).evaluate(env), args.nth(3).evaluate(env))
461
- words = split_into_words(str)
462
- Lisp::Boolean.with_value(words.all? {|w| lowercase?(w)})
463
- end
464
-
465
-
466
- def self.capitalize_string(str)
467
- saw_first = false
468
- str.chars.map do |c|
469
- if c =~ /[[:alpha:]]/
470
- if saw_first
471
- c.downcase
472
- else
473
- saw_first = true
474
- c.upcase
475
- end
476
- else
477
- c
478
- end
479
- end
480
- end
481
-
482
- def self.string_capitalize_impl(args, env)
483
- str = get_string("string-capitalize", args.nth(1).evaluate(env))
484
- new_chars = capitalize_string(str)
485
- new_str = ""
486
- new_chars.each {|c| new_str << c}
487
- self.with_value(new_str)
488
- end
489
-
490
-
491
- def self.string_capitalize_bang_impl(args, env)
492
- return Lisp::Debug.process_error("string-capitalize! requires 1 argument, but received #{args.length}", env) unless args.length == 1
493
- str = args.nth(1).evaluate(env)
494
- return Lisp::Debug.process_error("string-capitalize! requires a string, but received #{str}", env) unless str.string?
495
- new_chars = capitalize_string(str.value)
496
- new_str = ""
497
- new_chars.each {|c| new_str << c}
498
- str.set!(new_str)
499
- str
500
- end
501
-
502
-
503
- def self.substring_capitalize_bang_impl(args, env)
504
- return Lisp::Debug.process_error("substring-capitalize! requires 3 arguments, but received #{args.length}", env) unless args.length == 3
505
- s = args.nth(1).evaluate(env)
506
- return Lisp::Debug.process_error("substring-capitalize! requires a string as it's first argument, but received #{s}", env) unless s.string?
507
- str = s.value
508
-
509
- start_index = args.nth(2).evaluate(env)
510
- return Lisp::Debug.process_error("substring-capitalize! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
511
- si = start_index.value
512
- return Lisp::Debug.process_error("substring-capitalize! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length
513
-
514
- end_index = args.nth(3).evaluate(env)
515
- return Lisp::Debug.process_error("substring-capitalize! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
516
- ei = end_index.value
517
- return Lisp::Debug.process_error("substring-capitalize! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length
518
-
519
- prefix = str[0...si]
520
- substr = str[si...ei]
521
- suffix = str[ei..-1]
522
-
523
- new_chars = capitalize_string(substr)
524
- new_substr = ""
525
- new_chars.each {|c| new_substr << c}
526
- s.set!(prefix + new_substr + suffix)
527
- s
528
- end
529
-
530
-
531
- def self.string_downcase_impl(args, env)
532
- str = get_string("string-downcase?", args.nth(1).evaluate(env))
533
- self.with_value(str.downcase)
534
- end
535
-
536
-
537
- def self.string_downcase_bang_impl(args, env)
538
- return Lisp::Debug.process_error("string-downcase! requires 1 argument, but received #{args.length}", env) unless args.length == 1
539
- str = args.nth(1).evaluate(env)
540
- return Lisp::Debug.process_error("string-downcase! requires a string, but received #{str}", env) unless str.string?
541
- str.set!(str.value.downcase)
542
- str
543
- end
544
-
545
-
546
- def self.substring_downcase_bang_impl(args, env)
547
- return Lisp::Debug.process_error("substring-downcase! requires 3 arguments, but received #{args.length}", env) unless args.length == 3
548
- s = args.nth(1).evaluate(env)
549
- return Lisp::Debug.process_error("substring-downcase! requires a string as it's first argument, but received #{s}", env) unless s.string?
550
- str = s.value
551
-
552
- start_index = args.nth(2).evaluate(env)
553
- return Lisp::Debug.process_error("substring-downcase! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
554
- si = start_index.value
555
- return Lisp::Debug.process_error("substring-downcase! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length
556
-
557
- end_index = args.nth(3).evaluate(env)
558
- return Lisp::Debug.process_error("substring-downcase! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
559
- ei = end_index.value
560
- return Lisp::Debug.process_error("substring-downcase! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length
561
-
562
- prefix = str[0...si]
563
- substr = str[si...ei]
564
- suffix = str[ei..-1]
565
-
566
- new_chars = capitalize_string(substr)
567
- new_substr = ""
568
- new_chars.each {|c| new_substr << c}
569
- s.set!(prefix + substr.downcase + suffix)
570
- s
571
- end
572
-
573
-
574
- def self.string_upcase_impl(args, env)
575
- str = get_string("string-upcase?", args.nth(1).evaluate(env))
576
- self.with_value(str.upcase)
577
- end
578
-
579
-
580
- def self.string_upcase_bang_impl(args, env)
581
- return Lisp::Debug.process_error("string-upcase! requires 1 argument, but received #{args.length}", env) unless args.length == 1
582
- str = args.nth(1).evaluate(env)
583
- return Lisp::Debug.process_error("string-upcase! requires a string, but received #{str}", env) unless str.string?
584
- str.set!(str.value.upcase)
585
- str
586
- end
587
-
588
-
589
- def self.substring_upcase_bang_impl(args, env)
590
- return Lisp::Debug.process_error("substring-upcase! requires 3 arguments, but received #{args.length}", env) unless args.length == 3
591
- s = args.nth(1).evaluate(env)
592
- return Lisp::Debug.process_error("substring-upcase! requires a string as it's first argument, but received #{s}", env) unless s.string?
593
- str = s.value
594
-
595
- start_index = args.nth(2).evaluate(env)
596
- return Lisp::Debug.process_error("substring-upcase! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
597
- si = start_index.value
598
- return Lisp::Debug.process_error("substring-upcase! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length
599
-
600
- end_index = args.nth(3).evaluate(env)
601
- return Lisp::Debug.process_error("substring-upcase! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
602
- ei = end_index.value
603
- return Lisp::Debug.process_error("substring-upcase! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length
604
-
605
- prefix = str[0...si]
606
- substr = str[si...ei]
607
- suffix = str[ei..-1]
608
-
609
- new_chars = capitalize_string(substr)
610
- new_substr = ""
611
- new_chars.each {|c| new_substr << c}
612
- s.set!(prefix + substr.upcase + suffix)
613
- s
614
- end
615
-
616
-
617
- def self.string_append_impl(args, env)
618
- strings = args.to_a.map do |a|
619
- s = a.evaluate(env)
620
- return Lisp::Debug.process_error("string-append requires strings, but received #{s}", env) unless s.string?
621
- s.value
622
- end
623
-
624
- self.with_value(strings.join)
625
- end
626
-
627
-
628
- def self.substring_impl(args, env)
629
- str = get_substring("substring", args.nth(1).evaluate(env), args.nth(2).evaluate(env), args.nth(3).evaluate(env))
630
- self.with_value(str)
631
- end
632
-
633
-
634
- def self.string_head_impl(args, env)
635
- return Lisp::Debug.process_error("string-head requires 2 arguments, but received #{args.length}", env) unless args.length == 2
636
- s = args.nth(1).evaluate(env)
637
- return Lisp::Debug.process_error("string-head requires a string as it's first argument, but received #{s}", env) unless s.string?
638
- str = s.value
639
-
640
- end_index = args.nth(2).evaluate(env)
641
- return Lisp::Debug.process_error("string-head requires an integer end index, but received #{end_index}", env) unless end_index.integer?
642
- ei = end_index.value
643
- return Lisp::Debug.process_error("string-head received an invalid end index: #{ei}", env) if ei < 0 || ei > str.length
644
-
645
- self.with_value(str[0...ei])
646
- end
647
-
648
-
649
- def self.string_tail_impl(args, env)
650
- return Lisp::Debug.process_error("string-tail requires 2 arguments, but received #{args.length}", env) unless args.length == 2
651
- s = args.nth(1).evaluate(env)
652
- return Lisp::Debug.process_error("string-tail requires a string as it's first argument, but received #{s}", env) unless s.string?
653
- str = s.value
654
-
655
- start_index = args.nth(2).evaluate(env)
656
- return Lisp::Debug.process_error("string-tail requires an integer start index, but received #{start_index}", env) unless start_index.integer?
657
- si = start_index.value
658
- return Lisp::Debug.process_error("string-tail received an invalid end index: #{si}", env) if si < 0 || si > str.length
659
-
660
- self.with_value(str[si..-1])
661
- end
662
-
663
-
664
- def self.string_pad_left_impl(args, env)
665
- return Lisp::Debug.process_error("string-pad-left requires 2 or 3 arguments, but received #{args.length}", env) unless args.length == 2 || args.length == 3
666
- s = args.nth(1).evaluate(env)
667
- return Lisp::Debug.process_error("string-pad-left requires a string as it's first argument, but received #{s}", env) unless s.string?
668
- str = s.value
669
-
670
- size_arg = args.nth(2).evaluate(env)
671
- return Lisp::Debug.process_error("string-pad-left requires an integer size, but received #{size_arg}", env) unless size_arg.integer?
672
- size = size_arg.value
673
- return Lisp::Debug.process_error("string-pad-left received an invalid size: #{size}", env) if size < 0
674
-
675
- padding_char = if args.length == 3
676
- ch_arg = args.nth(3).evaluate(env)
677
- return Lisp::Debug.process_error("string-pad-left requires a character pad, but received #{ch_arg}", env) unless ch_arg.character?
678
- ch_arg.value
679
- else
680
- " "
681
- end
682
-
683
-
684
- new_str = if size > str.length
685
- padding = size - str.length
686
- pad = ""
687
- padding.times {|i| pad << padding_char}
688
- pad + str
689
- else
690
- start = str.length - size
691
- str[start..-1]
692
- end
693
- self.with_value(new_str)
694
- end
695
-
696
-
697
- def self.string_pad_right_impl(args, env)
698
- raise "string-pad-right requires 2 or 3 arguments, but received #{args.length}" unless args.length == 2 || args.length == 3
699
- s = args.nth(1).evaluate(env)
700
- raise "string-pad-right requires a string as it's first argument, but received #{s}" unless s.string?
701
- str = s.value
702
-
703
- size_arg = args.nth(2).evaluate(env)
704
- raise "string-pad-right requires an integer size, but received #{size_arg}" unless size_arg.integer?
705
- size = size_arg.value
706
- raise "string-pad-right received an invalid size: #{size}" if size < 0
707
-
708
- padding_char = if args.length == 3
709
- ch_arg = args.nth(3).evaluate(env)
710
- raise "string-pad-right requires a character pad, but received #{ch_arg}" unless ch_arg.character?
711
- ch_arg.value
712
- else
713
- " "
714
- end
715
-
716
-
717
- new_str = if size > str.length
718
- padding = size - str.length
719
- pad = ""
720
- padding.times {|i| pad << padding_char}
721
- str + pad
722
- else
723
- last = str.length - size
724
- str[0...4]
725
- end
726
- self.with_value(new_str)
727
- end
728
-
729
-
730
- def self.string_trim_impl(args, env)
731
- raise "string-trim requires 1 or 2 arguments, but received #{args.length}" unless args.length == 1 || args.length == 2
732
- s1 = args.nth(1).evaluate(env)
733
- raise "string-trim requires a string as it's first argument, but received #{s1}" unless s1.string?
734
- str = s1.value
735
-
736
- pattern = Regexp.new(if args.length == 2
737
- s2 = args.nth(2).evaluate(env)
738
- raise "string-trim requires a string as it's second argument, but received #{s2}" unless s2.string?
739
- s2.value
740
- else
741
- "[[:graph:]]"
742
- end)
743
-
744
-
745
- left_i = 0
746
- while pattern.match(str[left_i]).nil? && left_i < str.length
747
- left_i += 1
748
- end
749
-
750
- right_i = str.length - 1
751
- while pattern.match(str[right_i]).nil? && right_i >= 0
752
- right_i -= 1
753
- end
754
-
755
- self.with_value(str[left_i..right_i])
756
- end
757
-
758
-
759
- def self.string_trim_left_impl(args, env)
760
- raise "string-trim-left requires 1 or 2 arguments, but received #{args.length}" unless args.length == 1 || args.length == 2
761
- s1 = args.nth(1).evaluate(env)
762
- raise "string-trim-left requires a string as it's first argument, but received #{s1}" unless s1.string?
763
- str = s1.value
764
-
765
- pattern = Regexp.new(if args.length == 2
766
- s2 = args.nth(2).evaluate(env)
767
- raise "string-trim-left requires a string as it's second argument, but received #{s2}" unless s2.string?
768
- s2.value
769
- else
770
- "[[:graph:]]"
771
- end)
772
-
773
-
774
- left_i = 0
775
- while pattern.match(str[left_i]).nil? && left_i < str.length
776
- left_i += 1
777
- end
778
-
779
- self.with_value(str[left_i..-1])
780
- end
781
-
782
-
783
- def self.string_trim_right_impl(args, env)
784
- raise "string-trim-right requires 1 or 2 arguments, but received #{args.length}" unless args.length == 1 || args.length == 2
785
- s1 = args.nth(1).evaluate(env)
786
- raise "string-trim-right requires a string as it's first argument, but received #{s1}" unless s1.string?
787
- str = s1.value
788
-
789
- pattern = Regexp.new(if args.length == 2
790
- s2 = args.nth(2).evaluate(env)
791
- raise "string-trim-right requires a string as it's second argument, but received #{s2}" unless s2.string?
792
- s2.value
793
- else
794
- "[[:graph:]]"
795
- end)
796
-
797
- right_i = str.length - 1
798
- while pattern.match(str[right_i]).nil? && right_i >= 0
799
- right_i -= 1
800
- end
801
-
802
- self.with_value(str[0..right_i])
803
- end
804
-
805
-
806
- # --------------------------------------------------------------------------------
807
4
 
808
5
  def self.with_value(n)
809
6
  self.new(n)
@@ -821,6 +18,10 @@ end
821
18
  true
822
19
  end
823
20
 
21
+ def equal?(other)
22
+ other.string? && self.value == other.value
23
+ end
24
+
824
25
  def type
825
26
  :string
826
27
  end