diff options
-rw-r--r-- | share/txr/stdlib/awk.tl | 6 | ||||
-rw-r--r-- | share/txr/stdlib/conv.tl | 83 | ||||
-rw-r--r-- | txr.1 | 113 |
3 files changed, 201 insertions, 1 deletions
diff --git a/share/txr/stdlib/awk.tl b/share/txr/stdlib/awk.tl index bc5dc9dd..b1e9f509 100644 --- a/share/txr/stdlib/awk.tl +++ b/share/txr/stdlib/awk.tl @@ -23,6 +23,8 @@ ;; AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS ;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +(load "conv.tl") + (defstruct sys:awk-state () (rs "\n") krs fs ft kfs @@ -202,7 +204,9 @@ (set f [(opip ,*opip-args) f]))) (mf (. opip-args) ^(symacrolet ((f (rslot ,',aws-sym 'fields 'f-to-rec))) - (set f (mapcar (opip ,*opip-args) f))))) + (set f (mapcar (opip ,*opip-args) f)))) + (fconv (. conv-args) + ^(set f (sys:conv (,*conv-args) f)))) ,*body))) (defmacro awk (:env e . clauses) diff --git a/share/txr/stdlib/conv.tl b/share/txr/stdlib/conv.tl new file mode 100644 index 00000000..546b8759 --- /dev/null +++ b/share/txr/stdlib/conv.tl @@ -0,0 +1,83 @@ +;; Copyright 2016 +;; Kaz Kylheku <kaz@kylheku.com> +;; Vancouver, Canada +;; All rights reserved. +;; +;; Redistribution of this software in source and binary forms, with or without +;; modification, is permitted provided that the following two conditions are met. +;; +;; Use of this software in any manner constitutes agreement with the disclaimer +;; which follows the two conditions. +;; +;; 1. Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in +;; the documentation and/or other materials provided with the +;; distribution. +;; +;; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +;; WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE +;; COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED, +;; AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS +;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(defun sys:conv-let (. body) + ^(flet ((i (arg : radix) + (toint arg radix)) + (o (arg) + (toint arg 8)) + (x (arg) + (toint arg 16)) + (b (arg) + (toint arg 2)) + (r (arg) + (tofloat arg))) + ,*body)) + +(defun sys:do-conv (lfl mfl tfl nm list) + (while (and list lfl) + (set (car list) (call (car lfl) (car list))) + (set list (cdr list)) + (set lfl (cdr lfl))) + (dotimes (i nm) + (unless list + (return)) + (when mfl + (set (car list) (call (car mfl) (car list))) + (set mfl (cdr mfl))) + (set list (cdr list))) + (while (and list tfl) + (set (car list) (call (car tfl) (car list))) + (set list (cdr list)) + (set tfl (cdr tfl)))) + +(defun sys:conv-expand (form specs list-sym) + (mac-param-bind form (lead : mid trail) + (split* (mapcar [iff (op eq :) + identity + [iff (op eq '-) + (retf '(fun identity)) + (ret ^[identity ,@1])]] + specs) + (op where (op eq :))) + (let ((nl (length lead)) + (nt (length trail))) + (with-gensyms (i nm lfl mfl tfl) + (sys:conv-let + ^(let* ((,nm (- (length ,list-sym) ,(+ nl nt))) + (,lfl (list ,*lead)) + (,mfl (if (plusp ,nm) (repeat (list ,*mid)))) + (,tfl (list ,*trail))) + (sys:do-conv ,lfl ,mfl ,tfl ,nm ,list-sym))))))) + +(defmacro sys:conv (:form form (. specs) list-expr) + (cond + ((null specs) list-expr) + ((atom specs) + (throwf 'eval-error "sys:conv: invalid conversion list: ~s" specs)) + (t (with-gensyms (list-sym) + ^(let ((,list-sym ,list-expr)) + ,(sys:conv-expand form specs list-sym) + ,list-sym))))) @@ -38260,6 +38260,119 @@ a binding which shadows (mf flo-str) .cble +.coNP Macro @ fconv +.synb +.mets (fconv >> { clause | : | - }*) +.syne +.desc +The awk macro +.code fconv +provides a succinct way to request conversions of the textual fields. +Conversions are expressed by clauses which correspond with fields. + +Each +.code clause +is an expression which must evaluate to a function. The clause is evaluated +in the same manner as the argument a +.code dwim +operator, using Lisp-1-style name lookup. Thus, functions may be +specified simply by using their name as a +.metn clause . + +Furthermore, several local functions exist in the scope of each +.codn clause , +providing a short-hand notation. These are described below. + +Conversion proceeds by applying the function produced by +a clause to the field to which that clause corresponds, positionally. +The return value of the function applied to the field replaces +the field. + +When a clause is specified as the symbol +.code - +(minus) +it has a special meaning: this minus clause occupies a field +position and corresponds to a field, but performs no conversion +on its field. + +The +.code : +(colon) +symbol isn't a clause and does not correspond to a field position. +Rather, it acts as a separator among clauses. It need not appear at +all. If it appears, it may appear at most twice. Thus, the +clauses may be separated into up to three sequences. + +If the colon does not appear, then all the clauses are +.IR "prefix clauses" . +Prefix clauses line up with fields from left to right. If there are fewer +fields than prefix clauses, the values of the excess clauses are evaluated, but +ignored. +.IR "Vice versa" , +if there are fewer prefix clauses than fields, then the excess +fields are not subject to conversions. + +If the colon appears once, then the clauses before the colon, if any, are +prefix clauses, as described in the previous paragraph. Clauses after the +colon, if any, are +.IR "interior clauses" . +Interior clauses apply to any fields which are left unconverted by the prefix +clauses. All interior clauses are evaluated. If there are fewer fields than +interior clauses, then the values of the excess interior clauses are ignored. +If there are more fields than clauses, then the clause values are cycled: +re-used from the beginning against the excess fields, enough times to convert +all the fields. + +If the colon appears twice, then the clauses before the first colon, if any, +are prefix clauses, the clauses between the two clause are interior clauses, +and those after the second colon are +.IR "suffix clauses" . +The presence of suffix clauses change the behavior relative to the one-colon +case as follows. After the conversions are performed according to the prefix +clauses, the remaining fields are counted. If there are are only as many +fields as there are suffix clauses, or fewer, then the interior clauses are +evaluated, but ignored. The remaining fields are processed against the suffix +clauses. If after processing the prefix clauses there are more fields +remaining than suffix clauses, then a number of rightmost fields equal to the +number of suffix clauses is reserved for those clauses. The interior fields +are applied only to the unreserved middle fields which precede these reserved +rightmost fields, using the same repeating behavior as in the one-colon case. +Finally, the previously reserved rightmost fields are processed using +the suffix clauses. + +The following special convenience functions are in scope of the clauses, +effectively providing a short-hand for commonly-needed conversions: +.RS +.coIP i +Provides conversion to integer. It is identical to the +.code toint +function. +.coIP o +Converts a string value holding an octal representation +to the integer which it denotes. The expression +.code "(o str)" +is equivalent to +.codn "(toint str 8)" . +.coIP x +Converts a string value holding a hexadecimal representation +to the integer which it denotes. The expression +.code "(x str)" +is equivalent to +.codn "(toint str 16)" . +.coIP b +Converts a string value holding a binary (base two) representation +to the integer which it denotes. The expression +.code "(c str)" +is equivalent to +.codn "(toint str 2)" . +.coIP r +Converts a string holding a floating-point representation to +the floating-point value which it denotes. The expression +.code "(r str)" +is equivalent to +.codn "(tofloat str)" . +.RE + .SS* Environment Variables and Command Line Note that environment variable names, their values, and command line |