klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 9877b1ad617e3fd452f42c2ed1a9bb802e8eed44
parent 6fdc0dabcbb73819675aca0aa530dfd9f03382a5
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Mon, 28 Nov 2011 19:05:50 -0300

Added string-for-each, vector-for-each, and bytevector-for-each to the ground environment. Added the corresponding tests.

Diffstat:
MTODO | 6------
Msrc/kgcontrol.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/tests/control.k | 168++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 246 insertions(+), 8 deletions(-)

diff --git a/TODO b/TODO @@ -30,9 +30,6 @@ * operatives: ** $when (r7rs) ** $unless (r7rs) -** $string-for-each (r7rs) -** $vector-for-each (r7rs) -** $bytevector-for-each ** $case (r7rs) ** $case-lambda (r7rs) ** $case-vau (r7rs) @@ -40,9 +37,6 @@ ** $do (r7rs) ** $define-record-type (r7rs) * applicatives: -** vector-map (r7rs) -** bytevector-map (r7rs) -** string-map (r7rs) ** read-line (r7rs) ** number->string (r7rs) ** string->number (r7rs) diff --git a/src/kgcontrol.c b/src/kgcontrol.c @@ -368,6 +368,79 @@ void for_each(klisp_State *K) kapply_cc(K, KINERT); } +/* 6.9.? string-for-each, vector-for-each, bytevector-for-each */ +void array_for_each(klisp_State *K) +{ + TValue *xparams = K->next_xparams; + TValue ptree = K->next_value; + TValue denv = K->next_env; + klisp_assert(ttisenvironment(K->next_env)); + + /* + ** xparams[1]: array->list fn (with type check and size ret) + */ + + TValue (*array_to_list)(klisp_State *K, TValue array, int32_t *size) = + pvalue(xparams[0]); + + bind_al1tp(K, ptree, "applicative", ttisapplicative, app, lss); + + /* check that lss is a non empty list, and copy it */ + if (ttisnil(lss)) { + klispE_throw_simple(K, "no arguments after applicative"); + return; + } + + int32_t app_pairs, app_apairs, app_cpairs; + /* the copied list should be protected from gc, and will host + the lists resulting from the conversion */ + lss = check_copy_list(K, lss, true, &app_pairs, &app_cpairs); + app_apairs = app_pairs - app_cpairs; + krooted_tvs_push(K, lss); + + /* check that all elements have the correct type and same size, + and convert them to lists */ + int32_t res_pairs; + TValue head = kcar(lss); + TValue tail = kcdr(lss); + TValue ls = array_to_list(K, head, &res_pairs); + kset_car(lss, ls); /* save the first */ + /* all array will produce acyclic lists */ + for(int32_t i = 1 /* jump over first */; i < app_pairs; ++i) { + head = kcar(tail); + int32_t pairs; + ls = array_to_list(K, head, &pairs); + /* in klisp all arrays should have the same length */ + if (pairs != res_pairs) { + klispE_throw_simple(K, "arguments of different length"); + return; + } + kset_car(tail, ls); + tail = kcdr(tail); + } + + /* create the list of parameters to app */ + lss = map_for_each_transpose(K, lss, app_apairs, app_cpairs, + res_pairs, 0); /* cycle pairs is always 0 */ + + /* ASK John: the semantics when this is mixed with continuations, + isn't all that great..., but what are the expectations considering + there is no prescribed order? */ + + krooted_tvs_pop(K); + krooted_tvs_push(K, lss); + + /* schedule all elements at once, this will also return #inert once + done. */ + TValue new_cont = + kmake_continuation(K, kget_cc(K), do_for_each, 4, app, lss, + i2tv(res_pairs), denv); + kset_cc(K, new_cont); + krooted_tvs_pop(K); + /* this will be a nop */ + kapply_cc(K, KINERT); +} + /* init ground */ void kinit_control_ground_env(klisp_State *K) { @@ -385,6 +458,13 @@ void kinit_control_ground_env(klisp_State *K) add_operative(K, ground_env, "$cond", Scond, 0); /* 6.9.1 for-each */ add_applicative(K, ground_env, "for-each", for_each, 0); + /* 6.9.? string-for-each, vector-for-each, bytevector-for-each */ + add_applicative(K, ground_env, "string-for-each", array_for_each, 1, + p2tv(string_to_list_h)); + add_applicative(K, ground_env, "vector-for-each", array_for_each, 1, + p2tv(vector_to_list_h)); + add_applicative(K, ground_env, "bytevector-for-each", array_for_each, 1, + p2tv(bytevector_to_list_h)); } /* init continuation names */ diff --git a/src/tests/control.k b/src/tests/control.k @@ -146,6 +146,128 @@ #f)) +;; string-for-each +($check-predicate (applicative? string-for-each)) +($check eq? (string-for-each char-upcase "abcd") #inert) +($check eq? (string-for-each char<? "abcd" "efgh") #inert) + +($let ((p (cons () ()))) + ($check eq? + ($sequence (string-for-each (wrap ($vau #ignore env + (set-car! p env))) + "a") + (car p)) + (get-current-environment))) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (string-for-each ($lambda (x) + (set-car! p (+ (car p) + (char->integer x)))) + "abcd") + (car p)) + (apply + (map char->integer (string->list "abcd"))))) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (string-for-each ($lambda (x y ) + (set-car! p (+ (car p) + (char->integer x) + (char->integer y)))) + "abc" + "def") + (car p)) + (apply + (map char->integer (string->list "abcdef"))))) + + +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (string-for-each ($lambda ls + (set-car! p (finite-list? ls))) + . #0=("abc" + "def" + . #0#)) + (car p)) + #f)) + + +;; vector-for-each +($check-predicate (applicative? vector-for-each)) +($check eq? (vector-for-each + (vector 1 2 3)) #inert) +($check eq? (vector-for-each <? (vector 1 2) (vector 3 4)) + #inert) + +($let ((p (cons () ()))) + ($check eq? + ($sequence (vector-for-each (wrap ($vau #ignore env + (set-car! p env))) + (vector 1)) + (car p)) + (get-current-environment))) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (vector-for-each ($lambda (x) + (set-car! p (+ (car p) x))) + (vector 1 2 3 4)) + (car p)) + 10)) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (vector-for-each ($lambda (x y ) + (set-car! p (+ (car p) x y))) + (vector 1 2 3 4) + (vector 10 20 30 40)) + (car p)) + 110)) + + +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (vector-for-each ($lambda ls + (set-car! p (finite-list? ls))) + . #0=((vector 1 2) + (vector 3 4) + . #0#)) + (car p)) + #f)) + +;; bytevector-for-each +($check-predicate (applicative? bytevector-for-each)) +($check eq? (bytevector-for-each + (bytevector 1 2 3)) #inert) +($check eq? (bytevector-for-each <? (bytevector 1 2) (bytevector 3 4)) + #inert) + +($let ((p (cons () ()))) + ($check eq? + ($sequence (bytevector-for-each (wrap ($vau #ignore env + (set-car! p env))) + (bytevector 1)) + (car p)) + (get-current-environment))) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (bytevector-for-each ($lambda (x) + (set-car! p (+ (car p) x))) + (bytevector 1 2 3 4)) + (car p)) + 10)) +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (bytevector-for-each ($lambda (x y ) + (set-car! p (+ (car p) x y))) + (bytevector 1 2 3 4) + (bytevector 10 20 30 40)) + (car p)) + 110)) + +($let ((p (cons 0 ()))) + ($check eq? + ($sequence (bytevector-for-each ($lambda ls + (set-car! p (finite-list? ls))) + . #0=((bytevector 1 2) + (bytevector 3 4) + . #0#)) + (car p)) + #f)) + ;;; ;;; Error Checking and Robustness ;;; @@ -185,8 +307,7 @@ ;; for-each ($check-error (for-each)) -;; the list can't be empty -($check-error (for-each list)) +($check-error (for-each list)) ; the list can't be empty ($check-error (for-each list (list 1 2) (list 1 2 3))) ($check-error (for-each list (list . #0=(1 2 . #0#)) (list 1 2 3))) @@ -197,3 +318,46 @@ ($check-error (for-each list (list 1 2) #inert)) ($check-error (for-each cons (list 1 2))) + + +;; string-for-each +($check-error (string-for-each)) +($check-error (string-for-each char-upcase)) ; the list can't be empty + +($check-error (string-for-each char<? "ab" "abc")) + +($check-error (string-for-each char-upcase #inert)) +($check-error (string-for-each #inert "abc")) +($check-error (string-for-each (unwrap char-upcase) "abc")) + +($check-error (string-for-each char<? "abc" #inert)) +($check-error (string-for-each cons "abc")) + +;; vector-for-each +($check-error (vector-for-each)) +($check-error (vector-for-each char-upcase)) ; the list can't be empty + +($check-error (vector-for-each <? (vector 1 2) (vector 1 2 3))) + +($check-error (vector-for-each char-upcase #inert)) +($check-error (vector-for-each #inert (vector 1 2))) +($check-error (vector-for-each (unwrap char-upcase) (vector 1))) + +($check-error (vector-for-each <? (vector 1 2) #inert)) +($check-error (vector-for-each cons (vector 1 2 3))) + +;; bytevector-for-each +($check-error (bytevector-for-each)) +($check-error (bytevector-for-each +)) ; the list can't be empty + +($check-error (bytevector-for-each <? (bytevector 1 2) + (bytevector 1 2 3))) + +($check-error (bytevector-for-each + #inert)) +($check-error (bytevector-for-each #inert (bytevector 1 2 3))) +($check-error (bytevector-for-each (unwrap char-upcase) + (bytevector 1 2))) + +($check-error (bytevector-for-each <? (bytevector 1 2) #inert)) +($check-error (bytevector-for-each cons + (bytevector 1 2 3)))