Class: Lisp::PrimString

Inherits:
Object show all
Defined in:
lib/rubylisp/prim_string.rb

Class Method Summary collapse

Class Method Details

.capitalize_string(str) ⇒ Object



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/rubylisp/prim_string.rb', line 453

def self.capitalize_string(str)
  saw_first = false
  str.chars.map do |c|
    if c =~ /[[:alpha:]]/
      if saw_first
        c.downcase
      else
        saw_first = true
        c.upcase
      end
    else
      c
    end
  end
end

.capitalized?(str) ⇒ Boolean

Returns:



398
399
400
401
402
403
# File 'lib/rubylisp/prim_string.rb', line 398

def self.capitalized?(str)
  first = str[0]
  rest = str[1..-1]
  return false unless first =~ /[[:upper:]]/
  lowercase?(rest)
end

.extract_strings(func, args, env) ⇒ Object



211
212
213
214
215
# File 'lib/rubylisp/prim_string.rb', line 211

def self.extract_strings(func, args, env)
  str1 = get_string(func, args.nth(0).evaluate(env), env)
  str2 = get_string(func, args.nth(1).evaluate(env), env)
  return [str1, str2]
end

.extract_substrings(func, args, env) ⇒ Object



198
199
200
201
202
# File 'lib/rubylisp/prim_string.rb', line 198

def self.extract_substrings(func, args, env)
  substr1 = get_substring(func, args.nth(0), args.nth(1), args.nth(2), env)
  substr2 = get_substring(func, args.nth(3), args.nth(4), args.nth(5), env)
  return [substr1, substr2]
end

.get_string(func, str, env) ⇒ Object



205
206
207
208
# File 'lib/rubylisp/prim_string.rb', line 205

def self.get_string(func, str, env)
  return Lisp::Debug.process_error("#{func} requires a string, but received #{str}", env) unless str.string?
  str.value
end

.get_substring(func, str, start_index, end_index, env) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rubylisp/prim_string.rb', line 185

def self.get_substring(func, str, start_index, end_index, env)
  return Lisp::Debug.process_error("#{func} requires a string, but received #{str}", env) unless str.string?
  s = str.value
  return Lisp::Debug.process_error("#{func} requires an integer start index, but received #{start_index}", env) unless start_index.integer?
  si = start_index.value
  return Lisp::Debug.process_error("#{func} received an invalid substring start index: #{si}", env) if si < 0 || si > s.length
  return Lisp::Debug.process_error("#{func} requires an integer end index, but received #{end_index}", env) unless end_index.integer?
  ei = end_index.value
  return Lisp::Debug.process_error("#{func} received an invalid substring end index: #{ei}", env) if ei < 0 || ei > s.length
  s[si...ei]
end

.list_string_impl(args, env) ⇒ Object



116
117
118
119
120
121
122
123
124
125
# File 'lib/rubylisp/prim_string.rb', line 116

def self.list_string_impl(args, env)
  list_of_chars = args.car
  return Lisp::Debug.process_error("list->string requires a list argument, but received #{list_of_chars}", env) unless list_of_chars.list?      
  chars = list_of_chars.to_a.map do |a|
    ea = a.evaluate(env)
    return Lisp::Debug.process_error("string requires a list of characters, but it contained #{ea}.", env) unless ea.character?
    ea.value
  end
  Lisp::String.with_value(chars.join)
end

.lowercase?(str) ⇒ Boolean

Returns:



393
394
395
# File 'lib/rubylisp/prim_string.rb', line 393

def self.lowercase?(str)
  (str =~ /^[[:lower:]]*$/) == 0
end

.make_string_impl(args, env) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rubylisp/prim_string.rb', line 92

def self.make_string_impl(args, env)
  k_arg = args.car
  return Lisp::Debug.process_error("make-string requires an integer as it's first argument.", env) unless k_arg.integer?
  k = k_arg.value
  c = if args.length == 2
        c_arg = args.cadr
        return Lisp::Debug.process_error("make-string requires a character as it's second argument, but received #{c_arg}.", env) unless c_arg.character?
        c_arg.value
      else
        " "
      end
  Lisp::String.with_value(c * k)
end

.registerObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rubylisp/prim_string.rb', line 5

def self.register
      Primitive.register("str", ">=1")   {|args, env| Lisp::PrimString::str_impl(args, env) }
      Primitive.register("string?", "1")   {|args, env| Lisp::PrimString::stringp_impl(args, env) }
      Primitive.register("make-string", "1|2") {|args, env| Lisp::PrimString::make_string_impl(args, env) }      
      Primitive.register("string", "*") {|args, env| Lisp::PrimString::string_impl(args, env) }      
      Primitive.register("list->string", "1") {|args, env| Lisp::PrimString::list_string_impl(args, env) }      
      Primitive.register("string->list", "1") {|args, env| Lisp::PrimString::string_list_impl(args, env) }      
      Primitive.register("string-copy", "1") {|args, env| Lisp::PrimString::string_copy_impl(args, env) }      
      Primitive.register("string-length", "1") {|args, env| Lisp::PrimString::string_length_impl(args, env) }      
      Primitive.register("string-null?", "1") {|args, env| Lisp::PrimString::string_nullp_impl(args, env) }      
      Primitive.register("string-ref", "2") {|args, env| Lisp::PrimString::string_ref_impl(args, env) }      
      Primitive.register("string-set!", "3") {|args, env| Lisp::PrimString::string_set_impl(args, env) }      

      Primitive.register("string=?", "2") {|args, env| Lisp::PrimString::string_eq_impl(args, env) }      
      Primitive.register("substring=?", "6") {|args, env| Lisp::PrimString::substring_eq_impl(args, env) }      
      Primitive.register("string-ci=?", "2") {|args, env| Lisp::PrimString::string_ci_eq_impl(args, env) }      
      Primitive.register("substring-ci=?", "6") {|args, env| Lisp::PrimString::substring_ci_eq_impl(args, env) }      

      Primitive.register("string<?", "2") {|args, env| Lisp::PrimString::string_lt_impl(args, env) }      
      Primitive.register("substring<?", "6") {|args, env| Lisp::PrimString::substring_lt_impl(args, env) }      
      Primitive.register("string-ci<?", "2") {|args, env| Lisp::PrimString::string_ci_lt_impl(args, env) }      
      Primitive.register("substring-ci<?", "6") {|args, env| Lisp::PrimString::substring_ci_lt_impl(args, env) }      

      Primitive.register("string>?", "2") {|args, env| Lisp::PrimString::string_gt_impl(args, env) }      
      Primitive.register("substring>?", "6") {|args, env| Lisp::PrimString::substring_gt_impl(args, env) }      
      Primitive.register("string-ci>?", "2") {|args, env| Lisp::PrimString::string_ci_gt_impl(args, env) }      
      Primitive.register("substring-ci>?", "6") {|args, env| Lisp::PrimString::substring_ci_gt_impl(args, env) }      

      Primitive.register("string<=?", "2") {|args, env| Lisp::PrimString::string_lte_impl(args, env) }      
      Primitive.register("substring<=?", "6") {|args, env| Lisp::PrimString::substring_lte_impl(args, env) }      
      Primitive.register("string-ci<=?", "2") {|args, env| Lisp::PrimString::string_ci_lte_impl(args, env) }      
      Primitive.register("substring-ci<=?", "6") {|args, env| Lisp::PrimString::substring_ci_lte_impl(args, env) }      

      Primitive.register("string>=?", "2") {|args, env| Lisp::PrimString::string_gte_impl(args, env) }      
      Primitive.register("substring>=?", "6") {|args, env| Lisp::PrimString::substring_gte_impl(args, env) }      
      Primitive.register("string-ci>=?", "2") {|args, env| Lisp::PrimString::string_ci_gte_impl(args, env) }      
      Primitive.register("substring-ci>=?", "6") {|args, env| Lisp::PrimString::substring_ci_gte_impl(args, env) }      

      Primitive.register("string-compare", "5") {|args, env| Lisp::PrimString::string_compare_impl(args, env) }      
      Primitive.register("string-compare-ci", "5") {|args, env| Lisp::PrimString::string_compare_ci_impl(args, env) }      

      Primitive.register("string-hash", "1") {|args, env| Lisp::PrimString::string_hash_impl(args, env) }      
      Primitive.register("string-hash-mod", "2") {|args, env| Lisp::PrimString::string_hash_mod_impl(args, env) }      

      Primitive.register("string-capitalized?", "1") {|args, env| Lisp::PrimString::string_capitalizedp_impl(args, env) }      
      Primitive.register("substring-capitalized?", "3") {|args, env| Lisp::PrimString::substring_capitalizedp_impl(args, env) }      
      Primitive.register("string-upper-case?", "1") {|args, env| Lisp::PrimString::string_upperp_impl(args, env) }      
      Primitive.register("substring-upper-case?", "3") {|args, env| Lisp::PrimString::substring_upperp_impl(args, env) }      
      Primitive.register("string-lower-case?", "1") {|args, env| Lisp::PrimString::string_lowerp_impl(args, env) }      
      Primitive.register("substring-lower-case?", "3") {|args, env| Lisp::PrimString::substring_lowerp_impl(args, env) }      

      Primitive.register("string-capitalize", "1") {|args, env| Lisp::PrimString::string_capitalize_impl(args, env) }      
      Primitive.register("string-capitalize!", "1") {|args, env| Lisp::PrimString::string_capitalize_bang_impl(args, env) }      
      Primitive.register("substring-capitalize!", "3") {|args, env| Lisp::PrimString::substring_capitalize_bang_impl(args, env) }      
      Primitive.register("string-downcase", "1") {|args, env| Lisp::PrimString::string_downcase_impl(args, env) }      
      Primitive.register("string-downcase!", "1") {|args, env| Lisp::PrimString::string_downcase_bang_impl(args, env) }      
      Primitive.register("substring-downcase!", "3") {|args, env| Lisp::PrimString::substring_downcase_bang_impl(args, env) }      
      Primitive.register("string-upcase", "1") {|args, env| Lisp::PrimString::string_upcase_impl(args, env) }      
      Primitive.register("string-upcase!", "1") {|args, env| Lisp::PrimString::string_upcase_bang_impl(args, env) }      
      Primitive.register("substring-upcase!", "3") {|args, env| Lisp::PrimString::substring_upcase_bang_impl(args, env) }

      Primitive.register("string-append", "*") {|args, env| Lisp::PrimString::string_append_impl(args, env) }      
      Primitive.register("substring", "3") {|args, env| Lisp::PrimString::substring_impl(args, env) }      
      Primitive.register("string-head", "2") {|args, env| Lisp::PrimString::string_head_impl(args, env) }      
      Primitive.register("string-tail", "2") {|args, env| Lisp::PrimString::string_tail_impl(args, env) }      

      Primitive.register("string-pad-left", "2|3") {|args, env| Lisp::PrimString::string_pad_left_impl(args, env) }      
      Primitive.register("string-pad-right", "2|3") {|args, env| Lisp::PrimString::string_pad_right_impl(args, env) }      

      Primitive.register("string-trim", "1|2") {|args, env| Lisp::PrimString::string_trim_impl(args, env) }      
      Primitive.register("string-trim-right", "1|2") {|args, env| Lisp::PrimString::string_trim_right_impl(args, env) }      
      Primitive.register("string-trim-left", "1|2") {|args, env| Lisp::PrimString::string_trim_left_impl(args, env) }      

      Primitive.register("string-split", "2") {|args, env| Lisp::PrimString::string_split_impl(args, env) }      
end

.split_into_words(str) ⇒ Object



406
407
408
# File 'lib/rubylisp/prim_string.rb', line 406

def self.split_into_words(str)
  str.split(/[^[[:alpha:]]]+/)
end

.str_impl(args, env) ⇒ Object



81
82
83
84
# File 'lib/rubylisp/prim_string.rb', line 81

def self.str_impl(args, env)
  strings = args.to_a.map {|e| e.to_s}
  String.with_value(strings.join)
end

.string_append_impl(args, env) ⇒ Object



598
599
600
601
602
603
604
605
# File 'lib/rubylisp/prim_string.rb', line 598

def self.string_append_impl(args, env)
  strings = args.to_a.map do |a|
    return Lisp::Debug.process_error("string-append requires strings, but received #{a}", env) unless a.string?
    a.value
  end

  Lisp::String.with_value(strings.join)
end

.string_capitalize_bang_impl(args, env) ⇒ Object



478
479
480
481
482
483
484
485
486
# File 'lib/rubylisp/prim_string.rb', line 478

def self.string_capitalize_bang_impl(args, env)
  str = args.nth(0)
  return Lisp::Debug.process_error("string-capitalize! requires a string, but received #{str}", env) unless str.string?
  new_chars = capitalize_string(str.value)
  new_str = ""
  new_chars.each {|c| new_str << c}
  str.set!(new_str)
  str
end

.string_capitalize_impl(args, env) ⇒ Object



469
470
471
472
473
474
475
# File 'lib/rubylisp/prim_string.rb', line 469

def self.string_capitalize_impl(args, env)
  str = get_string("string-capitalize", args.nth(0), env)
  new_chars = capitalize_string(str)
  new_str = ""
  new_chars.each {|c| new_str << c}
  Lisp::String.with_value(new_str)
end

.string_capitalizedp_impl(args, env) ⇒ Object



411
412
413
414
415
# File 'lib/rubylisp/prim_string.rb', line 411

def self.string_capitalizedp_impl(args, env)
  str = get_string("string-capitalized?", args.nth(0), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(capitalized?(words[0])&& words[1..-1].all? {|w| capitalized?(w) || lowercase?(w)})
end

.string_ci_eq_impl(args, env) ⇒ Object



230
231
232
233
# File 'lib/rubylisp/prim_string.rb', line 230

def self.string_ci_eq_impl(args, env)
  str1, str2 = extract_strings("string-ci=?", args, env)
  Lisp::Boolean.with_value(str1.downcase == str2.downcase)
end

.string_ci_gt_impl(args, env) ⇒ Object



278
279
280
281
# File 'lib/rubylisp/prim_string.rb', line 278

def self.string_ci_gt_impl(args, env)
  str1, str2 = extract_strings("string-ci>?", args, env)
  Lisp::Boolean.with_value(str1.downcase > str2.downcase)
end

.string_ci_gte_impl(args, env) ⇒ Object



326
327
328
329
# File 'lib/rubylisp/prim_string.rb', line 326

def self.string_ci_gte_impl(args, env)
  str1, str2 = extract_strings("string-ci>=?", args, env)
  Lisp::Boolean.with_value(str1.downcase >= str2.downcase)
end

.string_ci_lt_impl(args, env) ⇒ Object



254
255
256
257
# File 'lib/rubylisp/prim_string.rb', line 254

def self.string_ci_lt_impl(args, env)
  str1, str2 = extract_strings("string-ci<?", args, env)
  Lisp::Boolean.with_value(str1.downcase < str2.downcase)
end

.string_ci_lte_impl(args, env) ⇒ Object



302
303
304
305
# File 'lib/rubylisp/prim_string.rb', line 302

def self.string_ci_lte_impl(args, env)
  str1, str2 = extract_strings("string-ci<=?", args, env)
  Lisp::Boolean.with_value(str1.downcase <= str2.downcase)
end

.string_compare_ci_impl(args, env) ⇒ Object



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/rubylisp/prim_string.rb', line 355

def self.string_compare_ci_impl(args, env)
  str1 = get_string("string-compare-ci", args.nth(0), env)
  str2 = get_string("string-compare-ci", args.nth(1), env)
  f_number = case str1.downcase <=> str2.downcase
             when -1
               3
             when 0
               2
             when 1
               4
             end
  f = args.nth(f_number)
  return Lisp::Debug.process_error("string-compare-ci requires functions for argument #{f_number}, but received #{f}", env) unless f.function?
  f.apply_to(Lisp::ConsCell.cons, env)
end

.string_compare_impl(args, env) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/rubylisp/prim_string.rb', line 338

def self.string_compare_impl(args, env)
  str1 = get_string("string-compare", args.nth(0), env)
  str2 = get_string("string-compare", args.nth(1), env)
  f_number = case str1 <=> str2
             when -1
               3
             when 0
               2
             when 1
               4
             end
  f = args.nth(f_number)
  return Lisp::Debug.process_error("string-compare requires functions for argument #{f_number}, but received #{f}", env) unless f.function?
  f.apply_to(Lisp::ConsCell.cons, env)
end

.string_copy_impl(args, env) ⇒ Object



136
137
138
139
140
# File 'lib/rubylisp/prim_string.rb', line 136

def self.string_copy_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string-copy requires a string argument, but received #{str_arg}", env) unless str_arg.string?
  Lisp::String.with_value(str_arg.value)
end

.string_downcase_bang_impl(args, env) ⇒ Object



522
523
524
525
526
527
# File 'lib/rubylisp/prim_string.rb', line 522

def self.string_downcase_bang_impl(args, env)
  str = args.nth(0)
  return Lisp::Debug.process_error("string-downcase! requires a string, but received #{str}", env) unless str.string?
  str.set!(str.value.downcase)
  str
end

.string_downcase_impl(args, env) ⇒ Object



516
517
518
519
# File 'lib/rubylisp/prim_string.rb', line 516

def self.string_downcase_impl(args, env)
  str = get_string("string-downcase?", args.nth(0), env)
  Lisp::String.with_value(str.downcase)
end

.string_eq_impl(args, env) ⇒ Object



218
219
220
221
# File 'lib/rubylisp/prim_string.rb', line 218

def self.string_eq_impl(args, env)
  str1, str2 = extract_strings("string=?", args, env)
  Lisp::Boolean.with_value(str1 == str2)
end

.string_gt_impl(args, env) ⇒ Object



266
267
268
269
# File 'lib/rubylisp/prim_string.rb', line 266

def self.string_gt_impl(args, env)
  str1, str2 = extract_strings("string>?", args, env)
  Lisp::Boolean.with_value(str1 > str2)
end

.string_gte_impl(args, env) ⇒ Object



314
315
316
317
# File 'lib/rubylisp/prim_string.rb', line 314

def self.string_gte_impl(args, env)
  str1, str2 = extract_strings("string>=?", args, env)
  Lisp::Boolean.with_value(str1 >= str2)
end

.string_hash_impl(args, env) ⇒ Object



372
373
374
375
# File 'lib/rubylisp/prim_string.rb', line 372

def self.string_hash_impl(args, env)
  str = get_string("string-hash", args.nth(0), env)
  Lisp::Number.with_value(str.hash)
end

.string_hash_mod_impl(args, env) ⇒ Object



378
379
380
381
382
383
384
# File 'lib/rubylisp/prim_string.rb', line 378

def self.string_hash_mod_impl(args, env)
  str = get_string("string-hash-mod", args.nth(0), env)
  k_arg = args.cadr
  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?
  k = k_arg.value
  Lisp::Number.with_value(str.hash % k)
end

.string_head_impl(args, env) ⇒ Object



614
615
616
617
618
619
620
621
622
623
624
625
# File 'lib/rubylisp/prim_string.rb', line 614

def self.string_head_impl(args, env)
  s = args.nth(0)
  return Lisp::Debug.process_error("string-head requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  end_index = args.nth(1)
  return Lisp::Debug.process_error("string-head requires an integer end index, but received #{end_index}", env) unless end_index.integer?
  ei = end_index.value
  return Lisp::Debug.process_error("string-head received an invalid end index: #{ei}", env) if ei < 0 || ei > str.length

  Lisp::String.with_value(str[0...ei])
end

.string_impl(args, env) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/rubylisp/prim_string.rb', line 107

def self.string_impl(args, env)
  chars = args.to_a.map do |a|
    return Lisp::Debug.process_error("string requires character args, but was passed #{a}.", env) unless a.character?
    a.value
  end
  Lisp::String.with_value(chars.join)
end

.string_length_impl(args, env) ⇒ Object



143
144
145
146
147
# File 'lib/rubylisp/prim_string.rb', line 143

def self.string_length_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string-length requires a string argument, but received #{str_arg}", env) unless str_arg.string?
  Lisp::Number.with_value(str_arg.value.length)
end

.string_list_impl(args, env) ⇒ Object



128
129
130
131
132
133
# File 'lib/rubylisp/prim_string.rb', line 128

def self.string_list_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string->list requires a string argument, but received #{str_arg}", env) unless str_arg.string?
  chars = str_arg.value.each_char.map {|c| Lisp::PrimCharacter.find_character_for_chr(c) }
  Lisp::ConsCell.array_to_list(chars)
end

.string_lowerp_impl(args, env) ⇒ Object



439
440
441
442
443
# File 'lib/rubylisp/prim_string.rb', line 439

def self.string_lowerp_impl(args, env)
  str = get_string("string-lower-case?", args.nth(0), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(words.all? {|w| lowercase?(w)})
end

.string_lt_impl(args, env) ⇒ Object



242
243
244
245
# File 'lib/rubylisp/prim_string.rb', line 242

def self.string_lt_impl(args, env)
  str1, str2 = extract_strings("string<?", args, env)
  Lisp::Boolean.with_value(str1 < str2)
end

.string_lte_impl(args, env) ⇒ Object



290
291
292
293
# File 'lib/rubylisp/prim_string.rb', line 290

def self.string_lte_impl(args, env)
  str1, str2 = extract_strings("string<=?", args, env)
  Lisp::Boolean.with_value(str1 <= str2)
end

.string_nullp_impl(args, env) ⇒ Object



150
151
152
153
154
# File 'lib/rubylisp/prim_string.rb', line 150

def self.string_nullp_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string-length requires a string argument, but received #{str_arg}", env) unless str_arg.string?
  Lisp::Boolean.with_value(str_arg.value.length == 0)
end

.string_pad_left_impl(args, env) ⇒ Object



643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/rubylisp/prim_string.rb', line 643

def self.string_pad_left_impl(args, env)
  s = args.nth(0)
  return Lisp::Debug.process_error("string-pad-left requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  size_arg = args.nth(1)
  return Lisp::Debug.process_error("string-pad-left requires an integer size, but received #{size_arg}", env) unless size_arg.integer?
  size = size_arg.value
  return Lisp::Debug.process_error("string-pad-left received an invalid size: #{size}", env) if size < 0

  padding_char = if args.length == 3
                   ch_arg = args.nth(2)
                   return Lisp::Debug.process_error("string-pad-left requires a character pad, but received #{ch_arg}", env) unless ch_arg.character?
                   ch_arg.value
                 else
                   " "
                 end
    
  
  new_str = if size > str.length
              padding = size - str.length
              pad = ""
              padding.times {|i| pad << padding_char}
              pad + str
            else
              start = str.length - size
              str[start..-1]
            end
  Lisp::String.with_value(new_str)
end

.string_pad_right_impl(args, env) ⇒ Object



675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# File 'lib/rubylisp/prim_string.rb', line 675

def self.string_pad_right_impl(args, env)
  s = args.nth(0)
  raise "string-pad-right requires a string as it's first argument, but received #{s}" unless s.string?
  str = s.value
  
  size_arg = args.nth(1)
  raise "string-pad-right requires an integer size, but received #{size_arg}" unless size_arg.integer?
  size = size_arg.value
  raise "string-pad-right received an invalid size: #{size}" if size < 0

  padding_char = if args.length == 3
                   ch_arg = args.nth(2)
                   raise "string-pad-right requires a character pad, but received #{ch_arg}" unless ch_arg.character?
                   ch_arg.value
                 else
                   " "
                 end
    
  
  new_str = if size > str.length
              padding = size - str.length
              pad = ""
              padding.times {|i| pad << padding_char}
              str + pad
            else
              last = str.length - size
              str[0...4]
            end
  Lisp::String.with_value(new_str)
end

.string_ref_impl(args, env) ⇒ Object



157
158
159
160
161
162
163
164
165
166
# File 'lib/rubylisp/prim_string.rb', line 157

def self.string_ref_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string-ref requires a string as it's first argument, but received #{arg.car}", env) unless str_arg.string?
  str = str_arg.value
  k_arg = args.cadr
  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?
  k = k_arg.value
  return Lisp::FALSE if k < 0 || k >= str.length
  Lisp::PrimCharacter.find_character_for_chr(str[k])
end

.string_set_impl(args, env) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/rubylisp/prim_string.rb', line 169

def self.string_set_impl(args, env)
  str_arg = args.car
  return Lisp::Debug.process_error("string-set! needs a string as it's first argument, but received #{str_arg}", env) unless str_arg.string?
  str = str_arg.value
  k_arg = args.cadr
  return Lisp::Debug.process_error("string-set! requires an integer as it's second argument, but received #{k_arg}", env) unless k_arg.integer?
  k = k_arg.value
  return Lisp::FALSE if k < 0 || k >= str.length
  replacement_arg = args.caddr
  return Lisp::Debug.process_error("string-set! requires a character as it's third argument, but received #{replacement_arg}", env) unless replacement_arg.character?
  replacement = replacement_arg.value
  str[k] = replacement
  Lisp::String.with_value(str)
end

.string_split_impl(args, env) ⇒ Object



780
781
782
783
784
785
786
787
788
# File 'lib/rubylisp/prim_string.rb', line 780

def self.string_split_impl(args, env)
  the_string = args.car
  raise "string-split requires a string as it's first argument, but received #{the_string}" unless the_string.string?
  
  separator = args.cadr
  raise "string-split requires a string as it's second argument, but received #{separator}" unless separator.string?

  Lisp::ConsCell.array_to_list(the_string.value.split(separator.value).map {|s| Lisp::String.with_value(s)})
end

.string_tail_impl(args, env) ⇒ Object



628
629
630
631
632
633
634
635
636
637
638
639
640
# File 'lib/rubylisp/prim_string.rb', line 628

def self.string_tail_impl(args, env)
  return Lisp::Debug.process_error("string-tail requires 2 arguments, but received #{args.length}", env) unless args.length == 2
  s = args.nth(0).evaluate(env)
  return Lisp::Debug.process_error("string-tail requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  start_index = args.nth(1).evaluate(env)
  return Lisp::Debug.process_error("string-tail requires an integer start index, but received #{start_index}", env) unless start_index.integer?
  si = start_index.value
  return Lisp::Debug.process_error("string-tail received an invalid end index: #{si}", env) if si < 0 || si > str.length

  Lisp::String.with_value(str[si..-1])
end

.string_trim_impl(args, env) ⇒ Object



707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
# File 'lib/rubylisp/prim_string.rb', line 707

def self.string_trim_impl(args, env)
  s1 = args.nth(0)
  raise "string-trim requires a string as it's first argument, but received #{s1}" unless s1.string?
  str = s1.value

  pattern = Regexp.new(if args.length == 2
                         s2 = args.nth(1)
                         raise "string-trim requires a string as it's second argument, but received #{s2}" unless s2.string?
                         s2.value
                       else
                         "[[:graph:]]"
                       end)

  
  left_i = 0
  while pattern.match(str[left_i]).nil? && left_i < str.length
    left_i += 1
  end
  
  right_i = str.length - 1
  while pattern.match(str[right_i]).nil? && right_i >= 0
    right_i -= 1
  end
  
  Lisp::String.with_value(str[left_i..right_i])
end

.string_trim_left_impl(args, env) ⇒ Object



735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'lib/rubylisp/prim_string.rb', line 735

def self.string_trim_left_impl(args, env)
  s1 = args.nth(0)
  raise "string-trim-left requires a string as it's first argument, but received #{s1}" unless s1.string?
  str = s1.value

  pattern = Regexp.new(if args.length == 2
                         s2 = args.nth(1)
                         raise "string-trim-left requires a string as it's second argument, but received #{s2}" unless s2.string?
                         s2.value
                       else
                         "[[:graph:]]"
                       end)

  
  left_i = 0
  while pattern.match(str[left_i]).nil? && left_i < str.length
    left_i += 1
  end
  
  Lisp::String.with_value(str[left_i..-1])
end

.string_trim_right_impl(args, env) ⇒ Object



758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
# File 'lib/rubylisp/prim_string.rb', line 758

def self.string_trim_right_impl(args, env)
  s1 = args.nth(0)
  raise "string-trim-right requires a string as it's first argument, but received #{s1}" unless s1.string?
  str = s1.value

  pattern = Regexp.new(if args.length == 2
                         s2 = args.nth(1)
                         raise "string-trim-right requires a string as it's second argument, but received #{s2}" unless s2.string?
                         s2.value
                       else
                         "[[:graph:]]"
                       end)

  right_i = str.length - 1
  while pattern.match(str[right_i]).nil? && right_i >= 0
    right_i -= 1
  end
  
  Lisp::String.with_value(str[0..right_i])
end

.string_upcase_bang_impl(args, env) ⇒ Object



563
564
565
566
567
568
# File 'lib/rubylisp/prim_string.rb', line 563

def self.string_upcase_bang_impl(args, env)
  str = args.nth(0)
  return Lisp::Debug.process_error("string-upcase! requires a string, but received #{str}", env) unless str.string?
  str.set!(str.value.upcase)
  str
end

.string_upcase_impl(args, env) ⇒ Object



557
558
559
560
# File 'lib/rubylisp/prim_string.rb', line 557

def self.string_upcase_impl(args, env)
  str = get_string("string-upcase?", args.nth(0), env)
  Lisp::String.with_value(str.upcase)
end

.string_upperp_impl(args, env) ⇒ Object



425
426
427
428
429
# File 'lib/rubylisp/prim_string.rb', line 425

def self.string_upperp_impl(args, env)
  str = get_string("string-upper-case?", args.nth(0), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(words.all? {|w| uppercase?(w)})
end

.stringp_impl(args, env) ⇒ Object



87
88
89
# File 'lib/rubylisp/prim_string.rb', line 87

def self.stringp_impl(args, env)
  return Lisp::Boolean.with_value(args.car.string?)
end

.substring_capitalize_bang_impl(args, env) ⇒ Object



489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# File 'lib/rubylisp/prim_string.rb', line 489

def self.substring_capitalize_bang_impl(args, env)
  s = args.nth(0)
  return Lisp::Debug.process_error("substring-capitalize! requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  start_index = args.nth(1)
  return Lisp::Debug.process_error("substring-capitalize! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
  si = start_index.value
  return Lisp::Debug.process_error("substring-capitalize! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length

  end_index = args.nth(2)
  return Lisp::Debug.process_error("substring-capitalize! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
  ei = end_index.value
  return Lisp::Debug.process_error("substring-capitalize! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length

  prefix = str[0...si]
  substr = str[si...ei]
  suffix = str[ei..-1]
  
  new_chars = capitalize_string(substr)
  new_substr = ""   
  new_chars.each {|c| new_substr << c}
  s.set!(prefix + new_substr + suffix)
  s
end

.substring_capitalizedp_impl(args, env) ⇒ Object



418
419
420
421
422
# File 'lib/rubylisp/prim_string.rb', line 418

def self.substring_capitalizedp_impl(args, env)
  str = get_substring("substring-capitalized?", args.nth(0), args.nth(1), args.nth(2), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(capitalized?(words[0]) && words[1..-1].all? {|w| capitalized?(w) || lowercase?(w)})
end

.substring_ci_eq_impl(args, env) ⇒ Object



236
237
238
239
# File 'lib/rubylisp/prim_string.rb', line 236

def self.substring_ci_eq_impl(args, env)
  substr1, substr2 = extract_substrings("substring-ci=?", args, env)
  Lisp::Boolean.with_value(substr1.downcase == substr2.downcase)
end

.substring_ci_gt_impl(args, env) ⇒ Object



284
285
286
287
# File 'lib/rubylisp/prim_string.rb', line 284

def self.substring_ci_gt_impl(args, env)
  substr1, substr2 = extract_substrings("substring-ci>?", args, env)
  Lisp::Boolean.with_value(substr1.downcase > substr2.downcase)
end

.substring_ci_gte_impl(args, env) ⇒ Object



332
333
334
335
# File 'lib/rubylisp/prim_string.rb', line 332

def self.substring_ci_gte_impl(args, env)
  substr1, substr2 = extract_substrings("substring-ci>=?", args, env)
  Lisp::Boolean.with_value(substr1.downcase >= substr2.downcase)
end

.substring_ci_lt_impl(args, env) ⇒ Object



260
261
262
263
# File 'lib/rubylisp/prim_string.rb', line 260

def self.substring_ci_lt_impl(args, env)
  substr1, substr2 = extract_substrings("substring-ci<?", args, env)
  Lisp::Boolean.with_value(substr1.downcase < substr2.downcase)
end

.substring_ci_lte_impl(args, env) ⇒ Object



308
309
310
311
# File 'lib/rubylisp/prim_string.rb', line 308

def self.substring_ci_lte_impl(args, env)
  substr1, substr2 = extract_substrings("substring-ci<=?", args, env)
  Lisp::Boolean.with_value(substr1.downcase <= substr2.downcase)
end

.substring_downcase_bang_impl(args, env) ⇒ Object



530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/rubylisp/prim_string.rb', line 530

def self.substring_downcase_bang_impl(args, env)
  s = args.nth(0)
  return Lisp::Debug.process_error("substring-downcase! requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  start_index = args.nth(1)
  return Lisp::Debug.process_error("substring-downcase! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
  si = start_index.value
  return Lisp::Debug.process_error("substring-downcase! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length

  end_index = args.nth(2)
  return Lisp::Debug.process_error("substring-downcase! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
  ei = end_index.value
  return Lisp::Debug.process_error("substring-downcase! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length

  prefix = str[0...si]
  substr = str[si...ei]
  suffix = str[ei..-1]
  
  new_chars = capitalize_string(substr)
  new_substr = ""   
  new_chars.each {|c| new_substr << c}
  s.set!(prefix + substr.downcase + suffix)
  s
end

.substring_eq_impl(args, env) ⇒ Object



224
225
226
227
# File 'lib/rubylisp/prim_string.rb', line 224

def self.substring_eq_impl(args, env)
  substr1, substr2 = extract_substrings("substring=?", args, env)
  Lisp::Boolean.with_value(substr1 == substr2)
end

.substring_gt_impl(args, env) ⇒ Object



272
273
274
275
# File 'lib/rubylisp/prim_string.rb', line 272

def self.substring_gt_impl(args, env)
  substr1, substr2 = extract_substrings("substring>?", args, env)
  Lisp::Boolean.with_value(substr1 > substr2)
end

.substring_gte_impl(args, env) ⇒ Object



320
321
322
323
# File 'lib/rubylisp/prim_string.rb', line 320

def self.substring_gte_impl(args, env)
  substr1, substr2 = extract_substrings("substring>=?", args, env)
  Lisp::Boolean.with_value(substr1 >= substr2)
end

.substring_impl(args, env) ⇒ Object



608
609
610
611
# File 'lib/rubylisp/prim_string.rb', line 608

def self.substring_impl(args, env)
  str = get_substring("substring", args.nth(0), args.nth(1), args.nth(2), env)
  Lisp::String.with_value(str)
end

.substring_lowerp_impl(args, env) ⇒ Object



446
447
448
449
450
# File 'lib/rubylisp/prim_string.rb', line 446

def self.substring_lowerp_impl(args, env)
  str = get_substring("substring-lower-case?", args.nth(0), args.nth(1), args.nth(2), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(words.all? {|w| lowercase?(w)})
end

.substring_lt_impl(args, env) ⇒ Object



248
249
250
251
# File 'lib/rubylisp/prim_string.rb', line 248

def self.substring_lt_impl(args, env)
  substr1, substr2 = extract_substrings("substring<?", args, env)
  Lisp::Boolean.with_value(substr1 < substr2)
end

.substring_lte_impl(args, env) ⇒ Object



296
297
298
299
# File 'lib/rubylisp/prim_string.rb', line 296

def self.substring_lte_impl(args, env)
  substr1, substr2 = extract_substrings("substring<=?", args, env)
  Lisp::Boolean.with_value(substr1 <= substr2)
end

.substring_upcase_bang_impl(args, env) ⇒ Object



571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
# File 'lib/rubylisp/prim_string.rb', line 571

def self.substring_upcase_bang_impl(args, env)
  s = args.nth(0)
  return Lisp::Debug.process_error("substring-upcase! requires a string as it's first argument, but received #{s}", env) unless s.string?
  str = s.value
  
  start_index = args.nth(1)
  return Lisp::Debug.process_error("substring-upcase! requires an integer start index, but received #{start_index}", env) unless start_index.integer?
  si = start_index.value
  return Lisp::Debug.process_error("substring-upcase! received an invalid substring start index: #{si}", env) if si < 0 || si > str.length

  end_index = args.nth(2)
  return Lisp::Debug.process_error("substring-upcase! requires an integer end index, but received #{end_index}", env) unless end_index.integer?
  ei = end_index.value
  return Lisp::Debug.process_error("substring-upcase! received an invalid substring end index: #{ei}", env) if ei < 0 || ei > str.length

  prefix = str[0...si]
  substr = str[si...ei]
  suffix = str[ei..-1]
  
  new_chars = capitalize_string(substr)
  new_substr = ""   
  new_chars.each {|c| new_substr << c}
  s.set!(prefix + substr.upcase + suffix)
  s
end

.substring_upperp_impl(args, env) ⇒ Object



432
433
434
435
436
# File 'lib/rubylisp/prim_string.rb', line 432

def self.substring_upperp_impl(args, env)
  str = get_substring("substring-upper-case?", args.nth(0), args.nth(1), args.nth(2), env)
  words = split_into_words(str)
  Lisp::Boolean.with_value(words.all? {|w| uppercase?(w)})
end

.uppercase?(str) ⇒ Boolean

str is assumed to be a single word

Returns:



388
389
390
# File 'lib/rubylisp/prim_string.rb', line 388

def self.uppercase?(str)
  (str =~ /^[[:upper:]]*$/) == 0
end