diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-09-10 21:21:05 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-09-10 21:21:05 -0700 |
commit | 685ea1dd078bb9861a86b3af5d8b6d509e4fa982 (patch) | |
tree | d9155e8182419b5ad174a3a713b45546744f87d0 | |
parent | b26fd2a683aba1d25864ae38629fe2eae85fa3fe (diff) | |
download | txr-685ea1dd078bb9861a86b3af5d8b6d509e4fa982.tar.gz txr-685ea1dd078bb9861a86b3af5d8b6d509e4fa982.tar.bz2 txr-685ea1dd078bb9861a86b3af5d8b6d509e4fa982.zip |
awk macro: implement :begin-file and :end-file.
* share/txr/stdlib/awk.tl (sys:awk-compile-time): New slots,
begin-file-actions and end-file-actions.
(sys:awk-state loop): Take two additional functional arguments
for the begin file and end file actions, and do the
calls in the right places. unwind-protect triggers the
end file function.
(sys:awk-expander): Parse out :begin-file and :end-file
actions.
(awk): Generate lambdas for begin-file and end-file actions,
if they are defined. Pass these to the loop method.
The code is refactored here to do one big sys:awk-let
around everything.
* txr.1: Documented :begin-file and :end-file, revising
the :begin and :end documentation in the process.
-rw-r--r-- | share/txr/stdlib/awk.tl | 85 | ||||
-rw-r--r-- | txr.1 | 98 |
2 files changed, 135 insertions, 48 deletions
diff --git a/share/txr/stdlib/awk.tl b/share/txr/stdlib/awk.tl index 632b2fcc..de6bcb71 100644 --- a/share/txr/stdlib/awk.tl +++ b/share/txr/stdlib/awk.tl @@ -41,7 +41,10 @@ (set self.output (open-file self.output "w"))))) (defstruct sys:awk-compile-time () - inputs output name lets begin-actions end-actions cond-actions + inputs output name lets + begin-file-actions end-file-actions + begin-actions end-actions + cond-actions (nranges 0) rng-expr-temps rng-exprs) @@ -62,25 +65,30 @@ (set self.fields (take self.nf (append self.fields (repeat '(""))))) self.(f-to-rec)) -(defmeth sys:awk-state loop (aws func) +(defmeth sys:awk-state loop (aws func beg-file-func end-file-func) (whilet ((in (pop aws.inputs))) (block :awk-file (inc aws.file-num) - (let ((recin (record-adapter (if (regexp aws.rs) - aws.rs - (regex-compile aws.rs)) - (if (streamp in) - in - (open-file in))))) - (set aws.file-rec-num 0) - (whilet ((rec (get-line recin))) - (set aws.rec rec) - (inc aws.rec-num) - (inc aws.file-rec-num) - aws.(rec-to-f) - (block :awk-rec - (let ((*stdout* aws.output)) - [func aws]))))))) + (when beg-file-func + [beg-file-func aws]) + (unwind-protect + (let ((recin (record-adapter (if (regexp aws.rs) + aws.rs + (regex-compile aws.rs)) + (if (streamp in) + in + (open-file in))))) + (set aws.file-rec-num 0) + (whilet ((rec (get-line recin))) + (set aws.rec rec) + (inc aws.rec-num) + (inc aws.file-rec-num) + aws.(rec-to-f) + (block :awk-rec + (let ((*stdout* aws.output)) + [func aws])))) + (when end-file-func + [end-file-func aws]))))) (defmeth sys:awk-state prn (self . args) (put-string `@{(if args args self.rec) self.ofs}@{self.ors}`)) @@ -114,6 +122,8 @@ (:let (push actions awc.lets)) (:begin (push actions awc.begin-actions)) (:end (push actions awc.end-actions)) + (:begin-file (push actions awc.begin-file-actions)) + (:end-file (push actions awc.end-file-actions)) (t (push (if actions cl ^(,pattern (prn))) @@ -122,6 +132,8 @@ (set awc.lets [apply append (nreverse awc.lets)] awc.begin-actions [apply append (nreverse awc.begin-actions)] awc.end-actions [apply append (nreverse awc.end-actions)] + awc.begin-file-actions [apply append (nreverse awc.begin-file-actions)] + awc.end-file-actions [apply append (nreverse awc.end-file-actions)] awc.cond-actions (nreverse awc.cond-actions)) awc)) @@ -160,7 +172,7 @@ (defmacro awk (:env e . clauses) (let ((awc (sys:awk-expander clauses))) - (with-gensyms (aws-sym awk-fun awk-retval) + (with-gensyms (aws-sym awk-begf-fun awk-fun awk-endf-fun awk-retval) (let* ((p-actions-xform-unex (mapcar (aret ^(when ,@1 ,*@rest)) awc.cond-actions)) (p-actions-xform (sys:expand @@ -168,22 +180,31 @@ ,*p-actions-xform-unex) e))) ^(let* (,*awc.lets ,awk-retval) - (let* ((,aws-sym (new sys:awk-state - ,*(if awc.inputs ^(inputs (list ,*awc.inputs))) - ,*(if awc.output ^(output ,awc.output)) - rng-n (macro-time (qref ,awc nranges)))) - (,awk-fun (lambda (,aws-sym) - (sys:awk-let ,awc ,aws-sym + (sys:awk-let ,awc ,aws-sym + (let* ((,aws-sym (new sys:awk-state + ,*(if awc.inputs ^(inputs (list ,*awc.inputs))) + ,*(if awc.output ^(output ,awc.output)) + rng-n (macro-time (qref ,awc nranges)))) + ,*(if awc.begin-file-actions + ^((,awk-begf-fun (lambda (,aws-sym) + ,*awc.begin-file-actions)))) + ,*(if awc.end-file-actions + ^((,awk-endf-fun (lambda (,aws-sym) + ,*awc.end-file-actions)))) + (,awk-fun (lambda (,aws-sym) ,(if awc.rng-exprs ^(let* ,(nreverse (zip awc.rng-expr-temps awc.rng-exprs)) ,p-actions-xform) - p-actions-xform))))) - (sys:awk-let ,awc ,aws-sym - ,*awc.begin-actions) - (block ,awc.name - (unwind-protect - (qref ,aws-sym (loop ,awk-fun)) - (set ,awk-retval (progn ,*awc.end-actions))) - ,awk-retval))))))) + p-actions-xform)))) + ,*awc.begin-actions + (block ,awc.name + (unwind-protect + (qref ,aws-sym (loop ,awk-fun + ,(if awc.begin-file-actions + awk-begf-fun) + ,(if awc.end-file-actions + awk-endf-fun))) + (set ,awk-retval (progn ,*awc.end-actions))) + ,awk-retval)))))))) @@ -37137,7 +37137,10 @@ with special semantics: .codn :inputs , .codn :outputs , .codn :begin , -.codn :end . +.codn :end , +.code :begin-file +and +.codn :end-file . These clause types are explained below. In such a clause, the .meta action @@ -37289,36 +37292,46 @@ macro established by the .code awk macro. .meIP (:begin << form *) -Begin forms are all processed in the order in which they appear, just before -any records are processed. Each +All +.code :begin +clauses are processed in the order in which they appear, before +input processing begins. +Each .code form is evaluated. These forms have in their scope the awk local variables and macros. .meIP (:end << form *) -End forms are processed when the -.code awk -form terminates, which occurs when all records +All +.code :end +clauses are processed, in the order in which they appear, +when the input processing loop terminates. +This termination occurs when all records from all input sources are either processed or skipped, or else by an explicit termination such as a dynamic non-local transfer, such as .codn return-from , -or the throwing of an exception, issued from an ordinary clause. +or the throwing of an exception. -Upon termination, the -.code :end -clauses are processed in the order they appear. Each +Upon termination, the end clauses are processed in the order they appear. Each .code form is evaluated, left to right. In the normal termination case, the value of the last .meta form -of the last -.code :end -clause appears as the return value of the +of the last end clause appears as the return value of the .code awk macro. -Note that if termination of the +Note that only termination of the +.code awk +macro initiated from condition-action clauses, +.code :begin-file +clauses, or +.code :end-file +clauses triggers +.code :end +clause processing. +If termination of the .code awk macro is initiated from within a .codn :let , @@ -37326,9 +37339,62 @@ macro is initiated from within a .code :output or .code :begin -clause, then -.code :end +clause, then end clauses are not processed. +If an +.code :end +clause performs a non-local transfer, the remaining +.code :end +forms in that clause and +.code :end +clauses which follow are not evaluated. +.meIP (:begin-file << form *) +All +.code :begin-file +clauses are processed in the order in which they appear, before +.code awk +switches to each new input. + +If both +.code :begin +and +.code :begin-file +forms are specified, then before the first input is processed, +.code :begin +clauses are processed first, then the +.code :begin-file +clauses. +.meIP (:end-file << form *) +All +.code :end-file +clauses are processed after the processing of an input +source finishes. + +If both +.code :end +and +.code :end-file +forms are specified, then before after the last input is processed, +.code :end-file +clauses are processed first, then the +.code :end +clauses. + +The +:end-file +clauses are processed unconditionally, no matter how +the processing of an input source terminates, whether terminated +naturally by running out of records, prematurely by invocation of the +.code next-file +macro, or via a dynamic non-local control transfer such as a block +return or exception throw. + +If a +.code :begin-file +clause performs a non-local transfer, +.code :end-file +processing is not triggered, because the processing of the input +source is deemed not to have taken place. .meIP >> ( condition << action *) Clauses which do not have one of the specially recognized keywords in the first position are ordinary condition-action clauses. After |