chiark / gitweb /
go-fringe.go: Language change: `closed' function on channels has gone.
[fringe] / dylan-fringe.dylan
CommitLineData
5c4e9900
MW
1module: dylan-fringe
2language: infix-dylan
3author: Mark Wooding
4copyright: (c) 2010 Mark Wooding
5
6/* -*-dylan-*-
7 *
8 * Dylan implementation of a `same-fringe' solver.
9 */
10
11///--------------------------------------------------------------------------
12/// Utilities.
13
14define macro loop
15 // loop (ESCAPE) BODY end [loop]
16 //
17 // Repeatedly evaluate the BODY, with ESCAPE bound to a procedure which
18 // causes the loop to end immediately and yield its argument.
19
20 { loop (?escape:variable) ?:body end }
21 => { block (?escape) while (#t) ?body end end }
22end;
23
24///--------------------------------------------------------------------------
25/// Nodes and trees.
26
27// We specialize methods on trees, whether leaves or non-leaves, so we need a
28// common superclass.
29define abstract class <tree> (<collection>) end;
30
31// A leaf is an empty tree. We don't use #f because we need to specialize
32// methods on empty trees too. We only need one leaf, but there's no point
33// in being petty about it.
34define class <leaf> (<tree>) end;
35define constant $leaf = make(<leaf>);
36
37// A node is a tree which carries data and has subtrees.
38define class <node> (<tree>)
39 constant slot left :: <tree>, required-init-keyword: left:;
40 constant slot right :: <tree>, required-init-keyword: right:;
41 slot data, init-keyword: data:, init-value: #f;
42end;
43
44// Use method dispatch to decide whether a tree is a leaf.
45define generic leaf?(tree) => (p :: <boolean>);
46define method leaf?(tree :: <leaf>) => (p :: <boolean>) #t end;
47define method leaf?(tree :: <node>) => (p :: <boolean>) #f end;
48
49define method parse-tree
50 (string :: <string>,
51 #key start :: <integer> = 0,
52 end: stop :: <integer> = string.size)
53 => (tree :: <tree>)
54 // Parse STRING, and return the tree described.
55 //
56 // The syntax is simple:
57 //
58 // tree ::= empty | `(' tree char tree `)'
59 //
60 // The ambigity is resolved by always treating `(' as a tree when a tree is
61 // expected.
62
63 local method parse(i :: <integer>) => (tree :: <tree>, i :: <integer>)
64 if (i >= stop | string[i] ~= '(')
65 values($leaf, i)
66 else
67 let (left, i) = parse(i + 1);
68 if (i >= stop) error("no data") end;
69 let data = string[i];
70 let (right, i) = parse(i + 1);
71 if (i >= stop | string[i] ~= ')') error("missing )") end;
72 values(make(<node>, left: left, right: right, data: data), i + 1)
73 end
74 end;
75 let (tree, i) = parse(start);
76 if (i ~= stop) error("trailing junk") end;
77 tree
78end;
79
80define method print-object(tree :: <tree>, stream :: <stream>) => ()
81 // Print a TREE to the given STREAM. No newline is printed.
82
83 local method recur(tree)
84 unless (tree.leaf?)
85 write(stream, "(");
86 recur(tree.left);
87 write-element(stream, tree.data);
88 recur(tree.right);
89 write(stream, ")");
90 end
91 end;
92 recur(tree)
93end;
94
95///--------------------------------------------------------------------------
96/// Iteration utilities.
97
98define method iterator(coll :: <collection>) => (iter :: <function>)
99 // Return a function which iterates over the collection COLL.
100 //
101 // Each call to the function returns two values: ANY? is false if the
102 // collection is exhausted, or true if a new item was returned; and ITEM is
103 // the item from the collection. Obviously, ITEM is meaningful only if
104 // ANY? is true.
105
106 let (state, final, next, finished?, key, item, item-setter, copy) =
107 forward-iteration-protocol(coll);
108 method () => (any? :: <boolean>, item :: <object>)
109 if (finished?(coll, state, final))
110 values(#f, #f)
111 else
112 let this = item(coll, state);
113 state := next(coll, state);
114 values(#t, this)
115 end
116 end
117end;
118
119define method same-collections?
120 (coll-a :: <collection>, coll-b :: <collection>) => (p :: <boolean>)
121 // Answer whether COLL-A and COLL-B contain the same elements (according to
122 // `=') in the same order.
123
124 let iter-a = iterator(coll-a);
125 let iter-b = iterator(coll-b);
126 loop (done)
127 let (any-a, item-a) = iter-a();
128 let (any-b, item-b) = iter-b();
129 case
130 any-a ~= any-b => done(#f);
131 ~ any-a => done(#t);
132 item-a ~= item-b => done(#f);
133 end
134 end
135end;
136
137///--------------------------------------------------------------------------
138/// Fringe iteration.
139
140define class <tree-iteration-state> (<object>)
141 // The iteration state for a tree. We remember the current node, and a
142 // closure which will produce the rest of the iteration. Iteration states
143 // are immutable.
144
145 constant slot node :: <tree>, required-init-keyword: node:;
146 constant slot next :: <function>, required-init-keyword: next:;
147end;
148
149define method forward-iteration-protocol(tree :: <tree>)
150 => (state, final,
151 next :: <function>, finished? :: <function>,
152 this-key :: <function>,
153 this-item :: <function>, this-item-setter :: <function>,
154 copy :: <function>)
155 // Iteration protocol implementation for the fringe of a binary tree.
156
157 local method iter(tree, after)
158 if (tree.leaf?)
159 after()
160 else
161 iter(tree.left,
162 method ()
163 make(<tree-iteration-state>,
164 node: tree,
165 next: method () iter(tree.right, after) end)
166 end)
167 end
168 end;
169
170 values(iter(tree, method () #f end), // initial state
171 #f, // final state
172 method (tree, state) state.next() end, // next state
173 method (tree, state, limit) ~ state end, // finished?
174 method (tree, state) state.node end, // current key
175 method (tree, state) state.node.data end, // current item
176 method (new, tree, state) state.node.data := new end, // modify item
177 identity) // copy state
178end;
179
180///--------------------------------------------------------------------------
181/// Main program.
182
183define method main(argv0 :: <string>, #rest argv) => ()
184 let prog = begin
185 let last = 0;
186 for (i from 0 below argv0.size)
187 if (argv0[i] = '/') last := i + 1 end
188 end;
189 copy-sequence(argv0, start: last)
190 end;
191 block ()
192 select (argv.size)
193 1 =>
194 let t = parse-tree(argv[0]);
195 let iter = iterator(t);
196 loop (done)
197 let (any?, item) = iter();
198 unless (any?) done(#f) end;
199 write-element(*standard-output*, item);
200 end;
201 new-line(*standard-output*);
202 2 =>
203 let ta = parse-tree(argv[0]);
204 let tb = parse-tree(argv[1]);
205 format(*standard-output*, "%s\n",
206 if (same-collections?(ta, tb)) "match" else "no match" end);
207 otherwise
208 error("bad args");
209 end
210 exception (cond :: <error>)
211 format(*standard-error*, "%s: %s\n", prog, cond);
212 exit(exit-code: 1)
213 end
214end
215
216///----- That's all, folks --------------------------------------------------