]> gitweb.factorcode.org Git - factor.git/blob - core/parser/parser-docs.factor
Initial import
[factor.git] / core / parser / parser-docs.factor
1 USING: help.markup help.syntax kernel sequences words
2 math strings vectors quotations generic effects classes
3 vocabs.loader definitions io vocabs source-files
4 quotations namespaces ;
5 IN: parser
6
7 ARTICLE: "vocabulary-search-shadow" "Shadowing word names"
8 "If adding a vocabulary to the search path results in a word in another vocabulary becoming inaccessible due to the new vocabulary defining a word with the same name, a message is printed to the " { $link stdio } " stream. Except when debugging suspected name clashes, these messages can be ignored."
9 $nl
10 "Here is an example where shadowing occurs:"
11 { $code
12     "IN: foe"
13     "USING: sequences io ;"
14     ""
15     ": append"
16     "    #! Prints a message, then calls sequences::append."
17     "    \"foe::append calls sequences::append\" print append ;"
18     ""
19     "IN: fee"
20     ""
21     ": append"
22     "    #! Infinite recursion! Calls fee::append."
23     "    \"fee::append calls fee::append\" print append ;"
24     ""
25     "USE: foe"
26     ""
27     ": append"
28     "    #! Redefining fee::append to call foe::append."
29     "    \"fee::append calls foe::append\" print append ;"
30     ""
31     "\"1234\" \"5678\" append print"
32 }
33 "When placed in a source file and run, the above code produces the following output:"
34 { $code
35     "fee::append calls foe::append"
36     "foe::append calls sequences::append"
37     "12345678"
38 } ;
39
40 ARTICLE: "vocabulary-search-errors" "Word lookup errors"
41 "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. Then, one of three things happen:"
42 { $list
43     { "If there are no words having this name at all, an error is thrown and parsing stops." }
44     { "If there is exactly one vocabulary having a word with this name, the vocabulary is automatically added to the search path. This behavior is intended for interactive use and exploratory programming only, and production code should contain full " { $link POSTPONE: USING: } " declarations." }
45     { "If there is more than one vocabulary which contains a word with this name, a restartable error is thrown, with a restart for each vocabulary in question. The restarts add the vocabulary to the search path and continue parsing." }
46 }
47 "When writing a new vocabulary, one approach is to ignore " { $link POSTPONE: USING: } " declarations altogether, then to load the vocabulary and observe any parser notes and restarts and use this information to write the correct " { $link POSTPONE: USING: } " declaration." ;
48
49 ARTICLE: "vocabulary-search" "Vocabulary search"
50 "When the parser reads a token, it attempts to look up a word named by that token. The lookup is performed by searching each vocabulary in the search path, in order."
51 $nl
52 "For a source file the vocabulary search path starts off with two vocabularies:"
53 { $code "syntax\nscratchpad" }
54 "The " { $vocab-link "syntax" } " vocabulary consists of a set of parsing words for reading Factor data and defining new words. The " { $vocab-link "scratchpad" } " vocabulary is the default vocabulary for new word definitions."
55 $nl
56 "At the interactive listener, the default search path contains many more vocabularies. Details on the default search path and parser invocation are found in " { $link "parser" } "."
57 $nl
58 "Three parsing words deal with the vocabulary search path:"
59 { $subsection POSTPONE: USE: }
60 { $subsection POSTPONE: USING: }
61 { $subsection POSTPONE: IN: }
62 "Private words can be defined; note that this is just a convention and they can be called from other vocabularies anyway:"
63 { $subsection POSTPONE: <PRIVATE }
64 { $subsection POSTPONE: PRIVATE> }
65 { $subsection "vocabulary-search-errors" }
66 { $subsection "vocabulary-search-shadow" }
67 { $see-also "words" } ;
68
69 ARTICLE: "reading-ahead" "Reading ahead"
70 "Parsing words can consume input:"
71 { $subsection scan }
72 { $subsection scan-word }
73 "For example, the " { $link POSTPONE: HEX: } " word uses this feature to read hexadecimal literals:"
74 { $see POSTPONE: HEX: }
75 "It is defined in terms of a lower-level word that takes the numerical base on the data stack, but reads the number from the parser and then adds it to the parse tree:"
76 { $see parse-base }
77 "Another simple example is the " { $link POSTPONE: \ } " word:"
78 { $see POSTPONE: \ } ;
79
80 ARTICLE: "parsing-word-nest" "Nested structure"
81 "Recall that the parser loop calls parsing words with an accumulator vector on the stack. The parser loop can be invoked recursively with a new, empty accumulator; the result can then be added to the original accumulator. This is how parsing words for object literals are implemented; object literals can nest arbitrarily deep."
82 $nl
83 "A simple example is the parsing word that reads a quotation:"
84 { $see POSTPONE: [ }
85 "This word uses a utility word which recursively invokes the parser, reading objects into a new accumulator until an occurrence of " { $link POSTPONE: ] } ":"
86 { $subsection parse-literal }
87 "There is another, lower-level word for reading nested structure, which is also useful when called directly:"
88 { $subsection parse-until }
89 "Words such as " { $link POSTPONE: ] } " use a declaration which causes them to throw an error when an unpaired occurrence is encountered:"
90 { $subsection POSTPONE: delimiter }
91 { $see-also POSTPONE: { POSTPONE: H{ POSTPONE: V{ POSTPONE: W{ POSTPONE: T{ POSTPONE: } } ;
92
93 ARTICLE: "defining-words" "Defining words"
94 "Defining words add definitions to the dictionary without modifying the parse tree. The simplest example is the " { $link POSTPONE: SYMBOL: } " word."
95 { $see POSTPONE: SYMBOL: }
96 "The key factor in the definition of " { $link POSTPONE: SYMBOL: } " is " { $link CREATE } ", which reads a token from the input and creates a word with that name. This word is then passed to " { $link define-symbol } "."
97 { $subsection CREATE }
98 "Colon definitions are defined in a more elaborate way:"
99 { $subsection POSTPONE: : }
100 "The " { $link POSTPONE: : } " word first calls " { $link CREATE } ", and then reads input until reaching " { $link POSTPONE: ; } " using a utility word:"
101 { $subsection parse-definition }
102 "The " { $link POSTPONE: ; } " word is just a delimiter; an unpaired occurrence throws a parse error:"
103 { $see POSTPONE: ; }
104 "There are additional parsing words whose syntax is delimited by  " { $link POSTPONE: ; } ", and they are all implemented by calling " { $link parse-definition } "." ;
105
106 ARTICLE: "parsing-tokens" "Parsing raw tokens"
107 "So far we have seen how to read individual tokens, or read a sequence of parsed objects until a delimiter. It is also possible to read raw tokens from the input and perform custom processing."
108 $nl
109 "One example is the " { $link POSTPONE: USING: } " parsing word."
110 { $see POSTPONE: USING: } 
111 "It reads a list of vocabularies terminated by " { $link POSTPONE: ; } ". However, the vocabulary names do not name words, except by coincidence; so " { $link parse-until } " cannot be used here. Instead, a lower-level word is called:"
112 { $subsection parse-tokens } ;
113
114 ARTICLE: "parsing-words" "Parsing words"
115 "The Factor parser is follows a simple recursive-descent design. The parser reads successive tokens from the input; if the token identifies a number or an ordinary word, it is added to an accumulator vector. Otherwise if the token identifies a parsing word, the parsing word is executed immediately."
116 $nl
117 "Parsing words are marked by suffixing the definition with a " { $link POSTPONE: parsing } " declaration. Here is the simplest possible parsing word; it prints a greeting at parse time:"
118 { $code ": hello \"Hello world\" print ; parsing" }
119 "Parsing words must have stack effect " { $snippet "( accum -- accum )" } ", where " { $snippet "accum" } " is the accumulator vector supplied by the parser. Parsing words can read input, add word definitions to the dictionary, and do anything an ordinary word can."
120 $nl
121 "Tools for implementing parsing words:"
122 { $subsection "reading-ahead" }
123 { $subsection "parsing-word-nest" }
124 { $subsection "defining-words" }
125 { $subsection "parsing-tokens" } ;
126
127 ARTICLE: "parser-lexer" "The lexer"
128 "Two variables that encapsulate internal parser state:"
129 { $subsection file }
130 { $subsection lexer }
131 "Creating a default lexer:"
132 { $subsection <lexer> }
133 "A word to test of the end of input has been reached:"
134 { $subsection still-parsing? }
135 "A word to get the text of the current line:"
136 { $subsection line-text }
137 "A word to advance the lexer to the next line:"
138 { $subsection next-line }
139 "Two generic words to override the lexer's token boundary detection:"
140 { $subsection skip-blank }
141 { $subsection skip-word }
142 "A utility used when parsing string literals:"
143 { $subsection parse-string }
144 "The parser can be invoked with a custom lexer:"
145 { $subsection (parse-lines) }
146 { $subsection with-parser } ;
147
148 ARTICLE: "parser-files" "Parsing source files"
149 "The parser can run source files:"
150 { $subsection run-file }
151 { $subsection parse-file }
152 { $subsection bootstrap-file }
153 "The parser cross-references source files and definitions. This allows it to keep track of removed definitions, and prevent forward references and accidental redefinitions."
154 $nl
155 "When a source file is reloaded, the parser compares the previous list of definitions with the current list; any definitions which are no longer present in the file are removed by a call to " { $link forget } ". A warning message is printed if any other definitions still depend on the removed definitions."
156 $nl
157 "The parser also catches forward references when reloading source files. This is best illustrated with an example. Suppose we load a source file " { $snippet "a.factor" } ":"
158 { $code
159     "USING: io sequences ;"
160     "IN: a"
161     ": hello \"Hello\" ;"
162     ": world \"world\" ;"
163     ": hello-world hello " " world 3append print ;"
164 }
165 "The definitions for " { $snippet "hello" } ", " { $snippet "world" } ", and " { $snippet "hello-world" } " are in the dictionary."
166 $nl
167 "Now, after some heavily editing and refactoring, the file looks like this:"
168 { $code
169     "USING: namespaces ;"
170     "IN: a"
171     ": hello \"Hello\" % ;"
172     ": hello-world [ hello " " % world ] \"\" make ;"
173     ": world \"world\" % ;"
174 }
175 "Note that the developer has made a mistake, placing the definition of " { $snippet "world" } " " { $emphasis "after" } " its usage in " { $snippet "hello-world" } "."
176 $nl
177 "If the parser did not have special checks for this case, then the modified source file would still load, because when the definition of " { $snippet "hello-world" } " on line 4 is being parsed, the " { $snippet "world" } " word is already present in the dictionary from an earlier run. The developer would then not discover this mistake until attempting to load the source file into a fresh image."
178 $nl
179 "Since this is undesirable, the parser explicitly raises an error if a source file refers to a word which is in the dictionary, but defined after it is used."
180 { $subsection forward-error }
181 "If a source file raises a " { $link forward-error } " when loaded into a development image, then it would have raised a " { $link no-word } " error when loaded into a fresh image."
182 $nl
183 "The parser also catches duplicate definitions. If an artifact is defined twice in the same source file, the earlier definition will never be accessible, and this is almost always a mistake, perhaps due to a bad choice of word names, or a copy and paste error. The parser raises an error in this case."
184 { $subsection redefine-error }
185 { $see-also "source-files" } ;
186
187 ARTICLE: "parser-usage" "Reflective parser usage"
188 "The parser can be called on a string:"
189 { $subsection eval }
190 { $subsection parse }
191 { $subsection parse-fresh }
192 "The parser can also parse from a stream:"
193 { $subsection parse-stream } ;
194
195 ARTICLE: "parser" "The parser"
196 "This parser is a general facility for reading textual representations of objects and definitions. The parser is implemented in the " { $vocab-link "parser" } " and " { $vocab-link "syntax" } " vocabularies."
197 $nl
198 "This section concerns itself with usage and extension of the parser. Standard syntax is described in " { $link "syntax" } "."
199 { $subsection "vocabulary-search" }
200 { $subsection "parser-files" }
201 { $subsection "parser-usage" }
202 "The parser can be extended."
203 { $subsection "parsing-words" }
204 { $subsection "parser-lexer" } ;
205
206 ABOUT: "parser"
207
208 : $parsing-note
209     drop
210     "This word should only be called from parsing words."
211     $notes ;
212
213 HELP: lexer
214 { $var-description "Stores the current " { $link lexer } " instance." }
215 { $class-description "An object for tokenizing parser input. It has the following slots:"
216     { $list
217         { { $link lexer-text } " - the lines being parsed; an array of strings" }
218         { { $link lexer-line } " - the line number being parsed; unlike most indices this is 1-based for friendlier error reporting and integration with text editors" }
219         { { $link lexer-column } " - the current column position, zero-based" }
220     }
221 "Custom lexing can be implemented by delegating a tuple to an instance of this class and implementing the " { $link skip-word } " and " { $link skip-blank } " generic words." } ;
222
223 HELP: <lexer>
224 { $values { "text" "a sequence of strings" } { "lexer" lexer } }
225 { $description "Creates a new lexer for tokenizing the given sequence of lines." } ;
226
227 HELP: location
228 { $values { "loc" "a " { $snippet "{ path line# }" } " pair" } }
229 { $description "Outputs the current parser location. This value can be passed to " { $link set-where } " or " { $link (save-location) } "." } ;
230
231 HELP: redefine-error
232 { $values { "definition" "a definition specifier" } }
233 { $description "Throws a " { $link redefine-error } "." }
234 { $error-description "Indicates that a single source file contains two definitions for the same artifact, one of which shadows the other. This is an error since it indicates a likely mistake, such as two words accidentally named the same by the developer; the error is restartable." } ;
235
236 HELP: redefinition?
237 { $values { "definition" "a definition specifier" } { "?" "a boolean" } }
238 { $description "Tests if this definition is already present in the current source file." }
239 $parsing-note ;
240
241 HELP: (save-location)
242 { $values { "definition" "a definition specifier" } { "loc" "a " { $snippet "{ path line# }" } " pair" } }
243 { $description "Saves the location of a definition and associates this definition with the current source file."
244 $nl
245 "This is the book-keeping required to detect " { $link redefine-error } " and " { $link forward-error } "." } ;
246
247 HELP: save-location
248 { $values { "definition" "a definition specifier" } }
249 { $description "Saves the location of a definition and associates this definition with the current source file."
250 $nl
251 "This is the book-keeping required to detect " { $link redefine-error } " and " { $link forward-error } "." } ;
252
253 HELP: parser-notes
254 { $var-description "A boolean controlling whether the parser will print various notes and warnings. Switched on by default. If a source file is being run for its effect on the " { $link stdio } " stream, this variable should be switched off, to prevent parser notes from polluting the output." } ;
255
256 HELP: parser-notes?
257 { $values { "?" "a boolean" } }
258 { $description "Tests if the parser will print various notes and warnings. To disable parser notes, either set " { $link parser-notes } " to " { $link f } ", or pass the " { $snippet "-quiet" } " command line switch." } ;
259
260 HELP: next-line
261 { $values { "lexer" lexer } }
262 { $description "Advances the lexer to the next input line, discarding the remainder of the current line." } ;
263
264 HELP: file
265 { $var-description "Stores the " { $link source-file } " being parsed. The " { $link source-file-path } " of this object comes from the input parameter to " { $link parse-stream } "." } ;
266
267 HELP: old-definitions
268 { $var-description "Stores an assoc where the keys form the set of definitions which were defined by " { $link file } " the most recent time it was loaded." } ;
269
270 HELP: new-definitions
271 { $var-description "Stores an assoc where the keys form the set of definitions which were defined so far by the current parsing of " { $link file } "." } ;
272
273 HELP: parse-error
274 { $error-description "Thrown when the parser encounters invalid input. A parse error wraps an underlying error and holds the file being parsed, line number, and column number." } ;
275
276 HELP: <parse-error>
277 { $values { "msg" "an error" } { "error" parse-error } }
278 { $description "Creates a new " { $link parse-error } ", filling in the location information from the current " { $link lexer } "." } ;
279
280 HELP: line-text
281 { $values { "lexer" lexer } { "str" string } }
282 { $description "Outputs the text of the line being parsed." } ;
283
284 HELP: skip
285 { $values { "i" "a starting index" } { "seq" "a sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- ? )" } } { "n" integer } }
286 { $description "Variant of " { $link find* } " that outputs the length of the sequence instead of " { $link f } " if no elements satisfy the predicate." } ;
287
288 HELP: change-column
289 { $values { "lexer" lexer } { "quot" "a quotation with stack effect " { $snippet "( col line -- newcol )" } } }
290 { $description "Applies a quotation to the current column and line text to produce a new column, and moves the lexer position." } ;
291
292 HELP: skip-blank
293 { $values { "lexer" lexer } }
294 { $contract "Skips whitespace characters." }
295 { $notes "Custom lexers can implement this generic word." } ;
296
297 HELP: skip-word
298 { $values { "lexer" lexer } }
299 { $contract
300     "Skips until the end of the current token."
301     $nl
302     "The default implementation treats a single " { $snippet "\"" } " as a word by itself; otherwise it searches forward until a whitespace character or the end of the line."
303 }
304 { $notes "Custom lexers can implement this generic word." } ;
305
306 HELP: still-parsing-line?
307 { $values { "lexer" lexer } { "?" "a boolean" } }
308 { $description "Outputs " { $link f } " if the end of the current line has been reached, " { $link t } " otherwise." } ;
309
310 HELP: parse-token
311 { $values { "lexer" lexer } { "str/f" "a " { $link string } " or " { $link f } } }
312 { $description "Reads the next token from the lexer. Tokens are delimited by whitespace, with the exception that " { $snippet "\"" } " is treated like a single token even when not followed by whitespace." } ;
313
314 HELP: scan
315 { $values { "str/f" "a " { $link string } " or " { $link f } } }
316 { $description "Reads the next token from the lexer. See " { $link parse-token } " for details." }
317 $parsing-note ;
318
319 HELP: bad-escape
320 { $error-description "Indicates the parser encountered an invalid escape code following a backslash (" { $snippet "\\" } ") in a string literal. See " { $link "escape" } " for a list of valid escape codes." } ;
321
322 HELP: bad-number
323 { $error-description "Indicates the parser encountered an invalid numeric literal." } ;
324
325 HELP: escape
326 { $values { "escape" "a single-character escape" } { "ch" "a character" } }
327 { $description "Converts from a single-character escape code and the corresponding character." }
328 { $examples { $example "CHAR: n escape CHAR: \\n = ." "t" } } ;
329
330 HELP: next-escape
331 { $values { "m" "an index into " { $snippet "str" } } { "str" string } { "n" "an index into " { $snippet "str" } } { "ch" "a character" } }
332 { $description "Helper word for " { $link parse-string } " which parses an escape sequence starting at the " { $snippet "m" } "th index of " { $snippet "str" } "." }
333 { $errors "Throws a " { $link bad-escape } " if the string contains an invalid escape sequence." } ;
334
335 HELP: next-char
336 { $values { "m" "an index into " { $snippet "str" } } { "str" string } { "n" "an index into " { $snippet "str" } } { "ch" "a character" } }
337 { $description "Helper word for " { $link parse-string } " which parses a character starting at the " { $snippet "m" } "th index of " { $snippet "str" } "." } ;
338
339 HELP: parse-string
340 { $values { "str" "a new " { $link string } } }
341 { $description "Parses the line until a quote (\"), interpreting escape codes along the way." }
342 { $errors "Throws an " { $link bad-escape } " if the string contains an invalid escape sequence." }
343 $parsing-note ;
344
345 HELP: still-parsing?
346 { $values { "lexer" lexer } { "?" "a boolean" } }
347 { $description "Outputs " { $link f } " if end of input has been reached, " { $link t } " otherwise." } ;
348
349 HELP: use
350 { $var-description "A variable holding the current vocabulary search path as a sequence of assocs." } ;
351
352 { use in use+ (use+) set-use set-in POSTPONE: USING: POSTPONE: USE: file-vocabs } related-words
353
354 HELP: in
355 { $var-description "A variable holding the name of the current vocabulary for new definitions." } ;
356
357 HELP: shadow-warnings
358 { $values { "vocab" "an assoc mapping strings to words" } { "vocabs" "a sequence of assocs" } }
359 { $description "Tests if any keys in " { $snippet "vocab" } " shadow keys in the elements of " { $snippet "vocabs" } ", and if so, prints a warning message. These warning messages can be disabled by setting " { $link parser-notes } " to " { $link f } "." } ;
360
361 HELP: (use+)
362 { $values { "vocab" "an assoc mapping strings to words" } }
363 { $description "Adds an assoc at the front of the search path." }
364 $parsing-note ;
365
366 HELP: use+
367 { $values { "vocab" string } }
368 { $description "Adds a new vocabulary at the front of the search path after loading it if necessary. Subsequent word lookups by the parser will search this vocabulary first." }
369 $parsing-note
370 { $errors "Throws an error if the vocabulary does not exist." } ;
371
372 HELP: set-use
373 { $values { "seq" "a sequence of strings" } }
374 { $description "Sets the vocabulary search path. Later vocabularies take precedence." }
375 { $errors "Throws an error if one of the vocabularies does not exist." }
376 $parsing-note ;
377
378 HELP: add-use
379 { $values { "seq" "a sequence of strings" } }
380 { $description "Adds multiple vocabularies to the search path, with later vocabularies taking precedence." }
381 { $errors "Throws an error if one of the vocabularies does not exist." }
382 $parsing-note ;
383
384 HELP: set-in
385 { $values { "name" string } }
386 { $description "Sets the current vocabulary where new words will be defined, creating the vocabulary first if it does not exist." }
387 $parsing-note ;
388
389 HELP: create-in
390 { $values { "string" "a word name" } { "word" "a new word" } }
391 { $description "Creates a word in the current vocabulary. Until re-defined, the word throws an error when invoked." }
392 $parsing-note ;
393
394 HELP: parse-tokens
395 { $values { "end" string } { "seq" "a new sequence of strings" } }
396 { $description "Reads a sequence of tokens until the first occurrence of " { $snippet "end" } ". The tokens remain as strings and are not processed in any way." }
397 { $examples "This word is used to implement " { $link POSTPONE: USING: } "." }
398 $parsing-note ;
399
400 HELP: CREATE
401 { $values { "word" word } }
402 { $description "Reads the next token from the line currently being parsed, and creates a word with that name in the current vocabulary." }
403 { $errors "Throws an error if the end of the line is reached." }
404 $parsing-note ;
405
406 HELP: no-word
407 { $values { "name" string } { "newword" word } }
408 { $description "Throws a " { $link no-word } " error." }
409 { $error-description "Thrown if the parser encounters a token which does not name a word in the current vocabulary search path. If any words with this name exist in vocabularies not part of the search path, a number of restarts will offer to add those vocabularies to the search path and use the chosen word." }
410 { $notes "Apart from a missing " { $link POSTPONE: USE: } ", this error can also indicate an ordering issue. In Factor, words must be defined before they can be called. Mutual recursion can be implemented via " { $link POSTPONE: DEFER: } "." } ;
411
412 HELP: search
413 { $values { "str" string } { "word" word } }
414 { $description "Searches for a word by name in the current vocabulary search path. If no such word could be found, throws a " { $link no-word } " error. If the search path does not contain a word with this name but other vocabularies do, the error will have restarts offering to add vocabularies to the search path." }
415 $parsing-note ;
416
417 HELP: forward-error
418 { $values { "word" word } } 
419 { $description "Throws a " { $link forward-error } "." }
420 { $description "Indicates a word is being referenced prior to the location of its most recent definition. This can only happen if a source file is loaded, and subsequently edited such that two dependent definitions are reversed." } ;
421
422 HELP: scan-word
423 { $values { "word/number/f" "a word, number or " { $link f } } }
424 { $description "Reads the next token from parser input. If the token is a valid number literal, it is converted to a number, otherwise the dictionary is searched for a word named by the token. Outputs " { $link f } " if the end of the input has been reached." }
425 { $errors "Throws an error if the token does not name a word, and does not parse as a number." }
426 $parsing-note ;
427
428 HELP: unexpected
429 { $values { "want" "a " { $link word } " or " { $link f } } { "got" word } }
430 { $description "Throws an " { $link unexpected } " error." }
431 { $error-description "Thrown by the parser if an unmatched closing delimiter is encountered." }
432 { $examples
433     "Parsing the following snippet will throw this error:"
434     { $code "[ 1 2 3 }" }
435 } ;
436
437 HELP: unexpected-eof
438 { $values { "word" "a " { $link word } } }
439 { $description "Throws an " { $link unexpected } " error indicating the parser was looking for an occurrence of " { $snippet "word" } " but encountered end of file." } ;
440
441 HELP: parse-step
442 { $values { "accum" vector } { "end" word } { "?" "a boolean" } }
443 { $description "Parses a token. If the token is a number or an ordinary word, it is added to the accumulator. If it is a parsing word, calls the parsing word with the accumulator on the stack. Outputs " { $link f } " if " { $snippet "end" } " is encountered, " { $link t } " otherwise." }
444 $parsing-note ;
445
446 HELP: (parse-until)
447 { $values { "accum" vector } { "end" word } }
448 { $description "Parses objects from parser input until " { $snippet "end" } " is encountered, adding them to the accumulator." }
449 $parsing-note ;
450
451 HELP: parse-until
452 { $values { "end" word } { "vec" "a new vector" } }
453 { $description "Parses objects from parser input until " { $snippet "end" } ". Outputs a new vector with the results." }
454 { $examples "This word is used to implement " { $link POSTPONE: ARTICLE: } "." }
455 $parsing-note ;
456
457 { parse-tokens (parse-until) parse-until } related-words
458
459 HELP: parsed
460 { $values { "accum" vector } { "obj" object } }
461 { $description "Convenience word for parsing words. It behaves exactly the same as " { $link push } ", except the accumulator remains on the stack." }
462 $parsing-note ;
463
464 HELP: with-parser
465 { $values { "lexer" lexer } { "quot" "a quotation with stack effect " { $snippet "( -- accum )" } } { "newquot" "a new " { $link quotation } } }
466 { $description "Sets up the parser and calls the quotation. The quotation can make use of parsing words such as " { $link scan } " and " { $link parse-until } ". It must yield a sequence, which is converted to a quotation and output. Any errors thrown by the quotation are wrapped in parse errors." } ;
467
468 HELP: (parse-lines)
469 { $values { "lexer" lexer } { "quot" "a new " { $link quotation } } }
470 { $description "Parses Factor source code using a custom lexer. The vocabulary search path is taken from the current scope." }
471 { $errors "Throws a " { $link parse-error } " if the input is malformed." } ;
472
473 HELP: parse-lines
474 { $values { "lines" "a sequence of strings" } { "quot" "a new " { $link quotation } } }
475 { $description "Parses Factor source code which has been tokenized into lines. The vocabulary search path is taken from the current scope." }
476 { $errors "Throws a " { $link parse-error } " if the input is malformed." } ;
477
478 HELP: lexer-factory
479 { $var-description "A variable holding a quotation with stack effect " { $snippet "( lines -- lexer )" } ". This quotation is called by the parser to create " { $link lexer } " instances. This variable can be rebound to a quotation which outputs a custom tuple delegating to " { $link lexer } " to customize syntax." } ;
480
481 HELP: parse-effect
482 { $values { "effect" "an instance of " { $link effect } } }
483 { $description "Parses a stack effect from the current input line." }
484 { $examples "This word is used by " { $link POSTPONE: ( } " to parse stack effect declarations." }
485 $parsing-note ;
486
487 HELP: parse-base
488 { $values { "base" "an integer between 2 and 36" } { "parsed" integer } }
489 { $description "Reads an integer in a specific numerical base from the parser input." }
490 $parsing-note ;
491
492 HELP: parse-literal
493 { $values { "accum" vector } { "end" word } { "quot" "a quotation with stack effect " { $snippet "( seq -- obj )" } } }
494 { $description "Parses objects from parser input until " { $snippet "end" } ", applies the quotation to the resulting sequence, and adds the output value to the accumulator." }
495 { $examples "This word is used to implement " { $link POSTPONE: C{ } "." }
496 $parsing-note ;
497
498 HELP: parse-definition
499 { $values { "quot" "a new " { $link quotation } } }
500 { $description "Parses objects from parser input until " { $link POSTPONE: ; } " and outputs a quotation with the results." }
501 { $examples "This word is used to implement " { $link POSTPONE: : } "." }
502 $parsing-note ;
503
504 HELP: bootstrap-syntax
505 { $var-description "Only set during bootstrap. Stores a copy of the " { $link vocab-words } " of the host's syntax vocabulary; this allows the host's parsing words to be used during bootstrap source parsing, not the target's." } ;
506
507 HELP: file-vocabs
508 { $description "Installs the initial the vocabulary search path for parsing a file. This consists of the " { $snippet "syntax" } " vocabulary together with the " { $snippet "scratchpad" } " vocabulary." } ;
509
510 HELP: parse
511 { $values { "str" string } { "quot" quotation } }
512 { $description "Parses Factor source code from a string. The current vocabulary search path is used." }
513 { $errors "Throws a parse error if the input is malformed." } ;
514
515 HELP: parse-fresh
516 { $values { "lines" "a sequence of strings" } { "quot" quotation } }
517 { $description "Parses Factor source code in a sequence of lines. The initial vocabulary search path is used (see " { $link file-vocabs } ")." }
518 { $errors "Throws a parse error if the input is malformed." } ;
519
520 HELP: eval
521 { $values { "str" string } }
522 { $description "Parses Factor source code from a string, and calls the resulting quotation. The current vocabulary search path is used." }
523 { $errors "Throws an error if the input is malformed, or if the quotation throws an error." } ;
524
525 HELP: parse-hook
526 { $var-description "A quotation called by " { $link parse-stream } " after parsing the input stream. The default value recompiles new word definitions; see " { $link "recompile" } " for details." } ;
527
528 { parse-hook no-parse-hook } related-words
529
530 HELP: no-parse-hook
531 { $values { "quot" "a quotation" } }
532 { $description "Runs the quotation in a new dynamic scope where " { $link parse-hook } " is set to " { $link f } ", then calls the outer " { $link parse-hook } " after the quotation returns. This has the effect of postponing any recompilation to the end of a quotation." } ;
533
534 HELP: start-parsing
535 { $values { "stream" "an input stream" } { "name" "a pathname string" } }
536 { $description "Prepares to parse a source file by reading the entire contents of the stream and setting some variables. The pathname identifies the stream for cross-referencing purposes." }
537 { $errors "Throws an I/O error if there was an error reading from the stream." }
538 { $notes "This is one of the factors of " { $link parse-stream } "." } ;
539
540 HELP: outside-usages
541 { $values { "seq" "a sequence of definitions" } { "usages" "an association list mapping definitions to sequences of definitions" } }
542 { $description "Outputs an association list mapping elements of " { $snippet "seq" } " to lists of usages which exclude the definitions in " { $snippet "seq" } " themselves." } ;
543
544 HELP: filter-moved
545 { $values { "assoc" "an assoc where the keys are definitions" } { "newassoc" "an assoc where the keys are definitions" } }
546 { $description "Removes all definitions from the assoc which are no longer present in the current " { $link file } "." } ;
547
548 HELP: smudged-usage
549 { $values { "usages" "a sequence of definitions which reference removed definitions" } { "referenced" "a sequence of definitions removed from this source file which are still referenced elsewhere" } { "removed" "a sequence of definitions removed from this source file" } }
550 { $description "Collects information about changed word definitioins after parsing." } ;
551
552 HELP: forget-smudged
553 { $description "Forgets removed definitions and prints a warning message if any of them are still referenced from other source files." } ;
554
555 HELP: record-definitions
556 { $values { "file" source-file } }
557 { $description "Records that all " { $link new-definitions } " were defined in " { $snippet "file" } "." } ;
558
559 HELP: finish-parsing
560 { $values { "quot" "the quotation just parsed" } }
561 { $description "Records information to the current " { $link file } " and prints warnings about any removed definitions which are still in use." }
562 { $notes "This is one of the factors of " { $link parse-stream } "." } ;
563
564 HELP: undo-parsing
565 { $description "Records information to the current " { $link file } " after an incomplete parse which ended with an error." } ;
566
567 HELP: parse-stream
568 { $values { "stream" "an input stream" } { "name" "a file name for error reporting and cross-referencing" } { "quot" quotation } }
569 { $description "Parses Factor source code read from the stream. The initial vocabulary search path is used." }
570 { $errors "Throws an I/O error if there was an error reading from the stream. Throws a parse error if the input is malformed." } ;
571
572 HELP: parse-file
573 { $values { "file" "a pathname string" } { "quot" quotation } }
574 { $description "Parses the Factor source code stored in a file. The initial vocabulary search path is used." }
575 { $errors "Throws an I/O error if there was an error reading from the file. Throws a parse error if the input is malformed." } ;
576
577 HELP: run-file
578 { $values { "file" "a pathname string" } }
579 { $description "Parses the Factor source code stored in a file and runs it. The initial vocabulary search path is used." }
580 { $errors "Throws an error if loading the file fails, there input is malformed, or if a runtime error occurs while calling the parsed quotation." }  ;
581
582 HELP: ?run-file
583 { $values { "path" "a pathname string" } }
584 { $description "If the file exists, runs it with " { $link run-file } ", otherwise does nothing." } ;
585
586 HELP: reload
587 { $values { "defspec" "a definition specifier" } }
588 { $description "Reloads the source file containing the definition." }
589 { $examples
590     "Reloading a word definition:"
591     { $code "\\ foo reload" }
592     "A word's documentation:"
593     { $code "\\ foo >link reload" }
594     "A method definition:"
595     { $code "{ editor draw-gadget* } reload" }
596     "A help article:"
597     { $code "\"handbook\" >link reload" }
598 } ;
599
600 HELP: bootstrap-file
601 { $values { "path" "a pathname string" } }
602 { $description "If bootstrapping, parses the source file and adds its top level form to the quotation being constructed with " { $link make } "; the bootstrap code uses this to build up a boot quotation to be run on image startup. If not bootstrapping, just runs the file normally." } ;
603
604 HELP: ?bootstrap-file
605 { $values { "path" "a pathname string" } }
606 { $description "If the file exists, loads it with " { $link bootstrap-file } ", otherwise does nothing." } ;
607
608 HELP: eval>string
609 { $values { "str" string } { "output" string } }
610 { $description "Evaluates the Factor code in " { $snippet "str" } " with the " { $link stdio } " stream rebound to a string output stream, then outputs the resulting string." } ;