diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | eval.c | 9 | ||||
-rw-r--r-- | txr.1 | 24 |
3 files changed, 38 insertions, 4 deletions
@@ -1,5 +1,14 @@ 2014-01-23 Kaz Kylheku <kaz@kylheku.com> + * eval.c (expand_op): Takes sym argument to distinguish op and do. + The dwim operator is deleted when the symbol is do. + (expand): Expand do_s form with expand_op, not only op_s. Pass down + symbol. + + * txr.1: Document do operator. + +2014-01-23 Kaz Kylheku <kaz@kylheku.com> + * eval.c (do_eval): Fix incorrect, recently introduced code rearrangement that gives precedence to operator lookup over function lookup. @@ -1611,7 +1611,7 @@ static val supplement_op_syms(val ssyms, val max) return outsyms; } -static val expand_op(val body) +static val expand_op(val sym, val body) { val body_ex = expand_forms(body); val rest_gensym = gensym(lit("rest-")); @@ -1637,6 +1637,9 @@ static val expand_op(val body) append2(body_trans, rest_gensym))), body_trans); + if (sym == do_s) + dwim_body = rlcp(cdr(dwim_body), dwim_body); + return cons(lambda_s, cons(append2(mapcar(cdr_f, ssyms), rest_gensym), cons(dwim_body, nil))); @@ -1793,8 +1796,8 @@ val expand(val form) return expand(expand_gen(rest(form))); } else if (sym == delay_s) { return expand(expand_delay(rest(form))); - } else if (sym == op_s) { - return expand_op(rest(form)); + } else if (sym == op_s || sym == do_s) { + return expand_op(sym, rest(form)); } else if (sym == catch_s) { return expand_catch(rest(form)); } else if (sym == regex_s || regexp(sym)) { @@ -10065,16 +10065,19 @@ for these common keys are those from <hash1>. .SH PARTIAL EVALUATION AND COMBINATORS -.SS Operator op +.SS Operators op and do .TP Syntax: (op {<form>}+) + (do {<form>}+) .TP Description: +The op and do operators are similar. + Like the lambda operator, the op operator creates an anonymous function. The difference is that the arguments of the function are implicit, or optionally specified within the function body. @@ -10083,6 +10086,18 @@ Also, the <form> arguments of op are implicitly turned into a DWIM expression, which means that argument evaluation follows Lisp-1 rules. (See the dwim operator below). +The do operator is like the op operator with the following difference: +the <form> arguments of op are not implicitly treated as a DWIM expression, +but as an ordinary expression. In particular, this means that operator +syntax is permitted. Note that the syntax (op @1) makes sense, since +the argument can be a function, which will be invoked, but (do @1) doesn't +make sense because it will produce a Lisp-2 form like (#:arg1 ...) referring +to nonexistent function #:arg1. This is why the operator is called "do": it +requires some operation. Moreover, it can be used with imperative constructs +which are not functions, like set: like set: for instance (do set x) produces +an anonymous function which, if called with one argument, stores that argument +into x. + The argument forms are arbitrary expressions, within which a special convention is permitted: @@ -10127,12 +10142,19 @@ symbols in the program. (op foo @rest @1) -> (lambda (arg1 . rest) [foo rest arg1]) + (do + foo) -> (lambda rest (+ foo . rest)) + + (do @1 @2) -> (lambda (arg1 arg2 . rest) (arg1 arg2)) + + (do foo @rest @1) -> (lambda (arg1 . rest) (foo rest arg1)) + Note that if argument @<n> appears, it is not necessary for arguments @1 through @<n-1> to appear. The function will have n arguments: (op @3) -> (lambda (arg1 arg2 arg3 . rest) [arg3]) + .PP .TP |