Skip to content

Commit d10a340

Browse files
authored
Love for collectors (dylan-lang#1627)
2 parents 8fa5f5a + afad952 commit d10a340

File tree

10 files changed

+198
-22
lines changed

10 files changed

+198
-22
lines changed

documentation/source/library-reference/collections/collectors.rst

+102-8
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,111 @@ The collectors Module
55
.. current-library:: collections
66
.. current-module:: collectors
77

8+
.. macro:: collecting
9+
:statement:
10+
11+
Collect values into a named or unnamed collector. A collector may be, for example, a
12+
:drm:`<collection>`, a number into which values are accumulated, etc.
13+
14+
:macrocall:
15+
.. parsed-literal::
16+
17+
collecting ([`name`] [as `type`])
18+
[ `body` ]
19+
end [ collecting ]
20+
21+
:parameter name: A Dylan variable-name *BNF*. If omitted, the collection is returned
22+
from the :macro:`collecting` macro call. If supplied, the caller is responsible for
23+
calling ``collected(name)`` to retrieve the collection before the call to
24+
`collecting` terminates.
25+
:parameter type: A Dylan type. The default value is :drm:`<list>`.
26+
:parameter body: A Dylan body *BNF*.
27+
28+
:description:
29+
30+
Binds *name* (or a default variable name if *name* is not supplied) to a collector
31+
that can efficiently collect new values into the collection when :macro:`collect`
32+
or the related ``collect-*`` macros are called.
33+
34+
:example:
35+
36+
.. code-block:: dylan
37+
38+
collecting () collect(1); collect(2) end;
39+
// => #(1, 2)
40+
41+
collecting () collect(1); collect-first(2) end;
42+
// => #(2, 1)
43+
44+
collecting (as <integer>) collect(1); collect(2) end;
45+
// => 3
46+
47+
collecting (a, b, c)
48+
collect-into(a, 1);
49+
collect-into(b, 2);
50+
collect-into(c, 3);
51+
values(collected(a), collected(b), collected(c)
52+
end;
53+
// => #(1), #(2), #(3)
54+
855
.. macro:: collect
956

57+
:description: Collect a value at the end of the unnamed collector: ``collect(100)``
58+
May only be used when ``collecting () ... end`` was called with no arguments.
59+
60+
:seealso: :macro:`collecting`
61+
1062
.. macro:: collect-first
1163

12-
.. macro:: collect-first-into
64+
:description: Collect a value at the beginning of the unnamed collector:
65+
``collect-first(100)`` May only be used when ``collecting () ... end`` was called
66+
with no arguments.
1367

14-
.. macro:: collect-into
68+
:seealso: :macro:`collecting`
1569

1670
.. macro:: collect-last
1771

72+
:description: Collect a value at the end of the unnamed collector:
73+
``collect-last(100)`` May only be used when ``collecting () ... end`` was called
74+
with no arguments.
75+
76+
:seealso: :macro:`collecting`
77+
78+
.. macro:: collect-into
79+
80+
:description: Collect a value at the end of a named collector: ``collect-into(c,
81+
100)`` May only be used when ``collecting (c) ... end`` was called with arguments.
82+
83+
:seealso: :macro:`collecting`
84+
85+
.. macro:: collect-first-into
86+
87+
:description: Collect a value at the beginning of a named collector:
88+
``collect-first-into(c, 100)`` May only be used when ``collecting (c) ... end`` was
89+
called with arguments.
90+
91+
:seealso: :macro:`collecting`
92+
1893
.. macro:: collect-last-into
1994

95+
:description: Collect a value at the end of a named collector: ``collect-last-into(c,
96+
100)`` May only be used when ``collecting (c) ... end`` was called with arguments.
97+
98+
:seealso: :macro:`collecting`
99+
20100
.. macro:: collected
21101

22-
.. macro:: collecting
102+
:description: Retrieve the value of the collection associated with a collector.
103+
104+
:example:
105+
106+
.. code-block:: dylan
107+
108+
collecting () ... map(f, collected()) ... end
109+
110+
collecting (a, b) ... map(f1, collected(a)); map(f2, collected(b)); ... end
111+
112+
:seealso: :macro:`collecting`
23113

24114
.. generic-function:: collector-protocol
25115
:open:
@@ -28,9 +118,13 @@ The collectors Module
28118

29119
:parameter class: An instance of :drm:`<object>`.
30120
:value new-collector: An instance of :drm:`<object>`.
31-
:value add-first: An instance of :drm:`<function>`.
32-
:value add-last: An instance of :drm:`<function>`.
33-
:value add-sequence-first: An instance of :drm:`<function>`.
34-
:value add-sequence-last: An instance of :drm:`<function>`.
35-
:value collection: An instance of :drm:`<function>`.
121+
:value add-first: A :drm:`<function>` that accepts the collection and a value and adds
122+
the value to the beginning of the collection.
123+
:value add-last: A :drm:`<function>` that accepts the collection and a value and adds
124+
the value to the end of the collection.
125+
:value add-sequence-first: An instance of :drm:`<function>`. **Not yet implemented.**
126+
:value add-sequence-last: An instance of :drm:`<function>`. **Not yet implemented.**
127+
:value collection: A :drm:`<function>` that receives the collector and returns the
128+
collection.
36129

130+
:seealso: :macro:`collecting`

sources/collections/collectors-macros.dylan

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ License: See License.txt in this distribution for details.
77
Warranty: Distributed WITHOUT WARRANTY OF ANY KIND
88

99
// Unfortunately, the implicitly generated name for a collecting () call
10-
// has to be antigygienic so that it can be referred to by name in more
10+
// has to be unhygienic so that it can be referred to by name in more
1111
// than one macro.
1212

1313
define macro collecting
@@ -28,6 +28,10 @@ define macro collecting
2828
?body;
2929
collected(?=_collector)
3030
end }
31+
// This variant could have returned values(collected(var1), collected(var2), ...)
32+
// to match the way unnamed collections work, but unfortunately that would break
33+
// current callers if it were changed now. (The callers I checked in OD would be
34+
// trivial to convert.)
3135
{ collecting (?vars) ?:body end }
3236
=> { ?vars;
3337
?body }
@@ -84,6 +88,8 @@ define macro collect-into
8488
end macro;
8589

8690
define macro collected
91+
{ collected () }
92+
=> { collected(?=_collector) }
8793
{ collected (?:name) }
8894
=> { ?name ## "-collection"(?name ## "-collector") }
8995
end macro;

sources/collections/collectors.dylan

+8-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ define open generic collector-protocol (class, #key)
1414
add-sequence-last :: <function>,
1515
collection :: <function>);
1616

17-
//// Default.
17+
//// By default collect into a <list>.
1818

1919
define inline sealed method collector-protocol
2020
(class == <object>, #rest options, #key)
@@ -65,12 +65,16 @@ define inline sealed method collector-protocol
6565
add-sequence-last :: <function>,
6666
collection :: <function>)
6767
values(begin
68-
let head-pair = pair(#f, #());
69-
head(head-pair) := head-pair;
68+
let head-pair = pair(#f, #()); // The collector is #(final-pair . collection)
69+
head(head-pair) := head-pair; // except when the collection is empty.
7070
end,
7171
method (collector :: <pair>, value)
72-
let new-pair = pair(value, collector.tail);
72+
let t = collector.tail;
73+
let new-pair = pair(value, t);
7374
collector.tail := new-pair;
75+
if (empty?(t))
76+
collector.head := new-pair;
77+
end;
7478
value;
7579
end,
7680
method (collector :: <pair>, value)
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module: collections-test-suite-app
22
3-
run-test-application(collections-test-suite);
3+
run-test-application();

sources/collections/tests/collections-test-suite.lid

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Files: library
1414
bit-count
1515
bit-set-tests
1616
table-extensions
17+
collectors
1718
collections-test-suite
1819
Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc.
1920
All rights reserved.
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
Module: collections-test-suite
2+
3+
4+
define test test-collect ()
5+
assert-instance?(<list>, collecting() end, "default collection type is <list>?");
6+
assert-equal(#(1, 2, 3),
7+
collecting ()
8+
collect(1);
9+
collect(2);
10+
collect(3);
11+
end,
12+
"items are added at the end by default for lists?");
13+
assert-equal(#(2, 1, 3),
14+
collecting ()
15+
collect(1);
16+
collect-first(2);
17+
collect-last(3);
18+
end,
19+
"collect-first adds to the beginning of the collection?");
20+
let c = collecting ()
21+
collect(1);
22+
collect(2);
23+
collect-first(3);
24+
assert-equal(#(3, 1, 2), collected(),
25+
"collected() works for unnamed collections?");
26+
collect(5);
27+
end;
28+
assert-equal(#(3, 1, 2, 5), c, "collecting returns the collection?");
29+
end test;
30+
31+
// Note that for named collections the collection isn't automatically returned from the
32+
// body of `collecting`, unlike for unnamed collections. See comment in the `collecting`
33+
// macro.
34+
define test test-collect-into ()
35+
assert-equal(#(1, 2, 3),
36+
collecting (c)
37+
collect-into(c, 1);
38+
collect-into(c, 2);
39+
collect-into(c, 3);
40+
collected(c)
41+
end,
42+
"items are added at the end by default?");
43+
assert-equal(#(2, 1, 3),
44+
collecting (c)
45+
collect-into(c, 1);
46+
collect-first-into(c, 2);
47+
collect-last-into(c, 3);
48+
collected(c)
49+
end,
50+
"collect-first-into adds to the beginning of the collection?");
51+
let cc = collecting (c)
52+
collect-first-into(c, 1); // first/last should not matter here
53+
assert-equal(#(1), collected(c));
54+
collect-last-into(c, 2);
55+
assert-equal(#(1, 2), collected(c));
56+
collect-first-into(c, 3);
57+
assert-equal(#(3, 1, 2), collected(c),
58+
"collected(c) works for named collections?");
59+
collect-last-into(c, 5);
60+
collected(c)
61+
end;
62+
assert-equal(#(3, 1, 2, 5), cc, "collecting returns the collection?");
63+
end test;
64+
65+
define test test-collecting-as ()
66+
let c = collecting (as <vector>)
67+
collect(1);
68+
collect(2);
69+
end;
70+
assert-instance?(<vector>, c);
71+
assert-equal(#[1, 2], c);
72+
73+
let c = collecting (as <integer>)
74+
collect(1);
75+
collect(2);
76+
end;
77+
assert-equal(c, 3);
78+
end test;
79+

sources/lib/source-records/file-source-records-library.dylan

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ define module file-source-records-implementation
3535
use threads;
3636
use locators;
3737
// Probably don't need all this, sort it out later
38-
// use collectors;
3938
use byte-vector;
4039
use set;
4140
use streams;

sources/lib/source-records/source-records-library.dylan

-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ define module source-records-implementation
8282
use common-dylan;
8383
use threads;
8484
// Probably don't need all this, sort it out later
85-
// use collectors;
8685
use set;
8786
use byte-vector;
8887
use streams;

sources/project-manager/projects/projects-library.dylan

-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ define library projects
1313
use release-info;
1414
use dood; //---*** andrewa: just for with-walk-progress
1515
// Probably don't need all this, sort it out later...
16-
use collections;
1716
use io;
1817
use system;
1918

@@ -150,8 +149,6 @@ define module projects-implementation
150149
import: { \with-walk-progress };
151150

152151
// Probably don't need all this, sort it out later...
153-
use collectors;
154-
use set;
155152
use locators;
156153
use streams;
157154
use format;

sources/project-manager/registry-projects/registry-projects-library.dylan

-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Warranty: Distributed WITHOUT WARRANTY OF ANY KIND
88
define library registry-projects
99
use dylan;
1010
// Probably don't need all this, sort it out later...
11-
use collections;
1211
use io;
1312
use system;
1413
use build-system;
@@ -26,8 +25,6 @@ define module registry-projects-internal
2625
use dylan-extensions;
2726
use simple-debugging;
2827
// Probably don't need all this, sort it out later...
29-
use collectors;
30-
use set;
3128
use streams;
3229
use locators;
3330
use format;

0 commit comments

Comments
 (0)