diff --git a/doc/handbook/alien.facts b/doc/handbook/alien.facts index 21978bb8a3..a502ac526d 100644 --- a/doc/handbook/alien.facts +++ b/doc/handbook/alien.facts @@ -114,7 +114,9 @@ ARTICLE: "c-types-strings" "C string types" } "Passing an instance of " { $link c-ptr } " to a C function expecting a C string will simply pass in the address of the " { $link c-ptr } "." $terpri -"Passing a Factor string to a C function expecting a C string allocates a byte array in the Factor heap; the string is then converted to the requested format and a raw pointer is passed to the function. The function must not retain such pointers after it returns, since byte arrays in the Factor heap can be moved by the garbage collector. To allocate a string which will not move, use " { $link } " and then " { $link free } "." +"Passing a Factor string to a C function expecting a C string allocates a byte array in the Factor heap; the string is then converted to the requested format and a raw pointer is passed to the function. If the conversion fails, for example if the string contains null bytes or characters with values higher than 255, a " { $link c-string-error. } " is thrown." +$terpri +"C functions must not retain such pointers to heap-allocated strings after returning, since byte arrays in the Factor heap can be moved by the garbage collector. To allocate a string which will not move, use " { $link } " and then " { $link free } "." $terpri "A couple of words can be used to read and write " { $snippet "char*" } " and " { $snippet "ushort*" } " strings from arbitrary addresses:" { $subsection alien>char-string } diff --git a/doc/handbook/handbook.facts b/doc/handbook/handbook.facts index 3ff7031762..2a93d063e9 100644 --- a/doc/handbook/handbook.facts +++ b/doc/handbook/handbook.facts @@ -39,8 +39,9 @@ ARTICLE: "handbook" "Factor documentation" { $heading "Index" } { $subsection "article-index" } { $subsection "primitive-index" } +{ $subsection "error-index" } { $subsection "type-index" } -{ $subsection "class-index" } ; +{ $subsection "class-index" }; ARTICLE: "article-index" "Article index" { $outliner [ articles get hash-keys ] } ; @@ -48,6 +49,46 @@ ARTICLE: "article-index" "Article index" ARTICLE: "primitive-index" "Primitive index" { $outliner [ all-words [ primitive? ] subset ] } ; +ARTICLE: "error-index" "Type index" +{ $subsection /0 } +{ $subsection alien-callback-error } +{ $subsection alien-invoke-error } +{ $subsection assert } +{ $subsection bad-escape } +{ $subsection bounds-error } +{ $subsection c-stream-error } +{ $subsection c-string-error. } +{ $subsection callstack-overflow. } +{ $subsection check-create } +{ $subsection check-method } +{ $subsection check-ptr } +{ $subsection check-vocab } +{ $subsection condition } +{ $subsection datastack-overflow. } +{ $subsection datastack-underflow. } +{ $subsection duplex-closed } +{ $subsection empty-queue } +{ $subsection expired-error. } +{ $subsection ffi-error. } +{ $subsection heap-scan-error. } +{ $subsection inference-error } +{ $subsection io-error. } +{ $subsection negative-array-size-error. } +{ $subsection no-article } +{ $subsection no-cond } +{ $subsection no-math-method } +{ $subsection no-method } +{ $subsection parse-error } +{ $subsection retainstack-overflow. } +{ $subsection retainstack-underflow. } +{ $subsection signal-error. } +{ $subsection slice-error } +{ $subsection tuple-class-error } +{ $subsection type-check-error. } +{ $subsection undefined-symbol-error. } +{ $subsection undefined-word-error. } +{ $subsection user-interrupt. } ; + ARTICLE: "type-index" "Type index" { $outliner [ builtins get [ ] subset ] } ; diff --git a/doc/handbook/syntax.facts b/doc/handbook/syntax.facts index 90f0bad5f4..8e132f9709 100644 --- a/doc/handbook/syntax.facts +++ b/doc/handbook/syntax.facts @@ -50,7 +50,7 @@ $terpri "Here is an example demonstrating the vocabulary search path. If you can understand this example, then you have grasped vocabularies." { $code "IN: foe" - "USE: sequences" + "USING: sequences io ;" "" ": append" " #! Prints a message, then calls sequences::append." diff --git a/library/collections/growable.facts b/library/collections/growable.facts index c4d8a8e0a2..ec9c938f31 100644 --- a/library/collections/growable.facts +++ b/library/collections/growable.facts @@ -33,7 +33,8 @@ $terpri HELP: bounds-error "( n seq -- )" { $values { "n" "a positive integer" } { "seq" "a sequence" } } -{ $description "Throws an error signalling an out-of-bounds access, where " { $snippet "n" } " is the index and " { $snippet "seq" } " is the sequence." } ; +{ $description "Throws a " { $link bounds-error } "." } +{ $error-description "Thrown by " { $link nth } ", " { $link set-nth } " and " { $link set-length } " if the given index lies beyond the bounds of the sequence." } ; HELP: bounds-check "( n seq -- n seq )" { $values { "n" "a positive integer" } { "seq" "a sequence" } } diff --git a/library/collections/queues.facts b/library/collections/queues.facts index 39e55eb336..125da61b34 100644 --- a/library/collections/queues.facts +++ b/library/collections/queues.facts @@ -1,6 +1,9 @@ IN: queues USING: help ; +HELP: queue f +{ $class-description "A simple first-in-first-out queue. See " { $link "queues" } "." } ; + HELP: "( -- queue )" { $values { "queue" "a new queue" } } { $description "Makes a new queue with no elements." } ; @@ -11,8 +14,13 @@ HELP: queue-empty? "( queue -- ? )" HELP: deque "( queue -- elt )" { $values { "queue" "a queue" } { "elt" "an object" } } -{ $description "Removes an element from the front of the queue." } ; +{ $description "Removes an element from the front of the queue." } +{ $errors "Throws an " { $link empty-queue } " error if the queue has no entries." } ; HELP: enque "( elt queue -- )" { $values { "elt" "an object" } { "queue" "a queue" } } { $description "Adds an element to the back of the queue." } ; + +HELP: empty-queue "( -- )" +{ $description "Throws an " { $link empty-queue } " error." } +{ $error-description "Thrown by " { $link deque } " if the queue has no entries." } ; diff --git a/library/collections/sequences-epilogue.facts b/library/collections/sequences-epilogue.facts index 7542c8876e..ab91563438 100644 --- a/library/collections/sequences-epilogue.facts +++ b/library/collections/sequences-epilogue.facts @@ -202,9 +202,8 @@ HELP: cond "( assoc -- )" "The following two phrases are equivalent:" { $code "{ { [ X ] [ Y ] } { [ Z ] [ T ] } } cond" } { $code "X [ Y ] [ Z [ T ] [ no-cond ] if ] if" } - "Note that the base case is " { $link no-cond } " which throws an error." } -{ $errors "Throws an error if the first quotation in every pair yields " { $link f } "." } +{ $errors "Throws a " { $link no-cond } " error if none of the test quotations yield a true value." } { $examples { $example "{" @@ -215,6 +214,10 @@ HELP: cond "( assoc -- )" } } ; +HELP: no-cond "( -- )" +{ $description "Throws a " { $link no-cond } " error." } +{ $error-description "Thrown by " { $link cond } " if none of the test quotations yield a true value. Most uses of " { $link cond } " include a default case where the test quotation is " { $snippet "[ t ]" } "; such a " { $link cond } " form will never throw this error. If you wish to assert that certain conditions are true, and fail otherwise, you can use " { $link cond } " without a default case." } ; + HELP: unix? "( -- ? )" { $values { "?" "a boolean" } } { $description "Tests if Factor is running on a Unix-like system. While this is a rather vague notion, one can use it to make certain assumptions about system calls and file structure which are not valid on Windows." } ; diff --git a/library/collections/sequences.facts b/library/collections/sequences.facts index d420a16f97..d4ba7e1c17 100644 --- a/library/collections/sequences.facts +++ b/library/collections/sequences.facts @@ -7,13 +7,13 @@ HELP: length "( seq -- n )" HELP: set-length "( n seq -- )" { $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } } { $description "Resizes the sequence. Not all sequences are resizable." } -{ $errors "Throws an error if the new length is negative, or if the sequence is not resizable." } +{ $errors "Throws a " { $link bounds-error } " if the new length is negative, or if the sequence is not resizable." } { $side-effects "seq" } ; HELP: nth "( n seq -- elt )" { $values { "n" "a non-negative integer" } { "seq" "a sequence" } { "elt" "the element at the " { $snippet "n" } "th index" } } { $contract "Outputs the " { $snippet "n" } "th element of the sequence. Elements are numbered from zero, so the last element has an index one less than the length of the sequence. All sequences support this operation." } -{ $errors "Throws an error if the index is negative, or greater than or equal to the length of the sequence." } ; +{ $errors "Throws a " { $link bounds-error } " if the index is negative, or greater than or equal to the length of the sequence." } ; HELP: set-nth "( elt n seq -- )" { $values { "elt" "an object" } { "n" "a non-negative integer" } { "seq" "a mutable sequence" } } @@ -95,6 +95,6 @@ HELP: set-nth-unsafe "( elt n seq -- )" { $values { "elt" "an object" } { "n" "an integer" } { "seq" "a sequence" } } { $contract "Unsafe variant of " { $link set-nth } " that does not perform bounds checks." } ; -HELP: exchange "( m n seq -- )" +HELP: exchange-unsafe "( m n seq -- )" { $values { "m" "a non-negative integer" } { "n" "a non-negative integer" } { "seq" "a mutable sequence" } } { $description "Unsafe variant of " { $link exchange } " that does not perform bounds checks." } ; diff --git a/library/collections/virtual-sequences.facts b/library/collections/virtual-sequences.facts index 10b85c8e9e..9ef9fd48b1 100644 --- a/library/collections/virtual-sequences.facts +++ b/library/collections/virtual-sequences.facts @@ -1,5 +1,20 @@ USING: help sequences ; +HELP: slice-error "( str -- )" +{ $values { "str" "a reason" } } +{ $description "Throws a " { $link slice-error } "." } +{ $error-description "Thrown by " { $link } " if one of the following invalid conditions holds:" + { $list + "The start index is negative" + "The end index is greater than the length of the sequence" + "The start index is greater than the end index" + } +} ; + +HELP: slice f +{ $class-description "A virtual sequence which presents a subrange of the elements of an underlying sequence." } +{ $see-also subseq } ; + HELP: "( m n seq -- slice )" { $values { "m" "a non-negative integer" } { "n" "a non-negative integer" } { "seq" "a sequence" } { "slice" "a slice" } } { $description "Outputs a new virtual sequence sharing storage with the subrange of elements in " { $snippet "seq" } " with indices starting from and including " { $snippet "m" } ", and up to but not including " { $snippet "n" } "." } diff --git a/library/compiler/alien/alien-callback.facts b/library/compiler/alien/alien-callback.facts index 82472c5060..0a750a8bd5 100644 --- a/library/compiler/alien/alien-callback.facts +++ b/library/compiler/alien/alien-callback.facts @@ -1,13 +1,14 @@ IN: alien USING: errors help ; +HELP: alien-callback-error "( -- )" +{ $error-description "Thrown when " { $link alien-callback } " is called in the interpreter. Words using " { $link alien-callback } " must be compiled first, and all three inputs to " { $link alien-callback } " must be literals." } ; + HELP: alien-callback "( return parameters quot -- alien )" { $values { "return" "a C return type" } { "parameters" "a sequence of C parameter types" } { "quot" "a quotation" } { "alien" "an alien address" } } { $description "Defines a callback from C to Factor which accepts the given set of parameters from the C caller, pushes them on the data stack, calls the quotation, and passes a return value back to the C caller. A return type of " { $snippet "\"void\"" } " indicates that no value is to be returned." $terpri - "This word only runs when it is called from within a " { $emphasis "compiled" } " word, with all three parameters as literal inputs." - $terpri "When a compiled reference to this word is called, it pushes the callback's alien address on the data stack. This address can be passed to any C function expecting a C function pointer with the correct signature. The callback is actually generated when the word calling " { $link alien-callback } " is compiled." $terpri "Callback quotations run with freshly-allocated stacks. This means the data stack contains the values passed by the C function, and nothing else. It also means that if the callback throws an error which is not caught, the Factor runtime will halt. See " { $link "errors" } " for error handling options." @@ -19,4 +20,5 @@ HELP: alien-callback "( return parameters quot -- alien )" " \"int\" { \"int\" \"int\" } [ - ] alien-callback ;" } } +{ $errors "Throws an " { $link alien-callback-error } " if the word calling " { $link alien-callback } " is not compiled." } { $see-also alien-invoke } ; diff --git a/library/compiler/alien/alien-invoke.facts b/library/compiler/alien/alien-invoke.facts index 446fd8c19c..cc730445c9 100644 --- a/library/compiler/alien/alien-invoke.facts +++ b/library/compiler/alien/alien-invoke.facts @@ -1,11 +1,13 @@ IN: alien USING: help ; +HELP: alien-invoke-error "( -- )" +{ $error-description "Thrown when " { $link alien-invoke } " is called in the interpreter. Words using " { $link alien-invoke } " must be compiled first, and all four inputs to " { $link alien-invoke } " must be literals." } ; + HELP: alien-invoke "( ... return library function parameters -- ... )" { $values { "return" "a C return type" } { "library" "a logical library name" } { "function" "a C function name" } { "parameters" "a sequence of C parameter types" } } -{ $description "Calls a C library function with the given name. Input parameters are taken from the data stack, and the return value is pushed on the data stack after the function returns. A return type of " { $snippet "\"void\"" } " indicates that no value is to be expected." -$terpri -"This word only runs when it is called from within a " { $emphasis "compiled" } " word, with all four parameters as literal inputs." } +{ $description "Calls a C library function with the given name. Input parameters are taken from the data stack, and the return value is pushed on the data stack after the function returns. A return type of " { $snippet "\"void\"" } " indicates that no value is to be expected." } +{ $errors "Throws an " { $link alien-invoke-error } " if the word calling " { $link alien-invoke } " is not compiled." } { $see-also alien-callback } ; HELP: define-c-word "( return library function parameters -- )" diff --git a/library/compiler/alien/malloc.facts b/library/compiler/alien/malloc.facts index 3446de7163..aa6551ab4e 100644 --- a/library/compiler/alien/malloc.facts +++ b/library/compiler/alien/malloc.facts @@ -29,7 +29,8 @@ HELP: memcpy "( dst src size -- newalien )" HELP: check-ptr "( c-ptr -- checked )" { $values { "c-ptr" "an alien address, byte array, or " { $link f } } { "checked" "an alien address or byte array with non-zero address" } } -{ $description "Throws an error if the input is " { $link f } ". Otherwise the object remains on the data stack." } ; +{ $description "Throws an error if the input is " { $link f } ". Otherwise the object remains on the data stack. This word should be used to check the return values of " { $link malloc } " and " { $link realloc } " before use." } +{ $error-description "Thrown by " { $link malloc } " and " { $link realloc } " to indicate a memory allocation failure." } ; HELP: free "( ptr -- )" { $values { "ptr" "an alien address" } } diff --git a/library/compiler/inference/inference.facts b/library/compiler/inference/inference.facts index e18a6f5e98..4e2ac2fe18 100644 --- a/library/compiler/inference/inference.facts +++ b/library/compiler/inference/inference.facts @@ -1,5 +1,18 @@ IN: inference -USING: help ; +USING: help kernel ; + +HELP: inference-error "( msg -- )" +{ $values { "msg" "an object" } } +{ $description "Throws an " { $link inference-error } "." } +{ $error-description + "Thrown by " { $link infer } " when the stack effect of a quotation cannot be inferred. There are several possible reasons that this can occur:" + { $list + { "The quotation applies " { $link call } " or " { $link if } " to quotation values which are not literals; thus the potential stack effect is arbitrary" } + "The quotation involves conditionals where the branches have incompatible stack effects" + "The quotation calls a recursive word with no base case" + } + "Words without a static stack effect cannot be compiled, but will still run in the interpreter." +} ; HELP: infer "( quot -- effect )" { $values { "quot" "a quotation" } { "effect" "a pair of integers" } } diff --git a/library/generic/generic.factor b/library/generic/generic.factor index 37a29f448e..8881a1306f 100644 --- a/library/generic/generic.factor +++ b/library/generic/generic.factor @@ -101,13 +101,11 @@ M: generic definer drop \ G: ; : make-generic ( word -- ) dup dup "combination" word-prop call define-compound ; -: check-method ( class generic -- ) - dup generic? [ - dup word-name " is not a generic word" append throw - ] unless - over "class" word-prop [ - over word-name " is not a class" append throw - ] unless 2drop ; +TUPLE: check-method class generic ; + +: check-method ( class generic -- class generic ) + dup generic? [ throw ] unless + over class? [ throw ] unless ; : ?make-generic ( word -- ) bootstrapping? get @@ -118,7 +116,7 @@ M: generic definer drop \ G: ; inline : define-method ( definition class generic -- ) - >r bootstrap-word r> 2dup check-method + >r bootstrap-word r> check-method [ set-hash ] with-methods ; : forget-method ( class generic -- ) diff --git a/library/generic/generic.facts b/library/generic/generic.facts index 79854240ef..f5d6f16bc2 100644 --- a/library/generic/generic.facts +++ b/library/generic/generic.facts @@ -90,9 +90,10 @@ HELP: make-generic "( word -- )" { $description "Regenerates the definition of a generic word by applying the method combination to the set of defined methods." } $low-level-note ; -HELP: check-method "( class generic -- )" +HELP: check-method "( class generic -- class generic )" { $values { "class" "a class word" } { "generic" "a generic word" } } -{ $description "Asserts that " { $snippet "class" } " is a class word and " { $snippet "generic" } " is a generic word, throwing an error if the assertion fails." } ; +{ $description "Asserts that " { $snippet "class" } " is a class word and " { $snippet "generic" } " is a generic word, throwing a " { $link check-method } " error if the assertion fails." } +{ $error-description "Thrown if " { $link POSTPONE: M: } " or " { $link define-method } " is given an invalid class or generic word." } ; HELP: ?make-generic "( word -- )" { $values { "word" "a generic word" } } diff --git a/library/generic/math-combination.facts b/library/generic/math-combination.facts index a783171fa2..78db450c28 100644 --- a/library/generic/math-combination.facts +++ b/library/generic/math-combination.facts @@ -7,7 +7,8 @@ HELP: math-upgrade "( class1 class2 -- quot )" HELP: no-math-method "( left right generic -- )" { $values { "left" "an object" } { "right" "an object" } { "generic" "a generic word" } } -{ $description } ; +{ $description "Throws a " { $link no-math-method } " error." } +{ $error-description "Thrown by generic words using the " { $link math-combination } " method combination if there is no suitable method defined for the two inputs." } ; HELP: math-method "( word class1 class2 -- quot )" { $values { "word" "a generic word" } { "class1" "a class word" } { "class2" "a class word" } { "quot" "a quotation" } } diff --git a/library/generic/standard-combination.facts b/library/generic/standard-combination.facts index f4722c1019..33470115e0 100644 --- a/library/generic/standard-combination.facts +++ b/library/generic/standard-combination.facts @@ -2,7 +2,8 @@ USING: generic help sequences ; HELP: no-method "( object generic -- )" { $values { "object" "an object" } { "generic" "a generic word" } } -{ $description "Throws an error indicating that " { $snippet "object" } " does not respond to the " { $snippet "generic" } " word." } ; +{ $description "Throws a " { $link no-method } " error." } +{ $error-description "Thrown by the " { $snippet "generic" } " word to indicate it does not have a method for the class of " { $snippet "object" } "." } ; HELP: standard-combination "( word dispatch# -- quot )" { $values { "word" "a generic word" } { "dispatch#" "a dispatch position" } { "quot" "a new quotation" } } diff --git a/library/generic/tuple.factor b/library/generic/tuple.factor index 5f34daff79..0d98a32ed3 100644 --- a/library/generic/tuple.factor +++ b/library/generic/tuple.factor @@ -49,11 +49,9 @@ IN: generic PREDICATE: word tuple-class "tuple-size" word-prop ; -TUPLE: tuple-class-error class ; -: tuple-class-error ( class -- ) throw ; - -: check-tuple-class ( class -- class ) - dup tuple-class? [ tuple-class-error ] unless ; +TUPLE: check-tuple class ; +: check-tuple ( class -- class ) + dup tuple-class? [ throw ] unless ; : define-constructor ( word class def -- ) pick reset-generic diff --git a/library/generic/tuple.facts b/library/generic/tuple.facts index a4bdc9d8c8..4e8626d1bd 100644 --- a/library/generic/tuple.facts +++ b/library/generic/tuple.facts @@ -45,6 +45,11 @@ HELP: define-constructor "( word class def -- )" { $description "Define a constructor word for a tuple class. The constructor definition receives a new instance of the class on the stack, with all slots initially set to " { $link f } "." } { $see-also POSTPONE: C: } ; +HELP: check-tuple "( class -- )" +{ $values { "word" "a word" } } +{ $description "Throws an error if " { $snippet "word" } " is not a tuple class word." } +{ $error-description "Thrown if " { $link define-constructor } " or " { $link POSTPONE: C: } " is called with a word which does not name a tuple class. Only tuple classes can have user-defined constructors." } ; + HELP: default-constructor "( class -- )" { $values { "class" "a tuple class word" } } { $description "Defines the default constructor for a tuple class. The default constructor fills slot values in from the stack." } diff --git a/library/help/markup.factor b/library/help/markup.factor index 5fe8f4265f..ccd8e3ab56 100644 --- a/library/help/markup.factor +++ b/library/help/markup.factor @@ -90,10 +90,16 @@ M: word print-element { } swap execute ; "\n" join dup [ write ] ($code) ; : $description ( content -- ) - "Description" $heading print-element ; + "Word description" $heading print-element ; + +: $class-description ( content -- ) + "Class description" $heading print-element ; + +: $error-description ( content -- ) + "Error description" $heading print-element ; : $contract ( content -- ) - "Contract" $heading print-element ; + "Generic word contract" $heading print-element ; : $examples ( content -- ) "Examples" $heading print-element ; diff --git a/library/help/topics.factor b/library/help/topics.factor index 95a4abf7ad..8b0fd326c1 100644 --- a/library/help/topics.factor +++ b/library/help/topics.factor @@ -12,9 +12,11 @@ SYMBOL: articles TUPLE: article title content ; +TUPLE: no-article name ; +: no-article ( name -- ) throw ; + : article ( name -- article ) - dup articles get hash - [ ] [ "No such article: " swap unparse append throw ] ?if ; + dup articles get hash [ ] [ no-article ] ?if ; : (add-article) ( name title element -- )
swap articles get set-hash ; diff --git a/library/help/topics.facts b/library/help/topics.facts index 6f6f64f746..8cc0703b5e 100644 --- a/library/help/topics.facts +++ b/library/help/topics.facts @@ -8,6 +8,11 @@ HELP: print-element "( element -- )" HELP: articles f { $description "Variable. Hashtable mapping article names to " { $link article } " instances." } ; +HELP: no-article "( name -- )" +{ $values { "name" "an article name" } } +{ $description "Throws a " { $link no-article } " error." } +{ $error-description "Thrown by " { $link help } " if the given help topic does not exist, or if the help topic being dispayed links to a help topic which does not exist." } ; + HELP: article "( name -- article )" { $values { "name" "an article name" } { "article" "an " { $link article } " object" } } { $description "Outputs a named " { $link article } " object." } ; diff --git a/library/io/c-streams.facts b/library/io/c-streams.facts index c2e3fd609a..d54140821f 100644 --- a/library/io/c-streams.facts +++ b/library/io/c-streams.facts @@ -68,3 +68,6 @@ HELP: fgetc "( alien -- ch )" { $values { "alien" "a C FILE* handle" } { "ch" "a character" } } { $description "Reads a single character from a C FILE* handle." } { $errors "Throws an error if the input operation failed." } ; + +HELP: c-stream-error "( -- )" +{ $error-description "This error is thrown when C stream I/O is in use and one of the TCP/IP networking words is called. C stream I/O will be in use if either the " { $snippet "-no-native-io" } " switch is passed to bootstrap (see " { $link "bootstrap-cli-args" } ") or if Factor does not have a native I/O implementation for your operating system." } ; diff --git a/library/io/duplex-stream.facts b/library/io/duplex-stream.facts index 25c1a9b860..5887006b46 100644 --- a/library/io/duplex-stream.facts +++ b/library/io/duplex-stream.facts @@ -1,8 +1,13 @@ USING: help io ; HELP: duplex-stream f -{ $description "A bidirectional stream delegating to a pair of streams, sending input to one delegate and output to another." } ; +{ $class-description "A bidirectional stream delegating to a pair of streams, sending input to one delegate and output to another." } ; HELP: "( in out -- stream )" -{ $values { "in" "an input stream" } { "out" "an output stream" } { "stream" " a bidirectional stream" } } +{ $values { "in" "an input stream" } { "out" "an output stream" } { "stream" " a duplex stream" } } { $description "Creates a duplex stream. Writing to a duplex stream will write to " { $snippet "out" } ", and reading from a duplex stream will read from " { $snippet "in" } ". Closing a duplex stream closes both the input and output streams." } ; + +HELP: check-closed "( stream -- )" +{ $values { "stream" "a duplex stream" } } +{ $description "Throws a " { $link check-closed } " error if the stream has already been closed." } +{ $error-description "This error is thrown when performing an I/O operation on a " { $link duplex-stream } " which has been closed with " { $link stream-close } "." } ; diff --git a/library/math/integer.factor b/library/math/integer.factor index 487b85b197..e9fc05767e 100644 --- a/library/math/integer.factor +++ b/library/math/integer.factor @@ -34,7 +34,7 @@ IN: math-internals dup 1 number= [ drop ] [ (fraction>) ] if ; inline TUPLE: /0 ; -: /0 ( x y -- ) throw ; +: /0 ( -- ) throw ; M: integer / ( x y -- x/y ) dup zero? [ diff --git a/library/math/integer.facts b/library/math/integer.facts index c98e3efe6b..addea2dc60 100644 --- a/library/math/integer.facts +++ b/library/math/integer.facts @@ -1,4 +1,4 @@ -USING: help math math-internals ; +USING: errors help math math-internals ; HELP: fixnum f { $description "The class of fixnums, which are fixed-width integers small enough to fit in a machine cell. Because they are not heap-allocated, fixnums do not have object identity. Equality of tagged pointer bit patterns is actually " { $emphasis "value" } " equality for fixnums." } ; @@ -213,3 +213,7 @@ HELP: bignum-shift "( x y -- z )" { $values { "x" "a bignum" } { "y" "a bignum" } { "z" "a bignum" } } { $description "Primitive version of " { $link shift } "." } { $warning "This word does not perform type checking, and passing objects of the wrong type can crash the runtime. User code should call the generic word " { $link shift } " instead." } ; + +HELP: /0 "( -- )" +{ $error-description "This error is thrown when " { $link / } " is called with two integer inputs, the denominator being zero." } +{ $notes "Floating point division by zero does not raise an error at all, whereas integer division by zero in " { $link /i } " typically raises an operating system signal (see " { $link signal-error. } ")." } ; diff --git a/library/syntax/early-parser.factor b/library/syntax/early-parser.factor index 532da730f6..6d2effd6cc 100644 --- a/library/syntax/early-parser.factor +++ b/library/syntax/early-parser.factor @@ -13,16 +13,19 @@ SYMBOL: line-number SYMBOL: line-text SYMBOL: column +TUPLE: check-vocab name ; : check-vocab ( name -- vocab ) dup vocab [ ] [ - "No such vocabulary: " swap >string append throw + + { { "Continue" f } } condition ] ?if ; -: use+ ( string -- ) check-vocab use get push ; +: use+ ( string -- ) check-vocab [ use get push ] when* ; : add-use ( seq -- ) [ use+ ] each ; -: set-use ( seq -- ) [ check-vocab ] map >vector use set ; +: set-use ( seq -- ) + [ check-vocab ] map [ ] subset >vector use set ; : set-in ( name -- ) dup ensure-vocab dup in set use+ ; diff --git a/library/syntax/early-parser.facts b/library/syntax/early-parser.facts index 2768869181..19f33c9844 100644 --- a/library/syntax/early-parser.facts +++ b/library/syntax/early-parser.facts @@ -12,9 +12,9 @@ HELP: in f { $see-also use set-in POSTPONE: IN: } ; HELP: check-vocab "( name -- vocab )" -{ $values { "name" "a string" } { "vocab" "a hashtable" } } -{ $description "Outputs a named vocabulary." } -{ $errors "Throws an error if the vocabulary does not exist." } ; +{ $values { "name" "a string" } { "vocab" "a hashtable or " { $link f } } } +{ $description "Outputs a named vocabulary. If the vocabulary does not exist, throws a restartable " { $link check-vocab } " error. If the user invokes the restart, this word outputs " { $link f } "." } +{ $error-description "Thrown by " { $link POSTPONE: USE: } " and " { $link POSTPONE: USING: } " when a given vocabulary does not exist. Vocabularies must be created by " { $link POSTPONE: IN: } " before being used." } HELP: use+ "( vocab -- )" { $values { "vocab" "a string" } } diff --git a/library/syntax/parse-stream.facts b/library/syntax/parse-stream.facts index e508fdf05b..6ddd39eb4d 100644 --- a/library/syntax/parse-stream.facts +++ b/library/syntax/parse-stream.facts @@ -10,7 +10,8 @@ HELP: parse-lines "( lines -- quot )" HELP: parse-error "( msg -- )" { $values { "msg" "an object" } } -{ $description "Throws a parse error encapsulating a message along with current parser state, including the file being parsed, line number, and column number." } ; +{ $description "Throws a " { $link parse-error } "." } +{ $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." } ; HELP: with-parser "( quot -- )" { $values { "quot" "a quotation" } } diff --git a/library/syntax/parse-syntax.facts b/library/syntax/parse-syntax.facts index a810b19822..66cfa3ac51 100644 --- a/library/syntax/parse-syntax.facts +++ b/library/syntax/parse-syntax.facts @@ -178,7 +178,7 @@ HELP: BIN: "integer" HELP: GENERIC: "word" { $values { "word" "a new word to define" } } -{ $description "Defines a new generic word in the current vocabulary. Initially, it contains no methods, and thus will throw an error when called." } +{ $description "Defines a new generic word in the current vocabulary. Initially, it contains no methods, and thus will throw a " { $link no-method } " error when called." } { $notes "A " { $link "method-combination" } " facility exists for customizing method dispatch behavior." $terpri diff --git a/library/syntax/parser.facts b/library/syntax/parser.facts index a1327c9685..498c1cc192 100644 --- a/library/syntax/parser.facts +++ b/library/syntax/parser.facts @@ -41,6 +41,9 @@ HELP: scan-word "( -- obj )" { $errors "Throws an error if the token does not name a word, and does not parse as a number." } $parsing-note ; +HELP: bad-escape "( -- )" +{ $error-description "This error is thrown if the parser encounters an invalid escape code following a backslash (" { $snippet "\\" } ") in a string literal. See " { $link "escape" } " for a list of valid escape codes." } ; + HELP: escape "( escape -- ch )" { $values { "escape" "a single-character escape" } { "ch" "a character" } } { $description "Converts from a single-character escape code and the corresponding character." } diff --git a/library/test/test.factor b/library/test/test.factor index 04a9cb97d1..f1d9d4009c 100644 --- a/library/test/test.factor +++ b/library/test/test.factor @@ -6,10 +6,10 @@ memory namespaces parser prettyprint sequences strings words vectors ; TUPLE: assert got expect ; - M: assert summary drop "Assertion failed" ; +: assert ( got expect -- ) throw ; -: assert= ( a b -- ) 2dup = [ 2drop ] [ throw ] if ; +: assert= ( a b -- ) 2dup = [ 2drop ] [ assert ] if ; : print-test ( input output -- ) "----> Quotation: " write . diff --git a/library/test/test.facts b/library/test/test.facts index 35b6f2075b..d047548480 100644 --- a/library/test/test.facts +++ b/library/test/test.facts @@ -1,6 +1,12 @@ IN: test USING: help kernel ; +HELP: assert "( got expect -- )" +{ $values { "got" "the obtained value" } { "expect" "the expected value" } } +{ $description "Throws an " { $link assert } " error." } +{ $error-description "Thrown when a unit test or other assertion fails." } +{ $see-also unit-test unit-test-fails assert-depth } ; + HELP: benchmark "( quot -- gctime runtime )" { $values { "quot" "a quotation" } { "gctime" "an integer denoting milliseconds" } { "runtime" "an integer denoting milliseconds" } } { $description "Runs a quotation, measuring the total wall clock time and the total time spent in the garbage collector." } diff --git a/library/tools/debugger.factor b/library/tools/debugger.factor index 583a9eabd1..c1f395c12e 100644 --- a/library/tools/debugger.factor +++ b/library/tools/debugger.factor @@ -131,6 +131,8 @@ M: bounds-error summary drop "Sequence index out of bounds" ; M: condition error. delegate error. ; +M: condition error-help drop f ; + M: tuple error. ( error -- ) describe ; M: string error. ( error -- ) print ; diff --git a/library/tools/debugger.facts b/library/tools/debugger.facts index 3d7e71b58f..9ec518c5f0 100644 --- a/library/tools/debugger.facts +++ b/library/tools/debugger.facts @@ -1,4 +1,6 @@ -USING: errors help ; +IN: errors +USING: alien arrays generic help inference kernel math memory +strings vectors ; HELP: error f { $description "Global variable holding most recently thrown error." } @@ -40,3 +42,65 @@ HELP: print-error "( error -- )" HELP: try "( quot -- )" { $values { "quot" "a quotation" } } { $description "Calls the quotation. If it throws an error, logs the error to the default stream and restores the datastack." } ; + +HELP: expired-error. f +{ $error-description "Thrown by " { $link alien-address } " and " { $link alien-invoke } " if an " { $link alien } " object passed in as a parameter has expired. Alien objects expire if they are saved an image which is subsequently loaded; this prevents a certain class of programming errors, usually attempts to use uninitialized objects, since holding a C address is meaningless between sessions." } +{ $notes "You can check if an alien object has expired by calling " { $link expired? } "." } ; + +HELP: io-error. f +{ $error-description "Thrown by the C streams I/O primitives if an I/O error occurs." } ; + +HELP: undefined-word-error. f +{ $error-description "Thrown if an attempt is made to call a word which was defined by " { $link POSTPONE: DEFER: } "." } ; + +HELP: type-check-error. f +{ $error-description "Thrown by various primitives if one of the inputs does not have the expected type. Generic words throw " { $link no-method } " and " { $link no-math-method } " errors in such cases instead." } ; + +HELP: signal-error. f +{ $error-description + "Thrown by the runtime when a Unix signal is received. While signal numbers are system-specific, the following are relatively standard:" + { $list + { "4 - Illegal instruction. If you see this error, it is a bug in Factor's compiler and should be reported." } + { "8 - Arithmetic exception. Most likely a divide by zero in " { $link /i } "." } + { "10, 11 - Memory protection fault. This error suggests invalid values are being passed to C functions by an " { $link alien-invoke } ". Factor also uses memory protection to trap stack underflows and overflows, but usually these are reported as their own errors. Sometimes they'll show up as a generic signal 11, though." } + } + "The Windows equivalent of a signal 11 is a SEH fault. When one occurs, the runtime throws a singal error, even though it does not correspond to a Unix signal." +} ; + +HELP: negative-array-size-error. f +{ $error-description "Thrown by " { $link } ", " { $link } ", " { $link } " and " { $link } " if a negative capacity is specified." } ; + +HELP: c-string-error. f +{ $error-description "Thrown by " { $link alien-invoke } " and various primitives if a string containing null bytes, or characters with values higher than 255 is passed in where a C string is expected.See " { $link "c-types-strings" } "." } ; + +HELP: ffi-error. f +{ $error-description "Thrown by " { $link dlopen } " and " { $link dlsym } " if a problem occurs while loading a native library or looking up a symbol. See " { $link "alien" } "." } ; + +HELP: heap-scan-error. f +{ $error-description "Thrown if " { $link next-object } " is called outside of a " { $link begin-scan } "/" { $link end-scan } " pair." } ; + +HELP: undefined-symbol-error. f +{ $error-description "Thrown if a previously-compiled " { $link alien-invoke } " call refers to a native library symbol which no longer exists." } ; + +HELP: user-interrupt. f +{ $error-description "Thrown by the " { $snippet "t" } " command in the FEP." } ; + +HELP: datastack-underflow. f +{ $error-description "Thrown by the runtime if an attempt is made to pop elements from an empty data stack." } +{ $notes "You can use the " { $link infer } " tool to statically check stack effects of quotations." } ; + +HELP: datastack-overflow. f +{ $error-description "Thrown by the runtime if an attempt is made to push elements on a full data stack." } +{ $notes "This error usually indicates a run-away recursion, however if you legitimately need a data stack larger than the default, see " { $link "runtime-cli-args" } "." } ; + +HELP: retainstack-underflow. f +{ $error-description "Thrown by the runtime if " { $link r> } " is called while the retain stack is empty." } +{ $notes "You can use the " { $link infer } " tool to statically check stack effects of quotations." } ; + +HELP: retainstack-overflow. f +{ $error-description "Thrown by the runtime if " { $link >r } " is called when the retain stack is full." } +{ $notes "This error usually indicates a run-away recursion, however if you legitimately need a retain stack larger than the default, see " { $link "runtime-cli-args" } "." } ; + +HELP: callstack-overflow. f +{ $error-description "Thrown by the runtime if the call stack is full." } +{ $notes "This error usually indicates a run-away recursion, however if you legitimately need a call stack larger than the default, see " { $link "runtime-cli-args" } "." } ; diff --git a/library/tools/memory.facts b/library/tools/memory.facts index 5a1817a4f2..3a96418baf 100644 --- a/library/tools/memory.facts +++ b/library/tools/memory.facts @@ -36,7 +36,7 @@ $terpri HELP: next-object "( -- obj )" { $description "Outputs the object at the heap scan pointer, and then advances the heap scan pointer. If the end of the heap has been reached, outputs " { $link f } ". This is unambiguous since the " { $link f } " object is tagged immediate and not actually stored in the heap." } -{ $errors "Throws an error if called outside a " { $link begin-scan } "/" { $link end-scan } " pair." } +{ $errors "Throws a " { $link heap-scan-error. } " if called outside a " { $link begin-scan } "/" { $link end-scan } " pair." } { $notes "This is a low-level facility and can be dangerous. Use the " { $link each-object } " combinator instead." } ; HELP: end-scan "( -- )" diff --git a/library/words.facts b/library/words.facts index 89b8e4ac5c..7878236fbd 100644 --- a/library/words.facts +++ b/library/words.facts @@ -223,6 +223,11 @@ HELP: reveal "( word -- )" { $description "Adds a newly-created word to the dictionary. Usually this word does not need to be called directly." } { $see-also create } ; +HELP: check-create "( name vocab -- name vocab )" +{ $values { "name" "a string" } { "vocab" "a string" } } +{ $description "Throws a " { $link check-create } " error if " { $snippet "name" } " or " { $snippet "vocab" } " is not a string." } +{ $error-description "Thrown if " { $link create } " is called with invalid parameters." } ; + HELP: create "( name vocab -- word )" { $values { "name" "a string" } { "vocab" "a string" } { "word" "a word" } } { $description "Creates a new word. Creates the vocabulary first if it does not already exist. If the vocabulary exists and already contains a word with the requested name, outputs the existing word." } ;