]> gitweb.factorcode.org Git - factor.git/commitdiff
Improve stack checker documentation
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 23 Apr 2009 08:48:32 +0000 (03:48 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Thu, 23 Apr 2009 08:48:32 +0000 (03:48 -0500)
20 files changed:
basis/combinators/smart/smart-docs.factor
basis/compiler/compiler-docs.factor
basis/help/cookbook/cookbook.factor
basis/help/handbook/handbook.factor
basis/io/mmap/mmap-docs.factor
basis/io/sockets/sockets-docs.factor
basis/math/matrices/matrices.factor
basis/memoize/memoize-docs.factor
basis/stack-checker/errors/errors-docs.factor
basis/stack-checker/stack-checker-docs.factor
basis/threads/threads-docs.factor
basis/tools/errors/errors-docs.factor
core/combinators/combinators-docs.factor
core/continuations/continuations-docs.factor
core/effects/effects-docs.factor
core/generic/generic-docs.factor
core/io/files/files-docs.factor
core/io/io-docs.factor
core/syntax/syntax-docs.factor
core/words/words-docs.factor

index 679b5877594d7af40cdfb0b1b6bca227ee0e92f5..d8ee89ef2d5d7ecea076936d5973261a09760f85 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2009 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: help.markup help.syntax kernel quotations math sequences
-multiline ;
+multiline stack-checker ;
 IN: combinators.smart
 
 HELP: input<sequence
@@ -108,7 +108,7 @@ HELP: append-outputs-as
 
 
 ARTICLE: "combinators.smart" "Smart combinators"
-"The macros in the " { $vocab-link "combinators.smart" } " vocabulary look at the static stack effects of input quotations and generate code which produces or consumes the relevant number of stack values." $nl
+"A " { $emphasis "smart combinator" } " is a macro which reflects on the stack effect of an input quotation. The " { $vocab-link "combinators.smart" } " vocabulary implements a few simple smart combinators which look at the static stack effects of input quotations and generate code which produces or consumes the relevant number of stack values." $nl
 "Call a quotation and discard all output values:"
 { $subsection drop-outputs }
 "Take all input values from a sequence:"
@@ -122,6 +122,7 @@ ARTICLE: "combinators.smart" "Smart combinators"
 { $subsection sum-outputs }
 "Concatenating output values:"
 { $subsection append-outputs }
-{ $subsection append-outputs-as } ;
+{ $subsection append-outputs-as }
+"New smart combinators can be created by defining " { $link "macros" } " which call " { $link infer } "." ;
 
 ABOUT: "combinators.smart"
index cdd410457c882dd07af6a4a87d595eb394140b79..89b9b3cbe96aece57f1f201190d7fbc392c25759 100644 (file)
@@ -46,9 +46,9 @@ $nl
     { "The " { $emphasis "non-optimizing quotation compiler" } " compiles quotations to naive machine code very quickly. The non-optimizing quotation compiler is part of the VM." }
     { "The " { $emphasis "optimizing word compiler" } " compiles whole words at a time while performing extensive data and control flow analysis. This provides greater performance for generated code, but incurs a much longer compile time. The optimizing compiler is written in Factor." }
 }
-"The optimizing compiler only compiles words which have a static stack effect. This means that methods defined on fundamental generic words such as " { $link nth } " should have a static stack effect. See " { $link "inference" } " and " { $link "cookbook-pitfalls" } "."
-$nl
 "The optimizing compiler also trades off compile time for performance of generated code, so loading certain vocabularies might take a while. Saving the image after loading vocabularies can save you a lot of time that you would spend waiting for the same code to load in every coding session; see " { $link "images" } " for information."
+$nl
+"Most code you write will run with the optimizing compiler. Sometimes, the non-optimizing compiler is used, for example for listener interactions, or for running the quotation passed to " { $link POSTPONE: call( } "."
 { $subsection "compiler-errors" }
 { $subsection "hints" }
 { $subsection "compiler-usage" }
index 9bb76f8d5a4767d73d973451d4c1b420ab7323c8..59486a9c35d17defe1dc643a9eebbccc227d709b 100644 (file)
@@ -12,7 +12,7 @@ $nl
 $nl
 "Factor evaluates code left to right, and stores intermediate values on a " { $emphasis "stack" } ". If you think of the stack as a pile of papers, then " { $emphasis "pushing" } " a value on the stack corresponds to placing a piece of paper at the top of the pile, while " { $emphasis "popping" } " a value corresponds to removing the topmost piece."
 $nl
-"All words except those which only push literals on the stack must have a " { $emphasis "stack effect declaration" } ", for example " { $snippet "( x y -- z )" } " denotes that a word takes two inputs, with " { $snippet "y" } " at the top of the stack, and returns one output. Stack effect declarations can be viewed by browsing source code, or using tools such as " { $link see } "; they are also checked by the compiler. See " { $link "effect-declaration" } "."
+"All words have a " { $emphasis "stack effect declaration" } ", for example " { $snippet "( x y -- z )" } " denotes that a word takes two inputs, with " { $snippet "y" } " at the top of the stack, and returns one output. Stack effect declarations can be viewed by browsing source code, or using tools such as " { $link see } "; they are also checked by the compiler. See " { $link "effects" } "."
 $nl
 "Coming back to the example in the beginning of this article, the following series of steps occurs as the code is evaluated:"
 { $table
@@ -56,18 +56,9 @@ $nl
     "5 0 -       ! Computes 5-0"
     "5 0 swap -  ! Computes 0-5"
 }
-"Also, in the above example a stack effect declaration is written between " { $snippet "(" } " and " { $snippet ")" } " with a mnemonic description of what the word does to the stack. See " { $link "effect-declaration" } " for details."
+"Also, in the above example a stack effect declaration is written between " { $snippet "(" } " and " { $snippet ")" } " with a mnemonic description of what the word does to the stack. See " { $link "effects" } " for details."
 { $curious
-    "This syntax will be familiar to anybody who has used Forth before. However the behavior is slightly different. In most Forth systems, the below code prints 2, because the definition of " { $snippet "b" } " still refers to the previous definition of " { $snippet "a" } ":"
-    { $code
-        ": a 1 ;"
-        ": b ( -- x ) a 1 + ;"
-        ": a 2 ;"
-        "b ."
-    }
-    "In Factor, this example will print 3 since word redefinition is explicitly supported."
-    $nl
-    "Indeed, redefining a word twice in the same source file is an error; this is almost always a mistake since there's no way to call the first definition. See " { $link "definition-checking" } "."
+  "This syntax will be familiar to anybody who has used Forth before. However, unlike Forth, some additional static checks are performed. See " { $link "definition-checking" } " and " { $link "inference" } "."
 }
 { $references
     { "A whole slew of shuffle words can be used to rearrange the stack. There are forms of word definition other than colon definition, words can be defined entirely at runtime, and word definitions can be " { $emphasis "annotated" } " with tracing calls and breakpoints without modifying the source code." }
@@ -175,53 +166,11 @@ $nl
     "parser"
 } ;
 
-ARTICLE: "cookbook-io" "Input and output cookbook"
-"Ask the user for their age, and print it back:"
-{ $code
-    "USING: io math.parser ;"
-    ": ask-age ( -- ) \"How old are you?\" print ;"
-    ": read-age ( -- n ) readln string>number ;"
-    ": print-age ( n -- )"
-    "    \"You are \" write"
-    "    number>string write"
-    "    \" years old.\" print ;"
-    ": example ( -- ) ask-age read-age print-age ;"
-    "example"
-}
-"Print the lines of a file in sorted order:"
-{ $code
-    "USING: io io.encodings.utf8 io.files sequences sorting ;"
-    "\"lines.txt\" utf8 file-lines natural-sort [ print ] each"
-}
-"Read 1024 bytes from a file:"
-{ $code
-    "USING: io io.encodings.binary io.files ;"
-    "\"data.bin\" binary [ 1024 read ] with-file-reader"
-}
-"Convert a file of 4-byte cells from little to big endian or vice versa, by directly mapping it into memory and operating on it with sequence words:"
-{ $code
-    "USING: accessors grouping io.files io.mmap.char kernel sequences ;"
-    "\"mydata.dat\" ["
-    "    4 <sliced-groups> [ reverse-here ] change-each"
-    "] with-mapped-char-file"
-}
-"Send some bytes to a remote host:"
-{ $code
-    "USING: io io.encodings.ascii io.sockets strings ;"
-    "\"myhost\" 1033 <inet> ascii"
-    "[ B{ 12 17 102 } write ] with-client"
-}
-{ $references
-    { }
-    "number-strings"
-    "io"
-} ;
-
 ARTICLE: "cookbook-application" "Application cookbook"
 "Vocabularies can define a main entry point:"
 { $code "IN: game-of-life"
 "..."
-": play-life ... ;"
+": play-life ( -- ) ... ;"
 ""
 "MAIN: play-life"
 }
@@ -318,7 +267,6 @@ $nl
     { "Use " { $link "cleave-combinators" } " and " { $link "spread-combinators" } " instead of " { $link "shuffle-words" } " to give your code more structure." }
     { "Not everything has to go on the stack. The " { $vocab-link "namespaces" } " vocabulary provides dynamically-scoped variables, and the " { $vocab-link "locals" } " vocabulary provides lexically-scoped variables. Learn both and use them where they make sense, but keep in mind that overuse of variables makes code harder to factor." }
     "Every time you define a word which simply manipulates sequences, hashtables or objects in an abstract way which is not related to your program domain, check the library to see if you can reuse an existing definition."
-    { "Learn to use the " { $link "inference" } " tool." }
     { "Write unit tests. Factor provides good support for unit testing; see " { $link "tools.test" } ". Once your program has a good test suite you can refactor with confidence and catch regressions early." }
     "Don't write Factor as if it were C. Imperative programming and indexed loops are almost always not the most idiomatic solution."
     { "Use sequences, assocs and objects to group related data. Object allocation is very cheap. Don't be afraid to create tuples, pairs and triples. Don't be afraid of operations which allocate new objects either, such as " { $link append } "." }
@@ -332,6 +280,7 @@ $nl
 "Factor tries to implement as much of itself as possible, because this improves simplicity and performance. One consequence is that Factor exposes its internals for extension and study. You even have the option of using low-level features not usually found in high-level languages, such manual memory management, pointer arithmetic, and inline assembly code."
 $nl
 "Unsafe features are tucked away so that you will not invoke them by accident, or have to use them to solve conventional programming problems. However when the need arises, unsafe features are invaluable, for example you might have to do some pointer arithmetic when interfacing directly with C libraries." ;
+
 ARTICLE: "cookbook-pitfalls" "Pitfalls to avoid"
 "Factor is a very clean and consistent language. However, it has some limitations and leaky abstractions you should keep in mind, as well as behaviors which differ from other languages you may be used to."
 { $list
@@ -341,13 +290,6 @@ ARTICLE: "cookbook-pitfalls" "Pitfalls to avoid"
     { "If a literal object appears in a word definition, the object itself is pushed on the stack when the word executes, not a copy. If you intend to mutate this object, you must " { $link clone } " it first. See " { $link "syntax-literals" } "." }
     { "For a discussion of potential issues surrounding the " { $link f } " object, see " { $link "booleans" } "." }
     { "Factor's object system is quite flexible. Careless usage of union, mixin and predicate classes can lead to similar problems to those caused by “multiple inheritance” in other languages. In particular, it is possible to have two classes such that they have a non-empty intersection and yet neither is a subclass of the other. If a generic word defines methods on two such classes, various disambiguation rules are applied to ensure method dispatch remains deterministic, however they may not be what you expect. See " { $link "method-order" } " for details." }
-    { "Performance-sensitive code should have a static stack effect so that it can be compiled by the optimizing word compiler, which generates more efficient code than the non-optimizing quotation compiler. See " { $link "inference" } " and " { $link "compiler" } "."
-    $nl
-    "This means that methods defined on performance sensitive, frequently-called core generic words such as " { $link nth } " should have static stack effects which are consistent with each other, since a generic word will only have a static stack effect if all methods do."
-    $nl
-    "Unit tests for the " { $vocab-link "stack-checker" } " vocabulary can be used to ensure that any methods your vocabulary defines on core generic words have static stack effects:"
-    { $code "\"stack-checker\" test" }
-    "In general, you should strive to write code with inferable stack effects, even for sections of a program which are not performance sensitive; the " { $link infer. } " tool together with the optimizing compiler's error reporting can catch many bugs ahead of time." }
     { "Be careful when calling words which access variables from a " { $link make-assoc } " which constructs an assoc with arbitrary keys, since those keys might shadow variables." }
     { "If " { $link run-file } " throws a stack depth assertion, it means that the top-level form in the file left behind values on the stack. The stack depth is compared before and after loading a source file, since this type of situation is almost always an error. If you have a legitimate need to load a source file which returns data in some manner, define a word in the source file which produces this data on the stack and call the word after loading the file." }
 } ;
@@ -372,7 +314,6 @@ ARTICLE: "cookbook" "Factor cookbook"
 { $subsection "cookbook-combinators" }
 { $subsection "cookbook-variables" }
 { $subsection "cookbook-vocabs" }
-{ $subsection "cookbook-io" }
 { $subsection "cookbook-application" }
 { $subsection "cookbook-scripts" }
 { $subsection "cookbook-philosophy" }
index a97a46badc94df4f96287a20a7381e90c293eb32..262c46bbc3205c5b68989300ff116c769f1668c2 100644 (file)
@@ -39,7 +39,7 @@ $nl
     { { $snippet "$" { $emphasis "foo" } } { "help markup" } { $links $heading $emphasis } }
 }
 { $heading "Stack effect conventions" }
-"Stack effect conventions are documented in " { $link "effect-declaration" } "."
+"Stack effect conventions are documented in " { $link "effects" } "."
 { $heading "Glossary of terms" }
 "Common terminology and abbreviations used throughout Factor and its documentation:"
 { $table
@@ -229,9 +229,11 @@ ARTICLE: "handbook-language-reference" "The language"
 { $heading "Fundamentals" }
 { $subsection "conventions" }
 { $subsection "syntax" }
-{ $subsection "effects" }
+{ $heading "The stack" }
 { $subsection "evaluator" }
-{ $heading "Data types" }
+{ $subsection "effects" }
+{ $subsection "inference" }
+{ $heading "Basic data types" }
 { $subsection "booleans" }
 { $subsection "numbers" }
 { $subsection "collections" }
@@ -239,16 +241,18 @@ ARTICLE: "handbook-language-reference" "The language"
 { $subsection "words" }
 { $subsection "shuffle-words" }
 { $subsection "combinators" }
-{ $subsection "errors" }
-{ $subsection "continuations" }
+{ $subsection "threads" }
 { $heading "Named values" }
 { $subsection "locals" }
 { $subsection "namespaces" }
 { $subsection "namespaces-global" }
 { $subsection "values" }
 { $heading "Abstractions" }
+{ $subsection "errors" }
 { $subsection "objects" }
 { $subsection "destructors" }
+{ $subsection "continuations" }
+{ $subsection "memoize" }
 { $subsection "parsing-words" }
 { $subsection "macros" }
 { $subsection "fry" }
@@ -263,6 +267,7 @@ ARTICLE: "handbook-system-reference" "The implementation"
 { $subsection "vocabularies" }
 { $subsection "source-files" }
 { $subsection "compiler" }
+{ $subsection "tools.errors" }
 { $heading "Virtual machine" }
 { $subsection "images" }
 { $subsection "cli" }
@@ -283,7 +288,7 @@ ARTICLE: "handbook-tools-reference" "Developer tools"
 { $subsection "prettyprint" }
 { $subsection "inspector" }
 { $subsection "tools.annotations" }
-{ $subsection "inference" }
+{ $subsection "tools.inference" }
 { $heading "Browsing" }
 { $subsection "see" }
 { $subsection "tools.crossref" }
index 5ef3400a6dd7969dd11828f94b484ee319493399..f0adb4732112bab5957f19e7e22b7205cafb40fc 100644 (file)
@@ -54,11 +54,20 @@ ARTICLE: "io.mmap.arrays" "Memory-mapped arrays"
 ARTICLE: "io.mmap.low-level" "Reading and writing mapped files directly"
 "Data can be read and written from the " { $link mapped-file } " by applying low-level alien words to the " { $slot "address" } " slot. See " { $link "reading-writing-memory" } "." ;
 
+ARTICLE: "io.mmap.examples" "Memory-mapped file example"
+"Convert a file of 4-byte cells from little to big endian or vice versa, by directly mapping it into memory and operating on it with sequence words:"
+{ $code
+    "USING: accessors grouping io.files io.mmap.char kernel sequences ;"
+    "\"mydata.dat\" ["
+    "    4 <sliced-groups> [ reverse-here ] change-each"
+    "] with-mapped-char-file"
+} ;
+
 ARTICLE: "io.mmap" "Memory-mapped files"
 "The " { $vocab-link "io.mmap" } " vocabulary implements support for memory-mapped files."
 { $subsection <mapped-file> }
 "Memory-mapped files are disposable and can be closed with " { $link dispose } " or " { $link with-disposal } "."
-$nl
+{ $subsection "io.mmap.examples" }
 "A utility combinator which wraps the above:"
 { $subsection with-mapped-file }
 "Instances of " { $link mapped-file } " don't support any interesting operations in themselves. There are two facilities for accessing their contents:"
index a66ed1d0c008feccada997d1ca3a351e3432529d..970aa34ea625a7408fd4ec1106083e4e1cef668f 100644 (file)
@@ -56,12 +56,23 @@ $nl
 }
 "The " { $link inet } " address specifier is not supported by the " { $link send } " word because a single host name can resolve to any number of IPv4 or IPv6 addresses, therefore there is no way to know which address should be used. Applications should call " { $link resolve-host } " then use some kind of strategy to pick the correct address (for example, by sending a packet to each one and waiting for a response, or always assuming IPv4)." ;
 
+ARTICLE: "network-examples" "Networking examples"
+"Send some bytes to a remote host:"
+{ $code
+    "USING: io io.encodings.ascii io.sockets strings ;"
+    "\"myhost\" 1033 <inet> ascii"
+    "[ B{ 12 17 102 } write ] with-client"
+}
+"Look up the IP addresses associated with a host name:"
+{ $code "USING: io.sockets ;" "\"www.apple.com\" 80 <inet> resolve-host ." } ;
+
 ARTICLE: "network-streams" "Networking"
 "Factor supports connection-oriented and packet-oriented communication over a variety of protocols:"
 { $list
     "TCP/IP and UDP/IP, over IPv4 and IPv6"
     "Unix domain sockets (Unix only)"
 }
+{ $subsection "network-examples" }
 { $subsection "network-addressing" }
 { $subsection "network-connection" }
 { $subsection "network-packet" }
index 7c687d753d37e74d30ce6996ec8ce56e73b75ef5..4c2c641c84c0ef3f465b9f904b9c6f0bcee7f7a7 100755 (executable)
@@ -1,6 +1,7 @@
 ! Copyright (C) 2005, 2009 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: arrays kernel math math.order math.vectors sequences ;
+USING: arrays kernel math math.order math.vectors
+sequences sequences.private accessors columns ;
 IN: math.matrices
 
 ! Matrices
@@ -24,9 +25,19 @@ IN: math.matrices
 : m*   ( m m -- m ) [ v* ] 2map ;
 : m/   ( m m -- m ) [ v/ ] 2map ;
 
-: v.m ( v m -- v ) flip [ v. ] with map ;
-: m.v ( m v -- v ) [ v. ] curry map ;
-: m.  ( m m -- m ) flip [ swap m.v ] curry map ;
+TUPLE: flipped { seq read-only } ;
+
+M: flipped length seq>> first length ;
+
+M: flipped nth-unsafe seq>> swap <column> ;
+
+INSTANCE: flipped sequence
+
+C: <flipped> flipped
+
+: v.m ( v m -- v ) <flipped> [ v. ] with map ;
+: m.v ( m v -- v ) [ v. ] curry map ; inline
+: m.  ( m m -- m ) <flipped> [ swap m.v ] curry map ;
 
 : mmin ( m -- n ) [ 1/0. ] dip [ [ min ] each ] each ;
 : mmax ( m -- n ) [ -1/0. ] dip [ [ max ] each ] each ;
index cfb5cffb37ad38f07f372a01a80324bb485e7a87..a551272f43d17aa8aa881d70a6a56fc002bf8953 100644 (file)
@@ -3,6 +3,20 @@
 USING: help.syntax help.markup words quotations effects ;
 IN: memoize
 
+ARTICLE: "memoize" "Memoization"
+"The " { $vocab-link "memoize" } " vocabulary implements a simple form of memoization, which is when a word caches results for every unique set of inputs that is supplied. Calling a memoized word with the same inputs more than once does not recalculate anything."
+$nl
+"Memoization is useful in situations where the set of possible inputs is small, but the results are expensive to compute and should be cached. Memoized words should not have any side effects."
+$nl
+"Defining a memoized word at parse time:"
+{ $subsection POSTPONE: MEMO: }
+"Defining a memoized word at run time:"
+{ $subsection define-memoized }
+"Clearing memoized results:"
+{ $subsection reset-memoized } ;
+
+ABOUT: "memoize"
+
 HELP: define-memoized
 { $values { "word" word } { "quot" quotation } { "effect" effect } }
 { $description "defines the given word at runtime as one which memoizes its output given a particular input" }
index 5b314a3154d11d4a7d7a2e03702c4937122d9abe..3c36d95d1ef5d9e8258b043ecf722782bfc08918 100644 (file)
@@ -3,10 +3,9 @@ sequences.private words ;
 IN: stack-checker.errors
 
 HELP: literal-expected
-{ $error-description "Thrown when inference encounters a " { $link call } " or " { $link if } " being applied to a value which is not known to be a literal. Such a form can have an arbitrary stack effect, and does not compile." }
-{ $notes "This error will be thrown when compiling any combinator, such as " { $link each } ". However, words calling combinators can compile if the combinator is declared " { $link POSTPONE: inline } " and the quotation being passed in is a literal." }
+{ $error-description "Thrown when inference encounters a combinator or macro being applied to a value which is not known to be a literal, or constructed in a manner which can be analyzed statically. Such code needs changes before it can compile and run. See " { $link "inference-combinators" } " and " { $link "inference-escape" } " for details." }
 { $examples
-    "In this example, words calling " { $snippet "literal-expected-example" } " will compile, even if " { $snippet "literal-expected-example" } " does not compile itself:"
+    "In this example, words calling " { $snippet "literal-expected-example" } " will have a static stac keffect, even if " { $snippet "literal-expected-example" } " does not:"
     { $code
         ": literal-expected-example ( quot -- )"
         "    [ call ] [ call ] bi ; inline"
@@ -16,10 +15,8 @@ HELP: literal-expected
 HELP: unbalanced-branches-error
 { $values { "in" "a sequence of integers" } { "out" "a sequence of integers" } }
 { $description "Throws an " { $link unbalanced-branches-error } "." }
-{ $error-description "Thrown when inference encounters an " { $link if } " or " { $link dispatch } " where the branches do not all exit with the same stack height." }
-{ $notes "Conditionals with variable stack effects are considered to be bad style and should be avoided since they do not compile."
-$nl
-"If this error comes up when inferring the stack effect of a recursive word, check the word's stack effect declaration; it might be wrong." }
+{ $error-description "Thrown when inference encounters an " { $link if } " or " { $link dispatch } " where the branches do not all exit with the same stack height. See " { $link "inference-branches" } " for details." }
+{ $notes "If this error comes up when inferring the stack effect of a recursive word, check the word's stack effect declaration; it might be wrong." }
 { $examples
     { $code
         ": unbalanced-branches-example ( a b c -- )"
@@ -86,25 +83,26 @@ HELP: inconsistent-recursive-call-error
     }
 } ;
 
-ARTICLE: "inference-errors" "Inference warnings and errors"
+ARTICLE: "inference-errors" "Stack checker errors"
 "These conditions are thrown by " { $link "inference" } ", as well as the " { $link "compiler" } "."
 $nl
-"Main wrapper for all inference warnings and errors:"
-{ $subsection inference-error }
-"Inference warnings:"
+"Error thrown when insufficient information is available to calculate the stack effect of a combinator call (see " { $link "inference-combinators" } "):"
 { $subsection literal-expected }
-"Inference errors:"
-{ $subsection recursive-quotation-error }
-{ $subsection unbalanced-branches-error }
+"Error thrown when a word's stack effect declaration does not match the composition of the stack effects of its factors:"
 { $subsection effect-error }
-{ $subsection missing-effect }
-"Inference errors for inline recursive words:"
+"Error thrown when branches have incompatible stack effects (see " { $link "inference-branches" } "):"
+{ $subsection unbalanced-branches-error }
+"Inference errors for inline recursive words (see " { $link "inference-recursive-combinators" } "):"
 { $subsection undeclared-recursion-error }
 { $subsection diverging-recursion-error }
 { $subsection unbalanced-recursion-error }
 { $subsection inconsistent-recursive-call-error }
-"Retain stack usage errors:"
+"More obscure errors that are unlikely to arise in ordinary code:"
+{ $subsection recursive-quotation-error }
 { $subsection too-many->r }
-{ $subsection too-many-r> } ;
+{ $subsection too-many-r> }
+{ $subsection missing-effect }
+"Main wrapper for all inference warnings and errors:"
+{ $subsection inference-error } ;
 
 ABOUT: "inference-errors"
index 78196abfba607f4737cb3e686ba2eefccc2a8289..243221ccf0c943fc60eafa9b55185a52217beb39 100644 (file)
@@ -4,38 +4,54 @@ stack-checker.backend
 stack-checker.branches
 stack-checker.errors
 stack-checker.transforms
-stack-checker.state ;
+stack-checker.state
+continuations ;
 IN: stack-checker
 
 ARTICLE: "inference-simple" "Straight-line stack effects"
-"The simplest case to look at is that of a quotation which does not have any branches or recursion, and just pushes literals and calls words, each of which has a known stack effect."
+"The simplest case is when a piece of code does not have any branches or recursion, and just pushes literals and calls words."
 $nl
-"Stack effect inference works by stepping through the quotation, while maintaining a \"shadow stack\" which tracks stack height at the current position in the quotation. Initially, the shadow stack is empty. If a word is encountered which expects more values than there are on the shadow stack, a global counter is incremented. This counter keeps track of the number of inputs the quotation expects on the stack. When inference is done, this counter, together with the final height of the shadow stack, gives the inferred stack effect."
-{ $subsection d-in }
-{ $subsection meta-d }
-"When a literal is encountered, it is simply pushed on the shadow stack. For example, the stack effect of the following quotation is inferred by pushing all three literals on the shadow stack, then taking the value of " { $link d-in } " and the length of " { $link meta-d } ":"
+"Pushing a literal has stack effect " { $snippet "( -- object )" } ". The stack effect of a most words is always known statically from the declaration. Stack effects of " { $link POSTPONE: inline } " words and " { $link "macros" } ", may depend on literals pushed on the stack prior to the call, and this case is discussed in " { $link "inference-combinators" } "."
+$nl
+"The stack effect of each element in a code snippet is composed. The result is then the stack effect of the snippet."
+$nl
+"An example:"
 { $example "[ 1 2 3 ] infer." "( -- object object object )" }
-"In the following example, the call to " { $link + } " expects two values on the shadow stack, but only one value is present, the literal which was pushed previously. This increments the " { $link d-in } " counter by one:"
-{ $example "[ 2 + ] infer." "( object -- object )" }
-"After the call to " { $link + } ", the shadow stack contains a \"computed value placeholder\", since the inferencer has no way to know what the resulting value actually is (in fact it is arbitrary)." ;
+"Another example:"
+{ $example "[ 2 + ] infer." "( object -- object )" } ;
 
 ARTICLE: "inference-combinators" "Combinator stack effects"
-"Without further information, one cannot say what the stack effect of " { $link call } " is; it depends on the given quotation. If the inferencer encounters a " { $link call } " without further information, a " { $link literal-expected } " error is raised."
-{ $example "[ dup call ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help." }
-"On the other hand, the stack effect of applying " { $link call } " to a literal quotation or a " { $link curry } " of a literal quotation is easy to compute; it behaves as if the quotation was substituted at that point:"
-{ $example "[ [ 2 + ] call ] infer." "( object -- object )" }
-"Consider a combinator such as " { $link keep } ". The combinator itself does not have a stack effect, because it applies " { $link call } " to a potentially arbitrary quotation. However, since the combinator is declared " { $link POSTPONE: inline } ", a given usage of it can have a stack effect:"
-{ $example "[ [ 2 + ] keep ] infer." "( object -- object object )" }
-"Another example is the " { $link compose } " combinator. Because it is decared " { $link POSTPONE: inline } ", we can infer the stack effect of applying " { $link call } " to the result of " { $link compose } ":"
-{ $example "[ 2 [ + ] curry [ sq ] compose ] infer." "( -- object )" }
-"Incidentally, this example demonstrates that the stack effect of nested currying and composition can also be inferred."
-$nl
-"A general rule of thumb is that any word which applies " { $link call } " or " { $link curry } " to one of its inputs must be declared " { $link POSTPONE: inline } "."
+"If a word, call it " { $snippet "W" } ", calls a combinator, one of the following two conditions must hold:"
+{ $list
+  { "The combinator may be called with a quotation that is either a literal, or built from literals, " { $link curry } " and " { $link compose } "." }
+  { "The combinator must be called on an input parameter, or be built from input parameters, literals, " { $link curry } " and " { $link compose } ", " { $strong "if" } " the word " { $snippet "W" } " must be declared " { $link POSTPONE: inline } ". Then " { $snippet "W" } " is itself considered to be a combinator, and its callers must satisfy one of these two conditions." }
+}
+"If neither condition holds, the stack checker throws a " { $link literal-expected } " error, and an escape hatch such as " { $link POSTPONE: call( } " must be used instead. See " { $link "inference-escape" } " for details. An inline combinator can be called with an unknown quotation by currying the quotation onto a literal quotation that uses " { $link POSTPONE: call( } "."
+{ $heading "Examples" }
+{ $subheading "Calling a combinator" }
+"The following usage of " { $link map } " passes the stack checker, because the quotation is the result of " { $link curry } ":"
+{ $example "[ [ + ] curry map ] infer." "( object object -- object )" }
+{ $subheading "Defining an inline combinator" }
+"The following word calls a quotation twice; the word is declared " { $link POSTPONE: inline } ", since it invokes " { $link call } " on the result of " { $link compose } " on an input parameter:"
+{ $code ": twice ( value quot -- result ) dup compose call ; inline" }
+"The following code now passes the stack checker; it would fail were " { $snippet "twice" } " not declared " { $link POSTPONE: inline } ":"
+{ $unchecked-example "USE: math.functions" "[ [ sqrt ] twice ] infer." "( object -- object )" }
+{ $subheading "Defining a combinator for unknown quotations" }
+"In the next example, " { $link POSTPONE: call( } " must be used because the quotation the result of calling a runtime accessor, and the compiler cannot make any static assumptions about this quotation at all:"
+{ $code
+  "TUPLE: action name quot ;"
+  ": perform ( value action -- result ) quot>> call( value -- result ) ;"
+}
+{ $subheading "Passing an unknown quotation to an inline combinator" }
+"Suppose we want to write :"
+{ $code ": perform ( values action -- results ) quot>> map ;" }
+"However this fails to pass the stack checker since there is no guarantee the quotation has the right stack effect for " { $link map } ". It can be wrapped in a new quotation with a declaration:"
+{ $code ": perform ( values action -- results )" "    quot>> [ call( value -- result ) ] curry map ;" }
+{ $heading "Explanation" }
+"This restriction exists because without further information, one cannot say what the stack effect of " { $link call } " is; it depends on the given quotation. If the stack checker encounters a " { $link call } " without further information, a " { $link literal-expected } " error is raised."
 $nl
-"Here is an example where the stack effect cannot be inferred:"
-{ $code ": foo ( -- n quot ) 0 [ + ] ;" "[ foo reduce ] infer." }
-"However if " { $snippet "foo" } " was declared " { $link POSTPONE: inline } ", everything would work, since the " { $link reduce } " combinator is also " { $link POSTPONE: inline } ", and the inferencer can see the literal quotation value at the point it is passed to " { $link call } ":"
-{ $example ": foo ( -- n quot ) 0 [ + ] ; inline" "[ foo reduce ] infer." "( object -- object )" }
+"On the other hand, the stack effect of applying " { $link call } " to a literal quotation or a " { $link curry } " of a literal quotation is easy to compute; it behaves as if the quotation was substituted at that point."
+{ $heading "Limitations" }
 "Passing a literal quotation on the data stack through an inlined recursive combinator nullifies its literal status. For example, the following will not infer:"
 { $example
   "[ [ reverse ] swap [ reverse ] map swap call ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help."
@@ -46,30 +62,25 @@ $nl
 } ;
 
 ARTICLE: "inference-branches" "Branch stack effects"
-"Conditionals such as " { $link if } " and combinators built on " { $link if } " present a problem, in that if the two branches leave the stack at a different height, it is not clear what the stack effect should be. In this case, inference throws a " { $link unbalanced-branches-error } "."
+"Conditionals such as " { $link if } " and combinators built on top have the same restrictions as " { $link POSTPONE: inline } " combinators (see " { $link "inference-combinators" } ") with the additional requirement that all branches leave the stack at the same height. If this is not the case, the stack checker throws a " { $link unbalanced-branches-error } "."
 $nl
 "If all branches leave the stack at the same height, then the stack effect of the conditional is just the maximum of the stack effect of each branch. For example,"
 { $example "[ [ + ] [ drop ] if ] infer." "( object object object -- object )" }
 "The call to " { $link if } " takes one value from the stack, a generalized boolean. The first branch " { $snippet "[ + ]" } " has stack effect " { $snippet "( x x -- x )" } " and the second has stack effect " { $snippet "( x -- )" } ". Since both branches decrease the height of the stack by one, we say that the stack effect of the two branches is " { $snippet "( x x -- x )" } ", and together with the boolean popped off the stack by " { $link if } ", this gives a total stack effect of " { $snippet "( x x x -- x )" } "." ;
 
-ARTICLE: "inference-recursive" "Stack effects of recursive words"
-"When a recursive call is encountered, the declared stack effect is substituted in. When inference is complete, the inferred stack effect is compared with the declared stack effect."
-$nl
-"Attempting to infer the stack effect of a recursive word which outputs a variable number of objects on the stack will fail. For example, the following will throw an " { $link unbalanced-branches-error } ":"
-{ $code ": foo ( seq -- ) dup empty? [ drop ] [ dup pop foo ] if ;" "[ foo ] infer." }
-"If you declare an incorrect stack effect, inference will fail also. Badly defined recursive words cannot confuse the inferencer." ;
-
-ARTICLE: "inference-recursive-combinators" "Recursive combinator inference"
-"Most combinators are not explicitly recursive; instead, they are implemented in terms of existing combinators, for example " { $link while } ", " { $link map } ", and the " { $link "compositional-combinators" } "."
-$nl
-"Combinators which are recursive require additional care."
-$nl
-"If a recursive word takes quotation parameters from the stack and calls them, it must be declared " { $link POSTPONE: inline } " (as documented in " { $link "inference-combinators" } ") as well as " { $link POSTPONE: recursive } "."
+ARTICLE: "inference-recursive-combinators" "Recursive combinator stack effects"
+"Most combinators do not call themselves recursively directly; instead, they are implemented in terms of existing combinators, for example " { $link while } ", " { $link map } ", and the " { $link "compositional-combinators" } ". In these cases, the rules outlined in " { $link "inference-combinators" } " apply."
 $nl
-"Furthermore, the input parameters which are quotations must be annotated in the stack effect. For example, the following will not infer:"
+"Combinators which are recursive require additional care. In addition to being declared " { $link POSTPONE: inline } ", they must be declared " { $link POSTPONE: recursive } ". There are three restrictions that only apply to combinators with this declaration:"
+{ $heading "Input quotation declaration" }
+"Input parameters which are quotations must be annotated as much in the stack effect. For example, the following will not infer:"
 { $example ": bad ( quot -- ) [ call ] keep foo ; inline recursive" "[ [ ] bad ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help." }
 "The following is correct:"
 { $example ": good ( quot: ( -- ) -- ) [ call ] keep good ; inline recursive" "[ [ ] good ] infer." "( -- )" }
+"The effect of the nested quotation itself is only present for documentation purposes; the mere presence of a nested effect is sufficient to mark that value as a quotation parameter."
+{ $heading "Data flow restrictions" }
+"The stack checker does not trace data flow in two instances."
+$nl
 "An inline recursive word cannot pass a quotation on the data stack through the recursive call. For example, the following will not infer:"
 { $example ": bad ( ? quot: ( ? -- ) -- ) 2dup [ not ] dip bad call ; inline recursive" "[ [ drop ] bad ] infer." "Got a computed value where a literal quotation was expected\n\nType :help for debugging help." }
 "However a small change can be made:"
@@ -80,23 +91,47 @@ $nl
     "[ [ 5 ] t foo ] infer."
 } ;
 
-ARTICLE: "inference" "Stack effect inference"
-"The stack effect inference tool is used to check correctness of code before it is run. It is also used by the optimizing compiler to build the high-level SSA representation on which optimizations can be performed. Only words for which a stack effect can be inferred will compile with the optimizing compiler; all other words will be compiled with the non-optimizing compiler (see " { $link "compiler" } ")."
-$nl
-"The main entry point is a single word which takes a quotation and prints its stack effect and variable usage:"
-{ $subsection infer. }
-"Instead of printing the inferred information, it can be returned as objects on the stack:"
+ARTICLE: "tools.inference" "Stack effect tools"
+{ $link "inference" } " can be used interactively to print stack effects of quotations without running them. It can also be used from " { $link "combinators.smart" } "."
 { $subsection infer }
-"Static stack effect inference can be combined with unit tests; see " { $link "tools.test.write" } "."
+{ $subsection infer. }
+"There are also some words for working with " { $link effect } " instances. Getting a word's declared stack effect:"
+{ $subsection stack-effect }
+"Converting a stack effect to a string form:"
+{ $subsection effect>string }
+"Comparing effects:"
+{ $subsection effect-height }
+{ $subsection effect<= }
+"The class of stack effects:"
+{ $subsection effect }
+{ $subsection effect? } ;
+
+ARTICLE: "inference-escape" "Stack effect checking escape hatches"
+"In a static checking regime, sometimes it is necessary to step outside the boundaries and run some code which cannot be statically checked; perhaps this code is constructed at run-time. There are two ways to get around the static stack checker."
+$nl
+"If the stack effect of a word or quotation is known, but the word or quotation itself is not, " { $link POSTPONE: execute( } " or " { $link POSTPONE: call( } " can be used. See " { $link "call" } " for details."
+$nl
+"If the stack effect is not known, the code being called cannot manipulate the datastack directly. Instead, it must reflect the datastack into an array:"
+{ $subsection with-datastack }
+"The surrounding code has a static stack effect since " { $link with-datastack } " has one. However, the array passed in as input may be transformed arbitrarily by calling this combinator." ;
+
+ARTICLE: "inference" "Stack effect checking"
+"The " { $link "compiler" } " checks the " { $link "effects" } " of words before they can be run. This ensures that words take exactly the number of inputs and outputs that the programmer declares in source."
+$nl
+"Words that do not pass the stack checker are rejected and cannot be run, and so essentially this defines a very simple and permissive type system that nevertheless catches some invalid programs and enables compiler optimizations."
+$nl
+"If a word's stack effect cannot be inferred, a compile error is reported. See " { $link "compiler-errors" } "."
 $nl
-"The following articles describe the implementation of the stack effect inference algorithm:"
+"The following articles describe how different control structures are handled by the stack checker."
 { $subsection "inference-simple" }
-{ $subsection "inference-recursive" } 
 { $subsection "inference-combinators" }
 { $subsection "inference-recursive-combinators" }
 { $subsection "inference-branches" }
+"Stack checking catches several classes of errors."
 { $subsection "inference-errors" }
-{ $see-also "effects" } ;
+"Sometimes code with a dynamic stack effect has to be run."
+{ $subsection "inference-escape" }
+{ $see-also "effects" "tools.inference" "tools.errors" } ;
 
 ABOUT: "inference"
 
index a1d7e50594ae5fae4b7f4b7f77dc8f8332f3b838..dbdb69b3e9d45549cd8481dd0832357c4118771e 100644 (file)
@@ -48,7 +48,7 @@ ARTICLE: "thread-impl" "Thread implementation"
 { $subsection sleep-queue } ;
 
 ARTICLE: "threads" "Lightweight co-operative threads"
-"Factor supports lightweight co-operative threads implemented on top of continuations. A thread will yield while waiting for input/output operations to complete, or when a yield has been explicitly requested."
+"Factor supports lightweight co-operative threads implemented on top of " { $link "continuations" } ". A thread will yield while waiting for input/output operations to complete, or when a yield has been explicitly requested."
 $nl
 "Factor threads are very lightweight. Each thread can take as little as 900 bytes of memory. This library has been tested running hundreds of thousands of simple threads."
 $nl
index 96b13b69b6871df37fadbdee738e3fe4a73639ea..5bbb6c472116cb6677c269109430874f8eda86b8 100644 (file)
@@ -6,15 +6,15 @@ ARTICLE: "compiler-errors" "Compiler warnings and errors"
 "After loading a vocabulary, you might see messages like:"
 { $code
     ":errors - print 2 compiler errors"
-    ":warnings - print 50 compiler warnings"
+    ":warnings - print 1 compiler warnings"
 }
-"These messages arise from the compiler's stack effect checker. Production code should not have any warnings and errors in it. Warning and error conditions are documented in " { $link "inference-errors" } "."
+"This indicates that some words did not pass the stack checker. Stack checker error conditions are documented in " { $link "inference-errors" } ", and the stack checker itself in " { $link "inference" } "."
 $nl
 "Words to view warnings and errors:"
 { $subsection :warnings }
 { $subsection :errors }
 { $subsection :linkage }
-"Compiler warnings and errors are reported using the " { $link "tools.errors" } " mechanism and are shown in the " { $link "ui.tools.error-list" } "." ;
+"Compiler warnings and errors are reported using the " { $link "tools.errors" } " mechanism, and as a result, they are also are shown in the " { $link "ui.tools.error-list" } "." ;
 
 HELP: compiler-error
 { $values { "error" "an error" } { "word" word } }
index dd55d5fabe1600652eba74aa848410f06a984438..e02103697d15a82f789bd4d2265e2d2d98d64548 100644 (file)
@@ -269,28 +269,28 @@ ARTICLE: "combinators-quot" "Quotation construction utilities"
 { $subsection case>quot }
 { $subsection alist>quot } ;
 
+ARTICLE: "call-unsafe" "Unsafe combinators"
+"Unsafe calls declare an effect statically without any runtime checking:"
+{ $subsection call-effect-unsafe }
+{ $subsection execute-effect-unsafe } ;
+
 ARTICLE: "call" "Fundamental combinators"
-"The most basic combinators are those that take either a quotation or word, and invoke it immediately. There are two sets of combinators; they differe in whether or not the stack effect of the expected code is declared."
+"The most basic combinators are those that take either a quotation or word, and invoke it immediately."
+$nl
+"There are two sets of combinators; they differ in whether or not the stack effect of the expected code is declared."
 $nl
-"The simplest combinators do not take an effect declaration:"
+"The simplest combinators do not take an effect declaration. The compiler checks the stack effect at compile time, rejecting the program if this cannot be done:"
 { $subsection call }
 { $subsection execute }
-"These combinators only get optimized by the compiler if the quotation or word parameter is a literal; otherwise a compiler warning will result. Definitions of combinators which require literal parameters must be followed by the " { $link POSTPONE: inline } " declaration. For example:"
-{ $code
-    ": keep ( x quot -- x )"
-    "    over [ call ] dip ; inline"
-}
-"See " { $link "declarations" } " and " { $link "compiler-errors" } " for details."
-$nl
-"The other set of combinators allow arbitrary quotations and words to be called from optimized code. This is done by specifying the stack effect of the quotation literally. It is checked at runtime that the stack effect is accurate."
-{ $subsection call-effect }
-{ $subsection execute-effect }
-"A simple layer of syntax sugar is defined on top:"
+"The second set of combinators takes an effect declaration. The stack effect of the quotation or word is checked at runtime:"
 { $subsection POSTPONE: call( }
 { $subsection POSTPONE: execute( }
-"Unsafe calls declare an effect statically without any runtime checking:"
-{ $subsection call-effect-unsafe }
-{ $subsection execute-effect-unsafe }
+"The above are syntax sugar. The underlying words are a bit more verbose but allow non-constant effects to be passed in:"
+{ $subsection call-effect }
+{ $subsection execute-effect }
+{ $subsection "call-unsafe" }
+"The combinator variants that do not take an effect declaration can only be used if the compiler is able to infer the stack effect by other means. See " { $link "inference-combinators" } "."
+{ $subsection "call-unsafe" }
 { $see-also "effects" "inference" } ;
 
 ARTICLE: "combinators" "Combinators"
index 651169554eacabea03ece6839a3b596e4e761c0e..2c91981f1362c2ad554ce296d404458debfd8cc2 100644 (file)
@@ -81,8 +81,6 @@ $nl
 { $subsection attempt-all }
 { $subsection retry }
 { $subsection with-return }
-"Reflecting the datastack:"
-{ $subsection with-datastack }
 "Continuations serve as the building block for a number of higher-level abstractions, such as " { $link "errors" } " and " { $link "threads" } "."
 { $subsection "continuations.private" } ;
 
@@ -211,7 +209,7 @@ $low-level-note ;
 
 HELP: with-datastack
 { $values { "stack" sequence } { "quot" quotation } { "newstack" sequence } }
-{ $description "Executes the quotation with the given data stack contents, and outputs the new data stack after the word returns. The input sequence is not modified. Does not affect the data stack in surrounding code, other than consuming the two inputs and pushing the output." }
+{ $description "Executes the quotation with the given data stack contents, and outputs the new data stack after the word returns. The input sequence is not modified; a new sequence is produced. Does not affect the data stack in surrounding code, other than consuming the two inputs and pushing the output." }
 { $examples
     { $example "USING: continuations math prettyprint ;" "{ 3 7 } [ + ] with-datastack ." "{ 10 }" }
 } ;
index 20709ca8075fa5cc1b711fe9e201423d8757e594..495aeb39c141d1a601e3b7b36f97f63a5eda27a5 100644 (file)
@@ -1,16 +1,20 @@
 USING: help.markup help.syntax math strings words kernel combinators ;
 IN: effects
 
-ARTICLE: "effect-declaration" "Stack effect declaration"
-"Stack effects of words must be declared, with the exception of words which only push literals on the stack."
-$nl
-"A stack effect declaration is written in parentheses and lists word inputs and outputs, separated by " { $snippet "--" } ". Here is an example:"
-{ $synopsis sq }
+ARTICLE: "effects" "Stack effect declarations"
+"Word definition words such as " { $link POSTPONE: : } " and " { $link POSTPONE: GENERIC: } " have a " { $emphasis "stack effect declaration" } " as part of their syntax. A stack effect declaration takes the following form:"
+{ $code "( input1 input2 ... -- output1 ... )" }
+"Stack elements in a stack effect are ordered so that the top of the stack is on the right side. Here is an example:"
+{ $synopsis + }
 "Parameters which are quotations can be declared by suffixing the parameter name with " { $snippet ":" } " and then writing a nested stack effect declaration:"
 { $synopsis while }
-"Stack effect declarations are read in using a parsing word:"
-{ $subsection POSTPONE: ( }
-"Stack elements in a stack effect are ordered so that the top of the stack is on the right side. Each value can be named by a data type or description. The following are some examples of value names:"
+"Only the number of inputs and outputs carries semantic meaning."
+$nl
+"Nested quotation declaration only has semantic meaning for " { $link POSTPONE: inline } " " { $link POSTPONE: recursive } " words. See " { $link "inference-recursive-combinators" } "."
+$nl
+"In concatenative code, input and output names are for documentation purposes only and certain conventions have been established to make them more descriptive. For code written with " { $link "locals" } ", stack values are bound to local variables named by the stack effect's input parameters."
+$nl
+"Inputs and outputs are typically named after some pun on their data type, or a description of the value's purpose if the type is very general. The following are some examples of value names:"
 { $table
     { { { $snippet "?" } } "a boolean" }
     { { { $snippet "<=>" } } { "an ordering sepcifier; see " { $link "order-specifiers" } } }
@@ -26,25 +30,7 @@ $nl
     { { $snippet "dim" } "a screen dimension specified as a two-element array holding width and height values" }
     { { $snippet "*" } "when this symbol appears by itself in the list of outputs, it means the word unconditionally throws an error" }
 }
-"The stack effect inferencer verifies stack effect comments to ensure the correct number of inputs and outputs is listed. Value names are ignored; only their number matters. An error is thrown if a word's declared stack effect does not match its inferred stack effect. See " { $link "inference" } "." ;
-
-ARTICLE: "effects" "Stack effects"
-"A " { $emphasis "stack effect declaration" } ", for example " { $snippet "( x y -- z )" } " denotes that an operation takes two inputs, with " { $snippet "y" } " at the top of the stack, and returns one output. Stack effects are first-class, and words for working with them are found in the " { $vocab-link "effects" } " vocabulary."
-$nl
-"Stack effects of words must be declared, and the " { $link "compiler" } " checks that these declarations are correct. Invalid declarations are reported as " { $link "compiler-errors" } ". The " { $link "inference" } " tool can be used to check stack effects interactively."
-{ $subsection "effect-declaration" }
-"There is a literal syntax for stack objects. It is most often used with " { $link define-declared } ", " { $link call-effect } " and " { $link execute-effect } "."
-{ $subsection POSTPONE: (( }
-"Getting a word's declared stack effect:"
-{ $subsection stack-effect }
-"Converting a stack effect to a string form:"
-{ $subsection effect>string }
-"Comparing effects:"
-{ $subsection effect-height }
-{ $subsection effect<= }
-"The class of stack effects:"
-{ $subsection effect }
-{ $subsection effect? } ;
+{ $see-also "inference" } ;
 
 ABOUT: "effects"
 
index 7017ef8a087928d93bb777d7cb38170050696a63..e8b5e6d69c746443c7549c5bebb15b90981809c2 100644 (file)
@@ -95,7 +95,7 @@ $nl
 { $subsection POSTPONE: MATH: }
 "Method definition:"
 { $subsection POSTPONE: M: }
-"Generic words must declare their stack effect in order to compile. See " { $link "effect-declaration" } "."
+"Generic words must declare their stack effect in order to compile. See " { $link "effects" } "."
 { $subsection "method-order" }
 { $subsection "call-next-method" }
 { $subsection "method-combination" }
index cf0aea787bcc98c0cfabef70b788c8c967e64129..9989d889a80bb24bdc84469a1db824af5bad2995 100644 (file)
@@ -2,7 +2,20 @@ USING: help.markup help.syntax io strings arrays io.backend
 io.files.private quotations sequences ;
 IN: io.files
 
+ARTICLE: "io.files.examples" "Examples of reading and writing files"
+"Sort the lines in a file and write them back to the same file:"
+{ $code
+    "USING: io io.encodings.utf8 io.files sequences sorting ;"
+    "\"lines.txt\" utf8 [ file-lines natural-sort ] 2keep set-file-lines"
+}
+"Read 1024 bytes from a file:"
+{ $code
+    "USING: io io.encodings.binary io.files ;"
+    "\"data.bin\" binary [ 1024 read ] with-file-reader"
+} ;
+
 ARTICLE: "io.files" "Reading and writing files"
+{ $subsection "io.files.examples" }
 "File streams:"
 { $subsection <file-reader> }
 { $subsection <file-writer> }
index ebc248bbbf8adf9995cc8cfdff9180252dc0feb4..740152f2941420a14046046f1ef8dc0fd527031f 100644 (file)
@@ -355,9 +355,27 @@ $nl
 "Copying the contents of one stream to another:"
 { $subsection stream-copy } ;
 
+ARTICLE: "stream-examples" "Stream example"
+"Ask the user for their age, and print it back:"
+{ $code
+    "USING: io math.parser ;"
+    ""
+    ": ask-age ( -- ) \"How old are you?\" print ;"
+    ""
+    ": read-age ( -- n ) readln string>number ;"
+    ""
+    ": print-age ( n -- )"
+    "    \"You are \" write"
+    "    number>string write"
+    "    \" years old.\" print ;"
+    ": example ( -- ) ask-age read-age print-age ;"
+    ""
+    "example"
+} ;
+
 ARTICLE: "streams" "Streams"
 "Input and output centers on the concept of a " { $emphasis "stream" } ", which is a source or sink of " { $emphasis "elements" } "."
-$nl
+{ $subsection "stream-examples" }
 "A stream can either be passed around on the stack or bound to a dynamic variable and used as one of the two implicit " { $emphasis "default streams" } "."
 { $subsection "stream-protocol" }
 { $subsection "stdio" }
index a0e1d280d5e6ef665099079533f8688d36b2e7bb..7ab287fd20cdddd1bbb0f1c5400982f8bfcff7e4 100644 (file)
@@ -1,7 +1,7 @@
 USING: generic help.syntax help.markup kernel math parser words
 effects classes generic.standard classes.tuple generic.math
 generic.standard arrays io.pathnames vocabs.loader io sequences
-assocs words.symbol words.alias words.constant ;
+assocs words.symbol words.alias words.constant combinators ;
 IN: syntax
 
 ARTICLE: "parser-algorithm" "Parser algorithm"
@@ -152,6 +152,11 @@ ARTICLE: "syntax-pathnames" "Pathname syntax"
 { $subsection POSTPONE: P" }
 "Pathnames are documented in " { $link "io.pathnames" } "." ;
 
+ARTICLE: "syntax-effects" "Stack effect syntax"
+"Note that this is " { $emphasis "not" } " syntax to declare stack effects of words. This pushes an " { $link effect } " instance on the stack for reflection, for use with words such as " { $link define-declared } ", " { $link call-effect } " and " { $link execute-effect } "."
+{ $subsection POSTPONE: (( }
+{ $see-also "effects" "inference" "tools.inference" } ;
+
 ARTICLE: "syntax-literals" "Literals"
 "Many different types of objects can be constructed at parse time via literal syntax. Numbers are a special case since support for reading them is built-in to the parser. All other literals are constructed via parsing words."
 $nl
@@ -168,7 +173,8 @@ $nl
 { $subsection "syntax-sbufs" }
 { $subsection "syntax-hashtables" }
 { $subsection "syntax-tuples" }
-{ $subsection "syntax-pathnames" } ;
+{ $subsection "syntax-pathnames" }
+{ $subsection "syntax-effects" } ;
 
 ARTICLE: "syntax" "Syntax"
 "Factor has two main forms of syntax: " { $emphasis "definition" } " syntax and " { $emphasis "literal" } " syntax. Code is data, so the syntax for code is a special case of object literal syntax. This section documents literal syntax. Definition syntax is covered in " { $link "words" } ". Extending the parser is the main topic of " { $link "parser" } "."
@@ -517,7 +523,7 @@ HELP: (
 { $syntax "( inputs -- outputs )" }
 { $values { "inputs" "a list of tokens" } { "outputs" "a list of tokens" } }
 { $description "A stack effect declaration. This is treated as a comment unless it appears inside a word definition." }
-{ $see-also "effect-declaration" } ;
+{ $see-also "effects" } ;
 
 HELP: ((
 { $syntax "(( inputs -- outputs ))" }
index 9cc1f5b2b9aeecfcb1a6f76cc8588d4b153bd41c..94609a06e5956f55fd5a4f918ebbe7b577cb83d2 100644 (file)
@@ -21,8 +21,8 @@ $nl
 { $subsection gensym }
 { $subsection define-temp } ;
 
-ARTICLE: "colon-definition" "Word definitions"
-"Every word has an associated quotation definition that is called when the word is executed."
+ARTICLE: "colon-definition" "Colon definitions"
+"Every word has an associated quotation definition that is called when the word is executed. A " { $emphasis "colon definition" } " is a word where this quotation is supplied directly by the user. This is the simplest and most common type of word definition."
 $nl
 "Defining words at parse time:"
 { $subsection POSTPONE: : }
@@ -31,7 +31,7 @@ $nl
 { $subsection define }
 { $subsection define-declared }
 { $subsection define-inline }
-"Word definitions must declare their stack effect. See " { $link "effect-declaration" } "."
+"Word definitions must declare their stack effect. See " { $link "effects" } "."
 $nl
 "All other types of word definitions, such as " { $link "words.symbol" } " and " { $link "generic" } ", are just special cases of the above." ;
 
@@ -56,30 +56,16 @@ $nl
     ": foo undefined ;"
 } ;
 
-ARTICLE: "declarations" "Declarations"
-"Declarations are parsing words that set a word property in the most recently defined word. Declarations only affect definitions compiled with the optimizing compiler. They do not change evaluation semantics of a word, but instead declare that the word follows a certain contract, and thus may be compiled differently."
+ARTICLE: "declarations" "Compiler declarations"
+"Compiler declarations are parsing words that set a word property in the most recently defined word. They appear after the final " { $link POSTPONE: ; } " of a word definition:"
+{ $code ": cubed ( x -- y ) dup dup * * ; foldable" }
+"Compiler declarations assert that the word follows a certain contract, enabling certain optimizations that are not valid in general."
 { $subsection POSTPONE: inline }
 { $subsection POSTPONE: foldable }
 { $subsection POSTPONE: flushable }
 { $subsection POSTPONE: recursive }
-{ $warning "If a generic word is declared " { $link POSTPONE: foldable } " or " { $link POSTPONE: flushable } ", all methods must satisfy the contract, otherwise unpredicable behavior will occur." }
-"Stack effect declarations are documented in " { $link "effect-declaration" } "." ;
-
-ARTICLE: "word-definition" "Defining words"
-"There are two approaches to creating word definitions:"
-{ $list
-    "using parsing words at parse time,"
-    "using defining words at run time."
-}
-"The latter is a more dynamic feature that can be used to implement code generation and such, and in fact parse time defining words are implemented in terms of run time defining words."
-{ $subsection "colon-definition" }
-{ $subsection "words.symbol" }
-{ $subsection "words.alias" }
-{ $subsection "words.constant" }
-{ $subsection "primitives" }
-{ $subsection "deferred" }
-{ $subsection "declarations" }
-"Words implement the definition protocol; see " { $link "definitions" } "." ;
+"It is entirely up to the programmer to ensure that the word satisfies the contract of a declaration. Furthermore, if a generic word is declared " { $link POSTPONE: foldable } " or " { $link POSTPONE: flushable } ", all methods must satisfy the contract. Unspecified behavior may result if a word does not follow the contract of one of its declarations."
+{ $see-also "effects" } ;
 
 ARTICLE: "word-props" "Word properties"
 "Each word has a hashtable of properties."
@@ -100,7 +86,7 @@ $nl
     
     { { { $snippet "\"reading\"" } ", " { $snippet "\"writing\"" } } { "Set on slot accessor words - " { $link "slots" } } }
 
-    { { $snippet "\"declared-effect\"" } { $link "effect-declaration" } }
+    { { $snippet "\"declared-effect\"" } { $link "effects" } }
     
     { { { $snippet "\"help\"" } ", " { $snippet "\"help-loc\"" } ", " { $snippet "\"help-parent\"" } } { "Where word help is stored - " { $link "writing-help" } } }
 
@@ -134,9 +120,7 @@ $nl
 "An " { $emphasis "XT" } " (execution token) is the machine code address of a word:"
 { $subsection word-xt } ;
 
-ARTICLE: "words" "Words"
-"Words are the Factor equivalent of functions or procedures; a word is essentially a named quotation."
-$nl
+ARTICLE: "words.introspection" "Word introspection"
 "Word introspection facilities and implementation details are found in the " { $vocab-link "words" } " vocabulary."
 $nl
 "Word objects contain several slots:"
@@ -149,11 +133,32 @@ $nl
 "Words are instances of a class."
 { $subsection word }
 { $subsection word? }
+"Words implement the definition protocol; see " { $link "definitions" } "."
 { $subsection "interned-words" }
 { $subsection "uninterned-words" }
-{ $subsection "word-definition" }
 { $subsection "word-props" }
-{ $subsection "word.private" }
+{ $subsection "word.private" } ;
+
+ARTICLE: "words" "Words"
+"Words are the Factor equivalent of functions or procedures; a word is essentially a named quotation."
+$nl
+"There are two ways of creating word definitions:"
+{ $list
+    "using parsing words at parse time,"
+    "using defining words at run time."
+}
+"The latter is a more dynamic feature that can be used to implement code generation and such, and in fact parse time defining words are implemented in terms of run time defining words."
+$nl
+"Types of words:"
+{ $subsection "colon-definition" }
+{ $subsection "words.symbol" }
+{ $subsection "words.alias" }
+{ $subsection "words.constant" }
+{ $subsection "primitives" }
+"Advanced topics:"
+{ $subsection "deferred" }
+{ $subsection "declarations" }
+{ $subsection "words.introspection" }
 { $see-also "vocabularies" "vocabs.loader" "definitions" "see" } ;
 
 ABOUT: "words"