retroforth/example/display-names.retro
crc 06ee9705a8 image: rename some words
s:contains-char?  to  s:contains/char?
s:contains-string? to s:contains/string?
a:contains-string? to a:contains/string?

old names are now deprecated and will be removed after 2021.7.

FossilOrigin-Name: 5a19d7aac514c5ba87963c5f0645f3daa8a8e3dc04546c0627fa046479ecd8dd
2021-06-04 13:54:21 +00:00

80 lines
2.6 KiB
Forth

Forth systems often have a word that displays the names of all
words in the dictionary. This can be helpful on occasion, but it
doesn't provide very much information and can be quite daunting
to newer users.
In Retro, I want to do better. The first step towards this is to
allow listing words in different ways. Retro includes two for
doing this:
word stack description
================ ===== ===================================
d:words - display all words in the dictionary
d:words-with s- display words with the specified
substring in their name
In this, I propose two additional ones:
word stack description
================ ===== ===================================
d:words-in-class a- display words with the specified
class handler
d:words-by-class - display all words, grouped by their
class handler
The first is pretty easy. Retro has a `d:for-each` combinator
for iterating over the dictionary. With this I can pass a pointer
to the class handler and compare this to each header, showing
only the entries that match.
I am using `reorder` to setup the stack. I could also have done
this via `[ over ] dip swap` or `push over pop swap`. The use of
`reorder` is simply done to make the stack alteration obvious.
~~~
:d:words-in-class (a-)
[ dup d:class fetch
'abc 'abca reorder
eq? [ d:name s:put sp ] &drop choose ] d:for-each
drop ;
~~~
The second one is a little more involved.
First, all class handlers must be identified. I do this with the
`d:for-each` combinator, looking for names that have a `class:`
prefix. (This suffices as I keep all my class handlers in the
`class:` namespace; it won't pick up ones with non-standard naming)
I iterate over the dictionary and construct a set to hold a pointer
to the header for each class I identify.
The exposed word also uses `d:for-each`, iterating over the
dictionary once for each class in the set. It displays the name of
the class, and then uses `d:words-in-class` to display the words.
Of note here, creating a set consumes space. I'm using the
`v:preserve` combinator to preserve the location of `here` so that
any used space is recovered.
~~~
{{
:identify-classes (-a)
here #0 ,
[ dup d:name 'class: s:contains/string?
&, &drop choose ] d:for-each
here over - n:dec over store ;
---reveal---
:d:words-by-class
&Heap [ identify-classes
[ [ d:name s:put nl ]
[ d:xt fetch d:words-in-class ] bi
nl nl ] a:for-each ] v:preserve ;
}}
~~~
```
d:words-by-class
```