summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-09-10 21:21:05 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-09-10 21:21:05 -0700
commit685ea1dd078bb9861a86b3af5d8b6d509e4fa982 (patch)
treed9155e8182419b5ad174a3a713b45546744f87d0
parentb26fd2a683aba1d25864ae38629fe2eae85fa3fe (diff)
downloadtxr-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.tl85
-rw-r--r--txr.198
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))))))))
diff --git a/txr.1 b/txr.1
index dc6874cc..d4a42a72 100644
--- a/txr.1
+++ b/txr.1
@@ -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