]> gitweb.factorcode.org Git - factor.git/blob - core/vocabs/parser/parser-docs.factor
Update documentation for stricter vocabulary search path semantics
[factor.git] / core / vocabs / parser / parser-docs.factor
1 USING: help.markup help.syntax parser strings words assocs vocabs ;
2 IN: vocabs.parser
3
4 ARTICLE: "word-search-errors"  "Word lookup errors"
5 "If the parser cannot not find a word in the current vocabulary search path, it attempts to look for the word in all loaded vocabularies."
6 $nl
7 "If " { $link auto-use? } " mode is off, a restartable error is thrown with a restart for each vocabulary in question, together with a restart which defers the word in the current vocabulary, as if " { $link POSTPONE: DEFER: } " was used."
8 $nl
9 "If " { $link auto-use? } " mode is on and only one vocabulary has a word with this name, the vocabulary is added to the search path and parsing continues."
10 $nl
11 "If any restarts were invoked, or if " { $link auto-use? } " is on, the parser will print the correct " { $link POSTPONE: USING: } " after parsing completes. This form can be copy and pasted back into the source file."
12 { $subsection auto-use? } ;
13
14 ARTICLE: "word-search-syntax" "Syntax to control word lookup"
15 "Parsing words which make all words in a vocabulary available:"
16 { $subsection POSTPONE: USE: }
17 { $subsection POSTPONE: USING: }
18 { $subsection POSTPONE: QUALIFIED: }
19 { $subsection POSTPONE: QUALIFIED-WITH: }
20 "Parsing words which make a subset of all words in a vocabulary available:"
21 { $subsection POSTPONE: FROM: }
22 { $subsection POSTPONE: EXCLUDE: }
23 { $subsection POSTPONE: RENAME: }
24 "Removing vocabularies from the search path:"
25 { $subsection POSTPONE: UNUSE: }
26 "In the listener, the " { $vocab-link "scratchpad" } " is the default vocabulary for new word definitions. In source files, there is no default vocabulary. Defining words before declaring a vocabulary with " { $link POSTPONE: IN: } " results in an error."
27 { $subsection POSTPONE: IN: } ;
28
29 ARTICLE: "word-search-semantics" "Resolution of ambiguous word names"
30 "There is a distinction between parsing words which perform “open” imports versus “closed” imports. An open import introduces all words from a vocabulary as identifiers, except possibly a finite set of exclusions. The " { $link POSTPONE: USE: } ", " { $link POSTPONE: USING: } " and " { $link POSTPONE: EXCLUDE: } " words perform open imports. A closed import only adds a fixed set of identifiers. The " { $link POSTPONE: FROM: } ", " { $link POSTPONE: RENAME: } ", " { $link POSTPONE: QUALIFIED: } " and " { $link POSTPONE: QUALIFIED-WITH: } " words perform closed imports. Note that the latter two are considered as closed imports, due to the fact that all identifiers they introduce are unambiguously qualified with a prefix. The " { $link POSTPONE: IN: } " parsing word also performs a closed import of the newly-created vocabulary."
31 $nl
32 "When the parser encounters a reference to a word, it first searches the closed imports, in order. Closed imports are searched from the most recent to least recent. If the word could not be found this way, it searches open imports. Unlike closed imports, with open imports, the order does not matter -- instead, if more than one vocabulary defines a word with this name, an error is thrown."
33 { $subsection ambiguous-use-error }
34 "To resolve the error, add a closed import, using " { $link POSTPONE: FROM: } ", " { $link POSTPONE: QUALIFIED: } " or " { $link POSTPONE: QUALIFIED-WITH: } ". The closed import will then take precedence over the open imports, and the ambiguity will be resolved."
35 $nl
36 "The rationale for this behavior is as follows. Open imports are named such because they are open to future extension; if a future version of a vocabulary that you use adds new words, those new words will now be in scope in your source file, too. To avoid problems, any references to the new word have to be resolved since the parser cannot safely determine which vocabulary was meant. This problem can be avoided entirely by using only closed imports, but this leads to additional verbosity."
37 $nl
38 "In practice, a small set of guidelines helps avoid name clashes:"
39 { $list
40   "Keep vocabularies small"
41   { "Hide internal words using " { $link POSTPONE: <PRIVATE } }
42   { "Make good use of " { $link POSTPONE: FROM: } ", " { $link POSTPONE: QUALIFIED: } " or " { $link POSTPONE: QUALIFIED-WITH: } }
43 } ;
44
45 ARTICLE: "word-search-private" "Private words"
46 "Words which only serve as implementation detail should be defined in a private code block. Words in a private code blocks get defined in a vocabulary whose name is the name of the current vocabulary suffixed with " { $snippet ".private" } ". Privacy is not enforced by the system; private words can be called from other vocabularies, and from the listener. However, this should be avoided where possible."
47 { $subsection POSTPONE: <PRIVATE }
48 { $subsection POSTPONE: PRIVATE> } ;
49
50 ARTICLE: "word-search" "Parse-time word lookup"
51 "When the parser reads a word name, it resolves the word at parse-time, looking up the " { $link word } " instance in the right vocabulary and adding it to the parse tree."
52 $nl
53 "Initially, only words from the " { $vocab-link "syntax" } " vocabulary are available in source files. Since most files will use words in other vocabularies, they will need to make those words available using a set of parsing words."
54 { $subsection "word-search-syntax" }
55 { $subsection "word-search-private" }
56 { $subsection "word-search-semantics" }
57 { $subsection "word-search-errors" }
58 { $see-also "words" } ;
59
60 ARTICLE: "word-search-parsing" "Word lookup in parsing words"
61 "The parsing words described in " { $link "word-search-syntax" } " are implemented using the below words, which you can also call from your own parsing words."
62 $nl
63 "The current state used for word search is stored in a " { $emphasis "manifest" } ":"
64 { $subsection manifest }
65 "Words for working with the current manifest:"
66 { $subsection use-vocab }
67 { $subsection unuse-vocab }
68 { $subsection only-use-vocabs }
69 { $subsection add-qualified }
70 { $subsection add-words-from }
71 { $subsection add-words-excluding }
72 "Words used to implement " { $link POSTPONE: IN: } ":"
73 { $subsection current-vocab }
74 { $subsection set-current-vocab }
75 "Words used to implement " { $link "word-search-private" } ":"
76 { $subsection begin-private }
77 { $subsection end-private } ;
78
79 ABOUT: "word-search"
80
81 HELP: manifest
82 { $var-description "The current manifest. Only set at parse time." }
83 { $class-description "Encapsulates the current vocabulary, as well as the vocabulary search path." } ;
84
85 HELP: <manifest>
86 { $values { "manifest" manifest } }
87 { $description "Creates a new manifest." } ;
88
89 HELP: set-current-vocab
90 { $values { "name" string } }
91 { $description "Sets the current vocabulary where new words will be defined, creating the vocabulary first if it does not exist." }
92 { $notes "This word is used to implement " { $link POSTPONE: IN: } "." } ;
93
94 HELP: no-current-vocab
95 { $error-description "Thrown when a new word is defined in a source file that does not have an " { $link POSTPONE: IN: } " form." } ;
96
97 HELP: current-vocab
98 { $values { "vocab" vocab } }
99 { $description "Returns the current vocabulary, where new words will be defined." }
100 { $errors "Throws an error if the current vocabulary has not been set." } ;
101
102 HELP: begin-private
103 { $description "Begins a block of private word definitions. Private word definitions are placed in the current vocabulary name, suffixed with " { $snippet ".private" } "." }
104 { $notes "This word is used to implement " { $link POSTPONE: <PRIVATE } "." } ;
105
106 HELP: end-private
107 { $description "Ends a block of private word definitions." }
108 { $notes "This word is used to implement " { $link POSTPONE: PRIVATE> } "." } ;
109
110 HELP: use-vocab
111 { $values { "vocab" "a vocabulary specifier" } }
112 { $description "Adds a vocabulary to the current manifest." }
113 { $notes "This word is used to implement " { $link POSTPONE: USE: } "." } ;
114
115 HELP: unuse-vocab
116 { $values { "vocab" "a vocabulary specifier" } }
117 { $description "Removes a vocabulary from the current manifest." }
118 { $notes "This word is used to implement " { $link POSTPONE: UNUSE: } "." } ;
119
120 HELP: only-use-vocabs
121 { $values { "vocabs" "a sequence of vocabulary specifiers" } }
122 { $description "Replaces the current manifest's vocabulary search path with the given set of vocabularies." } ;
123
124 HELP: add-qualified
125 { $values { "vocab" "a vocabulary specifier" } { "prefix" string } }
126 { $description "Adds the vocabulary's words, prefixed with the given string, to the current manifest." }
127 { $notes "If adding the vocabulary introduces ambiguity, the vocabulary will take precedence when resolving any ambiguous names. See the example in " { $link POSTPONE: QUALIFIED: } " for further explanation." } ;
128
129 HELP: add-words-from
130 { $values { "vocab" "a vocabulary specifier" } { "words" "a sequence of word names" } }
131 { $description "Adds " { $snippet "words" } " from " { $snippet "vocab" } " to the current manifest." }
132 { $notes "This word is used to implement " { $link POSTPONE: FROM: } "." } ;
133
134 HELP: add-words-excluding
135 { $values { "vocab" "a vocabulary specifier" } { "words" "a sequence of word names" } }
136 { $description "Adds all words except for " { $snippet "words" } " from " { $snippet "vocab" } "  to the manifest." }
137 { $notes "This word is used to implement " { $link POSTPONE: EXCLUDE: } "." } ;
138
139 HELP: add-renamed-word
140 { $values { "word" string } { "vocab" "a vocabulary specifier" } { "new-name" string } }
141 { $description "Imports " { $snippet "word" } " from " { $snippet "vocab" } ", but renamed to " { $snippet "new-name" } "." }
142 { $notes "This word is used to implement " { $link POSTPONE: RENAME: } "." } ;
143
144 HELP: use-words
145 { $values { "assoc" assoc } }
146 { $description "Adds an assoc mapping word names to words to the current manifest." }
147 { $notes "This word is used by " { $link "locals" } " to implement lexically-scoped names." } ;
148
149 HELP: unuse-words
150 { $values { "assoc" assoc } }
151 { $description "Removes an assoc mapping word names to words from the current manifest." }
152 { $notes "This word is used by " { $link "locals" } " to implement lexically-scoped names." } ;
153
154 HELP: ambiguous-use-error
155 { $error-description "Thrown when a word name referenced in source file is available in more than one vocabulary in the manifest. Such cases must be explicitly disambiguated using " { $link POSTPONE: FROM: } ", " { $link POSTPONE: EXCLUDE: } ", " { $link POSTPONE: QUALIFIED: } ", or " { $link POSTPONE: QUALIFIED-WITH: } "." } ;
156
157 HELP: search-manifest
158 { $values { "name" string } { "manifest" manifest } { "word/f" { $maybe word } } }
159 { $description "Searches for a word by name in the given manifest. If no such word could be found, outputs " { $link f } "." } ;
160
161 HELP: search
162 { $values { "name" string } { "word/f" { $maybe word } } }
163 { $description "Searches for a word by name in the current manifest. If no such word could be found, outputs " { $link f } "." }
164 $parsing-note ;