~crc_/retroforth

ref: 5d9c9f1ad3ad64fe312798aff34bb642ad4c8d19 retroforth/tools/retro-describe.retro -rwxr-xr-x 4.3 KiB
5d9c9f1a — crc update references to old s:split in retro-describe 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/usr/bin/env retro

# retro-describe

This is a small tool to display some helpful information
about a word.

# Usage

    retro-describe wordname

# Notes

This is based on the `glossary.forth` tool included with
Retro. It's basically just the `describe` functionality,
but is a little more streamlined to use and abandons the
editing and export functionality of the full tool.

# The Code

First, gather the command line arguments. If no word name
was passed, just exit.

~~~
script:arguments n:zero? [ #0 unix:exit ] if
~~~

~~~
#166 'DATA-START const
~~~

# Data File

/usr/local/share/RETRO12/words.tsv

I like plain text formats, so the data is stored as a plain text
file, with one line per word. Each line has a number of fields.
These are tab separated. The fields are:

    | name                       | 0
    | data stack                 | 1
    | address stack              | 2
    | float stack                | 3
    | general description        | 4
    | interpret time description | 5
    | compile time description   | 6
    | class handler              | 7
    | example 1                  | 8
    | example 2                  | 9
    | namespace                  | 10
    | interface                  | 11

I use a variable named `SourceLine` to point to the current line
contents.

~~~
'SourceLine var
~~~

I next define words to access each field. This involves helpers
to skip over fields I'm not intersted in, a word to return a 
specific field, and the top level wrappers over these.

Rather than manually enter each of the field accessors, I am
just listing them in a set and constructing the words via some
simple code.

~~~
{{
  :skip (n-) [ ASCII:HT s:split/char drop n:inc ] times ;
  :select   (n-s)
    @SourceLine swap skip ASCII:HT s:split/char nip ;

---reveal---

  #0 { 'name        'dstack     'astack     'fstack
       'descr       'itime      'ctime      'class
       'ex1         'ex2        'namespace  'interface }

  [ 'field: s:prepend d:create
    dup compile:lit &select compile:call compile:ret
    &class:word reclass n:inc ] a:for-each drop
}}
~~~

# Display an Entry

I implement a word to display an entry. This will use a
format like:

    name

      Data:  -
      Addr:  -
      Float: -

    A description of the word.

    Class Handler: class:word | Namespace: global | Interface Layer: all

If there are specific notes on interpret or compile time
actions, or any examples, they will be displayed after
the description.

~~~
{{
  :s:putfmt (s-)   s:format s:put ;
  :name            field:name    '%s\n\n           s:putfmt ;
  :data            field:dstack  '__Data:__%s\n    s:putfmt ;
  :address         field:astack  '__Addr:__%s\n    s:putfmt ;
  :float           field:fstack  '__Float:_%s\n\n  s:putfmt ;
  :description     field:descr   '%s\n\n           s:putfmt ;
  :interpret-time  field:itime s:length 0; drop
                   field:itime   'Interpret_Time:\n__%s\n\n s:putfmt ;
  :compile-time    field:ctime s:length 0; drop
                   field:ctime   'Compile_Time:\n__%s\n\n   s:putfmt ;
  :|                               '_|_ s:put ;
  :class           field:class     'Class:_%s     s:putfmt ;
  :namespace       field:namespace 'Namespace:_%s s:putfmt ;
  :interface       field:interface 'Interface_Layer:_%s s:putfmt ;
  :example1        field:ex1 '{n/a} s:eq? not 0; drop
                   field:ex1 s:format '\nExample_#1:\n\n%s\n\n s:putfmt ;
  :example2        field:ex2 '{n/a} s:eq? not 0; drop
                   field:ex2 s:format '\nExample_#2:\n\n%s\n\n s:putfmt ;
---reveal---
  :display-result
    name
      data    (stack)
      address (stack)
      float   (stack)
    description
    interpret-time
    compile-time
    class | namespace | interface nl
    example1
    example2 ;
}}
~~~

## Describe a Word

~~~
{{
  'Target var
  'LineNumber var
  :matched? (-f) field:name @Target s:eq? ;
  :entry?   (-f) @LineNumber DATA-START gteq? &LineNumber v:inc ;
  :process  (-)  &Heap [ s:keep !SourceLine matched? [ display-result ] if ] v:preserve ;
---reveal---
  :find-and-display-entry
    #0 !LineNumber  s:keep !Target
    script:name [ entry? [ process ] [ drop ] choose ] file:for-each-line nl ;
}}
~~~

# Finish

This checks the command line arguments and calls the proper words to
handle each case.

~~~
script:arguments [ I script:get-argument find-and-display-entry ] indexed-times
~~~

# Glossary Data