heist 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,20 @@
1
+ === Version 0.3.0 (2009-07-31)
2
+
3
+ We've got all your data types now
4
+ * Vectors are supported, including the full R5RS library, macro and quasiquoting support
5
+ * Characters are available, including named characters (#\newline, #\space, #\tab)
6
+ * The full R5RS character and string libraries are implemented
7
+ * Complex numbers work correctly on Ruby1.9
8
+ * Dotted tail notation properly supported in macro templates
9
+
10
+
11
+ === Version 0.2.1 (2009-05-19)
12
+
13
+ * Fixed a bug in (append) where '() is the last argument
14
+ * Implemented (begin) in Ruby rather than Scheme for performance reasons
15
+ * Fixed a macro bug relating to binding of macro keywords
16
+
17
+
1
18
  === Version 0.2.0 (2009-04-01)
2
19
 
3
20
  The 'lists' release
@@ -6,6 +6,7 @@ bin/heist
6
6
  lib/bin_spec.rb
7
7
  lib/heist.rb
8
8
  lib/repl.rb
9
+ lib/trie.rb
9
10
  lib/builtin/library.scm
10
11
  lib/builtin/primitives.rb
11
12
  lib/builtin/syntax.scm
@@ -20,9 +21,11 @@ lib/runtime/callable/macro.rb
20
21
  lib/runtime/callable/macro/matches.rb
21
22
  lib/runtime/callable/macro/tree.rb
22
23
  lib/runtime/callable/macro/expansion.rb
24
+ lib/runtime/data/character.rb
23
25
  lib/runtime/data/cons.rb
24
26
  lib/runtime/data/expression.rb
25
27
  lib/runtime/data/identifier.rb
28
+ lib/runtime/data/vector.rb
26
29
  lib/runtime/binding.rb
27
30
  lib/runtime/frame.rb
28
31
  lib/runtime/runtime.rb
@@ -51,7 +54,9 @@ test/macro-helpers.scm
51
54
  test/macros.scm
52
55
  test/numbers.scm
53
56
  test/plt-macros.txt
57
+ test/strings.scm
54
58
  test/test_heist.rb
55
59
  test/unhygienic.scm
56
60
  test/vars.scm
61
+ test/vectors.scm
57
62
 
data/README.txt CHANGED
@@ -46,52 +46,63 @@ Currently implemented R5RS features include:
46
46
  * Numeric literals for integers, reals, rationals and complexes. The
47
47
  latter two are mapped to Ruby's <tt>Rational</tt> and <tt>Complex</tt>
48
48
  objects and Ruby handles all math procedures.
49
- * String and symbol literals
49
+ * Character, string and symbol literals
50
50
  * Proper and improper lists and full (quasi)quoting with <tt>'</tt>,
51
51
  <tt>`</tt>, <tt>,</tt>, <tt>,@</tt>
52
- * Macros: <tt>syntax-rules</tt>, <tt>define-syntax</tt>,
53
- <tt>let-syntax</tt>, <tt>letrec-syntax</tt>. Supports keywords,
54
- lists, pattern variables and ellipses down to arbitrary depth, as
55
- well as the R6RS ellipsis-escaping feature (<tt>(... ...)</tt>) to
56
- better enable macro-writing macros
57
- * Continuations: <tt>call-with-current-continuation</tt>, aliased
58
- as <tt>call/cc</tt>
59
- * Proper tail recursion
60
- * Variable assignment: <tt>define</tt> and <tt>set!</tt>
61
- * Lambda expressions: <tt>(lambda (x ...) body ...)</tt>, including lexical
62
- scoping and closures. Supports varargs using <tt>(lambda args body ...)</tt>
63
- and <tt>(lambda (x y . rest) body ...)</tt> forms.
64
- * Control flow: <tt>begin</tt>, <tt>if</tt>, <tt>cond</tt>,
65
- <tt>case</tt>
66
- * Binding constructs: <tt>let</tt>, <tt>let*</tt>, <tt>letrec</tt>
52
+ * Vector literals, also with quasiquoting support
53
+ * Definition and assignment: <tt>define</tt>, <tt>set!</tt>
54
+ * Lambdas: <tt>(lambda (x y) body ...)</tt>, <tt>(lambda args body ...)</tt>,
55
+ <tt>(lambda (x y . rest) body ...)</tt>
56
+ * Conditionals: <tt>if</tt>, <tt>cond</tt>, <tt>case</tt>
57
+ * Binding constructs: <tt>let</tt>, <tt>let*</tt>, <tt>letrec</tt>, <tt>begin</tt>
67
58
  * Iteration: named <tt>let</tt>, <tt>do</tt>
59
+ * Quoting: <tt>quote</tt>, <tt>quasiquote</tt> and shorthands <tt>'</tt>,
60
+ <tt>`</tt>, <tt>,</tt>, <tt>,@</tt>
61
+ * Macros: <tt>let-syntax</tt>, <tt>letrec-syntax</tt>, <tt>define-syntax</tt>,
62
+ <tt>syntax-rules</tt>
68
63
  * Delayed evaluation: <tt>delay</tt> and <tt>force</tt>
69
- * Logical connectives: <tt>and</tt>, <tt>or</tt>, <tt>not</tt>
70
- * Type checking: <tt>boolean?</tt>, <tt>number?</tt>, <tt>complex?</tt>,
71
- <tt>real?</tt>, <tt>rational?</tt>, <tt>integer?</tt>, <tt>exact?</tt>,
72
- <tt>inexact?</tt>, <tt>symbol?</tt>, <tt>string?</tt>, <tt>pair?</tt>,
73
- <tt>list?</tt>, <tt>null?</tt>, <tt>procedure?</tt>
74
- * Comparators: <tt>eq?</tt>, <tt>eqv?</tt>, <tt>equal?</tt>, <tt>=</tt>,
75
- <tt><</tt>, <tt><=</tt>, <tt>></tt>, <tt>>=</tt>
76
- * Numeric library: <tt>max</tt>, <tt>min</tt>, <tt>+</tt>, <tt>-</tt>,
77
- <tt>*</tt>, <tt>/</tt>, <tt>quotient</tt>, <tt>remainder</tt>,
78
- <tt>modulo</tt>, <tt>numerator</tt>, <tt>denominator</tt>, <tt>floor</tt>,
79
- <tt>ceiling</tt>, <tt>truncate</tt>, <tt>round</tt>, <tt>exp</tt>,
80
- <tt>log</tt>, <tt>sin</tt>, <tt>cos</tt>, <tt>tan</tt>, <tt>asin</tt>,
81
- <tt>acos</tt>, <tt>atan</tt>, <tt>expt</tt>, <tt>sqrt</tt>,
82
- <tt>zero?</tt>, <tt>positive?</tt>, <tt>negative?</tt>, <tt>odd?</tt>,
83
- <tt>even?</tt>, <tt>abs</tt>, <tt>gcd</tt>, <tt>lcm</tt>,
64
+ * Continuations: <tt>call-with-current-continuation</tt>, aliased as <tt>call/cc</tt>
65
+ * Equivalance predicates: <tt>eqv?</tt>, <tt>eq?</tt>, <tt>equal?</tt>
66
+ * Numeric library: <tt>number?</tt>, <tt>complex?</tt>, <tt>real?</tt>,
67
+ <tt>rational?</tt>, <tt>integer?</tt>, <tt>exact?</tt>, <tt>inexact?</tt>,
68
+ <tt>=</tt>, <tt><</tt>, <tt>></tt>, <tt><=</tt>, <tt>>=</tt>, <tt>zero?</tt>,
69
+ <tt>positive?</tt>, <tt>negative?</tt>, <tt>odd?</tt>, <tt>even?</tt>,
70
+ <tt>max</tt>, <tt>min</tt>, <tt>+</tt>, <tt>*</tt>, <tt>-</tt>, <tt>/</tt>,
71
+ <tt>abs</tt>, <tt>quotient</tt>, <tt>remainder</tt>, <tt>modulo</tt>,
72
+ <tt>gcd</tt>, <tt>lcm</tt>, <tt>numerator</tt>, <tt>denominator</tt>,
73
+ <tt>floor</tt>, <tt>ceiling</tt>, <tt>truncate</tt>, <tt>round</tt>,
74
+ <tt>exp</tt>, <tt>log</tt>, <tt>sin</tt>, <tt>cos</tt>, <tt>tan</tt>,
75
+ <tt>asin</tt>, <tt>acos</tt>, <tt>atan</tt>, <tt>sqrt</tt>, <tt>expt</tt>,
84
76
  <tt>make-rectangular</tt>, <tt>make-polar</tt>, <tt>real-part</tt>,
85
- <tt>imag-part</tt>, <tt>magnitude</tt>, <tt>angle</tt>, <tt>factorial</tt>,
86
- <tt>number->string</tt>
87
- * List library: <tt>cons</tt>, <tt>car</tt>, <tt>cdr</tt>, <tt>set-car!</tt>,
88
- <tt>set-cdr!</tt>, <tt>c[ad]{1,4}r</tt>, <tt>list</tt>, <tt>length</tt>,
89
- <tt>append</tt>, <tt>reverse</tt>, <tt>list-tail</tt>, <tt>list-ref</tt>,
90
- <tt>memq</tt>, <tt>memv</tt>, <tt>member</tt>, <tt>assq</tt>, <tt>assv</tt>,
91
- <tt>assoc</tt>, <tt>apply</tt>, <tt>map</tt>, <tt>for-each</tt>
92
- * String library: <tt>display</tt>, <tt>newline</tt>, <tt>string->number</tt>
93
- * File loading: <tt>(load "foo.scm")</tt>, paths are relative to the
94
- current file
77
+ <tt>imag-part</tt>, <tt>magnitude</tt>, <tt>angle</tt>, <tt>number->string</tt>,
78
+ <tt>string->number</tt>
79
+ * Boolean library: <tt>and</tt>, <tt>or</tt>, <tt>not</tt>, <tt>boolean?</tt>
80
+ * List library: <tt>pair?</tt>, <tt>cons</tt>, <tt>car</tt>, <tt>cdr</tt>,
81
+ <tt>set-car!</tt>, <tt>set-cdr!</tt>, <tt>caar</tt>, <tt>cadr</tt> ...
82
+ <tt>cdddar</tt>, <tt>cddddr</tt>, <tt>null?</tt>, <tt>list?</tt>, <tt>list</tt>,
83
+ <tt>length</tt>, <tt>append</tt>, <tt>reverse</tt>, <tt>list-tail</tt>,
84
+ <tt>list-ref</tt>, <tt>memq</tt>, <tt>memv</tt>, <tt>member</tt>, <tt>assq</tt>,
85
+ <tt>assv</tt>, <tt>assoc</tt>
86
+ * Symbol library: <tt>symbol?</tt>, <tt>symbol->string</tt>, <tt>string->symbol</tt>
87
+ * Character library: <tt>char?</tt>, <tt>char=?</tt>, <tt>char<?</tt>,
88
+ <tt>char>?</tt>, <tt>char<=?</tt>, <tt>char>=?</tt>, <tt>char-ci=?</tt>,
89
+ <tt>char-ci<?</tt>, <tt>char-ci>?</tt>, <tt>char-ci<=?</tt>, <tt>char-ci>=?</tt>,
90
+ <tt>char-alphabetic?</tt>, <tt>char-numeric?</tt>, <tt>char-whitespace?</tt>,
91
+ <tt>char-upper-case?</tt>, <tt>char-lower-case?</tt>, <tt>char->integer</tt>,
92
+ <tt>integer->char</tt>, <tt>char-upcase</tt>, <tt>char-downcase</tt>
93
+ * String library: <tt>string?</tt>, <tt>make-string</tt>, <tt>string</tt>,
94
+ <tt>string-length</tt>, <tt>string-ref</tt>, <tt>string-set!</tt>,
95
+ <tt>string=?</tt>, <tt>string-ci=?</tt>, <tt>string<?</tt>, <tt>string>?</tt>,
96
+ <tt>string<=?</tt>, <tt>string>=?</tt>, <tt>string-ci<?</tt>, <tt>string-ci>?</tt>,
97
+ <tt>string-ci<=?</tt>, <tt>string-ci>=?</tt>, <tt>substring</tt>,
98
+ <tt>string-append</tt>, <tt>string->list</tt>, <tt>list->string</tt>,
99
+ <tt>string-copy</tt>, <tt>string-fill!</tt>
100
+ * Vector library: <tt>vector?</tt>, <tt>make-vector</tt>, <tt>vector</tt>,
101
+ <tt>vector-length</tt>, <tt>vector-ref</tt>, <tt>vector-set!</tt>,
102
+ <tt>vector->list</tt>, <tt>list->vector</tt>, <tt>vector-fill!</tt>
103
+ * Control features: <tt>procedure?</tt>, <tt>apply</tt>, <tt>map</tt>,
104
+ <tt>for-each</tt>, <tt>eval</tt>, <tt>load</tt>
105
+ * Input/output: <tt>display</tt>, <tt>newline</tt>
95
106
 
96
107
  In addition to the above R5RS features, the following are provided. Heist
97
108
  allows the behaviour of some of these features to be configured on a
@@ -194,16 +205,17 @@ For example, using our <tt>Heist::Runtime</tt> instance from above:
194
205
  scheme.exec [:square, 9]
195
206
  #=> 81
196
207
 
197
- Arrays map directly to Scheme lists, symbols map to identifiers, strings
198
- and numbers are treated as literals, and any other data is interpreted
199
- verbatim. So, you can use any piece of Ruby data in these expressions
200
- as long as the functions you're calling can operate on it.
208
+ Arrays map directly to Scheme lists, symbols map to identifiers, strings,
209
+ numbers and booleans are treated as literals, and any other data is
210
+ interpreted verbatim. So, you can use any piece of Ruby data in these
211
+ expressions as long as the functions you're calling can operate on it.
201
212
 
202
- Due to syntactic limitations, some Scheme syntax cannot be used in this
203
- interface. Quoting is out, so the expression <tt>'(1 2 3)</tt> would
204
- need to be written <tt>[:quote, [1, 2, 3]]</tt>. Dotted pairs and
205
- improper lists are also not available, though you can work around
206
- this to some extent using <tt>:cons</tt>.
213
+ Due to syntactic limitations, some Scheme constructs cannot be used in this
214
+ interface. Quoting syntax is out, so the expression <tt>'(1 2 3)</tt> would
215
+ need to be written <tt>[:quote, [1, 2, 3]]</tt>. Dotted pairs and improper
216
+ lists are also not available, though you can work around this to some extent
217
+ using <tt>:cons</tt>. Vectors should be written as <tt>[:vector, 1, 2, 3]</tt>
218
+ for example. Characters are not supported at all.
207
219
 
208
220
 
209
221
  == Notes
@@ -217,7 +229,9 @@ and can be assumed to be reasonably stable.
217
229
  I have not documented how to write your own syntax using Ruby because
218
230
  it requires far too much knowledge of Heist's plumbing at present (I
219
231
  suspect this may be unavoidable). Besides, we have macros so if you
220
- want new syntax we've got you covered.
232
+ want new syntax we've got you covered. In fact, writing syntax using
233
+ macros makes sure that new syntactic forms support continuations
234
+ correctly, and Heist itself eschews Ruby-based syntax where possible.
221
235
 
222
236
  Heist is extremely liberal as regards symbols. Any sequence of
223
237
  characters that does not contain any spaces or parentheses and that
data/Rakefile CHANGED
@@ -4,9 +4,33 @@ require 'rubygems'
4
4
  require 'hoe'
5
5
  require './lib/heist.rb'
6
6
 
7
- Hoe.new('heist', Heist::VERSION) do |p|
7
+ Hoe.spec('heist') do |p|
8
8
  p.developer('James Coglan', 'jcoglan@googlemail.com')
9
9
  p.extra_deps = %w(oyster treetop)
10
10
  end
11
11
 
12
+ namespace :spec do
13
+ task :r5rs do
14
+ procedures = Dir['r5rs/*.html'].
15
+ map { |f| File.read(f) }.
16
+ join("\n").
17
+ split(/\n+/).
18
+ grep(/(syntax|procedure)\:/).
19
+ map { |s| s.gsub(/<\/?[^>]+>/, '').
20
+ scan(/\(([^\) ]+)/).
21
+ flatten.
22
+ first }.
23
+ uniq.
24
+ compact.
25
+ map { |s| s.gsub('&lt;', '<').
26
+ gsub('&gt;', '>') }
27
+
28
+ scope = Heist::Runtime.new.top_level
29
+ procedures.each do |proc|
30
+ message = scope.defined?(proc) ? scope.exec(proc) : 'MISSING'
31
+ puts " %-32s %-48s" % [proc, message]
32
+ end
33
+ end
34
+ end
35
+
12
36
  # vim: syntax=Ruby
@@ -25,14 +25,6 @@
25
25
  (define (not x)
26
26
  (if x #f #t))
27
27
 
28
- ; (negate x)
29
- ; Returns a negated form of x, like (not) but also
30
- ; works on functions
31
- (define (negate proc)
32
- (if (procedure? proc)
33
- (lambda args (not (apply proc args)))
34
- (not proc)))
35
-
36
28
  ; Longhand aliases for boolean constants
37
29
  (define true #t)
38
30
  (define false #f)
@@ -50,9 +42,19 @@
50
42
  ; Returns true iff x is any type of number
51
43
  (define number? complex?)
52
44
 
45
+ ; (exact? x)
46
+ ; Returns true iff the given number is exact i.e. an integer, a
47
+ ; rational, or a complex made of integers or rationals
48
+ (define (exact? x)
49
+ (or (rational? x)
50
+ (and (not (zero? (imag-part x)))
51
+ (exact? (real-part x))
52
+ (exact? (imag-part x)))))
53
+
53
54
  ; (inexact? x)
54
55
  ; Returns true iff x is not an exact number
55
- (define inexact? (negate exact?))
56
+ (define (inexact? x)
57
+ (not (exact? x)))
56
58
 
57
59
  ; Returns true iff all arguments are numerically equal
58
60
  (define (= . args)
@@ -336,3 +338,236 @@
336
338
  (proc (car list)
337
339
  (foldr proc value (cdr list)))))
338
340
 
341
+ ;----------------------------------------------------------------
342
+
343
+ ; Character functions
344
+
345
+ ; (char-upper-case? letter)
346
+ ; Returns true iff letter is an uppercase letter
347
+ (define (char-upper-case? letter)
348
+ (and (char? letter)
349
+ (let ([code (char->integer letter)])
350
+ (and (>= code 65)
351
+ (<= code 90)))))
352
+
353
+ ; (char-lower-case? letter)
354
+ ; Returns true iff letter is a lowercase letter
355
+ (define (char-lower-case? letter)
356
+ (and (char? letter)
357
+ (let ([code (char->integer letter)])
358
+ (and (>= code 97)
359
+ (<= code 122)))))
360
+
361
+ ; (char-alphabetic? char)
362
+ ; Returns true iff char is an alphabetic character
363
+ (define (char-alphabetic? char)
364
+ (or (char-upper-case? char)
365
+ (char-lower-case? char)))
366
+
367
+ ; (char-numeric? char)
368
+ ; Returns true iff char is a numeric character
369
+ (define (char-numeric? char)
370
+ (and (char? char)
371
+ (let ([code (char->integer char)])
372
+ (and (>= code 48)
373
+ (<= code 57)))))
374
+
375
+ ; (char-whitespace? char)
376
+ ; Returns true iff char is a whitespace character
377
+ (define (char-whitespace? char)
378
+ (and (char? char)
379
+ (if (member (char->integer char)
380
+ '(9 10 32))
381
+ #t
382
+ #f)))
383
+
384
+ ; (char-upcase char)
385
+ ; Returns an uppercase copy of char
386
+ (define (char-upcase char)
387
+ (let ([code (char->integer char)])
388
+ (if (and (>= code 97) (<= code 122))
389
+ (integer->char (- code 32))
390
+ (integer->char code))))
391
+
392
+ ; (char-downcase char)
393
+ ; Returns a lowercase copy of char
394
+ (define (char-downcase char)
395
+ (let ([code (char->integer char)])
396
+ (if (and (>= code 65) (<= code 90))
397
+ (integer->char (+ code 32))
398
+ (integer->char code))))
399
+
400
+ (define (char-compare-ci operator)
401
+ (lambda (x y)
402
+ (operator (char-downcase x)
403
+ (char-downcase y))))
404
+
405
+ (define char-ci=? (char-compare-ci char=?))
406
+ (define char-ci<? (char-compare-ci char<?))
407
+ (define char-ci>? (char-compare-ci char>?))
408
+ (define char-ci<=? (char-compare-ci char<=?))
409
+ (define char-ci>=? (char-compare-ci char>=?))
410
+
411
+ ;----------------------------------------------------------------
412
+
413
+ ; String functions
414
+
415
+ ; (string char ...)
416
+ ; Returns a new string formed by combining the given characters
417
+ (define (string . chars) (list->string chars))
418
+
419
+ (define (string-compare string1 string2 char-less? char-greater?)
420
+ (if (or (not (string? string1))
421
+ (not (string? string2)))
422
+ (error "Expected two strings as arguments")
423
+ (do ([pair1 (string->list string1) (cdr pair1)]
424
+ [pair2 (string->list string2) (cdr pair2)]
425
+ [diff '()])
426
+ ((integer? diff) diff)
427
+ (set! diff (cond [(null? pair1) (if (null? pair2) 0 -1)]
428
+ [(null? pair2) 1]
429
+ [else (let ([char1 (car pair1)]
430
+ [char2 (car pair2)])
431
+ (cond [(char-less? char1 char2) -1]
432
+ [(char-greater? char1 char2) 1]
433
+ [else '()]))])))))
434
+
435
+ ; (string=? string1 string2)
436
+ ; Returns true iff string1 and string2 are equal strings
437
+ (define (string=? string1 string2)
438
+ (zero? (string-compare string1 string2 char<? char>?)))
439
+
440
+ ; (string-ci=? string1 string2)
441
+ ; Returns true iff string1 and string2 are equal strings, ignoring case
442
+ (define (string-ci=? string1 string2)
443
+ (zero? (string-compare string1 string2 char-ci<? char-ci>?)))
444
+
445
+ ; (string<? string1 string2)
446
+ ; Returns true iff string1 is lexicographically less than string2
447
+ (define (string<? string1 string2)
448
+ (= (string-compare string1 string2 char<? char>?) -1))
449
+
450
+ ; (string>? string1 string2)
451
+ ; Returns true iff string1 is lexicographically greater than string2
452
+ (define (string>? string1 string2)
453
+ (= (string-compare string1 string2 char<? char>?) 1))
454
+
455
+ ; (string<=? string1 string2)
456
+ ; Returns true iff string1 is lexicographically less than or equal
457
+ ; to string2
458
+ (define (string<=? string1 string2)
459
+ (not (string>? string1 string2)))
460
+
461
+ ; (string>=? string1 string2)
462
+ ; Returns true iff string1 is lexicographically greater than or equal
463
+ ; to string2
464
+ (define (string>=? string1 string2)
465
+ (not (string<? string1 string2)))
466
+
467
+ ; (string-ci<? string1 string2)
468
+ ; Returns true iff string1 is lexicographically less than string2,
469
+ ; ignoring differences in case
470
+ (define (string-ci<? string1 string2)
471
+ (= (string-compare string1 string2 char-ci<? char-ci>?) -1))
472
+
473
+ ; (string-ci>? string1 string2)
474
+ ; Returns true iff string1 is lexicographically greater than string2,
475
+ ; ignoring differences in case
476
+ (define (string-ci>? string1 string2)
477
+ (= (string-compare string1 string2 char-ci<? char-ci>?) 1))
478
+
479
+ ; (string-ci<=? string1 string2)
480
+ ; Returns true iff string1 is lexicographically less than or equal
481
+ ; to string2, ignoring differences in case
482
+ (define (string-ci<=? string1 string2)
483
+ (not (string-ci>? string1 string2)))
484
+
485
+ ; (string-ci>=? string1 string2)
486
+ ; Returns true iff string1 is lexicographically greater than or equal
487
+ ; to string2, ignoring differences in case
488
+ (define (string-ci>=? string1 string2)
489
+ (not (string-ci<? string1 string2)))
490
+
491
+ ; (substring string start end)
492
+ ; Returns a string composed of the characters from start (inclusive)
493
+ ; to end (exclusive) in string
494
+ (define (substring string start end)
495
+ (let ([size (string-length string)])
496
+ (cond [(< start 0) (error "start index must be positive")]
497
+ [(> end size) (error "end index must be <= the length of string")]
498
+ [(> start end) (error "start must be <= end index")]
499
+ [else
500
+ (let* ([subsize (- end start)]
501
+ [substr (make-string subsize)])
502
+ (do ([i 0 (+ i 1)])
503
+ ((= i subsize) substr)
504
+ (string-set! substr i (string-ref string (+ start i)))))])))
505
+
506
+ ; (list->string chars)
507
+ ; Returns a new string formed by combining the list
508
+ (define (list->string chars)
509
+ (let* ([size (length chars)]
510
+ [str (make-string size)])
511
+ (do ([list chars (cdr list)]
512
+ [i 0 (+ i 1)])
513
+ ((= i size) str)
514
+ (string-set! str i (car list)))))
515
+
516
+ ; (string->list string)
517
+ ; Returns a newly allocated list of the characters in the string
518
+ (define (string->list string)
519
+ (let ([size (string-length string)])
520
+ (do ([i size (- i 1)]
521
+ [list '() (cons (string-ref string (- i 1)) list)])
522
+ ((zero? i) list))))
523
+
524
+ ; (string-copy string)
525
+ ; Returns a newly allocated copy of the string
526
+ (define (string-copy string)
527
+ (list->string (string->list string)))
528
+
529
+ ; (string-fill! string char)
530
+ ; Replaces every character of string with char
531
+ (define (string-fill! string char)
532
+ (let ([size (string-length string)])
533
+ (do ([i size (- i 1)])
534
+ ((zero? i) string)
535
+ (string-set! string (- i 1) char))))
536
+
537
+ ; (string-append string ...)
538
+ ; Returns a new string formed by concatenating the arguments
539
+ (define (string-append . strings)
540
+ (list->string (apply append (map string->list strings))))
541
+
542
+ ;----------------------------------------------------------------
543
+
544
+ ; Vector functions
545
+
546
+ ; (vector object ...)
547
+ ; Returns a newly allocated vector from its arguments
548
+ (define (vector . args) (list->vector args))
549
+
550
+ ; (list->vector list)
551
+ ; Returns a newly allocated vector from a list
552
+ (define (list->vector list)
553
+ (let* ([size (length list)]
554
+ [new-vector (make-vector size)])
555
+ (do ([i 0 (+ i 1)]
556
+ [pair list (cdr pair)])
557
+ ((= i size) new-vector)
558
+ (vector-set! new-vector i (car pair)))))
559
+
560
+ ; (vector->list vector)
561
+ ; Returns a newly allocated proper list from a vector
562
+ (define (vector->list vector)
563
+ (do ([i (vector-length vector) (- i 1)]
564
+ [pair '() (cons (vector-ref vector (- i 1)) pair)])
565
+ ((zero? i) pair)))
566
+
567
+ ; (vector-fill! vector fill)
568
+ ; Sets every element of vector to fill
569
+ (define (vector-fill! vector fill)
570
+ (do ([i (vector-length vector) (- i 1)])
571
+ ((zero? i) vector)
572
+ (vector-set! vector (- i 1) fill)))
573
+