diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | eval.c | 90 | ||||
-rw-r--r-- | txr.1 | 24 |
3 files changed, 104 insertions, 21 deletions
@@ -1,5 +1,16 @@ 2012-01-25 Kaz Kylheku <kaz@kylheku.com> + * eval.c (dwim_loc): Handles full responsibility for assigning + to list and array ranges. + (op_modplace): Pass extra arguments to dwim_loc so it can + do the job for ranges. If dwim_loc returns 0, it means + that it did everything. + (op_dwim): Support list and array ranges. + + * txr.1: Documented. + +2012-01-25 Kaz Kylheku <kaz@kylheku.com> + * arith.c (zerop): Misspelling in error message. * lib.c (sub_list, replace_list, sub_vec, replace_vec): @@ -637,7 +637,7 @@ static val op_defun(val form, val env) return name; } -static val *dwim_loc(val form, val env) +static val *dwim_loc(val form, val env, val op, val newval) { val obj = eval(second(form), env, form); val args = eval_args(rest(rest(form)), env, form); @@ -659,7 +659,23 @@ static val *dwim_loc(val form, val env) if (rest(args)) eval_error(form, lit("[~s ...]: vector indexing needs one arg"), obj, nao); - return vecref_l(obj, first(args)); + { + val index = first(args); + + if (consp(index)) { + val from = eval(car(index), env, form); + val to = eval(cdr(index), env, form); + + if (op != set_s) + eval_error(form, lit("[~s ~s]: slice takes only simple assignments"), + obj, index, nao); + + replace_vec(obj, from, to, newval); + return 0; + } else { + return vecref_l(obj, first(args)); + } + } case CONS: case LCONS: if (rest(args)) @@ -668,15 +684,32 @@ static val *dwim_loc(val form, val env) { val index = first(args); val cell = obj; - if (!bignump(index) && !fixnump(index)) - eval_error(form, lit("[~s ~s]: index must be integer"), + if (bignump(index) || fixnump(index)) { + for (; gt(index, zero); index = minus(index, one)) + cell = cdr(cell); + if (lt(index, zero) || !cell) + eval_error(form, lit("[~s ~s]: cannot assign nonexistent location"), + cell, first(args), nao); + return car_l(cell); + } else if (consp(index)) { + val from = eval(car(index), env, form); + val to = eval(cdr(index), env, form); + val newlist; + val tempform; + + if (op != set_s) + eval_error(form, lit("[~s ~s]: slice takes only simple assignments"), + cell, index, nao); + + newlist = replace_list(obj, from, to, newval); + tempform = list(op, second(form), + cons(quote_s, cons(newlist, nil)), nao); + eval(tempform, env, form); + return 0; + } else { + eval_error(form, lit("[~s ~s]: index must be integer, or pair"), cell, index, nao); - for (; gt(index, zero); index = minus(index, one)) - cell = cdr(cell); - if (lt(index, zero) || !cell) - eval_error(form, lit("[~s ~s]: cannot assign nonexistent location"), - cell, first(args), nao); - return car_l(cell); + } } case COBJ: { @@ -727,7 +760,9 @@ static val op_modplace(val form, val env) /* TODO: dispatch these with hash table. */ val sym = car(place); if (sym == dwim_s) { - loc = dwim_loc(place, env); + loc = dwim_loc(place, env, op, newval); + if (loc == 0) + return newval; } else if (sym == gethash_s) { val hash = eval(second(place), env, form); val key = eval(third(place), env, form); @@ -908,7 +943,17 @@ static val op_dwim(val form, val env) if (rest(args)) eval_error(form, lit("[~s ...]: vector indexing needs one arg"), obj, nao); - return vecref(obj, first(args)); + { + val index = first(args); + + if (consp(index)) { + val from = eval(car(index), env, form); + val to = eval(cdr(index), env, form); + return sub_vec(obj, from, to); + } else { + return vecref(obj, first(args)); + } + } case CONS: case LCONS: if (rest(args)) @@ -916,14 +961,21 @@ static val op_dwim(val form, val env) obj, nao); { val index = first(args); - if (!bignump(index) && !fixnump(index)) - eval_error(form, lit("[~s ~s]: index must be integer"), + if (!bignump(index) && !fixnump(index) && !consp(index)) + eval_error(form, lit("[~s ~s]: index must be integer or pair"), obj, index, nao); - if (lt(index, zero)) - return nil; - for (; gt(index, zero); index = minus(index, one)) - obj = cdr(obj); - return car(obj); + + if (consp(index)) { + val from = eval(car(index), env, form); + val to = eval(cdr(index), env, form); + return sub_list(obj, from, to); + } else { + if (lt(index, zero)) + return nil; + for (; gt(index, zero); index = minus(index, one)) + obj = cdr(obj); + return car(obj); + } } case COBJ: { @@ -4372,8 +4372,10 @@ shorthand for cons. That is to say, A .. B translates to (cons A B), and so for instance (a b .. (c d) e .. f . g) means (a (cons b (c d)) (cons e f) . g). -This is a syntactic sugar in certain situations in which a cons -is used to represent a pair of numbers or other objects. +This is a syntactic sugar useful in certain situations in which a cons is used +to represent a pair of numbers or other objects. For instance, if L +is a list, then [L 1 .. 3] computes a sublist of L consisting of +elements 1 through 2 (counting from zero). .SS The DWIM Brackets @@ -4843,10 +4845,22 @@ refers to the first element. Indexed list access does not throw exceptions. Negative indices yield nil, and indices beyond the end of a list yield nil. (However assignment to a nonexistent list element throws.) +.IP [<list> <from-index>..<to-below-index>] +Retrieve the specified range of elements, exactly as if +using (sub-list <list> <from-index> <to-below-index>). +The range of elements is specified in the car and cdr fields of a cons cell, +for which the .. (dotdot) syntactic sugar is useful. + .IP [<vector> <index>] Retrieve the specified element of a vector. This is equivalent to (vecref <vector> <index>). +.IP [<vector> <from-index>..<to-below-index>] +Retrieve the specified range of elements, exactly as if +using (sub-vec <list> <from-index> <to-below-index>). +The range of elements is specified in the car and cdr fields of a cons cell, +for which the .. (dotdot) syntactic sugar is useful. + .IP [<string> <index>] Retrieve the specified element of a string. This is equivalent to (chr-str <string> <index>). @@ -4858,6 +4872,12 @@ or <default-value> if there is no such entry. The list, vector and hash table forms of dwim denote places that can be assigned. +The list and vector range forms can be assigned only using the set operator, +not using the others like push and inc. Assigning to a vector range modifies +the vector object; it is implemented using replace-vec. Assigning to a list +range updates the form which contains the list, so the expression denoting the +list must be an assignable place. + .TP Notes: |