]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorJoe Groff <arcata@gmail.com>
Wed, 1 Oct 2008 01:22:41 +0000 (18:22 -0700)
committerJoe Groff <arcata@gmail.com>
Wed, 1 Oct 2008 01:22:41 +0000 (18:22 -0700)
567 files changed:
basis/alarms/summary.txt [new file with mode: 0644]
basis/alias/summary.txt [new file with mode: 0644]
basis/ascii/ascii-docs.factor
basis/binary-search/summary.txt [new file with mode: 0644]
basis/bootstrap/image/image.factor
basis/bootstrap/random/random.factor
basis/boxes/summary.txt [new file with mode: 0644]
basis/calendar/calendar-docs.factor
basis/calendar/format/format-tests.factor
basis/calendar/format/format.factor
basis/channels/channels-docs.factor
basis/channels/remote/tags.txt
basis/channels/tags.txt
basis/circular/circular-docs.factor [new file with mode: 0644]
basis/circular/circular.factor
basis/cocoa/cocoa-docs.factor
basis/colors/summary.txt [new file with mode: 0644]
basis/columns/columns-docs.factor
basis/combinators/short-circuit/short-circuit-docs.factor [new file with mode: 0644]
basis/combinators/short-circuit/smart/smart-docs.factor [new file with mode: 0644]
basis/command-line/command-line-docs.factor
basis/compiler/constants/constants.factor
basis/compiler/generator/generator-docs.factor
basis/compiler/intrinsics/intrinsics.factor
basis/compiler/tree/propagation/info/info.factor
basis/concurrency/combinators/combinators.factor
basis/concurrency/combinators/tags.txt [new file with mode: 0644]
basis/concurrency/conditions/tags.txt [new file with mode: 0644]
basis/concurrency/count-downs/count-downs.factor
basis/concurrency/count-downs/tags.txt [new file with mode: 0644]
basis/concurrency/distributed/tags.txt
basis/concurrency/exchangers/tags.txt [new file with mode: 0644]
basis/concurrency/flags/tags.txt [new file with mode: 0644]
basis/concurrency/futures/tags.txt [new file with mode: 0644]
basis/concurrency/locks/tags.txt [new file with mode: 0644]
basis/concurrency/mailboxes/tags.txt [new file with mode: 0644]
basis/concurrency/messaging/messaging.factor
basis/concurrency/messaging/tags.txt [new file with mode: 0644]
basis/concurrency/promises/promises.factor
basis/concurrency/promises/tags.txt [new file with mode: 0644]
basis/concurrency/semaphores/tags.txt [new file with mode: 0644]
basis/core-foundation/fsevents/fsevents.factor
basis/core-foundation/run-loop/run-loop.factor
basis/core-foundation/run-loop/thread/thread.factor [new file with mode: 0644]
basis/db/db-docs.factor
basis/db/db.factor
basis/db/postgresql/postgresql.factor
basis/db/queries/queries.factor
basis/db/sqlite/sqlite.factor
basis/db/tuples/tuples-docs.factor
basis/db/tuples/tuples-tests.factor
basis/db/tuples/tuples.factor
basis/db/types/types-docs.factor
basis/db/types/types.factor
basis/debugger/debugger.factor
basis/delegate/delegate-docs.factor
basis/delegate/delegate.factor
basis/deques/deques-docs.factor
basis/disjoint-sets/disjoint-sets-docs.factor
basis/editors/macvim/authors.txt [new file with mode: 0644]
basis/editors/macvim/macvim.factor [new file with mode: 0755]
basis/editors/macvim/summary.txt [new file with mode: 0644]
basis/editors/macvim/tags.txt [new file with mode: 0644]
basis/editors/textedit/authors.txt [new file with mode: 0644]
basis/editors/textedit/summary.txt [new file with mode: 0644]
basis/editors/textedit/tags.txt [new file with mode: 0644]
basis/editors/textedit/textedit.factor [new file with mode: 0755]
basis/eval/authors.txt [new file with mode: 0644]
basis/eval/summary.txt [new file with mode: 0644]
basis/farkup/farkup-docs.factor
basis/farkup/farkup-tests.factor
basis/farkup/farkup.factor
basis/furnace/actions/actions.factor
basis/furnace/actions/authors.txt [new file with mode: 0644]
basis/furnace/actions/summary.txt [new file with mode: 0644]
basis/furnace/actions/tags.txt [new file with mode: 0644]
basis/furnace/alloy/alloy.factor
basis/furnace/alloy/authors.txt [new file with mode: 0644]
basis/furnace/alloy/summary.txt [new file with mode: 0644]
basis/furnace/alloy/tags.txt [new file with mode: 0644]
basis/furnace/asides/asides.factor [new file with mode: 0644]
basis/furnace/asides/authors.txt [new file with mode: 0644]
basis/furnace/asides/summary.txt [new file with mode: 0644]
basis/furnace/asides/tags.txt [new file with mode: 0644]
basis/furnace/auth/auth.factor
basis/furnace/auth/authors.txt [new file with mode: 0644]
basis/furnace/auth/basic/summary.txt [new file with mode: 0644]
basis/furnace/auth/features/deactivate-user/authors.txt [new file with mode: 0644]
basis/furnace/auth/features/deactivate-user/deactivate-user.factor
basis/furnace/auth/features/deactivate-user/summary.txt [new file with mode: 0644]
basis/furnace/auth/features/deactivate-user/tags.txt [new file with mode: 0644]
basis/furnace/auth/features/edit-profile/authors.txt [new file with mode: 0644]
basis/furnace/auth/features/edit-profile/edit-profile.factor
basis/furnace/auth/features/edit-profile/edit-profile.xml
basis/furnace/auth/features/edit-profile/summary.txt [new file with mode: 0644]
basis/furnace/auth/features/edit-profile/tags.txt [new file with mode: 0644]
basis/furnace/auth/features/recover-password/authors.txt [new file with mode: 0644]
basis/furnace/auth/features/recover-password/recover-1.xml
basis/furnace/auth/features/recover-password/recover-3.xml
basis/furnace/auth/features/recover-password/recover-password.factor
basis/furnace/auth/features/recover-password/summary.txt [new file with mode: 0644]
basis/furnace/auth/features/recover-password/tags.txt [new file with mode: 0644]
basis/furnace/auth/features/registration/authors.txt [new file with mode: 0644]
basis/furnace/auth/features/registration/register.xml
basis/furnace/auth/features/registration/registration.factor
basis/furnace/auth/features/registration/summary.txt [new file with mode: 0644]
basis/furnace/auth/features/registration/tags.txt [new file with mode: 0644]
basis/furnace/auth/login/authors.txt [new file with mode: 0644]
basis/furnace/auth/login/login.factor
basis/furnace/auth/login/login.xml
basis/furnace/auth/login/permits/authors.txt [new file with mode: 0644]
basis/furnace/auth/login/permits/tags.txt [new file with mode: 0644]
basis/furnace/auth/login/summary.txt [new file with mode: 0644]
basis/furnace/auth/login/tags.txt [new file with mode: 0644]
basis/furnace/auth/providers/assoc/summary.txt [new file with mode: 0644]
basis/furnace/auth/providers/authors.txt [new file with mode: 0644]
basis/furnace/auth/providers/db/authors.txt [new file with mode: 0644]
basis/furnace/auth/providers/db/summary.txt [new file with mode: 0644]
basis/furnace/auth/providers/db/tags.txt [new file with mode: 0644]
basis/furnace/auth/providers/null/summary.txt [new file with mode: 0644]
basis/furnace/auth/providers/summary.txt [new file with mode: 0644]
basis/furnace/auth/providers/tags.txt [new file with mode: 0644]
basis/furnace/auth/summary.txt [new file with mode: 0644]
basis/furnace/auth/tags.txt [new file with mode: 0644]
basis/furnace/authors.txt [new file with mode: 0644]
basis/furnace/boilerplate/authors.txt [new file with mode: 0644]
basis/furnace/boilerplate/boilerplate.factor
basis/furnace/boilerplate/summary.txt [new file with mode: 0644]
basis/furnace/boilerplate/tags.txt [new file with mode: 0644]
basis/furnace/cache/authors.txt [new file with mode: 0644]
basis/furnace/cache/summary.txt [new file with mode: 0644]
basis/furnace/cache/tags.txt [new file with mode: 0644]
basis/furnace/chloe-tags/authors.txt [new file with mode: 0644]
basis/furnace/chloe-tags/chloe-tags.factor
basis/furnace/chloe-tags/summary.txt [new file with mode: 0644]
basis/furnace/chloe-tags/tags.txt [new file with mode: 0644]
basis/furnace/conversations/authors.txt [new file with mode: 0644]
basis/furnace/conversations/conversations.factor
basis/furnace/conversations/summary.txt [new file with mode: 0644]
basis/furnace/conversations/tags.txt [new file with mode: 0644]
basis/furnace/db/authors.txt [new file with mode: 0644]
basis/furnace/db/summary.txt [new file with mode: 0644]
basis/furnace/db/tags.txt [new file with mode: 0644]
basis/furnace/furnace-tests.factor
basis/furnace/furnace.factor
basis/furnace/json/summary.txt [new file with mode: 0644]
basis/furnace/redirection/authors.txt [new file with mode: 0644]
basis/furnace/redirection/redirection.factor
basis/furnace/redirection/summary.txt [new file with mode: 0644]
basis/furnace/redirection/tags.txt [new file with mode: 0644]
basis/furnace/referrer/authors.txt [new file with mode: 0644]
basis/furnace/referrer/referrer.factor
basis/furnace/referrer/summary.txt [new file with mode: 0644]
basis/furnace/referrer/tags.txt [new file with mode: 0644]
basis/furnace/scopes/authors.txt [new file with mode: 0644]
basis/furnace/scopes/summary.txt [new file with mode: 0644]
basis/furnace/scopes/tags.txt [new file with mode: 0644]
basis/furnace/sessions/authors.txt
basis/furnace/sessions/sessions.factor
basis/furnace/sessions/summary.txt [new file with mode: 0644]
basis/furnace/sessions/tags.txt [new file with mode: 0644]
basis/furnace/syndication/authors.txt [new file with mode: 0644]
basis/furnace/syndication/summary.txt [new file with mode: 0644]
basis/furnace/syndication/syndication.factor
basis/furnace/syndication/tags.txt [new file with mode: 0644]
basis/furnace/tags.txt [new file with mode: 0644]
basis/furnace/utilities/authors.txt [new file with mode: 0644]
basis/furnace/utilities/summary.txt [new file with mode: 0644]
basis/furnace/utilities/tags.txt [new file with mode: 0644]
basis/generalizations/authors.txt [new file with mode: 0644]
basis/generalizations/summary.txt [new file with mode: 0644]
basis/globs/globs.factor
basis/heaps/heaps.factor
basis/help/cookbook/cookbook.factor
basis/help/handbook/handbook.factor
basis/help/html/html-tests.factor [new file with mode: 0644]
basis/help/html/html.factor
basis/help/html/stylesheet.css [new file with mode: 0644]
basis/help/lint/lint.factor
basis/help/markup/markup.factor
basis/html/components/authors.txt [new file with mode: 0644]
basis/html/components/components-docs.factor [new file with mode: 0644]
basis/html/components/components-tests.factor
basis/html/components/components.factor
basis/html/components/summary.txt [new file with mode: 0644]
basis/html/components/tags.txt [new file with mode: 0644]
basis/html/elements/elements-docs.factor [new file with mode: 0644]
basis/html/elements/elements.factor
basis/html/elements/summary.txt [new file with mode: 0644]
basis/html/elements/tags.txt [new file with mode: 0644]
basis/html/forms/authors.txt [new file with mode: 0644]
basis/html/forms/forms-docs.factor [new file with mode: 0644]
basis/html/forms/forms.factor
basis/html/forms/summary.txt [new file with mode: 0644]
basis/html/forms/tags.txt [new file with mode: 0644]
basis/html/streams/streams-docs.factor [new file with mode: 0644]
basis/html/streams/streams-tests.factor
basis/html/streams/streams.factor
basis/html/streams/summary.txt
basis/html/templates/authors.txt [new file with mode: 0644]
basis/html/templates/chloe/authors.txt [new file with mode: 0644]
basis/html/templates/chloe/chloe-docs.factor [new file with mode: 0644]
basis/html/templates/chloe/chloe-tests.factor
basis/html/templates/chloe/chloe.factor
basis/html/templates/chloe/compiler/compiler.factor
basis/html/templates/chloe/components/components.factor
basis/html/templates/chloe/summary.txt [new file with mode: 0644]
basis/html/templates/chloe/tags.txt [new file with mode: 0644]
basis/html/templates/fhtml/authors.txt
basis/html/templates/fhtml/fhtml-docs.factor [new file with mode: 0644]
basis/html/templates/fhtml/summary.txt [new file with mode: 0644]
basis/html/templates/fhtml/tags.txt [new file with mode: 0644]
basis/html/templates/summary.txt [new file with mode: 0644]
basis/html/templates/tags.txt [new file with mode: 0644]
basis/html/templates/templates-docs.factor [new file with mode: 0644]
basis/html/templates/templates.factor
basis/http/client/client-docs.factor [new file with mode: 0644]
basis/http/client/client.factor
basis/http/http-docs.factor [new file with mode: 0644]
basis/http/http-tests.factor
basis/http/http.factor
basis/http/parsers/parsers.factor
basis/http/server/cgi/cgi-docs.factor [new file with mode: 0644]
basis/http/server/cgi/cgi.factor
basis/http/server/dispatchers/dispatchers-docs.factor [new file with mode: 0644]
basis/http/server/dispatchers/tags.txt [new file with mode: 0644]
basis/http/server/filters/filters-docs.factor [new file with mode: 0644]
basis/http/server/filters/tags.txt [new file with mode: 0644]
basis/http/server/redirection/redirection-docs.factor [new file with mode: 0644]
basis/http/server/redirection/redirection-tests.factor
basis/http/server/redirection/tags.txt [new file with mode: 0644]
basis/http/server/remapping/remapping-docs.factor [new file with mode: 0644]
basis/http/server/remapping/remapping.factor [new file with mode: 0644]
basis/http/server/remapping/tags.txt [new file with mode: 0644]
basis/http/server/responses/responses-docs.factor [new file with mode: 0644]
basis/http/server/responses/tags.txt [new file with mode: 0644]
basis/http/server/server-docs.factor [new file with mode: 0644]
basis/http/server/server.factor
basis/http/server/static/static-docs.factor [new file with mode: 0644]
basis/http/server/static/static.factor
basis/http/server/tags.txt
basis/io/buffers/buffers-docs.factor
basis/io/encodings/iana/iana.factor
basis/io/launcher/launcher.factor
basis/io/servers/connection/connection.factor
basis/io/sockets/secure/secure.factor
basis/io/sockets/sockets.factor
basis/io/styles/styles-docs.factor
basis/io/styles/styles.factor
basis/io/unix/linux/monitors/monitors-tests.factor
basis/io/unix/sockets/secure/secure.factor
basis/io/windows/nt/files/files-tests.factor
basis/io/windows/nt/files/files.factor
basis/locals/locals-docs.factor
basis/locals/locals-tests.factor
basis/logging/analysis/analysis-docs.factor
basis/logging/logging-docs.factor
basis/macros/expander/expander-tests.factor
basis/macros/expander/expander.factor
basis/math/ranges/ranges-docs.factor
basis/models/range/range-tests.factor
basis/multiline/multiline-tests.factor
basis/multiline/multiline.factor
basis/nmake/authors.txt [new file with mode: 0644]
basis/nmake/summary.txt [new file with mode: 0644]
basis/nmake/tags.txt [new file with mode: 0644]
basis/opengl/opengl.factor
basis/present/authors.txt [new file with mode: 0644]
basis/present/present-docs.factor [new file with mode: 0644]
basis/present/summary.txt [new file with mode: 0644]
basis/prettyprint/prettyprint.factor
basis/random/authors.txt [new file with mode: 0644]
basis/random/summary.txt [new file with mode: 0644]
basis/random/unix/unix.factor
basis/regexp/authors.txt [new file with mode: 0644]
basis/regexp/backend/backend.factor [new file with mode: 0644]
basis/regexp/classes/classes.factor [new file with mode: 0644]
basis/regexp/dfa/dfa.factor [new file with mode: 0644]
basis/regexp/nfa/nfa.factor [new file with mode: 0644]
basis/regexp/parser/parser-tests.factor [new file with mode: 0644]
basis/regexp/parser/parser.factor [new file with mode: 0644]
basis/regexp/regexp-docs.factor [new file with mode: 0644]
basis/regexp/regexp-tests.factor [new file with mode: 0644]
basis/regexp/regexp.factor [new file with mode: 0644]
basis/regexp/summary.txt [new file with mode: 0644]
basis/regexp/tags.txt [new file with mode: 0644]
basis/regexp/transition-tables/transition-tables.factor [new file with mode: 0644]
basis/regexp/traversal/traversal.factor [new file with mode: 0644]
basis/regexp/utils/utils.factor [new file with mode: 0644]
basis/smtp/smtp-docs.factor
basis/stack-checker/errors/errors.factor
basis/stack-checker/transforms/transforms.factor
basis/summary/authors.txt [new file with mode: 0644]
basis/summary/summary-docs.factor
basis/summary/summary.txt [new file with mode: 0644]
basis/symbols/summary.txt [new file with mode: 0644]
basis/symbols/tags.txt [new file with mode: 0644]
basis/syndication/readme.txt [deleted file]
basis/syndication/syndication-docs.factor [new file with mode: 0644]
basis/syndication/syndication-tests.factor
basis/syndication/syndication.factor
basis/tools/deploy/backend/backend.factor
basis/tools/deploy/deploy-tests.factor
basis/tools/deploy/shaker/shaker.factor
basis/tools/deploy/shaker/strip-cocoa.factor
basis/tools/deploy/test/6/6.factor [new file with mode: 0644]
basis/tools/deploy/test/6/deploy.factor [new file with mode: 0644]
basis/tools/scaffold/scaffold.factor
basis/ui/gadgets/books/books.factor
basis/ui/gadgets/borders/borders.factor
basis/ui/gadgets/buttons/buttons.factor
basis/ui/gadgets/editors/editors.factor
basis/ui/gadgets/gadgets-tests.factor
basis/ui/gadgets/gadgets.factor
basis/ui/gadgets/grids/grids.factor
basis/ui/gadgets/incremental/incremental-docs.factor
basis/ui/gadgets/incremental/incremental.factor
basis/ui/gadgets/labelled/labelled.factor
basis/ui/gadgets/labels/labels.factor
basis/ui/gadgets/lists/lists.factor
basis/ui/gadgets/menus/menus.factor
basis/ui/gadgets/packs/packs.factor
basis/ui/gadgets/panes/panes.factor
basis/ui/gadgets/paragraphs/paragraphs.factor
basis/ui/gadgets/scrollers/scrollers-tests.factor
basis/ui/gadgets/scrollers/scrollers.factor
basis/ui/gadgets/sliders/sliders.factor
basis/ui/gadgets/slots/slots.factor
basis/ui/gadgets/tracks/tracks-tests.factor
basis/ui/gadgets/tracks/tracks.factor
basis/ui/gadgets/viewports/viewports.factor
basis/ui/gadgets/worlds/worlds-tests.factor
basis/ui/gadgets/worlds/worlds.factor
basis/ui/operations/operations.factor
basis/ui/render/render.factor
basis/ui/tools/browser/browser.factor
basis/ui/tools/deploy/deploy.factor
basis/ui/tools/inspector/inspector.factor
basis/ui/tools/listener/listener-tests.factor
basis/ui/tools/listener/listener.factor
basis/ui/tools/profiler/profiler.factor
basis/ui/tools/search/search-tests.factor
basis/ui/tools/search/search.factor
basis/ui/tools/tools-tests.factor
basis/ui/tools/tools.factor
basis/ui/tools/traceback/traceback.factor
basis/ui/tools/workspace/workspace.factor
basis/ui/ui.factor
basis/ui/x11/x11.factor
basis/unicode/breaks/breaks.factor
basis/unicode/collation/collation.factor
basis/unicode/data/data.factor
basis/unicode/script/script.factor
basis/urls/encoding/authors.txt [new file with mode: 0644]
basis/urls/encoding/encoding-docs.factor [new file with mode: 0644]
basis/urls/encoding/encoding-tests.factor [new file with mode: 0644]
basis/urls/encoding/encoding.factor [new file with mode: 0644]
basis/urls/encoding/summary.txt [new file with mode: 0644]
basis/urls/encoding/tags.txt [new file with mode: 0644]
basis/urls/urls-docs.factor [new file with mode: 0644]
basis/urls/urls-tests.factor
basis/urls/urls.factor
basis/validators/authors.txt [new file with mode: 0644]
basis/validators/summary.txt [new file with mode: 0644]
basis/validators/tags.txt [new file with mode: 0644]
basis/validators/validators-docs.factor [new file with mode: 0644]
basis/validators/validators.factor
basis/values/values-docs.factor
basis/values/values-tests.factor
basis/values/values.factor
basis/xmode/loader/loader.factor
basis/xmode/loader/syntax/syntax.factor
basis/xmode/marker/marker.factor
basis/xmode/rules/rules.factor
build-support/factor.sh
core/checksums/authors.txt [new file with mode: 0644]
core/checksums/summary.txt [new file with mode: 0644]
core/classes/tuple/parser/parser.factor
core/classes/tuple/tuple.factor
core/continuations/continuations-docs.factor
core/destructors/destructors-docs.factor
core/hashtables/hashtables-docs.factor
core/io/files/files.factor
core/io/io-docs.factor
core/io/io.factor
core/kernel/kernel-docs.factor
core/layouts/layouts.factor
core/lexer/authors.txt [new file with mode: 0644]
core/lexer/summary.txt [new file with mode: 0644]
core/make/authors.txt [new file with mode: 0644]
core/make/summary.txt [new file with mode: 0644]
core/make/tags.txt [new file with mode: 0644]
core/math/math-docs.factor
core/math/parser/parser-tests.factor
core/math/parser/parser.factor
core/memory/memory-docs.factor
core/memory/memory-tests.factor
core/sequences/sequences-docs.factor
core/sequences/sequences.factor
core/sets/sets-docs.factor
core/strings/strings-docs.factor
core/syntax/syntax-docs.factor
core/system/system.factor
extra/benchmark/regex-dna/regex-dna-test-in.txt [new file with mode: 0644]
extra/benchmark/regex-dna/regex-dna-test-out.txt [new file with mode: 0644]
extra/benchmark/regex-dna/regex-dna-tests.factor [new file with mode: 0644]
extra/benchmark/regex-dna/regex-dna.factor [new file with mode: 0644]
extra/hello-world/deploy.factor
extra/html/parser/analyzer/analyzer.factor
extra/html/parser/parser.factor
extra/html/parser/utils/utils.factor
extra/irc/client/client-tests.factor
extra/irc/client/client.factor [changed mode: 0644->0755]
extra/irc/messages/messages-tests.factor
extra/irc/messages/messages.factor
extra/mason/authors.txt [new file with mode: 0644]
extra/mason/build/build-tests.factor [new file with mode: 0644]
extra/mason/build/build.factor [new file with mode: 0644]
extra/mason/child/child-tests.factor [new file with mode: 0644]
extra/mason/child/child.factor [new file with mode: 0644]
extra/mason/cleanup/cleanup-tests.factor [new file with mode: 0644]
extra/mason/cleanup/cleanup.factor [new file with mode: 0644]
extra/mason/common/common-tests.factor [new file with mode: 0644]
extra/mason/common/common.factor [new file with mode: 0644]
extra/mason/config/config.factor [new file with mode: 0644]
extra/mason/email/email-tests.factor [new file with mode: 0644]
extra/mason/email/email.factor [new file with mode: 0644]
extra/mason/mason.factor [new file with mode: 0644]
extra/mason/platform/platform.factor [new file with mode: 0644]
extra/mason/release/archive/archive.factor [new file with mode: 0644]
extra/mason/release/branch/branch-tests.factor [new file with mode: 0644]
extra/mason/release/branch/branch.factor [new file with mode: 0644]
extra/mason/release/release.factor [new file with mode: 0644]
extra/mason/release/tidy/tidy-tests.factor [new file with mode: 0644]
extra/mason/release/tidy/tidy.factor [new file with mode: 0644]
extra/mason/release/upload/upload-tests.factor [new file with mode: 0644]
extra/mason/release/upload/upload.factor [new file with mode: 0644]
extra/mason/report/report-tests.factor [new file with mode: 0644]
extra/mason/report/report.factor [new file with mode: 0644]
extra/mason/summary.txt [new file with mode: 0644]
extra/mason/test/test.factor [new file with mode: 0644]
extra/mason/updates/updates.factor [new file with mode: 0644]
extra/math/compare/authors.txt [new file with mode: 0644]
extra/math/compare/compare-docs.factor [new file with mode: 0644]
extra/math/compare/compare-tests.factor [new file with mode: 0644]
extra/math/compare/compare.factor [new file with mode: 0644]
extra/math/compare/summary.txt [new file with mode: 0644]
extra/math/finance/authors.txt [new file with mode: 0644]
extra/math/finance/finance-docs.factor [new file with mode: 0644]
extra/math/finance/finance-tests.factor [new file with mode: 0644]
extra/math/finance/finance.factor [new file with mode: 0644]
extra/math/finance/summary.txt [new file with mode: 0644]
extra/math/statistics/statistics.factor
extra/parser-combinators/regexp/authors.txt [new file with mode: 0755]
extra/parser-combinators/regexp/regexp-tests.factor [new file with mode: 0755]
extra/parser-combinators/regexp/regexp.factor [new file with mode: 0755]
extra/parser-combinators/regexp/summary.txt [new file with mode: 0644]
extra/parser-combinators/regexp/tags.txt [new file with mode: 0755]
extra/peg/javascript/parser/parser-tests.factor
extra/peg/pl0/pl0-tests.factor
extra/printf/authors.txt [new file with mode: 0644]
extra/printf/printf-docs.factor [new file with mode: 0644]
extra/printf/printf-tests.factor [new file with mode: 0644]
extra/printf/printf.factor [new file with mode: 0644]
extra/printf/summary.txt [new file with mode: 0644]
extra/regexp/authors.txt [deleted file]
extra/regexp/regexp-tests.factor [deleted file]
extra/regexp/regexp.factor [deleted file]
extra/regexp/summary.txt [deleted file]
extra/regexp/tags.txt [deleted file]
extra/sequences/lib/lib-docs.factor
extra/sequences/lib/lib-tests.factor
extra/sequences/lib/lib.factor
extra/webapps/blogs/blogs.factor
extra/webapps/blogs/tags.txt [new file with mode: 0644]
extra/webapps/calculator/calculator.factor [new file with mode: 0644]
extra/webapps/calculator/calculator.xml [new file with mode: 0644]
extra/webapps/calculator/tags.txt [new file with mode: 0644]
extra/webapps/counter/counter.factor
extra/webapps/counter/tags.txt [new file with mode: 0644]
extra/webapps/help/help.factor [new file with mode: 0644]
extra/webapps/help/help.xml [new file with mode: 0644]
extra/webapps/help/search.xml [new file with mode: 0644]
extra/webapps/pastebin/new-paste.xml
extra/webapps/pastebin/paste.xml
extra/webapps/pastebin/pastebin-common.xml
extra/webapps/pastebin/pastebin.factor
extra/webapps/pastebin/pastebin.xml
extra/webapps/pastebin/tags.txt [new file with mode: 0644]
extra/webapps/planet/edit-blog.xml
extra/webapps/planet/new-blog.xml
extra/webapps/planet/planet-common.xml
extra/webapps/planet/planet.factor
extra/webapps/planet/planet.xml
extra/webapps/planet/tags.txt [new file with mode: 0644]
extra/webapps/todo/tags.txt [new file with mode: 0644]
extra/webapps/todo/todo.factor
extra/webapps/user-admin/edit-user.xml
extra/webapps/user-admin/new-user.xml
extra/webapps/user-admin/tags.txt [new file with mode: 0644]
extra/webapps/user-admin/user-admin.factor
extra/webapps/wee-url/shorten.xml
extra/webapps/wee-url/tags.txt [new file with mode: 0644]
extra/webapps/wiki/edit.xml
extra/webapps/wiki/initial-content/Farkup.txt
extra/webapps/wiki/initial-content/Wiki Help.txt
extra/webapps/wiki/revisions.xml
extra/webapps/wiki/tags.txt [new file with mode: 0644]
extra/webapps/wiki/view.xml
extra/webapps/wiki/wiki-common.xml
extra/webapps/wiki/wiki.css
extra/webapps/wiki/wiki.factor
extra/websites/concatenative/concatenative.factor
extra/websites/concatenative/page.xml
extra/wordtimer/wordtimer-docs.factor
misc/factor.el
misc/factor.vim
unfinished/compiler/backend/alien/alien.factor [deleted file]
unfinished/compiler/backend/backend.factor
unfinished/compiler/backend/x86/32/32.factor
unfinished/compiler/backend/x86/64/64.factor [new file with mode: 0644]
unfinished/compiler/backend/x86/sse2/sse2.factor [new file with mode: 0644]
unfinished/compiler/backend/x86/x86.factor [new file with mode: 0644]
unfinished/compiler/cfg/builder/builder.factor
unfinished/compiler/cfg/cfg.factor
unfinished/compiler/cfg/debugger/debugger.factor
unfinished/compiler/cfg/instructions/instructions.factor [new file with mode: 0644]
unfinished/compiler/cfg/instructions/syntax/syntax.factor [new file with mode: 0644]
unfinished/compiler/cfg/linear-scan/allocation/allocation.factor
unfinished/compiler/cfg/linear-scan/assignment/assignment-tests.factor [new file with mode: 0644]
unfinished/compiler/cfg/linear-scan/assignment/assignment.factor [new file with mode: 0644]
unfinished/compiler/cfg/linear-scan/debugger/debugger.factor [new file with mode: 0644]
unfinished/compiler/cfg/linear-scan/linear-scan-tests.factor [new file with mode: 0644]
unfinished/compiler/cfg/linear-scan/linear-scan.factor
unfinished/compiler/cfg/linear-scan/live-intervals/live-intervals.factor
unfinished/compiler/cfg/linearization/linearization.factor
unfinished/compiler/cfg/registers/registers.factor [new file with mode: 0644]
unfinished/compiler/cfg/rpo/rpo.factor
unfinished/compiler/cfg/stack-frame/stack-frame.factor [new file with mode: 0644]
unfinished/compiler/cfg/stacks/stacks.factor
unfinished/compiler/cfg/templates/templates.factor
unfinished/compiler/codegen/codegen.factor [new file with mode: 0644]
unfinished/compiler/codegen/fixup/fixup.factor
unfinished/compiler/instructions/instructions.factor [deleted file]
unfinished/compiler/instructions/syntax/syntax.factor [deleted file]
unfinished/compiler/new/new.factor [new file with mode: 0644]
unfinished/compiler/registers/registers.factor [deleted file]
unfinished/cpu/x86/syntax/syntax.factor [new file with mode: 0644]
unfinished/cpu/x86/syntax/tags.txt [new file with mode: 0644]
unfinished/cpu/x86/x86.factor [new file with mode: 0755]
unfinished/regexp2/authors.txt [deleted file]
unfinished/regexp2/backend/backend.factor [deleted file]
unfinished/regexp2/classes/classes.factor [deleted file]
unfinished/regexp2/dfa/dfa.factor [deleted file]
unfinished/regexp2/nfa/nfa.factor [deleted file]
unfinished/regexp2/parser/parser-tests.factor [deleted file]
unfinished/regexp2/parser/parser.factor [deleted file]
unfinished/regexp2/regexp2-docs.factor [deleted file]
unfinished/regexp2/regexp2-tests.factor [deleted file]
unfinished/regexp2/regexp2.factor [deleted file]
unfinished/regexp2/summary.txt [deleted file]
unfinished/regexp2/tags.txt [deleted file]
unfinished/regexp2/transition-tables/transition-tables.factor [deleted file]
unfinished/regexp2/traversal/traversal.factor [deleted file]
unfinished/regexp2/utils/utils.factor [deleted file]
vm/image.c
vm/types.c

diff --git a/basis/alarms/summary.txt b/basis/alarms/summary.txt
new file mode 100644 (file)
index 0000000..f6e1223
--- /dev/null
@@ -0,0 +1 @@
+One-time and recurring events
diff --git a/basis/alias/summary.txt b/basis/alias/summary.txt
new file mode 100644 (file)
index 0000000..15690a7
--- /dev/null
@@ -0,0 +1 @@
+Defining multiple words with the same name
index 75af8a7102431d74b867feb2c64a04accb710d46..6af697cf8935c09020d4a3846beb283eb2ea76bb 100755 (executable)
@@ -46,6 +46,6 @@ ARTICLE: "ascii" "ASCII character classes"
 { $subsection printable? }\r
 { $subsection control? }\r
 { $subsection quotable? }\r
-"Modern applications should use Unicode 5.0 instead (" { $vocab-link "unicode" } ")." ;\r
+"Modern applications should use Unicode 5.0 instead (" { $vocab-link "unicode.categories" } ")." ;\r
 \r
 ABOUT: "ascii"\r
diff --git a/basis/binary-search/summary.txt b/basis/binary-search/summary.txt
new file mode 100644 (file)
index 0000000..c4fd4f2
--- /dev/null
@@ -0,0 +1 @@
+Fast searching of sorted arrays
index 9284728a7a8ee0a72d5db303fab605d5ea7f5ec2..f3f570b462311bfae018899d13adbe2d44d5b35e 100755 (executable)
@@ -26,7 +26,6 @@ IN: bootstrap.image
         "x86.32"
         "x86.64"
         "linux-ppc" "macosx-ppc"
-        ! "arm"
     } ;
 
 <PRIVATE
@@ -412,14 +411,14 @@ M: quotation '
     all-words [ emit-word ] each ;
 
 : emit-global ( -- )
-    [
-        {
-            dictionary source-files builtins
-            update-map implementors-map class<=-cache
-            class-not-cache classes-intersect-cache class-and-cache
-            class-or-cache
-        } [ dup get swap bootstrap-word set ] each
-    ] H{ } make-assoc
+    {
+        dictionary source-files builtins
+        update-map implementors-map
+    } [ [ bootstrap-word ] [ get ] bi ] H{ } map>assoc
+    {
+        class<=-cache class-not-cache classes-intersect-cache
+        class-and-cache class-or-cache
+    } [ H{ } clone ] H{ } map>assoc assoc-union
     bootstrap-global set
     bootstrap-global emit-userenv ;
 
index 3782d517cfff4b1b8698882cecabf35b06b6da0b..f6527cdda1ef5519d0e98cdd2a7e67bab49fd3f8 100755 (executable)
@@ -13,4 +13,4 @@ IN: bootstrap.random
 [
     [ 32 random-bits ] with-system-random
     <mersenne-twister> random-generator set-global
-] "generator.random" add-init-hook
+] "bootstrap.random" add-init-hook
diff --git a/basis/boxes/summary.txt b/basis/boxes/summary.txt
new file mode 100644 (file)
index 0000000..44c1352
--- /dev/null
@@ -0,0 +1 @@
+An abstraction for enforcing a mutual-exclusion invariant
index 62ff4ad51779d3066ab726c2562b2cba50e1069c..c3d84fc783617804ca1a9afaf88611e970eb5ad4 100644 (file)
@@ -21,8 +21,8 @@ HELP: <date>
 { $description "Returns a timestamp object representing the start of the specified day in your current timezone." }
 { $examples
     { $example "USING: calendar prettyprint ;"
-               "2010 12 25 <date> ."
-               "T{ timestamp\n    { year 2010 }\n    { month 12 }\n    { day 25 }\n    { gmt-offset T{ duration { hour -5 } } }\n}"
+               "2010 12 25 <date> >gmt midnight ."
+               "T{ timestamp { year 2010 } { month 12 } { day 25 } }"
     }
 } ;
 
index c433a118c2fe1be19e47c4d13ba01a9b5a5a6a9a..81930cdf49fa1963a702d74abe5d531b68316ba4 100755 (executable)
@@ -62,3 +62,15 @@ IN: calendar.format.tests
         T{ duration f 0 0 0 -5 0 0 }\r
     }\r
 ] [ "2008-05-26T00:37:42.12345-05:00" rfc3339>timestamp ] unit-test\r
+\r
+[\r
+    T{ timestamp\r
+        { year 2008 }\r
+        { month 10 }\r
+        { day 2 }\r
+        { hour 23 }\r
+        { minute 59 }\r
+        { second 59 }\r
+        { gmt-offset T{ duration f 0 0 0 0 0 0 } }\r
+    }\r
+] [ "Thursday, 02-Oct-2008 23:59:59 GMT" cookie-string>timestamp ] unit-test\r
index bfe438fae11b05392fe63b93d8e5130f336c6bd2..b15da4240998ddd4ffeca4b9dbba53a347ec4a7c 100755 (executable)
@@ -201,9 +201,13 @@ ERROR: invalid-timestamp-format ;
 : rfc822>timestamp ( str -- timestamp )\r
     [ (rfc822>timestamp) ] with-string-reader ;\r
 \r
+: check-day-name ( str -- )\r
+    [ day-abbreviations3 member? ] [ day-names member? ] bi or\r
+    check-timestamp drop ;\r
+\r
 : (cookie-string>timestamp-1) ( -- timestamp )\r
     timestamp new\r
-        "," read-token day-abbreviations3 member? check-timestamp drop\r
+        "," read-token check-day-name\r
         read1 CHAR: \s assert=\r
         "-" read-token checked-number >>day\r
         "-" read-token month-abbreviations index 1+ check-timestamp >>month\r
@@ -218,7 +222,7 @@ ERROR: invalid-timestamp-format ;
 \r
 : (cookie-string>timestamp-2) ( -- timestamp )\r
     timestamp new\r
-        read-sp day-abbreviations3 member? check-timestamp drop\r
+        read-sp check-day-name\r
         read-sp month-abbreviations index 1+ check-timestamp >>month\r
         read-sp checked-number >>day\r
         ":" read-token checked-number >>hour\r
index 521a4a4ae20ca0174cb2a99472ee02247e029420..b6ddc299e54faf40baad917a17b09c1ff7f3e7eb 100644 (file)
@@ -33,3 +33,14 @@ HELP: from
 " It will block the calling thread until there is data in the channel." 
 }
 { $see-also <channel> to } ;
+
+ARTICLE: "channels" "Channels"
+"The " { $vocab-link "channels" } " vocabulary provides a simple abstraction to send and receive objects." $nl
+"Opening a channel:"
+{ $subsection <channel> }
+"Sending a message:"
+{ $subsection to }
+"Receiving a message:"
+{ $subsection from } ;
+
+ABOUT: "channels"
index f4274299b1c36db85f10b2e3f3e38f18fded1061..ce745d18c63eb297ba23b94fa73b4752b798b1b5 100644 (file)
@@ -1 +1 @@
-extensions
+concurrency
index f4274299b1c36db85f10b2e3f3e38f18fded1061..ce745d18c63eb297ba23b94fa73b4752b798b1b5 100644 (file)
@@ -1 +1 @@
-extensions
+concurrency
diff --git a/basis/circular/circular-docs.factor b/basis/circular/circular-docs.factor
new file mode 100644 (file)
index 0000000..c7af57c
--- /dev/null
@@ -0,0 +1,58 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string sequences
+math kernel ;
+IN: circular
+
+HELP: <circular-string>
+{ $values
+     { "n" integer }
+     { "circular" circular } }
+{ $description "Creates a new circular string object. A circular string is a string object that can be accessed out of bounds and the index will wrap around to the start of the string." } ;
+
+HELP: <circular>
+{ $values
+     { "seq" sequence }
+     { "circular" circular } }
+{ $description "Creates a new " { $link circular } " object that wraps an existing sequence. By default, the index is set to zero." } ;
+
+HELP: <growing-circular>
+{ $values
+     { "capacity" integer }
+     { "growing-circular" growing-circular } }
+{ $description "Creates a new growing-circular object." } ;
+
+HELP: change-circular-start
+{ $values
+     { "n" integer } { "circular" circular } }
+{ $description "Changes the start index of a circular object." } ;
+
+HELP: circular
+{ $description "A tuple class that stores a sequence and its start index." } ;
+
+HELP: growing-circular
+{ $description "A circular sequence that is growable." } ;
+
+HELP: push-circular
+{ $values
+     { "elt" object } { "circular" circular } }
+{ $description "Pushes an element to a " { $link circular } " object." } ;
+
+HELP: push-growing-circular
+{ $values
+     { "elt" object } { "circular" circular } }
+{ $description "Pushes an element onto a " { $link growing-circular } " object." } ;
+
+ARTICLE: "circular" "Circular sequences"
+"The " { $vocab-link "circular" } " vocabulary implements the " { $link "sequence-protocol" } " to allow an arbitrary start index and wrap-around indexing." $nl
+"Creating a new circular object:"
+{ $subsection <circular> }
+{ $subsection <circular-string> }
+{ $subsection <growing-circular> }
+"Changing the start index:"
+{ $subsection change-circular-start }
+"Pushing new elements:"
+{ $subsection push-circular }
+{ $subsection push-growing-circular } ;
+
+ABOUT: "circular"
index 5d2378120f78a28e739eae7d8c8e5f3da6655117..9f3a71f2a81b6f747d49f8badad6257ec5664a49 100755 (executable)
@@ -11,9 +11,11 @@ TUPLE: circular seq start ;
 : <circular> ( seq -- circular )
     0 circular boa ;
 
+<PRIVATE
 : circular-wrap ( n circular -- n circular )
     [ start>> + ] keep
     [ seq>> length rem ] keep ; inline
+PRIVATE>
 
 M: circular length seq>> length ;
 
@@ -37,11 +39,13 @@ TUPLE: growing-circular < circular length ;
 
 M: growing-circular length length>> ;
 
+<PRIVATE
 : full? ( circular -- ? )
     [ length ] [ seq>> length ] bi = ;
 
 : set-peek ( elt seq -- )
     [ length 1- ] keep set-nth ;
+PRIVATE>
 
 : push-growing-circular ( elt circular -- )
     dup full? [ push-circular ]
index 01b0809f37fc85deabdf7ef75177048c25a028d7..a97128825114cff17172339828923c64ffb1e2e4 100644 (file)
@@ -19,7 +19,7 @@ HELP: SUPER->
 ARTICLE: "objc-calling" "Calling Objective C code"
 "Before an Objective C class can be used, it must be imported; by default, a small set of common classes are imported automatically, but additional classes can be imported as needed."
 { $subsection import-objc-class }
-"Every imported Objective C class has as corresponding class word in the " { $vocab-link "objc-classes" } " vocabulary. Class words push the class object in the stack, allowing class methods to be invoked."
+"Every imported Objective C class has as corresponding class word in the " { $vocab-link "cocoa.classes" } " vocabulary. Class words push the class object in the stack, allowing class methods to be invoked."
 $nl
 "Messages can be sent to classes and instances using a pair of parsing words:"
 { $subsection POSTPONE: -> }
diff --git a/basis/colors/summary.txt b/basis/colors/summary.txt
new file mode 100644 (file)
index 0000000..a90b1aa
--- /dev/null
@@ -0,0 +1 @@
+Colors as a first-class data type
index 818ce2f75283b6366315f9c93f5b292bb18aeade..27dc1608127e35241dc034124024b8038b40eaca 100644 (file)
@@ -1,13 +1,6 @@
 USING: help.markup help.syntax sequences ;
 IN: columns
 
-ARTICLE: "columns" "Column sequences"
-"A " { $emphasis "column" } " presents a column of a matrix represented as a sequence of rows:"
-{ $subsection column }
-{ $subsection <column> }
-"A utility word:"
-{ $subsection <flipped> } ;
-
 HELP: column
 { $class-description "A virtual sequence which presents a fixed column of a matrix represented as a sequence of rows. New instances can be created by calling " { $link <column> } "." } ;
 
@@ -30,4 +23,11 @@ HELP: <flipped>
 { $description "Outputs a new virtual sequence which presents the transpose of " { $snippet "seq" } "." }
 { $notes "This is the virtual sequence equivalent of " { $link flip } "." } ;
 
+ARTICLE: "columns" "Column sequences"
+"A " { $emphasis "column" } " presents a column of a matrix represented as a sequence of rows:"
+{ $subsection column }
+{ $subsection <column> }
+"A utility word:"
+{ $subsection <flipped> } ;
+
 ABOUT: "columns"
diff --git a/basis/combinators/short-circuit/short-circuit-docs.factor b/basis/combinators/short-circuit/short-circuit-docs.factor
new file mode 100644 (file)
index 0000000..54fc3aa
--- /dev/null
@@ -0,0 +1,84 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string quotations
+math ;
+IN: combinators.short-circuit
+
+HELP: 0&&
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if every quotation in the sequence of quotations returns true." } ;
+
+HELP: 0||
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if any quotation in the sequence returns true." } ;
+
+HELP: 1&&
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same element from the datastack and must output a boolean." } ;
+
+HELP: 1||
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same element from the datastack and must return a boolean." } ;
+
+HELP: 2&&
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same two elements from the datastack and must output a boolean." } ;
+
+HELP: 2||
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same two elements from the datastack and must return a boolean." } ;
+
+HELP: 3&&
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if every quotation in the sequence of quotations returns true. Each quotation gets the same three elements from the datastack and must output a boolean." } ;
+
+HELP: 3||
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same three elements from the datastack and must return a boolean." } ;
+
+HELP: n&&-rewrite
+{ $values
+     { "quots" "a sequence of quotations" } { "N" integer }
+     { "quot" quotation } }
+{ $description "A macro that reqrites the code to pass " { $snippet "N" } " parameters from the stack to each AND quotation." } ;
+
+HELP: n||-rewrite
+{ $values
+     { "quots" "a sequence of quotations" } { "N" integer }
+     { "quot" quotation } }
+{ $description "A macro that reqrites the code to pass " { $snippet "N" } " parameters from the stack to each OR quotation." } ;
+
+ARTICLE: "combinators.short-circuit" "Short-circuit combinators"
+"The " { $vocab-link "combinators.short-circuit" } " vocabulary stops a computation early once a condition is met." $nl
+"AND combinators:"
+{ $subsection 0&& }
+{ $subsection 1&& }
+{ $subsection 2&& }
+{ $subsection 3&& }
+"OR combinators:"
+{ $subsection 0|| }
+{ $subsection 1|| }
+{ $subsection 2|| }
+{ $subsection 3|| }
+"Generalized combinators:"
+{ $subsection n&&-rewrite }
+{ $subsection n||-rewrite }
+;
+
+ABOUT: "combinators.short-circuit"
diff --git a/basis/combinators/short-circuit/smart/smart-docs.factor b/basis/combinators/short-circuit/smart/smart-docs.factor
new file mode 100644 (file)
index 0000000..34abde1
--- /dev/null
@@ -0,0 +1,38 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string quotations ;
+IN: combinators.short-circuit.smart
+
+HELP: &&
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Infers the number of arguments that each quotation takes from the stack. Eacn quotation must take the same number of arguments. Returns true if every quotation yields true, and stops early if one yields false." }
+{ $examples "Smart combinators will infer the two inputs:"
+    { $example "USING: prettyprint kernel math combinators.short-circuit.smart ;"
+    "2 3 { [ + 5 = ] [ - -1 = ] } && ."
+    "t"
+    }
+} ;
+
+HELP: ||
+{ $values
+     { "quots" "a sequence of quotations" }
+     { "quot" quotation } }
+{ $description "Infers the number of arguments that each quotation takes from the stack. Eacn quotation must take the same number of arguments. Returns true if any quotation yields true, and stops early when one yields true." }
+{ $examples "Smart combinators will infer the two inputs:"
+    { $example "USING: prettyprint kernel math combinators.short-circuit.smart ;"
+    "2 3 { [ - 1 = ] [ + 5 = ] } || ."
+    "t"
+    }
+} ;
+
+ARTICLE: "combinators.short-circuit.smart" "Smart short-circuit combinators"
+"The " { $vocab-link "combinators.short-circuit.smart" } " vocabulary is similar to " { $vocab-link "combinators.short-circuit" } " except the combinators here infer the number of inputs that the sequence of quotations takes."
+$nl
+"Generalized AND:"
+{ $subsection && }
+"Generalized OR:"
+{ $subsection || } ;
+
+ABOUT: "combinators.short-circuit.smart"
index 440896deac49a287036f8b4f9f9b0fce10283ae9..d1b18ab5daacc82fc807fce7a8ebee02d641b40e 100644 (file)
@@ -1,6 +1,43 @@
 USING: help.markup help.syntax parser vocabs.loader strings ;
 IN: command-line
 
+HELP: run-bootstrap-init
+{ $description "Runs the " { $snippet ".factor-boot-rc" } " file in the user's home directory unless the " { $snippet "-no-user-init" } " command line switch was given." } ;
+
+HELP: run-user-init
+{ $description "Runs the " { $snippet ".factor-rc" } " file in the user's home directory unless the " { $snippet "-no-user-init" } " command line switch was given." } ;
+
+HELP: cli-param
+{ $values { "param" string } }
+{ $description "Process a command-line switch."
+$nl
+"If the parameter contains " { $snippet "=" } ", the global variable named by the string before the equals sign is set to the string after the equals sign."
+$nl
+"If the parameter begins with " { $snippet "no-" } ", sets the global variable named by the parameter with the prefix removed to " { $link f } "."
+$nl
+"Otherwise, sets the global variable named by the parameter to " { $link t } "." } ;
+
+HELP: cli-args
+{ $values { "args" "a sequence of strings" } }
+{ $description "Outputs the command line parameters which were passed to the Factor VM on startup." } ;
+
+HELP: main-vocab-hook
+{ $var-description "Global variable holding a quotation which outputs a vocabulary name. UI backends set this so that the UI can automatically start if the prerequisites are met (for example, " { $snippet "$DISPLAY" } " being set on X11)." } ;
+
+HELP: main-vocab
+{ $values { "vocab" string } }
+{ $description "Outputs the name of the vocabulary which is to be run on startup using the " { $link run } " word. The " { $snippet "-run" } " command line switch overrides this setting." } ;
+
+HELP: default-cli-args
+{ $description "Sets global variables corresponding to default command line arguments." } ;
+
+HELP: ignore-cli-args?
+{ $values { "?" "a boolean" } }
+{ $description "On Mac OS X, source files to run are supplied by the Cocoa API, so to avoid running them twice the startup code has to call this word." } ;
+
+HELP: parse-command-line
+{ $description "Called on startup to process command line arguments. This sets global variables with " { $link cli-param } ", runs source files, and evaluates the string given by the " { $snippet "-e" } " switch, if there is one." } ;
+
 ARTICLE: "runtime-cli-args" "Command line switches for the VM"
 "A handful of command line switches are processed by the VM and not the library. They control low-level features."
 { $table
@@ -77,40 +114,3 @@ $nl
 { $subsection main-vocab-hook } ;
 
 ABOUT: "cli"
-
-HELP: run-bootstrap-init
-{ $description "Runs the " { $snippet ".factor-boot-rc" } " file in the user's home directory unless the " { $snippet "-no-user-init" } " command line switch was given." } ;
-
-HELP: run-user-init
-{ $description "Runs the " { $snippet ".factor-rc" } " file in the user's home directory unless the " { $snippet "-no-user-init" } " command line switch was given." } ;
-
-HELP: cli-param
-{ $values { "param" string } }
-{ $description "Process a command-line switch."
-$nl
-"If the parameter contains " { $snippet "=" } ", the global variable named by the string before the equals sign is set to the string after the equals sign."
-$nl
-"If the parameter begins with " { $snippet "no-" } ", sets the global variable named by the parameter with the prefix removed to " { $link f } "."
-$nl
-"Otherwise, sets the global variable named by the parameter to " { $link t } "." } ;
-
-HELP: cli-args
-{ $values { "args" "a sequence of strings" } }
-{ $description "Outputs the command line parameters which were passed to the Factor VM on startup." } ;
-
-HELP: main-vocab-hook
-{ $var-description "Global variable holding a quotation which outputs a vocabulary name. UI backends set this so that the UI can automatically start if the prerequisites are met (for example, " { $snippet "$DISPLAY" } " being set on X11)." } ;
-
-HELP: main-vocab
-{ $values { "vocab" string } }
-{ $description "Outputs the name of the vocabulary which is to be run on startup using the " { $link run } " word. The " { $snippet "-run" } " command line switch overrides this setting." } ;
-
-HELP: default-cli-args
-{ $description "Sets global variables corresponding to default command line arguments." } ;
-
-HELP: ignore-cli-args?
-{ $values { "?" "a boolean" } }
-{ $description "On Mac OS X, source files to run are supplied by the Cocoa API, so to avoid running them twice the startup code has to call this word." } ;
-
-HELP: parse-command-line
-{ $description "Called on startup to process command line arguments. This sets global variables with " { $link cli-param } ", runs source files, and evaluates the string given by the " { $snippet "-e" } " switch, if there is one." } ;
index 80f0b4f51570d5fe816651ca32f052484da9b782..b5b2be509581bbb15ffdc19afe4d6d2fba80be59 100755 (executable)
@@ -23,3 +23,30 @@ IN: compiler.constants
 : word-code-offset ( -- n ) 10 bootstrap-cells object tag-number - ;
 : array-start-offset ( -- n ) 2 bootstrap-cells object tag-number - ;
 : compiled-header-size ( -- n ) 4 bootstrap-cells ;
+
+! Relocation classes
+: rc-absolute-cell    0 ;
+: rc-absolute         1 ;
+: rc-relative         2 ;
+: rc-absolute-ppc-2/2 3 ;
+: rc-relative-ppc-2   4 ;
+: rc-relative-ppc-3   5 ;
+: rc-relative-arm-3   6 ;
+: rc-indirect-arm     7 ;
+: rc-indirect-arm-pc  8 ;
+
+! Relocation types
+: rt-primitive 0 ;
+: rt-dlsym     1 ;
+: rt-literal   2 ;
+: rt-dispatch  3 ;
+: rt-xt        4 ;
+: rt-here      5 ;
+: rt-label     6 ;
+: rt-immediate 7 ;
+
+: rc-absolute? ( n -- ? )
+    [ rc-absolute-ppc-2/2 = ]
+    [ rc-absolute-cell = ]
+    [ rc-absolute = ]
+    tri or or ;
index 45238ab00ad2c0040ac7bf9d2c043226ee9710cb..5d485b13d4e76bf6c87e35fd6808783e69366b00 100755 (executable)
@@ -4,7 +4,7 @@ kernel vectors arrays effects sequences ;
 IN: compiler.generator
 
 ARTICLE: "generator" "Compiled code generator"
-"Most of the words in the " { $vocab-link "generator" } " vocabulary are internal to the compiler and user code has no reason to call them."
+"Most of the words in the " { $vocab-link "compiler.generator" } " vocabulary are internal to the compiler and user code has no reason to call them."
 $nl
 "Debugging information can be enabled or disabled; this hook is used by " { $link "tools.deploy" } ":"
 { $subsection compiled-stack-traces? }
index b995e6d73767efe13ab8c9f455e021d6d857b764..471c05ee59c983bb10d19053a948fbf2ee5f71b8 100644 (file)
@@ -4,20 +4,42 @@ USING: kernel classes.tuple classes.tuple.private math arrays
 byte-arrays words stack-checker.known-words ;
 IN: compiler.intrinsics
 
-: (tuple) ( layout -- tuple )
-    "BUG: missing (tuple) intrinsic" throw ;
+ERROR: missing-intrinsic ;
+
+: (tuple) ( n -- tuple ) missing-intrinsic ;
 
 \ (tuple) { tuple-layout } { tuple } define-primitive
 \ (tuple) make-flushable
 
-: (array) ( n -- array )
-    "BUG: missing (array) intrinsic" throw ;
+: (array) ( n -- array ) missing-intrinsic ;
 
 \ (array) { integer } { array } define-primitive
 \ (array) make-flushable
 
-: (byte-array) ( n -- byte-array )
-    "BUG: missing (byte-array) intrinsic" throw ;
+: (byte-array) ( n -- byte-array ) missing-intrinsic ;
 
 \ (byte-array) { integer } { byte-array } define-primitive
 \ (byte-array) make-flushable
+
+: (ratio) ( -- ratio ) missing-intrinsic ;
+
+\ (ratio) { } { ratio } define-primitive
+\ (ratio) make-flushable
+
+: (complex) ( -- complex ) missing-intrinsic ;
+
+\ (complex) { } { complex } define-primitive
+\ (complex) make-flushable
+
+: (wrapper) ( -- wrapper ) missing-intrinsic ;
+
+\ (wrapper) { } { wrapper } define-primitive
+\ (wrapper) make-flushable
+
+: (set-slot) ( val obj n -- ) missing-intrinsic ;
+
+\ (set-slot) { object object fixnum } { } define-primitive
+
+: (write-barrier) ( obj -- ) missing-intrinsic ;
+
+\ (write-barrier) { object } { } define-primitive
index 0891a6629cc9384fed22064a9d84cd832a2a8a47..5f8de4eb4923753484a99562a30141b3ef01bc4d 100644 (file)
@@ -298,6 +298,12 @@ SYMBOL: value-infos
 : node-output-infos ( node -- seq )
     dup out-d>> [ node-value-info ] with map ;
 
+: first-literal ( #call -- obj )
+    dup in-d>> first node-value-info literal>> ;
+
+: last-literal ( #call -- obj )
+    dup out-d>> peek node-value-info literal>> ;
+
 : immutable-tuple-boa? ( #call -- ? )
     dup word>> \ <tuple-boa> eq? [
         dup in-d>> peek node-value-info
index eab0ed4cb415efccab028709fbcc5e96b9fbc5c9..ab3ca7ed4a27ffc175703ec4c51e29b77d13ba12 100755 (executable)
@@ -4,8 +4,10 @@ USING: concurrency.futures concurrency.count-downs sequences
 kernel ;\r
 IN: concurrency.combinators\r
 \r
+<PRIVATE\r
 : (parallel-each) ( n quot -- )\r
     >r <count-down> r> keep await ; inline\r
+PRIVATE>\r
 \r
 : parallel-each ( seq quot -- )\r
     over length [\r
@@ -20,7 +22,9 @@ IN: concurrency.combinators
 : parallel-filter ( seq quot -- newseq )\r
     over >r pusher >r each r> r> like ; inline\r
 \r
+<PRIVATE\r
 : future-values dup [ ?future ] change-each ; inline\r
+PRIVATE>\r
 \r
 : parallel-map ( seq quot -- newseq )\r
     [ curry future ] curry map future-values ;\r
diff --git a/basis/concurrency/combinators/tags.txt b/basis/concurrency/combinators/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/conditions/tags.txt b/basis/concurrency/conditions/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
index 93cef250a193625abe8aa853c1fb996a4ae12890..c4bc92c688145c09945c2354eef123fbb41982c6 100755 (executable)
@@ -11,14 +11,18 @@ TUPLE: count-down n promise ;
 : count-down-check ( count-down -- )\r
     dup n>> zero? [ t swap promise>> fulfill ] [ drop ] if ;\r
 \r
+ERROR: invalid-count-down-count count ;\r
+\r
 : <count-down> ( n -- count-down )\r
-    dup 0 < [ "Invalid count for count down" throw ] when\r
+    dup 0 < [ invalid-count-down-count ] when\r
     <promise> \ count-down boa\r
     dup count-down-check ;\r
 \r
+ERROR: count-down-already-done ;\r
+\r
 : count-down ( count-down -- )\r
     dup n>> dup zero?\r
-    [ "Count down already done" throw ]\r
+    [ count-down-already-done ]\r
     [ 1- >>n count-down-check ] if ;\r
 \r
 : await-timeout ( count-down timeout -- )\r
diff --git a/basis/concurrency/count-downs/tags.txt b/basis/concurrency/count-downs/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
index 50cfa263f67ec6a7bc51030efec316349a6c03d8..b7861c668941f79de096d9da94744e546039ca68 100644 (file)
@@ -1,2 +1,2 @@
+concurrency
 enterprise
-extensions
diff --git a/basis/concurrency/exchangers/tags.txt b/basis/concurrency/exchangers/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/flags/tags.txt b/basis/concurrency/flags/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/futures/tags.txt b/basis/concurrency/futures/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/locks/tags.txt b/basis/concurrency/locks/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/mailboxes/tags.txt b/basis/concurrency/mailboxes/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
index 12b5d270d4971a38090ba9006209c37e9b22804c..03d130452717e34eac12206d085027c3e3d5ad8f 100755 (executable)
@@ -4,7 +4,7 @@
 ! Concurrency library for Factor, based on Erlang/Termite style\r
 ! concurrency.\r
 USING: kernel threads concurrency.mailboxes continuations\r
-namespaces assocs random accessors ;\r
+namespaces assocs random accessors summary ;\r
 IN: concurrency.messaging\r
 \r
 GENERIC: send ( message thread -- )\r
@@ -52,9 +52,14 @@ TUPLE: reply data tag ;
     [ >r tag>> r> tag>> = ]\r
     [ 2drop f ] if ;\r
 \r
+ERROR: cannot-send-synchronous-to-self message thread ;\r
+\r
+M: cannot-send-synchronous-to-self summary\r
+    drop "Cannot synchronous send to myself" ;\r
+\r
 : send-synchronous ( message thread -- reply )\r
     dup self eq? [\r
-        "Cannot synchronous send to myself" throw\r
+        cannot-send-synchronous-to-self\r
     ] [\r
         >r <synchronous> dup r> send\r
         [ synchronous-reply? ] curry receive-if\r
diff --git a/basis/concurrency/messaging/tags.txt b/basis/concurrency/messaging/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
index 511decdf352a63268c71de05b9c52199f90d2fee..382697e04f1c7cb2b9c409ff3cc312d96895ffa7 100755 (executable)
@@ -11,9 +11,10 @@ TUPLE: promise mailbox ;
 : promise-fulfilled? ( promise -- ? )\r
     mailbox>> mailbox-empty? not ;\r
 \r
+ERROR: promise-already-fulfilled promise ;\r
 : fulfill ( value promise -- )\r
     dup promise-fulfilled? [ \r
-        "Promise already fulfilled" throw\r
+        promise-already-fulfilled\r
     ] [\r
         mailbox>> mailbox-put\r
     ] if ;\r
diff --git a/basis/concurrency/promises/tags.txt b/basis/concurrency/promises/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
diff --git a/basis/concurrency/semaphores/tags.txt b/basis/concurrency/semaphores/tags.txt
new file mode 100644 (file)
index 0000000..ce745d1
--- /dev/null
@@ -0,0 +1 @@
+concurrency
index bb21391f0a875d0d42586dee73f518c99b7639f6..6bec4b23c0958453baea559550e09fb818c27dc3 100644 (file)
@@ -3,13 +3,10 @@
 USING: alien alien.c-types alien.strings alien.syntax kernel
 math sequences namespaces make assocs init accessors
 continuations combinators core-foundation
-core-foundation.run-loop io.encodings.utf8 destructors ;
+core-foundation.run-loop core-foundation.run-loop.thread
+io.encodings.utf8 destructors ;
 IN: core-foundation.fsevents
 
-! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
-! FSEventStream API, Leopard only !
-! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
-
 : kFSEventStreamCreateFlagUseCFTypes 2 ; inline
 : kFSEventStreamCreateFlagWatchRoot 4 ; inline
 
index 5ffcafbbafb5fba51af4f8d29be8420f42ba0c8d..e30cc2eb6013141d3d8b139f4355901fcf430b4f 100644 (file)
@@ -35,5 +35,3 @@ FUNCTION: SInt32 CFRunLoopRunInMode (
 
 : start-run-loop-thread ( -- )
     [ run-loop-thread t ] "CFRunLoop dispatcher" spawn-server drop ;
-
-[ start-run-loop-thread ] "core-foundation.run-loop" add-init-hook
diff --git a/basis/core-foundation/run-loop/thread/thread.factor b/basis/core-foundation/run-loop/thread/thread.factor
new file mode 100644 (file)
index 0000000..326226e
--- /dev/null
@@ -0,0 +1,8 @@
+! Copyright (C) 2008 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: init core-foundation.run-loop ;
+IN: core-foundation.run-loop.thread
+
+! Load this vocabulary if you need a run loop running.
+
+[ start-run-loop-thread ] "core-foundation.run-loop.thread" add-init-hook
index f8e3956b3e7e9be59788dafc66f6ec1d6671d0af..74b72b87893b89500da72a9eecbfd3229330763f 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: classes kernel help.markup help.syntax sequences
-alien assocs strings math multiline ;
+alien assocs strings math multiline quotations ;
 IN: db
 
 HELP: db
@@ -45,7 +45,22 @@ HELP: prepared-statement
 { $description } ;
 
 HELP: result-set
-{ $description } ;
+{ $description "An object encapsulating a raw SQL result object. There are two ways in which a result set can be accessed, but they are specific to the database backend in use."
+    { $subsection "db-random-access-result-set" }
+    { $subsection "db-sequential-result-set" }
+} ;
+
+HELP: init-result-set
+{ $values
+     { "result-set" result-set } }
+{ $description "" } ;
+
+HELP: new-result-set
+{ $values
+     { "query" "a query" } { "handle" alien } { "class" class }
+     { "result-set" result-set } }
+{ $description "Creates a new " { $link result-set } " object of type " { $snippet "class" } "." } ;
+
 
 HELP: new-statement
 { $values { "sql" string } { "in" sequence } { "out" sequence } { "class" class } { "statement" statement } }
@@ -81,7 +96,7 @@ HELP: query-results
 { $values { "query" object }
     { "result-set" result-set }
 }
-{ $description "" } ;
+{ $description "Returns a " { $link result-set } " object representing the reults of a SQL query." } ;
 
 HELP: #rows
 { $values { "result-set" result-set } { "n" integer } }
@@ -95,36 +110,126 @@ HELP: row-column
 { $values { "result-set" result-set } { "column" integer }
     { "obj" object }
 }
-{ $description "" } ;
+{ $description "Returns the value indexed by " { $snippet "column" } " in the current row of a " { $link result-set } "." } ;
 
 HELP: row-column-typed
 { $values { "result-set" result-set } { "column" integer }
     { "sql" "sql" } }
-{ $description "" } ;
+{ $description "Returns the value indexed by " { $snippet "column" } " in the current row of a " { $link result-set } " and converts the result based on a type stored in the " { $link result-set } "'s " { $slot "out-params" } "." } ;
 
 HELP: advance-row
 { $values { "result-set" result-set } }
-;
+{ $description "Advanced the pointer to an underlying SQL result set stored in a " { $link result-set } " object." } ;
 
 HELP: more-rows?
 { $values { "result-set" result-set } { "?" "a boolean" } }
-;
+{ $description "Returns true if the " { $link result-set } " has more rows to traverse." } ;
 
 HELP: execute-statement*
 { $values { "statement" statement } { "type" object } }
 { $description } ;
 
+HELP: execute-one-statement
+{ $values
+     { "statement" null } }
+{ $description "" } ;
+
 HELP: execute-statement
 { $values { "statement" statement } }
-{ $description } ;
+{ $description "" } ;
+
+
+
+
+
+
+HELP: begin-transaction
+{ $description "Begins a new transaction. User code should make use of the " { $link with-transaction } " combinator." } ;
+
+HELP: bind-statement
+{ $values
+     { "obj" object } { "statement" null } }
+{ $description "" } ;
+
+HELP: commit-transaction
+{ $description "Commits a transaction. User code should make use of the " { $link with-transaction } " combinator." } ;
 
-ARTICLE: "db" "Low-level database library"
+HELP: default-query
+{ $values
+     { "query" null }
+     { "result-set" null } }
+{ $description "" } ;
+
+HELP: in-transaction
+{ $description "A variable that is set true when a transaction is in progress." } ;
+
+HELP: in-transaction?
+{ $values
+     { "?" "a boolean" } }
+{ $description "Returns true if there is currently a transaction in progress in this scope." } ;
+
+HELP: query-each
+{ $values
+     { "statement" null } { "quot" quotation } }
+{ $description "" } ;
+
+HELP: query-map
+{ $values
+     { "statement" null } { "quot" quotation }
+     { "seq" sequence } }
+{ $description "" } ;
+
+HELP: rollback-transaction
+{ $description "Rolls back a transaction; no data is committed to the database. User code should make use of the " { $link with-transaction } " combinator." } ;
+
+HELP: sql-command
+{ $values
+     { "sql" string } }
+{ $description "Executes a SQL string using the databse in the " { $link db } " symbol." } ;
+
+HELP: sql-query
+{ $values
+     { "sql" string }
+     { "rows" "an array of arrays of strings" } }
+{ $description "Runs a SQL query of raw text in the database in the " { $link db } " symbol. Each row is returned as an array of strings; no type-conversions are done on the resulting data." } ;
+
+{ sql-command sql-query } related-words
+
+HELP: sql-row
+{ $values
+     { "result-set" result-set }
+     { "seq" sequence } }
+{ $description "Returns the current row in a " { $link result-set } " as an array of strings." } ;
+
+HELP: sql-row-typed
+{ $values
+     { "result-set" result-set }
+     { "seq" sequence } }
+{ $description "Returns the current row in a " { $link result-set } " as an array of typed Factor objects." } ;
+
+{ sql-row sql-row-typed } related-words
+
+HELP: with-db
+{ $values
+     { "seq" sequence } { "class" class } { "quot" quotation } }
+{ $description "Calls the quotation with a database bound to the " { $link db } " symbol. The database called is based on the " { $snippet "class" } " with the " } ;
+
+HELP: with-transaction
+{ $values
+     { "quot" quotation } }
+{ $description "" } ;
+
+ARTICLE: "db" "Database library"
 { $subsection "db-custom-database-combinators" }
 { $subsection "db-protocol" }
+{ $subsection "db-result-sets" }
 { $subsection "db-lowlevel-tutorial" }
 "Higher-level database:"
 { $vocab-subsection "Database types" "db.types" }
 { $vocab-subsection "High-level tuple/database integration" "db.tuples" }
+! { $subsection "db-tuples" }
+! { $subsection "db-tuples-protocol" }
+! { $subsection "db-tuples-tutorial" }
 "Supported database backends:"
 { $vocab-subsection "SQLite" "db.sqlite" }
 { $vocab-subsection "PostgreSQL" "db.postgresql" }
@@ -132,6 +237,40 @@ ARTICLE: "db" "Low-level database library"
 { $subsection "db-porting-the-library" }
 ;
 
+ARTICLE: "db-random-access-result-set" "Random access result sets"
+"Random-access result sets do not have to be traversed in order. For instance, PostgreSQL's result set object can be accessed as a matrix with i,j coordinates."
+$nl
+"Databases which work in this way must provide methods for the following traversal words:"
+{ $subsection #rows }
+{ $subsection #columns }
+{ $subsection row-column }
+{ $subsection row-column-typed } ;
+
+ARTICLE: "db-sequential-result-set" "Sequential result sets"
+"Sequential result sets can be iterated one element after the next.  SQLite's result sets offer this method of traversal."
+$nl
+"Databases which work in this way must provide methods for the following traversal words:"
+{ $subsection more-rows? }
+{ $subsection advance-row }
+{ $subsection row-column }
+{ $subsection row-column-typed } ;
+
+ARTICLE: "db-result-sets" "Result sets"
+"Result sets are the encapsulated, database-specific results from a SQL query."
+$nl
+"Two possible protocols for iterating over result sets exist:"
+{ $subsection "db-random-access-result-set" }
+{ $subsection "db-sequential-result-set" }
+"Query the number of rows or columns:"
+{ $subsection #rows }
+{ $subsection #columns }
+"Traversing a result set:"
+{ $subsection advance-row }
+{ $subsection more-rows? }
+"Pulling out a single row of results:"
+{ $subsection row-column }
+{ $subsection row-column-typed } ;
+
 ARTICLE: "db-protocol" "Low-level database protocol"
 "The high-level protocol (see " { $vocab-link "db.tuples" } ") uses this low-level protocol for executing statements and queries."
 ;
@@ -144,7 +283,6 @@ ARTICLE: "db-porting-the-library" "Porting the database library"
 "This section is not yet written."
 ;
 
-
 ARTICLE: "db-custom-database-combinators" "Custom database combinators"
 "Every database library requires some effort on the programmer's part to initialize and open a database.  SQLite uses files on your harddisk, so a simple pathname is all the setup required. With PostgreSQL, you log in to a networked server as a user on a specfic port." $nl
 
@@ -155,7 +293,6 @@ USING: db.sqlite db io.files ;
     { "my-database.db" temp-file } sqlite-db rot with-db ;
 "> }
 
-
 ;
 
 ABOUT: "db"
index eac22a2999684e3144a647eb00ad2fe596b29558..87bf21d26139e431bccce30bb5a2686713925abf 100755 (executable)
@@ -80,11 +80,14 @@ GENERIC: execute-statement* ( statement type -- )
 M: object execute-statement* ( statement type -- )
     drop query-results dispose ;
 
+: execute-one-statement ( statement -- )
+    dup type>> execute-statement* ;
+
 : execute-statement ( statement -- )
     dup sequence? [
-        [ execute-statement ] each
+        [ execute-one-statement ] each
     ] [
-        dup type>> execute-statement*
+        execute-one-statement
     ] if ;
 
 : bind-statement ( obj statement -- )
index 38fa4cc715227d59ca01ad11a634f56ec2908db3..28548d1260efe456c23820552e89fa9fe1c05d44 100755 (executable)
@@ -5,7 +5,7 @@ kernel math math.parser namespaces make prettyprint quotations
 sequences debugger db db.postgresql.lib db.postgresql.ffi
 db.tuples db.types tools.annotations math.ranges
 combinators classes locals words tools.walker
-nmake accessors random db.queries destructors ;
+nmake accessors random db.queries destructors db.tuples.private ;
 USE: tools.walker
 IN: db.postgresql
 
@@ -37,8 +37,7 @@ M: postgresql-db db-open ( db -- db )
 M: postgresql-db dispose ( db -- )
     handle>> PQfinish ;
 
-M: postgresql-statement bind-statement* ( statement -- )
-    drop ;
+M: postgresql-statement bind-statement* ( statement -- ) drop ;
 
 GENERIC: postgresql-bind-conversion ( tuple object -- low-level-binding )
 
@@ -67,11 +66,11 @@ M: postgresql-result-set #columns ( result-set -- n )
     [ handle>> ] [ n>> ] bi ;
 
 M: postgresql-result-set row-column ( result-set column -- object )
-    >r result-handle-n r> pq-get-string ;
+    [ result-handle-n ] dip pq-get-string ;
 
 M: postgresql-result-set row-column-typed ( result-set column -- object )
     dup pick out-params>> nth type>>
-    >r >r result-handle-n r> r> postgresql-column-typed ;
+    [ result-handle-n ] 2dip postgresql-column-typed ;
 
 M: postgresql-statement query-results ( query -- result-set )
     dup bind-params>> [
@@ -126,13 +125,20 @@ M: postgresql-db bind# ( spec object -- )
 
 : create-table-sql ( class -- statement )
     [
+        dupd
         "create table " 0% 0%
         "(" 0% [ ", " 0% ] [
             dup column-name>> 0%
             " " 0%
             dup type>> lookup-create-type 0%
             modifiers 0%
-        ] interleave ");" 0%
+        ] interleave
+
+        ", " 0%
+        find-primary-key
+        "primary key(" 0%
+        [ "," 0% ] [ column-name>> 0% ] interleave
+        "));" 0%
     ] query-make ;
 
 : create-function-sql ( class -- statement )
@@ -160,8 +166,7 @@ M: postgresql-db bind# ( spec object -- )
 M: postgresql-db create-sql-statement ( class -- seq )
     [
         [ create-table-sql , ] keep
-        dup db-columns find-primary-key db-assigned-id-spec?
-        [ create-function-sql , ] [ drop ] if
+        dup db-assigned? [ create-function-sql , ] [ drop ] if
     ] { } make ;
 
 : drop-function-sql ( class -- statement )
@@ -181,15 +186,14 @@ M: postgresql-db create-sql-statement ( class -- seq )
 M: postgresql-db drop-sql-statement ( class -- seq )
     [
         [ drop-table-sql , ] keep
-        dup db-columns find-primary-key db-assigned-id-spec?
-        [ drop-function-sql , ] [ drop ] if
+        dup db-assigned? [ drop-function-sql , ] [ drop ] if
     ] { } make ;
 
 M: postgresql-db <insert-db-assigned-statement> ( class -- statement )
     [
         "select add_" 0% 0%
         "(" 0%
-        dup find-primary-key 2,
+        dup find-primary-key first 2,
         remove-id
         [ ", " 0% ] [ bind% ] interleave
         ");" 0%
@@ -218,14 +222,23 @@ M: postgresql-db <insert-user-assigned-statement> ( class -- statement )
         ");" 0%
     ] query-make ;
 
-M: postgresql-db insert-tuple* ( tuple statement -- )
+M: postgresql-db insert-tuple-set-key ( tuple statement -- )
     query-modify-tuple ;
 
 M: postgresql-db persistent-table ( -- hashtable )
     H{
-        { +db-assigned-id+ { "integer" "serial primary key" f } }
-        { +user-assigned-id+ { f f "primary key" } }
-        { +random-id+ { "bigint" "bigint primary key" f } }
+        { +db-assigned-id+ { "integer" "serial" f } }
+        { +user-assigned-id+ { f f f } }
+        { +random-id+ { "bigint" "bigint" f } }
+
+        { +foreign-id+ { f f "references" } }
+
+        { +on-delete+ { f f "on delete" } }
+        { +restrict+ { f f "restrict" } }
+        { +cascade+ { f f "cascade" } }
+        { +set-null+ { f f "set null" } }
+        { +set-default+ { f f "set default" } }
+
         { TEXT { "text" "text" f } }
         { VARCHAR { "varchar" "varchar" f } }
         { INTEGER { "integer" "integer" f } }
@@ -240,7 +253,6 @@ M: postgresql-db persistent-table ( -- hashtable )
         { BLOB { "bytea" "bytea" f } }
         { FACTOR-BLOB { "bytea" "bytea" f } }
         { URL { "varchar" "varchar" f } }
-        { +foreign-id+ { f f "references" } }
         { +autoincrement+ { f f "autoincrement" } }
         { +unique+ { f f "unique" } }
         { +default+ { f f "default" } }
@@ -256,10 +268,6 @@ M: postgresql-db compound ( string object -- string' )
     over {
         { "default" [ first number>string join-space ] }
         { "varchar" [ first number>string paren append ] }
-        { "references" [
-                first2 >r [ unparse join-space ] keep db-columns r>
-                swap [ slot-name>> = ] with find nip
-                column-name>> paren append
-            ] }
+        { "references" [ >reference-string ] }
         [ drop no-compound-found ]
     } case ;
index 89c28b52623d627876c9648038d4b30be425c370..f7809de578180097928ae73c859464d767addbd4 100644 (file)
@@ -3,7 +3,7 @@
 USING: accessors kernel math namespaces make sequences random
 strings math.parser math.intervals combinators math.bitwise
 nmake db db.tuples db.types db.sql classes words shuffle arrays
-destructors continuations ;
+destructors continuations db.tuples.private ;
 IN: db.queries
 
 GENERIC: where ( specs obj -- )
@@ -46,13 +46,18 @@ M: retryable execute-statement* ( statement type -- )
     [ db-columns ] [ db-table ] bi ;
 
 : query-make ( class quot -- )
-    >r sql-props r>
-    [ 0 sql-counter rot with-variable ] curry { "" { } { } } nmake
+    [ sql-props ] dip
+    [ 0 sql-counter rot with-variable ] curry
+    { "" { } { } } nmake
     <simple-statement> maybe-make-retryable ; inline
 
 : where-primary-key% ( specs -- )
     " where " 0%
-    find-primary-key dup column-name>> 0% " = " 0% bind% ;
+    find-primary-key [
+        " and " 0%
+    ] [
+        dup column-name>> 0% " = " 0% bind%
+    ] interleave ;
 
 M: db <update-tuple-statement> ( class -- statement )
     [
@@ -121,16 +126,15 @@ M: string where ( spec obj -- ) object-where ;
         dup double-infinite-interval? [ drop f ] when
     ] with filter ;
 
-: where-clause ( tuple specs -- )
-    dupd filter-slots [
-        drop
+: many-where ( tuple seq -- )
+    " where " 0% [
+        " and " 0%
     ] [
-        " where " 0% [
-            " and " 0%
-        ] [
-            2dup slot-name>> swap get-slot-named where
-        ] interleave drop
-    ] if-empty ;
+        2dup slot-name>> swap get-slot-named where
+    ] interleave drop ;
+
+: where-clause ( tuple specs -- )
+    dupd filter-slots [ drop ] [ many-where ] if-empty ;
 
 M: db <delete-tuples-statement> ( tuple table -- sql )
     [
@@ -168,7 +172,7 @@ M: db <select-by-slots-statement> ( tuple class -- statement )
         number>string " limit " swap 3append
     ] curry change-sql drop ;
 
-: make-query ( tuple query -- tuple' )
+: make-query* ( tuple query -- tuple' )
     dupd
     {
         [ group>> [ drop ] [ do-group ] if-empty ]
@@ -177,8 +181,9 @@ M: db <select-by-slots-statement> ( tuple class -- statement )
         [ offset>> [ do-offset ] [ drop ] if* ]
     } 2cleave ;
 
-M: db <query> ( tuple class query -- tuple )
-    [ <select-by-slots-statement> ] dip make-query ;
+M: db query>statement ( query -- tuple )
+    [ tuple>> dup class ] keep
+    [ <select-by-slots-statement> ] dip make-query* ;
 
 ! select ID, NAME, SCORE from EXAM limit 1 offset 3
 
@@ -194,11 +199,10 @@ M: db <query> ( tuple class query -- tuple )
     >r >r parse-sql 4drop r> r>
     <simple-statement> maybe-make-retryable do-select ;
 
-M: db <count-statement> ( tuple class groups -- statement )
-    \ query new
-        swap >>group
+M: db <count-statement> ( query -- statement )
+    [ tuple>> dup class ] keep
     [ [ "select count(*) from " 0% 0% where-clause ] query-make ]
-    dip make-query ;
+    dip make-query* ;
 
 : create-index ( index-name table-name columns -- )
     [
index 1eb9b566d33b9f5114987ee0f8b50e30bdc036c7..aab1e5f40f892f47af8a18ff489effaec2633e7d 100755 (executable)
@@ -5,7 +5,7 @@ io.files kernel math math.parser namespaces prettyprint
 sequences strings classes.tuple alien.c-types continuations
 db.sqlite.lib db.sqlite.ffi db.tuples words db.types combinators
 math.intervals io nmake accessors vectors math.ranges random
-math.bitwise db.queries destructors ;
+math.bitwise db.queries destructors db.tuples.private ;
 IN: db.sqlite
 
 TUPLE: sqlite-db < db path ;
@@ -88,7 +88,7 @@ M: sqlite-statement bind-tuple ( tuple statement -- )
     db get handle>> sqlite3_last_insert_rowid
     dup zero? [ "last-id failed" throw ] when ;
 
-M: sqlite-db insert-tuple* ( tuple statement -- )
+M: sqlite-db insert-tuple-set-key ( tuple statement -- )
     execute-statement last-insert-id swap set-primary-key ;
 
 M: sqlite-result-set #columns ( result-set -- n )
@@ -114,13 +114,20 @@ M: sqlite-statement query-results ( query -- result-set )
 
 M: sqlite-db create-sql-statement ( class -- statement )
     [
+        dupd
         "create table " 0% 0%
         "(" 0% [ ", " 0% ] [
             dup column-name>> 0%
             " " 0%
             dup type>> lookup-create-type 0%
             modifiers 0%
-        ] interleave ");" 0%
+        ] interleave
+
+        ", " 0%
+        find-primary-key
+        "primary key(" 0%
+        [ "," 0% ] [ column-name>> 0% ] interleave
+        "));" 0%
     ] query-make ;
 
 M: sqlite-db drop-sql-statement ( class -- statement )
@@ -161,23 +168,31 @@ M: sqlite-db bind% ( spec -- )
 
 M: sqlite-db persistent-table ( -- assoc )
     H{
-        { +db-assigned-id+ { "integer primary key" "integer primary key" "primary key" } }
-        { +user-assigned-id+ { f f "primary key" } }
-        { +random-id+ { "integer primary key" "integer primary key" "primary key" } }
-        { INTEGER { "integer" "integer" "primary key" } }
-        { BIG-INTEGER { "bigint" "bigint" } }
-        { SIGNED-BIG-INTEGER { "bigint" "bigint" } }
-        { UNSIGNED-BIG-INTEGER { "bigint" "bigint" } }
-        { TEXT { "text" "text" } }
-        { VARCHAR { "text" "text" } }
-        { DATE { "date" "date" } }
-        { TIME { "time" "time" } }
-        { DATETIME { "datetime" "datetime" } }
-        { TIMESTAMP { "timestamp" "timestamp" } }
-        { DOUBLE { "real" "real" } }
-        { BLOB { "blob" "blob" } }
-        { FACTOR-BLOB { "blob" "blob" } }
-        { URL { "text" "text" } }
+        { +db-assigned-id+ { "integer" "integer" f } }
+        { +user-assigned-id+ { f f f } }
+        { +random-id+ { "integer" "integer" f } }
+        { +foreign-id+ { "integer" "integer" "references" } }
+
+        { +on-delete+ { f f "on delete" } }
+        { +restrict+ { f f "restrict" } }
+        { +cascade+ { f f "cascade" } }
+        { +set-null+ { f f "set null" } }
+        { +set-default+ { f f "set default" } }
+
+        { INTEGER { "integer" "integer" f } }
+        { BIG-INTEGER { "bigint" "bigint" f } }
+        { SIGNED-BIG-INTEGER { "bigint" "bigint" f } }
+        { UNSIGNED-BIG-INTEGER { "bigint" "bigint" f } }
+        { TEXT { "text" "text" f } }
+        { VARCHAR { "text" "text" f } }
+        { DATE { "date" "date" f } }
+        { TIME { "time" "time" f } }
+        { DATETIME { "datetime" "datetime" f } }
+        { TIMESTAMP { "timestamp" "timestamp" f } }
+        { DOUBLE { "real" "real" f } }
+        { BLOB { "blob" "blob" f } }
+        { FACTOR-BLOB { "blob" "blob" f } }
+        { URL { "text" "text" f } }
         { +autoincrement+ { f f "autoincrement" } }
         { +unique+ { f f "unique" } }
         { +default+ { f f "default" } }
@@ -188,8 +203,9 @@ M: sqlite-db persistent-table ( -- assoc )
         { random-generator { f f f } }
     } ;
 
-M: sqlite-db compound ( str seq -- str' )
+M: sqlite-db compound ( string seq -- new-string )
     over {
         { "default" [ first number>string join-space ] }
-        [ 2drop ] 
+        { "references" [ >reference-string ] }
+        [ 2drop ]
     } case ;
index 26ecec03656dd3d3a04db21a53a0c945b0316a5d..d7ee3a5ad2beca27977962d7168d7e319b6c8eea 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: classes help.markup help.syntax io.streams.string kernel
-quotations sequences strings multiline math ;
+quotations sequences strings multiline math db.types ;
 IN: db.tuples
 
 HELP: define-persistent
@@ -11,7 +11,18 @@ HELP: define-persistent
 { $list
     { "a slot name from the " { $snippet "tuple class" } }
     { "the name of a database column that maps to the slot" }        { "a database type (see " { $link "db.types" } ")" }
-} } ;
+} "Throws an error if the slot name (column one from each row) is not a slot in the tuple or its superclases." }
+{ $examples
+    { $unchecked-example "USING: db.tuples db.types ;"
+        "TUPLE: boat id year name ;"
+        "boat \"BOAT\" {"
+        "    { \"id\" \"ID\" +db-assigned-id+ }"
+        "    { \"year\" \"YEAR\" INTEGER }"
+        "    { \"name\" \"NAME\" TEXT }"
+        "} define-persistent"
+        ""
+    }
+} ;
 
 HELP: create-table
 { $values
@@ -64,36 +75,35 @@ HELP: delete-tuples
 
 HELP: select-tuple
 { $values
-     { "tuple" tuple }
+     { "query/tuple" tuple }
      { "tuple/f" "a tuple or f" } }
 { $description "A SQL query is constructed from the slots of the exemplar tuple that are not " { $link f } ". Returns a single tuple from the database if it matches the query constructed from the exemplar tuple." } ;
 
 HELP: select-tuples
 { $values
-     { "tuple" tuple }
+     { "query/tuple" tuple }
      { "tuples" "an array of tuples" } }
 { $description "A SQL query is constructed from the slots of the exemplar tuple that are not " { $link f } ". Returns a multiple tuples from the database that match the query constructed from the exemplar tuple." } ;
 
 HELP: count-tuples
 { $values
-     { "tuple" tuple } { "groups" "an array of slots to group by" }
+     { "query/tuple" tuple }
      { "n" integer } }
-{ $description "" } ;
+{ $description "Returns the number of items that would be returned if the query were a select query. Counting the tuples with this word is more efficient than calling " { $link length } " on the result of " { $link select-tuples } "." } ;
+
+{ select-tuple select-tuples count-tuples } related-words
 
-HELP: query
-{ $values
-     { "tuple" tuple } { "query" query }
-     { "tuples" "a sequence of tuples" } }
-{ $description "Allows for queries with group by, order by, limit, and offset clauses.  " } ;
 
-{ select-tuple select-tuples count-tuples query } related-words
 
 ARTICLE: "db-tuples" "High-level tuple/database integration"
 "Start with a tutorial:"
 { $subsection "db-tuples-tutorial" }
+"Database types supported:"
+{ $subsection "db.types" }
 "Useful words:"
 { $subsection "db-tuples-words" }
-
+"For porting db.tuples to other databases:"
+{ $subsection "db-tuples-protocol" }
 ;
 
 ARTICLE: "db-tuples-words" "High-level tuple/database words"
@@ -115,12 +125,9 @@ ARTICLE: "db-tuples-words" "High-level tuple/database words"
 "Querying tuples:"
 { $subsection select-tuple }
 { $subsection select-tuples }
-{ $subsection count-tuples }
-"Advanced querying of tuples:"
-{ $subsection query } ;
-
+{ $subsection count-tuples } ;
 
-ARTICLE: "db-tuples-protocol" "High-level tuple/database protocol"
+ARTICLE: "db-tuples-protocol" "Tuple database protocol"
 ;
 
 ARTICLE: "db-tuples-tutorial" "Tuple database tutorial"
index 67e46f9e1825651d1989c55dfa114cedb28371fb..6a5e78aa4b9552391f86d9908200f7cf671170e0 100755 (executable)
@@ -4,9 +4,20 @@ USING: io.files kernel tools.test db db.tuples classes
 db.types continuations namespaces math math.ranges
 prettyprint calendar sequences db.sqlite math.intervals
 db.postgresql accessors random math.bitwise
-math.ranges strings urls fry ;
+math.ranges strings urls fry db.tuples.private ;
 IN: db.tuples.tests
 
+: test-sqlite ( quot -- )
+    [ ] swap '[
+        "tuples-test.db" temp-file sqlite-db _ with-db
+    ] unit-test ;
+
+: test-postgresql ( quot -- )
+    [ ] swap '[
+        { "localhost" "postgres" "foob" "factor-test" }
+        postgresql-db _ with-db
+    ] unit-test ;
+
 TUPLE: person the-id the-name the-number the-real
 ts date time blob factor-blob url ;
 
@@ -177,34 +188,55 @@ TUPLE: annotation n paste-id summary author mode contents ;
         { "channel" "CHANNEL" TEXT }
         { "mode" "MODE" TEXT }
         { "contents" "CONTENTS" TEXT }
-        { "date" "DATE" TIMESTAMP }
+        { "timestamp" "DATE" TIMESTAMP }
         { "annotations" { +has-many+ annotation } }
     } define-persistent
 
     annotation "ANNOTATION"
     {
         { "n" "ID" +db-assigned-id+ }
-        { "paste-id" "PASTE_ID" INTEGER { +foreign-id+ paste "n" } }
+        { "paste-id" "PASTE_ID" INTEGER { +foreign-id+ paste "n" }
+            +on-delete+ +cascade+ }
         { "summary" "SUMMARY" TEXT }
         { "author" "AUTHOR" TEXT }
         { "mode" "MODE" TEXT }
         { "contents" "CONTENTS" TEXT }
     } define-persistent ;
 
-! { "localhost" "postgres" "" "factor-test" } postgresql-db [
-    ! [ paste drop-table ] [ drop ] recover
-    ! [ annotation drop-table ] [ drop ] recover
-    ! [ paste drop-table ] [ drop ] recover
-    ! [ annotation drop-table ] [ drop ] recover
-    ! [ ] [ paste create-table ] unit-test
-    ! [ ] [ annotation create-table ] unit-test
-! ] with-db
+: test-paste-schema ( -- )
+    [ ] [ db-assigned-paste-schema ] unit-test
+    [ ] [ paste ensure-table ] unit-test
+    [ ] [ annotation ensure-table ] unit-test
+    [ ] [ annotation drop-table ] unit-test
+    [ ] [ paste drop-table ] unit-test
+    [ ] [ paste create-table ] unit-test
+    [ ] [ annotation create-table ] unit-test
 
-: test-sqlite ( quot -- )
-    [ ] swap '[ "tuples-test.db" temp-file sqlite-db _ with-db ] unit-test ;
+    [ ] [
+        paste new
+            "summary1" >>summary
+            "erg" >>author
+            "#lol" >>channel
+            "contents1" >>contents
+            now >>timestamp
+        insert-tuple
+    ] unit-test
 
-: test-postgresql ( quot -- )
-    [ ] swap '[ { "localhost" "postgres" "foob" "factor-test" } postgresql-db _ with-db ] unit-test ;
+    [ ] [
+        annotation new
+            1 >>paste-id
+            "annotation1" >>summary
+            "erg" >>author
+            "annotation contents" >>contents
+        insert-tuple
+    ] unit-test
+
+    [ ] [
+    ] unit-test
+    ;
+
+[ test-paste-schema ] test-sqlite
+[ test-paste-schema ] test-postgresql
 
 : test-repeated-insert
     [ ] [ person ensure-table ] unit-test
@@ -236,6 +268,17 @@ TUPLE: exam id name score ;
     exam boa ;
 
 : test-intervals ( -- )
+    [
+        exam "EXAM"
+        {
+            { "idd" "ID" +db-assigned-id+ }
+            { "named" "NAME" TEXT }
+            { "score" "SCORE" INTEGER }
+        } define-persistent
+    ] [
+        seq>> { "idd" "named" } =
+    ] must-fail-with
+
     exam "EXAM"
     {
         { "id" "ID" +db-assigned-id+ }
@@ -346,7 +389,7 @@ TUPLE: exam id name score ;
         T{ exam } select-tuples
     ] unit-test
 
-    [ 4 ] [ T{ exam } count-tuples ] unit-test ;
+    [ 4 ] [ T{ exam } count-tuples ] unit-test ;
 
 TUPLE: bignum-test id m n o ;
 : <bignum-test> ( m n o -- obj )
@@ -499,3 +542,42 @@ string-encoding-test "STRING_ENCODING_TEST" {
 \ ensure-table must-infer
 \ create-table must-infer
 \ drop-table must-infer
+
+: test-queries ( -- )
+    [ ] [ exam ensure-table ] unit-test
+    [ ] [ 1000 [ random-exam insert-tuple ] times ] unit-test
+    [ 5 ] [
+        <query>
+        T{ exam { score T{ interval { from { 0 t } } { to { 100 t } } } } }
+            >>tuple
+        5 >>limit select-tuples length
+    ] unit-test ;
+
+TUPLE: compound-foo a b c ;
+
+compound-foo "COMPOUND_FOO" 
+{
+    { "a" "A" INTEGER +user-assigned-id+ }
+    { "b" "B" INTEGER +user-assigned-id+ }
+    { "c" "C" INTEGER }
+} define-persistent
+
+: test-compound-primary-key ( -- )
+    [ ] [ compound-foo ensure-table ] unit-test
+    [ ] [ compound-foo drop-table ] unit-test
+    [ ] [ compound-foo create-table ] unit-test
+    [ ] [ 1 2 3 compound-foo boa insert-tuple ] unit-test
+    [ 1 2 3 compound-foo boa insert-tuple ] must-fail
+    [ ] [ 2 3 4 compound-foo boa insert-tuple ] unit-test
+    [ T{ compound-foo { a 2 } { b 3 } { c 4 } } ]
+    [ compound-foo new 4 >>c select-tuple ] unit-test ;
+
+[ test-compound-primary-key ] test-sqlite
+[ test-compound-primary-key ] test-postgresql
+
+: sqlite-test-db ( -- )
+    "tuples-test.db" temp-file sqlite-db make-db db-open db set ;
+
+: postgresql-test-db ( -- )
+    { "localhost" "postgres" "foob" "factor-test" } postgresql-db
+    make-db db-open db set ;
index 3c3bae3adcda98cf9d369ea0862d6a09c258cc31..7f567697d2ce0bf667faafb02f3a88fcb2217bd6 100755 (executable)
@@ -3,36 +3,10 @@
 USING: arrays assocs classes db kernel namespaces
 classes.tuple words sequences slots math accessors
 math.parser io prettyprint db.types continuations
-destructors mirrors ;
+destructors mirrors sets db.types ;
 IN: db.tuples
 
-: define-persistent ( class table columns -- )
-    >r dupd "db-table" set-word-prop dup r>
-    [ relation? ] partition swapd
-    dupd [ spec>tuple ] with map
-    "db-columns" set-word-prop
-    "db-relations" set-word-prop ;
-
-ERROR: not-persistent class ;
-
-: db-table ( class -- object )
-    dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
-
-: db-columns ( class -- object )
-    superclasses [ "db-columns" word-prop ] map concat ;
-
-: db-relations ( class -- object )
-    "db-relations" word-prop ;
-
-: set-primary-key ( key tuple -- )
-    [
-        class db-columns find-primary-key slot-name>>
-    ] keep set-slot-named ;
-
-SYMBOL: sql-counter
-: next-sql-counter ( -- str )
-    sql-counter [ inc ] [ get ] bi number>string ;
-
+<PRIVATE
 ! returns a sequence of prepared-statements
 HOOK: create-sql-statement db ( class -- object )
 HOOK: drop-sql-statement db ( class -- object )
@@ -42,19 +16,20 @@ HOOK: <insert-user-assigned-statement> db ( class -- object )
 HOOK: <update-tuple-statement> db ( class -- object )
 HOOK: <delete-tuples-statement> db ( tuple class -- object )
 HOOK: <select-by-slots-statement> db ( tuple class -- tuple )
-TUPLE: query group order offset limit ;
-HOOK: <query> db ( tuple class query -- statement' )
-HOOK: <count-statement> db ( tuple class groups -- n )
+HOOK: <count-statement> db ( query -- statement )
+HOOK: query>statement db ( query -- statement )
 
-HOOK: insert-tuple* db ( tuple statement -- )
+HOOK: insert-tuple-set-key db ( tuple statement -- )
+
+SYMBOL: sql-counter
+: next-sql-counter ( -- str )
+    sql-counter [ inc ] [ get ] bi number>string ;
 
 GENERIC: eval-generator ( singleton -- object )
 
 : resulting-tuple ( exemplar-tuple row out-params -- tuple )
     rot class new [
-        [
-            [ slot-name>> ] dip set-slot-named
-        ] curry 2each
+        [ [ slot-name>> ] dip set-slot-named ] curry 2each
     ] keep ;
 
 : query-tuples ( exemplar-tuple statement -- seq )
@@ -75,6 +50,51 @@ GENERIC: eval-generator ( singleton -- object )
         with-disposal
     ] if ; inline
 
+: insert-db-assigned-statement ( tuple -- )
+    dup class
+    db get insert-statements>> [ <insert-db-assigned-statement> ] cache
+    [ bind-tuple ] 2keep insert-tuple-set-key ;
+
+: insert-user-assigned-statement ( tuple -- )
+    dup class
+    db get insert-statements>> [ <insert-user-assigned-statement> ] cache
+    [ bind-tuple ] keep execute-statement ;
+
+: do-select ( exemplar-tuple statement -- tuples )
+    [ [ bind-tuple ] [ query-tuples ] 2bi ] with-disposal ;
+
+: do-count ( exemplar-tuple statement -- tuples )
+    [ [ bind-tuple ] [ nip default-query ] 2bi ] with-disposal ;
+PRIVATE>
+
+
+! High level
+ERROR: no-slots-named class seq ;
+: check-columns ( class columns -- )
+    tuck
+    [ [ first ] map ]
+    [ all-slots [ name>> ] map ] bi* diff
+    [ drop ] [ no-slots-named ] if-empty ;
+
+: define-persistent ( class table columns -- )
+    pick dupd
+    check-columns
+    [ dupd "db-table" set-word-prop dup ] dip
+    [ relation? ] partition swapd
+    dupd [ spec>tuple ] with map
+    "db-columns" set-word-prop
+    "db-relations" set-word-prop ;
+
+TUPLE: query tuple group order offset limit ;
+
+: <query> ( -- query ) \ query new ;
+
+GENERIC: >query ( object -- query )
+
+M: query >query clone ;
+
+M: tuple >query <query> swap >>tuple ;
+
 : create-table ( class -- )
     create-sql-statement [ execute-statement ] with-disposals ;
 
@@ -87,21 +107,9 @@ GENERIC: eval-generator ( singleton -- object )
         ] curry ignore-errors
     ] [ create-table ] bi ;
 
-: ensure-table ( class -- )
-    [ create-table ] curry ignore-errors ;
-
-: ensure-tables ( classes -- )
-    [ ensure-table ] each ;
+: ensure-table ( class -- ) [ create-table ] curry ignore-errors ;
 
-: insert-db-assigned-statement ( tuple -- )
-    dup class
-    db get insert-statements>> [ <insert-db-assigned-statement> ] cache
-    [ bind-tuple ] 2keep insert-tuple* ;
-
-: insert-user-assigned-statement ( tuple -- )
-    dup class
-    db get insert-statements>> [ <insert-user-assigned-statement> ] cache
-    [ bind-tuple ] keep execute-statement ;
+: ensure-tables ( classes -- ) [ ensure-table ] each ;
 
 : insert-tuple ( tuple -- )
     dup class db-columns find-primary-key db-assigned-id-spec?
@@ -117,25 +125,14 @@ GENERIC: eval-generator ( singleton -- object )
         [ bind-tuple ] keep execute-statement
     ] with-disposal ;
 
-: do-select ( exemplar-tuple statement -- tuples )
-    [ [ bind-tuple ] [ query-tuples ] 2bi ] with-disposal ;
-
-: query ( tuple query -- tuples )
-    [ dup dup class ] dip <query> do-select ;
-
-: select-tuples ( tuple -- tuples )
-    dup dup class <select-by-slots-statement> do-select ;
+: select-tuples ( query/tuple -- tuples )
+    >query [ tuple>> ] [ query>statement ] bi do-select ;
 
-: select-tuple ( tuple -- tuple/f )
-    dup dup class \ query new 1 >>limit <query> do-select
+: select-tuple ( query/tuple -- tuple/f )
+    >query 1 >>limit [ tuple>> ] [ query>statement ] bi do-select
     [ f ] [ first ] if-empty ;
 
-: do-count ( exemplar-tuple statement -- tuples )
-    [
-        [ bind-tuple ] [ nip default-query ] 2bi
-    ] with-disposal ;
-
-: count-tuples ( tuple groups -- n )
-    >r dup dup class r> <count-statement> do-count
+: count-tuples ( query/tuple -- n )
+    >query [ tuple>> ] [ <count-statement> ] bi do-count
     dup length 1 =
     [ first first string>number ] [ [ first string>number ] map ] if ;
index 9300a68f2ee263cffed81b436710fd9da249dc80..401bbbc4d7f7de8928dc32a65d02b3fd5cf3ab73 100644 (file)
@@ -1,14 +1,9 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: classes hashtables help.markup help.syntax io.streams.string kernel sequences strings ;
+USING: classes hashtables help.markup help.syntax io.streams.string
+kernel sequences strings math ;
 IN: db.types
 
-HELP: (lookup-type)
-{ $values
-     { "obj" object }
-     { "string" string } }
-{ $description "" } ;
-
 HELP: +autoincrement+
 { $description "" } ;
 
@@ -55,7 +50,7 @@ HELP: <low-level-binding>
 { $description "" } ;
 
 HELP: BIG-INTEGER
-{ $description "A 64-bit integer." } ;
+{ $description "A 64-bit integer. Whether this number is signed or unsigned depends on the database backend." } ;
 
 HELP: BLOB
 { $description "A serialized Factor object.  The database library automatically serializes the object for a SQL insert or update and deserializes it on a tuple query." } ;
@@ -73,13 +68,13 @@ HELP: DOUBLE
 { $description "Corresponds to Factor's 64bit floating-point numbers." } ;
 
 HELP: FACTOR-BLOB
-{ $description "" } ;
+{ $description "A serialized Factor object." } ;
 
 HELP: INTEGER
-{ $description "" } ;
+{ $description "A small integer, at least 32 bits in length. Whether this number is signed or unsigned depends on the database backend." } ;
 
 HELP: NULL
-{ $description "" } ;
+{ $description "The SQL null type." } ;
 
 HELP: REAL
 { $description "" } ;
@@ -94,22 +89,24 @@ HELP: TIME
 { $description "" } ;
 
 HELP: TIMESTAMP
-{ $description "" } ;
+{ $description "A Factor timestamp." } ;
 
 HELP: UNSIGNED-BIG-INTEGER
-{ $description "" } ;
+{ $description "For portability, if a number is known to be 64bit, then this datatype may be used.  Some databases, like SQLite, cannot store arbitrary bignums as BIGINT types.  If storing arbitrary bignums, use " { $link FACTOR-BLOB } "." } ;
+
+{ INTEGER SIGNED-BIG-INTEGER UNSIGNED-BIG-INTEGER } related-words
 
 HELP: URL
-{ $description "" } ;
+{ $description "A Factor " { $link "urls" } "  object." } ;
 
 HELP: VARCHAR
-{ $description "" } ;
+{ $description "The SQL varchar type.  This type can take an integer as an argument." } ;
 
-HELP: assigned-id-spec?
+HELP: user-assigned-id-spec?
 { $values
-     { "spec" null }
+     { "specs" "a sequence of sql specs" }
      { "?" "a boolean" } }
-{ $description "" } ;
+{ $description "Tests if any of the sql specs has the type " { $link +user-assigned-id+ } "." } ;
 
 HELP: bind#
 { $values
@@ -129,24 +126,25 @@ HELP: compound
 
 HELP: db-assigned-id-spec?
 { $values
-     { "spec" null }
+     { "specs" "a sequence of sql specs" }
      { "?" "a boolean" } }
-{ $description "" } ;
+{ $description "Tests if any of the sql specs has the type " { $link +db-assigned-id+ } "." } ;
 
 HELP: find-primary-key
 { $values
-     { "specs" null }
-     { "obj" object } }
-{ $description "" } ;
+     { "specs" "a sequence of sql-specs" }
+     { "seq" "a sequence of sql-specs" } }
+{ $description "Returns the rows from the sql-specs array that are part of the primary key. Composite primary keys are supported, so this word must return a sequence." }
+{ $notes "This is a low-level word." } ;
 
 HELP: generator-bind
 { $description "" } ;
 
 HELP: get-slot-named
 { $values
-     { "name" null } { "obj" object }
-     { "value" null } }
-{ $description "" } ;
+     { "name" "a slot name" } { "tuple" tuple }
+     { "value" "the value stored in the slot" } }
+{ $description "Returns the value stored in a tuple slot, where the tuple slot is a string." } ;
 
 HELP: join-space
 { $values
@@ -185,30 +183,20 @@ HELP: modifiers
 { $description "" } ;
 
 HELP: no-sql-type
-{ $description "" } ;
+{ $values
+     { "type" "a sql type" } }
+{ $description "Throws an error containing a sql type that is unsupported or the result of a typo." } ;
 
 HELP: normalize-spec
 { $values
      { "spec" null } }
 { $description "" } ;
 
-HELP: number>string*
-{ $values
-     { "n/string" null }
-     { "string" string } }
-{ $description "" } ;
-
 HELP: offset-of-slot
 { $values
-     { "string" string } { "obj" object }
-     { "n" null } }
-{ $description "" } ;
-
-HELP: paren
-{ $values
-     { "string" string }
-     { "new-string" null } }
-{ $description "" } ;
+     { "string" string } { "tuple" tuple }
+     { "n" integer } }
+{ $description "Returns the offset of a tuple slot accessed by name." } ;
 
 HELP: persistent-table
 { $values
@@ -264,7 +252,8 @@ HELP: sql-spec
 { $description "" } ;
 
 HELP: unknown-modifier
-{ $description "" } ;
+{ $values { "modifier" string } }
+{ $description "Throws an error containing an unknown sql modifier." } ;
 
 ARTICLE: "db.types" "Database types"
 "The " { $vocab-link "db.types" } " vocabulary maps Factor types to database types." $nl
@@ -294,7 +283,6 @@ ARTICLE: "db.types" "Database types"
 { $subsection BLOB }
 { $subsection FACTOR-BLOB }
 "Factor URLs:"
-{ $subsection URL }
-;
+{ $subsection URL } ;
 
 ABOUT: "db.types"
index 24344acbf7d259d85da9c503abc0aa329a12424f..bc33792e52432cbc6a30cf26b62cf4f26c111d47 100755 (executable)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays assocs db kernel math math.parser
-sequences continuations sequences.deep
+sequences continuations sequences.deep prettyprint
 words namespaces slots slots.private classes mirrors
 classes.tuple combinators calendar.format symbols
 classes.singleton accessors quotations random ;
@@ -22,22 +22,51 @@ SINGLETON: random-id-generator
 TUPLE: low-level-binding value ;
 C: <low-level-binding> low-level-binding
 
-SINGLETON: +db-assigned-id+
-SINGLETON: +user-assigned-id+
-SINGLETON: +random-id+
+SINGLETONS: +db-assigned-id+ +user-assigned-id+ +random-id+ ;
 UNION: +primary-key+ +db-assigned-id+ +user-assigned-id+ +random-id+ ;
 
 SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+
-+foreign-id+ +has-many+ ;
++foreign-id+ +has-many+ +on-delete+ +restrict+ +cascade+ +set-null+
++set-default+ ;
+
+: offset-of-slot ( string tuple -- n )
+    class superclasses [ "slots" word-prop ] map concat
+    slot-named offset>> ;
+
+: get-slot-named ( name tuple -- value )
+    tuck offset-of-slot slot ;
+
+: set-slot-named ( value name obj -- )
+    tuck offset-of-slot set-slot ;
+
+ERROR: not-persistent class ;
+
+: db-table ( class -- object )
+    dup "db-table" word-prop [ ] [ not-persistent ] ?if ;
+
+: db-columns ( class -- object )
+    superclasses [ "db-columns" word-prop ] map concat ;
+
+: db-relations ( class -- object )
+    "db-relations" word-prop ;
+
+: find-primary-key ( specs -- seq )
+    [ primary-key>> ] filter ;
+
+: set-primary-key ( value tuple -- )
+    [
+        class db-columns
+        find-primary-key first slot-name>>
+    ] keep set-slot-named ;
 
 : primary-key? ( spec -- ? )
     primary-key>> +primary-key+? ;
 
-: db-assigned-id-spec? ( spec -- ? )
-    primary-key>> +db-assigned-id+? ;
+: db-assigned-id-spec? ( specs -- ? )
+    [ primary-key>> +db-assigned-id+? ] contains? ;
 
-: assigned-id-spec? ( spec -- ? )
-    primary-key>> +user-assigned-id+? ;
+: user-assigned-id-spec? ( specs -- ? )
+    [ primary-key>> +user-assigned-id+? ] contains? ;
 
 : normalize-spec ( spec -- )
     dup type>> dup +primary-key+? [
@@ -49,8 +78,8 @@ SYMBOLS: +autoincrement+ +serial+ +unique+ +default+ +null+ +not-null+
         [ >>primary-key drop ] [ drop ] if*
     ] if ;
 
-: find-primary-key ( specs -- obj )
-    [ primary-key>> ] find nip ;
+: db-assigned? ( class -- ? )
+    db-columns find-primary-key db-assigned-id-spec? ;
 
 : relation? ( spec -- ? ) [ +has-many+ = ] deep-find ;
 
@@ -86,18 +115,22 @@ FACTOR-BLOB NULL URL ;
 ! PostgreSQL Types:
 ! http://developer.postgresql.org/pgdocs/postgres/datatype.html
 
-ERROR: unknown-modifier ;
+
+: ?at ( obj assoc -- value/obj ? )
+    dupd at* [ [ nip ] [ drop ] if ] keep ;
+
+ERROR: unknown-modifier modifier ;
 
 : lookup-modifier ( obj -- string )
     {
         { [ dup array? ] [ unclip lookup-modifier swap compound ] }
-        [ persistent-table at* [ unknown-modifier ] unless third ]
+        [ persistent-table ?at [ unknown-modifier ] unless third ]
     } cond ;
 
-ERROR: no-sql-type ;
+ERROR: no-sql-type type ;
 
 : (lookup-type) ( obj -- string )
-    persistent-table at* [ no-sql-type ] unless ;
+    persistent-table ?at [ no-sql-type ] unless ;
 
 : lookup-type ( obj -- string )
     dup array? [
@@ -113,25 +146,21 @@ ERROR: no-sql-type ;
         (lookup-type) second
     ] if ;
 
-: paren ( string -- new-string )
-    "(" swap ")" 3append ;
+: modifiers ( spec -- string )
+    modifiers>> [ lookup-modifier ] map " " join
+    [ "" ] [ " " prepend ] if-empty ;
 
 : join-space ( string1 string2 -- new-string )
     " " swap 3append ;
 
-: modifiers ( spec -- string )
-    modifiers>> [ lookup-modifier ] map " " join
-    [ "" ] [ " " prepend ] if-empty ;
+: paren ( string -- new-string )
+    "(" swap ")" 3append ;
 
 HOOK: bind% db ( spec -- )
 HOOK: bind# db ( spec obj -- )
 
-: offset-of-slot ( string obj -- n )
-    class superclasses [ "slots" word-prop ] map concat
-    slot-named offset>> ;
-
-: get-slot-named ( name obj -- value )
-    tuck offset-of-slot slot ;
-
-: set-slot-named ( value name obj -- )
-    tuck offset-of-slot set-slot ;
+: >reference-string ( string pair -- string )
+    first2
+    [ [ unparse join-space ] [ db-columns ] bi ] dip
+    swap [ slot-name>> = ] with find nip
+    column-name>> paren append ;
index b7fd34c5be90313df0f4d50956c5cc7242c6e9c5..ec93a01c19af449d65125cd574a01242955dae4b 100755 (executable)
@@ -22,6 +22,9 @@ M: tuple error-help class ;
 
 M: string error. print ;
 
+: :error ( -- )
+    error get error. ;
+
 : :s ( -- )
     error-continuation get data>> stack. ;
 
@@ -323,3 +326,5 @@ M: bad-effect summary
     drop "Bad stack effect declaration" ;
 
 M: bad-escape summary drop "Bad escape code" ;
+
+M: bad-literal-tuple summary drop "Bad literal tuple" ;
index 93bf70b9507762f2b00a753586dc275d5656d2db..0d2f94c13de177daa4bed07f63c20eb45945fc35 100644 (file)
@@ -45,5 +45,4 @@ $nl
 { $subsection define-consult }
 "The " { $vocab-link "delegate.protocols" } " vocabulary defines formal protocols for the various informal protocols used in the Factor core, such as " { $link "sequence-protocol" } ", " { $link "assocs-protocol" } " or " { $link "stream-protocol" } ;
 
-IN: delegate
 ABOUT: { "delegate" "intro" }
index 45cc214792e671b7e20010a8a03c05373fd1c7d7..12860337ffb9b2deef642ae652aa1c77fec058e7 100755 (executable)
@@ -62,7 +62,7 @@ M: tuple-class group-words
     protocol-consult keys ;
 
 : lost-words ( protocol wordlist -- lost-words )
-    >r protocol-words r> diff ;
+    [ protocol-words ] dip diff ;
 
 : forget-old-definitions ( protocol new-wordlist -- )
     [ drop protocol-users ] [ lost-words ] 2bi
index 5a4b33887b4480538e29c63e0fe4a6d597ab55d8..58f077ed1e44618eec2fd9f7f5325b686bfaf5e1 100644 (file)
@@ -1,45 +1,29 @@
+USING: help.markup help.syntax kernel math sequences
+quotations ;
 IN: deques
-USING: help.markup help.syntax kernel ;
-
-ARTICLE: "deques" "Dequeues"
-"A deque is a data structure with constant-time insertion and removal of elements at both ends. Dequeue operations are defined in the " { $vocab-link "deques" } " vocabulary."
-$nl
-"Dequeues must be instances of a mixin class:"
-{ $subsection deque }
-"Dequeues must implement a protocol."
-$nl
-"Querying the deque:"
-{ $subsection peek-front }
-{ $subsection peek-back }
-{ $subsection deque-length }
-{ $subsection deque-member? }
-"Adding and removing elements:"
-{ $subsection push-front* }
-{ $subsection push-back* }
-{ $subsection pop-front* }
-{ $subsection pop-back* }
-{ $subsection clear-deque }
-"Working with node objects output by " { $link push-front* } " and " { $link push-back* } ":"
-{ $subsection delete-node }
-{ $subsection node-value }
-"Utility operations built in terms of the above:"
-{ $subsection deque-empty? }
-{ $subsection push-front }
-{ $subsection push-all-front }
-{ $subsection push-back }
-{ $subsection push-all-back }
-{ $subsection pop-front }
-{ $subsection pop-back }
-{ $subsection slurp-deque }
-"When using a deque as a queue, the convention is to queue elements with " { $link push-front } " and deque them with " { $link pop-back } "." ;
-
-ABOUT: "deques"
 
 HELP: deque-empty?
-{ $values { "deque" { $link deque } } { "?" "a boolean" } }
+{ $values { "deque" deque } { "?" "a boolean" } }
 { $description "Returns true if a deque is empty." }
 { $notes "This operation is O(1)." } ;
 
+HELP: clear-deque
+{ $values
+     { "deque" deque } }
+{ $description "Removes all elements from a deque." } ;
+
+HELP: deque-length
+{ $values
+     { "deque" deque }
+     { "n" integer } }
+{ $description "Returns the number of elements in a deque." } ;
+
+HELP: deque-member?
+{ $values
+     { "value" object } { "deque" deque }
+     { "?" "a boolean" } }
+{ $description "Returns true if the " { $snippet "value" } " is found in the deque." } ;
+
 HELP: push-front
 { $values { "obj" object } { "deque" deque } }
 { $description "Push the object onto the front of the deque." } 
@@ -60,6 +44,16 @@ HELP: push-back*
 { $description "Push the object onto the back of the deque and return the newly created node." } 
 { $notes "This operation is O(1)." } ;
 
+HELP: push-all-back
+{ $values
+     { "seq" sequence } { "deque" deque } }
+{ $description "Pushes a sequence of elements onto the back of a deque." } ;
+
+HELP: push-all-front
+{ $values
+     { "seq" sequence } { "deque" deque } }
+{ $description "Pushes a sequence of elements onto the front of a deque." } ;
+
 HELP: peek-front
 { $values { "deque" deque } { "obj" object } }
 { $description "Returns the object at the front of the deque." } ;
@@ -87,3 +81,56 @@ HELP: pop-back*
 { $values { "deque" deque } }
 { $description "Pop the object off the back of the deque." }
 { $notes "This operation is O(1)." } ;
+
+HELP: delete-node
+{ $values
+     { "node" object } { "deque" deque } }
+{ $description "Deletes the node from the deque." } ;
+
+HELP: deque
+{ $description "A data structure that has constant-time insertion and removal of elements at both ends." } ;
+
+HELP: node-value
+{ $values
+     { "node" object }
+     { "value" object } }
+{ $description "Accesses the value stored at a node." } ;
+
+HELP: slurp-deque
+{ $values
+     { "deque" deque } { "quot" quotation } }
+{ $description "Pops off the back element of the deque and calls the quotation in a loop until the deque is empty." } ;
+
+ARTICLE: "deques" "Deques"
+"The " { $vocab-link "deques" } " vocabulary implements the deque data structure which has constant-time insertion and removal of elements at both ends."
+$nl
+"Deques must be instances of a mixin class:"
+{ $subsection deque }
+"Deques must implement a protocol."
+$nl
+"Querying the deque:"
+{ $subsection peek-front }
+{ $subsection peek-back }
+{ $subsection deque-length }
+{ $subsection deque-member? }
+"Adding and removing elements:"
+{ $subsection push-front* }
+{ $subsection push-back* }
+{ $subsection pop-front* }
+{ $subsection pop-back* }
+{ $subsection clear-deque }
+"Working with node objects output by " { $link push-front* } " and " { $link push-back* } ":"
+{ $subsection delete-node }
+{ $subsection node-value }
+"Utility operations built in terms of the above:"
+{ $subsection deque-empty? }
+{ $subsection push-front }
+{ $subsection push-all-front }
+{ $subsection push-back }
+{ $subsection push-all-back }
+{ $subsection pop-front }
+{ $subsection pop-back }
+{ $subsection slurp-deque }
+"When using a deque as a queue, the convention is to queue elements with " { $link push-front } " and deque them with " { $link pop-back } "." ;
+
+ABOUT: "deques"
index 40e14b7fca82b509fb678a09b2096e9c7516f120..cded25b48db4d496b478eb39b371c1caf3fb1fd6 100644 (file)
@@ -37,7 +37,7 @@ HELP: assoc>disjoint-set
 } ;
 
 ARTICLE: "disjoint-sets" "Disjoint sets"
-"The " { $emphasis "disjoint set" } " data structure, also known as " { $emphasis "union-find" } " (after the two main operations which it supports) represents a set of elements partitioned into disjoint equivalence classes, or alternatively, an equivalence relation on a set."
+"The " { $vocab-link "disjoint-sets" } " vocabulary implements the " { $emphasis "disjoint set" } " data structure (also known as " { $emphasis "union-find" } ", after the two main operations which it supports) that represents a set of elements partitioned into disjoint equivalence classes, or alternatively, an equivalence relation on a set."
 $nl
 "The two main supported operations are equating two elements, which joins their equivalence classes, and checking if two elements belong to the same equivalence class. Both operations have the time complexity of the inverse Ackermann function, which for all intents and purposes is constant time."
 $nl
diff --git a/basis/editors/macvim/authors.txt b/basis/editors/macvim/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/editors/macvim/macvim.factor b/basis/editors/macvim/macvim.factor
new file mode 100755 (executable)
index 0000000..b5f864d
--- /dev/null
@@ -0,0 +1,13 @@
+USING: definitions io.launcher kernel math math.parser parser
+namespaces prettyprint editors make ;
+
+IN: editors.macvim
+
+: macvim-location ( file line -- )
+    drop
+    [ "open" , "-a" , "MacVim", , ] { } make
+    try-process ;
+
+[ macvim-location ] edit-hook set-global
+
+
diff --git a/basis/editors/macvim/summary.txt b/basis/editors/macvim/summary.txt
new file mode 100644 (file)
index 0000000..894d635
--- /dev/null
@@ -0,0 +1 @@
+MacVim editor integration
diff --git a/basis/editors/macvim/tags.txt b/basis/editors/macvim/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/editors/textedit/authors.txt b/basis/editors/textedit/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/basis/editors/textedit/summary.txt b/basis/editors/textedit/summary.txt
new file mode 100644 (file)
index 0000000..1d72d10
--- /dev/null
@@ -0,0 +1 @@
+TextEdit editor integration
diff --git a/basis/editors/textedit/tags.txt b/basis/editors/textedit/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/basis/editors/textedit/textedit.factor b/basis/editors/textedit/textedit.factor
new file mode 100755 (executable)
index 0000000..6942e24
--- /dev/null
@@ -0,0 +1,13 @@
+USING: definitions io.launcher kernel math math.parser parser
+namespaces prettyprint editors make ;
+
+IN: editors.textedit
+
+: textedit-location ( file line -- )
+    drop
+    [ "open" , "-a" , "TextEdit", , ] { } make
+    try-process ;
+
+[ textedit-location ] edit-hook set-global
+
+
diff --git a/basis/eval/authors.txt b/basis/eval/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/eval/summary.txt b/basis/eval/summary.txt
new file mode 100644 (file)
index 0000000..679f074
--- /dev/null
@@ -0,0 +1 @@
+Ad-hoc evaluation of strings of code
index f2d53d23621d8622c435a141ad16d98246035737..8e7270cc015051266398a5e5fb3f36eac08e82f2 100644 (file)
@@ -9,7 +9,7 @@ HELP: write-farkup
 { $values { "string" string } }
 { $description "Parse a Farkup string and writes the resulting HTML to " { $link output-stream } "." } ;
 
-HELP: farkup ( string -- farkup )
+HELP: parse-farkup ( string -- farkup )
 { $values { "string" string } { "farkup" "a Farkup syntax tree node" } }
 { $description "Parses Farkup and outputs a tree of " { $link "farkup-ast" } "." } ;
 
@@ -18,7 +18,7 @@ HELP: (write-farkup)
 { $description "Writes a Farkup syntax tree as HTML on " { $link output-stream } "." } ;
 
 ARTICLE: "farkup-ast" "Farkup syntax tree nodes"
-"The " { $link farkup } " word outputs a tree of nodes corresponding to the Farkup syntax of the input string. This tree can be programatically traversed and mutated before being passed on to " { $link write-farkup } "."
+"The " { $link parse-farkup } " word outputs a tree of nodes corresponding to the Farkup syntax of the input string. This tree can be programatically traversed and mutated before being passed on to " { $link write-farkup } "."
 { $subsection heading1 }
 { $subsection heading2 }
 { $subsection heading3 }
@@ -30,7 +30,8 @@ ARTICLE: "farkup-ast" "Farkup syntax tree nodes"
 { $subsection inline-code }
 { $subsection paragraph }
 { $subsection list-item }
-{ $subsection list }
+{ $subsection unordered-list }
+{ $subsection ordered-list }
 { $subsection table }
 { $subsection table-row }
 { $subsection link }
@@ -44,7 +45,7 @@ $nl
 { $subsection convert-farkup }
 { $subsection write-farkup }
 "The syntax tree of a piece of Farkup can also be inspected and modified:"
-{ $subsection farkup }
+{ $subsection parse-farkup }
 { $subsection (write-farkup) }
 { $subsection "farkup-ast" } ;
 
index e25fa34960dec3ff844af2cce9c76106ebb05a82..27911a8d13ea089ed141fa9bb5f54b501bd8746d 100644 (file)
@@ -11,13 +11,11 @@ link-no-follow? off
 [ "Baz" ] [ "Baz" simple-link-title ] unit-test
 
 [ ] [
-    "abcd-*strong*\nasdifj\nweouh23ouh23"
-    "paragraph" \ farkup rule parse drop
+    "abcd-*strong*\nasdifj\nweouh23ouh23" parse-farkup drop
 ] unit-test
 
 [ ] [
-    "abcd-*strong*\nasdifj\nweouh23ouh23\n"
-    "paragraph" \ farkup rule parse drop
+    "abcd-*strong*\nasdifj\nweouh23ouh23\n" parse-farkup drop
 ] unit-test
 
 [ "<p>a-b</p>" ] [ "a-b" convert-farkup ] unit-test
@@ -37,22 +35,30 @@ link-no-follow? off
 
 [ "<ul><li>foo</li>\n</ul><p>bar\n</p>" ] [ "-foo\nbar\n" convert-farkup ] unit-test
 
+[ "<ol><li>a-b</li></ol>" ] [ "#a-b" convert-farkup ] unit-test
+[ "<ol><li>foo</li></ol>" ] [ "#foo" convert-farkup ] unit-test
+[ "<ol><li>foo</li>\n</ol>" ] [ "#foo\n" convert-farkup ] unit-test
+[ "<ol><li>foo</li>\n<li>bar</li></ol>" ] [ "#foo\n#bar" convert-farkup ] unit-test
+[ "<ol><li>foo</li>\n<li>bar</li>\n</ol>" ] [ "#foo\n#bar\n" convert-farkup ] unit-test
+
+[ "<ol><li>foo</li>\n</ol><p>bar\n</p>" ] [ "#foo\nbar\n" convert-farkup ] unit-test
+
 
 [ "\n\n" ] [ "\n\n" convert-farkup ] unit-test
 [ "\n\n" ] [ "\r\n\r\n" convert-farkup ] unit-test
 [ "\n\n\n\n" ] [ "\r\r\r\r" convert-farkup ] unit-test
 [ "\n\n\n" ] [ "\r\r\r" convert-farkup ] unit-test
 [ "\n\n\n" ] [ "\n\n\n" convert-farkup ] unit-test
-[ "<p>foo</p><p>bar</p>" ] [ "foo\n\nbar" convert-farkup ] unit-test
-[ "<p>foo</p><p>bar</p>" ] [ "foo\r\n\r\nbar" convert-farkup ] unit-test
-[ "<p>foo</p><p>bar</p>" ] [ "foo\r\rbar" convert-farkup ] unit-test
-[ "<p>foo</p><p>bar</p>" ] [ "foo\r\r\nbar" convert-farkup ] unit-test
+[ "<p>foo\n</p><p>bar</p>" ] [ "foo\n\nbar" convert-farkup ] unit-test
+[ "<p>foo\n</p><p>bar</p>" ] [ "foo\r\n\r\nbar" convert-farkup ] unit-test
+[ "<p>foo\n</p><p>bar</p>" ] [ "foo\r\rbar" convert-farkup ] unit-test
+[ "<p>foo\n</p><p>bar</p>" ] [ "foo\r\r\nbar" convert-farkup ] unit-test
 
 [ "\n<p>bar\n</p>" ] [ "\nbar\n" convert-farkup ] unit-test
 [ "\n<p>bar\n</p>" ] [ "\rbar\r" convert-farkup ] unit-test
 [ "\n<p>bar\n</p>" ] [ "\r\nbar\r\n" convert-farkup ] unit-test
 
-[ "<p>foo</p><p>bar</p>" ] [ "foo\n\n\nbar" convert-farkup ] unit-test
+[ "<p>foo\n</p><p>bar</p>" ] [ "foo\n\n\nbar" convert-farkup ] unit-test
 
 [ "" ] [ "" convert-farkup ] unit-test
 
@@ -107,7 +113,7 @@ link-no-follow? off
 ] [ "Feature comparison:\n|a|Factor|Java|Lisp|\n|Coolness|Yes|No|No|\n|Badass|Yes|No|No|\n|Enterprise|Yes|Yes|No|\n|Kosher|Yes|No|Yes|\n" convert-farkup ] unit-test
 
 [
-    "<p>Feature comparison:</p><table><tr><td>a</td><td>Factor</td><td>Java</td><td>Lisp</td></tr><tr><td>Coolness</td><td>Yes</td><td>No</td><td>No</td></tr><tr><td>Badass</td><td>Yes</td><td>No</td><td>No</td></tr><tr><td>Enterprise</td><td>Yes</td><td>Yes</td><td>No</td></tr><tr><td>Kosher</td><td>Yes</td><td>No</td><td>Yes</td></tr></table>"
+    "<p>Feature comparison:\n</p><table><tr><td>a</td><td>Factor</td><td>Java</td><td>Lisp</td></tr><tr><td>Coolness</td><td>Yes</td><td>No</td><td>No</td></tr><tr><td>Badass</td><td>Yes</td><td>No</td><td>No</td></tr><tr><td>Enterprise</td><td>Yes</td><td>Yes</td><td>No</td></tr><tr><td>Kosher</td><td>Yes</td><td>No</td><td>Yes</td></tr></table>"
 ] [ "Feature comparison:\n\n|a|Factor|Java|Lisp|\n|Coolness|Yes|No|No|\n|Badass|Yes|No|No|\n|Enterprise|Yes|Yes|No|\n|Kosher|Yes|No|Yes|\n" convert-farkup ] unit-test
 
 [
@@ -118,3 +124,36 @@ link-no-follow? off
 ] unit-test
 
 [ "<p><a href='a'>a</a> <a href='b'>c</a></p>" ] [ "[[a]] [[b|c]]" convert-farkup ] unit-test
+
+[ "<p><a href='C%2b%2b'>C++</a></p>" ] [ "[[C++]]" convert-farkup ] unit-test
+
+[ "<p>&lt;foo&gt;</p>" ] [ "<foo>" convert-farkup ] unit-test
+
+[ "<p>asdf\n<ul><li>lol</li>\n<li>haha</li></ul></p>" ] [ "asdf\n-lol\n-haha" convert-farkup ] unit-test
+
+[ "<p>asdf\n</p><ul><li>lol</li>\n<li>haha</li></ul>" ]
+ [ "asdf\n\n-lol\n-haha" convert-farkup ] unit-test
+
+[ "<hr/>" ] [ "___" convert-farkup ] unit-test
+[ "<hr/>\n" ] [ "___\n" convert-farkup ] unit-test
+
+[ "<p>before:\n<pre><span class='OPERATOR'>{</span> <span class='DIGIT'>1</span> <span class='DIGIT'>2</span> <span class='DIGIT'>3</span> <span class='OPERATOR'>}</span> <span class='DIGIT'>1</span> tail\n</pre></p>" ] 
+[ "before:\n[factor{{ 1 2 3 } 1 tail}]" convert-farkup ] unit-test
+[ "<p><a href='Factor'>Factor</a>-rific!</p>" ]
+[ "[[Factor]]-rific!" convert-farkup ] unit-test
+
+[ "<p>[ factor { 1 2 3 }]</p>" ]
+[ "[ factor { 1 2 3 }]" convert-farkup ] unit-test
+
+[ "<p>paragraph\n<hr/></p>" ]
+[ "paragraph\n___" convert-farkup ] unit-test
+
+[ "<p>paragraph\n a ___ b</p>" ]
+[ "paragraph\n a ___ b" convert-farkup ] unit-test
+
+[ "\n<ul><li> a</li>\n</ul><hr/>" ]
+[ "\n- a\n___" convert-farkup ] unit-test
+
+[ "<p>hello_world how are you today?\n<ul><li> hello_world how are you today?</li></ul></p>" ]
+[ "hello_world how are you today?\n- hello_world how are you today?" convert-farkup ] unit-test
index 4d6ac127ad56f12edaa6de4fe786b145cf367e80..73b0cba4d07469f24758016a05369bf117634d84 100644 (file)
@@ -1,32 +1,34 @@
 ! Copyright (C) 2008 Doug Coleman.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays combinators html.elements io io.streams.string
-kernel math memoize namespaces peg peg.ebnf prettyprint
-sequences sequences.deep strings xml.entities vectors splitting
-xmode.code2html ;
+USING: accessors arrays combinators html.elements io
+io.streams.string kernel math namespaces peg peg.ebnf
+sequences sequences.deep strings xml.entities
+vectors splitting xmode.code2html urls.encoding ;
 IN: farkup
 
 SYMBOL: relative-link-prefix
 SYMBOL: disable-images?
 SYMBOL: link-no-follow?
 
-TUPLE: heading1 obj ;
-TUPLE: heading2 obj ;
-TUPLE: heading3 obj ;
-TUPLE: heading4 obj ;
-TUPLE: strong obj ;
-TUPLE: emphasis obj ;
-TUPLE: superscript obj ;
-TUPLE: subscript obj ;
-TUPLE: inline-code obj ;
-TUPLE: paragraph obj ;
-TUPLE: list-item obj ;
-TUPLE: list obj ;
-TUPLE: table obj ;
-TUPLE: table-row obj ;
+TUPLE: heading1 child ;
+TUPLE: heading2 child ;
+TUPLE: heading3 child ;
+TUPLE: heading4 child ;
+TUPLE: strong child ;
+TUPLE: emphasis child ;
+TUPLE: superscript child ;
+TUPLE: subscript child ;
+TUPLE: inline-code child ;
+TUPLE: paragraph child ;
+TUPLE: list-item child ;
+TUPLE: unordered-list child ;
+TUPLE: ordered-list child ;
+TUPLE: table child ;
+TUPLE: table-row child ;
 TUPLE: link href text ;
 TUPLE: image href text ;
 TUPLE: code mode string ;
+TUPLE: line ;
 
 : absolute-url? ( string -- ? )
     { "http://" "https://" "ftp://" } [ head? ] with contains? ;
@@ -34,9 +36,9 @@ TUPLE: code mode string ;
 : simple-link-title ( string -- string' )
     dup absolute-url? [ "/" last-split1 swap or ] unless ;
 
-EBNF: farkup
+EBNF: parse-farkup
 nl               = ("\r\n" | "\r" | "\n") => [[ drop "\n" ]]
-2nl              = nl nl
+whitespace       = " " | "\t" | nl
 
 heading1      = "=" (!("=" | nl).)+ "="
     => [[ second >string heading1 boa ]]
@@ -50,6 +52,10 @@ heading3      = "===" (!("=" | nl).)+ "==="
 heading4      = "====" (!("=" | nl).)+ "===="
     => [[ second >string heading4 boa ]]
 
+heading          = heading4 | heading3 | heading2 | heading1
+
+
+
 strong        = "*" (!("*" | nl).)+ "*"
     => [[ second >string strong boa ]]
 
@@ -65,8 +71,6 @@ subscript     = "~" (!("~" | nl).)+ "~"
 inline-code   = "%" (!("%" | nl).)+ "%"
     => [[ second >string inline-code boa ]]
 
-escaped-char  = "\" .                => [[ second ]]
-
 link-content     = (!("|"|"]").)+
 
 image-link       = "[[image:" link-content  "|" link-content "]]"
@@ -82,43 +86,70 @@ labelled-link    = "[[" link-content "|" link-content "]]"
 
 link             = image-link | labelled-link | simple-link
 
-heading          = heading4 | heading3 | heading2 | heading1
+escaped-char  = "\" .
+    => [[ second 1string ]]
 
 inline-tag       = strong | emphasis | superscript | subscript | inline-code
                    | link | escaped-char
 
+
+
 inline-delimiter = '*' | '_' | '^' | '~' | '%' | '\' | '['
 
-table-column     = (list | (!(nl | inline-delimiter | '|').)+ | inline-tag | inline-delimiter  ) '|'
+cell             = (!(inline-delimiter | '|' | nl).)+
+    => [[ >string ]]
+    
+table-column     = (list | cell | inline-tag | inline-delimiter  ) '|'
     => [[ first ]]
 table-row        = "|" (table-column)+
     => [[ second table-row boa ]]
 table            =  ((table-row nl => [[ first ]] )+ table-row? | table-row)
     => [[ table boa ]]
 
-paragraph-item = ( table | (!(nl | code | heading | inline-delimiter | table ).) | inline-tag | inline-delimiter)+
-paragraph = ((paragraph-item nl => [[ first ]])+ nl+ => [[ first ]]
-             | (paragraph-item nl)+ paragraph-item?
+text = (!(nl | code | heading | inline-delimiter | table ).)+
+    => [[ >string ]]
+
+paragraph-nl-item = nl (list | line)?
+paragraph-item = (table | code | text | inline-tag | inline-delimiter)+
+paragraph = ((paragraph-item paragraph-nl-item)+ nl+ => [[ first ]]
+             | (paragraph-item paragraph-nl-item)+ paragraph-item?
              | paragraph-item)
     => [[ paragraph boa ]]
-                
-list-item      = '-' ((!(inline-delimiter | nl).)+ | inline-tag)*
+
+
+list-item     = (cell | inline-tag | inline-delimiter)*
+
+ordered-list-item      = '#' list-item
+    => [[ second list-item boa ]]
+ordered-list = ((ordered-list-item nl)+ ordered-list-item? | ordered-list-item)
+    => [[ ordered-list boa ]]
+
+unordered-list-item    = '-' list-item
     => [[ second list-item boa ]]
-list = ((list-item nl)+ list-item? | list-item)
-    => [[ list boa ]]
+unordered-list = ((unordered-list-item nl)+ unordered-list-item? | unordered-list-item)
+    => [[ unordered-list boa ]]
+
+list = ordered-list | unordered-list
+
+
+line = '___'
+    => [[ drop line new ]]
 
-code       =  '[' (!('{' | nl | '[').)+ '{' (!("}]").)+ "}]"
+
+named-code
+           =  '[' (!('{' | whitespace | '[').)+ '{' (!("}]").)+ "}]"
     => [[ [ second >string ] [ fourth >string ] bi code boa ]]
 
 simple-code
            = "[{" (!("}]").)+ "}]"
     => [[ second f swap code boa ]]
 
-stand-alone
-           = (code | simple-code | heading | list | table | paragraph | nl)*
-;EBNF
+code = named-code | simple-code
 
 
+stand-alone
+           = (line | code | heading | list | table | paragraph | nl)*
+;EBNF
 
 : invalid-url "javascript:alert('Invalid URL in farkup');" ;
 
@@ -136,7 +167,7 @@ stand-alone
 
 : write-link ( href text -- )
     escape-link
-    [ <a =href link-no-follow? get [ "true" =nofollow ] when a> ]
+    [ <a url-encode =href link-no-follow? get [ "true" =nofollow ] when a> ]
     [ write </a> ]
     bi* ;
 
@@ -146,7 +177,7 @@ stand-alone
         <strong> "Images are not allowed" write </strong>
     ] [
         escape-link
-        [ <img =src ] [ [ =alt ] unless-empty img/> ] bi*
+        [ <img url-encode =src ] [ [ =alt ] unless-empty img/> ] bi*
     ] if ;
 
 : render-code ( string mode -- string' )
@@ -161,31 +192,32 @@ GENERIC: (write-farkup) ( farkup -- )
 : <foo.> ( string -- ) <foo> write ;
 : </foo.> ( string -- ) </foo> write ;
 : in-tag. ( obj quot string -- ) [ <foo.> call ] keep </foo.> ; inline
-M: heading1 (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "h1" in-tag. ;
-M: heading2 (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "h2" in-tag. ;
-M: heading3 (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "h3" in-tag. ;
-M: heading4 (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "h4" in-tag. ;
-M: strong (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "strong" in-tag. ;
-M: emphasis (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "em" in-tag. ;
-M: superscript (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "sup" in-tag. ;
-M: subscript (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "sub" in-tag. ;
-M: inline-code (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "code" in-tag. ;
-M: list-item (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "li" in-tag. ;
-M: list (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "ul" in-tag. ;
-M: paragraph (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "p" in-tag. ;
-M: link (write-farkup) ( obj -- ) [ href>> ] [ text>> ] bi write-link ;
-M: image (write-farkup) ( obj -- ) [ href>> ] [ text>> ] bi write-image-link ;
-M: code (write-farkup) ( obj -- ) [ string>> ] [ mode>> ] bi render-code ;
+M: heading1 (write-farkup) [ child>> (write-farkup) ] "h1" in-tag. ;
+M: heading2 (write-farkup) [ child>> (write-farkup) ] "h2" in-tag. ;
+M: heading3 (write-farkup) [ child>> (write-farkup) ] "h3" in-tag. ;
+M: heading4 (write-farkup) [ child>> (write-farkup) ] "h4" in-tag. ;
+M: strong (write-farkup) [ child>> (write-farkup) ] "strong" in-tag. ;
+M: emphasis (write-farkup) [ child>> (write-farkup) ] "em" in-tag. ;
+M: superscript (write-farkup) [ child>> (write-farkup) ] "sup" in-tag. ;
+M: subscript (write-farkup) [ child>> (write-farkup) ] "sub" in-tag. ;
+M: inline-code (write-farkup) [ child>> (write-farkup) ] "code" in-tag. ;
+M: list-item (write-farkup) [ child>> (write-farkup) ] "li" in-tag. ;
+M: unordered-list (write-farkup) [ child>> (write-farkup) ] "ul" in-tag. ;
+M: ordered-list (write-farkup) [ child>> (write-farkup) ] "ol" in-tag. ;
+M: paragraph (write-farkup) [ child>> (write-farkup) ] "p" in-tag. ;
+M: link (write-farkup) [ href>> ] [ text>> ] bi write-link ;
+M: image (write-farkup) [ href>> ] [ text>> ] bi write-image-link ;
+M: code (write-farkup) [ string>> ] [ mode>> ] bi render-code ;
+M: line (write-farkup) drop <hr/> ;
 M: table-row (write-farkup) ( obj -- )
-    obj>> [ [ [ (write-farkup) ] "td" in-tag. ] each ] "tr" in-tag. ;
-M: table (write-farkup) ( obj -- ) [ obj>> (write-farkup) ] "table" in-tag. ;
-M: fixnum (write-farkup) ( obj -- ) write1 ;
-M: string (write-farkup) ( obj -- ) write ;
-M: vector (write-farkup) ( obj -- ) [ (write-farkup) ] each ;
-M: f (write-farkup) ( obj -- ) drop ;
+    child>> [ [ [ (write-farkup) ] "td" in-tag. ] each ] "tr" in-tag. ;
+M: table (write-farkup) [ child>> (write-farkup) ] "table" in-tag. ;
+M: string (write-farkup) escape-string write ;
+M: vector (write-farkup) [ (write-farkup) ] each ;
+M: f (write-farkup) drop ;
 
 : write-farkup ( string -- )
-    farkup (write-farkup) ;
+    parse-farkup (write-farkup) ;
 
 : convert-farkup ( string -- string' )
-    farkup [ (write-farkup) ] with-string-writer ;
+    parse-farkup [ (write-farkup) ] with-string-writer ;
index cce098f208cfe9ab5c018eec2cf176a46d953f84..7505b3c6126f7588be4bdfc0fac0db318cb71546 100755 (executable)
@@ -14,7 +14,8 @@ html.elements
 html.components\r
 html.components\r
 html.templates.chloe\r
-html.templates.chloe.syntax ;\r
+html.templates.chloe.syntax\r
+html.templates.chloe.compiler ;\r
 IN: furnace.actions\r
 \r
 SYMBOL: params\r
@@ -29,7 +30,8 @@ SYMBOL: rest
         </ul>\r
     ] unless-empty ;\r
 \r
-CHLOE: validation-messages drop render-validation-messages ;\r
+CHLOE: validation-messages\r
+    drop [ render-validation-messages ] [code] ;\r
 \r
 TUPLE: action rest authorize init display validate submit ;\r
 \r
@@ -77,14 +79,14 @@ TUPLE: action rest authorize init display validate submit ;
 \r
 : revalidate-url ( -- url/f )\r
     revalidate-url-key param\r
-    dup [ >url [ same-host? ] keep and ] when ;\r
+    dup [ >url ensure-port [ same-host? ] keep and ] when ;\r
 \r
 : validation-failed ( -- * )\r
     post-request? revalidate-url and [\r
         begin-conversation\r
         nested-forms-key param " " split harvest nested-forms cset\r
         form get form cset\r
-        <redirect>\r
+        <continue-conversation>\r
     ] [ <400> ] if*\r
     exit-with ;\r
 \r
diff --git a/basis/furnace/actions/authors.txt b/basis/furnace/actions/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/actions/summary.txt b/basis/furnace/actions/summary.txt
new file mode 100644 (file)
index 0000000..53b775a
--- /dev/null
@@ -0,0 +1 @@
+Actions and form validation
diff --git a/basis/furnace/actions/tags.txt b/basis/furnace/actions/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 6f5f6fdbf61ba6f6f3d514b7d43f9e26cab17d88..decee690a31f46798f97e27a5e6f42c5c9fe8440 100644 (file)
@@ -3,6 +3,7 @@
 USING: kernel sequences db.tuples alarms calendar db fry
 furnace.db
 furnace.cache
+furnace.asides
 furnace.referrer
 furnace.sessions
 furnace.conversations
@@ -10,20 +11,24 @@ furnace.auth.providers
 furnace.auth.login.permits ;
 IN: furnace.alloy
 
-: <alloy> ( responder db params -- responder' )
-    '[
-        <conversations>
-        <sessions>
-        _ _ <db-persistence>
-        <check-form-submissions>
-    ] call ;
-
-: state-classes { session conversation permit } ; inline
+: state-classes { session aside conversation permit } ; inline
 
 : init-furnace-tables ( -- )
     state-classes ensure-tables
     user ensure-table ;
 
+: <alloy> ( responder db params -- responder' )
+    [ [ init-furnace-tables ] with-db ]
+    [
+        [
+            <asides>
+            <conversations>
+            <sessions>
+        ] 2dip
+        <db-persistence>
+        <check-form-submissions>
+    ] 2bi ;
+
 : start-expiring ( db params -- )
     '[
         _ _ [ state-classes [ expire-state ] each ] with-db
diff --git a/basis/furnace/alloy/authors.txt b/basis/furnace/alloy/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/alloy/summary.txt b/basis/furnace/alloy/summary.txt
new file mode 100644 (file)
index 0000000..7bad952
--- /dev/null
@@ -0,0 +1 @@
+Convenience responder combines several features
diff --git a/basis/furnace/alloy/tags.txt b/basis/furnace/alloy/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/asides/asides.factor b/basis/furnace/asides/asides.factor
new file mode 100644 (file)
index 0000000..6d4196c
--- /dev/null
@@ -0,0 +1,111 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces assocs kernel sequences accessors hashtables
+urls db.types db.tuples math.parser fry logging combinators
+html.templates.chloe.syntax
+http http.server http.server.filters http.server.redirection
+furnace
+furnace.cache
+furnace.sessions
+furnace.redirection ;
+IN: furnace.asides
+
+TUPLE: aside < server-state
+session method url post-data ;
+
+: <aside> ( id -- aside )
+    aside new-server-state ;
+
+aside "ASIDES" {
+    { "session" "SESSION" BIG-INTEGER +not-null+ }
+    { "method" "METHOD" { VARCHAR 10 } }
+    { "url" "URL" URL }
+    { "post-data" "POST_DATA" FACTOR-BLOB }
+} define-persistent
+
+: aside-id-key "__a" ;
+
+TUPLE: asides < server-state-manager ;
+
+: <asides> ( responder -- responder' )
+    asides new-server-state-manager ;
+
+SYMBOL: aside-id
+
+: get-aside ( id -- aside )
+    dup [ aside get-state ] when check-session ;
+
+: request-aside-id ( request -- id )
+    aside-id-key swap request-params at string>number ;
+
+: request-aside ( request -- aside )
+    request-aside-id get-aside ;
+
+: set-aside ( aside -- )
+    [ id>> aside-id set ] when* ;
+
+: init-asides ( asides -- )
+    asides set
+    request get request-aside-id
+    get-aside
+    set-aside ;
+
+M: asides call-responder*
+    [ init-asides ] [ asides set ] [ call-next-method ] tri ;
+
+: touch-aside ( aside -- )
+    asides get touch-state ;
+
+: begin-aside ( url -- )
+    f <aside>
+        swap >>url
+        session get id>> >>session
+        request get method>> >>method
+        request get post-data>> >>post-data
+    [ touch-aside ] [ insert-tuple ] [ set-aside ] tri ;
+
+: end-aside-post ( aside -- response )
+    [ url>> ] [ post-data>> ] bi
+    request [
+        clone
+            swap >>post-data
+            over >>url
+    ] change
+    [ url set ] [ path>> split-path ] bi
+    asides get responder>> call-responder ;
+
+\ end-aside-post DEBUG add-input-logging
+
+ERROR: end-aside-in-get-error ;
+
+: move-on ( id -- response )
+    post-request? [ end-aside-in-get-error ] unless
+    dup method>> {
+        { "GET" [ url>> <redirect> ] }
+        { "HEAD" [ url>> <redirect> ] }
+        { "POST" [ end-aside-post ] }
+    } case ;
+
+: end-aside ( default -- response )
+    aside-id get aside-id off get-aside [ move-on ] [ <redirect> ] ?if ;
+
+M: asides link-attr ( tag -- )
+    drop
+    "aside" optional-attr {
+        { "none" [ aside-id off ] }
+        { "begin" [ url get begin-aside ] }
+        { "current" [ ] }
+        { f [ ] }
+    } case ;
+
+M: asides modify-query ( query asides -- query' )
+    drop
+    aside-id get [
+        aside-id-key associate assoc-union
+    ] when* ;
+
+M: asides modify-form ( asides -- )
+    drop
+    aside-id get
+    aside-id-key
+    hidden-form-field ;
diff --git a/basis/furnace/asides/authors.txt b/basis/furnace/asides/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/asides/summary.txt b/basis/furnace/asides/summary.txt
new file mode 100644 (file)
index 0000000..38f1d58
--- /dev/null
@@ -0,0 +1 @@
+Asides start an interaction which can return to the original page
diff --git a/basis/furnace/asides/tags.txt b/basis/furnace/asides/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 8e18c18df9fdd744025767565ce5af0df67c5e43..1b5c5f9e73b940a83aa629d64e0c45349144425b 100755 (executable)
@@ -3,7 +3,7 @@
 USING: accessors assocs namespaces kernel sequences sets\r
 destructors combinators fry logging\r
 io.encodings.utf8 io.encodings.string io.binary random\r
-checksums checksums.sha2\r
+checksums checksums.sha2 urls\r
 html.forms\r
 http.server\r
 http.server.filters\r
@@ -60,6 +60,10 @@ TUPLE: realm < dispatcher name users checksum secure ;
 \r
 GENERIC: login-required* ( description capabilities realm -- response )\r
 \r
+GENERIC: user-registered ( user realm -- response )\r
+\r
+M: object user-registered 2drop URL" $realm" <redirect> ;\r
+\r
 GENERIC: init-realm ( realm -- )\r
 \r
 GENERIC: logged-in-username ( realm -- username )\r
diff --git a/basis/furnace/auth/authors.txt b/basis/furnace/auth/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/auth/basic/summary.txt b/basis/furnace/auth/basic/summary.txt
new file mode 100644 (file)
index 0000000..26e1125
--- /dev/null
@@ -0,0 +1 @@
+Basic client authentication
diff --git a/basis/furnace/auth/features/deactivate-user/authors.txt b/basis/furnace/auth/features/deactivate-user/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 43560d021c28006477492a53694330322714bfd9..4e80f9188b4f09361507e6cb4108f53b7ba812c0 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel assocs namespaces accessors db db.tuples urls
 http.server.dispatchers
-furnace.conversations
+furnace.asides
 furnace.actions
 furnace.auth
 furnace.auth.providers ;
diff --git a/basis/furnace/auth/features/deactivate-user/summary.txt b/basis/furnace/auth/features/deactivate-user/summary.txt
new file mode 100644 (file)
index 0000000..81a1a71
--- /dev/null
@@ -0,0 +1 @@
+Allow users to deactivate their accounts
diff --git a/basis/furnace/auth/features/deactivate-user/tags.txt b/basis/furnace/auth/features/deactivate-user/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/features/edit-profile/authors.txt b/basis/furnace/auth/features/edit-profile/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index e6d85809b9867511dcd10dd6cee96cbffbf82a28..243ea7bfffc80299421de8053afe3a5b9001952a 100644 (file)
@@ -3,8 +3,8 @@
 USING: kernel accessors namespaces sequences assocs
 validators urls html.forms http.server.dispatchers
 furnace.auth
-furnace.actions
-furnace.conversations ;
+furnace.asides
+furnace.actions ;
 IN: furnace.auth.features.edit-profile
 
 : <edit-profile-action> ( -- action )
index a9d7994e970128165acad686218a1d00ffd0812e..f486f4e246cf10bfddad3055651a0fe7df2741e4 100644 (file)
@@ -4,7 +4,7 @@
 
        <t:title>Edit Profile</t:title>
 
-       <t:form t:action="$realm/edit-profile">
+       <t:form t:action="$realm/edit-profile" autocomplete="off">
 
        <table>
        
@@ -61,7 +61,7 @@
        </table>
 
        <p>
-               <input type="submit" value="Update" />
+               <button>Update</button>
                <t:validation-messages />
        </p>
 
diff --git a/basis/furnace/auth/features/edit-profile/summary.txt b/basis/furnace/auth/features/edit-profile/summary.txt
new file mode 100644 (file)
index 0000000..de0e1f5
--- /dev/null
@@ -0,0 +1 @@
+Allow users to edit account info
diff --git a/basis/furnace/auth/features/edit-profile/tags.txt b/basis/furnace/auth/features/edit-profile/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/features/recover-password/authors.txt b/basis/furnace/auth/features/recover-password/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 46e52d5319435e5f982dca7692a83e7cfbc82438..a8b67513a4317a249a684738afc3323b6c79e909 100644 (file)
@@ -32,7 +32,7 @@
 
                </table>
 
-               <input type="submit" value="Recover password" />
+               <button>Recover password</button>
 
        </t:form>
 
index a71118ea3111819281cd3f4197ed2d744687cb18..a8ea635a1f9826e05306c832d2b6335b8c8b12e1 100644 (file)
@@ -31,7 +31,7 @@
                </table>
 
                <p>
-                       <input type="submit" value="Set password" />
+                       <button>Set password</button>
                        <t:validation-messages />
                </p>
 
index a0fd05c6d49d62d5af59623e05b8214c0b59d307..49e692d5a6319a269e5b719501a67eac445b3285 100644 (file)
@@ -19,7 +19,7 @@ SYMBOL: lost-password-from
         [ username>> "username" set-query-param ]
         [ ticket>> "ticket" set-query-param ]
         bi
-    adjust-url relative-to-request ;
+    adjust-url ;
 
 : password-email ( user -- email )
     <email>
diff --git a/basis/furnace/auth/features/recover-password/summary.txt b/basis/furnace/auth/features/recover-password/summary.txt
new file mode 100644 (file)
index 0000000..53c5c82
--- /dev/null
@@ -0,0 +1 @@
+Allow users to receive a new password
diff --git a/basis/furnace/auth/features/recover-password/tags.txt b/basis/furnace/auth/features/recover-password/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/features/registration/authors.txt b/basis/furnace/auth/features/registration/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 9815f21945824b941e71b559d6ef3531d47c527f..b0d6971d1bfac7fcd3e7e85769b021b9460e4173 100644 (file)
@@ -4,7 +4,7 @@
 
        <t:title>New User Registration</t:title>
 
-       <t:form t:action="register">
+       <t:form t:action="register" autocomplete="off">
 
                <table>
 
@@ -62,7 +62,7 @@
 
                <p>
 
-                       <input type="submit" value="Register" />
+                       <button>Register</button>
                        <t:validation-messages />
 
                </p>
index da58e2b2ed21151cf0984954a9d47123070acf7c..ef8923c98b8d80a4b5ba58b20a8a178dd704a601 100644 (file)
@@ -33,8 +33,7 @@ IN: furnace.auth.features.registration
             users new-user [ user-exists ] unless*
 
             realm get init-user-profile
-
-            URL" $realm" <redirect>
+            realm get user-registered
         ] >>submit
     <auth-boilerplate>
     <secure-realm-only> ;
diff --git a/basis/furnace/auth/features/registration/summary.txt b/basis/furnace/auth/features/registration/summary.txt
new file mode 100644 (file)
index 0000000..7206d72
--- /dev/null
@@ -0,0 +1 @@
+Allow new users to register from the login page
diff --git a/basis/furnace/auth/features/registration/tags.txt b/basis/furnace/auth/features/registration/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/login/authors.txt b/basis/furnace/auth/login/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 1a4477023d6e32b2f3e7d5ff0d45431456c35479..2c98672490def526fcd02369ae63f05124251e65 100755 (executable)
@@ -5,6 +5,7 @@ calendar validators urls logging html.forms
 http http.server http.server.dispatchers\r
 furnace\r
 furnace.auth\r
+furnace.asides\r
 furnace.actions\r
 furnace.sessions\r
 furnace.utilities\r
@@ -93,9 +94,18 @@ SYMBOL: capabilities
         [ logout ] >>submit ;\r
 \r
 M: login-realm login-required* ( description capabilities login -- response )\r
-    begin-aside\r
-    [ description cset ] [ capabilities cset ] [ drop ] tri*\r
-    URL" $realm/login" >secure-url <redirect> ;\r
+    begin-conversation\r
+    [ description cset ] [ capabilities cset ] [ secure>> ] tri*\r
+    [\r
+        url get >secure-url begin-aside\r
+        URL" $realm/login" >secure-url <continue-conversation>\r
+    ] [\r
+        url get begin-aside\r
+        URL" $realm/login" <continue-conversation>\r
+    ] if ;\r
+\r
+M: login-realm user-registered ( user realm -- )\r
+    drop successful-login ;\r
 \r
 : <login-realm> ( responder name -- auth )\r
     login-realm new-realm\r
index 81f9520e7611cdc8233e209acc4d39e204c4a8b0..766c097ca5fa5b39d8999bdd6d9cac4010b4cd24 100644 (file)
@@ -35,7 +35,7 @@
 
                <p>
 
-                       <input type="submit" value="Log in" />
+                       <button>Log in</button>
                        <t:validation-messages />
 
                </p>
diff --git a/basis/furnace/auth/login/permits/authors.txt b/basis/furnace/auth/login/permits/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/auth/login/permits/tags.txt b/basis/furnace/auth/login/permits/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/login/summary.txt b/basis/furnace/auth/login/summary.txt
new file mode 100644 (file)
index 0000000..c7e32f1
--- /dev/null
@@ -0,0 +1 @@
+Login page authentication
diff --git a/basis/furnace/auth/login/tags.txt b/basis/furnace/auth/login/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/providers/assoc/summary.txt b/basis/furnace/auth/providers/assoc/summary.txt
new file mode 100644 (file)
index 0000000..c1a0218
--- /dev/null
@@ -0,0 +1 @@
+Look up user credentials in an assoc object
diff --git a/basis/furnace/auth/providers/authors.txt b/basis/furnace/auth/providers/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/auth/providers/db/authors.txt b/basis/furnace/auth/providers/db/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/auth/providers/db/summary.txt b/basis/furnace/auth/providers/db/summary.txt
new file mode 100644 (file)
index 0000000..7a49ba2
--- /dev/null
@@ -0,0 +1 @@
+Look up user credentials in the database
diff --git a/basis/furnace/auth/providers/db/tags.txt b/basis/furnace/auth/providers/db/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/providers/null/summary.txt b/basis/furnace/auth/providers/null/summary.txt
new file mode 100644 (file)
index 0000000..4f198b3
--- /dev/null
@@ -0,0 +1 @@
+Refuse all authentication requests
diff --git a/basis/furnace/auth/providers/summary.txt b/basis/furnace/auth/providers/summary.txt
new file mode 100644 (file)
index 0000000..a720605
--- /dev/null
@@ -0,0 +1 @@
+Pluggable authentication backends
diff --git a/basis/furnace/auth/providers/tags.txt b/basis/furnace/auth/providers/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/auth/summary.txt b/basis/furnace/auth/summary.txt
new file mode 100644 (file)
index 0000000..81d6eee
--- /dev/null
@@ -0,0 +1 @@
+Authentication
diff --git a/basis/furnace/auth/tags.txt b/basis/furnace/auth/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/authors.txt b/basis/furnace/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/boilerplate/authors.txt b/basis/furnace/boilerplate/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 59f71b15242d0308edd69d8d6bef291ced2c1c85..946372e1f8c3f62dd14f47d3ceb4b4f3d05838e1 100644 (file)
@@ -17,16 +17,13 @@ TUPLE: boilerplate < filter-responder template init ;
         [ ] >>init ;
 
 : wrap-boilerplate? ( response -- ? )
-    {
-        [ code>> { [ 200 = ] [ 400 499 between? ] } 1|| ]
-        [ content-type>> "text/html" = ]
-    } 1&& ;
+    { [ code>> 200 = ] [ content-type>> "text/html" = ] } 1&& ;
 
 M:: boilerplate call-responder* ( path responder -- )
     begin-form
     path responder call-next-method
     responder init>> call
-    dup content-type>> "text/html" = [
+    dup wrap-boilerplate? [
         clone [| body |
             [
                 body
diff --git a/basis/furnace/boilerplate/summary.txt b/basis/furnace/boilerplate/summary.txt
new file mode 100644 (file)
index 0000000..8ed9956
--- /dev/null
@@ -0,0 +1 @@
+Adding common headers/footers to pages
diff --git a/basis/furnace/boilerplate/tags.txt b/basis/furnace/boilerplate/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/cache/authors.txt b/basis/furnace/cache/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/cache/summary.txt b/basis/furnace/cache/summary.txt
new file mode 100644 (file)
index 0000000..32fda13
--- /dev/null
@@ -0,0 +1 @@
+Shared code for storing session state in the database
diff --git a/basis/furnace/cache/tags.txt b/basis/furnace/cache/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/chloe-tags/authors.txt b/basis/furnace/chloe-tags/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 4e619ad534b191eba8530527b821a3e41a46174c..697c885a0143c7a0fc8d6b3362fb29f8937f5350 100644 (file)
@@ -37,12 +37,12 @@ IN: furnace.chloe-tags
         <url>
             swap parse-query-attr >>query
             -rot a-url-path >>path
-        adjust-url relative-to-request
+        adjust-url
     ] if ;
 
 : compile-a-url ( tag -- )
     {
-        [ "href" required-attr compile-attr ]
+        [ "href" optional-attr compile-attr ]
         [ "rest" optional-attr compile-attr ]
         [ "query" optional-attr compile-attr ]
         [ "value" optional-attr compile-attr ]
@@ -59,8 +59,12 @@ CHLOE: write-atom drop [ write-atom-feeds ] [code] ;
     attrs>> '[ [ [ _ ] dip link-attr ] each-responder ] [code] ;
 
 : a-start-tag ( tag -- )
-    [ compile-link-attrs ] [ compile-a-url ] bi
-    [ <a =href a> ] [code] ;
+    [ <a ] [code]
+    [ non-chloe-attrs-only compile-attrs ]
+    [ compile-link-attrs ]
+    [ compile-a-url ]
+    tri
+    [ =href a> ] [code] ;
 
 : a-end-tag ( tag -- )
     drop [ </a> ] [code] ;
@@ -70,11 +74,16 @@ CHLOE: a
         [ a-start-tag ] [ compile-children ] [ a-end-tag ] tri
     ] compile-with-scope ;
 
+CHLOE: base
+    compile-a-url [ <base =href base/> ] [code] ;
+
 : compile-hidden-form-fields ( for -- )
     '[
-        _ [ "," split [ hidden render ] each ] when*
-        nested-forms get " " join f like nested-forms-key hidden-form-field
-        [ modify-form ] each-responder
+        <div "display: none;" =style div>
+            _ [ "," split [ hidden render ] each ] when*
+            nested-forms get " " join f like nested-forms-key hidden-form-field
+            [ modify-form ] each-responder
+        </div>
     ] [code] ;
 
 : compile-form-attrs ( method action attrs -- )
@@ -109,7 +118,7 @@ CHLOE: form
 
 STRING: button-tag-markup
 <t:form class="inline" xmlns:t="http://factorcode.org/chloe/1.0">
-    <button type="submit"></button>
+    <div style="display: inline;"><button type="submit"></button></div>
 </t:form>
 ;
 
@@ -120,7 +129,7 @@ CHLOE: button
     button-tag-markup string>xml body>>
     {
         [ [ attrs>> chloe-attrs-only ] dip add-tag-attrs ]
-        [ [ attrs>> non-chloe-attrs-only ] dip "button" tag-named add-tag-attrs ]
-        [ [ children>> ] dip "button" tag-named (>>children) ]
+        [ [ attrs>> non-chloe-attrs-only ] dip "button" deep-tag-named add-tag-attrs ]
+        [ [ children>> ] dip "button" deep-tag-named (>>children) ]
         [ nip ]
     } 2cleave compile-chloe-tag ;
diff --git a/basis/furnace/chloe-tags/summary.txt b/basis/furnace/chloe-tags/summary.txt
new file mode 100644 (file)
index 0000000..b80b1d8
--- /dev/null
@@ -0,0 +1 @@
+Furnace-specific Chloe tags
diff --git a/basis/furnace/chloe-tags/tags.txt b/basis/furnace/chloe-tags/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/conversations/authors.txt b/basis/furnace/conversations/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 1c28193de8e98b383fc227dddbb840d392a22119..671296ce575975d871f694be5aaf8a45e2d96a2f 100644 (file)
@@ -11,18 +11,13 @@ furnace.sessions
 furnace.redirection ;
 IN: furnace.conversations
 
-TUPLE: conversation < scope
-session
-method url post-data ;
+TUPLE: conversation < scope session ;
 
-: <conversation> ( id -- aside )
+: <conversation> ( id -- conversation )
     conversation new-server-state ;
 
 conversation "CONVERSATIONS" {
     { "session" "SESSION" BIG-INTEGER +not-null+ }
-    { "method" "METHOD" { VARCHAR 10 } }
-    { "url" "URL" URL }
-    { "post-data" "POST_DATA" FACTOR-BLOB }
 } define-persistent
 
 : conversation-id-key "__c" ;
@@ -46,8 +41,7 @@ SYMBOL: conversation-id
     conversation get scope-change ; inline
 
 : get-conversation ( id -- conversation )
-    dup [ conversation get-state ] when
-    dup [ dup session>> session get id>> = [ drop f ] unless ] when ;
+    dup [ conversation get-state ] when check-session ;
 
 : request-conversation-id ( request -- id )
     conversation-id-key swap request-params at string>number ;
@@ -88,22 +82,21 @@ M: conversations call-responder*
 : add-conversation ( conversation -- )
     [ touch-conversation ] [ insert-tuple ] bi ;
 
-: begin-conversation* ( -- conversation )
-    empty-conversastion dup add-conversation ;
-
 : begin-conversation ( -- )
     conversation get [
-        begin-conversation*
-        set-conversation
+        empty-conversastion
+        [ add-conversation ]
+        [ set-conversation ] bi
     ] unless ;
 
 : end-conversation ( -- )
     conversation off
     conversation-id off ;
 
-: <conversation-redirect> ( url seq -- response )
-    begin-conversation
-    [ [ get ] keep cset ] each
+: <continue-conversation> ( url -- response )
+    conversation-id get
+    conversation-id-key
+    set-query-param
     <redirect> ;
 
 : restore-conversation ( seq -- )
@@ -114,64 +107,6 @@ M: conversations call-responder*
         bi
     ] [ 2drop ] if ;
 
-: begin-aside ( -- )
-    begin-conversation
-    conversation get
-        request get
-        [ method>> >>method ]
-        [ url>> >>url ]
-        [ post-data>> >>post-data ]
-        tri
-    touch-conversation ;
-
-: end-aside-post ( aside -- response )
-    request [
-        clone
-            over post-data>> >>post-data
-            over url>> >>url
-    ] change
-    [ url>> url set ]
-    [ url>> path>> split-path ] bi
-    conversations get responder>> call-responder ;
-
-\ end-aside-post DEBUG add-input-logging
-
-ERROR: end-aside-in-get-error ;
-
-: move-on ( id -- response )
-    post-request? [ end-aside-in-get-error ] unless
-    dup method>> {
-        { "GET" [ url>> <redirect> ] }
-        { "HEAD" [ url>> <redirect> ] }
-        { "POST" [ end-aside-post ] }
-    } case ;
-
-: get-aside ( id -- conversation )
-    get-conversation dup [ dup method>> [ drop f ] unless ] when ;
-
-: end-aside* ( url id -- response )
-    get-aside [ move-on ] [ <redirect> ] ?if ;
-
-: end-aside ( default -- response )
-    conversation-id get
-    end-conversation
-    end-aside* ;
-
-M: conversations link-attr ( tag -- )
-    drop
-    "aside" optional-attr {
-        { "none" [ conversation-id off ] }
-        { "begin" [ begin-aside ] }
-        { "current" [ ] }
-        { f [ ] }
-    } case ;
-
-M: conversations modify-query ( query conversations -- query' )
-    drop
-    conversation-id get [
-        conversation-id-key associate assoc-union
-    ] when* ;
-
 M: conversations modify-form ( conversations -- )
     drop
     conversation-id get
diff --git a/basis/furnace/conversations/summary.txt b/basis/furnace/conversations/summary.txt
new file mode 100644 (file)
index 0000000..4f7123a
--- /dev/null
@@ -0,0 +1 @@
+Retaining state between form submissions and redirects
diff --git a/basis/furnace/conversations/tags.txt b/basis/furnace/conversations/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/db/authors.txt b/basis/furnace/db/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/db/summary.txt b/basis/furnace/db/summary.txt
new file mode 100644 (file)
index 0000000..d1f51c4
--- /dev/null
@@ -0,0 +1 @@
+Database connection pooling
diff --git a/basis/furnace/db/tags.txt b/basis/furnace/db/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 223b20455d644280099728a7ecbde47a6897fecd..00e4f6f152584903da3a5e6840eccffc9b59547c 100644 (file)
@@ -1,7 +1,7 @@
 IN: furnace.tests
-USING: http.server.dispatchers http.server.responses
+USING: http http.server.dispatchers http.server.responses
 http.server furnace tools.test kernel namespaces accessors
-io.streams.string ;
+io.streams.string urls ;
 TUPLE: funny-dispatcher < dispatcher ;
 
 : <funny-dispatcher> funny-dispatcher new-dispatcher ;
@@ -33,3 +33,9 @@ M: base-path-check-responder call-responder*
 [ "<input type='hidden' name='foo' value='&amp;&amp;&amp;'/>" ]
 [ [ "&&&" "foo" hidden-form-field ] with-string-writer ]
 unit-test
+
+[ f ] [ <request> request [ referrer ] with-variable ] unit-test
+
+[ t ] [ URL" http://foo" dup url [ same-host? ] with-variable ] unit-test
+
+[ f ] [ f URL" http://foo" url [ same-host? ] with-variable ] unit-test
index 6a798abb9fb5c6583fd9e5793abdc0c4805831d8..7285c436bcbd658822b0b0afb94d7be9e1b6c545 100644 (file)
@@ -4,7 +4,7 @@ USING: namespaces make assocs sequences kernel classes splitting
 vocabs.loader accessors strings combinators arrays
 continuations present fry
 urls html.elements
-http http.server http.server.redirection ;
+http http.server http.server.redirection http.server.remapping ;
 IN: furnace
 
 : nested-responders ( -- seq )
@@ -37,6 +37,10 @@ GENERIC: modify-query ( query responder -- query' )
 
 M: object modify-query drop ;
 
+GENERIC: modify-redirect-query ( query responder -- query' )
+
+M: object modify-redirect-query drop ;
+
 GENERIC: adjust-url ( url -- url' )
 
 M: url adjust-url
@@ -47,6 +51,14 @@ M: url adjust-url
 
 M: string adjust-url ;
 
+GENERIC: adjust-redirect-url ( url -- url' )
+
+M: url adjust-redirect-url
+    adjust-url
+    [ [ modify-redirect-query ] each-responder ] change-query ;
+
+M: string adjust-redirect-url ;
+
 GENERIC: link-attr ( tag responder -- )
 
 M: object link-attr 2drop ;
@@ -77,16 +89,23 @@ M: object modify-form drop ;
         ] }
     } case ;
 
-: referrer ( -- referrer )
+: referrer ( -- referrer/f )
     #! Typo is intentional, its in the HTTP spec!
-    "referer" request get header>> at >url ;
+    "referer" request get header>> at
+    dup [ >url ensure-port [ remap-port ] change-port ] when ;
 
 : user-agent ( -- user-agent )
     "user-agent" request get header>> at "" or ;
 
 : same-host? ( url -- ? )
-    url get
-    [ [ protocol>> ] [ host>> ] [ port>> ] tri 3array ] bi@ = ;
+    dup [
+        url get [
+            [ protocol>> ]
+            [ host>> ]
+            [ port>> remap-port ]
+            tri 3array
+        ] bi@ =
+    ] when ;
 
 : cookie-client-state ( key request -- value/f )
     swap get-cookie dup [ value>> ] when ;
diff --git a/basis/furnace/json/summary.txt b/basis/furnace/json/summary.txt
new file mode 100644 (file)
index 0000000..60656a2
--- /dev/null
@@ -0,0 +1 @@
+Sending JSON responses to the client
diff --git a/basis/furnace/redirection/authors.txt b/basis/furnace/redirection/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index ff3ce951cb2a69d72ac7af1921d5340e1cf2604e..c5a63a795c7aff7de58eea2e677967334f2bfcac 100644 (file)
@@ -1,13 +1,12 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors combinators namespaces fry
-io.servers.connection urls http http.server
-http.server.redirection http.server.responses
-http.server.filters furnace ;
+USING: kernel accessors combinators namespaces fry urls http
+http.server http.server.redirection http.server.responses
+http.server.remapping http.server.filters furnace ;
 IN: furnace.redirection
 
 : <redirect> ( url -- response )
-    adjust-url request get method>> {
+    adjust-redirect-url request get method>> {
         { "GET" [ <temporary-redirect> ] }
         { "HEAD" [ <temporary-redirect> ] }
         { "POST" [ <permanent-redirect> ] }
@@ -16,7 +15,7 @@ IN: furnace.redirection
 : >secure-url ( url -- url' )
     clone
         "https" >>protocol
-        secure-port >>port ;
+        secure-http-port >>port ;
 
 : <secure-redirect> ( url -- response )
     >secure-url <redirect> ;
diff --git a/basis/furnace/redirection/summary.txt b/basis/furnace/redirection/summary.txt
new file mode 100644 (file)
index 0000000..c31a9ff
--- /dev/null
@@ -0,0 +1 @@
+Various forms of URL redirection
diff --git a/basis/furnace/redirection/tags.txt b/basis/furnace/redirection/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/referrer/authors.txt b/basis/furnace/referrer/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 4cfd4bb6c6b03d137d9a1c9a24e86a1c087f3313..003028ab1ea787e2e173f5f2590acf2f4b5c78ca 100644 (file)
@@ -14,4 +14,4 @@ M: referrer-check call-responder*
     [ 2drop 403 "Bad referrer" <trivial-response> ] if ;
 
 : <check-form-submissions> ( responder -- responder' )
-    [ same-host? post-request? not or ] <referrer-check> ;
+    [ post-request? [ same-host? ] [ drop t ] if ] <referrer-check> ;
diff --git a/basis/furnace/referrer/summary.txt b/basis/furnace/referrer/summary.txt
new file mode 100644 (file)
index 0000000..774f038
--- /dev/null
@@ -0,0 +1 @@
+Referrer checking
diff --git a/basis/furnace/referrer/tags.txt b/basis/furnace/referrer/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/scopes/authors.txt b/basis/furnace/scopes/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/scopes/summary.txt b/basis/furnace/scopes/summary.txt
new file mode 100644 (file)
index 0000000..efbe4c6
--- /dev/null
@@ -0,0 +1 @@
+Shared code for storing scopes in the database
diff --git a/basis/furnace/scopes/tags.txt b/basis/furnace/scopes/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 7c1b2f22790bfdca05f14a555a40b7eaa3ce2abd..56741201965fd1ac8e400094bb30d47ac3e97260 100755 (executable)
@@ -1 +1,2 @@
 Doug Coleman
+Slava Pestov
index 718953c58ce24f0206962550b312253dbe643ed8..b7120aaf11cc765a98ffc2f62d17021f7932ad3b 100755 (executable)
@@ -107,3 +107,8 @@ M: sessions call-responder* ( path responder -- response )
     sessions set
     request-session [ begin-session ] unless*
     existing-session put-session-cookie ;
+
+SLOT: session
+
+: check-session ( state/f -- state/f )
+    dup [ dup session>> session get id>> = [ drop f ] unless ] when ;
diff --git a/basis/furnace/sessions/summary.txt b/basis/furnace/sessions/summary.txt
new file mode 100644 (file)
index 0000000..da2783b
--- /dev/null
@@ -0,0 +1 @@
+Session management
diff --git a/basis/furnace/sessions/tags.txt b/basis/furnace/sessions/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/syndication/authors.txt b/basis/furnace/syndication/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/syndication/summary.txt b/basis/furnace/syndication/summary.txt
new file mode 100644 (file)
index 0000000..8ced718
--- /dev/null
@@ -0,0 +1 @@
+Atom feed syndication
index 396296bfac27c9c84de49f83d7127f2ad54767d3..a326e62f02c94907c0c381c05bcbc3ec20512a5c 100644 (file)
@@ -32,7 +32,7 @@ M: object >entry
 : process-entries ( seq -- seq' )
     20 short head-slice [
         >entry clone
-        [ adjust-url relative-to-request ] change-url
+        [ adjust-url ] change-url
     ] map ;
 
 : <feed-content> ( body -- response )
@@ -46,7 +46,7 @@ TUPLE: feed-action < action title url entries ;
             feed new
                 _
                 [ title>> call >>title ]
-                [ url>> call adjust-url relative-to-request >>url ]
+                [ url>> call adjust-url >>url ]
                 [ entries>> call process-entries >>entries ]
                 tri
             <feed-content>
diff --git a/basis/furnace/syndication/tags.txt b/basis/furnace/syndication/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/tags.txt b/basis/furnace/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/furnace/utilities/authors.txt b/basis/furnace/utilities/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/furnace/utilities/summary.txt b/basis/furnace/utilities/summary.txt
new file mode 100644 (file)
index 0000000..ab3b730
--- /dev/null
@@ -0,0 +1 @@
+Odds and ends
diff --git a/basis/furnace/utilities/tags.txt b/basis/furnace/utilities/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/generalizations/authors.txt b/basis/generalizations/authors.txt
new file mode 100644 (file)
index 0000000..6c66b74
--- /dev/null
@@ -0,0 +1,4 @@
+Chris Double
+Doug Coleman
+Eduardo Cavazos
+Slava Pestov
diff --git a/basis/generalizations/summary.txt b/basis/generalizations/summary.txt
new file mode 100644 (file)
index 0000000..a8ccb7d
--- /dev/null
@@ -0,0 +1 @@
+Generalized stack shufflers and combinators to arbitrary numbers of inputs
index c7d5413a4721d0d8aa6733cb77d5ad0e72ffb117..14ddb0ed9b7cbc7352097cabad4afcf60c8a5bc6 100755 (executable)
@@ -1,6 +1,6 @@
 ! Copyright (C) 2007 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: parser-combinators regexp lists sequences kernel
+USING: parser-combinators parser-combinators.regexp lists sequences kernel
 promises strings unicode.case ;
 IN: globs
 
index 21eab2b8f125f9f46421547b08df9c2af2aaf9a8..6c387632ed526e202e9d6fbfb855ca2842cabfe5 100755 (executable)
@@ -190,3 +190,8 @@ M: heap heap-pop ( heap -- value key )
     [ dup heap-empty? not ]
     [ dup heap-pop swap 2array ]
     [ ] produce nip ;
+
+: slurp-heap ( heap quot: ( elt -- ) -- )
+    over heap-empty? [ 2drop ] [
+        [ [ heap-pop drop ] dip call ] [ slurp-heap ] 2bi
+    ] if ; inline recursive
index aef6ce68093f6ee7c6752256ade4c55a209ce812..9fb837a8735955f56ac80fc64074969faf8ba2e3 100755 (executable)
@@ -312,13 +312,13 @@ ARTICLE: "cookbook-pitfalls" "Pitfalls to avoid"
     { "When a source file uses two vocabularies which define words with the same name, the order of the vocabularies in the " { $link POSTPONE: USE: } " or " { $link POSTPONE: USING: } " forms is important. The parser prints warnings when vocabularies shadow words from other vocabularies; see " { $link "vocabulary-search-shadow" } ". The " { $vocab-link "qualified" } " vocabulary implements qualified naming, which can be used to resolve ambiguities." }
     { "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, method precedence is undefined for objects that are instances of both classes. See " { $link "method-order" } " for details." }
+    { "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 "inference" } " vocabulary can be used to ensure that any methods your vocabulary defines on core generic words have static stack effects:"
-    { $code "\"inference\" test" }
+    "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." }
index 9d57e758c1abacfea0dca8d1234b45a2b7923ee1..51750d772fab63d634269b32501c07ba41fa6f5c 100755 (executable)
@@ -1,10 +1,10 @@
 USING: help help.markup help.syntax help.definitions help.topics
 namespaces words sequences classes assocs vocabs kernel arrays
 prettyprint.backend kernel.private io generic math system
-strings sbufs vectors byte-arrays
-quotations io.streams.byte-array
-classes.builtin parser lexer classes.predicate classes.union
-classes.intersection classes.singleton classes.tuple ;
+strings sbufs vectors byte-arrays quotations
+io.streams.byte-array classes.builtin parser lexer
+classes.predicate classes.union classes.intersection
+classes.singleton classes.tuple tools.vocabs.browser ;
 IN: help.handbook
 
 ARTICLE: "conventions" "Conventions"
@@ -108,6 +108,7 @@ USE: io.buffers
 ARTICLE: "collections" "Collections" 
 { $heading "Sequences" }
 { $subsection "sequences" }
+{ $subsection "virtual-sequences" }
 { $subsection "namespaces-make" }
 "Fixed-length sequences:"
 { $subsection "arrays" }
@@ -138,7 +139,7 @@ ARTICLE: "collections" "Collections"
 { $subsection "heaps" }
 { $subsection "graphs" }
 { $subsection "buffers" }
-"There are many other collections in " { $snippet "extra/" } ", such as " { $vocab-link "disjoint-sets" } ", " { $vocab-link "persistent-vectors" } ", and " { $vocab-link "tuple-arrays" } "." ;
+"There are also many other vocabularies tagged " { $link T{ vocab-tag { name "collections" } } } " in the library." ;
 
 USING: io.encodings.utf8 io.encodings.utf16 io.encodings.binary io.encodings.ascii io.files ;
 
@@ -243,7 +244,8 @@ ARTICLE: "handbook-language-reference" "Language reference"
 { $subsection "program-org" }
 { $subsection "numbers" }
 { $subsection "collections" }
-{ $subsection "io" } ;
+{ $subsection "io" }
+"Vocabularies tagged " { $link T{ vocab-tag { name "extensions" } } } " implement various additional language abstractions." ;
 
 ARTICLE: "handbook-environment-reference" "Environment reference"
 { $subsection "prettyprint" }
diff --git a/basis/help/html/html-tests.factor b/basis/help/html/html-tests.factor
new file mode 100644 (file)
index 0000000..475b211
--- /dev/null
@@ -0,0 +1,5 @@
+IN: help.html.tests
+USING: html.streams classes.predicate help.topics help.markup
+io.streams.string accessors prettyprint kernel tools.test ;
+
+[ ] [ [ [ \ predicate-instance? def>> . ] with-html-writer ] with-string-writer drop ] unit-test
index b1bf8958a82e31833c6405e8197ab30eaf73bdf9..386dca9576bcd9a463c4d9ffb54435fc4fafa9cf 100644 (file)
@@ -1,5 +1,127 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
+USING: io.encodings.utf8 io.encodings.ascii io.encodings.binary
+io.files html.streams html.elements html.components help kernel
+assocs sequences make words accessors arrays help.topics vocabs
+tools.vocabs tools.vocabs.browser namespaces prettyprint io
+vocabs.loader serialize fry memoize unicode.case math.order
+sorting ;
 IN: help.html
 
+: escape-char ( ch -- )
+    dup H{
+        { CHAR: " "__quote__" }
+        { CHAR: * "__star__" }
+        { CHAR: : "__colon__" }
+        { CHAR: < "__lt__" }
+        { CHAR: > "__gt__" }
+        { CHAR: ? "__question__" }
+        { CHAR: \\ "__backslash__" }
+        { CHAR: | "__pipe__" }
+        { CHAR: _ "__underscore__" }
+        { CHAR: / "__slash__" }
+        { CHAR: \\ "__backslash__" }
+        { CHAR: , "__comma__" }
+    } at [ % ] [ , ] ?if ;
 
+: escape-filename ( string -- filename )
+    [ [ escape-char ] each ] "" make ;
+
+GENERIC: topic>filename* ( topic -- name prefix )
+
+M: word topic>filename*
+    dup vocabulary>> [
+        [ name>> ] [ vocabulary>> ] bi 2array "word"
+    ] [ drop f f ] if ;
+
+M: link topic>filename* name>> dup [ "article" ] [ topic>filename* ] if ;
+M: word-link topic>filename* name>> topic>filename* ;
+M: vocab-spec topic>filename* vocab-name "vocab" ;
+M: vocab-tag topic>filename* name>> "tag" ;
+M: vocab-author topic>filename* name>> "author" ;
+M: f topic>filename* drop \ f topic>filename* ;
+
+: topic>filename ( topic -- filename )
+    topic>filename* dup [
+        [
+            % "-" %
+            dup array?
+            [ [ escape-filename ] map "," join ]
+            [ escape-filename ]
+            if % ".html" %
+        ] "" make
+    ] [ 2drop f ] if ;
+
+M: topic browser-link-href topic>filename ;
+
+: help-stylesheet ( -- )
+    "resource:basis/help/html/stylesheet.css" ascii file-contents write ;
+
+: help>html ( topic -- )
+    dup topic>filename utf8 [
+        dup article-title
+        [ <style> help-stylesheet </style> ]
+        [ [ help ] with-html-writer ] simple-page
+    ] with-file-writer ;
+
+: all-vocabs-really ( -- seq )
+    #! Hack.
+    all-vocabs values concat
+    vocabs [ find-vocab-root not ] filter [ vocab ] map append ;
+
+: all-topics ( -- topics )
+    [
+        articles get keys [ >link ] map %
+        all-words [ >link ] map %
+        all-authors [ <vocab-author> ] map %
+        all-tags [ <vocab-tag> ] map %
+        all-vocabs-really %
+    ] { } make ;
+
+: serialize-index ( index file -- )
+    [ [ [ topic>filename ] dip ] { } assoc-map-as object>bytes ] dip
+    binary set-file-contents ;
+
+: generate-indices ( -- )
+    articles get keys [ [ >link ] [ article-title ] bi ] { } map>assoc "articles.idx" serialize-index
+    all-words [ dup name>> ] { } map>assoc "words.idx" serialize-index
+    all-vocabs-really [ dup vocab-name ] { } map>assoc "vocabs.idx" serialize-index ;
+
+: generate-help-files ( -- )
+    all-topics [ help>html ] each ;
+
+: generate-help ( -- )
+    { "resource:core" "resource:basis" "resource:extra" } vocab-roots [
+        load-everything
+
+        "/tmp/docs/" make-directory
+
+        "/tmp/docs/" [
+            generate-indices
+            generate-help-files
+        ] with-directory
+    ] with-variable ;
+
+MEMO: load-index ( name -- index )
+    binary file-contents bytes>object ;
+
+TUPLE: result title href ;
+
+M: result link-title title>> ;
+
+M: result link-href href>> ;
+
+: offline-apropos ( string index -- results )
+    load-index swap >lower
+    '[ [ drop _ ] dip >lower subseq? ] assoc-filter
+    [ swap result boa ] { } assoc>map
+    [ [ title>> ] compare ] sort ;
+
+: article-apropos ( string -- results )
+    "articles.idx" offline-apropos ;
+
+: word-apropos ( string -- results )
+    "words.idx" offline-apropos ;
+
+: vocab-apropos ( string -- results )
+    "vocabs.idx" offline-apropos ;
diff --git a/basis/help/html/stylesheet.css b/basis/help/html/stylesheet.css
new file mode 100644 (file)
index 0000000..ff657d6
--- /dev/null
@@ -0,0 +1,4 @@
+a:link { text-decoration: none; color: #00004c; }
+a:visited { text-decoration: none; color: #00004c; }
+a:active { text-decoration: none; color: #00004c; }
+a:hover { text-decoration: underline; color: #00004c; }
index d49262e7c8e248572aaebdda9709cba38ecbc873..be6206f59ca8b7a1bea6c1ec1ac12894c7040145 100755 (executable)
@@ -61,10 +61,10 @@ IN: help.lint
 : vocab-exists? ( name -- ? )
     dup vocab swap "all-vocabs" get member? or ;
 
-: check-modules ( word element -- )
-    nip \ $vocab-link swap elements [
+: check-modules ( element -- )
+    \ $vocab-link swap elements [
         second
-        vocab-exists? [ "Missing vocabulary" throw ] unless
+        vocab-exists? [ "$vocab-link to non-existent vocabulary" throw ] unless
     ] each ;
 
 : check-rendering ( word element -- )
@@ -91,7 +91,7 @@ M: help-error error.
                 2dup check-examples
                 2dup check-values
                 2dup check-see-also
-                2dup check-modules
+                2dup nip check-modules
                 2dup drop check-rendering
             ] assert-depth 2drop
         ] check-something
@@ -101,12 +101,20 @@ M: help-error error.
 
 : check-article ( article -- )
     [
-        [ dup check-rendering ] assert-depth drop
+        dup article-content [
+            2dup check-modules check-rendering
+        ] assert-depth 2drop
     ] check-something ;
 
+: files>vocabs ( -- assoc )
+    vocabs
+    [ [ [ vocab-docs-path ] keep ] H{ } map>assoc ]
+    [ [ [ vocab-source-path ] keep ] H{ } map>assoc ]
+    bi assoc-union ;
+
 : group-articles ( -- assoc )
     articles get keys
-    vocabs [ dup vocab-docs-path swap ] H{ } map>assoc
+    files>vocabs
     H{ } clone [
         '[
             dup >link where dup
index b5e074b598c9fcc282d21d74c6f9be641d2c0b3c..1eae56cfcc6cb7c7e00ed3fca36e9448cbef84d7 100755 (executable)
@@ -71,7 +71,10 @@ ALIAS: $slot $snippet
     [ strong-style get print-element* ] ($span) ;
 
 : $url ( children -- )
-    [ url-style get print-element* ] ($span) ;
+    [
+        dup first href associate url-style get assoc-union
+        print-element*
+    ] ($span) ;
 
 : $nl ( children -- )
     nl nl drop ;
diff --git a/basis/html/components/authors.txt b/basis/html/components/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/html/components/components-docs.factor b/basis/html/components/components-docs.factor
new file mode 100644 (file)
index 0000000..d131cc3
--- /dev/null
@@ -0,0 +1,105 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string kernel strings
+urls lcs inspector present io ;
+IN: html.components
+
+HELP: checkbox
+{ $class-description "Checkbox components render a boolean value. The " { $slot "label" } " slot must be set to a string." } ;
+
+HELP: choice
+{ $class-description "Choice components render a popup menu or list box with either single or multiple selection."
+$nl
+"The " { $slot "multiple" } " slot determines whether multiple elements may be selected at once; if this is set to a true value, then the component value must be a sequence of strings, otherwise it must be a single string."
+$nl
+"The " { $slot "size" } " slot determines the number of items visible at one time; if neither this nor " { $slot "multiple" } " is set, the component is rendered as a popup menu rather than a list."
+$nl
+"The " { $slot "choices" } " slot determines all possible choices which may be selected. It names a value, rather than storing the choices directly." } ;
+
+HELP: code
+{ $class-description "Code components render string value with the " { $vocab-link "xmode.code2html" } " syntax highlighting vocabulary. The " { $slot "mode" } " slot names a value holding an XMode mode name." } ;
+
+HELP: field
+{ $class-description "Field components display a one-line editor for a string value. The " { $slot "size" } " slot determines the maximum displayed width of the field." } ;
+
+HELP: password
+{ $class-description "Password field components display a one-line editor which obscures the user's input. The " { $slot "size" } " slot determines the maximum displayed width of the field. Unlike other components, on failed validation, the contents of a password field are not sent back to the client. This is a security feature, intended to avoid revealing the password to potential snoopers who use the " { $strong "View Source" } " feature." } ;
+
+HELP: textarea
+{ $class-description "Text area components display a multi-line editor for a string value. The " { $slot "rows" } " and " { $slot "cols" } " properties determine the size of the text area." } ;
+
+HELP: link
+{ $description "Link components render a link to an object stored at a value, with the link title and URL determined by the " { $link link-title } " and " { $link link-href } " generic words. The optional " { $slot "target" } " slot is a target frame to open the link in." } ;
+
+HELP: link-title
+{ $values { "obj" object } { "string" string } }
+{ $description "Outputs the title to render for a link to the object." } ;
+
+HELP: link-href
+{ $values { "obj" object } { "url" "a " { $link string } " or " { $link url } } }
+{ $description "Outputs the URL to render for a link to the object." } ;
+
+ARTICLE: "html.components.links" "Link components"
+"Link components render a link to an object."
+{ $subsection link }
+"The link title and URL are determined by passing the object to a pair of generic words:"
+{ $subsection link-title }
+{ $subsection link-href }
+"The generic words provide methods on the " { $link string } " and " { $link url } " classes which treat the object as a URL. New methods can be defined for rendering links to custom data types." ;
+
+HELP: comparison
+{ $description "Comparison components render diffs output by the " { $link diff } " word." } ;
+
+HELP: farkup
+{ $description "Farkup components render " { $link "farkup" } "." } ;
+
+HELP: hidden
+{ $description "Hidden components render as a hidden form field. For example, a page for editing a weblog post might contain a hidden field with the post ID." } ;
+
+HELP: html
+{ $description "HTML components render HTML verbatim, without any escaping. Care must be taken to only render trusted input, to avoid cross-site scripting attacks." } ;
+
+HELP: inspector
+{ $description "Inspector components render an arbitrary object by passing it to the " { $link describe } " word." } ;
+
+HELP: label
+{ $description "Label components render an object as a piece of text by passing it to the " { $link present } " word." } ;
+
+HELP: render
+{ $values { "name" "a value name" } { "renderer" "a component renderer" } }
+{ $description "Renders an HTML component to the " { $link output-stream } "." } ;
+
+HELP: render*
+{ $values { "value" "a value" } { "name" "a value name" } { "renderer" "a component renderer" } }
+{ $contract "Renders an HTML component to the " { $link output-stream } "." } ;
+
+ARTICLE: "html.components" "HTML components"
+"The " { $vocab-link "html.components" } " vocabulary provides various HTML form components."
+$nl
+"Most web applications can use the " { $vocab-link "html.templates.chloe" } " templating framework instead of using this vocabulary directly. Where maximum flexibility is required, this vocabulary can be used together with the " { $vocab-link "html.templates.fhtml" } " templating framework."
+$nl
+"Rendering components:"
+{ $subsection render }
+"Components render a named value, and the name of the value is passed in every time the component is rendered, rather than being associated with the component itself. Named values are taken from the current HTML form (see " { $link "html.forms" } ")."
+$nl
+"Component come in two varieties: singletons and tuples. Components with no configuration are singletons; they do not have to instantiated, rather the class word represents the component. Tuple components have to be instantiated and offer configuration options."
+$nl
+"Singleton components:"
+{ $subsection hidden }
+{ $subsection link }
+{ $subsection inspector }
+{ $subsection comparison }
+{ $subsection html }
+"Tuple components:"
+{ $subsection field }
+{ $subsection password }
+{ $subsection textarea }
+{ $subsection choice }
+{ $subsection checkbox }
+{ $subsection code }
+{ $subsection farkup }
+"Creating custom components:"
+{ $subsection render* }
+"Custom components can emit HTML using the " { $vocab-link "html.elements" } " vocabulary." ;
+
+ABOUT: "html.components"
index 56c7118ab96e95e0090b88cb8666a3f29073a0fc..b4247e6e30574e6a7fcaf086043914b133db9d51 100644 (file)
@@ -134,7 +134,7 @@ M: link-test link-href drop "http://www.apple.com/foo&bar" ;
 [ ] [ link-test "link" set-value ] unit-test
 
 [ "<a href='http://www.apple.com/foo&amp;bar'>&lt;Link Title&gt;</a>" ] [
-    [ "link" link render ] with-string-writer
+    [ "link" link new render ] with-string-writer
 ] unit-test
 
 [ ] [
@@ -163,7 +163,7 @@ M: link-test link-href drop "http://www.apple.com/foo&bar" ;
 
 [ t ] [
     [ "object" inspector render ] with-string-writer
-    [ "object" value [ describe ] with-html-stream ] with-string-writer
+    [ "object" value [ describe ] with-html-writer ] with-string-writer
     =
 ] unit-test
 
index 6965cb582a03a1801fba5ca3055d63aea3e4a638..6f35ba5d975bd21af143347af6c39345422b3dbc 100644 (file)
@@ -9,7 +9,7 @@ xmode.code2html lcs.diff2html farkup
 html.elements html.streams html.forms ;
 IN: html.components
 
-GENERIC: render* ( value name render -- )
+GENERIC: render* ( value name renderer -- )
 
 : render ( name renderer -- )
     prepare-value
@@ -83,7 +83,7 @@ TUPLE: choice size multiple choices ;
     choice new ;
 
 : render-option ( text selected? -- )
-    <option [ "true" =selected ] when option>
+    <option [ "selected" =selected ] when option>
         present escape-string write
     </option> ;
 
@@ -126,11 +126,11 @@ M: string link-href ;
 M: url link-title ;
 M: url link-href ;
 
-SINGLETON: link
+TUPLE: link target ;
 
 M: link render*
-    2drop
-    <a dup link-href =href a>
+    nip
+    <a target>> [ =target ] when* dup link-href =href a>
         link-title present escape-string write
     </a> ;
 
@@ -144,26 +144,32 @@ M: code render*
     [ string-lines ] [ drop ] [ mode>> value ] tri* htmlize-lines ;
 
 ! Farkup component
-TUPLE: farkup no-follow disable-images ;
+TUPLE: farkup no-follow disable-images parsed ;
+
+: <farkup> ( -- farkup )
+    farkup new ;
 
 : string>boolean ( string -- boolean )
     {
         { "true" [ t ] }
         { "false" [ f ] }
+        { f [ f ] }
     } case ;
 
 M: farkup render*
     [
+        nip
         [ no-follow>> [ string>boolean link-no-follow? set ] when* ]
-        [ disable-images>> [ string>boolean disable-images? set ] when* ] bi
-        drop string-lines "\n" join write-farkup
+        [ disable-images>> [ string>boolean disable-images? set ] when* ]
+        [ parsed>> string>boolean [ (write-farkup) ] [ write-farkup ] if ]
+        tri
     ] with-scope ;
 
 ! Inspector component
 SINGLETON: inspector
 
 M: inspector render*
-    2drop [ describe ] with-html-stream ;
+    2drop [ describe ] with-html-writer ;
 
 ! Diff component
 SINGLETON: comparison
diff --git a/basis/html/components/summary.txt b/basis/html/components/summary.txt
new file mode 100644 (file)
index 0000000..9df7695
--- /dev/null
@@ -0,0 +1 @@
+HTML components for form rendering and validation
diff --git a/basis/html/components/tags.txt b/basis/html/components/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/html/elements/elements-docs.factor b/basis/html/elements/elements-docs.factor
new file mode 100644 (file)
index 0000000..f6e15e4
--- /dev/null
@@ -0,0 +1,29 @@
+IN: html.elements
+USING: help.markup help.syntax io present ;
+
+ARTICLE: "html.elements" "HTML elements"
+"The " { $vocab-link "html.elements" } " vocabulary provides words for writing HTML tags to the " { $link output-stream } " with a familiar look and feel in the code."
+$nl
+"HTML tags can be used in a number of different ways. The simplest is a tag with no attributes:"
+{ $code "<p> \"someoutput\" write </p>" }
+"In the above, " { $link <p> } " will output the opening tag with no attributes. and " { $link </p> } " will output the closing tag."
+{ $code "<p \"red\" =class p> \"someoutput\" write </p>" }
+"This time the opening tag does not have the '>'. Any attribute words used between the calls to " { $link <p } " and " { $link p> } " will write an attribute whose value is the top of the stack. Attribute values can be any object supported by the " { $link present } " word."
+$nl
+"Values for attributes can be used directly without any stack operations. Assuming we have a string on the stack, all three of the below will output a link:"
+{ $code "<a =href a> \"Click me\" write </a>" }
+{ $code "<a \"http://\" prepend =href a> \"click\" write </a>" }
+{ $code "<a [ \"http://\" % % ] \"\" make =href a> \"click\" write </a>" }
+"Tags that have no ``closing'' equivalent have a trailing " { $snippet "tag/>" } " form:"
+{ $code "<input \"text\" =type \"name\" =name 20 =size input/>" }
+"For the full list of HTML tags and attributes, consult the word list for the " { $vocab-link "html.elements" } " vocabulary. In addition to HTML tag and attribute words, a few utilities are provided."
+$nl
+"Writing unescaped HTML to " { $vocab-link "html.streams" } ":"
+{ $subsection write-html }
+{ $subsection print-html }
+"Writing some common HTML patterns:"
+{ $subsection xhtml-preamble }
+{ $subsection simple-page }
+{ $subsection render-error } ;
+
+ABOUT: "html.elements"
index ab9d987b6744f6643e5c3313bafc67fc2db8184f..0ee6955e292246889ec1bda71df4c225ba8147ff 100644 (file)
@@ -9,47 +9,6 @@ urls math math.parser combinators present fry ;
 
 IN: html.elements
 
-! These words are used to provide a means of writing
-! formatted HTML to standard output with a familiar 'html' look
-! and feel in the code.
-!
-! HTML tags can be used in a number of different ways. The highest
-! level involves a similar syntax to HTML:
-!
-! <p> "someoutput" write </p>
-!
-! <p> will output the opening tag and </p> will output the closing
-! tag with no attributes.
-!
-! <p "red" =class p> "someoutput" write </p>
-!
-! This time the opening tag does not have the '>'. It pushes
-! a namespace on the stack to hold the attributes and values.
-! Any attribute words used will store the attribute and values
-! in that namespace. Before the attribute word should come the
-! value of that attribute.
-! The finishing word will print out the operning tag including
-! attributes.
-! Any writes after this will appear after the opening tag.
-!
-! Values for attributes can be used directly without any stack
-! operations:
-!
-! (url -- )
-! <a =href a> "Click me" write </a>
-!
-! (url -- )
-! <a "http://" prepend =href a> "click" write </a>
-!
-! (url -- )
-! <a [ "http://" % % ] "" make =href a> "click" write </a>
-!
-! Tags that have no 'closing' equivalent have a trailing tag/> form:
-!
-! <input "text" =type "name" =name "20" =size input/>
-
-: elements-vocab ( -- vocab-name ) "html.elements" ;
-
 SYMBOL: html
 
 : write-html ( str -- )
@@ -60,6 +19,8 @@ SYMBOL: html
 
 <<
 
+: elements-vocab ( -- vocab-name ) "html.elements" ;
+
 : html-word ( name def effect -- )
     #! Define 'word creating' word to allow
     #! dynamically creating words.
@@ -149,8 +110,10 @@ SYMBOL: html
 [
     "input"
     "br"
+    "hr"
     "link"
     "img"
+    "base"
 ] [ define-open-html-word ] each
 
 ! Define some attributes
@@ -162,21 +125,25 @@ SYMBOL: html
     "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang"
     "media" "title" "multiple" "checked"
     "summary" "cellspacing" "align" "scope" "abbr"
-    "nofollow" "alt"
+    "nofollow" "alt" "target"
 ] [ define-attribute-word ] each
 
 >>
 
 : xhtml-preamble ( -- )
     "<?xml version=\"1.0\"?>" write-html
-    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" write-html ;
+    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" write-html ;
 
-: simple-page ( title quot -- )
+: simple-page ( title head-quot body-quot -- )
     #! Call the quotation, with all output going to the
     #! body of an html page with the given title.
+    spin
     xhtml-preamble
     <html "http://www.w3.org/1999/xhtml" =xmlns "en" =xml:lang "en" =lang html>
-        <head> <title> swap write </title> </head>
+        <head>
+            <title> write </title>
+            call
+        </head>
         <body> call </body>
     </html> ; inline
 
diff --git a/basis/html/elements/summary.txt b/basis/html/elements/summary.txt
new file mode 100644 (file)
index 0000000..7e4a4a0
--- /dev/null
@@ -0,0 +1 @@
+Rendering HTML with a familiar look and feel
diff --git a/basis/html/elements/tags.txt b/basis/html/elements/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/html/forms/authors.txt b/basis/html/forms/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/html/forms/forms-docs.factor b/basis/html/forms/forms-docs.factor
new file mode 100644 (file)
index 0000000..6556d2e
--- /dev/null
@@ -0,0 +1,126 @@
+IN: html.forms
+USING: help.markup help.syntax strings quotations kernel assocs ;
+
+HELP: <form>
+{ $values { "form" form } }
+{ $description "Creates a new form. Usually " { $link with-form } " is used instead." } ;
+
+HELP: form
+{ $var-description "Variable holding current form. Bound by " { $link with-form } ", " { $link nest-form } " and " { $link begin-form } "." }
+{ $class-description "The class of HTML forms. New instances are created by " { $link <form> } "." } ;
+
+HELP: with-form
+{ $values { "name" string } { "quot" quotation } }
+{ $description "Runs the quotation in a new dynamic scope with the " { $link form } " variable rebound to the form stored in the value named " { $snippet "name" } "." } ;
+
+HELP: nest-form
+{ $values { "name" string } { "quot" quotation } }
+{ $description "Runs the quotation in a new dynamic scope with the " { $link form } " variable rebound to a new form, which is subsequently stored in the value named " { $snippet "name" } "." }
+{ $examples
+    "The " { $vocab-link "webapps.pastebin" } " uses a form to display pastes; inside this form it nests another form for creating annotations, and fills in some default values for new annotations:"
+    { $code
+        "<page-action>"
+        "    ["
+        "        validate-integer-id"
+        "        \"id\" value paste from-object"
+        ""
+        "        \"id\" value"
+        "        \"new-annotation\" ["
+        "            \"parent\" set-value"
+        "            mode-names \"modes\" set-value"
+        "            \"factor\" \"mode\" set-value"
+        "        ] nest-form"
+        "    ] >>init"
+    }
+} ;
+
+HELP: begin-form
+{ $description "Begins a new form." } ;
+
+HELP: value
+{ $values { "name" string } { "value" object } }
+{ $description "Gets a form value. This word is used to get form field values after validation." } ;
+
+HELP: set-value
+{ $values { "value" object } { "name" string } }
+{ $description "Sets a form value. This word is used to preset form field values before rendering." } ;
+
+HELP: from-object
+{ $values { "object" object } }
+{ $description "Sets the current form's values to the object's slot values." }
+{ $examples
+    "Here is a typical action implementation, which selects a golf course object from the database with the ID specified in the HTTP request, and renders a form with values from this object:"
+    { $code
+        "<page-action>"
+        ""
+        "    ["
+        "        validate-integer-id"
+        "        \"id\" value <golf-course>"
+        "        select-tuple from-object"
+        "    ] >>init"
+        ""
+        "    { golf \"view-course\" } >>template"
+    }
+} ;
+
+HELP: to-object
+{ $values { "destination" object } { "names" "a sequence of value names" } }
+{ $description "Stores the given sequence of form values into the slots of the object having the same names. This word is used to extract form field values after validation." } ;
+
+HELP: with-each-value
+{ $values { "name" string } { "quot" quotation } }
+{ $description "Calls the quotation with each element of the value named " { $snippet "name" } "; the value must be a sequence. The quotation is called in a new dynamic scope with the " { $snippet "index" } " and " { $snippet "value" } " values set to the one-based index, and the sequence element in question, respectively." }
+{ $notes "This word is used to implement the " { $snippet "t:each" } " tag of the " { $vocab-link "html.templates.chloe" } " templating system. It can also be called directly from " { $vocab-link "html.templates.fhtml" } " templates." } ;
+
+HELP: with-each-object
+{ $values { "name" string } { "quot" quotation } }
+{ $description "Calls the quotation with each element of the value named " { $snippet "name" } "; the value must be a sequence. The quotation is called in a new dynamic scope where the object's slots become named values, as if " { $link from-object } " was called." }
+{ $notes "This word is used to implement the " { $snippet "t:bind-each" } " tag of the " { $vocab-link "html.templates.chloe" } " templating system. It can also be called directly from " { $vocab-link "html.templates.fhtml" } " templates." } ;
+
+HELP: validation-failed?
+{ $values { "?" "a boolean" } }
+{ $description "Tests if validation of the current form failed." } ;
+
+HELP: validate-values
+{ $values { "assoc" assoc } { "validators" "an assoc mapping value names to quotations" } }
+{ $description "Validates values in the assoc by looking up the corresponding validation quotation, and storing the results in named values of the current form." } ;
+
+ARTICLE: "html.forms.forms" "HTML form infrastructure"
+"The below words are used to implement the " { $vocab-link "furnace.actions" } " vocabulary. Calling them directly is rarely necessary."
+$nl
+"Creating a new form:"
+{ $subsection <form> }
+"Variable holding current form:"
+{ $subsection form }
+"Working with forms:"
+{ $subsection with-form }
+{ $subsection begin-form }
+"Validation:"
+{ $subsection validation-error }
+{ $subsection validation-failed? }
+{ $subsection validate-values } ;
+
+ARTICLE: "html.forms.values" "HTML form values"
+"Form values are a central concept in the Furnace framework. Web actions primarily concern themselves with validating values, marshalling values to a database, and setting values for display in a form."
+$nl
+"Getting and setting values:"
+{ $subsection value }
+{ $subsection set-value }
+{ $subsection from-object }
+{ $subsection to-object }
+"Iterating over values; these words are used by " { $vocab-link "html.templates.chloe" } " to implement the " { $snippet "t:each" } " and " { $snippet "t:bind-each" } " tags:"
+{ $subsection with-each-value }
+{ $subsection with-each-object }
+"Nesting a form inside another form as a value:"
+{ $subsection nest-form } ;
+
+ARTICLE: "html.forms" "HTML forms"
+"The " { $vocab-link "html.forms" } " vocabulary implements support for rendering and validating HTML forms. The definition of a " { $emphasis "form" } " is a bit more general than the content of an " { $snippet "<form>" } " tag. Namely, a page which displays a database record without offering any editing capability is considered a form too; it consists entirely of read-only components."
+$nl
+"This vocabulary is an integral part of the " { $vocab-link "furnace" } " web framework. The " { $vocab-link "html.templates.chloe" } " vocabulary uses the HTML form words to implement various template tags. The words are also often used directly from web action implementations."
+$nl
+"This vocabulary can be used without either the Furnace framework or the HTTP server; for example, as part of a static HTML generation tool."
+{ $subsection "html.forms.forms" }
+{ $subsection "html.forms.values" } ;
+
+ABOUT: "html.forms"
index 7dd4b6146bee69be4bef25d24343641d3f4e0752..c1c1aa3def13e4e21cd49d4ac2d9161006a7644e 100644 (file)
@@ -102,5 +102,5 @@ C: <validation-error> validation-error
     dup validation-error? [ form get t >>validation-failed drop ] when
     swap set-value ;
 
-: validate-values ( assoc validators -- assoc' )
+: validate-values ( assoc validators -- )
     swap '[ [ dup _ at ] dip validate-value ] assoc-each ;
diff --git a/basis/html/forms/summary.txt b/basis/html/forms/summary.txt
new file mode 100644 (file)
index 0000000..d4b20ee
--- /dev/null
@@ -0,0 +1 @@
+HTML form rendering and validation
diff --git a/basis/html/forms/tags.txt b/basis/html/forms/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/html/streams/streams-docs.factor b/basis/html/streams/streams-docs.factor
new file mode 100644 (file)
index 0000000..f05eeb3
--- /dev/null
@@ -0,0 +1,33 @@
+IN: html.streams
+USING: help.markup help.syntax kernel strings io io.styles
+quotations ;
+
+HELP: browser-link-href
+{ $values { "presented" object } { "href" string } }
+{ $contract "Outputs a link to a page displaying a presentation of the given object. This word is called when " { $link write-object } " is called on " { $link html-stream } " instances." } ;
+
+HELP: html-stream
+{ $class-description "A formatted output stream which emits HTML markup." } ;
+
+HELP: <html-stream>
+{ $values { "stream" "an output stream" } { "html-stream" html-stream } }
+{ $description "Creates a new formatted output stream which emits HTML markup on " { $snippet "stream" } "." } ;
+
+HELP: with-html-writer
+{ $values { "quot" quotation } }
+{ $description "Calls the quotation in a new dynamic scope with " { $link output-stream } " rebound to an " { $link html-stream } " wrapping the current " { $link output-stream } "." }
+{ $examples
+    { $example
+        "USING: io io.styles html.streams ;"
+        "[ \"Hello\" { { font-style bold } } format nl ] with-html-writer"
+        "<span style='font-style: normal; font-weight: bold; '>Hello</span><br/>"
+    }
+} ;
+
+ARTICLE: "html.streams" "HTML streams"
+"The " { $vocab-link "html.streams" } " vocabulary provides a stream which implements " { $link "styles" } " by writing HTML markup to the wrapped stream."
+{ $subsection html-stream }
+{ $subsection <html-stream> }
+{ $subsection with-html-writer } ;
+
+ABOUT: "html.streams"
index b5707c158ffe4b29fe88f48e8a5329b2cf41269a..94229b3aeaab8552dfde841692f2d00054e429ab 100644 (file)
@@ -4,7 +4,7 @@ xml.writer sbufs sequences inspector colors ;
 IN: html.streams.tests
 
 : make-html-string
-    [ with-html-stream ] with-string-writer ; inline
+    [ with-html-writer ] with-string-writer ; inline
 
 [ [ ] make-html-string ] must-infer
 
@@ -71,4 +71,4 @@ M: funky browser-link-href
     [ H{ } [ ] with-nesting nl ] make-html-string
 ] unit-test
 
-[ ] [ [ { 1 2 3 } describe ] with-html-stream ] unit-test
+[ ] [ [ { 1 2 3 } describe ] with-html-writer ] unit-test
index 7d90296fcbfdc7dac29ed4fdca5f31afcdc42c83..fa81a69bb403bfb4fc44cdcd9e8ad2b8b22041fe 100755 (executable)
@@ -4,7 +4,7 @@ USING: combinators generic assocs help http io io.styles
 io.files continuations io.streams.string kernel math math.order
 math.parser namespaces make quotations assocs sequences strings
 words html.elements xml.entities sbufs continuations destructors
-accessors arrays ;
+accessors arrays urls.encoding ;
 IN: html.streams
 
 GENERIC: browser-link-href ( presented -- href )
@@ -22,10 +22,10 @@ TUPLE: html-stream stream last-div ;
 : not-a-div ( stream -- stream )
     f >>last-div ; inline
 
-: a-div ( stream -- straem )
+: a-div ( stream -- stream )
     t >>last-div ; inline
 
-: <html-stream> ( stream -- stream )
+: <html-stream> ( stream -- html-stream )
     f html-stream boa ;
 
 <PRIVATE
@@ -44,10 +44,15 @@ TUPLE: html-sub-stream < html-stream style parent ;
 : object-link-tag ( style quot -- )
     presented pick at [
         browser-link-href [
-            <a =href a> call </a>
+            <a url-encode =href a> call </a>
         ] [ call ] if*
     ] [ call ] if* ; inline
 
+: href-link-tag ( style quot -- )
+    href pick at [
+        <a url-encode =href a> call </a>
+    ] [ call ] if* ; inline
+
 : hex-color, ( color -- )
     [ red>> ] [ green>> ] [ blue>> ] tri
     [ 255 * >fixnum >hex 2 CHAR: 0 pad-left % ] tri@ ;
@@ -95,7 +100,7 @@ TUPLE: html-sub-stream < html-stream style parent ;
 
 : format-html-span ( string style stream -- )
     stream>> [
-        [ [ drop write ] span-tag ] object-link-tag
+        [ [ [ drop write ] span-tag ] href-link-tag ] object-link-tag
     ] with-output-stream* ;
 
 TUPLE: html-span-stream < html-sub-stream ;
@@ -192,5 +197,5 @@ M: html-stream stream-write-table
 
 M: html-stream dispose stream>> dispose ;
 
-: with-html-stream ( quot -- )
+: with-html-writer ( quot -- )
     output-stream get <html-stream> swap with-output-stream* ; inline
index 29ec8d3df76c33833336e381f0e2b1dee7e81d79..56b83c5c52983b10404a31c33d817f00777f4baa 100644 (file)
@@ -1 +1 @@
-HTML reader, writer and utilities
+HTML implementation of formatted output stream protocol
diff --git a/basis/html/templates/authors.txt b/basis/html/templates/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/html/templates/chloe/authors.txt b/basis/html/templates/chloe/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/html/templates/chloe/chloe-docs.factor b/basis/html/templates/chloe/chloe-docs.factor
new file mode 100644 (file)
index 0000000..f390aad
--- /dev/null
@@ -0,0 +1,280 @@
+IN: html.templates.chloe
+USING: help.markup help.syntax html.components html.forms
+html.templates html.templates.chloe.syntax
+html.templates.chloe.compiler html.templates.chloe.components
+math xml.data strings quotations namespaces ;
+
+HELP: <chloe> ( path -- template )
+{ $values { "path" "a pathname string without the trailing " { $snippet ".xml" } " extension" } { "template" chloe } }
+{ $description "Creates a new Chloe template object which can be passed to " { $link call-template } "." } ;
+
+HELP: required-attr
+{ $values { "tag" tag } { "name" string } { "value" string } }
+{ $description "Extracts an attribute from a tag." }
+{ $errors "Throws an error if the attribute is not specified." } ;
+
+HELP: optional-attr
+{ $values { "tag" tag } { "name" string } { "value" "a " { $link string } " or " { $link f } } }
+{ $description "Extracts an attribute from a tag." }
+{ $notes "Outputs " { $link f } " if the attribute is not specified." } ;
+
+HELP: compile-attr
+{ $values { "value" "an attribute value" } }
+{ $description "Compiles code which pushes an attribute value previously extracted by " { $link required-attr } " or " { $link optional-attr } " on the stack. If the attribute value begins with " { $snippet "@" } ", compiles into code which pushes the a form value." } ;
+
+HELP: CHLOE:
+{ $syntax "name definition... ;" }
+{ $values { "name" "the tag name" } { "definition" "a quotation with stack effect " { $snippet "( tag -- )" } } }
+{ $description "Defines compilation semantics for the Chloe tag named " { $snippet "tag" } ". The definition body receives a " { $link tag } " on the stack." } ;
+
+HELP: COMPONENT:
+{ $syntax "COMPONENT: name" }
+{ $description "Defines a Chloe tag named " { $snippet "name" } " rendering the HTML component with class word " { $snippet "name" } ". See " { $link "html.components" } "." } ;
+
+HELP: reset-cache
+{ $description "Resets the compiled template cache. Chloe automatically recompiles templates when their file changes on disk, however other when redefining Chloe tags or words which they call, the cache may have to be reset manually for the changes to take effect." } ;
+
+HELP: tag-stack
+{ $var-description "During template compilation, holds the current nesting of XML element names. Can be used from " { $link POSTPONE: CHLOE: } " definitions to make a custom tag behave differently depending on how it is nested." } ;
+
+HELP: [write]
+{ $values { "string" string } }
+{ $description "Compiles code which writes the string when the template is called." } ;
+
+HELP: [code]
+{ $values { "quot" quotation } }
+{ $description "Compiles the quotation. It will be called when the template is called." } ;
+
+HELP: process-children
+{ $values { "tag" tag } { "quot" "a quotation with stack effect " { $snippet "( compiled-tag -- )" } } }
+{ $description "Compiles the tag. The quotation will be applied to the resulting quotation when the template is called." }
+{ $examples "See " { $link "html.templates.chloe.extend.tags.example" } " for an example which uses this word to implement a custom control flow tag." } ;
+
+HELP: compile-children>string
+{ $values { "tag" tag } }
+{ $description "Compiles the tag so that the output it generates is written to a string, which is pushed on the stack when the template runs. A subsequent " { $link [code] } " call must be made with a quotation which consumes the string." }  ;
+
+HELP: compile-with-scope
+{ $values { "quot" quotation } }
+{ $description "Calls the quotation and wraps any output it compiles in a " { $link with-scope } " form." } ;
+
+ARTICLE: "html.templates.chloe.tags.component" "Component Chloe tags"
+"The following Chloe tags correspond exactly to " { $link "html.components" } ". Singleton component tags do not allow any attributes. Attributes of tuple component tags are mapped to tuple slot values of the component instance."
+{ $table
+    { "Tag" "Component class" }
+    { { $snippet "t:checkbox" }   { $link checkbox } }
+    { { $snippet "t:choice" }     { $link choice } }
+    { { $snippet "t:code" }       { $link code } }
+    { { $snippet "t:comparison" } { $link comparison } }
+    { { $snippet "t:farkup" }     { $link farkup } }
+    { { $snippet "t:field" }      { $link field } }
+    { { $snippet "t:hidden" }     { $link hidden } }
+    { { $snippet "t:html" }       { $link html } }
+    { { $snippet "t:inspector" }  { $link inspector } }
+    { { $snippet "t:label" }      { $link label } }
+    { { $snippet "t:link" }       { $link link } }
+    { { $snippet "t:password" }   { $link password } }
+    { { $snippet "t:textarea" }   { $link textarea } }
+} ;                                       
+
+ARTICLE: "html.templates.chloe.tags.boilerplate" "Boilerplate Chloe tags"
+"The following Chloe tags interface with the HTML templating " { $link "html.templates.boilerplate" } "."
+$nl
+"The tags marked with (*) are only available if the " { $vocab-link "furnace.chloe-tags" } " vocabulary is loaded."
+{ $table
+    { { $snippet "t:title" } "Sets the title from a child template" }
+    { { $snippet "t:write-title" } "Renders the child's title from a master template" }
+    { { $snippet "t:style" } "Adds CSS markup from a child template" }
+    { { $snippet "t:write-style" } "Renders the children's CSS from a master template" }
+    { { $snippet "t:atom" } "Adds an Atom feed link from a child template (*)" }
+    { { $snippet "t:write-atom" } "Renders the children's list of Atom feed links (*)" }
+    { { $snippet "t:call-next-template" } "Calls the child template from a master template" }
+} ;
+
+ARTICLE: "html.templates.chloe.tags.control" "Control-flow Chloe tags"
+"While most control flow and logic should be embedded in the web actions themselves and not in the template, Chloe templates do support a minimal amount of control flow."
+{ $table
+    { { $snippet "t:comment" } "All markup within a comment tag is ignored by the compiler." }
+    { { $snippet "t:bind" } { "Renders child content bound to a nested form named by the " { $snippet "t:name" } " attribute. See " { $link with-form } "." } }
+    { { $snippet "t:each" } { "Renders child content once for each element of the sequence in the value named by the " { $snippet "t:name" } " attribute. The sequence element and index are bound to the " { $snippet "value" } " and " { $snippet "index" } " values, respectively. See " { $link with-each-value } "." } }
+    { { $snippet "t:bind-each" } { "Renders child content once for each element of the sequence in the value named by the " { $snippet "t:name" } " attribute. The sequence element's slots are bound to values. See " { $link with-each-object } "." } }
+    { { $snippet "t:even" } { "Only valid inside a " { $snippet "t:each" } " or " { $snippet "t:bind-each" } ". Only renders child content if the " { $snippet "index" } " value is even." } }
+    { { $snippet "t:odd" } "As above, but only if the index value is odd." }
+    { { $snippet "t:if" } { "Renders child content if a boolean condition evaluates to true. The condition value is determined by the " { $snippet "t:code" } " or " { $snippet "t:value" } " attribute, exactly one of which must be specified. The former is a string of the form " { $snippet "vocabulary:word" } " denoting a word to execute with stack effect " { $snippet "( -- ? )" } ". The latter is a value name." } }
+} ;
+
+ARTICLE: "html.templates.chloe.tags.form" "Chloe link and form tags"
+"The following tags are only available if the " { $vocab-link "furnace.chloe-tags" } " vocabulary is loaded."
+{ $table
+    { { $snippet "t:a" } { "Renders a link; extends the standard XHTML " { $snippet "a" } " tag by providing some integration with other web framework features. The following attributes are supported:"
+        { $list
+            { { $snippet "href" } " - a URL. If it begins with " { $snippet "$" } ", then it is interpreted as a responder-relative path." }
+            { { $snippet "rest" } " - a value to add at the end of the URL." }
+            { { $snippet "query" } " - a comma-separated list of value names defined in the current form which are to be passed to the link as query parameters." }
+            { { $snippet "value" } " - a value name holding a URL. If this attribute is specified, it overrides all others." }
+        }
+        "Any attributes not in the Chloe XML namespace are passed on to the generated " { $snippet "a" } " tag."
+        $nl
+        "An example:"
+        { $code
+            "<t:a t:href=\"$wiki/view/\""
+            "     t:rest=\"title\""
+            "     class=\"small-link\">"
+            "    View"
+            "</t:a>"
+        }
+        "The above might render as"
+        { $code
+            "<a href=\"http://mysite.org/wiki/view/Factor\""
+            "   class=\"small-link\">"
+            "    View"
+            "s</a>"
+        }
+    } }
+    { { $snippet "t:base" } { "Outputs an HTML " { $snippet "<base>" } " tag. The attributes are interpreted in the same manner as the attributes of " { $snippet "t:a" } "." } }
+    { { $snippet "t:form" } {
+        "Renders a form; extends the standard XHTML " { $snippet "form" } " tag by providing some integration with other web framework features, for example by adding hidden fields for authentication credentials and session management allowing those features to work with form submission transparently. The following attributes are supported:"
+        { $list
+            { { $snippet "t:method" } " - just like the " { $snippet "method" } " attribute of an HTML " { $snippet "form" } " tag, this can equal " { $snippet "get" } " or " { $snippet "post" } ". Unlike the HTML tag, the default is " { $snippet "post" } "." }
+            { { $snippet "t:action" } " - a URL. If it begins with " { $snippet "$" } ", then it is interpreted as a responder-relative path." }
+            { { $snippet "t:for" } " - a comma-separated list of form values which are to be inserted in the form as hidden fields. Other than being more concise, this is equivalent to nesting a series of " { $snippet "t:hidden" } " tags inside the form." }
+        }
+        "Any attributes not in the Chloe XML namespace are passed on to the generated " { $snippet "form" } " tag."
+    } }
+    { { $snippet "t:button" } {
+        "Shorthand for a form with a single button, whose label is the text child of the " { $snippet "t:button" } " tag. Attributes are processed as with the " { $snippet "t:form" } " tag, with the exception that any attributes not in the Chloe XML namespace are passed on to the generated " { $snippet "button" } " tag, rather than the " { $snippet "form" } " tag surrounding it."
+        $nl
+        "An example:"
+        { $code
+            "<t:button t:method=\"POST\""
+            "          t:action=\"$wiki/delete\""
+            "          t:for=\"id\">"
+            "          class=\"link-button\""
+            "    Delete"
+            "</t:button>"
+        }
+    } }
+} ;
+
+ARTICLE: "html.templates.chloe.tags" "Standard Chloe tags"
+"A Chloe template is an XML file with a mix of standard XHTML and Chloe tags."
+$nl
+"XHTML tags are rendered verbatim, except attribute values which begin with " { $snippet "@" } " are replaced with the corresponding " { $link "html.forms.values" } "."
+$nl
+"Chloe tags are defined in the " { $snippet "http://factorcode.org/chloe/1.0" } " namespace; by convention, it is bound with a prefix of " { $snippet "t" } ". The top-level tag must always be the " { $snippet "t:chloe" } " tag. A typical Chloe template looks like so:"
+{ $code
+    "<?xml version=\"1.0\"?>"
+    ""
+    "<t:chloe xmlns:t=\"http://factorcode.org/chloe/1.0\">"
+    "    ..."
+    "</t:chloe>"
+}
+{ $subsection "html.templates.chloe.tags.component" }
+{ $subsection "html.templates.chloe.tags.boilerplate" }
+{ $subsection "html.templates.chloe.tags.control" }
+{ $subsection "html.templates.chloe.tags.form" } ;
+
+ARTICLE: "html.templates.chloe.extend" "Extending Chloe"
+"The " { $vocab-link "html.templates.chloe.syntax" } " and " { $vocab-link "html.templates.chloe.compiler" } " vocabularies contain the heart of the Chloe implementation."
+$nl
+"Chloe is implemented as a compiler which converts XML templates into Factor quotations. The template only has to be parsed and compiled once, and not on every HTTP request. This helps improve performance and memory usage."
+$nl
+"These vocabularies provide various hooks by which Chloe can be extended. First of all, new " { $link "html.components" } " can be wired in. If further flexibility is needed, entirely new tags can be defined by hooking into the Chloe compiler."
+{ $subsection "html.templates.chloe.extend.components" }
+{ $subsection "html.templates.chloe.extend.tags" } ;
+
+ARTICLE: "html.templates.chloe.extend.tags" "Extending Chloe with custom tags"
+"Syntax for defining custom tags:"
+{ $subsection POSTPONE: CHLOE: }
+"A number of compiler words can be used from the " { $link POSTPONE: CHLOE: } " body to emit compiled template code."
+$nl
+"Extracting attributes from the XML tag:"
+{ $subsection required-attr }
+{ $subsection optional-attr }
+{ $subsection compile-attr }
+"Examining tag nesting:"
+{ $subsection tag-stack }
+"Generating code for printing strings and calling quotations:"
+{ $subsection [write] }
+{ $subsection [code] }
+"Generating code from child elements:"
+{ $subsection process-children }
+{ $subsection compile-children>string }
+{ $subsection compile-with-scope }
+"Examples which illustrate some of the above:"
+{ $subsection "html.templates.chloe.extend.tags.example" } ;
+
+ARTICLE: "html.templates.chloe.extend.tags.example" "Examples of custom Chloe tags"
+"As a first example, let's develop a custom Chloe tag which simply renders a random number. The tag will be used as follows:"
+{ $code
+    "<t:random t:min='10' t:max='20' t:generator='system' />"
+}
+"The " { $snippet "t:min" } " and " { $snippet "t:max" } " parameters are required, and " { $snippet "t:generator" } ", which can equal one of " { $snippet "default" } ", " { $snippet "system" } " or " { $snippet "secure" } ", is optional, with the default being " { $snippet "default" } "."
+$nl
+"Here is the " { $link POSTPONE: USING: } " form that we need for the below code to work:"
+{ $code
+    "USING: combinators kernel math.parser math.ranges random"
+    "html.templates.chloe.compiler html.templates.chloe.syntax ;"
+}
+"We write a word which extracts the relevant attributes from an XML tag:"
+{ $code
+    ": random-attrs ( tag -- min max generator )"
+    "    [ \"min\" required-attr string>number ]"
+    "    [ \"max\" required-attr string>number ]"
+    "    [ \"generator\" optional-attr ]"
+    "    tri ;"
+}
+"Next, we convert a random generator name into a random generator object:"
+{ $code
+    ": string>random-generator ( string -- generator )"
+    "    {"
+    "        { \"default\" [ random-generator ] }"
+    "        { \"system\" [ system-random-generator ] }"
+    "        { \"secure\" [ secure-random-generator ] }"
+    "    } case ;"
+}
+"Finally, we can write our Chloe tag:"
+{ $code
+    "CHLOE: random"
+    "    random-attrs string>random-generator"
+    "    '["
+    "        _ _ _"
+    "        [ [a,b] random present write ]"
+    "        with-random-generator"
+    "    ] [code] ;"
+}
+"For the second example, let's develop a Chloe tag which repeatedly renders its child several times, where the number comes from a form value. The tag will be used as follows:"
+{ $code
+    "<t:repeat t:times='n'>Hello world.<br /></t:repeat>"
+}
+"This time, we cannot simply extract the " { $snippet "t:times" } " attribute at compile time since its value cannot be determined then. Instead, we execute " { $link compile-attr } " to generate code which pushes the value of that attribute on the stack. We then use " { $link process-children } " to compile child elements as a nested quotation which we apply " { $link times } " to."
+{ $code
+    "CHLOE: repeat"
+    "    [ \"times\" required-attr compile-attr ]"
+    "    [ [ times ] process-children ]"
+    "    bi ;"
+} ;
+
+ARTICLE: "html.templates.chloe.extend.components.example" "An example of a custom Chloe component"
+"As an example, let's develop a custom Chloe component which renders an image stored in a form value. Since the component does not require any configuration, we can define a singleton class:"
+{ $code "SINGLETON: image" }
+"Now we define a method on the " { $link render* } " generic word which renders the image using " { $vocab-link "html.elements" } ":"
+{ $code "M: image render* 2drop <img =src img/> ;" }
+"Finally, we can define a Chloe component:"
+{ $code "COMPONENT: image" }
+"We can use it as follows, assuming the current form has a value named " { $snippet "image" } ":"
+{ $code "<t:image t:name='image' />" } ;
+
+ARTICLE: "html.templates.chloe.extend.components" "Extending Chloe with custom components"
+"Custom HTML components implementing the " { $link render* } " word can be wired up with Chloe using the following syntax from " { $vocab-link "html.templates.chloe.components" } ":"
+{ $subsection POSTPONE: COMPONENT: }
+{ $subsection "html.templates.chloe.extend.components.example" } ;
+
+ARTICLE: "html.templates.chloe" "Chloe templates"
+"The " { $vocab-link "html.templates.chloe" } " vocabulary implements an XHTML templating engine. Unlike " { $vocab-link "html.templates.fhtml" } ", Chloe templates are always well-formed XML, and no Factor code can be embedded in them, enforcing proper separation of concerns. Chloe templates can be edited using standard XML editing tools; they are less flexible than FHTML, but often simpler as a result."
+{ $subsection <chloe> }
+{ $subsection reset-cache }
+{ $subsection "html.templates.chloe.tags" }
+{ $subsection "html.templates.chloe.extend" } ;
+
+ABOUT: "html.templates.chloe"
index 9eb4a5709cb17fd18da8c7704d4b513ce4b614c9..5114b4088adf95d0286a4df4a679901e5a181713 100644 (file)
@@ -4,8 +4,6 @@ namespaces xml html.components html.forms
 splitting unicode.categories furnace accessors ;
 IN: html.templates.chloe.tests
 
-reset-templates
-
 : run-template
     with-string-writer [ "\r\n\t" member? not ] filter
     "?>" split1 nip ; inline
@@ -136,7 +134,7 @@ TUPLE: person first-name last-name ;
 
 [ ] [ H{ { "a" H{ { "b" "c" } } } } values set ] unit-test
 
-[ "<form method='post' action='foo'><input type='hidden' name='__n' value='a'/></form>" ] [
+[ "<form method='post' action='foo'><div style='display: none;'><input type='hidden' name='__n' value='a'/></div></form>" ] [
     [
         "test10" test-template call-template
     ] run-template
index 5fe53fc7a503868b703a65c47d57e57d06df9e35..1bc4684d5c41488e16c78c7bd40bdc2615783363 100644 (file)
@@ -1,9 +1,9 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors kernel sequences combinators kernel fry
-namespaces make classes.tuple assocs splitting words arrays
-memoize io io.files io.encodings.utf8 io.streams.string
-unicode.case mirrors math urls present multiline quotations xml
+namespaces make classes.tuple assocs splitting words arrays io
+io.files io.encodings.utf8 io.streams.string unicode.case
+mirrors math urls present multiline quotations xml logging
 xml.data
 html.forms
 html.elements
@@ -37,7 +37,11 @@ CHLOE: style
     ] ?if ;
 
 CHLOE: write-style
-    drop [ <style> write-style </style> ] [code] ;
+    drop [
+        <style "text/css" =type style>
+            write-style
+        </style>
+    ] [code] ;
 
 CHLOE: even
     [ "index" value even? swap when ] process-children ;
@@ -74,36 +78,54 @@ CHLOE: call-next-template
 
 CHLOE: if dup if>quot [ swap when ] append process-children ;
 
-CHLOE-SINGLETON: label
-CHLOE-SINGLETON: link
-CHLOE-SINGLETON: inspector
-CHLOE-SINGLETON: comparison
-CHLOE-SINGLETON: html
-CHLOE-SINGLETON: hidden
-
-CHLOE-TUPLE: farkup
-CHLOE-TUPLE: field
-CHLOE-TUPLE: textarea
-CHLOE-TUPLE: password
-CHLOE-TUPLE: choice
-CHLOE-TUPLE: checkbox
-CHLOE-TUPLE: code
-
-: read-template ( chloe -- xml )
-    path>> ".xml" append utf8 <file-reader> read-xml ;
-
-MEMO: template-quot ( chloe -- quot )
-    read-template compile-template ;
-
-MEMO: nested-template-quot ( chloe -- quot )
-    read-template compile-nested-template ;
-
-: reset-templates ( -- )
-    { template-quot nested-template-quot } [ reset-memoized ] each ;
+COMPONENT: label
+COMPONENT: link
+COMPONENT: inspector
+COMPONENT: comparison
+COMPONENT: html
+COMPONENT: hidden
+COMPONENT: farkup
+COMPONENT: field
+COMPONENT: textarea
+COMPONENT: password
+COMPONENT: choice
+COMPONENT: checkbox
+COMPONENT: code
+
+SYMBOL: template-cache
+
+H{ } template-cache set-global
+
+TUPLE: cached-template path last-modified quot ;
+
+: load-template ( chloe -- cached-template )
+    path>> ".xml" append
+    [ ]
+    [ file-info modified>> ]
+    [ utf8 <file-reader> read-xml compile-template ] tri
+    \ cached-template boa ;
+
+\ load-template DEBUG add-input-logging
+
+: cached-template ( chloe -- cached-template/f )
+    template-cache get at* [
+        [
+            [ path>> file-info modified>> ]
+            [ last-modified>> ]
+            bi =
+        ] keep and
+    ] when ;
+
+: template-quot ( chloe -- quot )
+    dup cached-template [ ] [
+        [ load-template dup ] keep
+        template-cache get set-at
+    ] ?if quot>> ;
+
+: reset-cache ( -- )
+    template-cache get clear-assoc ;
 
 M: chloe call-template*
-    nested-template? get
-    [ nested-template-quot ] [ template-quot ] if
-    assert-depth ;
+    template-quot assert-depth ;
 
 INSTANCE: chloe template
index f32923f6207e922d8c7bd72489b5dd6d43a53f4c..4f2eaafe269698ab406850a19f818d4f14729cff 100644 (file)
@@ -3,7 +3,7 @@
 USING: assocs namespaces make kernel sequences accessors
 combinators strings splitting io io.streams.string present
 xml.writer xml.data xml.entities html.forms
-html.templates.chloe.syntax ;
+html.templates html.templates.chloe.syntax ;
 IN: html.templates.chloe.compiler
 
 : chloe-attrs-only ( assoc -- assoc' )
@@ -98,9 +98,6 @@ DEFER: compile-element
         reset-buffer
     ] [ ] make ; inline
 
-: compile-nested-template ( xml -- quot )
-    [ compile-element ] with-compiler ;
-
 : compile-chunk ( seq -- )
     [ compile-element ] each ;
 
@@ -121,12 +118,25 @@ DEFER: compile-element
 : compile-with-scope ( quot -- )
     compile-quot [ with-scope ] [code] ; inline
 
+: if-not-nested ( quot -- )
+    nested-template? get swap unless ; inline
+
+: compile-prologue ( xml -- )
+    [
+        [ prolog>> [ write-prolog ] [code-with] ]
+        [ before>> compile-chunk ]
+        bi
+    ] compile-quot
+    [ if-not-nested ] [code] ;
+
+: compile-epilogue ( xml -- )
+    [ after>> compile-chunk ] compile-quot
+    [ if-not-nested ] [code] ;
+
 : compile-template ( xml -- quot )
     [
-        {
-            [ prolog>> [ write-prolog ] [code-with] ]
-            [ before>> compile-chunk ]
-            [ compile-element ]
-            [ after>> compile-chunk ]
-        } cleave
+        [ compile-prologue ]
+        [ compile-element ]
+        [ compile-epilogue ]
+        tri
     ] with-compiler ;
index 77d7c937be5a29bb1ba0b0cf4c1042b343c1e72a..3041120d43d222470e2d11cae62265496f07ad30 100644 (file)
@@ -1,35 +1,31 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors assocs sequences kernel parser fry quotations
-classes.tuple
+classes.tuple classes.singleton
 html.components
 html.templates.chloe.compiler
 html.templates.chloe.syntax ;
 IN: html.templates.chloe.components
+  
+GENERIC: component-tag ( tag class -- )
 
-: singleton-component-tag ( tag class -- )
+M: singleton-class component-tag ( tag class -- )
     [ "name" required-attr compile-attr ]
     [ literalize [ render ] [code-with] ]
     bi* ;
 
-: CHLOE-SINGLETON:
-    scan-word
-    [ name>> ] [ '[ _ singleton-component-tag ] ] bi
-    define-chloe-tag ;
-    parsing
-
 : compile-component-attrs ( tag class -- )
     [ attrs>> [ drop main>> "name" = not ] assoc-filter ] dip
     [ all-slots swap '[ name>> _ at compile-attr ] each ]
     [ [ boa ] [code-with] ]
     bi ;
 
-: tuple-component-tag ( tag class -- )
+M: tuple-class component-tag ( tag class -- )
     [ drop "name" required-attr compile-attr ] [ compile-component-attrs ] 2bi
     [ render ] [code] ;
 
-: CHLOE-TUPLE:
+: COMPONENT:
     scan-word
-    [ name>> ] [ '[ _ tuple-component-tag ] ] bi
+    [ name>> ] [ '[ _ component-tag ] ] bi
     define-chloe-tag ;
     parsing
diff --git a/basis/html/templates/chloe/summary.txt b/basis/html/templates/chloe/summary.txt
new file mode 100644 (file)
index 0000000..568fb3f
--- /dev/null
@@ -0,0 +1 @@
+XHTML templating engine with extensible compiler and separation of concerns
diff --git a/basis/html/templates/chloe/tags.txt b/basis/html/templates/chloe/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index b47eafb62a99f16153bc341b58aa173e5b275996..22d592c1dd2724fc2e2d4193087a0e87a3e7c1e8 100644 (file)
@@ -1,2 +1,2 @@
 Slava Pestov
-Matthew Willis
+Alex Chapman
diff --git a/basis/html/templates/fhtml/fhtml-docs.factor b/basis/html/templates/fhtml/fhtml-docs.factor
new file mode 100644 (file)
index 0000000..c302a58
--- /dev/null
@@ -0,0 +1,16 @@
+IN: html.templates.fhtml
+USING: help.markup help.syntax ;
+
+HELP: <fhtml> ( path -- fhtml )
+{ $values { "path" "a pathname string" } { "fhtml" fhtml } }
+{ $description "Creates an FHTML template descriptor." } ;
+
+ARTICLE: "html.templates.fhtml" "FHTML templates"
+"The " { $vocab-link "html.templates.fhtml" } " vocabulary implements a templating engine which mixes markup with Factor code."
+$nl
+"FHTML provides an alternative to " { $vocab-link "html.templates.chloe" } " for situations where complex logic must be embedded in the presentation layer of a web application. While this is discouraged for larger applications, it is useful for prototyping as well as simpler applications."
+$nl
+"The entire syntax of an FHTML template can be summarized as thus: text outside of " { $snippet "<%" } " and " { $snippet "%>" } " is rendered literally. Text inside " { $snippet "<%" } " and " { $snippet "%>" } " is interpreted as Factor source code."
+{ $subsection <fhtml> } ;
+
+ABOUT: "html.templates.fhtml"
diff --git a/basis/html/templates/fhtml/summary.txt b/basis/html/templates/fhtml/summary.txt
new file mode 100644 (file)
index 0000000..71745ff
--- /dev/null
@@ -0,0 +1 @@
+Simple templating engine mixing Factor code with content
diff --git a/basis/html/templates/fhtml/tags.txt b/basis/html/templates/fhtml/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/html/templates/summary.txt b/basis/html/templates/summary.txt
new file mode 100644 (file)
index 0000000..ef0aa59
--- /dev/null
@@ -0,0 +1 @@
+HTML templating engine interface
diff --git a/basis/html/templates/tags.txt b/basis/html/templates/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/html/templates/templates-docs.factor b/basis/html/templates/templates-docs.factor
new file mode 100644 (file)
index 0000000..3251b46
--- /dev/null
@@ -0,0 +1,88 @@
+IN: html.templates
+USING: help.markup help.syntax io strings quotations xml.data
+continuations urls ;
+
+HELP: template
+{ $class-description "The class of HTML templates." } ;
+
+HELP: call-template*
+{ $values { "template" template } }
+{ $contract "Writes a template to " { $link output-stream } ", possibly using " { $vocab-link "html.forms" } " state."
+$nl
+"In addition to methods added by other vocabularies, this generic word has methods on the following classes:"
+{ $list
+    { { $link string } " - the simplest type of template; simply written to " { $link output-stream } }
+    { { $link callable } " - a custom quotation, called to yield output" }
+    { { $link xml } " - written to " { $link output-stream } }
+    { "an input stream - copied to " { $link output-stream } }
+} } ;
+
+HELP: call-template
+{ $values { "template" template } }
+{ $description "Writes a template to " { $link output-stream } ", possibly using " { $vocab-link "html.forms" } " state."
+$nl
+"This word calls " { $link call-template* } ", wrapping it in a " { $link recover } " form which improves error reporting by combining the underlying error with the template object." } ;
+
+HELP: set-title
+{ $values { "string" string } }
+{ $description "Sets the title of the current page. This is usually called by child templates, and a master template calls " { $link write-title } "." } ;
+
+HELP: write-title
+{ $description "Writes the title of the current page, previously set by " { $link set-title } ". This is usually called by a master template after rendering a child template." } ;
+
+HELP: add-style
+{ $values { "string" string } }
+{ $description "Adds some CSS markup to the CSS stylesheet of a master template. Usually called by child templates which need to insert CSS style information in the " { $snippet "<head>" } " tag of the resulting HTML page." } ;
+
+HELP: write-style
+{ $description "Writes a CSS stylesheet assembled from " { $link add-style } " calls by child templates. Usually called by the master template to emit a CSS style in the " { $snippet "<head>" } " tag of the resulting HTML page." } ;
+
+HELP: add-atom-feed
+{ $values { "title" string } { "url" "a " { $link string } " or " { $link url } } }
+{ $description "Adds an Atom feed link to the list of feeds in a master template. Usually called by child templates which need to insert an Atom feed link information in the " { $snippet "<head>" } " tag of the resulting HTML page." } ;
+
+HELP: write-atom-feeds
+{ $description "Writes a list of Atom feed links assembled from " { $link add-atom-feed } " calls by child templates. Usually called by the master template to emit a list of Atom feed links in the " { $snippet "<head>" } " tag of the resulting HTML page." } ;
+
+HELP: nested-template?
+{ $var-description "Set to a true value if the current call to " { $link call-template } " is nested inside a " { $link with-boilerplate } " and will therefore appear as part of another template. In this case, XML processing instructions and document type declarations should be omitted." } ;
+
+HELP: call-next-template
+{ $description "Calls the next innermost child template from a master template. This is used to implement the " { $snippet "t:call-next-template" } " tag in the " { $vocab-link "html.templates.chloe" } " templating engine." } ;
+
+HELP: with-boilerplate
+{ $values { "child" template } { "master" template } }
+{ $description "Calls the child template, storing its output in a string, then calls the master template. The master template may call " { $link call-next-template } " to insert the output of the child template at any point; both templates may also use the master/child interface words documented in " { $link "html.templates.boilerplate" } "." } ;
+
+HELP: template-convert
+{ $values { "template" template } { "output" "a pathname string" } }
+{ $description "Calls the template and writes its output to a file with UTF8 encoding." } ;
+
+ARTICLE: "html.templates.boilerplate" "Boilerplate support"
+"The following words define the interface between a templating engine and the " { $vocab-link "furnace.boilerplate" } " vocabulary."
+$nl
+"The master/child template interface follows a pattern where for each concept there is a word called by the child to store an entity, and another word to write the entity out; this solves the problem where certain HTML tags, such as " { $snippet "<title>" } " and " { $snippet "<link>" } " must appear inside the " { $snippet "<head>" } " tag, even though those tags are usually precisely those that the child template will want to set."
+{ $subsection set-title }
+{ $subsection write-title }
+{ $subsection add-style }
+{ $subsection write-style }
+{ $subsection add-atom-feed }
+{ $subsection write-atom-feeds }
+"Processing a master template with a child:"
+{ $subsection with-boilerplate }
+{ $subsection call-next-template } ;
+
+ARTICLE: "html.templates" "HTML template interface"
+"The " { $vocab-link "html.templates" } " vocabulary implements an abstract interface to HTML templating engines. The " { $vocab-link "html.templates.fhtml" } " and " { $vocab-link "html.templates.chloe" } " vocabularies are two implementations of this."
+$nl
+"An HTML template is an instance of a mixin:"
+{ $subsection template }
+"HTML templates must also implement a method on a generic word:"
+{ $subsection call-template* }
+"Calling an HTML template:"
+{ $subsection call-template }
+"Usually HTML templates are invoked dynamically by the Furnace web framework and HTTP server. They can also be used in static HTML generation tools:"
+{ $subsection template-convert }
+{ $subsection "html.templates.boilerplate" } ;
+
+ABOUT: "html.templates"
index de774f0864d1c29846e95bbb132610027499fcf3..57418a3e02a0e0b6fa8aa9fb8ff6018b4ad69708 100644 (file)
@@ -67,7 +67,7 @@ SYMBOL: next-template
 
 M: f call-template* drop call-next-template ;
 
-: with-boilerplate ( body template -- )
+: with-boilerplate ( child master -- )
     [
         title [ <box> or ] change
         style [ SBUF" " clone or ] change
diff --git a/basis/http/client/client-docs.factor b/basis/http/client/client-docs.factor
new file mode 100644 (file)
index 0000000..ed84632
--- /dev/null
@@ -0,0 +1,93 @@
+USING: http help.markup help.syntax io.files io.streams.string
+io.encodings.8-bit io.encodings.binary kernel strings urls
+urls.encoding byte-arrays strings assocs sequences ;
+IN: http.client
+
+HELP: download-failed
+{ $error-description "Thrown by " { $link http-request } " if the server returns a status code other than 200. The " { $slot "response" } " and " { $slot "body" } " slots can be inspected for the underlying cause of the problem." } ;
+
+HELP: too-many-redirects
+{ $error-description "Thrown by " { $link http-request } " if the server returns a chain of than " { $link max-redirects } " redirections." } ;
+
+HELP: <get-request>
+{ $values { "url" "a " { $link url } " or " { $link string } } { "request" request } }
+{ $description "Constructs an HTTP GET request for retrieving the URL." }
+{ $notes "The request can be passed on to " { $link http-request } ", possibly after cookies and headers are set." } ;
+
+HELP: <post-request>
+{ $values { "post-data" object } { "url" "a " { $link url } " or " { $link string } } { "request" request } }
+{ $description "Constructs an HTTP POST request for submitting post data to the URL." }
+{ $notes "The request can be passed on to " { $link http-request } ", possibly after cookies and headers are set." } ;
+
+HELP: download
+{ $values { "url" "a " { $link url } " or " { $link string } } }
+{ $description "Downloads the contents of the URL to a file in the " { $link current-directory } " having the same file name." }
+{ $errors "Throws an error if the HTTP request fails." } ;
+
+HELP: download-to
+{ $values { "url" "a " { $link url } " or " { $link string } } { "file" "a pathname string" } }
+{ $description "Downloads the contents of the URL to a file with the given pathname." }
+{ $errors "Throws an error if the HTTP request fails." } ;
+
+HELP: http-get
+{ $values { "url" "a " { $link url } " or " { $link string } } { "response" response } { "data" sequence } }
+{ $description "Downloads the contents of a URL." }
+{ $errors "Throws an error if the HTTP request fails." } ;
+
+HELP: http-post
+{ $values { "post-data" object } { "url" "a " { $link url } " or " { $link string } } { "response" response } { "data" sequence } }
+{ $description "Submits a form at a URL." }
+{ $errors "Throws an error if the HTTP request fails." } ;
+
+HELP: http-request
+{ $values { "request" request } { "response" response } { "data" sequence } }
+{ $description "Sends an HTTP request to an HTTP server, and reads the response." }
+{ $errors "Throws an error if the HTTP request fails." } ;
+
+ARTICLE: "http.client.get" "GET requests with the HTTP client"
+"Basic usage involves passing a " { $link url } " and getting a " { $link response } " and data back:"
+{ $subsection http-get }
+"Utilities to retrieve a " { $link url } " and save the contents to a file:"
+{ $subsection download }
+{ $subsection download-to }
+"Advanced usage involves constructing a " { $link request } ", which allows " { $link "http.cookies" } " and " { $link "http.headers" } " to be set:"
+{ $subsection <get-request> }
+{ $subsection http-request } ;
+
+ARTICLE: "http.client.post" "POST requests with the HTTP client"
+"As with GET requests, there is a high-level word which takes a " { $link url } " and a lower-level word which constructs an HTTP request object which can be passed to " { $link http-request } ":"
+{ $subsection http-post }
+{ $subsection <post-request> }
+"Both words take a post data parameter, which can be one of the following:"
+{ $list
+    { "a " { $link byte-array } " or " { $link string } " is sent the server without further encoding" }
+    { "an " { $link assoc } " is interpreted as a series of form parameters, which are encoded with " { $link assoc>query } }
+    { { $link f } " denotes that there is no post data" }
+} ;
+
+ARTICLE: "http.client.encoding" "Character encodings and the HTTP client"
+"The " { $link http-request } ", " { $link http-get } " and " { $link http-post } " words output a sequence containing data that was sent by the server."
+$nl
+"If the server specifies a " { $snippet "content-type" } " header with a character encoding, the HTTP client decodes the data using this character encoding, and the sequence will be a string."
+$nl
+"If no encoding was specified but the MIME type is a text type, the " { $link latin1 } " encoding is assumed, and the sequence will be a string."
+$nl
+"For any other MIME type, the " { $link binary } " encoding is assumed, and thus the data is returned literally in a byte array." ;
+
+ARTICLE: "http.client.errors" "HTTP client errors"
+"HTTP operations may fail for one of two reasons. The first is an I/O error resulting from a network problem; a name server lookup failure, or a refused connection. The second is a protocol-level error returned by the server. There are two such errors:"
+{ $subsection download-failed }
+{ $subsection too-many-redirects } ;
+
+ARTICLE: "http.client" "HTTP client"
+"The " { $vocab-link "http.client" } " vocabulary implements an HTTP and HTTPS client on top of " { $link "http" } "."
+$nl
+"There are two primary usage patterns, data retrieval with GET requests and form submission with POST requests:"
+{ $subsection "http.client.get" }
+{ $subsection "http.client.post" }
+"More esoteric use-cases, for example HTTP methods other than the above, are accomodated by constructing an empty request object with " { $link <request> } " and filling everything in by hand."
+{ $subsection "http.client.encoding" }
+{ $subsection "http.client.errors" }
+{ $see-also "urls" } ;
+
+ABOUT: "http.client"
index 5e22f5144d15e6879416a369631e2bf72770f7c9..174c4e1b3a56be3e7cad1d48a6f9dc4c949895a4 100755 (executable)
@@ -10,7 +10,7 @@ io.encodings.ascii
 io.encodings.8-bit
 io.encodings.binary
 io.streams.duplex
-fry debugger summary ascii urls present
+fry debugger summary ascii urls urls.encoding present
 http http.parsers ;
 IN: http.client
 
@@ -33,7 +33,7 @@ IN: http.client
         [ content-type>> "content-type" pick set-at ]
         bi
     ] when*
-    over cookies>> f like [ unparse-cookie "cookie" pick set-at ] when*
+    over cookies>> [ unparse-cookie "cookie" pick set-at ] unless-empty
     write-header ;
 
 GENERIC: >post-data ( object -- post-data )
diff --git a/basis/http/http-docs.factor b/basis/http/http-docs.factor
new file mode 100644 (file)
index 0000000..4db04f0
--- /dev/null
@@ -0,0 +1,166 @@
+USING: assocs help.markup help.syntax io.streams.string sequences strings present math kernel byte-arrays urls
+calendar ;
+IN: http
+
+HELP: <request>
+{ $values { "request" request } }
+{ $description "Creates an empty request." } ;
+
+HELP: request
+{ $description "An HTTP request."
+$nl
+"Instances contain the following slots:"
+{ $table
+    { { $slot "method" } { "The HTTP method as a " { $link string } ". The most frequently-used HTTP methods are " { $snippet "GET" } ", " { $snippet "HEAD" } " and " { $snippet "POST" } "." } }
+    { { $slot "url" } { "The " { $link url } " being requested" } }
+    { { $slot "version" } { "The HTTP version. Default is " { $snippet "1.1" } " and should not be changed without good reason." } }
+    { { $slot "header" } { "An assoc of HTTP header values. See " { $link "http.headers" } } }
+    { { $slot "post-data" } { "See " { $link "http.post-data" } } }
+    { { $slot "cookies" } { "A sequence of HTTP cookies. See " { $link "http.cookies" } } }
+} } ;
+
+HELP: <response>
+{ $values { "response" response } }
+{ $description "Creates an empty response." } ;
+
+HELP: response
+{ $class-description "An HTTP response."
+$nl
+"Instances contain the following slots:"
+{ $table
+    { { $slot "version" } { "The HTTP version. Default is " { $snippet "1.1" } " and should not be changed without good reason." } }
+    { { $slot "code" } { "HTTP status code, an " { $link integer } ". Examples are 200 for success, 404 for file not found, and so on." } }
+    { { $slot "message" } { "HTTP status message, only displayed to the user. If the status code is 200, the status message might be ``Success'', for example." } }
+    { { $slot "header" } { "An assoc of HTTP header values. See " { $link "http.headers" } } }
+    { { $slot "cookies" } { "A sequence of HTTP cookies. See " { $link "http.cookies" } } }
+    { { $slot "content-type" } { "an HTTP content type" } }
+    { { $slot "content-charset" } { "an encoding descriptor. See " { $link "io.encodings" } } }
+    { { $slot "body" } { "an HTTP response body" } }
+} } ;
+
+HELP: <raw-response>
+{ $values { "response" raw-response } }
+{ $description "Creates an empty raw response." } ;
+
+HELP: raw-response
+{ $class-description "A minimal HTTP response used by webapps which need full control over all output sent to the client. Most webapps can use " { $link response } " instead."
+$nl
+"Instances contain the following slots:"
+{ $table
+    { { $slot "version" } { "The HTTP version. Default is " { $snippet "1.1" } " and should not be changed without good reason." } }
+    { { $slot "code" } { "HTTP status code, an " { $link integer } ". Examples are 200 for success, 404 for file not found, and so on." } }
+    { { $slot "message" } { "HTTP status message, only displayed to the user. If the status code is 200, the status message might be ``Success'', for example." } }
+    { { $slot "body" } { "an HTTP response body" } }
+} } ;
+
+HELP: <cookie>
+{ $values { "value" object } { "name" string } { "cookie" cookie } }
+{ $description "Creates a cookie with the specified name and value. The value can be any object supported by the " { $link present } " word." } ;
+
+HELP: cookie
+{ $class-description
+"An HTTP cookie."
+$nl
+"Instances contain a number of slots which correspond exactly to the fields of a cookie in the cookie specification:"
+{ $table
+    { { $slot "name" } { "The cookie name, a " { $link string } } }
+    { { $slot "value" } { "The cookie value, an object supported by " { $link present } } }
+    { { $slot "comment" } { "A " { $link string } } }
+    { { $slot "path" } { "The pathname prefix where the cookie is valid, a " { $link string } } }
+    { { $slot "domain" } { "The domain name where the cookie is valid, a " { $link string } } }
+    { { $slot "expires" } { "The expiry time, a " { $link timestamp } " or " { $link f } " for a session cookie" } }
+    { { $slot "max-age" } { "The expiry duration, a " { $link duration } " or " { $link f } " for a session cookie" } }
+    { { $slot "http-only" } { "If set to a true value, JavaScript code cannot see the cookie" } }
+    { { $slot "secure" } { "If set to a true value, the cookie is only sent for " { $snippet "https" } " protocol connections" } }
+}
+"Only one of " { $snippet "expires" } " and " { $snippet "max-age" } " can be set; the latter is preferred and is supported by all modern browsers." } ;
+
+HELP: delete-cookie
+{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "name" string } }
+{ $description "Deletes a cookie from a request or response." }
+{ $side-effects "request/response" } ;
+
+HELP: get-cookie
+{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "name" string } { "cookie/f" "a " { $link cookie } " or " { $link f } } }
+{ $description "Gets a named cookie from a request or response." } ;
+
+HELP: put-cookie
+{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "cookie" cookie } }
+{ $description "Stores a cookie in a request or response." }
+{ $side-effects "request/response" } ;
+
+HELP: <post-data>
+{ $values { "raw" byte-array } { "content-type" "a MIME type string" } { "post-data" post-data } }
+{ $description "Creates a new " { $link post-data } "." } ;
+
+HELP: header
+{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "key" string } { "value" string } }
+{ $description "Obtains an HTTP header value from a request or response." } ;
+
+HELP: post-data
+{ $class-description "HTTP POST data passed in a POST request."
+$nl
+"Instances contain the following slots:"
+{ $table
+    { { $slot "raw" } { "The raw bytes of the POST data" } }
+    { { $slot "content" } { "The POST data. This can be in a higher-level form, such as an assoc of POST parameters, a string, or an XML document" } }
+    { { $slot "content-type" } "A MIME type" }
+} } ;
+
+HELP: set-header
+{ $values { "request/response" "a " { $link request } " or a " { $link response } } { "value" object } { "key" string } }
+{ $description "Stores a value into the HTTP header of a request or response. The value can be any object supported by " { $link present } "." }
+{ $notes "This word always returns the same object that was input. This allows for a ``pipeline'' coding style, where several header parameters are set in a row." }
+{ $side-effects "request/response" } ;
+
+ARTICLE: "http.cookies" "HTTP cookies"
+"Every " { $link request } " and " { $link response } " instance can contain cookies."
+$nl
+"The " { $vocab-link "furnace.sessions" } " vocabulary implements session management using cookies, thus the most common use case can be taken care of without working with cookies directly."
+$nl
+"The class of cookies:"
+{ $subsection cookie }
+"Creating cookies:"
+{ $subsection <cookie> }
+"Getting, adding, and deleting cookies in " { $link request } " and " { $link response } " objects:"
+{ $subsection get-cookie }
+{ $subsection put-cookie }
+{ $subsection delete-cookie } ;
+
+ARTICLE: "http.headers" "HTTP headers"
+"Every " { $link request } " and " { $link response } " has a set of HTTP headers stored in the " { $slot "header" } " slot. Header names are normalized to lower-case when a request or response is being parsed."
+{ $subsection header }
+{ $subsection set-header } ;
+
+ARTICLE: "http.post-data" "HTTP post data"
+"Every " { $link request } " where the " { $slot "method" } " slot is " { $snippet "POST" } " can contain post data."
+{ $subsection post-data }
+{ $subsection <post-data> } ;
+
+ARTICLE: "http.requests" "HTTP requests"
+"HTTP requests:"
+{ $subsection request }
+{ $subsection <request> }
+"Requests can contain form submissions:"
+{ $subsection "http.post-data" } ;
+
+ARTICLE: "http.responses" "HTTP responses"
+"HTTP responses:"
+{ $subsection response }
+{ $subsection <response> }
+"Raw responses only contain a status line, with no header. They are used by webapps which need full control over the HTTP response, for example " { $vocab-link "http.server.cgi" } ":"
+{ $subsection raw-response }
+{ $subsection <raw-response> } ;
+
+ARTICLE: "http" "HTTP protocol objects"
+"The " { $vocab-link "http" } " vocabulary contains data types shared by " { $vocab-link "http.client" } " and " { $vocab-link "http.server" } "."
+$nl
+"The HTTP client sends an HTTP request to the server and receives an HTTP response back. The HTTP server receives HTTP requests from clients and sends HTTP responses back."
+{ $subsection "http.requests" }
+{ $subsection "http.responses" }
+"Both requests and responses support some common functionality:"
+{ $subsection "http.headers" }
+{ $subsection "http.cookies" }
+{ $see-also "urls" } ;
+
+ABOUT: "http"
index 3294940d8988f2b153009b20caf1e4be12f9b1ba..9a1421a3ad04ed5b0661b3631c9313860629348a 100755 (executable)
@@ -257,7 +257,7 @@ test-db [
             "" add-responder
             add-quit-action
             <dispatcher>
-                <action> "a" add-main-responder
+                <action> "" add-responder
             "d" add-responder
         test-db <db-persistence>
         main-responder set
index 0cc228c73b841636f3eec96ecf719adca797bd15..cfc205dbb57a0c63558e770489e61b327643f106 100755 (executable)
@@ -3,15 +3,13 @@
 USING: accessors kernel combinators math namespaces make
 assocs sequences splitting sorting sets debugger
 strings vectors hashtables quotations arrays byte-arrays
-math.parser calendar calendar.format present
+math.parser calendar calendar.format present urls logging
 
 io io.encodings io.encodings.iana io.encodings.binary
 io.encodings.8-bit
 
 unicode.case unicode.categories qualified
 
-urls
-
 http.parsers ;
 
 EXCLUDE: fry => , ;
@@ -98,6 +96,8 @@ TUPLE: cookie name value version comment path domain expires max-age http-only s
         drop
     ] { } make ;
 
+\ parse-cookie DEBUG add-input-logging
+
 : check-cookie-string ( string -- string' )
     dup "=;'\"\r\n" intersect empty?
     [ "Bad cookie name or value" throw ] unless ;
index 8e8e7358d1602eb273084f08eb47b286c9ba63d6..ce8257dec5b1c3eb57b09daf8f85016e2d79970c 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: combinators.short-circuit math math.order math.parser
 kernel sequences sequences.deep peg peg.parsers assocs arrays
-hashtables strings unicode.case namespaces make ascii ;
+hashtables strings unicode.case namespaces make ascii logging ;
 IN: http.parsers
 
 : except ( quot -- parser )
@@ -61,6 +61,8 @@ PEG: parse-request-line ( string -- triple )
         'space' ,
     ] seq* just ;
 
+\ parse-request-line DEBUG add-input-logging
+
 : 'text' ( -- parser )
     [ ctl? ] except ;
 
diff --git a/basis/http/server/cgi/cgi-docs.factor b/basis/http/server/cgi/cgi-docs.factor
new file mode 100644 (file)
index 0000000..e4ce71f
--- /dev/null
@@ -0,0 +1,17 @@
+USING: help.markup help.syntax http.server.static multiline ;
+IN: http.server.cgi
+
+HELP: enable-cgi
+{ $values { "responder" file-responder } }
+{ $description "Enables the responder to serve " { $snippet ".cgi" } " scripts by executing them as per the CGI specification." }
+{ $examples
+    { $code
+        <" <dispatcher>
+    "/var/www/cgi/" <static> enable-cgi "cgi-bin" add-responder" ">
+    }
+}
+{ $side-effects "responder" } ;
+
+ARTICLE: "http.server.cgi" "Serving CGI scripts"
+"The " { $vocab-link "http.server.cgi" } " implements CGI support. It is used in conjunction with a " { $link <static> } " responder."
+{ $subsection enable-cgi } ;
index 0a3cb5cff34b67e693497f5f382d0918728a4a1f..e618249ff4a56d228ec35f4a9777fbf6cdacae14 100755 (executable)
@@ -1,8 +1,9 @@
 ! Copyright (C) 2007, 2008 Slava Pestov.\r
 ! See http://factorcode.org/license.txt for BSD license.\r
 USING: namespaces kernel assocs io.files io.streams.duplex\r
-combinators arrays io.launcher io http.server.static http.server\r
-http accessors sequences strings math.parser fry urls ;\r
+combinators arrays io.launcher io.encodings.binary io\r
+http.server.static http.server http accessors sequences strings\r
+math.parser fry urls urls.encoding calendar ;\r
 IN: http.server.cgi\r
 \r
 : cgi-variables ( script-path -- assoc )\r
@@ -43,14 +44,15 @@ IN: http.server.cgi
 : <cgi-process> ( name -- desc )\r
     <process>\r
         over 1array >>command\r
-        swap cgi-variables >>environment ;\r
+        swap cgi-variables >>environment\r
+        1 minutes >>timeout ;\r
 \r
 : serve-cgi ( name -- response )\r
     <raw-response>\r
     200 >>code\r
     "CGI output follows" >>message\r
     swap '[\r
-        _ output-stream get swap <cgi-process> <process-stream> [\r
+        _ output-stream get swap <cgi-process> binary <process-stream> [\r
             post-request? [ request get post-data>> raw>> write flush ] when\r
             input-stream get swap (stream-copy)\r
         ] with-stream\r
diff --git a/basis/http/server/dispatchers/dispatchers-docs.factor b/basis/http/server/dispatchers/dispatchers-docs.factor
new file mode 100644 (file)
index 0000000..71842f6
--- /dev/null
@@ -0,0 +1,91 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: classes help.markup help.syntax io.streams.string
+multiline ;
+IN: http.server.dispatchers
+
+HELP: new-dispatcher
+{ $values { "class" class } { "dispatcher" dispatcher } }
+{ $description "Creates a new instance of a subclass of " { $link dispatcher } "." } ;
+
+HELP: dispatcher
+{ $description "The class of dispatchers. May be subclassed, in which case subclasses should be constructed by calling " { $link new-dispatcher } "." } ;
+
+HELP: <dispatcher>
+{ $values { "dispatcher" dispatcher } }
+{ $description "Creates a new pathname dispatcher." } ;
+
+HELP: vhost-dispatcher
+{ $description "The class of virtual host dispatchers." } ;
+
+HELP: <vhost-dispatcher>
+{ $values { "dispatcher" vhost-dispatcher } }
+{ $description "Creates a new virtual host dispatcher." } ;
+
+HELP: add-responder
+{ $values
+     { "dispatcher" dispatcher } { "responder" "a responder" } { "path" "a pathname string or hostname" } }
+{ $description "Adds a responder to a dispatcher." }
+{ $notes "The " { $snippet "path" } " parameter is interpreted differently depending on the dispatcher type." }
+{ $side-effects "dispatcher" } ;
+
+ARTICLE: "http.server.dispatchers.example" "HTTP dispatcher examples"
+{ $heading "Simple pathname dispatcher" }
+{ $code
+    <" <dispatcher>
+    <new-action> "new" add-responder
+    <edit-action> "edit" add-responder
+    <delete-action> "delete" add-responder
+    <list-action> "" add-responder
+main-responder set-global">
+}
+"In the above example, visiting any URL other than " { $snippet "/new" } ", " { $snippet "/edit" } ", " { $snippet "/delete" } ", or " { $snippet "/" } " will result in a 404 error."
+{ $heading "Another pathname dispatcher" }
+"On the other hand, suppose we wanted to route all unrecognized paths to a ``view'' action:"
+{ $code
+    <" <dispatcher>
+    <new-action> "new" add-responder
+    <edit-action> "edit" add-responder
+    <delete-action> "delete" add-responder
+    <view-action> >>default
+main-responder set-global">
+}
+"The " { $slot "default" } " slot holds a responder to which all unrecognized paths are sent to."
+{ $heading "Dispatcher subclassing example" }
+{ $code
+    <" TUPLE: golf-courses < dispatcher ;
+
+: <golf-courses> ( -- golf-courses )
+    golf-courses new-dispatcher ;
+
+<golf-courses>
+    <new-action> "new" add-responder
+    <edit-action> "edit" add-responder
+    <delete-action> "delete" add-responder
+    <list-action> "" add-responder
+main-responder set-global">
+}
+"The action templates can now emit links to responder-relative URLs prefixed by " { $snippet "$golf-courses/" } "."
+{ $heading "Virtual hosting example" }
+{ $code
+    <" <vhost-dispatcher>
+    <casino> "concatenative-casino.com" add-responder
+    <dating> "raptor-dating.com" add-responder
+main-responder set-global">
+}
+"Note that the virtual host dispatcher strips off a " { $snippet "www." } " prefix, so " { $snippet "www.concatenative-casino.com" } " would be routed to the " { $snippet "<casino>" } " responder instead of receiving a 404." ;
+
+ARTICLE: "http.server.dispatchers" "HTTP dispatchers and virtual hosting"
+"The " { $vocab-link "http.server.dispatchers" } " vocabulary implements two responders which route HTTP requests to one or more child responders."
+{ $subsection "http.server.dispatchers.example" }
+"Pathname dispatchers implement a directory hierarchy where each subdirectory is its own responder:"
+{ $subsection dispatcher }
+{ $subsection <dispatcher> }
+"Virtual host dispatchers dispatch each virtual host to a different responder:"
+{ $subsection vhost-dispatcher }
+{ $subsection <vhost-dispatcher> }
+"Adding responders to dispatchers:"
+{ $subsection add-responder }
+"The " { $slot "default" } " slot holds a responder which receives all unrecognized URLs. By default, it responds with 404 messages." ;
+
+ABOUT: "http.server.dispatchers"
diff --git a/basis/http/server/dispatchers/tags.txt b/basis/http/server/dispatchers/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/http/server/filters/filters-docs.factor b/basis/http/server/filters/filters-docs.factor
new file mode 100644 (file)
index 0000000..8130fcc
--- /dev/null
@@ -0,0 +1,12 @@
+USING: help.markup help.syntax http.server ;
+IN: http.server.filters
+
+HELP: filter-responder
+{ $description "The class of filter responders. This class is intended to be subclassed." } ;
+
+ARTICLE: "http.server.filters" "HTTP responder filters"
+"The " { $vocab-link "http.server.filters" } " vocabulary implements the common pattern where one responder wraps another, doing some processing before calling the wrapped responder."
+{ $subsection filter-responder }
+"To use it, simply subclass " { $link filter-responder } ", and call " { $link POSTPONE: call-next-method } " from your " { $link call-responder* } " method to pass control to the wrapped responder." ;
+
+ABOUT: "http.server.filters"
diff --git a/basis/http/server/filters/tags.txt b/basis/http/server/filters/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/http/server/redirection/redirection-docs.factor b/basis/http/server/redirection/redirection-docs.factor
new file mode 100644 (file)
index 0000000..83b420e
--- /dev/null
@@ -0,0 +1,26 @@
+USING: help.markup help.syntax urls strings http ;
+IN: http.server.redirection
+
+HELP: relative-to-request
+{ $values { "url" "a " { $link url } " or " { $link string } } { "url'" "a " { $link url } " or " { $link string } } }
+{ $description "If the input is a relative " { $link url } ", makes it an absolute URL by resolving it to the current request's URL. If the input is a string, does nothing." } ;
+
+HELP: <permanent-redirect>
+{ $values { "url" "a " { $link url } " or " { $link string } } { "response" response } }
+{ $description "Redirects to the user to the URL after applying " { $link relative-to-request } "." }
+{ $notes "This redirect type should always be used with POST requests, and with GET requests in cases where the new URL always supercedes the old one. This is due to browsers caching the new URL with permanent redirects." } ;
+
+HELP: <temporary-redirect>
+{ $values { "url" "a " { $link url } " or " { $link string } } { "response" response } }
+{ $description "Redirects to the user to the URL after applying " { $link relative-to-request } "." }
+{ $notes "This redirect type should be used with GET requests where the new URL does not always supercede the old one. Use from POST requests with care, since this will cause the browser to resubmit the form to the new URL." } ;
+
+ARTICLE: "http.server.redirection" "HTTP responder redirection"
+"The " { $vocab-link "http.server.redirection" } " defines some " { $link response } " types which redirect the user's client to a new page."
+{ $subsection <permanent-redirect> }
+{ $subsection <temporary-redirect> }
+"A utility used by the above:"
+{ $subsection relative-to-request }
+"The " { $vocab-link "furnace.redirection" } " vocabulary provides a higher-level implementation of this. The " { $vocab-link "furnace.conversations" } " vocabulary allows state to be maintained between redirects." ;
+
+ABOUT: "http.server.redirection"
index c7a13703978711d58f16fc099b5badb6426af67d..14855ca8755aa64f7e063da595febd367a35e253 100644 (file)
@@ -15,35 +15,39 @@ namespaces tools.test present kernel ;
         >>url
     request set
 
-    [ "http://www.apple.com:80/xxx/bar" ] [ 
+    [ "http://www.apple.com/xxx/bar" ] [ 
         <url> relative-to-request present 
     ] unit-test
 
-    [ "http://www.apple.com:80/xxx/baz" ] [
+    [ "http://www.apple.com/xxx/baz" ] [
         <url> "baz" >>path relative-to-request present
     ] unit-test
     
-    [ "http://www.apple.com:80/xxx/baz?c=d" ] [
+    [ "http://www.apple.com/xxx/baz?c=d" ] [
         <url> "baz" >>path { { "c" "d" } } >>query relative-to-request present
     ] unit-test
     
-    [ "http://www.apple.com:80/xxx/bar?c=d" ] [
+    [ "http://www.apple.com/xxx/bar?c=d" ] [
         <url> { { "c" "d" } } >>query relative-to-request present
     ] unit-test
     
-    [ "http://www.apple.com:80/flip" ] [
+    [ "http://www.apple.com/flip" ] [
         <url> "/flip" >>path relative-to-request present
     ] unit-test
     
-    [ "http://www.apple.com:80/flip?c=d" ] [
+    [ "http://www.apple.com/flip?c=d" ] [
         <url> "/flip" >>path { { "c" "d" } } >>query relative-to-request present
     ] unit-test
     
-    [ "http://www.jedit.org:80/" ] [
+    [ "http://www.jedit.org/" ] [
         "http://www.jedit.org" >url relative-to-request present
     ] unit-test
     
-    [ "http://www.jedit.org:80/?a=b" ] [
+    [ "http://www.jedit.org/?a=b" ] [
         "http://www.jedit.org" >url { { "a" "b" } } >>query relative-to-request present
     ] unit-test
+    
+    [ "http://www.jedit.org:1234/?a=b" ] [
+        "http://www.jedit.org:1234" >url { { "a" "b" } } >>query relative-to-request present
+    ] unit-test
 ] with-scope
diff --git a/basis/http/server/redirection/tags.txt b/basis/http/server/redirection/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/http/server/remapping/remapping-docs.factor b/basis/http/server/remapping/remapping-docs.factor
new file mode 100644 (file)
index 0000000..aa38087
--- /dev/null
@@ -0,0 +1,24 @@
+USING: help.markup help.syntax ;
+IN: http.server.remapping
+
+HELP: port-remapping
+{ $var-description "An assoc mapping port numbers that the HTTP server listens on to external port numbers presented to the user." } ;
+
+ARTICLE: "http.server.remapping" "HTTP server port remapping"
+"On Unix systems, non-root processes cannot bind to sockets on port numbers under 1024. Since running an HTTP server as root is a potential security risk, a typical setup runs an HTTP server under an ordinary user account, set up to listen on a higher port number such as 8080. Then, the HTTP port is redirected to 8080. On Linux, this might be done using commands such as the following:"
+{ $code
+    "echo 1 > /proc/sys/net/ipv4/ip_forward"
+    "iptables -t nat -F"
+    "iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j DNAT --to :8443"
+    "iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j DNAT --to :8080"
+}
+"However, the HTTP server is unaware of the forwarding, and still believes that it is listening on port 8080 and 8443, respectively. This can be a problem if a responder wishes to redirect the user to a secure page; they will be sent to port 8443 and not 443 as one would expect."
+$nl
+"The " { $vocab-link "http.server.remapping" } " vocabulary defines a variable which may store an assoc of port mappings:"
+{ $subsection port-remapping }
+"For example, with the above setup, we would set it as follows:"
+{ $code
+    "{ { 8080 80 } { 8443 443 } } port-remapping set-global"
+} ;
+
+ABOUT: "http.server.remapping"
diff --git a/basis/http/server/remapping/remapping.factor b/basis/http/server/remapping/remapping.factor
new file mode 100644 (file)
index 0000000..36e7697
--- /dev/null
@@ -0,0 +1,12 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces assocs kernel io.servers.connection ;
+IN: http.server.remapping
+
+SYMBOL: port-remapping
+
+: remap-port ( n -- n' )
+    [ port-remapping get at ] keep or ;
+
+: secure-http-port ( -- n )
+    secure-port remap-port ;
diff --git a/basis/http/server/remapping/tags.txt b/basis/http/server/remapping/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/http/server/responses/responses-docs.factor b/basis/http/server/responses/responses-docs.factor
new file mode 100644 (file)
index 0000000..5e93c4c
--- /dev/null
@@ -0,0 +1,29 @@
+USING: help.markup help.syntax io.streams.string strings
+http math ;
+IN: http.server.responses
+
+HELP: <content>
+{ $values { "body" "a response body" } { "content-type" string } { "response" response } }
+{ $description "Creates a successful HTTP response which sends a response body with the specified content type to the client." } ;
+
+HELP: <trivial-response>
+{ $values { "code" integer } { "message" string } { "response" response } }
+{ $description "Creates an HTTP error response." }
+{ $examples
+    { $code
+        "USE: http.server.responses"
+        "415 \"Unsupported Media Type\" <trivial-response>"
+    }
+} ;
+
+ARTICLE: "http.server.responses" "Canned HTTP responses"
+"The " { $vocab-link "http.server.responses" } " vocabulary provides constructors for a few useful " { $link response } " objects."
+{ $subsection <content> }
+{ $subsection <304> }
+{ $subsection <403> }
+{ $subsection <400> }
+{ $subsection <404> }
+"New error responses like the above can be created for other error codes too:"
+{ $subsection <trivial-response> } ;
+
+ABOUT: "http.server.responses"
diff --git a/basis/http/server/responses/tags.txt b/basis/http/server/responses/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/http/server/server-docs.factor b/basis/http/server/server-docs.factor
new file mode 100644 (file)
index 0000000..12183f1
--- /dev/null
@@ -0,0 +1,101 @@
+USING: help.markup help.syntax io.streams.string quotations strings urls http tools.vocabs math io.servers.connection ;
+IN: http.server
+
+HELP: trivial-responder
+{ $description "The class of trivial responders, which output the same response for every request. New instances are created by calling " { $link <trivial-responder> } "." } ;
+
+HELP: <trivial-responder> ( response -- responder )
+{ $values { "response" response } { "responder" trivial-responder } }
+{ $description "Creates a new trivial responder which outputs the same response for every request." } ;
+
+HELP: benchmark?
+{ $var-description "If set to a true value, the HTTP server will log the time taken to process each request." } ;
+
+HELP: call-responder
+{ $values
+     { "path" "a sequence of strings" } { "responder" "a responder" }
+     { "response" response } }
+{ $description "Calls a responder." } ;
+
+HELP: call-responder*
+{ $values
+     { "path" "a sequence of strings" } { "responder" "a responder" }
+     { "response" response } }
+{ $contract "Processes an HTTP request and returns a response." }
+{ $notes "When this word is called, various dynamic variables are set; see " { $link "http.server.requests" } "." } ;
+
+HELP: development?
+{ $var-description "If set to a true value, the HTTP server will call " { $link refresh-all } " on each request, and error pages will contain stack traces." } ;
+
+HELP: main-responder
+{ $var-description "The responder which will handle HTTP requests." } ;
+
+HELP: post-request?
+{ $values { "?" "a boolean" } }
+{ $description "Outputs if the current request is a POST request.s" } ;
+
+HELP: responder-nesting
+{ $description "A sequence of " { $snippet "{ path responder }" } " pairs." } ;
+
+HELP: http-server
+{ $class-description "The class of HTTP servers. New instances are created by calling " { $link <http-server> } "." } ;
+
+HELP: <http-server>
+{ $values { "server" http-server } }
+{ $description "Creates a new HTTP server with default parameters." } ;
+
+HELP: httpd
+{ $values { "port" integer } }
+{ $description "Starts an HTTP server on the specified port number." }
+{ $notes "For more flexibility, use " { $link <http-server> } " and fill in the tuple slots before calling " { $link start-server } "." } ;
+
+HELP: http-insomniac
+{ $description "Starts a thread which rotates the logs and e-mails a summary of HTTP requests every 24 hours. See " { $link "logging.insomniac" } "." } ;
+
+ARTICLE: "http.server.requests" "HTTP request variables"
+"The following variables are set by the HTTP server at the beginning of a request."
+{ $subsection request }
+{ $subsection url }
+{ $subsection post-request? }
+{ $subsection responder-nesting }
+"Additional vocabularies may be set by vocabularies such as " { $vocab-link "html.forms" } " and " { $vocab-link "furnace.sessions" } "." ;
+
+ARTICLE: "http.server.responders" "HTTP server responders"
+"The HTTP server dispatches requests to a main responder:"
+{ $subsection main-responder }
+"The main responder may in turn dispatch it a subordinate dispatcher, and so on."
+$nl
+"Responders process requests and output " { $link "http.responses" } "; concretely are instances of classes which implement a generic word:"
+{ $subsection call-responder* }
+"To actually call a subordinate responder, use the following word instead:"
+{ $subsection call-responder }
+"A simple implementation of a responder which always outputs the same response:"
+{ $subsection trivial-responder }
+{ $subsection <trivial-responder> }
+{ $vocab-subsection "Furnace actions" "furnace.actions" }
+"In particular, writing new responders by hand is rarely necessary, because in most cases it is easier to use " { $vocab-link "furnace.actions" } " instead." ;
+
+ARTICLE: "http.server.variables" "HTTP server variables"
+"The following global variables control the behavior of the HTTP server. Both are off by default."
+{ $subsection development? }
+{ $subsection benchmark? } ;
+
+ARTICLE: "http.server" "HTTP server"
+"The " { $vocab-link "http.server" } " vocabulary implements an HTTP and HTTPS server on top of " { $vocab-link "io.servers.connection" } "."
+{ $subsection "http.server.responders" }
+{ $subsection "http.server.requests" }
+"Various types of responders are defined in other vocabularies:"
+{ $subsection "http.server.dispatchers" }
+{ $subsection "http.server.filters" }
+"Useful canned responses:"
+{ $subsection "http.server.responses" }
+{ $subsection "http.server.redirection" }
+"Configuration:"
+{ $subsection "http.server.variables" }
+{ $subsection "http.server.remapping" }
+"Features:"
+{ $subsection "http.server.static" }
+{ $subsection "http.server.cgi" }
+"The " { $vocab-link "furnace" } " framework implements high-level abstractions which make developing web applications much easier than writing responders by hand." ;
+
+ABOUT: "http.server"
index bad1eb48311f55dbaf0e6fe99460394b1574e244..547e1b69fbfd21a125f7e50985598d1b41d01655 100755 (executable)
@@ -14,10 +14,11 @@ io.encodings.binary
 io.streams.limited
 io.servers.connection
 io.timeouts
-fry logging logging.insomniac calendar urls
+fry logging logging.insomniac calendar urls urls.encoding
 http
 http.parsers
 http.server.responses
+http.server.remapping
 html.templates
 html.elements
 html.streams ;
@@ -152,8 +153,8 @@ main-responder global [ <404> <trivial-responder> or ] change-at
     [ add-responder-nesting ] [ call-responder* ] 2bi ;
 
 : http-error. ( error -- )
-    "Internal server error" [
-        [ print-error nl :c ] with-html-stream
+    "Internal server error" [ ] [
+        [ print-error nl :c ] with-html-writer
     ] simple-page ;
 
 : <500> ( error -- response )
@@ -198,19 +199,20 @@ LOG: httpd-header NOTICE
     [
         local-address get
         [ secure? "https" "http" ? >>protocol ]
-        [ port>> '[ _ or ] change-port ]
+        [ port>> remap-port '[ _ or ] change-port ]
         bi
     ] change-url drop ;
 
 : valid-request? ( request -- ? )
-    url>> port>> local-address get port>> = ;
+    url>> port>> remap-port
+    local-address get port>> remap-port = ;
 
 : do-request ( request -- response )
     '[
         _
         {
-            [ init-request ]
             [ prepare-request ]
+            [ init-request ]
             [ log-request ]
             [ dup valid-request? [ dispatch-request ] [ drop <400> ] if ]
         } cleave
@@ -253,3 +255,11 @@ M: http-server handle-client*
 
 : http-insomniac ( -- )
     "http.server" { "httpd-hit" } schedule-insomniac ;
+
+USE: vocabs.loader
+
+"http.server.filters" require
+"http.server.dispatchers" require
+"http.server.redirection" require
+"http.server.static" require
+"http.server.cgi" require
diff --git a/basis/http/server/static/static-docs.factor b/basis/http/server/static/static-docs.factor
new file mode 100644 (file)
index 0000000..866d2a3
--- /dev/null
@@ -0,0 +1,37 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string ;
+IN: http.server.static
+
+HELP: <file-responder>
+{ $values { "root" "a pathname string" } { "hook" "a quotation with stack effect " { $snippet "( path mime-type -- response )" } } { "responder" file-responder } }
+{ $description "Creates a file responder which serves content from " { $snippet "path" } " by using the hook to generate a response." } ;
+
+HELP: <static>
+{ $values
+     { "root" "a pathname string" }
+     { "responder" file-responder } }
+ { $description "Creates a file responder which serves content from " { $snippet "path" } "." } ;
+
+HELP: enable-fhtml
+{ $values { "responder" file-responder } }
+{ $description "Enables the responder to serve " { $snippet ".fhtml" } " files by running them." }
+{ $notes "See " { $link "html.templates.fhtml" } "." }
+{ $side-effects "responder" } ;
+
+ARTICLE: "http.server.static" "Serving static content"
+"The " { $vocab-link "http.server.static" } " vocabulary implements a responder for serving static files."
+{ $subsection <static> }
+"The static responder does not serve directory listings by default, as a security measure. Directory listings can be enabled by storing a true value in the " { $slot "allow-listings" } " slot."
+$nl
+"The static responder can be extended for dynamic content by associating quotations with MIME types in the hashtable stored in the " { $slot "special" } " slot. The quotations have stack effect " { $snippet "( path -- )" } "."
+$nl
+"A utility word uses the above feature to enable server-side " { $snippet ".fhtml" } " scripts, allowing a development style much like PHP:"
+{ $subsection enable-fhtml }
+"This feature is also used by " { $vocab-link "http.server.cgi" } " to run " { $snippet ".cgi" } " files."
+$nl
+"It is also possible to override the hook used when serving static files to the client:"
+{ $subsection <file-responder> }
+"The default just sends the file's contents with the request; " { $vocab-link "xmode.code2html.responder" } " provides an alternate hook which sends a syntax-highlighted version of the file." ;
+
+ABOUT: "http.server.static"
index b484e64368ada4a22dd8f1491bf88b2368afab30..5ae18156b084582eae7339466d03f0ce886ba776 100755 (executable)
@@ -12,7 +12,6 @@ http.server.responses
 http.server.redirection ;\r
 IN: http.server.static\r
 \r
-! special maps mime types to quots with effect ( path -- )\r
 TUPLE: file-responder root hook special allow-listings ;\r
 \r
 : modified-since? ( filename -- ? )\r
@@ -61,7 +60,7 @@ TUPLE: file-responder root hook special allow-listings ;
     dup <a =href a> escape-string write </a> ;\r
 \r
 : directory. ( path -- )\r
-    dup file-name [\r
+    dup file-name [ ] [\r
         [ <h1> file-name escape-string write </h1> ]\r
         [\r
             <ul>\r
index b0881a9ec0c408dd092b87c1465ae4b0c248d6a0..b822da1665910eef73af4d4ebf20cefb84cb0a1b 100644 (file)
@@ -1,3 +1,3 @@
+web
 enterprise
 network
-web
index fbe352185cc83f0930223013f4cf02ab943f6831..5ab25b9c31f11212e0e6f2d8a4b09a50b6812045 100755 (executable)
@@ -8,7 +8,7 @@ $nl
 $nl
 "Buffers are used to implement native I/O backends."
 $nl
-"Buffer words are found in the " { $vocab-link "buffers" } " vocabulary."
+"Buffer words are found in the " { $vocab-link "io.buffers" } " vocabulary."
 { $subsection buffer }
 { $subsection <buffer> }
 "Buffers must be manually deallocated by calling " { $link dispose } "."
index dcd806d9a07f44807bc747ead05b0f0857ef7b1a..19b887cd75c6b586d3793f57d0c861b90ebadfc0 100755 (executable)
@@ -59,4 +59,4 @@ PRIVATE>
 PRIVATE>
 
 "resource:basis/io/encodings/iana/character-sets"
-ascii <file-reader> make-n>e \ n>e-table set-value
+ascii <file-reader> make-n>e to: n>e-table
index 1b22ca8501eccb634887457c876972b89de3fa9c..7f1a3f45075212a952934e4dede80589276a4cba 100755 (executable)
@@ -99,10 +99,12 @@ M: process hashcode* handle>> hashcode* ;
 
 GENERIC: >process ( obj -- process )
 
-ERROR: process-already-started ;
+ERROR: process-already-started process ;
 
-M: process-already-started summary
-    drop "Process has already been started once" ;
+M: process-already-started error.
+    "Process has already been started" print nl
+    "Launch descriptor:" print nl
+    process>> . ;
 
 M: process >process
     dup process-started? [
@@ -116,7 +118,14 @@ HOOK: current-process-handle io-backend ( -- handle )
 
 HOOK: run-process* io-backend ( process -- handle )
 
-ERROR: process-was-killed ;
+ERROR: process-was-killed process ;
+
+M: process-was-killed error.
+    "Process was killed as a result of a call to" print
+    "kill-process, or a timeout" print
+    nl
+    "Launch descriptor:" print nl
+    process>> . ;
 
 : wait-for-process ( process -- status )
     [
@@ -145,10 +154,13 @@ M: process-failed error.
     "Launch descriptor:" print nl
     process>> . ;
 
-: try-process ( desc -- )
-    run-process dup wait-for-process dup zero?
+: wait-for-success ( process -- )
+    dup wait-for-process dup zero?
     [ 2drop ] [ process-failed ] if ;
 
+: try-process ( desc -- )
+    run-process wait-for-success ;
+
 HOOK: kill-process* io-backend ( handle -- )
 
 : kill-process ( process -- )
@@ -167,7 +179,7 @@ M: object run-pipeline-element
     3bi
     wait-for-process ;
 
-: <process-reader*> ( process encoding -- process stream )
+: <process-reader*> ( desc encoding -- stream process )
     [
         >r (pipe) {
             [ |dispose drop ]
@@ -178,13 +190,18 @@ M: object run-pipeline-element
             ]
             [ out>> dispose ]
             [ in>> <input-port> ]
-        } cleave r> <decoder>
+        } cleave r> <decoder> swap
     ] with-destructors ;
 
 : <process-reader> ( desc encoding -- stream )
-    <process-reader*> nip ; inline
+    <process-reader*> drop ; inline
+
+: with-process-reader ( desc encoding quot -- )
+    [ <process-reader*> ] dip
+    swap [ with-input-stream ] dip
+    wait-for-success ; inline
 
-: <process-writer*> ( process encoding -- process stream )
+: <process-writer*> ( desc encoding -- stream process )
     [
         >r (pipe) {
             [ |dispose drop ]
@@ -195,13 +212,18 @@ M: object run-pipeline-element
             ]
             [ in>> dispose ]
             [ out>> <output-port> ]
-        } cleave r> <encoder>
+        } cleave r> <encoder> swap
     ] with-destructors ;
 
 : <process-writer> ( desc encoding -- stream )
-    <process-writer*> nip ; inline
+    <process-writer*> drop ; inline
 
-: <process-stream*> ( process encoding -- process stream )
+: with-process-writer ( desc encoding quot -- )
+    [ <process-writer*> ] dip
+    swap [ with-output-stream ] dip
+    wait-for-success ; inline
+
+: <process-stream*> ( desc encoding -- stream process )
     [
         >r (pipe) (pipe) {
             [ [ |dispose drop ] bi@ ]
@@ -213,11 +235,16 @@ M: object run-pipeline-element
             ]
             [ [ out>> dispose ] [ in>> dispose ] bi* ]
             [ [ in>> <input-port> ] [ out>> <output-port> ] bi* ]
-        } 2cleave r> <encoder-duplex>
+        } 2cleave r> <encoder-duplex> swap
     ] with-destructors ;
 
 : <process-stream> ( desc encoding -- stream )
-    <process-stream*> nip ; inline
+    <process-stream*> drop ; inline
+
+: with-process-stream ( desc encoding quot -- )
+    [ <process-stream*> ] dip
+    swap [ with-stream ] dip
+    wait-for-success ; inline
 
 : notify-exit ( process status -- )
     >>status
index 7d72659f6df82980540b4681bdbdf8e1078cf5c7..bde4e518ac84108d5cd2d9beb3aa835230926d24 100755 (executable)
@@ -2,10 +2,10 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: continuations destructors kernel math math.parser
 namespaces parser sequences strings prettyprint debugger
-quotations combinators logging calendar assocs
+quotations combinators logging calendar assocs present
 fry accessors arrays io io.sockets io.encodings.ascii
 io.sockets.secure io.files io.streams.duplex io.timeouts
-io.encodings threads concurrency.combinators
+io.encodings threads make concurrency.combinators
 concurrency.semaphores concurrency.flags
 combinators.short-circuit ;
 IN: io.servers.connection
@@ -56,11 +56,17 @@ GENERIC: handle-client* ( threaded-server -- )
     [ secure>> >secure ] [ insecure>> >insecure ] bi
     [ resolve-host ] bi@ append ;
 
-LOG: accepted-connection NOTICE
+: accepted-connection ( remote local -- )
+    [
+        [ "remote: " % present % ", " % ]
+        [ "local: " % present % ]
+        bi*
+    ] "" make
+    \ accepted-connection NOTICE log-message ;
 
 : log-connection ( remote local -- )
+    [ accepted-connection ]
     [ [ remote-address set ] [ local-address set ] bi* ]
-    [ 2array accepted-connection ]
     2bi ;
 
 M: threaded-server handle-client* handler>> call ;
@@ -72,6 +78,8 @@ M: threaded-server handle-client* handler>> call ;
         [ timeout>> timeouts ] [ handle-client* ] bi
     ] with-stream ;
 
+\ handle-client ERROR add-error-logging
+
 : thread-name ( server-name addrspec -- string )
     unparse-short " connection from " swap 3append ;
 
@@ -113,9 +121,9 @@ PRIVATE>
     dup secure-config>> [
         dup threaded-server [
             dup name>> [
-                listen-on [
-                    start-accept-loop
-                ] parallel-each
+                [ listen-on [ start-accept-loop ] parallel-each ]
+                [ ready>> raise-flag ]
+                bi
             ] with-logging
         ] with-variable
     ] with-secure-context ;
index 3e516dff8b8ffed8287855d21c5c55228a1031ab..42ca7276530e9f58f3160cdcf1c7fb7f2b2f4c62 100755 (executable)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors kernel symbols namespaces continuations
 destructors io.sockets sequences summary calendar delegate
-system vocabs.loader combinators ;
+system vocabs.loader combinators present ;
 IN: io.sockets.secure
 
 SYMBOL: secure-socket-timeout
@@ -43,6 +43,8 @@ TUPLE: secure addrspec ;
 
 C: <secure> secure
 
+M: secure present addrspec>> present " (secure)" append ;
+
 CONSULT: inet secure addrspec>> ;
 
 M: secure resolve-host ( secure -- seq )
index 8c9f26b1dd218250ca2089e2faeebac18fa9ca99..9bfcc7e31057ad9ebc49e7f9e8c9705c3158e98b 100755 (executable)
@@ -5,8 +5,8 @@ USING: generic kernel io.backend namespaces continuations
 sequences arrays io.encodings io.ports io.streams.duplex
 io.encodings.ascii alien.strings io.binary accessors destructors
 classes debugger byte-arrays system combinators parser
-alien.c-types math.parser splitting grouping
-math assocs summary system vocabs.loader combinators ;
+alien.c-types math.parser splitting grouping math assocs summary
+system vocabs.loader combinators present ;
 IN: io.sockets
 
 << {
@@ -40,7 +40,14 @@ TUPLE: local path ;
 : <local> ( path -- addrspec )
     normalize-path local boa ;
 
-TUPLE: inet4 host port ;
+M: local present path>> "Unix domain socket: " prepend ;
+
+TUPLE: abstract-inet host port ;
+
+M: abstract-inet present
+    [ host>> ":" ] [ port>> number>string ] bi 3append ;
+
+TUPLE: inet4 < abstract-inet ;
 
 C: <inet4> inet4
 
@@ -81,7 +88,7 @@ M: inet4 parse-sockaddr
     >r dup sockaddr-in-addr <uint> r> inet-ntop
     swap sockaddr-in-port ntohs <inet4> ;
 
-TUPLE: inet6 host port ;
+TUPLE: inet6 < abstract-inet ;
 
 C: <inet6> inet6
 
@@ -255,7 +262,7 @@ HOOK: addrinfo-error io-backend ( n -- )
 
 GENERIC: resolve-host ( addrspec -- seq )
 
-TUPLE: inet host port ;
+TUPLE: inet < abstract-inet ;
 
 C: <inet> inet
 
index 48b72255a721321904247a0b8ca6c31e5790f7fb..febec6573a104221787751e48df6c4b91ce068d5 100644 (file)
@@ -36,7 +36,7 @@ ARTICLE: "presentations" "Presentations"
 ARTICLE: "styles" "Formatted output"
 "The " { $link stream-format } ", " { $link with-style } ", " { $link with-nesting } " and " { $link tabular-output } " words take a hashtable of style attributes. Output stream implementations are free to ignore style information."
 $nl
-"Style hashtables are keyed by symbols from the " { $vocab-link "styles" } " vocabulary."
+"Style hashtables are keyed by symbols from the " { $vocab-link "io.styles" } " vocabulary."
 { $subsection "character-styles" }
 { $subsection "paragraph-styles" }
 { $subsection "table-styles" }
index b0eb327927b9f3f120bc867c1fe2d3b15b1eb3be..c9ba8f66dfe0a82ff6c5d5fedd8e2635aa596f12 100644 (file)
@@ -20,6 +20,8 @@ SYMBOL: presented
 SYMBOL: presented-path
 SYMBOL: presented-printer
 
+SYMBOL: href
+
 ! Paragraph styles
 SYMBOL: page-color
 SYMBOL: border-color
index c71b0539194779e470a31aea117aaaab7a2b4ed0..42c5009ccbbe3684b64bbf81d2dae63111b0d8a6 100644 (file)
@@ -10,6 +10,7 @@ threads calendar prettyprint destructors io.timeouts ;
     
     ! Non-recursive
     [ ] [ "monitor-test-self" temp-file f <monitor> "m" set ] unit-test
+    [ ] [ 3 seconds "m" get set-timeout ] unit-test
 
     [ ] [ "monitor-test-self" temp-file touch-file ] unit-test
 
@@ -22,6 +23,7 @@ threads calendar prettyprint destructors io.timeouts ;
     
     ! Recursive
     [ ] [ "monitor-test-self" temp-file t <monitor> "m" set ] unit-test
+    [ ] [ 3 seconds "m" get set-timeout ] unit-test
 
     [ ] [ "monitor-test-self" temp-file touch-file ] unit-test
 
index a8adedf25a1342fda564b57d06cc1e2782e41351..649c68673fe4c34679e8fc48da0d0b5cbfdaff82 100755 (executable)
@@ -27,8 +27,10 @@ M: ssl-handle handle-fd file>> handle-fd ;
     {
         { SSL_ERROR_NONE [ 2drop f ] }
         { SSL_ERROR_WANT_READ [ 2drop +input+ ] }
+        { SSL_ERROR_WANT_ACCEPT [ 2drop +input+ ] }
         { SSL_ERROR_WANT_WRITE [ 2drop +output+ ] }
         { SSL_ERROR_SYSCALL [ syscall-error ] }
+        { SSL_ERROR_ZERO_RETURN [ (ssl-error) ] }
         { SSL_ERROR_SSL [ (ssl-error) ] }
     } case ;
 
index 830861eba095ddcbb8b54893d93c785dc94001a3..6620dd691eb71856f6a78e37698b12b0131ab262 100755 (executable)
@@ -4,8 +4,12 @@ IN: io.windows.nt.files.tests
 
 [ f ] [ "\\foo" absolute-path? ] unit-test
 [ t ] [ "\\\\?\\c:\\foo" absolute-path? ] unit-test
+[ t ] [ "\\\\?\\c:\\" absolute-path? ] unit-test
+[ t ] [ "\\\\?\\c:" absolute-path? ] unit-test
 [ t ] [ "c:\\foo" absolute-path? ] unit-test
 [ t ] [ "c:" absolute-path? ] unit-test
+[ t ] [ "c:\\" absolute-path? ] unit-test
+[ f ] [ "/cygdrive/c/builds" absolute-path? ] unit-test
 
 [ "c:\\foo\\" ] [ "c:\\foo\\bar" parent-directory ] unit-test
 [ "c:\\" ] [ "c:\\foo\\" parent-directory ] unit-test
@@ -26,6 +30,9 @@ IN: io.windows.nt.files.tests
 [ f ] [ "c:\\foo" root-directory? ] unit-test
 [ f ] [ "." root-directory? ] unit-test
 [ f ] [ ".." root-directory? ] unit-test
+[ t ] [ "\\\\?\\c:\\" root-directory? ] unit-test
+[ t ] [ "\\\\?\\c:" root-directory? ] unit-test
+[ f ] [ "\\\\?\\c:\\bar" root-directory? ] unit-test
 
 [ "\\foo\\bar" ] [ "/foo/bar" normalize-path ":" split1 nip ] unit-test
 
index b572d9ec65e9dd485e82fe8052238cf5a9aad534..157662ade8bfdb9e5b13360cfffc6eb2e73d8438 100755 (executable)
@@ -20,11 +20,14 @@ M: winnt cd
 
 M: winnt root-directory? ( path -- ? )
     {
-        { [ dup empty? ] [ f ] }
-        { [ dup [ path-separator? ] all? ] [ t ] }
-        { [ dup trim-right-separators { [ length 2 = ] [ second CHAR: : = ] } 1&& ] [ t ] }
-        [ f ]
-    } cond nip ;
+        { [ dup empty? ] [ drop f ] }
+        { [ dup [ path-separator? ] all? ] [ drop t ] }
+        { [ dup trim-right-separators { [ length 2 = ]
+          [ second CHAR: : = ] } 1&& ] [ drop t ] }
+        { [ dup unicode-prefix head? ]
+          [ trim-right-separators length unicode-prefix length 2 + = ] }
+        [ drop f ]
+    } cond ;
 
 ERROR: not-absolute-path ;
 
index b3b676c1cb91905c3c0543661434b08d2c418ea8..3dfc17c08167418d2f2987d0e43650d4efe9dea4 100644 (file)
@@ -31,7 +31,7 @@ HELP: [let
 } ;
 
 HELP: [let*
-{ $syntax "[let* | binding1 [ value1... ]\n       binding2 [ value2... ]\n       ... |\n    body... ]" }
+{ $syntax "[let* | binding1 [ value1... ]\n        binding2 [ value2... ]\n        ... |\n    body... ]" }
 { $description "Introduces a set of lexical bindings and evaluates the body. The values are evaluated sequentially, and may refer to previous bindings from the same " { $link POSTPONE: [let* } " form; for Lisp programmers, this means that " { $link POSTPONE: [let* } " is equivalent to the Lisp " { $snippet "let*" } ", not " { $snippet "let" } "." }
 { $examples
     { $example
@@ -65,7 +65,7 @@ HELP: [wlet
 
 HELP: ::
 { $syntax ":: word ( bindings... -- outputs... ) body... ;" }
-{ $description "Defines a word with named inputs; it reads stack values into bindings from left to right, then executes the body with those bindings in lexical scope. Any " { $link POSTPONE: [| } ", " { $link POSTPONE: [let } " or " { $link POSTPONE: [wlet } " forms used in the body of the word definition are automatically closure-converted." }
+{ $description "Defines a word with named inputs; it reads stack values into bindings from left to right, then executes the body with those bindings in lexical scope." }
 { $notes "The output names do not affect the word's behavior, however the compiler attempts to check the stack effect as with other definitions." }
 { $examples "See " { $link POSTPONE: [| } ", " { $link POSTPONE: [let } " and " { $link POSTPONE: [wlet } "." } ;
 
@@ -85,7 +85,7 @@ HELP: MEMO::
 { POSTPONE: MEMO: POSTPONE: MEMO:: } related-words
 
 ARTICLE: "locals-mutable" "Mutable locals"
-"In the list of bindings supplied to " { $link POSTPONE: :: } ", " { $link POSTPONE: [let } " or " { $link POSTPONE: [| } ", a mutable binding may be introduced by suffixing its named with " { $snippet "!" } ". Mutable bindings are read by giving their name as usual; the suffix is not part of the binding's name. To write to a mutable binding, use the binding's with the " { $snippet "!" } " suffix."
+"In the list of bindings supplied to " { $link POSTPONE: :: } ", " { $link POSTPONE: [let } ", " { $link POSTPONE: [let* } " or " { $link POSTPONE: [| } ", a mutable binding may be introduced by suffixing its named with " { $snippet "!" } ". Mutable bindings are read by giving their name as usual; the suffix is not part of the binding's name. To write to a mutable binding, use the binding's with the " { $snippet "!" } " suffix."
 $nl
 "Here is a example word which outputs a pair of quotations which increment and decrement an internal counter, and then return the new value. The quotations are closed over the counter and each invocation of the word yields new quotations with their unique internal counter:"
 { $code
index eb06d051466fa379955b09800998e057cad21cb6..bc1e736b750b81a4a3e5362c49910cee1c5a71f9 100755 (executable)
@@ -1,7 +1,7 @@
 USING: locals math sequences tools.test hashtables words kernel
 namespaces arrays strings prettyprint io.streams.string parser
 accessors generic eval combinators combinators.short-circuit
-combinators.short-circuit.smart ;
+combinators.short-circuit.smart math.order ;
 IN: locals.tests
 
 :: foo ( a b -- a a ) a a ;
@@ -331,4 +331,13 @@ M:: sequence method-with-locals ( a -- y ) a reverse ;
 [ T{ slice f 0 3 "abc" } ]
 [ 0 3 "abc" [| from to seq | T{ slice f from to seq } ] call ] unit-test
 
-{ 3 1 } [| from to seq | T{ slice f from to seq } ] must-infer-as
\ No newline at end of file
+{ 3 1 } [| from to seq | T{ slice f from to seq } ] must-infer-as
+
+:: compare-case ( obj1 obj2 lt-quot eq-quot gt-quot -- )
+    obj1 obj2 <=> {
+        { +lt+ [ lt-quot call ] }
+        { +eq+ [ eq-quot call ] }
+        { +gt+ [ gt-quot call ] }
+    } case ; inline
+
+[ [ ] [ ] [ ] compare-case ] must-infer
\ No newline at end of file
index 10b6924b52343563351dea220a8b3a802fcf8b92..98ad28e4f63f31da79236d5af9a7620bf934e80f 100644 (file)
@@ -20,7 +20,7 @@ HELP: analyze-log
 { $description "Analyzes a log file and prints a formatted report. The " { $snippet "word-names" } " parameter is documented in " { $link analyze-entries } "." } ;
 
 ARTICLE: "logging.analysis" "Log analysis"
-"The " { $vocab-link "logging.analysis" } " vocabulary builds on the " { $vocab-link "logging.parser" } " vocabulary. It parses log files and produces formatted summary reports. It is used by the " { $vocab-link "logger.insomniac" } " vocabulary to e-mail daily reports."
+"The " { $vocab-link "logging.analysis" } " vocabulary builds on the " { $vocab-link "logging.parser" } " vocabulary. It parses log files and produces formatted summary reports. It is used by the " { $vocab-link "logging.insomniac" } " vocabulary to e-mail daily reports."
 $nl
 "Print log file summary:"
 { $subsection analyze-log }
index f4bdbfc64df22cb71afbf7ace21d42470d2cdbbc..7c14cae78e150068baa3c002c53866fbe56ae356 100755 (executable)
@@ -100,7 +100,7 @@ ARTICLE: "logging.rotation" "Log rotation"
 "The " { $vocab-link "logging.insomniac" } " vocabulary automates log rotation." ;
 
 ARTICLE: "logging.server" "Log implementation"
-"The " { $vocab-link "logging.server" } " vocabulary implements a concurrent log server using " { $vocab-link "concurrency" } ". User code never interacts with the server directly, instead it uses the words in the " { $link "logging" } " vocabulary. The server is used to synchronize access to log files and ensure that log rotation can proceed in an orderly fashion."
+"The " { $vocab-link "logging.server" } " vocabulary implements a concurrent log server using " { $vocab-link "concurrency.messaging" } ". User code never interacts with the server directly, instead it uses the words in the " { $link "logging" } " vocabulary. The server is used to synchronize access to log files and ensure that log rotation can proceed in an orderly fashion."
 $nl
 "The " { $link log-message } " word sends a message to the server which results in the server executing an internal word:"
 { $subsection (log-message) }
index fe0154b725e8ac7e696ff0b25e784852bf6957ae..af67ac5639d15f5b044a3d82481b952522f16582 100644 (file)
@@ -1,9 +1,11 @@
 IN: macros.expander.tests
 USING: macros.expander tools.test math combinators.short-circuit
-kernel ;
+kernel combinators ;
 
 [ t ] [ 20 [ { [ integer? ] [ even? ] [ 10 > ] } 1&& ] expand-macros call ] unit-test
 
 [ f ] [ 15 [ { [ integer? ] [ even? ] [ 10 > ] } 1&& ] expand-macros call ] unit-test
 
 [ f ] [ 5.0 [ { [ integer? ] [ even? ] [ 10 > ] } 1&& ] expand-macros call ] unit-test
+
+[ [ no-case ] ] [ [ { } case ] expand-macros ] unit-test
index d766430810bfeef03317aee10a97a992fa49d388..d62c6bf46606215f7a4ed0d8423561494ecbd31c 100644 (file)
@@ -33,8 +33,8 @@ M: wrapper expand-macros* wrapped>> literal ;
     stack get pop >quotation end (expand-macros) ;
 
 : expand-macro? ( word -- quot ? )
-    dup [ "macro" word-prop ] [ "transform-quot" word-prop ] bi or dup [
-        swap [ stack-effect in>> length ] [ "transform-n" word-prop ] bi or
+    dup [ "transform-quot" word-prop ] [ "macro" word-prop ] bi or dup [
+        swap [ "transform-n" word-prop ] [ stack-effect in>> length ] bi or
         stack get length <=
     ] [ 2drop f f ] if ;
 
index f3c65e51a458b19d6a08556c1a1358acaf24760a..8987def80bbae6727504c3d32449e4d2de93089c 100644 (file)
@@ -4,7 +4,7 @@ IN: math.ranges
 
 ARTICLE: "ranges" "Ranges"
 "A " { $emphasis "range" } " is a virtual sequence with real number elements "
-"ranging from " { $emphasis "a" } " to " { $emphasis "b" } " by " { $emphasis "step" } "."
+"ranging from " { $emphasis "a" } " to " { $emphasis "b" } " by " { $emphasis "step" } ". Ascending as well as descending ranges are supported."
 $nl
 "The class of ranges:"
 { $subsection range }
@@ -19,9 +19,9 @@ $nl
 "Creating general ranges:"
 { $subsection <range> }
 "Ranges are most frequently used with sequence combinators as a means of iterating over integers. For example,"
-{ $code
-    "3 10 [a,b] [ sqrt ] map"
-}
+{ $code "3 10 [a,b] [ sqrt ] map" }
+"Computing the factorial of 100 with a descending range:"
+{ $code "100 1 [a,b] product" }
 "A range can be converted into a concrete sequence using a word such as " { $link >array } ". In most cases this is unnecessary since ranges implement the sequence protocol already. It is necessary if a mutable sequence is needed, for use with words such as " { $link set-nth } " or " { $link change-each } "." ;
   
 ABOUT: "ranges"
\ No newline at end of file
index c8a2d1acc684d73179de53caa010d011777bb709..50c0365728246e1ebc2fc0554de74d0045569197 100755 (executable)
@@ -31,6 +31,6 @@ tools.test models.range ;
 \r
 ! should be able to move by a page of 10\r
 [ 10 ] [ \r
-  setup-range 10 over set-range-page-value \r
-  1 over move-by-page range-value \r
+    setup-range 10 over set-range-page-value \r
+    1 over move-by-page range-value \r
 ] unit-test\r
index c323e9b96aa6a63bb8aab5cf4908d5d77d5cfadf..357fd2cb6c15069100bd4e1b10169d764ae540da 100755 (executable)
@@ -10,4 +10,7 @@ bar
 [ "foo\nbar\n" ] [ test-it ] unit-test
 [ "foo\nbar\n" ] [ <" foo
 bar
- "> ] unit-test
+"> ] unit-test
+
+[ "hello\nworld" ] [ <" hello
+world"> ] unit-test
index 5969fc0a95dc0a9349bdac8be37a3bdc87074bbd..ecbe9e668f14f852fcc83a1ea63279924058e21f 100755 (executable)
@@ -38,7 +38,7 @@ PRIVATE>
 : parse-multiline-string ( end-text -- str )
     [
         lexer get [ swap (parse-multiline-string) ] change-column drop
-    ] "" make rest-slice but-last ;
+    ] "" make rest ;
 
 : <"
     "\">" parse-multiline-string parsed ; parsing
diff --git a/basis/nmake/authors.txt b/basis/nmake/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/nmake/summary.txt b/basis/nmake/summary.txt
new file mode 100644 (file)
index 0000000..1b82985
--- /dev/null
@@ -0,0 +1 @@
+Generalization of make for constructing several sequences simultaneously
diff --git a/basis/nmake/tags.txt b/basis/nmake/tags.txt
new file mode 100644 (file)
index 0000000..42d711b
--- /dev/null
@@ -0,0 +1 @@
+collections
index 2d1b64405086ab822302a3c149a557c45eb66c86..bae05f4244b1bbda9a55c6ddedbf7687f15bb32b 100755 (executable)
@@ -16,8 +16,6 @@ IN: opengl
 : fix-coordinates ( point1 point2 -- x1 y2 x2 y2 )
     [ first2 [ >fixnum ] bi@ ] bi@ ;
 
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
 : gl-color ( color -- ) first4 glColor4d ; inline
 
 : gl-clear-color ( color -- )
@@ -27,13 +25,11 @@ IN: opengl
     gl-clear-color GL_COLOR_BUFFER_BIT glClear ;
 
 : color>raw ( object -- r g b a )
-  >rgba { [ red>> ] [ green>> ] [ blue>> ] [ alpha>> ] } cleave ;
+    >rgba { [ red>> ] [ green>> ] [ blue>> ] [ alpha>> ] } cleave ;
 
-: set-color       ( object -- ) color>raw glColor4d ;
+: set-color ( object -- ) color>raw glColor4d ;
 : set-clear-color ( object -- ) color>raw glClearColor ;
 
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
 : gl-error ( -- )
     glGetError dup zero? [
         "GL error: " over gluErrorString append throw
@@ -53,7 +49,9 @@ IN: opengl
 : (all-enabled) ( seq quot -- )
     over [ glEnable ] each dip [ glDisable ] each ; inline
 : (all-enabled-client-state) ( seq quot -- )
-    over [ glEnableClientState ] each dip [ glDisableClientState ] each ; inline
+    [ dup [ glEnableClientState ] each ] dip
+    dip
+    [ glDisableClientState ] each ; inline
 
 MACRO: all-enabled ( seq quot -- )
     >r words>values r> [ (all-enabled) ] 2curry ;
diff --git a/basis/present/authors.txt b/basis/present/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/present/present-docs.factor b/basis/present/present-docs.factor
new file mode 100644 (file)
index 0000000..f148d96
--- /dev/null
@@ -0,0 +1,13 @@
+IN: present
+USING: help.markup help.syntax kernel strings ;
+
+ARTICLE: "present" "Converting objects to human-readable strings"
+"A word for converting an object into a human-readable string:"
+{ $subsection present } ;
+
+HELP: present
+{ $values { "object" object } { "string" string } }
+{ $contract "Outputs a human-readable string from an object." }
+{ $notes "New methods can be defined by user code. Most often, this is done so that the object can be used with various words in the " { $link "html.components" } " or " { $link "urls" } " vocabularies." } ;
+
+ABOUT: "present"
diff --git a/basis/present/summary.txt b/basis/present/summary.txt
new file mode 100644 (file)
index 0000000..94d0a5b
--- /dev/null
@@ -0,0 +1 @@
+Generic word for converting objects to strings for human consumption
index 149ecde447b3175b78c0d566aa34d1ed0a41820f..f63ce44c7184e7125e70bb13dfff55ef04e09200 100755 (executable)
@@ -123,7 +123,11 @@ PRIVATE>
 : callstack. ( callstack -- )
     callstack>array 2 <groups> [
         remove-breakpoints
-        3 nesting-limit [ . ] with-variable
+        [
+            3 nesting-limit set
+            100 length-limit set
+            .
+        ] with-scope
     ] assoc-each ;
 
 : .c ( -- ) callstack callstack. ;
@@ -225,14 +229,15 @@ M: word declarations.
 
 : pprint-; ( -- ) \ ; pprint-word ;
 
-: (see) ( spec -- )
-    <colon dup synopsis*
-    <block dup definition pprint-elements block>
-    dup definer nip [ pprint-word ] when* declarations.
-    block> ;
-
 M: object see
-    [ (see) ] with-use nl ;
+    [
+        12 nesting-limit set
+        100 length-limit set
+        <colon dup synopsis*
+        <block dup definition pprint-elements block>
+        dup definer nip [ pprint-word ] when* declarations.
+        block>
+    ] with-use nl ;
 
 GENERIC: see-class* ( word -- )
 
@@ -320,10 +325,8 @@ M: word see
     dup class? over symbol? not and [
         nl
     ] when
-    dup class? over symbol? and not [
-        [ dup (see) ] with-use nl
-    ] when
-    drop ;
+    dup [ class? ] [ symbol? ] bi and
+    [ drop ] [ call-next-method ] if ;
 
 : see-all ( seq -- )
     natural-sort [ nl ] [ see ] interleave ;
diff --git a/basis/random/authors.txt b/basis/random/authors.txt
new file mode 100644 (file)
index 0000000..5674120
--- /dev/null
@@ -0,0 +1,2 @@
+Doug Coleman
+Slava Pestov
diff --git a/basis/random/summary.txt b/basis/random/summary.txt
new file mode 100644 (file)
index 0000000..6981c56
--- /dev/null
@@ -0,0 +1 @@
+Random number generator protocol and implementations
index 90f3d1efbb7b76a8ddafb57451826a6c5cb84d65..599cd5e0ad6b3cbc03e1015e3eac9c324935ef5b 100644 (file)
@@ -1,3 +1,5 @@
+! Copyright (C) 2008 Doug Coleman
+! See http://factorcode.org/license.txt for BSD license.
 USING: alien.c-types io io.files kernel namespaces random
 io.encodings.binary init accessors system ;
 IN: random.unix
diff --git a/basis/regexp/authors.txt b/basis/regexp/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/basis/regexp/backend/backend.factor b/basis/regexp/backend/backend.factor
new file mode 100644 (file)
index 0000000..1a261fb
--- /dev/null
@@ -0,0 +1,26 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors hashtables kernel math state-tables vars vectors ;
+IN: regexp.backend
+
+TUPLE: regexp
+    raw
+    { stack vector }
+    parse-tree
+    { options hashtable }
+    nfa-table
+    dfa-table
+    minimized-table
+    { nfa-traversal-flags hashtable }
+    { dfa-traversal-flags hashtable }
+    { state integer }
+    { new-states vector }
+    { visited-states hashtable } ;
+
+: reset-regexp ( regexp -- regexp )
+    0 >>state
+    V{ } clone >>stack
+    V{ } clone >>new-states
+    H{ } clone >>visited-states ;
+
+SYMBOL: current-regexp
diff --git a/basis/regexp/classes/classes.factor b/basis/regexp/classes/classes.factor
new file mode 100644 (file)
index 0000000..a2d91b9
--- /dev/null
@@ -0,0 +1,55 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel math math.order symbols regexp.parser
+words regexp.utils unicode.categories combinators.short-circuit ;
+IN: regexp.classes
+
+GENERIC: class-member? ( obj class -- ? )
+
+M: word class-member? ( obj class -- ? ) 2drop f ;
+M: integer class-member? ( obj class -- ? ) 2drop f ;
+
+M: character-class-range class-member? ( obj class -- ? )
+    [ from>> ] [ to>> ] bi between? ;
+
+M: any-char class-member? ( obj class -- ? )
+    2drop t ;
+    
+M: letter-class class-member? ( obj class -- ? )
+    drop letter? ;
+            
+M: LETTER-class class-member? ( obj class -- ? )
+    drop LETTER? ;
+
+M: Letter-class class-member? ( obj class -- ? )
+    drop Letter? ;
+
+M: ascii-class class-member? ( obj class -- ? )
+    drop ascii? ;
+
+M: digit-class class-member? ( obj class -- ? )
+    drop digit? ;
+
+M: alpha-class class-member? ( obj class -- ? )
+    drop alpha? ;
+
+M: punctuation-class class-member? ( obj class -- ? )
+    drop punct? ;
+
+M: java-printable-class class-member? ( obj class -- ? )
+    drop java-printable? ;
+
+M: non-newline-blank-class class-member? ( obj class -- ? )
+    drop { [ blank? ] [ CHAR: \n = not ] } 1&& ;
+
+M: control-character-class class-member? ( obj class -- ? )
+    drop control-char? ;
+
+M: hex-digit-class class-member? ( obj class -- ? )
+    drop hex-digit? ;
+
+M: java-blank-class class-member? ( obj class -- ? )
+    drop java-blank? ;
+
+M: unmatchable-class class-member? ( obj class -- ? )
+    2drop f ;
diff --git a/basis/regexp/dfa/dfa.factor b/basis/regexp/dfa/dfa.factor
new file mode 100644 (file)
index 0000000..ef98525
--- /dev/null
@@ -0,0 +1,83 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators fry kernel locals
+math math.order regexp.nfa regexp.transition-tables sequences
+sets sorting vectors regexp.utils sequences.deep ;
+USING: io prettyprint threads ;
+IN: regexp.dfa
+
+: find-delta ( states transition regexp -- new-states )
+    nfa-table>> transitions>>
+    rot [ swap at at ] with with gather sift ;
+
+: (find-epsilon-closure) ( states regexp -- new-states )
+    eps swap find-delta ;
+
+: find-epsilon-closure ( states regexp -- new-states )
+    '[ dup _ (find-epsilon-closure) union ] [ length ] while-changes
+    natural-sort ;
+
+: find-closure ( states transition regexp -- new-states )
+    [ find-delta ] 2keep nip find-epsilon-closure ;
+
+: find-start-state ( regexp -- state )
+    [ nfa-table>> start-state>> 1vector ] keep find-epsilon-closure ;
+
+: find-transitions ( seq1 regexp -- seq2 )
+    nfa-table>> transitions>>
+    [ at keys ] curry gather
+    eps swap remove ;
+
+: add-todo-state ( state regexp -- )
+    2dup visited-states>> key? [
+        2drop
+    ] [
+        [ visited-states>> conjoin ]
+        [ new-states>> push ] 2bi
+    ] if ;
+
+: new-transitions ( regexp -- )
+    dup new-states>> [
+        drop
+    ] [
+        dupd pop dup pick find-transitions rot
+        [
+            [ [ find-closure ] 2keep nip dupd add-todo-state ] 3keep
+            >r swapd transition make-transition r> dfa-table>> add-transition 
+        ] curry with each
+        new-transitions
+    ] if-empty ;
+
+: states ( hashtable -- array )
+    [ keys ]
+    [ values [ values concat ] map concat append ] bi ;
+
+: set-final-states ( regexp -- )
+    dup
+    [ nfa-table>> final-states>> keys ]
+    [ dfa-table>> transitions>> states ] bi
+    [ intersect empty? not ] with filter
+
+    swap dfa-table>> final-states>>
+    [ conjoin ] curry each ;
+
+: set-initial-state ( regexp -- )
+    dup
+    [ dfa-table>> ] [ find-start-state ] bi
+    [ >>start-state drop ] keep
+    1vector >>new-states drop ;
+
+: set-traversal-flags ( regexp -- )
+    dup
+    [ nfa-traversal-flags>> ]
+    [ dfa-table>> transitions>> keys ] bi
+    [ tuck [ swap at ] with map concat ] with H{ } map>assoc
+    >>dfa-traversal-flags drop ;
+
+: construct-dfa ( regexp -- )
+    {
+        [ set-initial-state ]
+        [ new-transitions ]
+        [ set-final-states ]
+        [ set-traversal-flags ]
+    } cleave ;
diff --git a/basis/regexp/nfa/nfa.factor b/basis/regexp/nfa/nfa.factor
new file mode 100644 (file)
index 0000000..72d0fe9
--- /dev/null
@@ -0,0 +1,168 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs grouping kernel regexp.backend
+locals math namespaces regexp.parser sequences state-tables fry
+quotations math.order math.ranges vectors unicode.categories
+regexp.utils regexp.transition-tables words sets ;
+IN: regexp.nfa
+
+SYMBOL: negation-mode
+: negated? ( -- ? ) negation-mode get 0 or odd? ; 
+
+SINGLETON: eps
+
+MIXIN: traversal-flag
+SINGLETON: lookahead-on INSTANCE: lookahead-on traversal-flag
+SINGLETON: lookahead-off INSTANCE: lookahead-off traversal-flag
+SINGLETON: lookbehind-on INSTANCE: lookbehind-on traversal-flag
+SINGLETON: lookbehind-off INSTANCE: lookbehind-off traversal-flag
+SINGLETON: capture-group-on INSTANCE: capture-group-on traversal-flag
+SINGLETON: capture-group-off INSTANCE: capture-group-off traversal-flag
+
+: next-state ( regexp -- state )
+    [ state>> ] [ [ 1+ ] change-state drop ] bi ;
+
+: set-start-state ( regexp -- )
+    dup stack>> [
+        drop
+    ] [
+        [ nfa-table>> ] [ pop first ] bi* >>start-state drop
+    ] if-empty ;
+
+GENERIC: nfa-node ( node -- )
+
+:: add-simple-entry ( obj class -- )
+    [let* | regexp [ current-regexp get ]
+            s0 [ regexp next-state ]
+            s1 [ regexp next-state ]
+            stack [ regexp stack>> ]
+            table [ regexp nfa-table>> ] |
+        negated? [
+            s0 f obj class make-transition table add-transition
+            s0 s1 <default-transition> table add-transition
+        ] [
+            s0 s1 obj class make-transition table add-transition
+        ] if
+        s0 s1 2array stack push
+        t s1 table final-states>> set-at ] ;
+
+: add-traversal-flag ( flag -- )
+    stack peek second
+    current-regexp get nfa-traversal-flags>> push-at ;
+
+:: concatenate-nodes ( -- )
+    [let* | regexp [ current-regexp get ]
+            stack [ regexp stack>> ]
+            table [ regexp nfa-table>> ]
+            s2 [ stack peek first ]
+            s3 [ stack pop second ]
+            s0 [ stack peek first ]
+            s1 [ stack pop second ] |
+        s1 s2 eps <literal-transition> table add-transition
+        s1 table final-states>> delete-at
+        s0 s3 2array stack push ] ;
+
+:: alternate-nodes ( -- )
+    [let* | regexp [ current-regexp get ]
+            stack [ regexp stack>> ]
+            table [ regexp nfa-table>> ]
+            s2 [ stack peek first ]
+            s3 [ stack pop second ]
+            s0 [ stack peek first ]
+            s1 [ stack pop second ]
+            s4 [ regexp next-state ]
+            s5 [ regexp next-state ] |
+        s4 s0 eps <literal-transition> table add-transition
+        s4 s2 eps <literal-transition> table add-transition
+        s1 s5 eps <literal-transition> table add-transition
+        s3 s5 eps <literal-transition> table add-transition
+        s1 table final-states>> delete-at
+        s3 table final-states>> delete-at
+        t s5 table final-states>> set-at
+        s4 s5 2array stack push ] ;
+
+M: kleene-star nfa-node ( node -- )
+    term>> nfa-node
+    [let* | regexp [ current-regexp get ]
+            stack [ regexp stack>> ]
+            s0 [ stack peek first ]
+            s1 [ stack pop second ]
+            s2 [ regexp next-state ]
+            s3 [ regexp next-state ]
+            table [ regexp nfa-table>> ] |
+        s1 table final-states>> delete-at
+        t s3 table final-states>> set-at
+        s1 s0 eps <literal-transition> table add-transition
+        s2 s0 eps <literal-transition> table add-transition
+        s2 s3 eps <literal-transition> table add-transition
+        s1 s3 eps <literal-transition> table add-transition
+        s2 s3 2array stack push ] ;
+
+M: concatenation nfa-node ( node -- )
+    seq>>
+    [ [ nfa-node ] each ]
+    [ length 1- [ concatenate-nodes ] times ] bi ;
+
+M: alternation nfa-node ( node -- )
+    seq>>
+    [ [ nfa-node ] each ]
+    [ length 1- [ alternate-nodes ] times ] bi ;
+
+M: constant nfa-node ( node -- )
+    char>> literal-transition add-simple-entry ;
+
+M: epsilon nfa-node ( node -- )
+    drop eps literal-transition add-simple-entry ;
+
+M: word nfa-node ( node -- )
+    class-transition add-simple-entry ;
+
+M: character-class-range nfa-node ( node -- )
+    class-transition add-simple-entry ;
+
+M: capture-group nfa-node ( node -- )
+    eps literal-transition add-simple-entry
+    capture-group-on add-traversal-flag
+    term>> nfa-node
+    eps literal-transition add-simple-entry
+    capture-group-off add-traversal-flag
+    2 [ concatenate-nodes ] times ;
+
+! xyzzy
+M: non-capture-group nfa-node ( node -- )
+    term>> nfa-node ;
+
+M: reluctant-kleene-star nfa-node ( node -- )
+    term>> <kleene-star> nfa-node ;
+
+!
+
+M: negation nfa-node ( node -- )
+    negation-mode inc
+    term>> nfa-node 
+    negation-mode dec ;
+
+M: lookahead nfa-node ( node -- )
+    eps literal-transition add-simple-entry
+    lookahead-on add-traversal-flag
+    term>> nfa-node
+    eps literal-transition add-simple-entry
+    lookahead-off add-traversal-flag
+    2 [ concatenate-nodes ] times ;
+
+M: lookbehind nfa-node ( node -- )
+    eps literal-transition add-simple-entry
+    lookbehind-on add-traversal-flag
+    term>> nfa-node
+    eps literal-transition add-simple-entry
+    lookbehind-off add-traversal-flag
+    2 [ concatenate-nodes ] times ;
+
+: construct-nfa ( regexp -- )
+    [
+        reset-regexp
+        negation-mode off
+        [ current-regexp set ]
+        [ parse-tree>> nfa-node ]
+        [ set-start-state ] tri
+    ] with-scope ;
diff --git a/basis/regexp/parser/parser-tests.factor b/basis/regexp/parser/parser-tests.factor
new file mode 100644 (file)
index 0000000..0f25b2e
--- /dev/null
@@ -0,0 +1,34 @@
+USING: kernel tools.test regexp.backend regexp ;
+IN: regexp.parser
+
+: test-regexp ( string -- )
+    default-regexp parse-regexp ;
+
+! [ "(" ] [ unmatched-parentheses? ] must-fail-with
+
+[ ] [ "a|b" test-regexp ] unit-test
+[ ] [ "a.b" test-regexp ] unit-test
+[ ] [ "a|b|c" test-regexp ] unit-test
+[ ] [ "abc|b" test-regexp ] unit-test
+[ ] [ "a|bcd" test-regexp ] unit-test
+[ ] [ "a|(b)" test-regexp ] unit-test
+[ ] [ "(a)|b" test-regexp ] unit-test
+[ ] [ "(a|b)" test-regexp ] unit-test
+[ ] [ "((a)|(b))" test-regexp ] unit-test
+
+[ ] [ "(?:a)" test-regexp ] unit-test
+[ ] [ "(?i:a)" test-regexp ] unit-test
+[ ] [ "(?-i:a)" test-regexp ] unit-test
+[ "(?z:a)" test-regexp ] [ bad-option? ] must-fail-with
+[ "(?-z:a)" test-regexp ] [ bad-option? ] must-fail-with
+
+[ ] [ "(?=a)" test-regexp ] unit-test
+
+[ ] [ "[abc]" test-regexp ] unit-test
+[ ] [ "[a-c]" test-regexp ] unit-test
+[ ] [ "[^a-c]" test-regexp ] unit-test
+[ "[^]" test-regexp ] must-fail
+
+[ ] [ "|b" test-regexp ] unit-test
+[ ] [ "b|" test-regexp ] unit-test
+[ ] [ "||" test-regexp ] unit-test
diff --git a/basis/regexp/parser/parser.factor b/basis/regexp/parser/parser.factor
new file mode 100644 (file)
index 0000000..d2ed346
--- /dev/null
@@ -0,0 +1,446 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators io io.streams.string
+kernel math math.parser namespaces qualified sets
+quotations sequences splitting symbols vectors math.order
+unicode.categories strings regexp.backend regexp.utils
+unicode.case words ;
+IN: regexp.parser
+
+FROM: math.ranges => [a,b] ;
+
+MIXIN: node
+TUPLE: concatenation seq ; INSTANCE: concatenation node
+TUPLE: alternation seq ; INSTANCE: alternation node
+TUPLE: kleene-star term ; INSTANCE: kleene-star node
+
+! !!!!!!!!
+TUPLE: possessive-question term ; INSTANCE: possessive-question node
+TUPLE: possessive-kleene-star term ; INSTANCE: possessive-kleene-star node
+
+! !!!!!!!!
+TUPLE: reluctant-question term ; INSTANCE: reluctant-question node
+TUPLE: reluctant-kleene-star term ; INSTANCE: reluctant-kleene-star node
+
+TUPLE: negation term ; INSTANCE: negation node
+TUPLE: constant char ; INSTANCE: constant node
+TUPLE: range from to ; INSTANCE: range node
+
+MIXIN: parentheses-group
+TUPLE: lookahead term ; INSTANCE: lookahead node
+INSTANCE: lookahead parentheses-group
+TUPLE: lookbehind term ; INSTANCE: lookbehind node
+INSTANCE: lookbehind parentheses-group
+TUPLE: capture-group term ; INSTANCE: capture-group node
+INSTANCE: capture-group parentheses-group
+TUPLE: non-capture-group term ; INSTANCE: non-capture-group node
+INSTANCE: non-capture-group parentheses-group
+TUPLE: independent-group term ; INSTANCE: independent-group node ! atomic group
+INSTANCE: independent-group parentheses-group
+TUPLE: comment-group term ; INSTANCE: comment-group node
+INSTANCE: comment-group parentheses-group
+
+TUPLE: character-class-range from to ; INSTANCE: character-class-range node
+SINGLETON: epsilon INSTANCE: epsilon node
+SINGLETON: any-char INSTANCE: any-char node
+SINGLETON: front-anchor INSTANCE: front-anchor node
+SINGLETON: back-anchor INSTANCE: back-anchor node
+
+TUPLE: option-on option ; INSTANCE: option-on node
+TUPLE: option-off option ; INSTANCE: option-off node
+SINGLETONS: unix-lines dotall multiline comments case-insensitive unicode-case reversed-regexp ;
+
+SINGLETONS: letter-class LETTER-class Letter-class digit-class
+alpha-class non-newline-blank-class
+ascii-class punctuation-class java-printable-class blank-class
+control-character-class hex-digit-class java-blank-class c-identifier-class
+unmatchable-class ;
+
+SINGLETONS: beginning-of-group end-of-group
+beginning-of-character-class end-of-character-class
+left-parenthesis pipe caret dash ;
+
+: get-option ( option -- ? ) current-regexp get options>> at ;
+: get-unix-lines ( -- ? ) unix-lines get-option ;
+: get-dotall ( -- ? ) dotall get-option ;
+: get-multiline ( -- ? ) multiline get-option ;
+: get-comments ( -- ? ) comments get-option ;
+: get-case-insensitive ( -- ? ) case-insensitive get-option ;
+: get-unicode-case ( -- ? ) unicode-case get-option ;
+: get-reversed-regexp ( -- ? ) reversed-regexp get-option ;
+
+: <possessive-kleene-star> ( obj -- kleene ) possessive-kleene-star boa ;
+: <reluctant-kleene-star> ( obj -- kleene ) reluctant-kleene-star boa ;
+: <possessive-question> ( obj -- kleene ) possessive-question boa ;
+: <reluctant-question> ( obj -- kleene ) reluctant-question boa ;
+
+: <negation> ( obj -- negation ) negation boa ;
+: <concatenation> ( seq -- concatenation )
+    >vector get-reversed-regexp [ reverse ] when
+    [ epsilon ] [ concatenation boa ] if-empty ;
+: <alternation> ( seq -- alternation ) >vector alternation boa ;
+: <capture-group> ( obj -- capture-group ) capture-group boa ;
+: <kleene-star> ( obj -- kleene-star ) kleene-star boa ;
+: <constant> ( obj -- constant )
+    dup Letter? get-case-insensitive and [
+        [ ch>lower constant boa ]
+        [ ch>upper constant boa ] bi 2array <alternation>
+    ] [
+        constant boa
+    ] if ;
+
+: first|concatenation ( seq -- first/concatenation )
+    dup length 1 = [ first ] [ <concatenation> ] if ;
+
+: first|alternation ( seq -- first/alternation )
+    dup length 1 = [ first ] [ <alternation> ] if ;
+
+: <character-class-range> ( from to -- obj )
+    2dup [ Letter? ] bi@ or get-case-insensitive and [
+        [ [ ch>lower ] bi@ character-class-range boa ]
+        [ [ ch>upper ] bi@ character-class-range boa ] 2bi
+        2array [ [ from>> ] [ to>> ] bi < ] filter
+        [ unmatchable-class ] [ first|alternation ] if-empty
+    ] [
+        2dup <
+        [ character-class-range boa ] [ 2drop unmatchable-class ] if
+    ] if ;
+
+ERROR: unmatched-parentheses ;
+
+ERROR: bad-option ch ;
+
+: option ( ch -- singleton )
+    {
+        { CHAR: i [ case-insensitive ] }
+        { CHAR: d [ unix-lines ] }
+        { CHAR: m [ multiline ] }
+        { CHAR: n [ multiline ] }
+        { CHAR: r [ reversed-regexp ] }
+        { CHAR: s [ dotall ] }
+        { CHAR: u [ unicode-case ] }
+        { CHAR: x [ comments ] }
+        [ bad-option ]
+    } case ;
+
+: option-on ( option -- ) current-regexp get options>> conjoin ;
+: option-off ( option -- ) current-regexp get options>> delete-at ;
+
+: toggle-option ( ch ? -- ) [ option ] dip [ option-on ] [ option-off ] if ;
+: (parse-options) ( string ? -- ) [ toggle-option ] curry each ;
+
+: parse-options ( string -- )
+    "-" split1 [ t (parse-options) ] [ f (parse-options) ] bi* ;
+
+ERROR: bad-special-group string ;
+
+DEFER: (parse-regexp)
+: nested-parse-regexp ( token ? -- )
+    [ push-stack (parse-regexp) pop-stack ] dip
+    [ <negation> ] when pop-stack boa push-stack ;
+
+! non-capturing groups
+: (parse-special-group) ( -- )
+    read1 {
+        { [ dup CHAR: # = ] ! comment
+            [ drop comment-group f nested-parse-regexp pop-stack drop ] }
+        { [ dup CHAR: : = ]
+            [ drop non-capture-group f nested-parse-regexp ] }
+        { [ dup CHAR: = = ]
+            [ drop lookahead f nested-parse-regexp ] }
+        { [ dup CHAR: ! = ]
+            [ drop lookahead t nested-parse-regexp ] }
+        { [ dup CHAR: > = ]
+            [ drop non-capture-group f nested-parse-regexp ] }
+        { [ dup CHAR: < = peek1 CHAR: = = and ]
+            [ drop drop1 lookbehind f nested-parse-regexp ] }
+        { [ dup CHAR: < = peek1 CHAR: ! = and ]
+            [ drop drop1 lookbehind t nested-parse-regexp ] }
+        [
+            ":)" read-until
+            [ swap prefix ] dip
+            {
+                { CHAR: : [ parse-options non-capture-group f nested-parse-regexp ] }
+                { CHAR: ) [ parse-options ] }
+                [ drop bad-special-group ]
+            } case
+        ]
+    } cond ;
+
+: handle-left-parenthesis ( -- )
+    peek1 CHAR: ? =
+    [ drop1 (parse-special-group) ]
+    [ capture-group f nested-parse-regexp ] if ;
+
+: handle-dot ( -- ) any-char push-stack ;
+: handle-pipe ( -- ) pipe push-stack ;
+: (handle-star) ( obj -- kleene-star )
+    peek1 {
+        { CHAR: + [ drop1 <possessive-kleene-star> ] }
+        { CHAR: ? [ drop1 <reluctant-kleene-star> ] }
+        [ drop <kleene-star> ]
+    } case ;
+: handle-star ( -- ) stack pop (handle-star) push-stack ;
+: handle-question ( -- )
+    stack pop peek1 {
+        { CHAR: + [ drop1 <possessive-question> ] }
+        { CHAR: ? [ drop1 <reluctant-question> ] }
+        [ drop epsilon 2array <alternation> ]
+    } case push-stack ;
+: handle-plus ( -- )
+    stack pop dup (handle-star)
+    2array <concatenation> push-stack ;
+
+ERROR: unmatched-brace ;
+: parse-repetition ( -- start finish ? )
+    "}" read-until [ unmatched-brace ] unless
+    [ "," split1 [ string>number ] bi@ ]
+    [ CHAR: , swap index >boolean ] bi ;
+
+: replicate/concatenate ( n obj -- obj' )
+    over zero? [ 2drop epsilon ]
+    [ <repetition> first|concatenation ] if ;
+
+: exactly-n ( n -- )
+    stack pop replicate/concatenate push-stack ;
+
+: at-least-n ( n -- )
+    stack pop
+    [ replicate/concatenate ] keep
+    <kleene-star> 2array <concatenation> push-stack ;
+
+: at-most-n ( n -- )
+    1+
+    stack pop
+    [ replicate/concatenate ] curry map <alternation> push-stack ;
+
+: from-m-to-n ( m n -- )
+    [a,b]
+    stack pop
+    [ replicate/concatenate ] curry map
+    <alternation> push-stack ;
+
+ERROR: invalid-range a b ;
+
+: handle-left-brace ( -- )
+    parse-repetition
+    >r 2dup [ [ 0 < [ invalid-range ] when ] when* ] bi@ r>
+    [
+        2dup and [ from-m-to-n ]
+        [ [ nip at-most-n ] [ at-least-n ] if* ] if
+    ] [ drop 0 max exactly-n ] if ;
+
+SINGLETON: beginning-of-input
+SINGLETON: end-of-input
+
+! : beginning-of-input ( -- obj ) 
+: handle-front-anchor ( -- ) front-anchor push-stack ;
+: end-of-line ( -- obj )
+    end-of-input
+    CHAR: \r <constant>
+    CHAR: \n <constant>
+    2dup 2array <concatenation> 4array <alternation> lookahead boa ;
+
+: handle-back-anchor ( -- ) end-of-line push-stack ;
+
+ERROR: bad-character-class obj ;
+ERROR: expected-posix-class ;
+
+: parse-posix-class ( -- obj )
+    read1 CHAR: { = [ expected-posix-class ] unless
+    "}" read-until [ bad-character-class ] unless
+    {
+        { "Lower" [ get-case-insensitive Letter-class letter-class ? ] }
+        { "Upper" [ get-case-insensitive Letter-class LETTER-class ? ] }
+        { "Alpha" [ Letter-class ] }
+        { "ASCII" [ ascii-class ] }
+        { "Digit" [ digit-class ] }
+        { "Alnum" [ alpha-class ] }
+        { "Punct" [ punctuation-class ] }
+        { "Graph" [ java-printable-class ] }
+        { "Print" [ java-printable-class ] }
+        { "Blank" [ non-newline-blank-class ] }
+        { "Cntrl" [ control-character-class ] }
+        { "XDigit" [ hex-digit-class ] }
+        { "Space" [ java-blank-class ] }
+        ! TODO: unicode-character-class, fallthrough in unicode is bad-char-clss
+        [ bad-character-class ]
+    } case ;
+
+: parse-octal ( -- n ) 3 read oct> check-octal ;
+: parse-short-hex ( -- n ) 2 read hex> check-hex ;
+: parse-long-hex ( -- n ) 6 read hex> check-hex ;
+: parse-control-character ( -- n ) read1 ;
+
+ERROR: bad-escaped-literals seq ;
+: parse-escaped-literals ( -- obj )
+    "\\E" read-until [ bad-escaped-literals ] unless
+    drop1
+    [ epsilon ] [
+        [ <constant> ] V{ } map-as
+        first|concatenation
+    ] if-empty ;
+
+ERROR: unrecognized-escape char ;
+
+: parse-escaped ( -- obj )
+    read1
+    {
+        { CHAR: \ [ CHAR: \ <constant> ] }
+        { CHAR: ^ [ CHAR: ^ <constant> ] }
+        { CHAR: $ [ CHAR: $ <constant> ] }
+        { CHAR: - [ CHAR: - <constant> ] }
+        { CHAR: { [ CHAR: { <constant> ] }
+        { CHAR: } [ CHAR: } <constant> ] }
+        { CHAR: [ [ CHAR: [ <constant> ] }
+        { CHAR: ] [ CHAR: ] <constant> ] }
+        { CHAR: ( [ CHAR: ( <constant> ] }
+        { CHAR: ) [ CHAR: ) <constant> ] }
+        { CHAR: @ [ CHAR: @ <constant> ] }
+        { CHAR: * [ CHAR: * <constant> ] }
+        { CHAR: + [ CHAR: + <constant> ] }
+        { CHAR: ? [ CHAR: ? <constant> ] }
+        { CHAR: . [ CHAR: . <constant> ] }
+        { CHAR: : [ CHAR: : <constant> ] }
+        { CHAR: t [ CHAR: \t <constant> ] }
+        { CHAR: n [ CHAR: \n <constant> ] }
+        { CHAR: r [ CHAR: \r <constant> ] }
+        { CHAR: f [ HEX: c <constant> ] }
+        { CHAR: a [ HEX: 7 <constant> ] }
+        { CHAR: e [ HEX: 1b <constant> ] }
+
+        { CHAR: d [ digit-class ] }
+        { CHAR: D [ digit-class <negation> ] }
+        { CHAR: s [ java-blank-class ] }
+        { CHAR: S [ java-blank-class <negation> ] }
+        { CHAR: w [ c-identifier-class ] }
+        { CHAR: W [ c-identifier-class <negation> ] }
+
+        { CHAR: p [ parse-posix-class ] }
+        { CHAR: P [ parse-posix-class <negation> ] }
+        { CHAR: x [ parse-short-hex <constant> ] }
+        { CHAR: u [ parse-long-hex <constant> ] }
+        { CHAR: 0 [ parse-octal <constant> ] }
+        { CHAR: c [ parse-control-character ] }
+
+        ! { CHAR: b [ handle-word-boundary ] }
+        ! { CHAR: B [ handle-word-boundary <negation> ] }
+        ! { CHAR: A [ handle-beginning-of-input ] }
+        ! { CHAR: G [ end of previous match ] }
+        ! { CHAR: Z [ handle-end-of-input ] }
+        ! { CHAR: z [ handle-end-of-input ] } ! except for terminator
+
+        ! { CHAR: 1 [ CHAR: 1 <constant> ] }
+        ! { CHAR: 2 [ CHAR: 2 <constant> ] }
+        ! { CHAR: 3 [ CHAR: 3 <constant> ] }
+        ! { CHAR: 4 [ CHAR: 4 <constant> ] }
+        ! { CHAR: 5 [ CHAR: 5 <constant> ] }
+        ! { CHAR: 6 [ CHAR: 6 <constant> ] }
+        ! { CHAR: 7 [ CHAR: 7 <constant> ] }
+        ! { CHAR: 8 [ CHAR: 8 <constant> ] }
+        ! { CHAR: 9 [ CHAR: 9 <constant> ] }
+
+        { CHAR: Q [ parse-escaped-literals ] }
+        [ unrecognized-escape ]
+    } case ;
+
+: handle-escape ( -- ) parse-escaped push-stack ;
+
+: handle-dash ( vector -- vector' )
+    H{ { dash CHAR: - } } substitute ;
+
+: character-class>alternation ( seq -- alternation )
+    [ dup number? [ <constant> ] when ] map first|alternation ;
+
+: handle-caret ( vector -- vector' )
+    dup [ length 2 >= ] [ first caret eq? ] bi and [
+        rest-slice character-class>alternation <negation>
+    ] [
+        character-class>alternation
+    ] if ;
+
+: make-character-class ( -- character-class )
+    [ beginning-of-character-class swap cut-stack ] change-whole-stack
+    handle-dash handle-caret ;
+
+: apply-dash ( -- )
+    stack [ pop3 nip <character-class-range> ] keep push ;
+
+: apply-dash? ( -- ? )
+    stack dup length 3 >=
+    [ [ length 2 - ] keep nth dash eq? ] [ drop f ] if ;
+
+ERROR: empty-negated-character-class ;
+DEFER: handle-left-bracket
+: (parse-character-class) ( -- )
+    read1 [ empty-negated-character-class ] unless* {
+        { CHAR: [ [ handle-left-bracket t ] }
+        { CHAR: ] [ make-character-class push-stack f ] }
+        { CHAR: - [ dash push-stack t ] }
+        { CHAR: \ [ parse-escaped push-stack t ] }
+        [ push-stack apply-dash? [ apply-dash ] when t ]
+    } case
+    [ (parse-character-class) ] when ;
+
+: parse-character-class-second ( -- )
+    read1 {
+        { CHAR: [ [ CHAR: [ <constant> push-stack ] }
+        { CHAR: ] [ CHAR: ] <constant> push-stack ] }
+        { CHAR: - [ CHAR: - <constant> push-stack ] }
+        [ push1 ]
+    } case ;
+
+: parse-character-class-first ( -- )
+    read1 {
+        { CHAR: ^ [ caret push-stack parse-character-class-second ] }
+        { CHAR: [ [ CHAR: [ <constant> push-stack ] }
+        { CHAR: ] [ CHAR: ] <constant> push-stack ] }
+        { CHAR: - [ CHAR: - <constant> push-stack ] }
+        [ push1 ]
+    } case ;
+
+: handle-left-bracket ( -- )
+    beginning-of-character-class push-stack
+    parse-character-class-first (parse-character-class) ;
+
+: finish-regexp-parse ( stack -- obj )
+    { pipe } split
+    [ first|concatenation ] map first|alternation ;
+
+: handle-right-parenthesis ( -- )
+    stack dup [ parentheses-group "members" word-prop member? ] find-last -rot cut rest
+    [ [ push ] keep current-regexp get (>>stack) ]
+    [ finish-regexp-parse push-stack ] bi* ;
+
+
+: parse-regexp-token ( token -- ? )
+    {
+! todo: only match these at beginning/end of regexp
+        { CHAR: ^ [ handle-front-anchor t ] }
+        { CHAR: $ [ handle-back-anchor t ] }
+
+        { CHAR: . [ handle-dot t ] }
+        { CHAR: ( [ handle-left-parenthesis t ] }
+        { CHAR: ) [ handle-right-parenthesis f ] }
+        { CHAR: | [ handle-pipe t ] }
+        { CHAR: ? [ handle-question t ] }
+        { CHAR: * [ handle-star t ] }
+        { CHAR: + [ handle-plus t ] }
+        { CHAR: { [ handle-left-brace t ] }
+        { CHAR: [ [ handle-left-bracket t ] }
+        { CHAR: \ [ handle-escape t ] }
+        [ <constant> push-stack t ]
+    } case ;
+
+: (parse-regexp) ( -- )
+    read1 [ parse-regexp-token [ (parse-regexp) ] when ] when* ;
+
+: parse-regexp ( regexp -- )
+    dup current-regexp [
+        raw>> [
+            <string-reader> [ (parse-regexp) ] with-input-stream
+        ] unless-empty
+        current-regexp get
+        stack finish-regexp-parse
+            >>parse-tree drop
+    ] with-variable ;
diff --git a/basis/regexp/regexp-docs.factor b/basis/regexp/regexp-docs.factor
new file mode 100644 (file)
index 0000000..f6a1fe1
--- /dev/null
@@ -0,0 +1,14 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel strings help.markup help.syntax regexp.backend ;
+IN: regexp
+
+HELP: <regexp>
+{ $values { "string" string } { "regexp" regexp } }
+{ $description "Compiles a regular expression into a DFA and returns this object.  Regular expressions only have to be compiled once and can then be used multiple times to match input strings." } ;
+
+HELP: <iregexp>
+{ $values { "string" string } { "regexp" regexp } }
+{ $description "Compiles a case-insensitive regular expression into a DFA and returns this object.  Otherwise, exactly the same as " { $link <regexp> } } ;
+
+{ <regexp> <iregexp> } related-words
diff --git a/basis/regexp/regexp-tests.factor b/basis/regexp/regexp-tests.factor
new file mode 100644 (file)
index 0000000..46696c8
--- /dev/null
@@ -0,0 +1,334 @@
+USING: regexp tools.test kernel sequences regexp.parser
+regexp.traversal eval ;
+IN: regexp-tests
+
+[ f ] [ "b" "a*" <regexp> matches? ] unit-test
+[ t ] [ "" "a*" <regexp> matches? ] unit-test
+[ t ] [ "a" "a*" <regexp> matches? ] unit-test
+[ t ] [ "aaaaaaa" "a*"  <regexp> matches? ] unit-test
+[ f ] [ "ab" "a*" <regexp> matches? ] unit-test
+
+[ t ] [ "abc" "abc" <regexp> matches? ] unit-test
+[ t ] [ "a" "a|b|c" <regexp> matches? ] unit-test
+[ t ] [ "b" "a|b|c" <regexp> matches? ] unit-test
+[ t ] [ "c" "a|b|c" <regexp> matches? ] unit-test
+[ f ] [ "c" "d|e|f" <regexp> matches? ] unit-test
+
+[ t ] [ "b" "|b" <regexp> matches? ] unit-test
+[ t ] [ "b" "b|" <regexp> matches? ] unit-test
+[ t ] [ "" "b|" <regexp> matches? ] unit-test
+[ t ] [ "" "b|" <regexp> matches? ] unit-test
+[ f ] [ "" "|" <regexp> matches? ] unit-test
+[ f ] [ "" "|||||||" <regexp> matches? ] unit-test
+
+[ f ] [ "aa" "a|b|c" <regexp> matches? ] unit-test
+[ f ] [ "bb" "a|b|c" <regexp> matches? ] unit-test
+[ f ] [ "cc" "a|b|c" <regexp> matches? ] unit-test
+[ f ] [ "cc" "d|e|f" <regexp> matches? ] unit-test
+
+[ f ] [ "" "a+" <regexp> matches? ] unit-test
+[ t ] [ "a" "a+" <regexp> matches? ] unit-test
+[ t ] [ "aa" "a+" <regexp> matches? ] unit-test
+
+[ t ] [ "" "a?" <regexp> matches? ] unit-test
+[ t ] [ "a" "a?" <regexp> matches? ] unit-test
+[ f ] [ "aa" "a?" <regexp> matches? ] unit-test
+
+[ f ] [ "" "." <regexp> matches? ] unit-test
+[ t ] [ "a" "." <regexp> matches? ] unit-test
+[ t ] [ "." "." <regexp> matches? ] unit-test
+! [ f ] [ "\n" "." <regexp> matches? ] unit-test
+
+[ f ] [ "" ".+" <regexp> matches? ] unit-test
+[ t ] [ "a" ".+" <regexp> matches? ] unit-test
+[ t ] [ "ab" ".+" <regexp> matches? ] unit-test
+
+
+[ t ] [ "" "a|b*|c+|d?" <regexp> matches? ] unit-test
+[ t ] [ "a" "a|b*|c+|d?" <regexp> matches? ] unit-test
+[ t ] [ "c" "a|b*|c+|d?" <regexp> matches? ] unit-test
+[ t ] [ "cc" "a|b*|c+|d?" <regexp> matches? ] unit-test
+[ f ] [ "ccd" "a|b*|c+|d?" <regexp> matches? ] unit-test
+[ t ] [ "d" "a|b*|c+|d?" <regexp> matches? ] unit-test
+
+[ t ] [ "foo" "foo|bar" <regexp> matches? ] unit-test
+[ t ] [ "bar" "foo|bar" <regexp> matches? ] unit-test
+[ f ] [ "foobar" "foo|bar" <regexp> matches? ] unit-test
+
+[ f ] [ "" "(a)" <regexp> matches? ] unit-test
+[ t ] [ "a" "(a)" <regexp> matches? ] unit-test
+[ f ] [ "aa" "(a)" <regexp> matches? ] unit-test
+[ t ] [ "aa" "(a*)" <regexp> matches? ] unit-test
+
+[ f ] [ "aababaaabbac" "(a|b)+" <regexp> matches? ] unit-test
+[ t ] [ "ababaaabba" "(a|b)+" <regexp> matches? ] unit-test
+
+[ f ] [ "" "a{1}" <regexp> matches? ] unit-test
+[ t ] [ "a" "a{1}" <regexp> matches? ] unit-test
+[ f ] [ "aa" "a{1}" <regexp> matches? ] unit-test
+
+[ f ] [ "a" "a{2,}" <regexp> matches? ] unit-test
+[ t ] [ "aaa" "a{2,}" <regexp> matches? ] unit-test
+[ t ] [ "aaaa" "a{2,}" <regexp> matches? ] unit-test
+[ t ] [ "aaaaa" "a{2,}" <regexp> matches? ] unit-test
+
+[ t ] [ "" "a{,2}" <regexp> matches? ] unit-test
+[ t ] [ "a" "a{,2}" <regexp> matches? ] unit-test
+[ t ] [ "aa" "a{,2}" <regexp> matches? ] unit-test
+[ f ] [ "aaa" "a{,2}" <regexp> matches? ] unit-test
+[ f ] [ "aaaa" "a{,2}" <regexp> matches? ] unit-test
+[ f ] [ "aaaaa" "a{,2}" <regexp> matches? ] unit-test
+
+[ f ] [ "" "a{1,3}" <regexp> matches? ] unit-test
+[ t ] [ "a" "a{1,3}" <regexp> matches? ] unit-test
+[ t ] [ "aa" "a{1,3}" <regexp> matches? ] unit-test
+[ t ] [ "aaa" "a{1,3}" <regexp> matches? ] unit-test
+[ f ] [ "aaaa" "a{1,3}" <regexp> matches? ] unit-test
+
+[ f ] [ "" "[a]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[a]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[abc]" <regexp> matches? ] unit-test
+[ f ] [ "b" "[a]" <regexp> matches? ] unit-test
+[ f ] [ "d" "[abc]" <regexp> matches? ] unit-test
+[ t ] [ "ab" "[abc]{1,2}" <regexp> matches? ] unit-test
+[ f ] [ "abc" "[abc]{1,2}" <regexp> matches? ] unit-test
+
+[ f ] [ "" "[^a]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[^a]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[^abc]" <regexp> matches? ] unit-test
+[ t ] [ "b" "[^a]" <regexp> matches? ] unit-test
+[ t ] [ "d" "[^abc]" <regexp> matches? ] unit-test
+[ f ] [ "ab" "[^abc]{1,2}" <regexp> matches? ] unit-test
+[ f ] [ "abc" "[^abc]{1,2}" <regexp> matches? ] unit-test
+
+[ t ] [ "]" "[]]" <regexp> matches? ] unit-test
+[ f ] [ "]" "[^]]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^]]" <regexp> matches? ] unit-test
+
+[ "^" "[^]" <regexp> matches? ] must-fail
+[ t ] [ "^" "[]^]" <regexp> matches? ] unit-test
+[ t ] [ "]" "[]^]" <regexp> matches? ] unit-test
+
+[ t ] [ "[" "[[]" <regexp> matches? ] unit-test
+[ f ] [ "^" "[^^]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^^]" <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[-]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[-]" <regexp> matches? ] unit-test
+[ f ] [ "-" "[^-]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^-]" <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[-a]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[-a]" <regexp> matches? ] unit-test
+[ t ] [ "-" "[a-]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-]" <regexp> matches? ] unit-test
+[ f ] [ "b" "[a-]" <regexp> matches? ] unit-test
+[ f ] [ "-" "[^-]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^-]" <regexp> matches? ] unit-test
+
+[ f ] [ "-" "[a-c]" <regexp> matches? ] unit-test
+[ t ] [ "-" "[^a-c]" <regexp> matches? ] unit-test
+[ t ] [ "b" "[a-c]" <regexp> matches? ] unit-test
+[ f ] [ "b" "[^a-c]" <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[a-c-]" <regexp> matches? ] unit-test
+[ f ] [ "-" "[^a-c-]" <regexp> matches? ] unit-test
+
+[ t ] [ "\\" "[\\\\]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\\\]" <regexp> matches? ] unit-test
+[ f ] [ "\\" "[^\\\\]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^\\\\]" <regexp> matches? ] unit-test
+
+[ t ] [ "0" "[\\d]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\d]" <regexp> matches? ] unit-test
+[ f ] [ "0" "[^\\d]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[^\\d]" <regexp> matches? ] unit-test
+
+[ t ] [ "a" "[a-z]{1,}|[A-Z]{2,4}|b*|c|(f|g)*" <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}|b*|c|(f|g)*" <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}" <regexp> matches? ] unit-test
+
+[ t ] [ "1000" "\\d{4,6}" <regexp> matches? ] unit-test
+[ t ] [ "1000" "[0-9]{4,6}" <regexp> matches? ] unit-test
+
+[ t ] [ "abc" "\\p{Lower}{3}" <regexp> matches? ] unit-test
+[ f ] [ "ABC" "\\p{Lower}{3}" <regexp> matches? ] unit-test
+[ t ] [ "ABC" "\\p{Upper}{3}" <regexp> matches? ] unit-test
+[ f ] [ "abc" "\\p{Upper}{3}" <regexp> matches? ] unit-test
+! 
+[ f ] [ "abc" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
+[ t ] [ "ABC" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
+
+[ f ] [ "" "\\Q\\E" <regexp> matches? ] unit-test
+[ f ] [ "a" "\\Q\\E" <regexp> matches? ] unit-test
+[ t ] [ "|*+" "\\Q|*+\\E" <regexp> matches? ] unit-test
+[ f ] [ "abc" "\\Q|*+\\E" <regexp> matches? ] unit-test
+[ t ] [ "s" "\\Qs\\E" <regexp> matches? ] unit-test
+
+[ t ] [ "S" "\\0123" <regexp> matches? ] unit-test
+[ t ] [ "SXY" "\\0123XY" <regexp> matches? ] unit-test
+[ t ] [ "x" "\\x78" <regexp> matches? ] unit-test
+[ f ] [ "y" "\\x78" <regexp> matches? ] unit-test
+[ t ] [ "x" "\\u000078" <regexp> matches? ] unit-test
+[ f ] [ "y" "\\u000078" <regexp> matches? ] unit-test
+
+[ t ] [ "ab" "a+b" <regexp> matches? ] unit-test
+[ f ] [ "b" "a+b" <regexp> matches? ] unit-test
+[ t ] [ "aab" "a+b" <regexp> matches? ] unit-test
+[ f ] [ "abb" "a+b" <regexp> matches? ] unit-test
+
+[ t ] [ "abbbb" "ab*" <regexp> matches? ] unit-test
+[ t ] [ "a" "ab*" <regexp> matches? ] unit-test
+[ f ] [ "abab" "ab*" <regexp> matches? ] unit-test
+
+[ f ] [ "x" "\\." <regexp> matches? ] unit-test
+[ t ] [ "." "\\." <regexp> matches? ] unit-test
+
+[ t ] [ "aaaab" "a+ab" <regexp> matches? ] unit-test
+[ f ] [ "aaaxb" "a+ab" <regexp> matches? ] unit-test
+[ t ] [ "aaacb" "a+cb" <regexp> matches? ] unit-test
+
+[ 3 ] [ "aaacb" "a*" <regexp> match-head ] unit-test
+[ 2 ] [ "aaacb" "aa?" <regexp> match-head ] unit-test
+
+[ t ] [ "aaa" "AAA" <iregexp> matches? ] unit-test
+[ f ] [ "aax" "AAA" <iregexp> matches? ] unit-test
+[ t ] [ "aaa" "A*" <iregexp> matches? ] unit-test
+[ f ] [ "aaba" "A*" <iregexp> matches? ] unit-test
+[ t ] [ "b" "[AB]" <iregexp> matches? ] unit-test
+[ f ] [ "c" "[AB]" <iregexp> matches? ] unit-test
+[ t ] [ "c" "[A-Z]" <iregexp> matches? ] unit-test
+[ f ] [ "3" "[A-Z]" <iregexp> matches? ] unit-test
+
+[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
+[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
+[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
+[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
+
+[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
+[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
+[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
+[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
+
+[ f ] [ "A" "[a-z]" <regexp> matches? ] unit-test
+[ t ] [ "A" "[a-z]" <iregexp> matches? ] unit-test
+
+[ f ] [ "A" "\\p{Lower}" <regexp> matches? ] unit-test
+[ t ] [ "A" "\\p{Lower}" <iregexp> matches? ] unit-test
+
+[ t ] [ "abc" <reversed> "abc" <rregexp> matches? ] unit-test
+[ t ] [ "abc" <reversed> "a[bB][cC]" <rregexp> matches? ] unit-test
+[ t ] [ "adcbe" "a(?r)(bcd)(?-r)e" <rregexp> matches? ] unit-test
+
+[ t ] [ "s@f" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
+[ t ] [ ".o" "\\.[a-z]" <regexp> matches? ] unit-test
+
+[ t ] [ "abc*" "[^\\*]*\\*" <regexp> matches? ] unit-test
+[ t ] [ "bca" "[^a]*a" <regexp> matches? ] unit-test
+
+[ ] [
+    "(0[lL]?|[1-9]\\d{0,9}(\\d{0,9}[lL])?|0[xX]\\p{XDigit}{1,8}(\\p{XDigit}{0,8}[lL])?|0[0-7]{1,11}([0-7]{0,11}[lL])?|([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][+-]?[0-9]+)?[fFdD]?|[0-9]+([eE][+-]?[0-9]+[fFdD]?|([eE][+-]?[0-9]+)?[fFdD]))"
+    <regexp> drop
+] unit-test
+
+[ ] [ "(\\$[\\p{XDigit}]|[\\p{Digit}])" <regexp> drop ] unit-test
+
+! Comment
+[ t ] [ "ac" "a(?#boo)c" <regexp> matches? ] unit-test
+
+
+
+! [ "{Lower}" <regexp> ] [ invalid-range? ] must-fail-with
+
+! [ 1 ] [ "aaacb" "a+?" <regexp> match-head ] unit-test
+! [ 1 ] [ "aaacb" "aa??" <regexp> match-head ] unit-test
+! [ f ] [ "aaaab" "a++ab" <regexp> matches? ] unit-test
+! [ t ] [ "aaacb" "a++cb" <regexp> matches? ] unit-test
+! [ 3 ] [ "aacb" "aa?c" <regexp> match-head ] unit-test
+! [ 3 ] [ "aacb" "aa??c" <regexp> match-head ] unit-test
+
+! [ t ] [ "fxxbar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
+! [ f ] [ "foobar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
+
+[ 3 ] [ "foobar" "foo(?=bar)" <regexp> match-head ] unit-test
+[ f ] [ "foobxr" "foo(?=bar)" <regexp> match-head ] unit-test
+
+! [ f ] [ "foobxr" "foo\\z" <regexp> match-head ] unit-test
+! [ 3 ] [ "foo" "foo\\z" <regexp> match-head ] unit-test
+
+! [ 3 ] [ "foo bar" "foo\\b" <regexp> match-head ] unit-test
+! [ f ] [ "fooxbar" "foo\\b" <regexp> matches? ] unit-test
+! [ t ] [ "foo" "foo\\b" <regexp> matches? ] unit-test
+! [ t ] [ "foo bar" "foo\\b bar" <regexp> matches? ] unit-test
+! [ f ] [ "fooxbar" "foo\\bxbar" <regexp> matches? ] unit-test
+! [ f ] [ "foo" "foo\\bbar" <regexp> matches? ] unit-test
+
+! [ f ] [ "foo bar" "foo\\B" <regexp> matches? ] unit-test
+! [ 3 ] [ "fooxbar" "foo\\B" <regexp> match-head ] unit-test
+! [ t ] [ "foo" "foo\\B" <regexp> matches? ] unit-test
+! [ f ] [ "foo bar" "foo\\B bar" <regexp> matches? ] unit-test
+! [ t ] [ "fooxbar" "foo\\Bxbar" <regexp> matches? ] unit-test
+! [ f ] [ "foo" "foo\\Bbar" <regexp> matches? ] unit-test
+
+[ ] [ "USING: regexp kernel ; R' -{3}[+]{1,6}(?:!!)?\\s' drop" eval ] unit-test
+
+[ ] [ "USING: regexp kernel ; R' (ftp|http|https)://(\\w+:?\\w*@)?(\\S+)(:[0-9]+)?(/|/([\\w#!:.?+=&%@!\\-/]))?' drop" eval ] unit-test
+
+[ ] [ "USING: regexp kernel ; R' \\*[^\s*][^*]*\\*' drop" eval ] unit-test
+
+! Bug in parsing word
+! [ t ] [ "a" R' a' matches?  ] unit-test
+
+! ((A)(B(C)))
+! 1.  ((A)(B(C)))
+! 2. (A)
+! 3. (B(C))
+! 4. (C) 
+
+! clear "a(?=b*)" <regexp> "ab" over match
+! clear "a(?=b*c)" <regexp> "abbbbbc" over match
+! clear "a(?=b*)" <regexp> "ab" over match
+
+! clear "^a" <regexp> "a" over match
+! clear "^a" <regexp> "\na" over match
+! clear "^a" <regexp> "\r\na" over match
+! clear "^a" <regexp> "\ra" over match
+
+! clear "a$" <regexp> "a" over match
+! clear "a$" <regexp> "a\n" over match
+! clear "a$" <regexp> "a\r" over match
+! clear "a$" <regexp> "a\r\n" over match
+
+! "(az)(?<=b)" <regexp> "baz" over first-match
+! "a(?<=b*)" <regexp> "cbaz" over first-match
+! "a(?<=b)" <regexp> "baz" over first-match
+
+! "a(?<!b)" <regexp> "baz" over first-match
+! "a(?<!b)" <regexp> "caz" over first-match
+
+! "a(?=bcdefg)bcd" <regexp> "abcdefg" over first-match
+! "a(?#bcdefg)bcd" <regexp> "abcdefg" over first-match
+! "a(?:bcdefg)" <regexp> "abcdefg" over first-match
+
+[ { 0 1 } ] [ "ac" "a(?!b)" <regexp> first-match ] unit-test
+[ f ] [ "ab" "a(?!b)" <regexp> first-match ] unit-test
+
+! "a(?<=b)" <regexp> "caba" over first-match
+
+[ { 0 1 } ] [ "ab" "a(?=b)(?=b)" <regexp> first-match ] unit-test
+[ { 1 2 } ] [ "ba" "a(?<=b)(?<=b)" <regexp> first-match ] unit-test
+[ { 1 2 } ] [ "cab" "a(?=b)(?<=c)" <regexp> first-match ] unit-test
+
+! capture group 1: "aaaa"  2: ""
+! "aaaa" "(a*)(a*)" <regexp> match*
+! "aaaa" "(a*)(a+)" <regexp> match*
+
+[ { 0 2 } ] [ "ab" "(a|ab)(bc)?" <regexp> first-match ] unit-test
+[ { 0 3 } ] [ "abc" "(a|ab)(bc)?" <regexp> first-match ] unit-test
+
+[ { 0 2 } ] [ "ab" "(ab|a)(bc)?" <regexp> first-match ] unit-test
+[ { 0 3 } ] [ "abc" "(ab|a)(bc)?" <regexp> first-match ] unit-test
+
+[ { 23 24 } ] [ "aaaaaaaaaaaaaaaaaaaaaaab" "((a*)*b)*b" <regexp> first-match ] unit-test
+
diff --git a/basis/regexp/regexp.factor b/basis/regexp/regexp.factor
new file mode 100644 (file)
index 0000000..73555fe
--- /dev/null
@@ -0,0 +1,144 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators kernel math math.ranges sequences
+sets assocs prettyprint.backend make lexer namespaces parser
+arrays fry regexp.backend regexp.utils regexp.parser regexp.nfa
+regexp.dfa regexp.traversal regexp.transition-tables ;
+IN: regexp
+
+: default-regexp ( string -- regexp )
+    regexp new
+        swap >>raw
+        <transition-table> >>nfa-table
+        <transition-table> >>dfa-table
+        <transition-table> >>minimized-table
+        H{ } clone >>nfa-traversal-flags
+        H{ } clone >>dfa-traversal-flags
+        H{ } clone >>options
+        reset-regexp ;
+
+: construct-regexp ( regexp -- regexp' )
+    {
+        [ parse-regexp ]
+        [ construct-nfa ]
+        [ construct-dfa ]
+        [ ]
+    } cleave ;
+
+: match ( string regexp -- pair )
+    <dfa-traverser> do-match return-match ;
+
+: match* ( string regexp -- pair )
+    <dfa-traverser> do-match [ return-match ] [ captured-groups>> ] bi ;
+
+: matches? ( string regexp -- ? )
+    dupd match
+    [ [ length ] [ length>> 1- ] bi* = ] [ drop f ] if* ;
+
+: match-head ( string regexp -- end/f ) match [ length>> 1- ] [ f ] if* ;
+
+: match-at ( string m regexp -- n/f finished? )
+    [
+        2dup swap length > [ 2drop f f ] [ tail-slice t ] if
+    ] dip swap [ match-head f ] [ 2drop f t ] if ;
+
+: match-range ( string m regexp -- a/f b/f )
+    3dup match-at over [
+        drop nip rot drop dupd +
+    ] [
+        [ 3drop drop f f ] [ drop [ 1+ ] dip match-range ] if
+    ] if ;
+
+: first-match ( string regexp -- pair/f )
+    0 swap match-range dup [ 2array ] [ 2drop f ] if ;
+
+: re-cut ( string regexp -- end/f start )
+    dupd first-match
+    [ [ second tail-slice ] [ first head ] 2bi ]
+    [ "" like f swap ]
+    if* ;
+
+: re-split ( string regexp -- seq )
+    [ dup ] swap '[ _ re-cut ] [ ] produce nip ;
+
+: re-replace ( string regexp replacement -- result )
+    [ re-split ] dip join ;
+
+: next-match ( string regexp -- end/f match/f )
+    dupd first-match dup
+    [ [ second tail-slice ] keep ]
+    [ 2drop f f ]
+    if ;
+
+: all-matches ( string regexp -- seq )
+    [ dup ] swap '[ _ next-match ] [ ] produce nip ;
+
+: count-matches ( string regexp -- n )
+    all-matches length 1- ;
+
+: initial-option ( regexp option -- regexp' )
+    over options>> conjoin ;
+
+: <regexp> ( string -- regexp )
+    default-regexp construct-regexp ;
+
+: <iregexp> ( string -- regexp )
+    default-regexp
+    case-insensitive initial-option
+    construct-regexp ;
+
+: <rregexp> ( string -- regexp )
+    default-regexp
+    reversed-regexp initial-option
+    construct-regexp ;
+
+
+: parsing-regexp ( accum end -- accum )
+    lexer get dup skip-blank
+    [ [ index-from dup 1+ swap ] 2keep swapd subseq swap ] change-lexer-column
+    lexer get dup still-parsing-line?
+    [ (parse-token) ] [ drop f ] if
+    "i" = [ <iregexp> ] [ <regexp> ] if parsed ;
+
+: R! CHAR: ! parsing-regexp ; parsing
+: R" CHAR: " parsing-regexp ; parsing
+: R# CHAR: # parsing-regexp ; parsing
+: R' CHAR: ' parsing-regexp ; parsing
+: R( CHAR: ) parsing-regexp ; parsing
+: R/ CHAR: / parsing-regexp ; parsing
+: R@ CHAR: @ parsing-regexp ; parsing
+: R[ CHAR: ] parsing-regexp ; parsing
+: R` CHAR: ` parsing-regexp ; parsing
+: R{ CHAR: } parsing-regexp ; parsing
+: R| CHAR: | parsing-regexp ; parsing
+
+
+: find-regexp-syntax ( string -- prefix suffix )
+    {
+        { "R/ "  "/"  }
+        { "R! "  "!"  }
+        { "R\" " "\"" }
+        { "R# "  "#"  }
+        { "R' "  "'"  }
+        { "R( "  ")"  }
+        { "R@ "  "@"  }
+        { "R[ "  "]"  }
+        { "R` "  "`"  }
+        { "R{ "  "}"  }
+        { "R| "  "|"  }
+    } swap [ subseq? not nip ] curry assoc-find drop ;
+
+: option? ( option regexp -- ? )
+    options>> key? ;
+
+USE: multiline
+/*
+M: regexp pprint*
+    [
+        [
+            dup raw>>
+            dup find-regexp-syntax swap % swap % %
+            case-insensitive swap option? [ "i" % ] when
+        ] "" make
+    ] keep present-text ;
+*/
diff --git a/basis/regexp/summary.txt b/basis/regexp/summary.txt
new file mode 100644 (file)
index 0000000..aa1e1c2
--- /dev/null
@@ -0,0 +1 @@
+Regular expressions
diff --git a/basis/regexp/tags.txt b/basis/regexp/tags.txt
new file mode 100644 (file)
index 0000000..65bc471
--- /dev/null
@@ -0,0 +1,2 @@
+parsing
+text
diff --git a/basis/regexp/transition-tables/transition-tables.factor b/basis/regexp/transition-tables/transition-tables.factor
new file mode 100644 (file)
index 0000000..1c9a3e3
--- /dev/null
@@ -0,0 +1,46 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs fry hashtables kernel sequences
+vectors regexp.utils ;
+IN: regexp.transition-tables
+
+TUPLE: transition from to obj ;
+TUPLE: literal-transition < transition ;
+TUPLE: class-transition < transition ;
+TUPLE: default-transition < transition ;
+
+TUPLE: literal obj ;
+TUPLE: class obj ;
+TUPLE: default ;
+: make-transition ( from to obj class -- obj )
+    new
+        swap >>obj
+        swap >>to
+        swap >>from ;
+
+: <literal-transition> ( from to obj -- transition )
+    literal-transition make-transition ;
+: <class-transition> ( from to obj -- transition )
+    class-transition make-transition ;
+: <default-transition> ( from to -- transition )
+    t default-transition make-transition ;
+
+TUPLE: transition-table transitions start-state final-states ;
+
+: <transition-table> ( -- transition-table )
+    transition-table new
+        H{ } clone >>transitions
+        H{ } clone >>final-states ;
+
+: maybe-initialize-key ( key hashtable -- )
+    2dup key? [ 2drop ] [ H{ } clone -rot set-at ] if ;
+
+: set-transition ( transition hash -- )
+    #! set the state as a key
+    2dup [ to>> ] dip maybe-initialize-key
+    [ [ to>> ] [ obj>> ] [ from>> ] tri ] dip
+    2dup at* [ 2nip insert-at ]
+    [ drop >r >r H{ } clone [ insert-at ] keep r> r> set-at ] if ;
+
+: add-transition ( transition transition-table -- )
+    transitions>> set-transition ;
diff --git a/basis/regexp/traversal/traversal.factor b/basis/regexp/traversal/traversal.factor
new file mode 100644 (file)
index 0000000..f5a235f
--- /dev/null
@@ -0,0 +1,150 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators kernel math math.ranges
+quotations sequences regexp.parser regexp.classes fry arrays
+combinators.short-circuit regexp.utils prettyprint regexp.nfa ;
+IN: regexp.traversal
+
+TUPLE: dfa-traverser
+    dfa-table
+    traversal-flags
+    traverse-forward
+    lookahead-counters
+    lookbehind-counters
+    capture-counters
+    captured-groups
+    capture-group-index
+    last-state current-state
+    text
+    start-index current-index
+    matches ;
+
+: <dfa-traverser> ( text regexp -- match )
+    [ dfa-table>> ] [ dfa-traversal-flags>> ] bi
+    dfa-traverser new
+        swap >>traversal-flags
+        swap [ start-state>> >>current-state ] keep
+        >>dfa-table
+        swap >>text
+        t >>traverse-forward
+        0 >>start-index
+        0 >>current-index
+        0 >>capture-group-index
+        V{ } clone >>matches
+        V{ } clone >>capture-counters
+        V{ } clone >>lookbehind-counters
+        V{ } clone >>lookahead-counters
+        H{ } clone >>captured-groups ;
+
+: final-state? ( dfa-traverser -- ? )
+    [ current-state>> ] [ dfa-table>> final-states>> ] bi
+    key? ;
+
+: text-finished? ( dfa-traverser -- ? )
+    {
+        [ current-state>> empty? ]
+        [ [ current-index>> ] [ text>> length ] bi >= ]
+        ! [ current-index>> 0 < ]
+    } 1|| ;
+
+: save-final-state ( dfa-straverser -- )
+    [ current-index>> ] [ matches>> ] bi push ;
+
+: match-done? ( dfa-traverser -- ? )
+    dup final-state? [
+        dup save-final-state
+    ] when text-finished? ;
+
+GENERIC: flag-action ( dfa-traverser flag -- )
+
+M: lookahead-on flag-action ( dfa-traverser flag -- )
+    drop
+    lookahead-counters>> 0 swap push ;
+
+M: lookahead-off flag-action ( dfa-traverser flag -- )
+    drop
+    dup lookahead-counters>>
+    [ drop ] [ pop '[ _ - ] change-current-index drop ] if-empty ;
+
+M: lookbehind-on flag-action ( dfa-traverser flag -- )
+    drop
+    f >>traverse-forward
+    [ 2 - ] change-current-index
+    lookbehind-counters>> 0 swap push ;
+
+M: lookbehind-off flag-action ( dfa-traverser flag -- )
+    drop
+    t >>traverse-forward
+    dup lookbehind-counters>>
+    [ drop ] [ pop '[ _ + 2 + ] change-current-index drop ] if-empty ;
+
+M: capture-group-on flag-action ( dfa-traverser flag -- )
+    drop
+    [ current-index>> 0 2array ]
+    [ capture-counters>> ] bi push ;
+
+M: capture-group-off flag-action ( dfa-traverser flag -- )
+    drop
+    dup capture-counters>> empty? [
+        drop
+    ] [
+        {
+            [ capture-counters>> pop first2 dupd + ]
+            [ text>> <slice> ]
+            [ [ 1+ ] change-capture-group-index capture-group-index>> ]
+            [ captured-groups>> set-at ]
+        } cleave
+    ] if ;
+
+: process-flags ( dfa-traverser -- )
+    [ [ 1+ ] map ] change-lookahead-counters
+    [ [ 1+ ] map ] change-lookbehind-counters
+    [ [ first2 1+ 2array ] map ] change-capture-counters
+    ! dup current-state>> .
+    dup [ current-state>> ] [ traversal-flags>> ] bi
+    at [ dup . flag-action ] with each ;
+
+: increment-state ( dfa-traverser state -- dfa-traverser )
+    [
+        dup traverse-forward>>
+        [ 1+ ] [ 1- ] ? change-current-index
+        dup current-state>> >>last-state
+    ] dip
+    first >>current-state ;
+
+: match-failed ( dfa-traverser -- dfa-traverser )
+    V{ } clone >>matches ;
+
+: match-literal ( transition from-state table -- to-state/f )
+    transitions>> at* [ at ] [ 2drop f ] if ;
+
+: match-class ( transition from-state table -- to-state/f )
+    transitions>> at* [
+        [ drop class-member? ] assoc-with assoc-find [ nip ] [ drop ] if
+    ] [ drop ] if ;
+
+: match-default ( transition from-state table -- to-state/f )
+    [ nip ] dip transitions>> at*
+    [ t swap at* [ ] [ drop f ] if ] [ drop f ] if ;
+
+: match-transition ( obj from-state dfa -- to-state/f )
+    { [ match-literal ] [ match-class ] [ match-default ] } 3|| ;
+
+: setup-match ( match -- obj state dfa-table )
+    {
+        [ current-index>> ] [ text>> ]
+        [ current-state>> ] [ dfa-table>> ]
+    } cleave
+    [ nth ] 2dip ;
+
+: do-match ( dfa-traverser -- dfa-traverser )
+    dup process-flags
+    dup match-done? [
+        dup setup-match match-transition
+        [ increment-state do-match ] when*
+    ] unless ;
+
+: return-match ( dfa-traverser -- interval/f )
+    dup matches>>
+    [ drop f ]
+    [ [ start-index>> ] [ peek ] bi* 1 <range> ] if-empty ;
diff --git a/basis/regexp/utils/utils.factor b/basis/regexp/utils/utils.factor
new file mode 100644 (file)
index 0000000..fb058ec
--- /dev/null
@@ -0,0 +1,83 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs io kernel math math.order
+namespaces regexp.backend sequences unicode.categories
+math.ranges fry combinators.short-circuit vectors ;
+IN: regexp.utils
+
+: (while-changes) ( obj quot pred pred-ret -- obj )
+    ! quot: ( obj -- obj' )
+    ! pred: ( obj -- <=> )
+    [ [ dup slip ] dip pick over call ] dip dupd =
+    [ 3drop ] [ (while-changes) ] if ; inline recursive
+
+: while-changes ( obj quot pred -- obj' )
+    pick over call (while-changes) ; inline
+
+: assoc-with ( param assoc quot -- assoc curry )
+    swapd [ [ -rot ] dip call ] 2curry ; inline
+
+: insert-at ( value key hash -- )
+    2dup at* [
+        2nip push
+    ] [
+        drop
+        [ dup vector? [ 1vector ] unless ] 2dip set-at
+    ] if ;
+
+: ?insert-at ( value key hash/f -- hash )
+    [ H{ } clone ] unless* [ insert-at ] keep ;
+
+: last-state ( regexp -- range ) stack>> peek first2 [a,b] ;
+: push1 ( obj -- ) input-stream get stream>> push ;
+: peek1 ( -- obj ) input-stream get stream>> [ f ] [ peek ] if-empty ;
+: pop3 ( seq -- obj1 obj2 obj3 ) [ pop ] [ pop ] [ pop ] tri spin ;
+: drop1 ( -- ) read1 drop ;
+
+: stack ( -- obj ) current-regexp get stack>> ;
+: change-whole-stack ( quot -- )
+    current-regexp get
+    [ stack>> swap call ] keep (>>stack) ; inline
+: push-stack ( obj -- ) stack push ;
+: pop-stack ( -- obj ) stack pop ;
+: cut-out ( vector n -- vector' vector ) cut rest ;
+ERROR: cut-stack-error ;
+: cut-stack ( obj vector -- vector' vector )
+    tuck last-index [ cut-stack-error ] unless* cut-out swap ;
+
+ERROR: bad-octal number ;
+ERROR: bad-hex number ;
+: check-octal ( octal -- octal ) dup 255 > [ bad-octal ] when ;
+: check-hex ( hex -- hex ) dup number? [ bad-hex ] unless ;
+
+: ascii? ( n -- ? ) 0 HEX: 7f between? ;
+: octal-digit? ( n -- ? ) CHAR: 0 CHAR: 7 between? ;
+: decimal-digit? ( n -- ? ) CHAR: 0 CHAR: 9 between? ;
+
+: hex-digit? ( n -- ? )
+    [
+        [ decimal-digit? ]
+        [ CHAR: a CHAR: f between? ]
+        [ CHAR: A CHAR: F between? ]
+    ] 1|| ;
+
+: control-char? ( n -- ? )
+    [
+        [ 0 HEX: 1f between? ]
+        [ HEX: 7f = ]
+    ] 1|| ;
+
+: punct? ( n -- ? )
+    "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" member? ;
+
+: c-identifier-char? ( ch -- ? )
+    [ [ alpha? ] [ CHAR: _ = ] ] 1|| ;
+
+: java-blank? ( n -- ? )
+    {
+        CHAR: \s CHAR: \t CHAR: \n
+        HEX: b HEX: 7 CHAR: \r
+    } member? ;
+
+: java-printable? ( n -- ? )
+    [ [ alpha? ] [ punct? ] ] 1|| ;
index e859e082ff65cb7c244858954c31104221b6b367..c1c2d1c1f8f151a9884c2ec5e673097966c00e51 100644 (file)
@@ -41,7 +41,7 @@ HELP: send-email
     }
 } ;
 
-ARTICLE: "smtp" "SMTP Client Library"
+ARTICLE: "smtp" "SMTP client library"
 "Configuring SMTP:"
 { $subsection smtp-server }
 { $subsection smtp-read-timeout }
index 3d92aea3e831d9d1d6b5fdb82f064d054cdaad61..bab6c17c85e93151037cf61ba272643e3f2e6615 100644 (file)
@@ -72,8 +72,8 @@ TUPLE: effect-error word inferred declared ;
 M: effect-error error.
     "Stack effects of the word " write
     [ word>> pprint " do not match." print ]
-    [ "Inferred: " write inferred>> effect>string . ]
-    [ "Declared: " write declared>> effect>string . ] tri ;
+    [ "Inferred: " write inferred>> . ]
+    [ "Declared: " write declared>> . ] tri ;
 
 TUPLE: recursive-quotation-error quot ;
 
index 41c7e2c9729f74655eb9ebe0c074bd371e121252..abc3ae1950962550730774b2e392585e25c4181c 100755 (executable)
@@ -96,7 +96,7 @@ IN: stack-checker.transforms
 \ boa [
     dup tuple-class? [
         dup inlined-dependency depends-on
-        [ "boa-check" word-prop ]
+        [ "boa-check" word-prop [ ] or ]
         [ tuple-layout '[ _ <tuple-boa> ] ]
         bi append
     ] [ drop f ] if
diff --git a/basis/summary/authors.txt b/basis/summary/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
index 4dfbd16ed49e2aa52bc8d6ffc85e33d218d227bf..7822857bbbd7740e4338cf7c04d9876a4a1752b5 100644 (file)
@@ -1,12 +1,13 @@
 IN: summary
 USING: kernel strings help.markup help.syntax ;
 
-ARTICLE: "summary" "Summary"
+ARTICLE: "summary" "Converting objects to summary strings"
 "A word for getting very brief descriptions of words and general objects:"
 { $subsection summary } ;
 
 HELP: summary
 { $values { "object" object } { "string" string } }
-{ $contract "Outputs a brief description of the object." } ;
+{ $contract "Outputs a brief description of the object." }
+{ $notes "New methods can be defined by user code. Most often, this is used with error classes so that " { $link "debugger" } " can print friendlier error messages." } ;
 
 ABOUT: "summary"
diff --git a/basis/summary/summary.txt b/basis/summary/summary.txt
new file mode 100644 (file)
index 0000000..0229413
--- /dev/null
@@ -0,0 +1 @@
+Generic word for converting an object into a brief one-line string
diff --git a/basis/symbols/summary.txt b/basis/symbols/summary.txt
new file mode 100644 (file)
index 0000000..3093468
--- /dev/null
@@ -0,0 +1 @@
+Utility for defining multiple symbols at a time
diff --git a/basis/symbols/tags.txt b/basis/symbols/tags.txt
new file mode 100644 (file)
index 0000000..f427429
--- /dev/null
@@ -0,0 +1 @@
+extensions
diff --git a/basis/syndication/readme.txt b/basis/syndication/readme.txt
deleted file mode 100644 (file)
index 2e64b0d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-This library is a simple RSS2 parser and RSS reader web
-application. To run the web application you'll need to make sure you
-have the sqlite library working. This can be tested with
-
-  "contrib/sqlite" require
-  "contrib/sqlite" test-module
-
-Remember that to use "sqlite" you need to have done the following
-somewhere:
-
-  USE: alien
-  "sqlite" "/usr/lib/libsqlite3.so" "cdecl" add-library
-
-Replacing "libsqlite3.so" with the path to the sqlite shared library
-or DLL. I put this in my ~/.factor-rc.
-
-The RSS reader web application creates a database file called
-'rss-reader.db' in the same directory as the Factor executable when
-first started. This database contains all the feed information.
-
-To load the web application use:
-
-  "contrib/rss" require
-
-Fire up the web server and navigate to the URL:
-
-  http://localhost:8888/responder/maintain-feeds
-
-Add any RSS2 compatible feed. Use 'Update Feeds' to retrieve them and
-update the sqlite database with the feed contains. Use 'Database' to
-view the entries from the database for that feed.
-
diff --git a/basis/syndication/syndication-docs.factor b/basis/syndication/syndication-docs.factor
new file mode 100644 (file)
index 0000000..5604a94
--- /dev/null
@@ -0,0 +1,68 @@
+USING: help.markup help.syntax io.streams.string strings urls
+calendar xml.data xml.writer present ;
+IN: syndication
+
+HELP: entry
+{ $description "An Atom or RSS feed entry. Has the following slots:"
+    { $table
+        { "Name" "Class" }
+        { "title" { $link string } }
+        { "url" { "any class supported by " { $link present } } }
+        { "description" { $link string } }
+        { "date" { $link timestamp } }
+    }
+} ;
+
+HELP: <entry>
+{ $values { "entry" entry } }
+{ $description "Creates a new entry." } ;
+
+HELP: feed
+{ $description "An Atom or RSS feed. Has the following slots:"
+    { $table
+        { "Name" "Class" }
+        { "title" { $link string } }
+        { "url" { "any class supported by " { $link present } } }
+        { "entries" { "a sequence of " { $link entry } " instances" } }
+    }
+} ;
+
+HELP: <feed>
+{ $values { "feed" feed } }
+{ $description "Creates a new feed." } ;
+
+HELP: download-feed
+{ $values { "url" url } { "feed" feed } }
+{ $description "Downloads a feed from a URL using the " { $link "http.client" } "." } ;
+
+HELP: string>feed
+{ $values { "string" string } { "feed" feed } }
+{ $description "Parses a feed in string form." } ;
+
+HELP: xml>feed
+{ $values { "xml" xml } { "feed" feed } }
+{ $description "Parses a feed in XML form." } ;
+
+HELP: feed>xml
+{ $values { "feed" feed } { "xml" xml } }
+{ $description "Converts a feed to Atom XML form." }
+{ $notes "The result of this word can then be passed to " { $link write-xml } ", or stored in an HTTP response object." } ;
+
+ARTICLE: "syndication" "Atom and RSS feed syndication"
+"The " { $vocab-link "syndication" } " vocabulary implements support for reading Atom and RSS feeds, and writing Atom feeds."
+$nl
+"Data types:"
+{ $subsection feed }
+{ $subsection <feed> }
+{ $subsection entry }
+{ $subsection <entry> }
+"Reading feeds:"
+{ $subsection download-feed }
+{ $subsection string>feed }
+{ $subsection xml>feed }
+"Writing feeds:"
+{ $subsection feed>xml }
+"The " { $vocab-link "furnace.syndication" } " vocabulary builds on top of this vocabulary to enable easy generation of Atom feeds from web applications. The " { $vocab-link "webapps.planet" } " vocabulary is a complete example of a web application which reads and exports feeds."
+{ $see-also "urls" } ;
+
+ABOUT: "syndication"
index eb2095203cad728ea4b8d624eb90e5fd0cbc34c1..1ddcbf809050653d1c561283d96b24730efac437 100755 (executable)
@@ -8,7 +8,7 @@ IN: syndication.tests
 : load-news-file ( filename -- feed )
     #! Load an news syndication file and process it, returning
     #! it as an feed tuple.
-    utf8 file-contents read-feed ;
+    utf8 file-contents string>feed ;
 
 [ T{
     feed
index a432d8c31c92a4cb9d1dbea726ca0cd771c73beb..aca09b939c4e374d89d3cb02f711c968906ae5d8 100644 (file)
@@ -69,11 +69,15 @@ TUPLE: entry title url description date ;
     [ "item" tags-named [ rss2.0-entry ] map set-entries ]
     tri ;
 
+: atom-entry-link ( tag -- url/f )
+    "link" tags-named [ "rel" swap at "alternate" = ] find nip
+    dup [ "href" swap at >url ] when ;
+
 : atom1.0-entry ( tag -- entry )
     entry new
     swap {
         [ "title" tag-named children>string >>title ]
-        [ "link" tag-named "href" swap at >url >>url ]
+        [ atom-entry-link >>url ]
         [
             { "content" "summary" } any-tag-named
             dup children>> [ string? not ] contains?
@@ -102,12 +106,12 @@ TUPLE: entry title url description date ;
         { "feed" [ atom1.0 ] }
     } case ;
 
-: read-feed ( string -- feed )
+: string>feed ( string -- feed )
     [ string>xml xml>feed ] with-html-entities ;
 
 : download-feed ( url -- feed )
     #! Retrieve an news syndication file, return as a feed tuple.
-    http-get nip read-feed ;
+    http-get nip string>feed ;
 
 ! Atom generation
 : simple-tag, ( content name -- )
index 324adcaad20ea055f385a526ce071242abce9122..cb899f4b872fd2256b95d5cafab2b6ff5037c715 100755 (executable)
@@ -18,12 +18,8 @@ IN: tools.deploy.backend
 : image-name ( vocab bundle-name -- str )
   prepend-path ".image" append ;
 
-: (copy-lines) ( stream -- )
-    dup stream-readln dup
-    [ print flush (copy-lines) ] [ 2drop ] if ;
-
-: copy-lines ( stream -- )
-    [ (copy-lines) ] with-disposal ;
+: copy-lines ( -- )
+    readln [ print flush copy-lines ] when* ;
 
 : run-with-output ( arguments -- )
     <process>
@@ -31,9 +27,7 @@ IN: tools.deploy.backend
         +stdout+ >>stderr
         +closed+ >>stdin
         +low-priority+ >>priority
-    utf8 <process-reader*>
-    copy-lines
-    wait-for-process zero? [ "Deployment failed" throw ] unless ;
+    utf8 [ copy-lines ] with-process-reader ;
 
 : make-boot-image ( -- )
     #! If stage1 image doesn't exist, create one.
index acee098b8ff53a22c56cfca37956644fe2d0b72d..1d5b59bf0cf2312d204334c28e2ead00b5830207 100755 (executable)
@@ -43,6 +43,11 @@ namespaces continuations layouts accessors ;
 \r
 [ t ] [ 2500000 small-enough? ] unit-test\r
 \r
+: run-temp-image ( -- )\r
+    vm\r
+    "-i=" "test.image" temp-file append\r
+    2array try-process ;\r
+\r
 {\r
     "tools.deploy.test.1"\r
     "tools.deploy.test.2"\r
@@ -51,9 +56,7 @@ namespaces continuations layouts accessors ;
 } [\r
     [ ] swap [\r
         shake-and-bake\r
-        vm\r
-        "-i=" "test.image" temp-file append\r
-        2array try-process\r
+        run-temp-image\r
     ] curry unit-test\r
 ] each\r
 \r
@@ -88,9 +91,12 @@ M: quit-responder call-responder*
 \r
 [ ] [\r
     "tools.deploy.test.5" shake-and-bake\r
-    vm\r
-    "-i=" "test.image" temp-file append\r
-    2array try-process\r
+    run-temp-image\r
 ] unit-test\r
 \r
 [ ] [ "http://localhost:1237/quit" http-get 2drop ] unit-test\r
+\r
+[ ] [\r
+    "tools.deploy.test.6" shake-and-bake\r
+    run-temp-image\r
+] unit-test\r
index f2726c00fa21ad104fa5e81a686ace8d1988dbb4..f8b0862c9dbc33ccbdcf545b95650c93d0eeb42f 100755 (executable)
@@ -4,7 +4,7 @@ USING: accessors qualified io.streams.c init fry namespaces make
 assocs kernel parser lexer strings.parser tools.deploy.config
 vocabs sequences words words.private memory kernel.private
 continuations io prettyprint vocabs.loader debugger system
-strings sets vectors quotations byte-arrays ;
+strings sets vectors quotations byte-arrays sorting ;
 QUALIFIED: bootstrap.stage2
 QUALIFIED: classes
 QUALIFIED: command-line
@@ -29,6 +29,7 @@ IN: tools.deploy.shaker
     "cpu.x86" init-hooks get delete-at
     "command-line" init-hooks get delete-at
     "libc" init-hooks get delete-at
+    "system" init-hooks get delete-at
     deploy-threads? get [
         "threads" init-hooks get delete-at
     ] unless
@@ -36,7 +37,12 @@ IN: tools.deploy.shaker
         "io.thread" init-hooks get delete-at
     ] unless
     strip-io? [
+        "io.files" init-hooks get delete-at
         "io.backend" init-hooks get delete-at
+    ] when
+    strip-dictionary? [
+        "compiler.units" init-hooks get delete-at
+        "tools.vocabs" init-hooks get delete-at
     ] when ;
 
 : strip-debugger ( -- )
@@ -74,30 +80,50 @@ IN: tools.deploy.shaker
 : strip-word-props ( stripped-props words -- )
     "Stripping word properties" show
     [
-        [
-            props>> swap
-            '[ drop _ member? not ] assoc-filter sift-assoc
-            dup assoc-empty? [ drop f ] [ >alist >vector ] if
-        ] keep (>>props)
-    ] with each ;
+        swap '[
+            [
+                [ drop _ member? not ] assoc-filter sift-assoc
+                >alist f like
+            ] change-props drop
+        ] each
+    ] [
+        "Remaining word properties:" print
+        [ props>> keys ] gather .
+    ] [
+        H{ } clone '[
+            [ [ _ [ ] cache ] map ] change-props drop
+        ] each
+    ] tri ;
 
 : stripped-word-props ( -- seq )
     [
+        strip-dictionary? deploy-compiler? get and [
+            {
+                "combination"
+                "members"
+                "methods"
+            } %
+        ] when
+
         strip-dictionary? [
             {
+                "alias"
+                "boa-check"
                 "cannot-infer"
                 "coercer"
-                "combination"
                 "compiled-effect"
                 "compiled-generic-uses"
                 "compiled-uses"
                 "constraints"
+                "custom-inlining"
                 "declared-effect"
                 "default"
                 "default-method"
                 "default-output-classes"
                 "derived-from"
                 "engines"
+                "forgotten"
+                "identities"
                 "if-intrinsics"
                 "infer"
                 "inferred-effect"
@@ -114,11 +140,11 @@ IN: tools.deploy.shaker
                 "local-writer?"
                 "local?"
                 "macro"
-                "members"
                 "memo-quot"
+                "mixin"
                 "method-class"
                 "method-generic"
-                "methods"
+                "modular-arithmetic"
                 "no-compile"
                 "optimizer-hooks"
                 "outputs"
@@ -126,9 +152,12 @@ IN: tools.deploy.shaker
                 "predicate"
                 "predicate-definition"
                 "predicating"
+                "primitive"
                 "reader"
                 "reading"
                 "recursive"
+                "register"
+                "register-size"
                 "shuffle"
                 "slot-names"
                 "slots"
@@ -210,9 +239,12 @@ IN: tools.deploy.shaker
             "alarms"
             "tools"
             "io.launcher"
+            "random"
         } strip-vocab-globals %
 
         strip-dictionary? [
+            "libraries" "alien" lookup ,
+
             { } { "cpu" } strip-vocab-globals %
 
             {
@@ -230,6 +262,7 @@ IN: tools.deploy.shaker
                 compiled-generic-crossref
                 compiler.units:recompile-hook
                 compiler.units:update-tuples-hook
+                compiler.units:definition-observers
                 definitions:crossref
                 interactive-vocabs
                 layouts:num-tags
@@ -244,9 +277,12 @@ IN: tools.deploy.shaker
                 vocabs:dictionary
                 vocabs:load-vocab-hook
                 word
+                parser-notes
             } %
 
             { } { "math.partial-dispatch" } strip-vocab-globals %
+            
+            "peg-cache" "peg" lookup ,
         ] when
 
         strip-prettyprint? [
@@ -273,7 +309,7 @@ IN: tools.deploy.shaker
             "ui-error-hook" "ui.gadgets.worlds" lookup ,
         ] when
 
-        "<computer>" "inference.dataflow" lookup [ , ] when*
+        "<value>" "stack-checker.state" lookup [ , ] when*
 
         "windows-messages" "windows.messages" lookup [ , ] when*
 
index de5aee68e20aff79e0a7ef056a24e20a598dfe65..2cf803e2703b26984b156db03b846f4519f4e83d 100755 (executable)
@@ -1,30 +1,50 @@
-USING: cocoa cocoa.messages cocoa.application cocoa.nibs
-assocs namespaces kernel words compiler.units sequences
-ui ui.cocoa ;
+! Copyright (C) 2007, 2008 Slava Pestov
+! See http://factorcode.org/license.txt for BSD license.
+USING: cocoa cocoa.messages cocoa.application cocoa.nibs assocs
+namespaces kernel kernel.private words compiler.units sequences
+ui ui.cocoa init ;
+IN: tools.deploy.shaker.cocoa
+
+: pool ( obj -- obj' ) \ pool get [ ] cache ;
+
+: pool-array ( obj -- obj' ) [ pool ] map pool ;
+
+: pool-keys ( assoc -- assoc' ) [ [ pool-array ] dip ] assoc-map ;
+
+: pool-values ( assoc -- assoc' ) [ pool-array ] assoc-map ;
+
+IN: cocoa.application
+
+: objc-error ( error -- ) die ;
+
+[ [ die ] 19 setenv ] "cocoa.application" add-init-hook
 
 "stop-after-last-window?" get
-global [
-    stop-after-last-window? set
 
-    [ "MiniFactor.nib" load-nib ] cocoa-init-hook set-global
+H{ } clone \ pool [
+    global [
+        stop-after-last-window? set
+
+        [ "MiniFactor.nib" load-nib ] cocoa-init-hook set-global
 
-    ! Only keeps those methods that we actually call
-    sent-messages get super-sent-messages get assoc-union
-    objc-methods [ assoc-intersect ] change
+        ! Only keeps those methods that we actually call
+        sent-messages get super-sent-messages get assoc-union
+        objc-methods [ assoc-intersect pool-values ] change
 
-    sent-messages get
-    super-sent-messages get
-    [ keys [ objc-methods get at dup ] H{ } map>assoc ] bi@
-    super-message-senders [ assoc-intersect ] change
-    message-senders [ assoc-intersect ] change
+        sent-messages get
+        super-sent-messages get
+        [ keys [ objc-methods get at dup ] H{ } map>assoc ] bi@
+        super-message-senders [ assoc-intersect pool-keys ] change
+        message-senders [ assoc-intersect pool-keys ] change
 
-    sent-messages off
-    super-sent-messages off
+        sent-messages off
+        super-sent-messages off
 
-    alien>objc-types off
-    objc>alien-types off
+        alien>objc-types off
+        objc>alien-types off
 
-    ! We need this for strip-stack-traces to work fully
-    { message-senders super-message-senders }
-    [ get values compile ] each
-] bind
+        ! We need this for strip-stack-traces to work fully
+        { message-senders super-message-senders }
+        [ get values compile ] each
+    ] bind
+] with-variable
diff --git a/basis/tools/deploy/test/6/6.factor b/basis/tools/deploy/test/6/6.factor
new file mode 100644 (file)
index 0000000..da64bb6
--- /dev/null
@@ -0,0 +1,13 @@
+IN: tools.deploy.test.6
+USING: values math kernel ;
+
+VALUE: x
+
+VALUE: y
+
+: deploy-test-6 ( -- )
+    1 to: x
+    2 to: y
+    x y + 3 assert= ;
+
+MAIN: deploy-test-6
diff --git a/basis/tools/deploy/test/6/deploy.factor b/basis/tools/deploy/test/6/deploy.factor
new file mode 100644 (file)
index 0000000..410bb77
--- /dev/null
@@ -0,0 +1,15 @@
+USING: tools.deploy.config ;
+H{
+    { deploy-threads? f }
+    { deploy-ui? f }
+    { deploy-io 1 }
+    { deploy-c-types? f }
+    { deploy-name "tools.deploy.test.6" }
+    { deploy-compiler? t }
+    { deploy-reflection 1 }
+    { deploy-word-props? f }
+    { deploy-word-defs? f }
+    { "stop-after-last-window?" t }
+    { deploy-random? f }
+    { deploy-math? f }
+}
index 12f9a55795f859a3c65ebfbe3ad1aa393f06ab9f..d8d35ebf31837cb7a64e939d5f30152e1ae02f78 100644 (file)
@@ -4,7 +4,7 @@ USING: assocs io.files hashtables kernel namespaces sequences
 vocabs.loader io combinators io.encodings.utf8 calendar accessors
 math.parser io.streams.string ui.tools.operations quotations
 strings arrays prettyprint words vocabs sorting sets
-classes math alien ;
+classes math alien urls splitting ascii ;
 IN: tools.scaffold
 
 SYMBOL: developer-name
@@ -89,17 +89,12 @@ ERROR: no-vocab vocab ;
     ] if ;
 
 : lookup-type ( string -- object/string ? )
+    "new" ?head drop [ [ CHAR: ' = ] [ digit? ] bi or ] trim-right
     H{
         { "object" object } { "obj" object }
-        { "obj1" object } { "obj2" object }
-        { "obj3" object } { "obj4" object }
-        { "quot" quotation } { "quot1" quotation }
-        { "quot2" quotation } { "quot3" quotation }
-        { "quot'" quotation }
-        { "string" string } { "string1" string }
-        { "string2" string } { "string3" string }
+        { "quot" quotation }
+        { "string" string }
         { "str" string }
-        { "str1" string } { "str2" string } { "str3" string }
         { "hash" hashtable }
         { "hashtable" hashtable }
         { "?" "a boolean" }
@@ -111,15 +106,12 @@ ERROR: no-vocab vocab ;
         { "vocab" "a vocabulary specifier" }
         { "vocab-root" "a vocabulary root string" }
         { "c-ptr" c-ptr }
-        { "seq" sequence } { "seq1" sequence } { "seq2" sequence }
-        { "seq3" sequence } { "seq4" sequence }
-        { "seq1'" sequence } { "seq2'" sequence }
-        { "newseq" sequence } 
-        { "assoc" assoc } { "assoc1" assoc } { "assoc2" assoc }
-        { "assoc3" assoc } { "newassoc" assoc }
+        { "seq" sequence }
+        { "assoc" assoc }
         { "alist" "an array of key/value pairs" }
         { "keys" sequence } { "values" sequence }
         { "class" class } { "tuple" tuple }
+        { "url" url }
     } at* ;
 
 : add-using ( object -- )
@@ -170,7 +162,7 @@ ERROR: no-vocab vocab ;
 : interesting-words. ( vocab -- )
     interesting-words [ (help.) nl ] each ;
 
-: help-file-string ( str1 -- str2 )
+: help-file-string ( vocab -- str2 )
     [
         {
             [ "IN: " write print nl ]
@@ -184,16 +176,18 @@ ERROR: no-vocab vocab ;
         } cleave
     ] with-string-writer ;
 
-: write-using ( -- )
+: write-using ( vocab -- )
     "USING:" write
     using get keys
-    { "help.markup" "help.syntax" } append natural-sort 
+    { "help.markup" "help.syntax" } append natural-sort remove
     [ bl write ] each
     " ;" print ;
 
 : set-scaffold-help-file ( path vocab -- )
     swap utf8 <file-writer> [
-        scaffold-copyright help-file-string write-using write
+        scaffold-copyright
+        [ help-file-string ] [ write-using ] bi
+        write
     ] with-output-stream ;
 
 : check-scaffold ( vocab-root string -- vocab-root string )
index 161677b56a51f56ed0dc7ba7b7cdf59912544767..da0ff35728ce1df6986d2966c524037fc933b677 100755 (executable)
@@ -16,15 +16,15 @@ M: book model-changed ( model book -- )
     relayout ;
 
 : new-book ( pages model class -- book )
-  new-gadget
-    swap >>model
-    swap add-gadgets ; inline
+    new-gadget
+        swap >>model
+        swap add-gadgets ; inline
 
 : <book> ( pages model -- book ) book new-book ;
 
 M: book pref-dim* ( book -- dim ) children>> pref-dims max-dim ;
 
 M: book layout* ( book -- )
-   [ dim>> ] [ children>> ] bi [ (>>dim) ] with each ;
+    [ children>> ] [ dim>> ] bi [ >>dim drop ] curry each ;
 
 M: book focusable-child* ( book -- child/t ) current-page ;
index 4609562af4abd4512efbae4c1c38eced45fde3f3..94816788e1b4c8f287e689541f3578ab24cbd9bd 100644 (file)
@@ -10,7 +10,7 @@ TUPLE: border < gadget
 { align initial: { 1/2 1/2 } } ;
 
 : new-border ( child class -- border )
-    new-gadget [ swap add-gadget drop ] keep ; inline
+    new-gadget swap add-gadget ; inline
 
 : <border> ( child gap -- border )
     swap border new-border
@@ -42,7 +42,8 @@ M: border pref-dim*
 M: border layout*
     dup border-child-rect swap gadget-child
     over loc>> >>loc
-    swap dim>> swap (>>dim) ;
+    swap dim>> >>dim
+    drop ;
 
 M: border focusable-child*
     gadget-child ;
index e04e385a239d88a43c788122a8ac4e053266e9af..4ad9e1487434e6b3a6a7bf6e20fde2901c891559 100755 (executable)
@@ -25,7 +25,7 @@ TUPLE: button < border pressed? selected? quot ;
     dup mouse-clicked?
     over button-rollover? and
     buttons-down? and
-    over (>>pressed?)
+    >>pressed?
     relayout-1 ;
 
 : if-clicked ( button quot -- )
@@ -115,20 +115,18 @@ M: checkmark-paint draw-interior
         dup { 0 1 } v* swap { 1 0 } v* gl-line
     ] with-translation ;
 
-: checkmark-theme ( gadget -- )
+: checkmark-theme ( gadget -- gadget )
     f
     f
     black <solid>
     black <checkmark-paint>
-    <button-paint>
-    over (>>interior)
-    black <solid>
-    swap (>>boundary) ;
+    <button-paint> >>interior
+    black <solid> >>boundary ;
 
 : <checkmark> ( -- gadget )
     <gadget>
-    dup checkmark-theme
-    { 14 14 } over (>>dim) ;
+    checkmark-theme
+    { 14 14 } >>dim ;
 
 : toggle-model ( model -- )
     [ not ] change-model ;
@@ -148,7 +146,7 @@ TUPLE: checkbox < button ;
         align-left ;
 
 M: checkbox model-changed
-    swap value>> over (>>selected?) relayout-1 ;
+    swap value>> >>selected? relayout-1 ;
 
 TUPLE: radio-paint color ;
 
@@ -162,20 +160,18 @@ M: radio-paint draw-boundary
     color>> set-color
     origin get { 1 1 } v+ swap rect-dim { 2 2 } v- 12 gl-circle ;
 
-: radio-knob-theme ( gadget -- )
+: radio-knob-theme ( gadget -- gadget )
     f
     f
     black <radio-paint>
     black <radio-paint>
-    <button-paint>
-    over (>>interior)
-    black <radio-paint>
-    swap (>>boundary) ;
+    <button-paint> >>interior
+    black <radio-paint> >>boundary ;
 
 : <radio-knob> ( -- gadget )
     <gadget>
-    dup radio-knob-theme
-    { 16 16 } over (>>dim) ;
+    radio-knob-theme
+    { 16 16 } >>dim ;
 
 TUPLE: radio-control < button value ;
 
@@ -188,13 +184,12 @@ TUPLE: radio-control < button value ;
 
 M: radio-control model-changed
     swap value>>
-    over value>> =
-    over (>>selected?)
+    over value>> = >>selected?
     relayout-1 ;
 
 : <radio-controls> ( parent model assoc quot -- parent )
-  #! quot has stack effect ( value model label -- )
-  swapd [ swapd call add-gadget ] 2curry assoc-each ; inline
+    #! quot has stack effect ( value model label -- )
+    swapd [ swapd call add-gadget ] 2curry assoc-each ; inline
 
 : radio-button-theme ( gadget -- gadget )
     { 5 5 } >>gap
@@ -204,18 +199,18 @@ M: radio-control model-changed
     <radio-knob> label-on-right radio-button-theme <radio-control> ;
 
 : <radio-buttons> ( model assoc -- gadget )
-  <filled-pile>
-    -rot
-    [ <radio-button> ] <radio-controls>
-  { 5 5 } >>gap ;
+    <filled-pile>
+        -rot
+        [ <radio-button> ] <radio-controls>
+        { 5 5 } >>gap ;
 
 : <toggle-button> ( value model label -- gadget )
     <radio-control> bevel-button-theme ;
 
 : <toggle-buttons> ( model assoc -- gadget )
-  <shelf>
-    -rot
-    [ <toggle-button> ] <radio-controls> ;
+    <shelf>
+        -rot
+        [ <toggle-button> ] <radio-controls> ;
 
 : command-button-quot ( target command -- quot )
     [ invoke-command drop ] 2curry ;
@@ -227,7 +222,7 @@ M: radio-control model-changed
     <bevel-button> ;
 
 : <toolbar> ( target -- toolbar )
-  <shelf>
-    swap
-    "toolbar" over class command-map commands>> swap
-    [ -rot <command-button> add-gadget ] curry assoc-each ;
+    <shelf>
+        swap
+        "toolbar" over class command-map commands>> swap
+        [ -rot <command-button> add-gadget ] curry assoc-each ;
index 888716b364b95c9efbd98daed989263dab386d14..a1026ef35a02b84a567be2c6eb6d3608317cfc47 100755 (executable)
@@ -96,9 +96,9 @@ M: editor ungraft*
 : click-loc ( editor model -- )
     >r clicked-loc r> set-model ;
 
-: focus-editor ( editor -- ) t over (>>focused?) relayout-1 ;
+: focus-editor ( editor -- ) t >>focused? relayout-1 ;
 
-: unfocus-editor ( editor -- ) f over (>>focused?) relayout-1 ;
+: unfocus-editor ( editor -- ) f >>focused? relayout-1 ;
 
 : (offset>x) ( font col# str -- x )
     swap head-slice string-width ;
index a1602effe99abb622599b23b710eb394e991d9ab..877d4ad145ee0a1a29ed8ad83d3cbb33837c78e5 100755 (executable)
@@ -9,9 +9,9 @@ IN: ui.gadgets.tests
     ! c contains b contains a
     <gadget> "a" set
     <gadget> "b" set
-    "a" get "b" get swap add-gadget drop
+    "b" get "a" get add-gadget drop
     <gadget> "c" set
-    "b" get "c" get swap add-gadget drop
+    "c" get "b" get add-gadget drop
 
     ! position a and b
     "a" get { 100 200 } >>loc drop
@@ -33,8 +33,8 @@ IN: ui.gadgets.tests
 <gadget> "g3" set
 "g3" get { 100 200 } >>dim drop
 
-"g1" get "g2" get swap add-gadget drop
-"g2" get "g3" get swap add-gadget drop
+"g2" get "g1" get add-gadget drop
+"g3" get "g2" get add-gadget drop
 
 [ { 30 30 } ] [ "g1" get screen-loc ] unit-test
 [ { 30 30 } ] [ "g1" get screen-rect rect-loc ] unit-test
@@ -49,11 +49,11 @@ IN: ui.gadgets.tests
 <gadget> "g1" set
 "g1" get { 300 300 } >>dim drop
 <gadget> "g2" set
-"g2" get "g1" get swap add-gadget drop
+"g1" get "g2" get add-gadget drop
 "g2" get { 20 20 } >>loc
          { 20 20 } >>dim drop
 <gadget> "g3" set
-"g3" get "g1" get swap add-gadget drop
+"g1" get "g3" get add-gadget drop
 "g3" get { 100 100 } >>loc
          { 20 20 } >>dim drop
 
@@ -66,7 +66,7 @@ IN: ui.gadgets.tests
 [ t ] [ { 110 110 } "g1" get pick-up "g3" get eq? ] unit-test
 
 <gadget> "g4" set
-"g4" get "g2" get swap add-gadget drop
+"g2" get "g4" get add-gadget drop
 "g4" get { 5 5 } >>loc
          { 1 1 } >>dim drop
 
@@ -121,7 +121,7 @@ M: mock-gadget ungraft*
     : add-some-children
         3 [
             <mock-gadget> over <model> >>model
-            dup "g" get swap add-gadget drop
+            "g" get over add-gadget drop
             swap 1+ number>string set
         ] each ;
 
index 05764d5b84899c48d791802f1368b7400e1e9cd4..a18571d472e8eb9152618ca4143b352de4f93e54 100755 (executable)
@@ -27,10 +27,10 @@ M: gadget model-changed 2drop ;
 : nth-gadget ( n gadget -- child ) children>> nth ;
 
 : init-gadget ( gadget -- gadget )
-  init-rect
-  { 0 1 } >>orientation
-  t       >>visible?
-  { f f } >>graft-state ; inline
+    init-rect
+    { 0 1 } >>orientation
+    t >>visible?
+    { f f } >>graft-state ; inline
 
 : new-gadget ( class -- gadget ) new init-gadget ; inline
 
@@ -132,9 +132,9 @@ M: array gadget-text*
 : gadget-text ( gadget -- string ) [ gadget-text* ] "" make ;
 
 : invalidate ( gadget -- )
-    \ invalidate swap (>>layout-state) ;
+    \ invalidate >>layout-state drop ;
 
-: forget-pref-dim ( gadget -- ) f swap (>>pref-dim) ;
+: forget-pref-dim ( gadget -- ) f >>pref-dim drop ;
 
 : layout-queue ( -- queue ) \ layout-queue get ;
 
@@ -147,7 +147,7 @@ M: array gadget-text*
 DEFER: relayout
 
 : invalidate* ( gadget -- )
-    \ invalidate* over (>>layout-state)
+    \ invalidate* >>layout-state
     dup forget-pref-dim
     dup root?>>
     [ layout-later ] [ parent>> [ relayout ] when* ] if ;
@@ -160,20 +160,19 @@ DEFER: relayout
     dup layout-state>>
     [ drop ] [ dup invalidate layout-later ] if ;
 
-: show-gadget ( gadget -- ) t swap (>>visible?) ;
-
-: hide-gadget ( gadget -- ) f swap (>>visible?) ;
+: show-gadget ( gadget -- ) t >>visible? drop ;
+                              
+: hide-gadget ( gadget -- ) f >>visible? drop ;
 
 DEFER: in-layout?
 
-: do-invalidate ( gadget -- gadget )
-  in-layout? get [ dup invalidate ] [ dup invalidate* ] if ;
+GENERIC: dim-changed ( gadget -- )
+
+M: gadget dim-changed
+    in-layout? get [ invalidate ] [ invalidate* ] if ;
 
 M: gadget (>>dim) ( dim gadget -- )
-   2dup dim>> =
-     [ 2drop ]
-     [ tuck call-next-method do-invalidate drop ]
-   if ;
+    2dup dim>> = [ 2drop ] [ tuck call-next-method dim-changed ] if ;
 
 GENERIC: pref-dim* ( gadget -- dim )
 
@@ -194,9 +193,9 @@ GENERIC: layout* ( gadget -- )
 
 M: gadget layout* drop ;
 
-: prefer ( gadget -- ) dup pref-dim swap (>>dim) ;
+: prefer ( gadget -- ) dup pref-dim >>dim drop ;
 
-: validate ( gadget -- ) f swap (>>layout-state) ;
+: validate ( gadget -- ) f >>layout-state drop ;
 
 : layout ( gadget -- )
     dup layout-state>> [
@@ -255,11 +254,10 @@ M: gadget ungraft* drop ;
 : (unparent) ( gadget -- )
     dup ungraft
     dup forget-pref-dim
-    f swap (>>parent) ;
+    f >>parent drop ;
 
 : unfocus-gadget ( child gadget -- )
-    tuck focus>> eq?
-    [ f swap (>>focus) ] [ drop ] if ;
+    tuck focus>> eq? [ f >>focus ] when drop ;
 
 SYMBOL: in-layout?
 
@@ -282,8 +280,7 @@ SYMBOL: in-layout?
 
 : (clear-gadget) ( gadget -- )
     dup [ (unparent) ] each-child
-    f over (>>focus)
-    f swap (>>children) ;
+    f >>focus f >>children drop ;
 
 : clear-gadget ( gadget -- )
     not-in-layout
@@ -305,7 +302,7 @@ SYMBOL: in-layout?
     not-in-layout
     (add-gadget)
     dup relayout ;
-  
+
 : add-gadgets ( parent children -- parent )
     not-in-layout
     [ (add-gadget) ] each
index f14ccf1cca395614a8d63eddb93fd07f73d035eb..3e91e0ceb6614d11a13fef42d9a64d7598e52860 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays kernel math namespaces make sequences words io
 io.streams.string math.vectors ui.gadgets columns accessors
-math.geometry.rect ;
+math.geometry.rect locals ;
 IN: ui.gadgets.grids
 
 TUPLE: grid < gadget
@@ -12,18 +12,18 @@ grid
 
 : new-grid ( children class -- grid )
     new-gadget
-    [ (>>grid) ] [ >r concat r> swap add-gadgets drop ] [ nip ] 2tri ;
-    inline
+        swap >>grid
+        dup grid>> concat add-gadgets ; inline
 
 : <grid> ( children -- grid )
     grid new-grid ;
 
 : grid-child ( grid i j -- gadget ) rot grid>> nth nth ;
 
-: grid-add ( grid child i j -- grid )
-  >r >r dupd swap r> r>
-  >r >r 2dup swap add-gadget drop r> r>
-  3dup grid-child unparent rot grid>> nth set-nth ;
+:: grid-add ( grid child i j -- grid )
+    grid i j grid-child unparent
+    grid child add-gadget
+    child i j grid grid>> nth set-nth ;
 
 : grid-remove ( grid i j -- grid ) <gadget> -rot grid-add ;
 
@@ -33,10 +33,10 @@ grid
 : (compute-grid) ( grid -- seq ) [ max-dim ] map ;
 
 : compute-grid ( grid -- horiz vert )
-    pref-dim-grid dup flip (compute-grid) swap (compute-grid) ;
+    pref-dim-grid [ flip (compute-grid) ] [ (compute-grid) ] bi ;
 
 : (pair-up) ( horiz vert -- dim )
-    >r first r> second 2array ;
+    [ first ] [ second ] bi* 2array ;
 
 : pair-up ( horiz vert -- dims )
     [ [ (pair-up) ] curry map ] with map ;
index 28c28be3a733b608b05a40414b9ee0b5964782df..930d5ed5021a315cbb495506886b375351b3b157 100755 (executable)
@@ -8,7 +8,7 @@ $nl
 $nl
 "Children are managed with the " { $link add-incremental } " and " { $link clear-incremental } " words."
 $nl
-"Not every " { $link pack } " can use incremental layout, since incremental layout does not support non-default values for " { $snippet "align" } ", " { $snippet "fill" } ", and " { $snippet "gap" } "." } ;
+"Not every " { $link pack } " can use incremental layout, since incremental layout does not support non-default values for the " { $slot "align" } ", " { $slot "fill" } ", and " { $slot "gap" } " slots." } ;
 
 HELP: <incremental>
 { $values { "incremental" "a new instance of " { $link incremental } } }
index 4d67080775eb81f8064197c423d68f9d45615e7b..af249bbdc8c040ef74a412cf70c264e91f34fa4d 100755 (executable)
@@ -4,17 +4,6 @@ USING: io kernel math namespaces math.vectors ui.gadgets
 ui.gadgets.packs accessors math.geometry.rect ;
 IN: ui.gadgets.incremental
 
-! Incremental layout allows adding lines to panes to be O(1).
-! Note that incremental packs are distinct from ordinary packs
-! defined in layouts.factor, since you don't want all packs to
-! be incremental. In particular, incremental packs do not
-! support non-default values for pack-align, pack-fill and
-! pack-gap.
-
-! The cursor is the current size of the incremental pack.
-! New gadgets are added at
-!   incremental-cursor gadget-orientation v*
-
 TUPLE: incremental < pack cursor ;
 
 : <incremental> ( -- incremental )
@@ -24,38 +13,42 @@ TUPLE: incremental < pack cursor ;
 
 M: incremental pref-dim*
     dup layout-state>> [
-        dup call-next-method over (>>cursor)
+        dup call-next-method >>cursor
     ] when cursor>> ;
 
 : next-cursor ( gadget incremental -- cursor )
     [
-        swap rect-dim swap cursor>>
-        2dup v+ >r vmax r>
+        [ rect-dim ] [ cursor>> ] bi*
+        [ vmax ] [ v+ ] 2bi
     ] keep orientation>> set-axis ;
 
 : update-cursor ( gadget incremental -- )
-    [ next-cursor ] keep (>>cursor) ;
+    tuck next-cursor >>cursor drop ;
 
 : incremental-loc ( gadget incremental -- )
     [ cursor>> ] [ orientation>> ] bi v*
     >>loc drop ;
 
-: prefer-incremental ( gadget -- )
+: prefer-incremental ( gadget -- ) USE: slots.private
     dup forget-pref-dim dup pref-dim >>dim drop ;
 
+M: incremental dim-changed drop ;
+
 : add-incremental ( gadget incremental -- )
     not-in-layout
     2dup swap (add-gadget) drop
-    over prefer-incremental
-    over layout-later
-    2dup incremental-loc
-    tuck update-cursor
-    dup prefer-incremental
-    parent>> [ invalidate* ] when* ;
+    t in-layout? [
+        over prefer-incremental
+        over layout-later
+        2dup incremental-loc
+        tuck update-cursor
+        dup prefer-incremental
+        parent>> [ invalidate* ] when*
+    ] with-variable ;
 
 : clear-incremental ( incremental -- )
     not-in-layout
     dup (clear-gadget)
     dup forget-pref-dim
-    { 0 0 } over (>>cursor)
+    { 0 0 } >>cursor
     parent>> [ relayout ] when* ;
index 64020c76263dd764347ced5b906f7f2687a99e33..8cf13c83675084e5496382416f8693cbb7a8b760 100755 (executable)
@@ -11,10 +11,10 @@ IN: ui.gadgets.labelled
 TUPLE: labelled-gadget < track content ;
 
 : <labelled-gadget> ( gadget title -- newgadget )
-  { 0 1 } labelled-gadget new-track
-    swap <label> reverse-video-theme f track-add
-    swap >>content
-    dup content>> 1 track-add ;
+    { 0 1 } labelled-gadget new-track
+        swap <label> reverse-video-theme f track-add
+        swap >>content
+        dup content>> 1 track-add ;
 
 M: labelled-gadget focusable-child* content>> ;
 
@@ -22,25 +22,25 @@ M: labelled-gadget focusable-child* content>> ;
     >r <scroller> r> <labelled-gadget> ;
 
 : <labelled-pane> ( model quot scrolls? title -- gadget )
-    >r >r <pane-control> r> over (>>scrolls?) r>
+    >r >r <pane-control> r> >>scrolls? r>
     <labelled-scroller> ;
 
 : <close-box> ( quot -- button/f )
     gray close-box <polygon-gadget> swap <bevel-button> ;
 
-: title-theme ( gadget -- )
-    { 1 0 } over (>>orientation)
+: title-theme ( gadget -- gadget )
+    { 1 0 } >>orientation
     T{ gradient f {
         T{ rgba f 0.65 0.65 1.0 1.0 }
         T{ rgba f 0.65 0.45 1.0 1.0 }
-    } } swap (>>interior) ;
+    } } >>interior ;
 
-: <title-label> ( text -- label ) <label> dup title-theme ;
+: <title-label> ( text -- label ) <label> title-theme ;
 
 : <title-bar> ( title quot -- gadget )
-  <frame>
-    swap dup [ <close-box> @left grid-add ] [ drop ] if
-    swap <title-label> @center grid-add ;
+    <frame>
+        swap dup [ <close-box> @left grid-add ] [ drop ] if
+        swap <title-label> @center grid-add ;
 
 TUPLE: closable-gadget < frame content ;
 
@@ -48,9 +48,9 @@ TUPLE: closable-gadget < frame content ;
     [ closable-gadget? ] find-parent ;
 
 : <closable-gadget> ( gadget title quot -- gadget )
-  closable-gadget new-frame
-    -rot <title-bar> @top grid-add
-    swap >>content
-    dup content>> @center grid-add ;
+    closable-gadget new-frame
+        -rot <title-bar> @top grid-add
+        swap >>content
+        dup content>> @center grid-add ;
     
 M: closable-gadget focusable-child* content>> ;
index f27b9898a125b88a67e1919ef211011e629f1922..6c38b6183d8b78e895343bc219e46431b3cec14f 100755 (executable)
@@ -63,11 +63,11 @@ M: object >label ;
 M: f >label drop <gadget> ;
 
 : label-on-left ( gadget label -- button )
-  { 1 0 } <track>
-    swap >label f track-add
-    swap        1 track-add ;
-    
+    { 1 0 } <track>
+        swap >label f track-add
+        swap 1 track-add ;
+
 : label-on-right ( label gadget -- button )
-  { 1 0 } <track>
-    swap        f track-add
-    swap >label 1 track-add ;
+    { 1 0 } <track>
+        swap f track-add
+        swap >label 1 track-add ;
index 67c0ccc496b58c513c6999bac25ceb5930a38da4..62e5b7d780abae8d23e1da5b420c040e0acff751 100755 (executable)
@@ -27,8 +27,7 @@ TUPLE: list < pack index presenter color hook ;
     control-value length 1- min 0 max ;
 
 : bound-index ( list -- )
-    dup index>> over calc-bounded-index
-    swap (>>index) ;
+    dup index>> over calc-bounded-index >>index drop ;
 
 : list-presentation-hook ( list -- quot )
     hook>> [ [ list? ] find-parent ] prepend ;
@@ -49,7 +48,7 @@ TUPLE: list < pack index presenter color hook ;
 M: list model-changed
     nip
     dup clear-gadget
-    dup <list-items> over swap add-gadgets drop
+    dup <list-items> add-gadgets
     bound-index ;
 
 : selected-rect ( list -- rect )
@@ -79,8 +78,8 @@ M: list focusable-child* drop t ;
         2drop
     ] [
         [ control-value length rem ] keep
-        [ (>>index) ] keep
-        [ relayout-1 ] keep
+        swap >>index
+        dup relayout-1
         scroll>selected
     ] if ;
 
index 26e405f6dbe8400725b4aa868439bd28e4883cff..7dd57e526a4a6cb45c678f18808db467d89a7caf 100644 (file)
@@ -15,19 +15,17 @@ TUPLE: menu-glass < gadget ;
 : <menu-glass> ( menu world -- glass )
     menu-glass new-gadget
     >r over menu-loc >>loc r>
-    [ swap add-gadget drop ] keep ;
+    swap add-gadget ;
 
 M: menu-glass layout* gadget-child prefer ;
 
 : hide-glass ( world -- )
-    dup glass>> [ unparent ] when*
-    f swap (>>glass) ;
+    [ [ unparent ] when* f ] change-glass drop ;
 
 : show-glass ( gadget world -- )
-    over hand-clicked set-global
-    [ hide-glass ] keep
-    [ swap add-gadget drop ] 2keep
-    (>>glass) ;
+    dup hide-glass
+    swap [ hand-clicked set-global ] [ >>glass ] bi
+    dup glass>> add-gadget drop ;
 
 : show-menu ( gadget owner -- )
     find-world [ <menu-glass> ] keep show-glass ;
@@ -48,7 +46,7 @@ M: menu-glass layout* gadget-child prefer ;
     faint-boundary ;
 
 : <commands-menu> ( hook target commands -- gadget )
-  <filled-pile>
-  -roll
-    [ <menu-item> add-gadget ] with with each
-  5 <border> menu-theme ;
+    <filled-pile>
+        -roll
+        [ <menu-item> add-gadget ] with with each
+    5 <border> menu-theme ;
index 207708afdfe01c68414b4c49b5b65d74eefa70fd..32a60374ebcc8d271167c1f728b9431ad735d0f7 100755 (executable)
@@ -5,9 +5,9 @@ math.vectors namespaces math.order accessors math.geometry.rect ;
 IN: ui.gadgets.packs
 
 TUPLE: pack < gadget
-  { align initial: 0       }
-  { fill  initial: 0       }
-  { gap   initial: { 0 0 } } ;
+    { align initial: 0 }
+    { fill  initial: 0 }
+    { gap   initial: { 0 0 } } ;
 
 : packed-dim-2 ( gadget sizes -- list )
     [ over rect-dim over v- rot fill>> v*n v+ ] with map ;
@@ -40,7 +40,7 @@ TUPLE: pack < gadget
 
 : <pile> ( -- pack ) { 0 1 } <pack> ;
 
-: <filled-pile> ( -- pack ) <pile> 1 over (>>fill) ;
+: <filled-pile> ( -- pack ) <pile> 1 >>fill ;
 
 : <shelf> ( -- pack ) { 1 0 } <pack> ;
 
index 7f00084104366f64b0cde9dbe767a01c6e447e9c..f100a72f0646d81839601d384d5e9b265284a4cf 100755 (executable)
@@ -1,45 +1,51 @@
 ! Copyright (C) 2005, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays ui.gadgets ui.gadgets.borders ui.gadgets.buttons
-       ui.gadgets.labels ui.gadgets.scrollers
-       ui.gadgets.paragraphs ui.gadgets.incremental ui.gadgets.packs
-       ui.gadgets.theme ui.clipboards ui.gestures ui.traverse ui.render
-       hashtables io kernel namespaces sequences io.styles strings
-       quotations math opengl combinators math.vectors
-       sorting splitting io.streams.nested assocs
-       ui.gadgets.presentations ui.gadgets.slots ui.gadgets.grids
-       ui.gadgets.grid-lines classes.tuple models continuations
-       destructors accessors math.geometry.rect ;
+ui.gadgets.labels ui.gadgets.scrollers ui.gadgets.paragraphs
+ui.gadgets.incremental ui.gadgets.packs ui.gadgets.theme
+ui.clipboards ui.gestures ui.traverse ui.render hashtables io
+kernel namespaces sequences io.styles strings quotations math
+opengl combinators math.vectors sorting splitting
+io.streams.nested assocs ui.gadgets.presentations
+ui.gadgets.slots ui.gadgets.grids ui.gadgets.grid-lines
+classes.tuple models continuations destructors accessors
+math.geometry.rect ;
 
 IN: ui.gadgets.panes
 
 TUPLE: pane < pack
-       output current prototype scrolls?
-       selection-color caret mark selecting? ;
+output current prototype scrolls?
+selection-color caret mark selecting? ;
 
-: clear-selection ( pane -- pane ) f >>caret f >>mark ;
+: clear-selection ( pane -- pane )
+    f >>caret f >>mark ;
 
-: add-output  ( pane current -- pane ) [ >>output  ] [ add-gadget ] bi ;
-: add-current ( pane current -- pane ) [ >>current ] [ add-gadget ] bi ;
+: add-output  ( pane current -- pane )
+    [ >>output  ] [ add-gadget ] bi ;
+
+: add-current ( pane current -- pane )
+    [ >>current ] [ add-gadget ] bi ;
 
 : prepare-line ( pane -- pane )
-  clear-selection
-  dup prototype>> clone add-current ;
+    clear-selection
+    dup prototype>> clone add-current ;
 
-: pane-caret&mark ( pane -- caret mark ) [ caret>> ] [ mark>> ] bi ;
+: pane-caret&mark ( pane -- caret mark )
+    [ caret>> ] [ mark>> ] bi ;
 
 : selected-children ( pane -- seq )
     [ pane-caret&mark sort-pair ] keep gadget-subtree ;
 
 M: pane gadget-selection? pane-caret&mark and ;
 
-M: pane gadget-selection ( pane -- string/f ) selected-children gadget-text ;
+M: pane gadget-selection ( pane -- string/f )
+    selected-children gadget-text ;
 
 : pane-clear ( pane -- )
-  clear-selection
-  [ output>> clear-incremental ]
-  [ current>> clear-gadget ]
-  bi ;
+    clear-selection
+    [ output>> clear-incremental ]
+    [ current>> clear-gadget ]
+    bi ;
 
 : new-pane ( class -- pane )
     new-gadget
@@ -109,7 +115,7 @@ C: <pane-stream> pane-stream
 GENERIC: write-gadget ( gadget stream -- )
 
 M: pane-stream write-gadget ( gadget pane-stream -- )
-   pane>> current>> swap add-gadget drop ;
+    pane>> current>> swap add-gadget drop ;
 
 M: style-stream write-gadget
     stream>> write-gadget ;
@@ -132,12 +138,12 @@ M: style-stream write-gadget
 : make-pane ( quot -- gadget )
     <pane> [ swap with-pane ] keep smash-pane ; inline
 
-: <scrolling-pane> ( -- pane ) <pane> t over (>>scrolls?) ;
+: <scrolling-pane> ( -- pane ) <pane> t >>scrolls? ;
 
 TUPLE: pane-control < pane quot ;
 
 M: pane-control model-changed ( model pane-control -- )
-   [ value>> ] [ dup quot>> ] bi* with-pane ;
+    [ value>> ] [ dup quot>> ] bi* with-pane ;
 
 : <pane-control> ( model quot -- pane )
     pane-control new-pane
@@ -172,7 +178,7 @@ M: pane-stream make-span-stream
     >r pick at r> when* ; inline
 
 : apply-foreground-style ( style gadget -- style gadget )
-    foreground [ over (>>color) ] apply-style ;
+    foreground [ >>color ] apply-style ;
 
 : apply-background-style ( style gadget -- style gadget )
     background [ solid-interior ] apply-style ;
@@ -183,7 +189,7 @@ M: pane-stream make-span-stream
     font-size swap at 12 or 3array ;
 
 : apply-font-style ( style gadget -- style gadget )
-    over specified-font over (>>font) ;
+    over specified-font >>font ;
 
 : apply-presentation-style ( style gadget -- style gadget )
     presented [ <presentation> ] apply-style ;
@@ -254,15 +260,15 @@ M: pane-stream make-block-stream
 
 ! Tables
 : apply-table-gap-style ( style grid -- style grid )
-    table-gap [ over (>>gap) ] apply-style ;
+    table-gap [ >>gap ] apply-style ;
 
 : apply-table-border-style ( style grid -- style grid )
-    table-border [ <grid-lines> over (>>boundary) ]
+    table-border [ <grid-lines> >>boundary ]
     apply-style ;
 
 : styled-grid ( style grid -- grid )
     <grid>
-    f over (>>fill?)
+    f >>fill?
     apply-table-gap-style
     apply-table-border-style
     nip ;
@@ -286,13 +292,13 @@ M: pack dispose drop ;
 M: paragraph dispose drop ;
 
 : gadget-write ( string gadget -- )
-    over empty?
-    [ 2drop ] [ >r <label> text-theme r> swap add-gadget drop ] if ;
+    swap dup empty?
+    [ 2drop ] [ <label> text-theme add-gadget drop ] if ;
 
 M: pack stream-write gadget-write ;
 
 : gadget-bl ( style stream -- )
-    >r " " <word-break-gadget> style-label r> swap add-gadget drop ;
+    swap " " <word-break-gadget> style-label add-gadget drop ;
 
 M: paragraph stream-write
     swap " " split
@@ -309,8 +315,8 @@ M: paragraph stream-write1
     [ H{ } swap gadget-bl drop ] [ gadget-write1 ] if ;
 
 : gadget-format ( string style stream -- )
-    pick empty?
-    [ 3drop ] [ >r swap <styled-label> r> swap add-gadget drop ] if ;
+    spin dup empty?
+    [ 3drop ] [ <styled-label> add-gadget drop ] if ;
 
 M: pack stream-format
     gadget-format ;
@@ -326,13 +332,13 @@ M: paragraph stream-format
     ] if ;
 
 : caret>mark ( pane -- pane )
-  dup caret>> >>mark
-  dup relayout-1 ;
+    dup caret>> >>mark
+    dup relayout-1 ;
 
 GENERIC: sloppy-pick-up* ( loc gadget -- n )
 
 M: pack sloppy-pick-up* ( loc gadget -- n )
-   [ orientation>> ] [ children>> ] bi (fast-children-on) ;
+    [ orientation>> ] [ children>> ] bi (fast-children-on) ;
 
 M: gadget sloppy-pick-up*
     children>> [ inside? ] with find-last drop ;
@@ -350,12 +356,10 @@ M: f sloppy-pick-up*
     if ;
 
 : move-caret ( pane -- pane )
-  dup hand-rel
-  over sloppy-pick-up
-  over (>>caret)
-  dup relayout-1 ;
+    dup hand-rel over sloppy-pick-up >>caret
+    dup relayout-1 ;
 
-: begin-selection ( pane -- ) move-caret f swap (>>mark) ;
+: begin-selection ( pane -- ) move-caret f >>mark drop ;
 
 : extend-selection ( pane -- )
     hand-moved? [
index fed1fb97f10f27faa1cd61c3073eaba53204ba9c..216f21af27bbf4981aec5a4ba9ec57f7602e1aca 100644 (file)
@@ -17,8 +17,8 @@ TUPLE: paragraph < gadget margin ;
 
 : <paragraph> ( margin -- gadget )
     paragraph new-gadget
-    { 1 0 } over (>>orientation)
-    [ (>>margin) ] keep ;
+    { 1 0 } >>orientation
+    swap >>margin ;
 
 SYMBOL: x SYMBOL: max-x
 
index 48251c49273685094ea9c35dd42f56bfa6e1c9c8..625bfd7880a8a65b25b1f74502483e28b5330a33 100755 (executable)
@@ -61,7 +61,7 @@ IN: ui.gadgets.scrollers.tests
 
 <gadget> { 600 400 } >>dim "g1" set
 <gadget> { 600 10 } >>dim "g2" set
-"g2" get "g1" get swap add-gadget drop
+"g1" get "g2" get add-gadget drop
 
 "g1" get <scroller>
 { 300 300 } >>dim
index 70e56fc31c07c1fd33be63b0d24d34f492dabe26..fefce8a04099e5a3fe282349ca27f8c1af36ee98 100755 (executable)
@@ -33,17 +33,17 @@ scroller H{
     0 0 0 0 <range> 0 0 0 0 <range> 2array <compose> ;
 
 : new-scroller ( gadget class -- scroller )
-  new-frame
-    t >>root?
-    <scroller-model> >>model
-    faint-boundary
+    new-frame
+        t >>root?
+        <scroller-model> >>model
+        faint-boundary
 
-    dup model>> dependencies>> first  <x-slider> >>x dup x>> @bottom grid-add
-    dup model>> dependencies>> second <y-slider> >>y dup y>> @right  grid-add
+        dup model>> dependencies>> first  <x-slider> >>x dup x>> @bottom grid-add
+        dup model>> dependencies>> second <y-slider> >>y dup y>> @right  grid-add
+
+        swap over model>> <viewport> >>viewport
+        dup viewport>> @center grid-add ;
 
-    swap over model>> <viewport> >>viewport
-    dup viewport>> @center grid-add ;
-    
 : <scroller> ( gadget -- scroller ) scroller new-scroller ;
 
 : scroll ( value scroller -- )
@@ -81,7 +81,7 @@ scroller H{
 : scroll>rect ( rect gadget -- )
     dup find-scroller* dup [
         [ relative-scroll-rect ] keep
-        [ (>>follows) ] keep
+        swap >>follows
         relayout
     ] [
         3drop
@@ -94,7 +94,7 @@ scroller H{
 
 : scroll>gadget ( gadget -- )
     dup find-scroller* dup [
-        [ (>>follows) ] keep
+        swap >>follows
         relayout
     ] [
         2drop
@@ -104,9 +104,7 @@ scroller H{
     dup viewport>> viewport-dim { 0 1 } v* swap scroll ;
 
 : scroll>bottom ( gadget -- )
-    find-scroller [
-        t over (>>follows) relayout-1
-    ] when* ;
+    find-scroller [ t >>follows relayout-1 ] when* ;
 
 : scroll>top ( gadget -- )
     <zero-rect> swap scroll>rect ;
@@ -124,14 +122,14 @@ M: f update-scroller drop dup scroller-value swap scroll ;
 M: scroller layout*
     dup call-next-method
     dup follows>>
-    [ update-scroller ] 2keep
-    swap (>>follows) ;
+    2dup update-scroller
+    >>follows drop ;
 
 M: scroller focusable-child*
     viewport>> ;
 
 M: scroller model-changed
-    nip f swap (>>follows) ;
+    nip f >>follows drop ;
 
 TUPLE: limited-scroller < scroller fixed-dim ;
 
index 8d673e66adb3986c7204890e79cc0e78d525f0c0..f42d65f738f7be6c9a15083c85d359af121e19eb 100755 (executable)
@@ -46,7 +46,7 @@ M: slider model-changed nip elevator>> relayout-1 ;
 TUPLE: thumb < gadget ;
 
 : begin-drag ( thumb -- )
-    find-slider dup slider-value swap (>>saved) ;
+    find-slider dup slider-value >>saved drop ;
 
 : do-drag ( thumb -- )
     find-slider drag-loc over orientation>> v.
@@ -83,7 +83,7 @@ thumb H{
     dup direction>> swap find-slider slide-by-page ;
 
 : elevator-click ( elevator -- )
-    dup compute-direction over (>>direction)
+    dup compute-direction >>direction
     elevator-hold ;
 
 elevator H{
@@ -123,13 +123,13 @@ M: elevator layout*
 : <slide-button> ( vector polygon amount -- button )
     >r gray swap <polygon-gadget> r>
     [ swap find-slider slide-by-line ] curry <repeat-button>
-    [ (>>orientation) ] keep ;
+    swap >>orientation ;
 
 : elevator, ( gadget orientation -- gadget )
-  tuck <elevator> >>elevator
-  swap <thumb>    >>thumb
-  dup elevator>> over thumb>> add-gadget
-  @center grid-add ;
+    tuck <elevator> >>elevator
+    swap <thumb>    >>thumb
+    dup elevator>> over thumb>> add-gadget
+    @center grid-add ;
 
 : <left-button>  ( -- button ) { 0 1 } arrow-left -1 <slide-button> ;
 : <right-button> ( -- button ) { 0 1 } arrow-right 1 <slide-button> ;
@@ -143,16 +143,16 @@ M: elevator layout*
         32 >>line ;
 
 : <x-slider> ( range -- slider )
-  { 1 0 } <slider>
-    <left-button> @left grid-add
-    { 0 1 } elevator,
-    <right-button> @right grid-add ;
+    { 1 0 } <slider>
+        <left-button> @left grid-add
+        { 0 1 } elevator,
+        <right-button> @right grid-add ;
 
 : <y-slider> ( range -- slider )
-  { 0 1 } <slider>
-    <up-button> @top grid-add
-    { 1 0 } elevator,
-    <down-button> @bottom grid-add ;
+    { 0 1 } <slider>
+        <up-button> @top grid-add
+        { 1 0 } elevator,
+        <down-button> @bottom grid-add ;
 
 M: slider pref-dim*
     dup call-next-method
index b111caa1791e1989535bd0692570b0bedffc1fc0..1cf23e2d061bcb93a5e111b1f84ad14a6f5ca155 100755 (executable)
@@ -69,12 +69,12 @@ M: value-ref finish-editing
 } define-command
 
 : <slot-editor> ( ref -- gadget )
-  { 0 1 } slot-editor new-track
-    swap >>ref
-    dup <toolbar> f track-add
-    <source-editor> >>text
-    dup text>> <scroller> 1 track-add
-    dup revert ;
+    { 0 1 } slot-editor new-track
+        swap >>ref
+        dup <toolbar> f track-add
+        <source-editor> >>text
+        dup text>> <scroller> 1 track-add
+        dup revert ;
     
 M: slot-editor pref-dim* call-next-method { 600 200 } vmin ;
 
index 6feaf52b475e2973d3b0bfafd9b79aac7c1c8199..93f2d145282fe25f7bd651cccaf3a093702badb0 100644 (file)
@@ -3,14 +3,14 @@ USING: kernel ui.gadgets ui.gadgets.tracks tools.test
 IN: ui.gadgets.tracks.tests
 
 [ { 100 100 } ] [
-  { 0 1 } <track>
-    <gadget> { 100 100 } >>dim 1 track-add
-  pref-dim
+    { 0 1 } <track>
+        <gadget> { 100 100 } >>dim 1 track-add
+    pref-dim    
 ] unit-test
 
 [ { 100 110 } ] [
-  { 0 1 } <track>
-    <gadget> { 10 10 }   >>dim f track-add
-    <gadget> { 100 100 } >>dim 1 track-add
-  pref-dim
+    { 0 1 } <track>
+        <gadget> { 10 10 } >>dim f track-add
+        <gadget> { 100 100 } >>dim 1 track-add
+    pref-dim
 ] unit-test
index 029bc5447cc0b712bdba49a0a400396b34793949..5a9683ceff80f83ccd399cf021fa08961e6f1e63 100644 (file)
@@ -9,23 +9,23 @@ IN: ui.gadgets.tracks
 TUPLE: track < pack sizes ;
 
 : normalized-sizes ( track -- seq )
-  sizes>> dup sift sum '[ dup [ _ / ] when ] map ;
+    sizes>> dup sift sum '[ dup [ _ / ] when ] map ;
 
 : init-track ( track -- track )
-  init-gadget
-  V{ } clone >>sizes
-  1          >>fill ;
+    init-gadget
+    V{ } clone >>sizes
+    1 >>fill ;
 
 : new-track ( orientation class -- track )
-  new
-    init-track
-    swap >>orientation ;
+    new
+        init-track
+        swap >>orientation ;
 
 : <track> ( orientation -- track ) track new-track ;
 
 : alloted-dim ( track -- dim )
-  [ children>> ] [ sizes>> ] bi { 0 0 }
-  [ [ drop { 0 0 } ] [ pref-dim ] if v+ ] 2reduce ;
+    [ children>> ] [ sizes>> ] bi { 0 0 }
+    [ [ drop { 0 0 } ] [ pref-dim ] if v+ ] 2reduce ;
 
 : available-dim ( track -- dim ) [ dim>> ] [ alloted-dim ] bi v- ;
 
@@ -38,29 +38,26 @@ M: track layout* ( track -- ) dup track-layout pack-layout ;
 : track-pref-dims-1 ( track -- dim ) children>> pref-dims max-dim ;
 
 : track-pref-dims-2 ( track -- dim )
-  [ children>> pref-dims ] [ normalized-sizes ] bi
-  [ [ v/n ] when* ] 2map
-  max-dim
-  [ >fixnum ] map ;
+    [ children>> pref-dims ] [ normalized-sizes ] bi
+    [ [ v/n ] when* ] 2map
+    max-dim
+    [ >fixnum ] map ;
 
 M: track pref-dim* ( gadget -- dim )
-   [ track-pref-dims-1                           ]
-   [ [ alloted-dim ] [ track-pref-dims-2 ] bi v+ ]
-   [ orientation>>                               ]
-   tri
-   set-axis ;
+    [ track-pref-dims-1 ]
+    [ [ alloted-dim ] [ track-pref-dims-2 ] bi v+ ]
+    [ orientation>> ]
+    tri
+    set-axis ;
 
 : track-add ( track gadget constraint -- track )
-  pick sizes>> push add-gadget ;
+    pick sizes>> push add-gadget ;
 
 : track-remove ( track gadget -- track )
-  dupd dup
-    [
-      [ swap children>> index ]
-      [ unparent sizes>>      ] 2bi
-      delete-nth 
-    ]
-    [ 2drop ]
-  if ;
+    dupd dup [
+        [ swap children>> index ]
+        [ unparent sizes>> ] 2bi
+        delete-nth 
+    ] [ 2drop ] if ;
 
 : clear-track ( track -- ) V{ } clone >>sizes clear-gadget ;
index c6e4b044cd04c01c482079893478eba83fa52300..5f714a526b222845c7715532a4c830f4d231fece 100755 (executable)
@@ -18,7 +18,7 @@ TUPLE: viewport < gadget ;
     viewport new-gadget
         swap >>model
         t >>clipped?
-        [ swap add-gadget drop ] keep ;
+        swap add-gadget ;
 
 M: viewport layout*
     dup rect-dim viewport-gap 2 v*n v-
index dbaaa33a5146de75e0262aea044fd2850bd6cfcf..34ddc1776751143b262f8f88ae501b5e515acadd 100644 (file)
@@ -18,7 +18,7 @@ IN: ui.gadgets.worlds.tests
 
 <gadget> "g1" set
 <gadget> "g2" set
-"g1" get "g2" get swap add-gadget drop
+"g2" get "g1" get add-gadget drop
 
 [ ] [
     "g2" get <test-world> "w" set
@@ -33,8 +33,8 @@ IN: ui.gadgets.worlds.tests
 <gadget> "g1" set
 <gadget> "g2" set
 <gadget> "g3" set
-"g1" get "g3" get swap add-gadget drop
-"g2" get "g3" get swap add-gadget drop
+"g3" get "g1" get add-gadget drop
+"g3" get "g2" get add-gadget drop
 
 [ ] [
     "g3" get <test-world> "w" set
@@ -55,7 +55,7 @@ TUPLE: focus-test < gadget ;
 
 : <focus-test>
     focus-test new-gadget
-    <focusing> over swap add-gadget drop ;
+    dup <focusing> add-gadget drop ;
 
 M: focus-test focusable-child* gadget-child ;
 
index cedd03e39e256d731edca728592c5209c8619e1d..1bdc63ed0ef2ccfeebffea00da5c2d71a624c99a 100755 (executable)
@@ -89,7 +89,7 @@ SYMBOL: ui-error-hook
                 (draw-world)
             ] [
                 over <world-error> ui-error
-                f swap (>>active?)
+                f >>active? drop
             ] recover
         ] with-variable
     ] [
index 3e0b36486eb3cac4fd124aa3ea687255b693d675..8e83f69edbb18ba5304259480cd1ad81fb79f746 100755 (executable)
@@ -19,8 +19,7 @@ TUPLE: operation predicate command translator hook listener? ;
         swap >>predicate ;
 
 PREDICATE: listener-operation < operation
-    dup command>> listener-command?
-    swap listener?>> or ;
+    [ command>> listener-command? ] [ listener?>> ] bi or ;
 
 M: operation command-name
     command>> command-name ;
@@ -59,15 +58,15 @@ SYMBOL: operations
 
 : modify-operation ( hook translator operation -- operation )
     clone
-    tuck (>>translator)
-    tuck (>>hook)
-    t over (>>listener?) ;
+        swap >>translator
+        swap >>hook
+        t >>listener? ;
 
 : modify-operations ( operations hook translator -- operations )
-    rot [ >r 2dup r> modify-operation ] map 2nip ;
+    rot [ modify-operation ] with with map ;
 
 : operations>commands ( object hook translator -- pairs )
-    >r >r object-operations r> r> modify-operations
+    [ object-operations ] 2dip modify-operations
     [ [ operation-gesture ] keep ] { } map>assoc ;
 
 : define-operation-map ( class group blurb object hook translator -- )
index 2147fc2b53a76274da6c013e113331ed67099641..9aacf1c7247afa421c5c8bfacbac84229dc4722e 100644 (file)
@@ -139,7 +139,7 @@ M: polygon draw-interior
 : <polygon-gadget> ( color points -- gadget )
     dup max-dim
     >r <polygon> <gadget> r> >>dim
-    [ (>>interior) ] keep ;
+    swap >>interior ;
 
 ! Font rendering
 SYMBOL: font-renderer
index 33523701aa155d9c5394c5079224462d443a1c29..83a3b7ff68a4f9a393348a2ebf52623c9d2a2365 100755 (executable)
@@ -20,11 +20,11 @@ TUPLE: browser-gadget < track pane history ;
     "handbook" >link <history> >>history drop ;
 
 : <browser-gadget> ( -- gadget )
-  { 0 1 } browser-gadget new-track
-    dup init-history
-    dup <toolbar> f track-add
-    dup <help-pane> >>pane
-    dup pane>> <scroller> 1 track-add ;
+    { 0 1 } browser-gadget new-track
+        dup init-history
+        dup <toolbar> f track-add
+        dup <help-pane> >>pane
+        dup pane>> <scroller> 1 track-add ;
 
 M: browser-gadget call-tool* show-help ;
 
index 285757e390e606d1f745c75d28406a3c82b6f5a0..e6180e9982f099d3040ffe273e835c9bb1b584ad 100755 (executable)
@@ -42,8 +42,8 @@ TUPLE: deploy-gadget < pack vocab settings ;
     deploy-c-types? get "Retain all C types" <checkbox> add-gadget ;
 
 : deploy-settings-theme ( gadget -- gadget )
-  { 10 10 } >>gap
-  1         >>fill ;
+    { 10 10 } >>gap
+    1 >>fill ;
 
 : <deploy-settings> ( vocab -- control )
     default-config [ <model> ] assoc-map
@@ -57,7 +57,7 @@ TUPLE: deploy-gadget < pack vocab settings ;
             advanced-settings
 
             deploy-settings-theme
-            namespace <mapping> over (>>model)
+            namespace <mapping> >>model
         ]
     bind ;
 
index 273d6bc549c9a26f530224849fbbafa85c74f78d..dcb3a3f8adc361e73c828d3ebee4f9af34e46cc2 100644 (file)
@@ -16,11 +16,11 @@ TUPLE: inspector-gadget < track object pane ;
     ] with-pane ;
 
 : <inspector-gadget> ( -- gadget )
-  { 0 1 } inspector-gadget new-track
-    dup <toolbar> f track-add
-    <pane> >>pane
-    dup pane>> <scroller> 1 track-add ;
-    
+    { 0 1 } inspector-gadget new-track
+        dup <toolbar> f track-add
+        <pane> >>pane
+        dup pane>> <scroller> 1 track-add ;
+
 : inspect-object ( obj mirror keys inspector -- )
     2nip swap >>object refresh ;
 
index dff45251d1a3dbe48ce68ddac8924b58c9699535..e86b52c664bd63e8240926c4d276a426a09ca663 100755 (executable)
@@ -15,7 +15,7 @@ IN: ui.tools.listener.tests
     [ "dup" ] [
         \ dup word-completion-string
     ] unit-test
-  
+
     [ "equal?" ]
     [ \ array \ equal? method word-completion-string ] unit-test
 
index 4c20abca8773f7765610921c94da403a1bc91896..6fc6fa4f10293de47429e3023120f08c936b1be2 100755 (executable)
@@ -13,8 +13,8 @@ IN: ui.tools.listener
 TUPLE: listener-gadget < track input output stack ;
 
 : listener-output, ( listener -- listener )
-  <scrolling-pane> >>output
-  dup output>> <scroller> "Output" <labelled-gadget> 1 track-add ;
+    <scrolling-pane> >>output
+    dup output>> <scroller> "Output" <labelled-gadget> 1 track-add ;
 
 : listener-streams ( listener -- input output )
     [ input>> ] [ output>> <pane-stream> ] bi ;
@@ -23,15 +23,15 @@ TUPLE: listener-gadget < track input output stack ;
     output>> <pane-stream> <interactor> ;
 
 : listener-input, ( listener -- listener )
-  dup <listener-input> >>input
-  dup input>>
-    { 0 100 } <limited-scroller>
-    "Input" <labelled-gadget>
-  f track-add ;
+    dup <listener-input> >>input
+    dup input>>
+        { 0 100 } <limited-scroller>
+        "Input" <labelled-gadget>
+    f track-add ;
 
 : welcome. ( -- )
-   "If this is your first time with Factor, please read the " print
-   "handbook" ($link) "." print nl ;
+    "If this is your first time with Factor, please read the " print
+    "handbook" ($link) "." print nl ;
 
 M: listener-gadget focusable-child*
     input>> ;
@@ -121,11 +121,10 @@ M: engine-word word-completion-string
 TUPLE: stack-display < track ;
 
 : <stack-display> ( workspace -- gadget )
-  listener>>
-  { 0 1 } stack-display new-track
+    listener>>
+    { 0 1 } stack-display new-track
     over <toolbar> f track-add
-    swap
-      stack>> [ [ stack. ] curry try ] t "Data stack" <labelled-pane>
+    swap stack>> [ [ stack. ] curry try ] t "Data stack" <labelled-pane>
     1 track-add ;
 
 M: stack-display tool-scroller
@@ -166,14 +165,14 @@ M: stack-display tool-scroller
     } cleave ;
 
 : init-listener ( listener -- )
-    f <model> swap (>>stack) ;
+    f <model> >>stack drop ;
 
 : <listener-gadget> ( -- gadget )
-  { 0 1 } listener-gadget new-track
-    dup init-listener
-    listener-output,
-    listener-input, ;
-    
+    { 0 1 } listener-gadget new-track
+        dup init-listener
+        listener-output,
+        listener-input, ;
+
 : listener-help ( -- ) "ui-listener" help-window ;
 
 \ listener-help H{ { +nullary+ t } } define-command
index 98717fc7bc83a0a5417372ce7226006e5131695a..c60d0dac0981e825e502e09bba5e316e83b3fbbd 100755 (executable)
@@ -8,11 +8,11 @@ IN: ui.tools.profiler
 TUPLE: profiler-gadget < track pane ;
 
 : <profiler-gadget> ( -- gadget )
-  { 0 1 } profiler-gadget new-track
-    dup <toolbar> f track-add
-    <pane> >>pane
-    dup pane>> <scroller> 1 track-add ;
-    
+    { 0 1 } profiler-gadget new-track
+        dup <toolbar> f track-add
+        <pane> >>pane
+        dup pane>> <scroller> 1 track-add ;
+
 : with-profiler-pane ( gadget quot -- )
     >r pane>> r> with-pane ;
 
index dcfb7346b4cb03067adfaffc197a6efa818524b3..d47727452042fc246b067ad993f17d438e4bc061 100755 (executable)
@@ -19,7 +19,7 @@ IN: ui.tools.search.tests
     ] with-grafted-gadget ;
 
 : test-live-search ( gadget quot -- ? )
-   >r update-live-search dup assert-non-empty r> all? ;
+    >r update-live-search dup assert-non-empty r> all? ;
 
 [ t ] [
     "swp" all-words f <definition-search>
index 5237813fe02afc76cfd7a5d54021b4c4e504df09..b88fe8454e8115343799ee7868475a65f068e035 100755 (executable)
@@ -60,15 +60,14 @@ search-field H{
     swap <list> ;
 
 : <live-search> ( string seq limited? presenter -- gadget )
-  { 0 1 } live-search new-track
-    <search-field> >>field
-    dup field>> f track-add
-    -roll <search-list> >>list
-    dup list>> <scroller> 1 track-add
-
-  swap                         
-    over field>> set-editor-string
-  dup field>> end-of-document ;
+    { 0 1 } live-search new-track
+        <search-field> >>field
+        dup field>> f track-add
+        -roll <search-list> >>list
+        dup list>> <scroller> 1 track-add
+    swap                         
+        over field>> set-editor-string
+    dup field>> end-of-document ;
 
 M: live-search focusable-child* field>> ;
 
index b38dd52b6ea79e9f0e911f2f7c0f21e3575b6eab..2265f27cc84c08af08c352b7ec9ab147d4f3b27e 100755 (executable)
@@ -7,7 +7,7 @@ IN: ui.tools.tests
 
 [ f ]
 [
-  <gadget> 0 <model> >>model <workspace-tabs> children>> empty?
+    <gadget> 0 <model> >>model <workspace-tabs> children>> empty?
 ] unit-test
 
 [ ] [ <workspace> "w" set ] unit-test
index 21fa44b5932961734850baf7aa1c8e1e171f9e54..f4205061cd5050345883b4d250e5291b9f75af16 100755 (executable)
@@ -13,35 +13,30 @@ mirrors ;
 IN: ui.tools
 
 : <workspace-tabs> ( workspace -- tabs )
-  model>>
-  "tool-switching" workspace command-map commands>>
-    [ command-string ] { } assoc>map <enum> >alist
-  <toggle-buttons> ;
+    model>>
+        "tool-switching" workspace command-map commands>>
+        [ command-string ] { } assoc>map <enum> >alist
+    <toggle-buttons> ;
 
 : <workspace-book> ( workspace -- gadget )
-
-  dup
-    <stack-display>
-    <browser-gadget>
-    <inspector-gadget>
-    <profiler-gadget>
-  4array
-
-  swap model>>
-
-  <book> ;
+    dup
+        <stack-display>
+        <browser-gadget>
+        <inspector-gadget>
+        <profiler-gadget>
+    4array
+    swap model>> <book> ;
   
 : <workspace> ( -- workspace )
-  { 0 1 } workspace new-track
-
-    0 <model>            >>model
-    <listener-gadget>    >>listener
-    dup <workspace-book> >>book
-    
-    dup <workspace-tabs> f   track-add
-    dup book>>           1/5 track-add
-    dup listener>>       4/5 track-add
-    dup <toolbar>        f   track-add ;
+    { 0 1 } workspace new-track
+        0 <model> >>model
+        <listener-gadget> >>listener
+        dup <workspace-book> >>book
+
+        dup <workspace-tabs> f track-add
+        dup book>> 1/5 track-add
+        dup listener>> 4/5 track-add
+        dup <toolbar> f track-add ;
 
 : resize-workspace ( workspace -- )
     dup sizes>> over control-value zero? [
index 92c5e09a88f085c1845c04dff8aec0cc459e9576..6cb79916e08299698769acb02de5939d1db3c799 100755 (executable)
@@ -25,14 +25,14 @@ TUPLE: traceback-gadget < track ;
 M: traceback-gadget pref-dim* drop { 550 600 } ;
 
 : <traceback-gadget> ( model -- gadget )
-  { 0 1 } traceback-gadget new-track
-    swap >>model
+    { 0 1 } traceback-gadget new-track
+        swap >>model
 
     dup model>>
-      { 1 0 } <track>
-        over <datastack-display>   1/2 track-add
-        swap <retainstack-display> 1/2 track-add
-      1/3 track-add
+        { 1 0 } <track>
+            over <datastack-display> 1/2 track-add
+            swap <retainstack-display> 1/2 track-add
+        1/3 track-add
 
     dup model>> <callstack-display> 2/3 track-add
 
index ab6b3fe1cf08fada0feceb0da539c2e6eaaeac42..bbe4b127128379e5d0fabb10299d1cf648fe17cf 100755 (executable)
@@ -26,7 +26,7 @@ GENERIC: tool-scroller ( tool -- scroller )
 M: gadget tool-scroller drop f ;
 
 : find-tool ( class workspace -- index tool )
-  book>> children>> [ class eq? ] with find ;
+    book>> children>> [ class eq? ] with find ;
 
 : show-tool ( class workspace -- tool )
     [ find-tool swap ] keep book>> model>>
@@ -55,15 +55,15 @@ M: gadget tool-scroller drop f ;
     article-title open-window ;
 
 : hide-popup ( workspace -- )
-  dup popup>> track-remove
-  f >>popup
-  request-focus ;
+    dup popup>> track-remove
+    f >>popup
+    request-focus ;
 
 : show-popup ( gadget workspace -- )
-  dup hide-popup
-  over >>popup
-  over f track-add drop
-  request-focus ;
+    dup hide-popup
+    over >>popup
+    over f track-add drop
+    request-focus ;
 
 : show-titled-popup ( workspace gadget title -- )
     [ find-workspace hide-popup ] <closable-gadget>
index da9e2f0d43eb435adde7fb5dd1e0c7fb5d9a2593..f561f3cd49164828a465c4c35d850f4e5cc3770e 100755 (executable)
@@ -51,12 +51,12 @@ SYMBOL: stop-after-last-window?
     T{ gain-focus } swap each-gesture ;
 
 : focus-world ( world -- )
-    t over (>>focused?)
+    t >>focused?
     dup raised-window
     focus-path f focus-gestures ;
 
 : unfocus-world ( world -- )
-    f over (>>focused?)
+    f >>focused?
     focus-path f swap focus-gestures ;
 
 M: world graft*
@@ -69,7 +69,7 @@ M: world graft*
     #! when restoring saved worlds on image startup.
     dup fonts>> clear-assoc
     dup unfocus-world
-    f swap (>>handle) ;
+    f >>handle drop ;
 
 M: world ungraft*
     dup free-fonts
@@ -93,13 +93,8 @@ SYMBOL: ui-hook
     dup graft-state>> {
         { { f f } [ ] }
         { { f t } [ ] }
-        { { t t } [
-            { f f } over (>>graft-state)
-        ] }
-        { { t f } [
-            dup unqueue-graft
-            { f f } over (>>graft-state)
-        ] }
+        { { t t } [ { f f } >>graft-state ] }
+        { { t f } [ dup unqueue-graft { f f } >>graft-state ] }
     } case graft-later ;
 
 : restore-gadget ( gadget -- )
@@ -172,7 +167,7 @@ SYMBOL: ui-thread
     "UI update" spawn drop ;
 
 : open-world-window ( world -- )
-    dup pref-dim over (>>dim) dup relayout graft ;
+    dup pref-dim >>dim dup relayout graft ;
 
 : open-window ( gadget title -- )
     f <world> open-world-window ;
index 854a0b0c629168678652874345594f560a87b8fc..3122bc536b04ad034b7b9fa3a2f473cdc0ac1bc4 100755 (executable)
@@ -21,8 +21,8 @@ C: <x11-handle> x11-handle
 M: world expose-event nip relayout ;
 
 M: world configure-event
-    over configured-loc over (>>window-loc)
-    swap configured-dim over (>>dim)
+    over configured-loc >>window-loc
+    swap configured-dim >>dim
     ! In case dimensions didn't change
     relayout-1 ;
 
@@ -173,7 +173,7 @@ M: world client-event
     dup window-loc>> over rect-dim glx-window
     over "Factor" create-xic <x11-handle>
     2dup window>> register-window
-    swap (>>handle) ;
+    >>handle drop ;
 
 : wait-event ( -- event )
     QueuedAfterFlush events-queued 0 > [
index 88381ca7d704ad6fd0fb32bb13f0cd58f57e9552..6aa3e606473104000688dcdfbea27d4760cf94a0 100755 (executable)
@@ -98,5 +98,4 @@ VALUE: grapheme-table
 
 init-grapheme-table table
 [ make-grapheme-table finish-table ] with-variable
-\ grapheme-table set-value
-
+to: grapheme-table
index 3ebb474a8195d681bcfc2590ad2b38119f3d3066..8e9e2963a8cea0be9c49e0f2a59025d53914d755 100755 (executable)
@@ -27,7 +27,7 @@ TUPLE: weight primary secondary tertiary ignorable? ;
     [ parse-line ] H{ } map>assoc ;\r
 \r
 "resource:basis/unicode/collation/allkeys.txt"\r
-ascii <file-reader> parse-ducet \ ducet set-value\r
+ascii <file-reader> parse-ducet to: ducet\r
 \r
 ! Fix up table for long contractions\r
 : help-one ( assoc key -- )\r
index 6d6ed276a8848a86d17317af1887308887902b8f..cd54b93f2a258bb1b255647db5c03baf68600c58 100755 (executable)
@@ -164,18 +164,16 @@ C: <code-point> code-point
     [ [ set-code-point ] each ] H{ } make-assoc ;
 
 load-data {
-    [ process-names \ name-map set-value ]
-    [ 13 swap process-data \ simple-lower set-value ]
-    [ 12 swap process-data \ simple-upper set-value ]
-    [ 14 swap process-data
-        simple-upper assoc-union \ simple-title set-value ]
-    [ process-combining \ class-map set-value ]
-    [ process-canonical \ canonical-map set-value
-        \ combine-map set-value ]
-    [ process-compatibility \ compatibility-map set-value ]
-    [ process-category \ category-map set-value ]
+    [ process-names to: name-map ]
+    [ 13 swap process-data to: simple-lower ]
+    [ 12 swap process-data to: simple-upper ]
+    [ 14 swap process-data simple-upper assoc-union to: simple-title ]
+    [ process-combining to: class-map ]
+    [ process-canonical to: canonical-map to: combine-map ]
+    [ process-compatibility to: compatibility-map ]
+    [ process-category to: category-map ]
 } cleave
 
-load-special-casing \ special-casing set-value
+load-special-casing to: special-casing
 
-load-properties \ properties set-value
+load-properties to: properties
index aa9ca843bd17a9853c83b780b8bb1edabe0e3c5a..103beb4d2a0d1c24c5865d15ee94870366f2d506 100755 (executable)
@@ -32,7 +32,7 @@ SYMBOL: interned
 
 : process-script ( ranges -- )
     dup values prune >symbols interned [
-        expand-ranges \ script-table set-value
+        expand-ranges to: script-table
     ] with-variable ;
 
 : load-script ( -- )
diff --git a/basis/urls/encoding/authors.txt b/basis/urls/encoding/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/urls/encoding/encoding-docs.factor b/basis/urls/encoding/encoding-docs.factor
new file mode 100644 (file)
index 0000000..f8b4354
--- /dev/null
@@ -0,0 +1,57 @@
+IN: urls.encoding
+USING: strings help.markup help.syntax assocs multiline ;
+
+HELP: url-decode
+{ $values { "str" string } { "decoded" string } }
+{ $description "Decodes a URL-encoded string." } ;
+
+HELP: url-encode
+{ $values { "str" string } { "encoded" string } }
+{ $description "URL-encodes a string." } ;
+
+HELP: url-quotable?
+{ $values { "ch" "a character" } { "?" "a boolean" } }
+{ $description "Tests if a character be used without URL-encoding in a URL." } ;
+
+HELP: assoc>query
+{ $values { "assoc" assoc } { "str" string } }
+{ $description "Converts an assoc of query parameters into a query string, performing URL encoding." }
+{ $notes "This word is used by the implementation of " { $link "urls" } ". It is also used by the HTTP client to encode POST requests." }
+{ $examples
+    { $example
+        "USING: io urls.encoding ;"
+        "{ { \"from\" \"Lead\" } { \"to\" \"Gold, please\" } }"
+        "assoc>query print"
+        "from=Lead&to=Gold%2c%20please"
+    }
+} ;
+
+HELP: query>assoc
+{ $values { "query" string } { "assoc" assoc } }
+{ $description "Parses a URL query string and URL-decodes each component." }
+{ $notes "This word is used by the implementation of " { $link "urls" } ". It is also used by the HTTP server to parse POST requests." }
+{ $examples
+    { $unchecked-example
+        "USING: prettyprint urls.encoding ;"
+        "\"gender=female&agefrom=22&ageto=28&location=Omaha+NE\""
+        "query>assoc ."
+        <" H{
+    { "gender" "female" }
+    { "agefrom" "22" }
+    { "ageto" "28" }
+    { "location" "Omaha NE" }
+}">
+    }
+} ;
+
+ARTICLE: "url-encoding" "URL encoding and decoding"
+"URL encoding and decoding strings:"
+{ $subsection url-encode }
+{ $subsection url-decode }
+{ $subsection url-quotable? }
+"Encoding and decoding queries:"
+{ $subsection assoc>query }
+{ $subsection query>assoc }
+"See " { $url "http://en.wikipedia.org/wiki/Percent-encoding" } " for a description of URL encoding." ;
+
+ABOUT: "url-encoding"
diff --git a/basis/urls/encoding/encoding-tests.factor b/basis/urls/encoding/encoding-tests.factor
new file mode 100644 (file)
index 0000000..87b1812
--- /dev/null
@@ -0,0 +1,28 @@
+IN: urls.encoding.tests
+USING: urls.encoding tools.test arrays kernel assocs present accessors ;
+
+[ "~hello world" ] [ "%7ehello world" url-decode ] unit-test
+[ f ] [ "%XX%XX%XX" url-decode ] unit-test
+[ f ] [ "%XX%XX%X" url-decode ] unit-test
+
+[ "hello world" ] [ "hello%20world" url-decode ] unit-test
+[ " ! "         ] [ "%20%21%20"     url-decode ] unit-test
+[ "hello world" ] [ "hello world%"  url-decode ] unit-test
+[ "hello world" ] [ "hello world%x" url-decode ] unit-test
+[ "hello%20world" ] [ "hello world" url-encode ] unit-test
+
+[ "hello world" ] [ "hello+world" query-decode ] unit-test
+
+[ "\u001234hi\u002045" ] [ "\u001234hi\u002045" url-encode url-decode ] unit-test
+
+[ "a=b&a=c" ] [ { { "a" { "b" "c" } } } assoc>query ] unit-test
+
+[ H{ { "a" "b" } } ] [ "a=b" query>assoc ] unit-test
+
+[ H{ { "a" { "b" "c" } } } ] [ "a=b&a=c" query>assoc ] unit-test
+
+[ H{ { "a" { "b" "c" } } } ] [ "a=b;a=c" query>assoc ] unit-test
+
+[ H{ { "text" "hello world" } } ] [ "text=hello+world" query>assoc ] unit-test
+
+[ "a=3" ] [ { { "a" 3 } } assoc>query ] unit-test
diff --git a/basis/urls/encoding/encoding.factor b/basis/urls/encoding/encoding.factor
new file mode 100644 (file)
index 0000000..fa88260
--- /dev/null
@@ -0,0 +1,96 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel ascii combinators combinators.short-circuit
+sequences splitting fry namespaces make assocs arrays strings
+io.encodings.string io.encodings.utf8 math math.parser accessors
+hashtables present ;
+IN: urls.encoding
+
+: url-quotable? ( ch -- ? )
+    {
+        [ letter? ]
+        [ LETTER? ]
+        [ digit? ]
+        [ "/_-.:" member? ]
+    } 1|| ; foldable
+
+<PRIVATE
+
+: push-utf8 ( ch -- )
+    1string utf8 encode
+    [ CHAR: % , >hex 2 CHAR: 0 pad-left % ] each ;
+
+PRIVATE>
+
+: url-encode ( str -- encoded )
+    [
+        [ dup url-quotable? [ , ] [ push-utf8 ] if ] each
+    ] "" make ;
+
+<PRIVATE
+
+: url-decode-hex ( index str -- )
+    2dup length 2 - >= [
+        2drop
+    ] [
+        [ 1+ dup 2 + ] dip subseq  hex> [ , ] when*
+    ] if ;
+
+: url-decode-% ( index str -- index str )
+    2dup url-decode-hex ;
+
+: url-decode-iter ( index str -- )
+    2dup length >= [
+        2drop
+    ] [
+        2dup nth dup CHAR: % = [
+            drop url-decode-% [ 3 + ] dip
+        ] [
+            , [ 1+ ] dip
+        ] if url-decode-iter
+    ] if ;
+
+PRIVATE>
+
+: url-decode ( str -- decoded )
+    [ 0 swap url-decode-iter ] "" make utf8 decode ;
+
+: query-decode ( str -- decoded )
+    [ dup CHAR: + = [ drop "%20" ] [ 1string ] if ] { } map-as
+    concat url-decode ;
+
+<PRIVATE
+
+: add-query-param ( value key assoc -- )
+    [
+        at [
+            {
+                { [ dup string? ] [ swap 2array ] }
+                { [ dup array? ] [ swap suffix ] }
+                { [ dup not ] [ drop ] }
+            } cond
+        ] when*
+    ] 2keep set-at ;
+
+PRIVATE>
+
+: query>assoc ( query -- assoc )
+    dup [
+        "&;" split H{ } clone [
+            [
+                [ "=" split1 [ dup [ query-decode ] when ] bi@ swap ] dip
+                add-query-param
+            ] curry each
+        ] keep
+    ] when ;
+
+: assoc>query ( assoc -- str )
+    [
+        dup array? [ [ present ] map ] [ present 1array ] if
+    ] assoc-map
+    [
+        [
+            [ url-encode ] dip
+            [ url-encode "=" swap 3append , ] with each
+        ] assoc-each
+    ] { } make "&" join ;
diff --git a/basis/urls/encoding/summary.txt b/basis/urls/encoding/summary.txt
new file mode 100644 (file)
index 0000000..d156e44
--- /dev/null
@@ -0,0 +1 @@
+URL and form encoding/decoding
diff --git a/basis/urls/encoding/tags.txt b/basis/urls/encoding/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/urls/urls-docs.factor b/basis/urls/urls-docs.factor
new file mode 100644 (file)
index 0000000..03ffade
--- /dev/null
@@ -0,0 +1,196 @@
+USING: assocs hashtables help.markup help.syntax
+io.streams.string io.files kernel strings present math multiline
+;
+IN: urls
+
+HELP: url
+{ $class-description "The class of URLs. The slots correspond to the standard components of a URL." } ;
+
+HELP: <url>
+{ $values { "url" url } }
+{ $description "Creates an empty URL." } ;
+
+HELP: >url
+{ $values { "obj" object } { "url" url } }
+{ $description "Converts an object into a URL. If the object is already a URL, does nothing; if it is a string, then it is parsed as a URL." }
+{ $errors "Throws an error if the object is of the wrong type, or if it is a string which is not a valid URL." }
+{ $examples
+    "If we convert a string to a URL and print it out again, it will print similarly to the input string, except some normalization may have occurred:"
+    { $example
+        "USING: accessors prettyprint urls ;"
+        "\"http://www.apple.com\" >url ."
+        "URL\" http://www.apple.com/\""
+    }
+    "We can examine the URL object:"
+    { $example
+        "USING: accessors io urls ;"
+        "\"http://www.apple.com\" >url host>> print"
+        "www.apple.com"
+    }
+    "A relative URL does not have a protocol, host or port:"
+    { $example
+        "USING: accessors prettyprint urls ;"
+        "\"file.txt\" >url protocol>> ."
+        "f"
+    }
+} ;
+
+HELP: URL"
+{ $syntax "URL\" url...\"" }
+{ $description "URL literal syntax." }
+{ $examples
+    { $example
+        "USING: accessors prettyprint urls ;"
+        "URL\" http://factorcode.org:80\" port>> ."
+        "80"
+    }
+} ;
+
+HELP: derive-url
+{ $values { "base" url } { "url" url } { "url'" url } }
+{ $description "Builds a URL by filling in missing components of " { $snippet "url" } " from " { $snippet "base" } "." }
+{ $examples
+    { $example
+        "USING: prettyprint urls ;"
+        "URL\" http://factorcode.org\""
+        "URL\" binaries.fhtml\" derive-url ."
+        "URL\" http://factorcode.org/binaries.fhtml\""
+    }
+    { $example
+        "USING: prettyprint urls ;"
+        "URL\" http://www.truecasey.com/drinks/kombucha\""
+        "URL\" master-cleanser\" derive-url ."
+        "URL\" http://www.truecasey.com/drinks/master-cleanser\""
+    }
+} ;
+
+HELP: ensure-port
+{ $values { "url" url } }
+{ $description "If the URL does not specify a port number, fill in the default for the URL's protocol. If the protocol is unknown, the port number is not changed." }
+{ $side-effects "url" }
+{ $examples
+    { $example
+        "USING: accessors prettyprint urls ;"
+        "URL\" https://concatenative.org\" ensure-port port>> ."
+        "443"
+    }
+} ;
+
+HELP: parse-host
+{ $values { "string" string } { "host" string } { "port" "an " { $link integer } " or " { $link f } } }
+{ $description "Splits a string of the form " { $snippet "host:port" } " into a host and a port number. If the port number is not specified, outputs " { $link f } "." }
+{ $notes "This word is used by " { $link >url } ". It can also be used directly to parse " { $snippet "host:port" } " strings which are not full URLs." }
+{ $examples
+    { $example
+        "USING: prettyprint urls ;"
+        "\"sbcl.org:80\" parse-host .s"
+        "\"sbcl.org\"\n80"
+    }
+} ;
+
+HELP: protocol-port
+{ $values { "protocol" "a protocol string" } { "port" "an " { $link integer } " or " { $link f } } }
+{ $description "Outputs the port number associated with a protocol, or " { $link f } " if the protocol is unknown." } ;
+
+HELP: query-param
+{ $values
+     { "url" url } { "key" string }
+    { "value" "a " { $link string } " or " { $link f } } }
+{ $description "Outputs the URL-decoded value of a URL query parameter." }
+{ $examples
+    { $example
+        "USING: io urls ;"
+        "URL\" http://food.com/calories?item=French+Fries\""
+        "\"item\" query-param print"
+        "French Fries"
+    }
+} ;
+
+HELP: set-query-param
+{ $values { "url" url } { "value" object } { "key" string } }
+{ $description "Sets a query parameter. The value can be any object supported by " { $link present } ", or " { $link f } ", in which case the key is removed." }
+{ $notes "This word always returns the same URL object that was input. This allows for a ``pipeline'' coding style, where several query parameters are set in a row. Since it mutates the input object, you must " { $link clone } " it first if it is literal, as in the below example."
+}
+{ $examples
+    { $code
+        <" USING: kernel http.client urls ;
+URL" http://search.yahooapis.com/WebSearchService/V1/webSearch" clone
+    "concatenative programming (NSFW)" "query" set-query-param
+    "1" "adult_ok" set-query-param
+http-get">
+    }
+    "(For a complete Yahoo! search web service implementation, see the " { $vocab-link "yahoo" } " vocabulary.)"
+}
+{ $side-effects "url" } ;
+
+HELP: relative-url
+{ $values { "url" url } { "url'" url } }
+{ $description "Outputs a new URL with the same path and query components as the input value, but with the protocol, host and port set to " { $link f } "." }
+{ $examples
+    { $example
+        "USING: prettyprint urls ;"
+        "URL\" http://factorcode.org/binaries.fhtml\""
+        "relative-url ."
+        "URL\" /binaries.fhtml\""
+    }
+} ;
+
+HELP: secure-protocol?
+{ $values { "protocol" string } { "?" "a boolean" } }
+{ $description "Tests if protocol connections must be made with secure sockets (SSL/TLS)." }
+{ $examples
+    { $example
+        "USING: prettyprint urls ;"
+        "\"https\" secure-protocol? ."
+        "t"
+    }
+} ;
+
+HELP: url-addr
+{ $values { "url" url } { "addr" "an address specifier" } }
+{ $description "Outputs an address specifier for use with " { $link "network-connection" } "." }
+{ $examples
+    { $example
+        "USING: prettyprint urls ;"
+        "URL\" ftp://ftp.cdrom.com\" url-addr ."
+        "T{ inet { host \"ftp.cdrom.com\" } { port 21 } }"
+    }
+} ;
+
+HELP: url-append-path
+{ $values { "path1" string } { "path2" string } { "path" string } }
+{ $description "Like " { $link append-path } ", but intended for use with URL paths and not filesystem paths." } ;
+
+ARTICLE: "url-utilities" "URL implementation utilities"
+{ $subsection parse-host }
+{ $subsection secure-protocol? }
+{ $subsection url-append-path } ;
+
+ARTICLE: "urls" "URL objects"
+"The " { $vocab-link "urls" } " vocabulary implements a URL data type. The benefit of using a data type to prepresent URLs rather than a string is that the parsing, printing and escaping logic is encapsulated and reused, rather than re-implemented in a potentially buggy manner every time."
+$nl
+"URL objects are used heavily by the " { $vocab-link "http" } " and " { $vocab-link "furnace" } " vocabularies, and are also useful on their own."
+$nl
+"The class of URLs, and a constructor:"
+{ $subsection url }
+{ $subsection <url> }
+"Converting strings to URLs:"
+{ $subsection >url }
+"URLs can be converted back to strings using the " { $link present } " word."
+$nl
+"URL literal syntax:"
+{ $subsection POSTPONE: URL" }
+"Manipulating URLs:"
+{ $subsection derive-url }
+{ $subsection relative-url }
+{ $subsection ensure-port }
+{ $subsection query-param }
+{ $subsection set-query-param }
+"Creating " { $link "network-addressing" } " from URLs:"
+{ $subsection url-addr }
+"The URL implemention encodes and decodes components of " { $link url } " instances automatically, but sometimes this functionality is needed for non-URL strings."
+{ $subsection "url-encoding" }
+"Utility words used by the URL implementation:"
+{ $subsection "url-utilities" } ;
+
+ABOUT: "urls"
index 7f835b29182ab373e5a05ae8b224683c22f28153..cac206bf3cc8cfe44e39c2c84a5e5c232411127e 100644 (file)
@@ -2,30 +2,6 @@ IN: urls.tests
 USING: urls urls.private tools.test
 arrays kernel assocs present accessors ;
 
-[ "hello%20world" ] [ "hello world" url-encode ] unit-test
-[ "hello world" ] [ "hello%20world" url-decode ] unit-test
-[ "~hello world" ] [ "%7ehello+world" url-decode ] unit-test
-[ f ] [ "%XX%XX%XX" url-decode ] unit-test
-[ f ] [ "%XX%XX%X" url-decode ] unit-test
-
-[ "hello world"   ] [ "hello+world"    url-decode ] unit-test
-[ "hello world"   ] [ "hello%20world"  url-decode ] unit-test
-[ " ! "           ] [ "%20%21%20"      url-decode ] unit-test
-[ "hello world"   ] [ "hello world%"   url-decode ] unit-test
-[ "hello world"   ] [ "hello world%x"  url-decode ] unit-test
-[ "hello%20world" ] [ "hello world"    url-encode ] unit-test
-[ "%20%21%20"     ] [ " ! "            url-encode ] unit-test
-
-[ "\u001234hi\u002045" ] [ "\u001234hi\u002045" url-encode url-decode ] unit-test
-
-[ "a=b&a=c" ] [ { { "a" { "b" "c" } } } assoc>query ] unit-test
-
-[ H{ { "a" "b" } } ] [ "a=b" query>assoc ] unit-test
-
-[ H{ { "a" { "b" "c" } } } ] [ "a=b&a=c" query>assoc ] unit-test
-
-[ "a=3" ] [ { { "a" 3 } } assoc>query ] unit-test
-
 : urls
     {
         {
@@ -225,3 +201,29 @@ urls [
 ] unit-test
 
 [ "foo#3" ] [ URL" foo" clone 3 >>anchor present ] unit-test
+
+[ "http://www.foo.com/" ] [ "http://www.foo.com:80" >url present ] unit-test
+
+[ f ] [ URL" /gp/redirect.html/002-7009742-0004012?location=http://advantage.amazon.com/gp/vendor/public/join%26token%3d77E3769AB3A5B6CF611699E150DC33010761CE12" protocol>> ] unit-test
+
+[
+    T{ url
+        { protocol "http" }
+        { host "localhost" }
+        { query H{ { "foo" "bar" } } }
+        { path "/" }
+    }
+]
+[ "http://localhost?foo=bar" >url ] unit-test
+
+[
+    T{ url
+        { protocol "http" }
+        { host "localhost" }
+        { query H{ { "foo" "bar" } } }
+        { path "/" }
+    }
+]
+[ "http://localhost/?foo=bar" >url ] unit-test
+
+[ "/" ] [ "http://www.jedit.org" >url path>> ] unit-test
index e16f62d1f1e53ad30df6ba746415a8a9b854946b..5cc8c9693b50f7384a5ec566f13e652728324ef3 100644 (file)
@@ -4,99 +4,10 @@ USING: kernel ascii combinators combinators.short-circuit
 sequences splitting fry namespaces make assocs arrays strings
 io.sockets io.sockets.secure io.encodings.string
 io.encodings.utf8 math math.parser accessors parser
-strings.parser lexer prettyprint.backend hashtables present ;
+strings.parser lexer prettyprint.backend hashtables present
+peg.ebnf urls.encoding ;
 IN: urls
 
-: url-quotable? ( ch -- ? )
-    #! In a URL, can this character be used without
-    #! URL-encoding?
-    {
-        [ letter? ]
-        [ LETTER? ]
-        [ digit? ]
-        [ "/_-." member? ]
-    } 1|| ; foldable
-
-<PRIVATE
-
-: push-utf8 ( ch -- )
-    1string utf8 encode
-    [ CHAR: % , >hex 2 CHAR: 0 pad-left % ] each ;
-
-PRIVATE>
-
-: url-encode ( str -- str )
-    [
-        [ dup url-quotable? [ , ] [ push-utf8 ] if ] each
-    ] "" make ;
-
-<PRIVATE
-
-: url-decode-hex ( index str -- )
-    2dup length 2 - >= [
-        2drop
-    ] [
-        [ 1+ dup 2 + ] dip subseq  hex> [ , ] when*
-    ] if ;
-
-: url-decode-% ( index str -- index str )
-    2dup url-decode-hex [ 3 + ] dip ;
-
-: url-decode-+-or-other ( index str ch -- index str )
-    dup CHAR: + = [ drop CHAR: \s ] when , [ 1+ ] dip ;
-
-: url-decode-iter ( index str -- )
-    2dup length >= [
-        2drop
-    ] [
-        2dup nth dup CHAR: % = [
-            drop url-decode-%
-        ] [
-            url-decode-+-or-other
-        ] if url-decode-iter
-    ] if ;
-
-PRIVATE>
-
-: url-decode ( str -- str )
-    [ 0 swap url-decode-iter ] "" make utf8 decode ;
-
-<PRIVATE
-
-: add-query-param ( value key assoc -- )
-    [
-        at [
-            {
-                { [ dup string? ] [ swap 2array ] }
-                { [ dup array? ] [ swap suffix ] }
-                { [ dup not ] [ drop ] }
-            } cond
-        ] when*
-    ] 2keep set-at ;
-
-PRIVATE>
-
-: query>assoc ( query -- assoc )
-    dup [
-        "&" split H{ } clone [
-            [
-                [ "=" split1 [ dup [ url-decode ] when ] bi@ swap ] dip
-                add-query-param
-            ] curry each
-        ] keep
-    ] when ;
-
-: assoc>query ( hash -- str )
-    [
-        dup array? [ [ present ] map ] [ present 1array ] if
-    ] assoc-map
-    [
-        [
-            [ url-encode ] dip
-            [ url-encode "=" swap 3append , ] with each
-        ] assoc-each
-    ] { } make "&" join ;
-
 TUPLE: url protocol username password host port path query anchor ;
 
 : <url> ( -- url ) url new ;
@@ -104,8 +15,15 @@ TUPLE: url protocol username password host port path query anchor ;
 : query-param ( url key -- value )
     swap query>> at ;
 
+: delete-query-param ( url key -- url )
+    over query>> delete-at ;
+
 : set-query-param ( url value key -- url )
-    '[ [ _ _ ] dip ?set-at ] change-query ;
+    over [
+        '[ [ _ _ ] dip ?set-at ] change-query
+    ] [
+        nip delete-query-param
+    ] if ;
 
 : parse-host ( string -- host port )
     ":" split1 [ url-decode ] [
@@ -115,38 +33,65 @@ TUPLE: url protocol username password host port path query anchor ;
         ] when
     ] bi* ;
 
+GENERIC: >url ( obj -- url )
+
+M: f >url drop <url> ;
+
+M: url >url ;
+
 <PRIVATE
 
-: parse-host-part ( url protocol rest -- url string' )
-    [ >>protocol ] [
-        "//" ?head [ "Invalid URL" throw ] unless
-        "@" split1 [
-            [
-                ":" split1 [ >>username ] [ >>password ] bi*
-            ] dip
-        ] when*
-        "/" split1 [
-            parse-host [ >>host ] [ >>port ] bi*
-        ] [ "/" prepend ] bi*
-    ] bi* ;
+EBNF: parse-url
 
-PRIVATE>
+protocol = [a-z]+                   => [[ url-decode ]]
+username = [^/:@#?]+                => [[ url-decode ]]
+password = [^/:@#?]+                => [[ url-decode ]]
+pathname = [^#?]+                   => [[ url-decode ]]
+query    = [^#]+                    => [[ query>assoc ]]
+anchor   = .+                       => [[ url-decode ]]
 
-GENERIC: >url ( obj -- url )
+hostname = [^/#?]+                  => [[ url-decode ]]
 
-M: f >url drop <url> ;
+hostname-spec = hostname ("/"|!(.)) => [[ first ]]
 
-M: url >url ;
+auth     = (username (":" password  => [[ second ]])? "@"
+                                    => [[ first2 2array ]])?
+
+url      = ((protocol "://")        => [[ first ]] auth hostname)?
+           (pathname)?
+           ("?" query               => [[ second ]])?
+           ("#" anchor              => [[ second ]])?
+
+;EBNF
+
+PRIVATE>
 
 M: string >url
-    <url> swap
-    ":" split1 [ parse-host-part ] when*
-    "#" split1 [
-        "?" split1
-        [ url-decode >>path ]
-        [ [ query>assoc >>query ] when* ] bi*
-    ]
-    [ url-decode >>anchor ] bi* ;
+    parse-url {
+        [
+            first [
+                [ first ] ! protocol
+                [
+                    second
+                    [ first [ first2 ] [ f f ] if* ] ! username, password
+                    [ second parse-host ] ! host, port
+                    bi
+                ] bi
+            ] [ f f f f f ] if*
+        ]
+        [ second ] ! pathname
+        [ third ] ! query
+        [ fourth ] ! anchor
+    } cleave url boa
+    dup host>> [ [ "/" or ] change-path ] when ;
+
+: protocol-port ( protocol -- port )
+    {
+        { "http" [ 80 ] }
+        { "https" [ 443 ] }
+        { "ftp" [ 21 ] }
+        [ drop f ]
+    } case ;
 
 <PRIVATE
 
@@ -155,16 +100,22 @@ M: string >url
         % password>> [ ":" % % ] when* "@" %
     ] [ 2drop ] if ;
 
+: url-port ( url -- port/f )
+    [ port>> ] [ port>> ] [ protocol>> protocol-port ] tri =
+    [ drop f ] when ;
+
 : unparse-host-part ( url protocol -- )
     %
     "://" %
     {
         [ unparse-username-password ]
         [ host>> url-encode % ]
-        [ port>> [ ":" % # ] when* ]
+        [ url-port [ ":" % # ] when* ]
         [ path>> "/" head? [ "/" % ] unless ]
     } cleave ;
 
+PRIVATE>
+
 M: url present
     [
         {
@@ -188,14 +139,14 @@ PRIVATE>
 
 : derive-url ( base url -- url' )
     [ clone ] dip over {
-        [ [ protocol>> ] either? >>protocol ]
-        [ [ username>> ] either? >>username ]
-        [ [ password>> ] either? >>password ]
-        [ [ host>>     ] either? >>host ]
-        [ [ port>>     ] either? >>port ]
-        [ [ path>>     ] bi@ swap url-append-path >>path ]
-        [ [ query>>    ] either? >>query ]
-        [ [ anchor>>   ] either? >>anchor ]
+        [ [ protocol>>  ] either? >>protocol ]
+        [ [ username>>  ] either? >>username ]
+        [ [ password>>  ] either? >>password ]
+        [ [ host>>      ] either? >>host ]
+        [ [ port>>      ] either? >>port ]
+        [ [ path>>      ] bi@ swap url-append-path >>path ]
+        [ [ query>>     ] either? >>query ]
+        [ [ anchor>>    ] either? >>anchor ]
     } 2cleave ;
 
 : relative-url ( url -- url' )
@@ -209,17 +160,15 @@ PRIVATE>
     "https" = ;
 
 : url-addr ( url -- addr )
-    [ [ host>> ] [ port>> ] bi <inet> ] [ protocol>> ] bi
+    [
+        [ host>> ]
+        [ port>> ]
+        [ protocol>> protocol-port ]
+        tri or <inet>
+    ] [ protocol>> ] bi
     secure-protocol? [ <secure> ] when ;
 
-: protocol-port ( protocol -- port )
-    {
-        { "http" [ 80 ] }
-        { "https" [ 443 ] }
-        { "ftp" [ 21 ] }
-    } case ;
-
-: ensure-port ( url -- url' )
+: ensure-port ( url -- url )
     dup protocol>> '[ _ protocol-port or ] change-port ;
 
 ! Literal syntax
diff --git a/basis/validators/authors.txt b/basis/validators/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/basis/validators/summary.txt b/basis/validators/summary.txt
new file mode 100644 (file)
index 0000000..bcf9ac0
--- /dev/null
@@ -0,0 +1 @@
+Value validation for the web framework
diff --git a/basis/validators/tags.txt b/basis/validators/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/basis/validators/validators-docs.factor b/basis/validators/validators-docs.factor
new file mode 100644 (file)
index 0000000..fc16c48
--- /dev/null
@@ -0,0 +1,110 @@
+USING: help.markup help.syntax io.streams.string quotations 
+strings math parser-combinators.regexp ;
+IN: validators
+
+HELP: v-captcha
+{ $values { "str" string } }
+{ $description "Throws a validation error if the string is non-empty. This is used to create bait fields for spam-bots to fill in." } ;
+
+HELP: v-credit-card
+{ $values { "str" string } { "n" integer } }
+{ $description "If the credit card number passes the Luhn algorithm, converts it to an integer, otherwise throws an error." }
+{ $notes "See " { $url "http://en.wikipedia.org/wiki/Luhn_algorithm" } " for a description of this algorithm." } ;
+
+HELP: v-default
+{ $values { "str" string } { "def" string } { "str/def" string } }
+{ $description "If the input string is not specified, replaces it with the default value." } ;
+
+HELP: v-email
+{ $values { "str" string } }
+{ $description "Throws a validation error if the string is not a valid e-mail address, as determined by a regular expression." } ;
+
+HELP: v-integer
+{ $values { "str" string } { "n" integer } }
+{ $description "Converts the string into an integer, throwing a validation error if the string is not a valid integer." } ;
+
+HELP: v-min-length
+{ $values { "str" string } { "n" integer } }
+{ $description "Throws a validation error if the string is shorter than " { $snippet "n" } " characters." } ;
+
+HELP: v-max-length
+{ $values { "str" string } { "n" integer } }
+{ $description "Throws a validation error if the string is longer than " { $snippet "n" } " characters." } ;
+
+HELP: v-max-value
+{ $values { "x" integer } { "n" integer } }
+{ $description "Throws an error if " { $snippet "x" } " is larger than " { $snippet "n" } "." } ;
+
+HELP: v-min-value
+{ $values { "x" integer } { "n" integer } }  
+{ $description "Throws an error if " { $snippet "x" } " is smaller than " { $snippet "n" } "." } ;
+
+HELP: v-mode
+{ $values { "str" string } }
+{ $description "Throws an error if " { $snippet "str" } " is not a valid XMode mode name." } ;
+
+HELP: v-number
+{ $values { "str" string } { "n" real } }
+{ $description "Converts the string into a real number, throwing a validation error if the string is not a valid real number." } ;
+
+HELP: v-one-line
+{ $values { "str" string } }
+{ $description "Throws a validation error if the string contains line breaks." } ;
+
+HELP: v-one-word
+{ $values { "str" string } }
+{ $description "Throws a validation error if the string contains word breaks." } ;
+
+HELP: v-optional
+{ $values { "str" string } { "quot" quotation } { "result" string } }
+{ $description "If the string is non-empty, applies the quotation to the string, otherwise outputs the empty string." } ;
+
+HELP: v-password
+{ $values { "str" string } }
+{ $description "A reasonable default validator for passwords." } ;
+
+HELP: v-regexp
+{ $values { "str" string } { "what" string } { "regexp" regexp } }
+{ $description "Throws a validation error that " { $snippet "what" } " failed if the string does not match the regular expression." } ;
+
+HELP: v-required
+{ $values { "str" string } }
+{ $description "Throws a validation error if the string is empty." } ;
+
+HELP: v-url
+{ $values { "str" string } }
+{ $description "Throws an error if the string is not a valid URL, as determined by a regular expression." } ;
+
+HELP: v-username
+{ $values { "str" string } }
+{ $description "A reasonable default validator for usernames." } ;
+
+ARTICLE: "validators" "Form validators"
+"The " { $vocab-link "validators" } " vocabulary provides a set of words which are intended to be used with the form validation functionality offered by " { $vocab-link "furnace.actions" } ". They can also be used independently of the web framework."
+$nl
+"Note that validators which take numbers must be preceded by " { $link v-integer } " or " { $link v-number } " if the original input is a string."
+$nl
+"Higher-order validators which require additional parameters:"
+{ $subsection v-default     }
+{ $subsection v-optional    }
+{ $subsection v-min-length  }
+{ $subsection v-max-length  }
+{ $subsection v-min-value   }
+{ $subsection v-max-value   }
+{ $subsection v-regexp      }
+"Simple validators:"
+{ $subsection v-required    }
+{ $subsection v-number      }
+{ $subsection v-integer     }
+{ $subsection v-one-line    }
+{ $subsection v-one-word    }
+{ $subsection v-captcha     }
+"More complex validators:"
+{ $subsection v-email       }
+{ $subsection v-url         }
+{ $subsection v-username    }
+{ $subsection v-password    }
+{ $subsection v-credit-card }
+{ $subsection v-mode        } ;
+
+ABOUT: "validators"
index f24171b2b476551f5344f5cd090119025b4b5da0..30e1eadc7a627607fc80dbc5a937ad083fdb4318 100644 (file)
@@ -1,17 +1,18 @@
 ! Copyright (C) 2006, 2008 Slava Pestov
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel continuations sequences math namespaces make sets
-math.parser math.ranges assocs regexp unicode.categories arrays
-hashtables words classes quotations xmode.catalog ;
+math.parser math.ranges assocs parser-combinators.regexp
+unicode.categories arrays hashtables words classes quotations
+xmode.catalog ;
 IN: validators
 
-: v-default ( str def -- str )
+: v-default ( str def -- str/def )
     over empty? spin ? ;
 
 : v-required ( str -- str )
     dup empty? [ "required" throw ] when ;
 
-: v-optional ( str quot -- str )
+: v-optional ( str quot -- result )
     over empty? [ 2drop f ] [ call ] if ; inline
 
 : v-min-length ( str n -- str )
@@ -90,7 +91,7 @@ IN: validators
         "not a valid syntax mode" throw 
     ] unless ;
 
-: luhn? ( n -- ? )
+: luhn? ( str -- ? )
     string>digits <reversed>
     [ odd? [ 2 * 10 /mod + ] when ] map-index
     sum 10 mod 0 = ;
index 4984b03f039bb7470dcd3cbb97029967b1e73863..c96ea0f8cfbdc5a0512d79eb1633ac4c9bd2ce23 100755 (executable)
@@ -7,6 +7,7 @@ ARTICLE: "values" "Global values"
 "To get the value, just call the word. The following words manipulate values:"\r
 { $subsection get-value }\r
 { $subsection set-value }\r
+{ $subsection POSTPONE: to: }\r
 { $subsection change-value } ;\r
 \r
 HELP: VALUE:\r
@@ -20,8 +21,19 @@ HELP: get-value
 \r
 HELP: set-value\r
 { $values { "value" "a new value" } { "word" "a value word" } }\r
-{ $description "Sets the value word." } ;\r
+{ $description "Sets a value word." } ;\r
+\r
+HELP: to:\r
+{ $syntax "... to: value" }\r
+{ $values { "word" "a value word" } }\r
+{ $description "Sets a value word." }\r
+{ $notes\r
+    "Note that"\r
+    { $code "foo to: value" }\r
+    "is just sugar for"\r
+    { $code "foo \\ value set-value" }\r
+} ;\r
 \r
 HELP: change-value\r
-{ $values { "word" "a value word" } { "quot" "a quotation ( oldvalue -- newvalue )" } }\r
+{ $values { "word" "a value word" } { "quot" "a quotation with stack effect " { $snippet "( oldvalue -- newvalue )" } } }\r
 { $description "Changes the value using the given quotation." } ;\r
index 31b44be99eff0c5827f5019ed4381b622525025f..6ad5e7dee61fc74310d750798da49404a154e375 100755 (executable)
@@ -3,7 +3,7 @@ IN: values.tests
 \r
 VALUE: foo\r
 [ f ] [ foo ] unit-test\r
-[ ] [ 3 \ foo set-value ] unit-test\r
+[ ] [ 3 to: foo ] unit-test\r
 [ 3 ] [ foo ] unit-test\r
 [ ] [ \ foo [ 1+ ] change-value ] unit-test\r
 [ 4 ] [ foo ] unit-test\r
index 7f19898b18ab1eecf0bcb90f6c762a78d9fdd3f9..0dd1058370a75ab334c984b88bcffd45d74a410d 100755 (executable)
@@ -1,15 +1,42 @@
-USING: accessors kernel parser sequences words effects ;
+! Copyright (C) 2008 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel parser words sequences quotations ;
 IN: values
 
+! Mutating literals in word definitions is not really allowed,
+! and the deploy tool takes advantage of this fact to perform
+! some aggressive stripping and compression. However, this
+! breaks a naive implementation of values. We need to do two
+! things:
+! 1) Store the value in a subclass of identity-tuple, so that
+! two quotations from different value words are never equal.
+! This avoids bogus merging of values.
+! 2) Set the "no-def-strip" word-prop, so that the shaker leaves
+! the def>> slot alone, allowing us to introspect it. Otherwise,
+! it will get set to [ ] and we would lose access to the
+! value-holder.
+
+<PRIVATE
+
+TUPLE: value-holder < identity-tuple obj ;
+
+PRIVATE>
+
 : VALUE:
-    CREATE-WORD { f } clone [ first ] curry
+    CREATE-WORD
+    dup t "no-def-strip" set-word-prop
+    T{ value-holder } clone [ obj>> ] curry
     (( -- value )) define-declared ; parsing
 
 : set-value ( value word -- )
-    def>> first set-first ;
+    def>> first (>>obj) ;
+
+: to:
+    scan-word literalize parsed
+    \ set-value parsed ; parsing
 
 : get-value ( word -- value )
-    def>> first first ;
+    def>> first obj>> ;
 
 : change-value ( word quot -- )
-    over >r >r get-value r> call r> set-value ; inline
+    [ [ get-value ] dip call ] [ drop ] 2bi set-value ; inline
index 28c0de406a924bd32a53e3b0c13961c15f331ab8..8639c93e71651ebc9b2ffc2e071a5ee9b1583362 100755 (executable)
@@ -1,7 +1,7 @@
 USING: xmode.loader.syntax xmode.tokens xmode.rules
 xmode.keyword-map xml.data xml.utilities xml assocs kernel
 combinators sequences math.parser namespaces parser
-xmode.utilities regexp io.files accessors ;
+xmode.utilities parser-combinators.regexp io.files accessors ;
 IN: xmode.loader
 
 ! Based on org.gjt.sp.jedit.XModeHandler
index 69c4e4fac39bf87cbb2338aa96c8815d4ad6e3fe..cbebe090c33676bf68372c39f8c86c0ec7736612 100644 (file)
@@ -2,8 +2,8 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors xmode.tokens xmode.rules xmode.keyword-map
 xml.data xml.utilities xml assocs kernel combinators sequences
-math.parser namespaces make parser lexer xmode.utilities regexp
-io.files ;
+math.parser namespaces make parser lexer xmode.utilities
+parser-combinators.regexp io.files ;
 IN: xmode.loader.syntax
 
 SYMBOL: ignore-case?
index d0d68febec5b964b579a43e074a3599347ce81db..f777eaa18ca4b5d9d63a4b8b5afc1e5dfe132042 100755 (executable)
@@ -3,9 +3,9 @@
 IN: xmode.marker
 USING: kernel namespaces make xmode.rules xmode.tokens
 xmode.marker.state xmode.marker.context xmode.utilities
-xmode.catalog sequences math assocs combinators
-strings regexp splitting parser-combinators ascii unicode.case
-combinators.short-circuit accessors ;
+xmode.catalog sequences math assocs combinators strings
+parser-combinators.regexp splitting parser-combinators ascii
+unicode.case combinators.short-circuit accessors ;
 
 ! Based on org.gjt.sp.jedit.syntax.TokenMarker
 
index e3c0c65db0a61e0c7e443c93cc6b84728a3971a3..e4f12bcc49314d0a9debc17ef90b5dbea6a26a5a 100755 (executable)
@@ -1,5 +1,6 @@
 USING: accessors xmode.tokens xmode.keyword-map kernel
-sequences vectors assocs strings memoize regexp unicode.case ;
+sequences vectors assocs strings memoize unicode.case
+parser-combinators.regexp ;
 IN: xmode.rules
 
 TUPLE: string-matcher string ignore-case? ;
index 16ab260df5d96d6d3a9db4e5b8f888d9ba66b9b5..5cbc1e96e33251ea19a56491de42ef721a0fc804 100755 (executable)
@@ -175,6 +175,7 @@ find_os() {
         *FreeBSD*) OS=freebsd;;
         *OpenBSD*) OS=openbsd;;
         *DragonFly*) OS=dragonflybsd;;
+       SunOS) OS=solaris;;
     esac
 }
 
@@ -186,6 +187,7 @@ find_architecture() {
     case $uname_m in
        i386) ARCH=x86;;
        i686) ARCH=x86;;
+       i86pc) ARCH=x86;;
        amd64) ARCH=x86;;
        ppc64) ARCH=ppc;;
        *86) ARCH=x86;;
@@ -214,9 +216,8 @@ intel_macosx_word_size() {
     $ECHO -n "Testing if your Intel Mac supports 64bit binaries..."
     sysctl machdep.cpu.extfeatures | grep EM64T >/dev/null
     if [[ $? -eq 0 ]] ; then
-        WORD=32
+        WORD=64
         $ECHO "yes!"
-        $ECHO "Defaulting to 32bit for now though..."
     else
         WORD=32
         $ECHO "no."
@@ -261,6 +262,8 @@ check_os_arch_word() {
         $ECHO "ARCH: $ARCH"
         $ECHO "WORD: $WORD"
         $ECHO "OS, ARCH, or WORD is empty.  Please report this."
+
+       echo $MAKE_TARGET
         exit 5
     fi
 }
@@ -460,7 +463,7 @@ make_boot_image() {
 }
 
 install_build_system_apt() {
-    sudo apt-get --yes install sudo libc6-dev libfreetype6-dev libx11-dev xorg-dev glutg3-dev wget git-core git-doc rlwrap gcc make
+    sudo apt-get --yes install libc6-dev libfreetype6-dev libx11-dev xorg-dev glutg3-dev wget git-core git-doc rlwrap gcc make
     check_ret sudo
 }
 
@@ -486,6 +489,8 @@ usage() {
     echo "    $0 update macosx-x86-32"
 }
 
+MAKE_TARGET=unknown
+
 # -n is nonzero length, -z is zero length
 if [[ -n "$2" ]] ; then
     parse_build_info $2
diff --git a/core/checksums/authors.txt b/core/checksums/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/core/checksums/summary.txt b/core/checksums/summary.txt
new file mode 100644 (file)
index 0000000..e85ab35
--- /dev/null
@@ -0,0 +1 @@
+Checksum protocol and implementations
index c190ce85e7a990ebb3f09873e2514fac2a968c45..dd78b4ba3e14fefc9d011d8b9d543f2139d22a31 100644 (file)
@@ -63,11 +63,14 @@ ERROR: invalid-slot-name name ;
 : parse-slot-value ( -- )
     scan scan-object 2array , scan "}" assert= ;
 
+ERROR: bad-literal-tuple ;
+
 : (parse-slot-values) ( -- )
     parse-slot-value
     scan {
         { "{" [ (parse-slot-values) ] }
         { "}" [ ] }
+        [ bad-literal-tuple ]
     } case ;
 
 : parse-slot-values ( -- )
@@ -86,4 +89,5 @@ ERROR: invalid-slot-name name ;
         { "f" [ \ } parse-until boa>tuple ] }
         { "{" [ parse-slot-values assoc>tuple ] }
         { "}" [ new ] }
+        [ bad-literal-tuple ]
     } case ;
index f92c9c0fd58730e9c5e0191df761cdd319b9c24b..577ad133e19bf004bba1d170b255ad956edeefa9 100755 (executable)
@@ -125,7 +125,8 @@ ERROR: bad-superclass class ;
     } cond ;
 
 : boa-check-quot ( class -- quot )
-    all-slots [ class>> instance-check-quot ] map spread>quot ;
+    all-slots [ class>> instance-check-quot ] map spread>quot
+    f like ;
 
 : define-boa-check ( class -- )
     dup boa-check-quot "boa-check" set-word-prop ;
@@ -311,7 +312,7 @@ M: tuple-class new
     [ (clone) ] [ tuple-layout <tuple> ] ?if ;
 
 M: tuple-class boa
-    [ "boa-check" word-prop call ]
+    [ "boa-check" word-prop [ call ] when* ]
     [ tuple-layout ]
     bi <tuple-boa> ;
 
index 3949c4b56637dbe240e740b4f74f0601d096cc42..f5ebc2a3389f3145da505e5d918baa3a1c1acb8d 100755 (executable)
@@ -77,6 +77,9 @@ $nl
 "Another two words resume continuations:"
 { $subsection continue }
 { $subsection continue-with }
+"Continuations as control-flow:"
+{ $subsection attempt-all }
+{ $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" } "."
@@ -211,3 +214,42 @@ HELP: with-datastack
 { $examples
     { $example "USING: continuations math prettyprint ;" "{ 3 7 } [ + ] with-datastack ." "{ 10 }" }
 } ;
+
+HELP: <continuation>
+{ $description "Constructs a new continuation." }
+{ $notes "User code should call " { $link continuation } " instead." } ;
+
+HELP: attempt-all
+{ $values
+     { "seq" sequence } { "quot" quotation }
+     { "obj" object } }
+{ $description "Applies the quotation to elements in a sequence and returns the value from the first quotation that does not throw an error. If all quotations throw an error, returns the last error thrown." }
+{ $examples "The first two numbers throw, the last one doesn't:"
+    { $example
+    "USING: prettyprint continuations kernel math ;"
+    "{ 1 3 6 } [ dup odd? [ \"Odd\" throw ] when ] attempt-all ."
+    "6" }
+    "All quotations throw, the last exception is rethrown:"
+    { $example
+    "USING: prettyprint continuations kernel math ;"
+    "[ { 1 3 5 } [ dup odd? [ throw ] when ] attempt-all ] [ ] recover ."
+    "5"
+    }
+} ;
+
+HELP: return
+{ $description "Returns early from a quotation by reifying the continuation captured by " { $link with-return } " ; execution is resumed starting immediately after " { $link with-return } "." } ;
+
+HELP: with-return
+{ $values
+     { "quot" quotation } }
+{ $description "Captures a continuation that can be reified by calling the " { $link return } " word. If so, it will resume execution immediatly after the " { $link with-return } " word. If " { $link return } " is not called, then execution proceeds as if this word were simply " { $link call } "." }
+{ $examples
+    "Only \"Hi\" will print:"
+    { $example
+    "USING: prettyprint continuations io ;"
+    "[ \"Hi\" print return \"Bye\" print ] with-return"
+    "Hi"
+} } ;
+
+{ return with-return } related-words
index b611b8ec190bd7a31fefb36f0e11556e9b1641a4..c82f92dc102817117472b25dc179dc3d5140e463 100755 (executable)
@@ -1,4 +1,5 @@
-USING: help.markup help.syntax libc kernel continuations io ;
+USING: help.markup help.syntax libc kernel continuations io
+sequences ;
 IN: destructors
 
 HELP: dispose
@@ -45,6 +46,11 @@ HELP: |dispose
 { $values { "disposable" "a disposable object" } }
 { $description "Marks the object for disposal in the event of an error at the end of the current " { $link with-destructors } " scope." } ;
 
+HELP: dispose-each
+{ $values
+     { "seq" sequence } }
+{ $description "Attempts to dispose of each element of a sequence and collects all of the errors into a sequence. If any errors are thrown during disposal, the last error is rethrown after all objects have been disposed." } ;
+
 ARTICLE: "destructors-anti-patterns" "Resource disposal anti-patterns"
 "Words which create objects corresponding to external resources should always be used with " { $link with-disposal } ". The following code is wrong:"
 { $code
index 07517afdf7f9b6514ee2cdf1fb9ef43c93efeab6..7cc8333c12656cac001fd5cdc949feb7dba3b77b 100755 (executable)
@@ -111,6 +111,12 @@ HELP: associate
 { $values { "value" "a value" } { "key" "a key" } { "hash" "a new " { $link hashtable } } }
 { $description "Create a new hashtable holding one key/value pair." } ;
 
+HELP: ?set-at
+{ $values
+     { "value" object } { "key" object } { "assoc/f" "an assoc or " { $link f } }
+     { "assoc" assoc } }
+{ $description "If the third input is an assoc, stores the key/value pair into that assoc, or else creates a new hashtable with the key/value pair as its only entry." } ;
+
 HELP: >hashtable
 { $values { "assoc" "an assoc" } { "hashtable" "a hashtable" } }
 { $description "Constructs a hashtable from any assoc." } ;
index e52799d10ab5e3e65a523ede96570204dcbfaab9..1634b7a3f1eb00886bd8048ecb72c03592048616 100755 (executable)
@@ -1,9 +1,10 @@
 ! Copyright (C) 2004, 2008 Slava Pestov, Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: io.backend io.files.private io hashtables kernel math
-memory namespaces sequences strings assocs arrays definitions
-system combinators splitting sbufs continuations destructors
-io.encodings io.encodings.binary init accessors math.order ;
+USING: io.backend io.files.private io hashtables kernel
+kernel.private math memory namespaces sequences strings assocs
+arrays definitions system combinators splitting sbufs
+continuations destructors io.encodings io.encodings.binary init
+accessors math.order ;
 IN: io.files
 
 HOOK: (file-reader) io-backend ( path -- stream )
@@ -192,11 +193,15 @@ PRIVATE>
 
 SYMBOL: current-directory
 
-[ cwd current-directory set-global ] "io.files" add-init-hook
+[
+    cwd current-directory set-global
+    13 getenv cwd prepend-path \ image set-global
+    14 getenv cwd prepend-path \ vm set-global
+    image parent-directory "resource-path" set-global
+] "io.files" add-init-hook
 
 : resource-path ( path -- newpath )
-    "resource-path" get [ image parent-directory ] unless*
-    prepend-path ;
+    "resource-path" get prepend-path ;
 
 : (normalize-path) ( path -- path' )
     "resource:" ?head [
index b639696f57e3424c88fd7414734bb6a33a273d79..43f66657a7d3dc3ad0d61302b26bff5a005d404f 100755 (executable)
@@ -1,128 +1,7 @@
 USING: help.markup help.syntax quotations hashtables kernel
-classes strings continuations destructors ;
+classes strings continuations destructors math ;
 IN: io
 
-ARTICLE: "stream-protocol" "Stream protocol"
-"The stream protocol consists of a large number of generic words, many of which are optional."
-$nl
-"Stream protocol words are rarely called directly, since code which only works with one stream at a time should be written use " { $link "stdio" } " instead, wrapping I/O operations such as " { $link read } " and " { $link write } " in " { $link with-input-stream } " and " { $link with-output-stream } "."
-$nl
-"All streams must implement the " { $link dispose } " word in addition to the stream protocol."
-$nl
-"Three words are required for input streams:"
-{ $subsection stream-read1 }
-{ $subsection stream-read }
-{ $subsection stream-read-until }
-{ $subsection stream-readln }
-"Seven words are required for output streams:"
-{ $subsection stream-flush }
-{ $subsection stream-write1 }
-{ $subsection stream-write }
-{ $subsection stream-format }
-{ $subsection stream-nl }
-{ $subsection make-span-stream }
-{ $subsection make-block-stream }
-{ $subsection make-cell-stream }
-{ $subsection stream-write-table }
-{ $see-also "io.timeouts" } ;
-
-ARTICLE: "stdio" "Default input and output streams"
-"Most I/O code only operates on one stream at a time. The " { $link input-stream } " and " { $link output-stream } " variables are implicit parameters used by many I/O words. Using this idiom improves code in three ways:"
-{ $list
-    { "Code becomes simpler because there is no need to keep a stream around on the stack." }
-    { "Code becomes more robust because " { $link with-input-stream } " and " { $link with-output-stream } " automatically close the streams if there is an error." }
-    { "Code becomes more reusable because it can be written to not worry about which stream is being used, and instead the caller can use " { $link with-input-stream } " or " { $link with-output-stream } " to specify the source or destination for I/O operations." }
-}
-"For example, here is a program which reads the first line of a file, converts it to an integer, then reads that many characters, and splits them into groups of 16:"
-{ $code
-    "USING: continuations kernel io io.files math.parser splitting ;"
-    "\"data.txt\" utf8 <file-reader>"
-    "dup stream-readln number>string over stream-read 16 group"
-    "swap dispose"
-}
-"This code has two problems: it has some unnecessary stack shuffling, and if either " { $link stream-readln } " or " { $link stream-read } " throws an I/O error, the stream is not closed because " { $link dispose } " is never reached. So we can add a call to " { $link with-disposal } " to ensure the stream is always closed:"
-{ $code
-    "USING: continuations kernel io io.files math.parser splitting ;"
-    "\"data.txt\" utf8 <file-reader> ["
-    "    dup stream-readln number>string over stream-read"
-    "    16 group"
-    "] with-disposal"
-}
-"This code is robust however it is more complex than it needs to be since. This is where the default stream words come in; using them, the above can be rewritten as follows:"
-{ $code
-    "USING: continuations kernel io io.files math.parser splitting ;"
-    "\"data.txt\" utf8 <file-reader> ["
-    "    readln number>string read 16 group"
-    "] with-input-stream"
-}
-"An even better implementation that takes advantage of a utility word:"
-{ $code
-    "USING: continuations kernel io io.files math.parser splitting ;"
-    "\"data.txt\" utf8 ["
-    "    readln number>string read 16 group"
-    "] with-file-reader"
-}
-"The default input stream is stored in a dynamically-scoped variable:"
-{ $subsection input-stream }
-"Unless rebound in a child namespace, this variable will be set to a console stream for reading input from the user."
-$nl
-"Words reading from the default input stream:"
-{ $subsection read1 }
-{ $subsection read }
-{ $subsection read-until }
-{ $subsection readln }
-"A pair of combinators for rebinding the " { $link input-stream } " variable:"
-{ $subsection with-input-stream }
-{ $subsection with-input-stream* }
-"The default output stream is stored in a dynamically-scoped variable:"
-{ $subsection output-stream }
-"Unless rebound in a child namespace, this variable will be set to a console stream for showing output to the user."
-$nl
-"Words writing to the default input stream:"
-{ $subsection flush }
-{ $subsection write1 }
-{ $subsection write }
-{ $subsection print }
-{ $subsection nl }
-{ $subsection bl }
-"Formatted output:"
-{ $subsection format }
-{ $subsection with-style }
-{ $subsection with-nesting }
-"Tabular output:"
-{ $subsection tabular-output }
-{ $subsection with-row }
-{ $subsection with-cell }
-{ $subsection write-cell }
-"A pair of combinators for rebinding the " { $link output-stream } " variable:"
-{ $subsection with-output-stream }
-{ $subsection with-output-stream* }
-"A pair of combinators for rebinding both default streams at once:"
-{ $subsection with-streams }
-{ $subsection with-streams* } ;
-
-ARTICLE: "stream-utils" "Stream utilities"
-"There are a few useful stream-related words which are not generic, but merely built up from the stream protocol."
-$nl
-"First, a simple composition of " { $link stream-write } " and " { $link stream-nl } ":"
-{ $subsection stream-print }
-"Sluring an entire stream into memory all at once:"
-{ $subsection lines }
-{ $subsection contents }
-"Copying the contents of one stream to another:"
-{ $subsection stream-copy } ;
-
-ARTICLE: "streams" "Streams"
-"Input and output centers on the concept of a " { $emphasis "stream" } ", which is a source or sink of characters. Streams also support formatted output, which may be used to present styled text in a manner independent of output medium."
-$nl
-"A stream can either be passed around on the stack or bound to a dynamic variable and used as an implicit " { $emphasis "default stream" } "."
-{ $subsection "stream-protocol" }
-{ $subsection "stdio" }
-{ $subsection "stream-utils" }
-{ $see-also "io.streams.string" "io.streams.plain" "io.streams.duplex" } ;
-
-ABOUT: "streams"
-
 HELP: stream-readln
 { $values { "stream" "an input stream" } { "str/f" "a string or " { $link f } } }
 { $contract "Reads a line of input from the stream. Outputs " { $link f } " on stream exhaustion." }
@@ -147,6 +26,12 @@ HELP: stream-read-until
 { $notes "Most code only works on one stream at a time and should instead use " { $link read-until } "; see " { $link "stdio" } "." }
 $io-error ;
 
+HELP: stream-read-partial
+{ $values
+     { "n" integer } { "stream" "an input stream" }
+     { "str/f" "a string or " { $link f } } }
+{ $description "Reads at most " { $snippet "n" } " characters from a stream and returns up to that many characters without blocking. If no characters are available, blocks until some are and returns them." } ;
+
 HELP: stream-write1
 { $values { "ch" "a character" } { "stream" "an output stream" } }
 { $contract "Writes a character of output to the stream. If the stream does buffering, output may not be performed immediately; use " { $link stream-flush } " to force output." }
@@ -249,6 +134,12 @@ HELP: read-until
 { $contract "Reads characters from " { $link input-stream } ". until the first occurrence of a separator character, or stream exhaustion. In the former case, the separator character is pushed on the stack, and is not part of the output string. In the latter case, the entire stream contents are output, along with " { $link f } "." }
 $io-error ;
 
+HELP: read-partial
+{ $values
+     { "n" null }
+     { "str/f" null } }
+{ $description "Reads at most " { $snippet "n" } " characters from " { $link input-stream } " and returns up to that many characters without blocking. If no characters are available, blocks until some are and returns them." } ;
+
 HELP: write1
 { $values { "ch" "a character" } }
 { $contract "Writes a character of output to " { $link output-stream } ". If the stream does buffering, output may not be performed immediately; use " { $link flush } " to force output." }
@@ -363,3 +254,126 @@ HELP: contents
 { $values { "stream" "an input stream" } { "str" string } }
 { $description "Reads the entire contents of a stream into a string." }
 $io-error ;
+
+ARTICLE: "stream-protocol" "Stream protocol"
+"The stream protocol consists of a large number of generic words, many of which are optional."
+$nl
+"Stream protocol words are rarely called directly, since code which only works with one stream at a time should be written use " { $link "stdio" } " instead, wrapping I/O operations such as " { $link read } " and " { $link write } " in " { $link with-input-stream } " and " { $link with-output-stream } "."
+$nl
+"All streams must implement the " { $link dispose } " word in addition to the stream protocol."
+$nl
+"These words are required for input streams:"
+{ $subsection stream-read1 }
+{ $subsection stream-read }
+{ $subsection stream-read-until }
+{ $subsection stream-readln }
+{ $subsection stream-read-partial }
+"These words are required for output streams:"
+{ $subsection stream-flush }
+{ $subsection stream-write1 }
+{ $subsection stream-write }
+{ $subsection stream-format }
+{ $subsection stream-nl }
+{ $subsection make-span-stream }
+{ $subsection make-block-stream }
+{ $subsection make-cell-stream }
+{ $subsection stream-write-table }
+{ $see-also "io.timeouts" } ;
+
+ARTICLE: "stdio" "Default input and output streams"
+"Most I/O code only operates on one stream at a time. The " { $link input-stream } " and " { $link output-stream } " variables are implicit parameters used by many I/O words. Using this idiom improves code in three ways:"
+{ $list
+    { "Code becomes simpler because there is no need to keep a stream around on the stack." }
+    { "Code becomes more robust because " { $link with-input-stream } " and " { $link with-output-stream } " automatically close the streams if there is an error." }
+    { "Code becomes more reusable because it can be written to not worry about which stream is being used, and instead the caller can use " { $link with-input-stream } " or " { $link with-output-stream } " to specify the source or destination for I/O operations." }
+}
+"For example, here is a program which reads the first line of a file, converts it to an integer, then reads that many characters, and splits them into groups of 16:"
+{ $code
+    "USING: continuations kernel io io.files math.parser splitting ;"
+    "\"data.txt\" utf8 <file-reader>"
+    "dup stream-readln number>string over stream-read 16 group"
+    "swap dispose"
+}
+"This code has two problems: it has some unnecessary stack shuffling, and if either " { $link stream-readln } " or " { $link stream-read } " throws an I/O error, the stream is not closed because " { $link dispose } " is never reached. So we can add a call to " { $link with-disposal } " to ensure the stream is always closed:"
+{ $code
+    "USING: continuations kernel io io.files math.parser splitting ;"
+    "\"data.txt\" utf8 <file-reader> ["
+    "    dup stream-readln number>string over stream-read"
+    "    16 group"
+    "] with-disposal"
+}
+"This code is robust however it is more complex than it needs to be since. This is where the default stream words come in; using them, the above can be rewritten as follows:"
+{ $code
+    "USING: continuations kernel io io.files math.parser splitting ;"
+    "\"data.txt\" utf8 <file-reader> ["
+    "    readln number>string read 16 group"
+    "] with-input-stream"
+}
+"An even better implementation that takes advantage of a utility word:"
+{ $code
+    "USING: continuations kernel io io.files math.parser splitting ;"
+    "\"data.txt\" utf8 ["
+    "    readln number>string read 16 group"
+    "] with-file-reader"
+}
+"The default input stream is stored in a dynamically-scoped variable:"
+{ $subsection input-stream }
+"Unless rebound in a child namespace, this variable will be set to a console stream for reading input from the user."
+$nl
+"Words reading from the default input stream:"
+{ $subsection read1 }
+{ $subsection read }
+{ $subsection read-until }
+{ $subsection readln }
+{ $subsection read-partial }
+"A pair of combinators for rebinding the " { $link input-stream } " variable:"
+{ $subsection with-input-stream }
+{ $subsection with-input-stream* }
+"The default output stream is stored in a dynamically-scoped variable:"
+{ $subsection output-stream }
+"Unless rebound in a child namespace, this variable will be set to a console stream for showing output to the user."
+$nl
+"Words writing to the default input stream:"
+{ $subsection flush }
+{ $subsection write1 }
+{ $subsection write }
+{ $subsection print }
+{ $subsection nl }
+{ $subsection bl }
+"Formatted output:"
+{ $subsection format }
+{ $subsection with-style }
+{ $subsection with-nesting }
+"Tabular output:"
+{ $subsection tabular-output }
+{ $subsection with-row }
+{ $subsection with-cell }
+{ $subsection write-cell }
+"A pair of combinators for rebinding the " { $link output-stream } " variable:"
+{ $subsection with-output-stream }
+{ $subsection with-output-stream* }
+"A pair of combinators for rebinding both default streams at once:"
+{ $subsection with-streams }
+{ $subsection with-streams* } ;
+
+ARTICLE: "stream-utils" "Stream utilities"
+"There are a few useful stream-related words which are not generic, but merely built up from the stream protocol."
+$nl
+"First, a simple composition of " { $link stream-write } " and " { $link stream-nl } ":"
+{ $subsection stream-print }
+"Sluring an entire stream into memory all at once:"
+{ $subsection lines }
+{ $subsection contents }
+"Copying the contents of one stream to another:"
+{ $subsection stream-copy } ;
+
+ARTICLE: "streams" "Streams"
+"Input and output centers on the concept of a " { $emphasis "stream" } ", which is a source or sink of characters. Streams also support formatted output, which may be used to present styled text in a manner independent of output medium."
+$nl
+"A stream can either be passed around on the stack or bound to a dynamic variable and used as an implicit " { $emphasis "default stream" } "."
+{ $subsection "stream-protocol" }
+{ $subsection "stdio" }
+{ $subsection "stream-utils" }
+{ $see-also "io.streams.string" "io.streams.plain" "io.streams.duplex" } ;
+
+ABOUT: "streams"
index 0d5a8574901cc857114b7332f9710a0327fa378a..c50fc6f46c6004c959a5799660412c05175fc7bd 100755 (executable)
@@ -8,7 +8,7 @@ GENERIC: stream-readln ( stream -- str/f )
 GENERIC: stream-read1 ( stream -- ch/f )
 GENERIC: stream-read ( n stream -- str/f )
 GENERIC: stream-read-until ( seps stream -- str/f sep/f )
-GENERIC: stream-read-partial ( max stream -- str/f )
+GENERIC: stream-read-partial ( n stream -- str/f )
 GENERIC: stream-write1 ( ch stream -- )
 GENERIC: stream-write ( str stream -- )
 GENERIC: stream-flush ( stream -- )
index c833325c41a293f98ba46301d7baa3c61b3d91c9..786919bb6852b8ebc91b33d673ac365772d342cc 100755 (executable)
@@ -4,289 +4,6 @@ kernel.private vectors combinators quotations strings words
 assocs arrays math.order ;
 IN: kernel
 
-ARTICLE: "shuffle-words" "Shuffle words"
-"Shuffle words rearrange items at the top of the data stack. They control the flow of data between words that perform actions."
-$nl
-"The " { $link "cleave-combinators" } " and " { $link "spread-combinators" } " are closely related to shuffle words and should be used instead where possible because they can result in clearer code; also, see the advice in " { $link "cookbook-philosophy" } "."
-$nl
-"Removing stack elements:"
-{ $subsection drop }
-{ $subsection 2drop }
-{ $subsection 3drop }
-{ $subsection nip }
-{ $subsection 2nip }
-"Duplicating stack elements:"
-{ $subsection dup }
-{ $subsection 2dup }
-{ $subsection 3dup }
-{ $subsection dupd }
-{ $subsection over }
-{ $subsection 2over }
-{ $subsection pick }
-{ $subsection tuck }
-"Permuting stack elements:"
-{ $subsection swap }
-{ $subsection swapd }
-{ $subsection rot }
-{ $subsection -rot }
-{ $subsection spin }
-{ $subsection roll }
-{ $subsection -roll }
-"Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using the following two words:"
-{ $subsection >r }
-{ $subsection r> }
-"The top of the data stack is ``hidden'' between " { $link >r } " and " { $link r> } ":"
-{ $example "1 2 3 >r .s r>" "1\n2" }
-"Usages of " { $link >r } " and " { $link r> } " must be balanced within a single quotation; quotations are not permitted to pop retain stack elements they did not push, or leave elements on the retain stack after returning."
-$nl
-"The " { $link "inference" } " tool checks retain stack usage. The " { $link "slip-keep-combinators" } " combinators abstract out common retain stack usage patterns." ;
-
-ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
-"Cleave combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to cleave combinators are discussed in the documentation for " { $link bi } ", " { $link 2bi } ", " { $link 3bi } ", " { $link tri } ", " { $link 2tri } " and " { $link 3tri } "."
-$nl
-"Certain shuffle words can also be expressed in terms of the cleave combinators. Internalizing such identities can help with understanding and writing code using cleave combinators:"
-{ $code
-    ": keep  [ ] bi ;"
-    ": 2keep [ ] 2bi ;"
-    ": 3keep [ ] 3bi ;"
-    ""
-    ": dup   [ ] [ ] bi ;"
-    ": 2dup  [ ] [ ] 2bi ;"
-    ": 3dup  [ ] [ ] 3bi ;"
-    ""
-    ": tuck  [ nip ] [ ] 2bi ;"
-    ": swap  [ nip ] [ drop ] 2bi ;"
-    ""
-    ": over  [ ] [ drop ] 2bi ;"
-    ": pick  [ ] [ 2drop ] 3bi ;"
-    ": 2over [ ] [ drop ] 3bi ;"
-} ;
-
-ARTICLE: "cleave-combinators" "Cleave combinators"
-"The cleave combinators apply multiple quotations to a single value."
-$nl
-"Two quotations:"
-{ $subsection bi }
-{ $subsection 2bi }
-{ $subsection 3bi }
-"Three quotations:"
-{ $subsection tri }
-{ $subsection 2tri }
-{ $subsection 3tri }
-"Technically, the cleave combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on the top of the stack can be written in one of two ways:"
-{ $code
-    "! First alternative; uses keep"
-    "[ 1 + ] keep"
-    "[ 1 - ] keep"
-    "2 *"
-    "! Second alternative: uses tri"
-    "[ 1 + ]"
-    "[ 1 - ]"
-    "[ 2 * ] tri"
-}
-"The latter is more aesthetically pleasing than the former."
-$nl
-"A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
-{ $subsection "cleave-shuffle-equivalence" } ;
-
-ARTICLE: "spread-shuffle-equivalence" "Expressing shuffle words with spread combinators"
-"Spread combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to spread combinators are discussed in the documentation for " { $link bi* } ", " { $link 2bi* } ", and " { $link tri* } "."
-$nl
-"Certain shuffle words can also be expressed in terms of the spread combinators. Internalizing such identities can help with understanding and writing code using spread combinators:"
-{ $code
-    ": dip   [ ] bi* ;"
-    ": 2dip  [ ] [ ] tri* ;"
-    ""
-    ": slip  [ call ] [ ] bi* ;"
-    ": 2slip [ call ] [ ] [ ] tri* ;"
-    ""
-    ": nip   [ drop ] [ ] bi* ;"
-    ": 2nip  [ drop ] [ drop ] [ ] tri* ;"
-    ""
-    ": rot"
-    "    [ [ drop ] [      ] [ drop ] tri* ]"
-    "    [ [ drop ] [ drop ] [      ] tri* ]"
-    "    [ [      ] [ drop ] [ drop ] tri* ]"
-    "    3tri ;"
-    ""
-    ": -rot"
-    "    [ [ drop ] [ drop ] [      ] tri* ]"
-    "    [ [      ] [ drop ] [ drop ] tri* ]"
-    "    [ [ drop ] [      ] [ drop ] tri* ]"
-    "    3tri ;"
-    ""
-    ": spin"
-    "    [ [ drop ] [ drop ] [      ] tri* ]"
-    "    [ [ drop ] [      ] [ drop ] tri* ]"
-    "    [ [      ] [ drop ] [ drop ] tri* ]"
-    "    3tri ;"
-} ;
-
-ARTICLE: "spread-combinators" "Spread combinators"
-"The spread combinators apply multiple quotations to multiple values. The " { $snippet "*" } " suffix signifies spreading."
-$nl
-"Two quotations:"
-{ $subsection bi* }
-{ $subsection 2bi* }
-"Three quotations:"
-{ $subsection tri* }
-"Technically, the spread combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on three related values can be written in one of two ways:"
-{ $code
-    "! First alternative; uses retain stack explicitly"
-    ">r >r 1 +"
-    "r> 1 -"
-    "r> 2 *"
-    "! Second alternative: uses tri*"
-    "[ 1 + ]"
-    "[ 1 - ]"
-    "[ 2 * ] tri*"
-}
-
-$nl
-"A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
-{ $subsection "spread-shuffle-equivalence" } ;
-
-ARTICLE: "apply-combinators" "Apply combinators"
-"The apply combinators apply a single quotation to multiple values. The " { $snippet "@" } " suffix signifies application."
-$nl
-"Two quotations:"
-{ $subsection bi@ }
-{ $subsection 2bi@ }
-"Three quotations:"
-{ $subsection tri@ }
-"A pair of utility words built from " { $link bi@ } ":"
-{ $subsection both? }
-{ $subsection either? } ;
-
-ARTICLE: "slip-keep-combinators" "The dip, slip and keep combinators"
-"The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
-{ $subsection dip }
-{ $subsection 2dip }
-"The slip combinators invoke a quotation further down on the stack. They are most useful for implementing other combinators:"
-{ $subsection slip }
-{ $subsection 2slip }
-{ $subsection 3slip }
-"The keep combinators invoke a quotation which takes a number of values off the stack, and then they restore those values:"
-{ $subsection keep }
-{ $subsection 2keep }
-{ $subsection 3keep } ;
-
-ARTICLE: "compositional-combinators" "Compositional combinators"
-"Quotations can be composed using efficient quotation-specific operations:"
-{ $subsection curry }
-{ $subsection 2curry }
-{ $subsection 3curry }
-{ $subsection with }
-{ $subsection compose }
-{ $subsection 3compose }
-{ $subsection prepose }
-"Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } "." ;
-
-ARTICLE: "implementing-combinators" "Implementing combinators"
-"The following pair of words invoke words and quotations reflectively:"
-{ $subsection call }
-{ $subsection execute }
-"These words are used to implement combinators. Note that combinator definitions must be followed by the " { $link POSTPONE: inline } " declaration in order to compile in the optimizing compiler; for example:"
-{ $code
-    ": keep ( x quot -- x )"
-    "    over >r call r> ; inline"
-}
-"Word inlining is documented in " { $link "declarations" } "." ;
-
-ARTICLE: "booleans" "Booleans"
-"In Factor, any object that is not " { $link f } " has a true value, and " { $link f } " has a false value. The " { $link t } " object is the canonical true value."
-{ $subsection f }
-{ $subsection t }
-"The " { $link f } " object is the unique instance of the " { $link f } " class; the two are distinct objects. The latter is also a parsing word which adds the " { $link f } " object to the parse tree at parse time. To refer to the class itself you must use " { $link POSTPONE: POSTPONE: } " or " { $link POSTPONE: \ } " to prevent the parsing word from executing."
-$nl
-"Here is the " { $link f } " object:"
-{ $example "f ." "f" }
-"Here is the " { $link f } " class:"
-{ $example "\\ f ." "POSTPONE: f" }
-"They are not equal:"
-{ $example "f \\ f = ." "f" }
-"Here is an array containing the " { $link f } " object:"
-{ $example "{ f } ." "{ f }" }
-"Here is an array containing the " { $link f } " class:"
-{ $example "{ POSTPONE: f } ." "{ POSTPONE: f }" }
-"The " { $link f } " object is an instance of the " { $link f } " class:"
-{ $example "f class ." "POSTPONE: f" }
-"The " { $link f } " class is an instance of " { $link word } ":"
-{ $example "\\ f class ." "word" }
-"On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
-{ $example "t \\ t eq? ." "t" }
-"Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ;
-
-ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic"
-"Certain simple conditional forms can be expressed in a simpler manner using boolean logic."
-$nl
-"The following two lines are equivalent:"
-{ $code "[ drop f ] unless" "swap and" }
-"The following two lines are equivalent:"
-{ $code "[ ] [ ] ?if" "swap or" }
-"The following two lines are equivalent, where " { $snippet "L" } " is a literal:"
-{ $code "[ L ] unless*" "L or" } ;
-
-ARTICLE: "conditionals" "Conditionals and logic"
-"The basic conditionals:"
-{ $subsection if }
-{ $subsection when }
-{ $subsection unless }
-"Forms abstracting a common stack shuffle pattern:"
-{ $subsection if* }
-{ $subsection when* }
-{ $subsection unless* }
-"Another form abstracting a common stack shuffle pattern:"
-{ $subsection ?if }
-"Sometimes instead of branching, you just need to pick one of two values:"
-{ $subsection ? }
-"There are some logical operations on booleans:"
-{ $subsection >boolean }
-{ $subsection not }
-{ $subsection and }
-{ $subsection or }
-{ $subsection xor }
-{ $subsection "conditionals-boolean-equivalence" }
-"See " { $link "combinators" } " for forms which abstract away common patterns involving multiple nested branches."
-{ $see-also "booleans" "bitwise-arithmetic" both? either? } ;
-
-ARTICLE: "equality" "Equality"
-"There are two distinct notions of ``sameness'' when it comes to objects."
-$nl
-"You can test if two references point to the same object (" { $emphasis "identity comparison" } "). This is rarely used; it is mostly useful with large, mutable objects where the object identity matters but the value is transient:"
-{ $subsection eq? }
-"You can test if two objects are equal in a domain-specific sense, usually by being instances of the same class, and having equal slot values (" { $emphasis "value comparison" } "):"
-{ $subsection = }
-"A third form of equality is provided by " { $link number= } ". It compares numeric value while disregarding types."
-$nl
-"Custom value comparison methods for use with " { $link = } " can be defined on a generic word:"
-{ $subsection equal? }
-"Utility class:"
-{ $subsection identity-tuple }
-"An object can be cloned; the clone has distinct identity but equal value:"
-{ $subsection clone } ;
-
-ARTICLE: "dataflow" "Data and control flow"
-{ $subsection "evaluator" }
-{ $subsection "words" }
-{ $subsection "effects" }
-{ $subsection "booleans" }
-{ $subsection "shuffle-words" }
-"A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
-{ $subsection "cleave-combinators" }
-{ $subsection "spread-combinators" }
-{ $subsection "apply-combinators" }
-{ $subsection "slip-keep-combinators" }
-{ $subsection "conditionals" }
-{ $subsection "compositional-combinators" }
-{ $subsection "combinators" }
-"Advanced topics:"
-{ $subsection "implementing-combinators" }
-{ $subsection "errors" }
-{ $subsection "continuations" } ;
-
-ABOUT: "dataflow"
-
 HELP: eq? ( obj1 obj2 -- ? )
 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
 { $description "Tests if two references point at the same object." } ;
@@ -827,100 +544,399 @@ HELP: 2curry
     { $example "USING: kernel math prettyprint ;" "5 4 [ + ] 2curry ." "[ 5 4 + ]" }
 } ;
 
-HELP: 3curry
-{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "quot" callable } { "curry" curry } }
-{ $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } ", " { $snippet "obj2" } " and " { $snippet "obj3" } ", and then calls " { $snippet "quot" } "." }
-{ $notes "This operation is efficient and does not copy the quotation." } ;
-
-HELP: with
-{ $values { "param" object } { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
-{ $description "Partial application on the left. The following two lines are equivalent:"
-    { $code "swap [ swap A ] curry B" }
-    { $code "[ A ] with B" }
-    
+HELP: 3curry
+{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "quot" callable } { "curry" curry } }
+{ $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } ", " { $snippet "obj2" } " and " { $snippet "obj3" } ", and then calls " { $snippet "quot" } "." }
+{ $notes "This operation is efficient and does not copy the quotation." } ;
+
+HELP: with
+{ $values { "param" object } { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
+{ $description "Partial application on the left. The following two lines are equivalent:"
+    { $code "swap [ swap A ] curry B" }
+    { $code "[ A ] with B" }
+    
+}
+{ $notes "This operation is efficient and does not copy the quotation." }
+{ $examples
+    { $example "USING: kernel math prettyprint sequences ;" "2 { 1 2 3 } [ - ] with map ." "{ 1 0 -1 }" }
+} ;
+
+HELP: compose
+{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
+{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
+{ $notes
+    "The two quotations must leave the retain stack in the same state on exit as it was on entry, so the following code is not allowed:"
+    { $code
+        "[ 3 >r ] [ r> . ] compose"
+    }
+    "Except for this restriction, the following two lines are equivalent:"
+    { $code
+        "compose call"
+        "append call"
+    }
+    "However, " { $link compose } " runs in constant time, and the optimizing compiler is able to compile code which calls composed quotations."
+} ;
+
+
+HELP: prepose
+{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
+{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot2" } " followed by " { $snippet "quot1" } "." }
+{ $notes "See " { $link compose } " for details." } ;
+
+{ compose prepose } related-words
+
+HELP: 3compose
+{ $values { "quot1" callable } { "quot2" callable } { "quot3" callable } { "compose" compose } }
+{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } ", " { $snippet "quot2" } " and then " { $snippet "quot3" } "." }
+{ $notes
+    "The three quotations must leave the retain stack in the same state on exit as it was on entry, so for example, the following code is not allowed:"
+    { $code
+        "[ >r ] swap [ r> ] 3compose"
+    }
+    "The correct way to achieve the effect of the above is the following:"
+    { $code
+        "[ dip ] curry"
+    }
+    "Excepting the retain stack restriction, the following two lines are equivalent:"
+    { $code
+        "3compose call"
+        "3append call"
+    }
+    "However, " { $link 3compose } " runs in constant time, and the compiler is able to compile code which calls composed quotations."
+} ;
+
+HELP: dip
+{ $values { "obj" object } { "quot" quotation } }
+{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj" } " hidden on the retain stack." }
+{ $notes "The following are equivalent:"
+    { $code ">r foo bar r>" }
+    { $code "[ foo bar ] dip" }
+} ;
+
+HELP: 2dip
+{ $values { "obj1" object } { "obj2" object } { "quot" quotation } }
+{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj1" } " and " { $snippet "obj2" } " hidden on the retain stack." }
+{ $notes "The following are equivalent:"
+    { $code ">r >r foo bar r> r>" }
+    { $code "[ foo bar ] 2dip" }
+} ;
+
+HELP: while
+{ $values { "pred" "a quotation with stack effect " { $snippet "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $description "Repeatedly calls " { $snippet "pred" } ". If it yields " { $link f } ", iteration stops, otherwise " { $snippet "body" } " is called. After iteration stops, " { $snippet "tail" } " is called." }
+{ $notes "In most cases, tail recursion should be used, because it is simpler both in terms of implementation and conceptually. However in some cases this combinator expresses intent better and should be used."
+$nl
+"Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
+{ $code
+    "[ P ] [ Q ] [ T ] while"
+    "[ P ] [ Q ] [ ] while T"
+}
+"However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference." } ;
+
+HELP: loop
+{ $values
+     { "pred" quotation } }
+{ $description "Calls the quotation repeatedly until the output is true." }
+{ $examples "Loop until we hit a zero:"
+    { $unchecked-example "USING: kernel random math io ; "
+    " [ \"hi\" write bl 10 random zero? not ] loop"
+    "hi hi hi" }
+    "A fun loop:"
+    { $example "USING: kernel prettyprint math ; "
+    "3 [ dup . 7 + 11 mod dup 3 = not ] loop"
+    "3\n10\n6\n2\n9\n5\n1\n8\n4\n0\n7" }
+} ;
+
+HELP: assert
+{ $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." } ;
+
+HELP: assert=
+{ $values { "a" object } { "b" object } }
+{ $description "Throws an " { $link assert } " error if " { $snippet "a" } " does not equal " { $snippet "b" } "." } ;
+
+
+ARTICLE: "shuffle-words" "Shuffle words"
+"Shuffle words rearrange items at the top of the data stack. They control the flow of data between words that perform actions."
+$nl
+"The " { $link "cleave-combinators" } " and " { $link "spread-combinators" } " are closely related to shuffle words and should be used instead where possible because they can result in clearer code; also, see the advice in " { $link "cookbook-philosophy" } "."
+$nl
+"Removing stack elements:"
+{ $subsection drop }
+{ $subsection 2drop }
+{ $subsection 3drop }
+{ $subsection nip }
+{ $subsection 2nip }
+"Duplicating stack elements:"
+{ $subsection dup }
+{ $subsection 2dup }
+{ $subsection 3dup }
+{ $subsection dupd }
+{ $subsection over }
+{ $subsection 2over }
+{ $subsection pick }
+{ $subsection tuck }
+"Permuting stack elements:"
+{ $subsection swap }
+{ $subsection swapd }
+{ $subsection rot }
+{ $subsection -rot }
+{ $subsection spin }
+{ $subsection roll }
+{ $subsection -roll }
+"Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using the following two words:"
+{ $subsection >r }
+{ $subsection r> }
+"The top of the data stack is ``hidden'' between " { $link >r } " and " { $link r> } ":"
+{ $example "1 2 3 >r .s r>" "1\n2" }
+"Usages of " { $link >r } " and " { $link r> } " must be balanced within a single quotation; quotations are not permitted to pop retain stack elements they did not push, or leave elements on the retain stack after returning."
+$nl
+"The " { $link "inference" } " tool checks retain stack usage. The " { $link "slip-keep-combinators" } " combinators abstract out common retain stack usage patterns." ;
+
+ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
+"Cleave combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to cleave combinators are discussed in the documentation for " { $link bi } ", " { $link 2bi } ", " { $link 3bi } ", " { $link tri } ", " { $link 2tri } " and " { $link 3tri } "."
+$nl
+"Certain shuffle words can also be expressed in terms of the cleave combinators. Internalizing such identities can help with understanding and writing code using cleave combinators:"
+{ $code
+    ": keep  [ ] bi ;"
+    ": 2keep [ ] 2bi ;"
+    ": 3keep [ ] 3bi ;"
+    ""
+    ": dup   [ ] [ ] bi ;"
+    ": 2dup  [ ] [ ] 2bi ;"
+    ": 3dup  [ ] [ ] 3bi ;"
+    ""
+    ": tuck  [ nip ] [ ] 2bi ;"
+    ": swap  [ nip ] [ drop ] 2bi ;"
+    ""
+    ": over  [ ] [ drop ] 2bi ;"
+    ": pick  [ ] [ 2drop ] 3bi ;"
+    ": 2over [ ] [ drop ] 3bi ;"
+} ;
+
+ARTICLE: "cleave-combinators" "Cleave combinators"
+"The cleave combinators apply multiple quotations to a single value."
+$nl
+"Two quotations:"
+{ $subsection bi }
+{ $subsection 2bi }
+{ $subsection 3bi }
+"Three quotations:"
+{ $subsection tri }
+{ $subsection 2tri }
+{ $subsection 3tri }
+"Technically, the cleave combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on the top of the stack can be written in one of two ways:"
+{ $code
+    "! First alternative; uses keep"
+    "[ 1 + ] keep"
+    "[ 1 - ] keep"
+    "2 *"
+    "! Second alternative: uses tri"
+    "[ 1 + ]"
+    "[ 1 - ]"
+    "[ 2 * ] tri"
+}
+"The latter is more aesthetically pleasing than the former."
+$nl
+"A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
+{ $subsection "cleave-shuffle-equivalence" } ;
+
+ARTICLE: "spread-shuffle-equivalence" "Expressing shuffle words with spread combinators"
+"Spread combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to spread combinators are discussed in the documentation for " { $link bi* } ", " { $link 2bi* } ", and " { $link tri* } "."
+$nl
+"Certain shuffle words can also be expressed in terms of the spread combinators. Internalizing such identities can help with understanding and writing code using spread combinators:"
+{ $code
+    ": dip   [ ] bi* ;"
+    ": 2dip  [ ] [ ] tri* ;"
+    ""
+    ": slip  [ call ] [ ] bi* ;"
+    ": 2slip [ call ] [ ] [ ] tri* ;"
+    ""
+    ": nip   [ drop ] [ ] bi* ;"
+    ": 2nip  [ drop ] [ drop ] [ ] tri* ;"
+    ""
+    ": rot"
+    "    [ [ drop ] [      ] [ drop ] tri* ]"
+    "    [ [ drop ] [ drop ] [      ] tri* ]"
+    "    [ [      ] [ drop ] [ drop ] tri* ]"
+    "    3tri ;"
+    ""
+    ": -rot"
+    "    [ [ drop ] [ drop ] [      ] tri* ]"
+    "    [ [      ] [ drop ] [ drop ] tri* ]"
+    "    [ [ drop ] [      ] [ drop ] tri* ]"
+    "    3tri ;"
+    ""
+    ": spin"
+    "    [ [ drop ] [ drop ] [      ] tri* ]"
+    "    [ [ drop ] [      ] [ drop ] tri* ]"
+    "    [ [      ] [ drop ] [ drop ] tri* ]"
+    "    3tri ;"
+} ;
+
+ARTICLE: "spread-combinators" "Spread combinators"
+"The spread combinators apply multiple quotations to multiple values. The " { $snippet "*" } " suffix signifies spreading."
+$nl
+"Two quotations:"
+{ $subsection bi* }
+{ $subsection 2bi* }
+"Three quotations:"
+{ $subsection tri* }
+"Technically, the spread combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on three related values can be written in one of two ways:"
+{ $code
+    "! First alternative; uses retain stack explicitly"
+    ">r >r 1 +"
+    "r> 1 -"
+    "r> 2 *"
+    "! Second alternative: uses tri*"
+    "[ 1 + ]"
+    "[ 1 - ]"
+    "[ 2 * ] tri*"
 }
-{ $notes "This operation is efficient and does not copy the quotation." }
-{ $examples
-    { $example "USING: kernel math prettyprint sequences ;" "2 { 1 2 3 } [ - ] with map ." "{ 1 0 -1 }" }
-} ;
 
-HELP: compose
-{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
-{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
-{ $notes
-    "The two quotations must leave the retain stack in the same state on exit as it was on entry, so the following code is not allowed:"
-    { $code
-        "[ 3 >r ] [ r> . ] compose"
-    }
-    "Except for this restriction, the following two lines are equivalent:"
-    { $code
-        "compose call"
-        "append call"
-    }
-    "However, " { $link compose } " runs in constant time, and the optimizing compiler is able to compile code which calls composed quotations."
-} ;
+$nl
+"A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
+{ $subsection "spread-shuffle-equivalence" } ;
 
+ARTICLE: "apply-combinators" "Apply combinators"
+"The apply combinators apply a single quotation to multiple values. The " { $snippet "@" } " suffix signifies application."
+$nl
+"Two quotations:"
+{ $subsection bi@ }
+{ $subsection 2bi@ }
+"Three quotations:"
+{ $subsection tri@ }
+"A pair of utility words built from " { $link bi@ } ":"
+{ $subsection both? }
+{ $subsection either? } ;
 
-HELP: prepose
-{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
-{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot2" } " followed by " { $snippet "quot1" } "." }
-{ $notes "See " { $link compose } " for details." } ;
+ARTICLE: "slip-keep-combinators" "The dip, slip and keep combinators"
+"The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
+{ $subsection dip }
+{ $subsection 2dip }
+"The slip combinators invoke a quotation further down on the stack. They are most useful for implementing other combinators:"
+{ $subsection slip }
+{ $subsection 2slip }
+{ $subsection 3slip }
+"The keep combinators invoke a quotation which takes a number of values off the stack, and then they restore those values:"
+{ $subsection keep }
+{ $subsection 2keep }
+{ $subsection 3keep } ;
 
-{ compose prepose } related-words
+ARTICLE: "compositional-combinators" "Compositional combinators"
+"Quotations can be composed using efficient quotation-specific operations:"
+{ $subsection curry }
+{ $subsection 2curry }
+{ $subsection 3curry }
+{ $subsection with }
+{ $subsection compose }
+{ $subsection 3compose }
+{ $subsection prepose }
+"Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } "." ;
 
-HELP: 3compose
-{ $values { "quot1" callable } { "quot2" callable } { "quot3" callable } { "compose" compose } }
-{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } ", " { $snippet "quot2" } " and then " { $snippet "quot3" } "." }
-{ $notes
-    "The three quotations must leave the retain stack in the same state on exit as it was on entry, so for example, the following code is not allowed:"
-    { $code
-        "[ >r ] swap [ r> ] 3compose"
-    }
-    "The correct way to achieve the effect of the above is the following:"
-    { $code
-        "[ dip ] curry"
-    }
-    "Excepting the retain stack restriction, the following two lines are equivalent:"
-    { $code
-        "3compose call"
-        "3append call"
-    }
-    "However, " { $link 3compose } " runs in constant time, and the compiler is able to compile code which calls composed quotations."
-} ;
+ARTICLE: "implementing-combinators" "Implementing combinators"
+"The following pair of words invoke words and quotations reflectively:"
+{ $subsection call }
+{ $subsection execute }
+"These words are used to implement combinators. Note that combinator definitions must be followed by the " { $link POSTPONE: inline } " declaration in order to compile in the optimizing compiler; for example:"
+{ $code
+    ": keep ( x quot -- x )"
+    "    over >r call r> ; inline"
+}
+"Word inlining is documented in " { $link "declarations" } "." ;
 
-HELP: dip
-{ $values { "obj" object } { "quot" quotation } }
-{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj" } " hidden on the retain stack." }
-{ $notes "The following are equivalent:"
-    { $code ">r foo bar r>" }
-    { $code "[ foo bar ] dip" }
-} ;
+ARTICLE: "booleans" "Booleans"
+"In Factor, any object that is not " { $link f } " has a true value, and " { $link f } " has a false value. The " { $link t } " object is the canonical true value."
+{ $subsection f }
+{ $subsection t }
+"The " { $link f } " object is the unique instance of the " { $link f } " class; the two are distinct objects. The latter is also a parsing word which adds the " { $link f } " object to the parse tree at parse time. To refer to the class itself you must use " { $link POSTPONE: POSTPONE: } " or " { $link POSTPONE: \ } " to prevent the parsing word from executing."
+$nl
+"Here is the " { $link f } " object:"
+{ $example "f ." "f" }
+"Here is the " { $link f } " class:"
+{ $example "\\ f ." "POSTPONE: f" }
+"They are not equal:"
+{ $example "f \\ f = ." "f" }
+"Here is an array containing the " { $link f } " object:"
+{ $example "{ f } ." "{ f }" }
+"Here is an array containing the " { $link f } " class:"
+{ $example "{ POSTPONE: f } ." "{ POSTPONE: f }" }
+"The " { $link f } " object is an instance of the " { $link f } " class:"
+{ $example "f class ." "POSTPONE: f" }
+"The " { $link f } " class is an instance of " { $link word } ":"
+{ $example "\\ f class ." "word" }
+"On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
+{ $example "t \\ t eq? ." "t" }
+"Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ;
 
-HELP: 2dip
-{ $values { "obj1" object } { "obj2" object } { "quot" quotation } }
-{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj1" } " and " { $snippet "obj2" } " hidden on the retain stack." }
-{ $notes "The following are equivalent:"
-    { $code ">r >r foo bar r> r>" }
-    { $code "[ foo bar ] 2dip" }
-} ;
+ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic"
+"Certain simple conditional forms can be expressed in a simpler manner using boolean logic."
+$nl
+"The following two lines are equivalent:"
+{ $code "[ drop f ] unless" "swap and" }
+"The following two lines are equivalent:"
+{ $code "[ ] [ ] ?if" "swap or" }
+"The following two lines are equivalent, where " { $snippet "L" } " is a literal:"
+{ $code "[ L ] unless*" "L or" } ;
 
-HELP: while
-{ $values { "pred" "a quotation with stack effect " { $snippet "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
-{ $description "Repeatedly calls " { $snippet "pred" } ". If it yields " { $link f } ", iteration stops, otherwise " { $snippet "body" } " is called. After iteration stops, " { $snippet "tail" } " is called." }
-{ $notes "In most cases, tail recursion should be used, because it is simpler both in terms of implementation and conceptually. However in some cases this combinator expresses intent better and should be used."
+ARTICLE: "conditionals" "Conditionals and logic"
+"The basic conditionals:"
+{ $subsection if }
+{ $subsection when }
+{ $subsection unless }
+"Forms abstracting a common stack shuffle pattern:"
+{ $subsection if* }
+{ $subsection when* }
+{ $subsection unless* }
+"Another form abstracting a common stack shuffle pattern:"
+{ $subsection ?if }
+"Sometimes instead of branching, you just need to pick one of two values:"
+{ $subsection ? }
+"There are some logical operations on booleans:"
+{ $subsection >boolean }
+{ $subsection not }
+{ $subsection and }
+{ $subsection or }
+{ $subsection xor }
+{ $subsection "conditionals-boolean-equivalence" }
+"See " { $link "combinators" } " for forms which abstract away common patterns involving multiple nested branches."
+{ $see-also "booleans" "bitwise-arithmetic" both? either? } ;
+
+ARTICLE: "equality" "Equality"
+"There are two distinct notions of ``sameness'' when it comes to objects."
 $nl
-"Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
-{ $code
-    "[ P ] [ Q ] [ T ] while"
-    "[ P ] [ Q ] [ ] while T"
-}
-"However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference." } ;
+"You can test if two references point to the same object (" { $emphasis "identity comparison" } "). This is rarely used; it is mostly useful with large, mutable objects where the object identity matters but the value is transient:"
+{ $subsection eq? }
+"You can test if two objects are equal in a domain-specific sense, usually by being instances of the same class, and having equal slot values (" { $emphasis "value comparison" } "):"
+{ $subsection = }
+"A third form of equality is provided by " { $link number= } ". It compares numeric value while disregarding types."
+$nl
+"Custom value comparison methods for use with " { $link = } " can be defined on a generic word:"
+{ $subsection equal? }
+"Utility class:"
+{ $subsection identity-tuple }
+"An object can be cloned; the clone has distinct identity but equal value:"
+{ $subsection clone } ;
 
-HELP: assert
-{ $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." } ;
+ARTICLE: "dataflow" "Data and control flow"
+{ $subsection "evaluator" }
+{ $subsection "words" }
+{ $subsection "effects" }
+{ $subsection "booleans" }
+{ $subsection "shuffle-words" }
+"A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
+{ $subsection "cleave-combinators" }
+{ $subsection "spread-combinators" }
+{ $subsection "apply-combinators" }
+{ $subsection "slip-keep-combinators" }
+{ $subsection "conditionals" }
+{ $subsection "compositional-combinators" }
+{ $subsection "combinators" }
+"Advanced topics:"
+{ $subsection "implementing-combinators" }
+{ $subsection "errors" }
+{ $subsection "continuations" } ;
+
+ABOUT: "dataflow"
 
-HELP: assert=
-{ $values { "a" object } { "b" object } }
-{ $description "Throws an " { $link assert } " error if " { $snippet "a" } " does not equal " { $snippet "b" } "." } ;
index 4788af1a914035e5b4940ab329aee8bc03a3e7eb..9522aa5a0bb37ee515bc48b61846a40ac53931c7 100755 (executable)
@@ -1,4 +1,4 @@
-! Copyright (C) 2007 Slava Pestov.
+! Copyright (C) 2007, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: namespaces math words kernel assocs classes
 math.order kernel.private ;
@@ -25,8 +25,14 @@ SYMBOL: type-numbers
 : tag-fixnum ( n -- tagged )
     tag-bits get shift ;
 
+! We do this in its own compilation unit so that they can be
+! folded below
+<<
 : cell ( -- n ) 7 getenv ; foldable
 
+: (first-bignum) ( m -- n ) tag-bits get - 1 - 2^ ; foldable
+>>
+
 : cells ( m -- n ) cell * ; inline
 
 : cell-bits ( -- n ) 8 cells ; inline
@@ -37,23 +43,20 @@ SYMBOL: type-numbers
 
 : bootstrap-cell-bits 8 bootstrap-cells ; inline
 
-: (first-bignum) ( m -- n )
-    tag-bits get - 1 - 2^ ;
-
 : first-bignum ( -- n )
-    cell-bits (first-bignum) ;
+    cell-bits (first-bignum) ; inline
 
 : most-positive-fixnum ( -- n )
-    first-bignum 1- ;
+    first-bignum 1- ; inline
 
 : most-negative-fixnum ( -- n )
-    first-bignum neg ;
+    first-bignum neg ; inline
 
 : (max-array-capacity) ( b -- n )
-    5 - 2^ 1- ;
+    5 - 2^ 1- ; inline
 
 : max-array-capacity ( -- n )
-    cell-bits (max-array-capacity) ;
+    cell-bits (max-array-capacity) ; inline
 
 : bootstrap-first-bignum ( -- n )
     bootstrap-cell-bits (first-bignum) ;
@@ -74,3 +77,5 @@ M: bignum >integer
 M: real >integer
     dup most-negative-fixnum most-positive-fixnum between?
     [ >fixnum ] [ >bignum ] if ;
+
+UNION: immediate fixnum POSTPONE: f ;
diff --git a/core/lexer/authors.txt b/core/lexer/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/core/lexer/summary.txt b/core/lexer/summary.txt
new file mode 100644 (file)
index 0000000..7c31988
--- /dev/null
@@ -0,0 +1 @@
+Factor source code lexer
diff --git a/core/make/authors.txt b/core/make/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/core/make/summary.txt b/core/make/summary.txt
new file mode 100644 (file)
index 0000000..e076241
--- /dev/null
@@ -0,0 +1 @@
+Sequence construction utility
diff --git a/core/make/tags.txt b/core/make/tags.txt
new file mode 100644 (file)
index 0000000..42d711b
--- /dev/null
@@ -0,0 +1 @@
+collections
index b38baa5cc925d1f64a3167c0e6ef723da809144e..a863715d33257e9049c5fd06f3b77a7e404363d0 100755 (executable)
@@ -2,64 +2,6 @@ USING: help.markup help.syntax kernel sequences quotations
 math.private ;
 IN: math
 
-ARTICLE: "division-by-zero" "Division by zero"
-"Floating point division never raises an error if the denominator is zero. This means that if at least one of the two inputs to " { $link / } ", " { $link /f } " or " { $link mod } " is a float, the result will be a floating point infinity or not a number value."
-$nl
-"The behavior of integer division is hardware specific. On x86 processors, " { $link /i } " and " { $link mod } " raise an error if both inputs are integers and the denominator is zero. On PowerPC, integer division by zero yields a result of zero."
-$nl
-"On the other hand, the " { $link / } " word, when given integer arguments, implements a much more expensive division algorithm which always yields an exact rational answer, and this word always tests for division by zero explicitly." ;
-
-ARTICLE: "number-protocol" "Number protocol"
-"Math operations obey certain numerical upgrade rules. If one of the inputs is a bignum and the other is a fixnum, the latter is first coerced to a bignum; if one of the inputs is a float, the other is coerced to a float."
-$nl
-"Two examples where you should note the types of the inputs and outputs:"
-{ $example "3 >fixnum 6 >bignum * class ." "bignum" }
-{ $example "1/2 2.0 + ." "4.5" }
-"The following usual operations are supported by all numbers."
-{ $subsection + }
-{ $subsection - }
-{ $subsection * }
-{ $subsection / }
-"Non-commutative operations take operands from the stack in the natural order; " { $snippet "6 2 /" } " divides 6 by 2."
-{ $subsection "division-by-zero" }
-"Real numbers (but not complex numbers) can be ordered:"
-{ $subsection < }
-{ $subsection <= }
-{ $subsection > }
-{ $subsection >= }
-"Numbers can be compared for equality using " { $link = } ", or a less precise test which disregards types:"
-{ $subsection number= } ;
-
-ARTICLE: "modular-arithmetic" "Modular arithmetic"
-{ $subsection mod }
-{ $subsection rem }
-{ $subsection /mod }
-{ $subsection /i }
-{ $see-also "integer-functions" } ;
-
-ARTICLE: "bitwise-arithmetic" "Bitwise arithmetic"
-"There are two ways of looking at an integer -- as an abstract mathematical entity, or as a string of bits. The latter representation motivates " { $emphasis "bitwise operations" } "."
-{ $subsection bitand }
-{ $subsection bitor }
-{ $subsection bitxor }
-{ $subsection bitnot }
-{ $subsection shift }
-{ $subsection 2/ }
-{ $subsection 2^ }
-{ $subsection bit? }
-{ $see-also "conditionals" } ;
-
-ARTICLE: "arithmetic" "Arithmetic"
-"Factor attempts to preserve natural mathematical semantics for numbers. Multiplying two large integers never results in overflow, and dividing two integers yields an exact ratio. Floating point numbers are also supported, along with complex numbers."
-$nl
-"Math words are in the " { $vocab-link "math" } " vocabulary. Implementation details are in the " { $vocab-link "math.private" } " vocabulary."
-{ $subsection "number-protocol" }
-{ $subsection "modular-arithmetic" }
-{ $subsection "bitwise-arithmetic" }
-{ $see-also "integers" "rationals" "floats" "complex-numbers" } ;
-
-ABOUT: "arithmetic"
-
 HELP: number=
 { $values { "x" number } { "y" number } { "?" "a boolean" } }
 { $description "Tests if two numbers have the same numeric value." }
@@ -235,6 +177,9 @@ HELP: 1-
     { $code "1-" "1 -" }
 } ;
 
+HELP: ?1+
+{ $description "If the input is not " { $link f } ", adds one. Otherwise, outputs a " { $snippet "0" } "." } ;
+
 HELP: sq
 { $values { "x" number } { "y" number } }
 { $description "Multiplies a number by itself." } ;
@@ -357,3 +302,62 @@ HELP: find-last-integer
 { $values { "n" integer } { "quot" "a quotation with stack effect " { $snippet "( i -- ? )" } } { "i" "an integer or " { $link f } } }
 { $description "Applies the quotation to each integer from " { $snippet "n" } " down to 0, inclusive. Iteration stops when the quotation outputs a true value or 0 is reached. If the quotation yields a true value for some integer, the word outputs that integer. Otherwise, the word outputs " { $link f } "." }
 { $notes "This word is used to implement " { $link find-last } "." } ;
+
+ARTICLE: "division-by-zero" "Division by zero"
+"Floating point division never raises an error if the denominator is zero. This means that if at least one of the two inputs to " { $link / } ", " { $link /f } " or " { $link mod } " is a float, the result will be a floating point infinity or not a number value."
+$nl
+"The behavior of integer division is hardware specific. On x86 processors, " { $link /i } " and " { $link mod } " raise an error if both inputs are integers and the denominator is zero. On PowerPC, integer division by zero yields a result of zero."
+$nl
+"On the other hand, the " { $link / } " word, when given integer arguments, implements a much more expensive division algorithm which always yields an exact rational answer, and this word always tests for division by zero explicitly." ;
+
+ARTICLE: "number-protocol" "Number protocol"
+"Math operations obey certain numerical upgrade rules. If one of the inputs is a bignum and the other is a fixnum, the latter is first coerced to a bignum; if one of the inputs is a float, the other is coerced to a float."
+$nl
+"Two examples where you should note the types of the inputs and outputs:"
+{ $example "3 >fixnum 6 >bignum * class ." "bignum" }
+{ $example "1/2 2.0 + ." "4.5" }
+"The following usual operations are supported by all numbers."
+{ $subsection + }
+{ $subsection - }
+{ $subsection * }
+{ $subsection / }
+"Non-commutative operations take operands from the stack in the natural order; " { $snippet "6 2 /" } " divides 6 by 2."
+{ $subsection "division-by-zero" }
+"Real numbers (but not complex numbers) can be ordered:"
+{ $subsection < }
+{ $subsection <= }
+{ $subsection > }
+{ $subsection >= }
+"Numbers can be compared for equality using " { $link = } ", or a less precise test which disregards types:"
+{ $subsection number= } ;
+
+ARTICLE: "modular-arithmetic" "Modular arithmetic"
+{ $subsection mod }
+{ $subsection rem }
+{ $subsection /mod }
+{ $subsection /i }
+{ $see-also "integer-functions" } ;
+
+ARTICLE: "bitwise-arithmetic" "Bitwise arithmetic"
+"There are two ways of looking at an integer -- as an abstract mathematical entity, or as a string of bits. The latter representation motivates " { $emphasis "bitwise operations" } "."
+{ $subsection bitand }
+{ $subsection bitor }
+{ $subsection bitxor }
+{ $subsection bitnot }
+{ $subsection shift }
+{ $subsection 2/ }
+{ $subsection 2^ }
+{ $subsection bit? }
+{ $see-also "conditionals" } ;
+
+ARTICLE: "arithmetic" "Arithmetic"
+"Factor attempts to preserve natural mathematical semantics for numbers. Multiplying two large integers never results in overflow, and dividing two integers yields an exact ratio. Floating point numbers are also supported, along with complex numbers."
+$nl
+"Math words are in the " { $vocab-link "math" } " vocabulary. Implementation details are in the " { $vocab-link "math.private" } " vocabulary."
+{ $subsection "number-protocol" }
+{ $subsection "modular-arithmetic" }
+{ $subsection "bitwise-arithmetic" }
+{ $see-also "integers" "rationals" "floats" "complex-numbers" } ;
+
+ABOUT: "arithmetic"
+
index cee2314d078325f981888f3414d3778b1a91fc2e..0fb2559854d5f06371321470d4f2c9d149b2024c 100755 (executable)
@@ -41,8 +41,8 @@ unit-test
 [ "-1.0e-2" string>number number>string ]
 unit-test
 
-[ "-1.0e-12" ]
-[ "-1.0e-12" string>number number>string ]
+[ t ]
+[ "-1.0e-12" string>number number>string { "-1.0e-12" "-1.0e-012" } member? ]
 unit-test
 
 [ f ]
@@ -108,3 +108,6 @@ unit-test
 [ -1.0/0.0 ] [ "-1/0." string>number ] unit-test
 
 [ "-0.0" ] [ -0.0 number>string ] unit-test
+
+[ "-3/4" ] [ -3/4 number>string ] unit-test
+[ "-1-1/4" ] [ -5/4 number>string ] unit-test
index 04d8fb6a413977e4bfd094554a685a0842d8f6f9..0134693761969ab845b793380d8dc524658fe4bc 100755 (executable)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2004, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math.private namespaces make sequences strings
-arrays combinators splitting math assocs ;
+USING: kernel math.private namespaces sequences strings
+arrays combinators splitting math assocs make ;
 IN: math.parser
 
 : digit> ( ch -- n )
@@ -94,10 +94,10 @@ PRIVATE>
 : >digit ( n -- ch )
     dup 10 < [ CHAR: 0 + ] [ 10 - CHAR: a + ] if ;
 
-: integer, ( num radix -- )
+: positive>base ( num radix -- str )
     dup 1 <= [ "Invalid radix" throw ] when
-    [ /mod >digit , ] keep over 0 >
-    [ integer, ] [ 2drop ] if ;
+    [ dup 0 > ] swap [ /mod >digit ] curry [ ] "" produce-as nip
+    dup reverse-here ; inline
 
 PRIVATE>
 
@@ -105,29 +105,32 @@ GENERIC# >base 1 ( n radix -- str )
 
 <PRIVATE
 
-: (>base) ( n -- str ) radix get >base ;
+: (>base) ( n -- str ) radix get positive>base ;
 
 PRIVATE>
 
 M: integer >base
-    [
-        over 0 < [
-            swap neg swap integer, CHAR: - ,
+    over 0 = [
+        2drop "0"
+    ] [
+        over 0 > [
+            positive>base
         ] [
-            integer,
+            [ neg ] dip positive>base CHAR: - prefix
         ] if
-    ] "" make reverse ;
+    ] if ;
 
 M: ratio >base
     [
+        dup 0 < negative? set
+        abs 1 /mod
+        [ dup zero? [ drop "" ] [ (>base) sign append ] if ]
         [
-            dup 0 < dup negative? set [ "-" % neg ] when
-            1 /mod
-            >r dup zero? [ drop ] [ (>base) % sign % ] if r>
-            dup numerator (>base) %
-            "/" %
-            denominator (>base) %
-        ] "" make
+            [ numerator (>base) ]
+            [ denominator (>base) ] bi
+            "/" swap 3append
+        ] bi* append
+        negative? get [ CHAR: - prefix ] when
     ] with-radix ;
 
 : fix-float ( str -- newstr )
index 506ae43671f7fa2a3ea5f663e7a85e2c4b1f00d3..fb1d4a336f32864c8d49fa1e46b068e4c9c008d7 100755 (executable)
@@ -1,19 +1,7 @@
-USING: help.markup help.syntax debugger sequences kernel ;
+USING: help.markup help.syntax debugger sequences kernel
+quotations math ;
 IN: memory
 
-ARTICLE: "images" "Images"
-"The current image can be saved; the image contains a complete dump of all data and code in the current Factor instance:"
-{ $subsection save }
-{ $subsection save-image }
-{ $subsection save-image-and-exit }
-"To start Factor with a custom image, use the " { $snippet "-i=" { $emphasis "image" } } " command line switch; see " { $link "runtime-cli-args" } "."
-$nl
-"New images can be created from scratch:"
-{ $subsection "bootstrap.image" }
-{ $see-also "tools.memory" "tools.deploy" } ;
-
-ABOUT: "images"
-
 HELP: begin-scan ( -- )
 { $description "Moves all objects to tenured space, disables the garbage collector, and resets the heap scan pointer to point at the first object in the heap. The " { $link next-object } " word can then be called to advance the heap scan pointer and return successive objects."
 $nl
@@ -67,3 +55,27 @@ HELP: save-image-and-exit ( path -- )
 
 HELP: save
 { $description "Saves a snapshot of the heap to the current image file." } ;
+
+HELP: count-instances
+{ $values
+     { "quot" quotation }
+     { "n" integer } }
+{ $description "Applies the predicate quotation to each object in the heap and returns the number of objects that match. Since this word uses " { $link each-object } " with the garbage collector switched off, avoid allocating too much memory in the quotation." }
+{ $examples { $unchecked-example
+    "USING: memory words prettyprint ;"
+    "[ word? ] count-instances ."
+    "24210"
+} } ;
+
+ARTICLE: "images" "Images"
+"The current image can be saved; the image contains a complete dump of all data and code in the current Factor instance:"
+{ $subsection save }
+{ $subsection save-image }
+{ $subsection save-image-and-exit }
+"To start Factor with a custom image, use the " { $snippet "-i=" { $emphasis "image" } } " command line switch; see " { $link "runtime-cli-args" } "."
+$nl
+"New images can be created from scratch:"
+{ $subsection "bootstrap.image" }
+{ $see-also "tools.memory" "tools.deploy" } ;
+
+ABOUT: "images"
index 9fded3eb3a6bafc45a81a5008a0c3cf4a50b4c6c..1c23e700ca0c661a89615faff135c41335bb15ab 100755 (executable)
@@ -1,4 +1,4 @@
-USING: generic kernel kernel.private math memory prettyprint
+USING: generic kernel kernel.private math memory prettyprint io
 sequences tools.test words namespaces layouts classes
 classes.builtin arrays quotations ;
 IN: memory.tests
@@ -19,6 +19,7 @@ TUPLE: testing x y z ;
 [ ] [
     num-types get [
         type>class [
+            dup . flush
             "predicate" word-prop instances [
                 class drop
             ] each
index 015e82f2c523410a372044e4434021fa5aa9612d..0a4974607dd6b7f4b99fc4ec90537cf170932b92 100755 (executable)
@@ -3,341 +3,91 @@ sequences.private vectors strings kernel math.order layouts
 quotations ;
 IN: sequences
 
-ARTICLE: "sequences-unsafe" "Unsafe sequence operations"
-"The " { $link nth-unsafe } " and " { $link set-nth-unsafe } " sequence protocol bypasses bounds checks for increased performance."
-$nl
-"These words assume the sequence index given is within bounds; if it is not, memory corruption can occur. Great care must be exercised when using these words. First, make sure the code in question is actually a bottleneck; next, try improving the algorithm first. If all else fails, then the unsafe sequence words can be used."
-$nl
-"There is a very important invariant these word must preserve: if at some point in time, the length of a sequence was " { $snippet "n" } ", then any future lookups of elements with indices below " { $snippet "n" } " must not crash the VM, even if the sequence length is now less than " { $snippet "n" } ". For example, vectors preserve this invariant by never shrinking the underlying storage, only growing it as necessary."
-$nl
-"The justification for this is that the VM should not crash if a resizable sequence is resized during the execution of an iteration combinator."
-$nl
-"Indeed, iteration combinators are the primary use-case for these words; if the iteration index is already guarded by a loop test which ensures it is within bounds, then additional bounds checks are redundant. For example, see the implementation of " { $link each } "." ;
+HELP: sequence
+{ $class-description "A mixin class whose instances are sequences. Custom implementations of the sequence protocol should be declared as instances of this mixin for all sequence functionality to work correctly:"
+    { $code "INSTANCE: my-sequence sequence" }
+} ;
 
-ARTICLE: "sequence-protocol" "Sequence protocol"
-"All sequences must be instances of a mixin class:"
-{ $subsection sequence }
-{ $subsection sequence? }
-"All sequences must know their length:"
-{ $subsection length }
-"At least one of the following two generic words must have a method for accessing elements; the " { $link sequence } " mixin has default definitions which are mutually recursive:"
-{ $subsection nth }
-{ $subsection nth-unsafe }
-"At least one of the following two generic words must have a method for storing elements; the " { $link sequence } " mixin has default definitions which are mutually recursive:"
-{ $subsection set-nth }
-{ $subsection set-nth-unsafe }
-"Note that even if the sequence is immutable, at least one of the generic words must be specialized, otherwise calling them will result in an infinite recursion. There is a standard word which throws an error indicating a sequence is immutable:"
-{ $subsection immutable }
-"The following two generic words are optional, as not all sequences are resizable:"
-{ $subsection set-length }
-{ $subsection lengthen }
-"An optional generic word for creating sequences of the same class as a given sequence:"
-{ $subsection like }
-"Optional generic words for optimization purposes:"
-{ $subsection new-sequence }
-{ $subsection new-resizable }
-{ $see-also "sequences-unsafe" } ;
+HELP: length
+{ $values { "seq" sequence } { "n" "a non-negative integer" } }
+{ $contract "Outputs the length of the sequence. All sequences support this operation." } ;
 
-ARTICLE: "sequences-integers" "Integer sequences and counted loops"
-"Integers support the sequence protocol in a trivial fashion; a non-negative integer presents its non-negative predecessors as elements. For example, the integer 3, when viewed as a sequence, contains the elements 0, 1, and 2. This is very useful for performing counted loops."
-$nl
-"For example, the " { $link each } " combinator, given an integer, simply calls a quotation that number of times, pushing a counter on each iteration that ranges from 0 up to that integer:"
-{ $example "3 [ . ] each" "0\n1\n2" }
-"A common idiom is to iterate over a sequence, while also maintaining a loop counter. This can be done using " { $link each-index } ", " { $link map-index } " and " { $link reduce-index } "."
-$nl
-"Combinators that produce new sequences, such as " { $link map } ", will output an array if the input is an integer." ;
+HELP: set-length
+{ $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } }
+{ $contract "Resizes the sequence. Not all sequences are resizable." }
+{ $errors "Throws a " { $link bounds-error } " if the new length is negative." }
+{ $side-effects "seq" } ;
 
-ARTICLE: "sequences-access" "Accessing sequence elements"
-{ $subsection ?nth }
-"Concise way of extracting one of the first four elements:"
-{ $subsection first }
-{ $subsection second }
-{ $subsection third }
-{ $subsection fourth }
-"Unpacking sequences:"
-{ $subsection first2 }
-{ $subsection first3 }
-{ $subsection first4 }
-{ $see-also nth peek } ;
+HELP: lengthen
+{ $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } }
+{ $contract "Ensures the sequence has a length of at least " { $snippet "n" } " elements. This word differs from " { $link set-length } " in two respects:"
+    { $list
+        { "This word does not shrink the sequence if " { $snippet "n" } " is less than its length." }
+        { "The word doubles the underlying storage of " { $snippet "seq" } ", whereas " { $link set-length } " is permitted to set it to equal " { $snippet "n" } ". This ensures that repeated calls to this word with constant increments of " { $snippet "n" } " do not result in a quadratic amount of copying, so that for example " { $link push-all } " can run efficiently when used in a loop." }
+    }
+} ;
 
-ARTICLE: "sequences-add-remove" "Adding and removing sequence elements"
-"Adding elements:"
-{ $subsection prefix }
-{ $subsection suffix }
-"Removing elements:"
-{ $subsection remove } ;
+HELP: nth
+{ $values { "n" "a non-negative integer" } { "seq" 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 a " { $link bounds-error } " if the index is negative, or greater than or equal to the length of the sequence." } ;
 
-ARTICLE: "sequences-reshape" "Reshaping sequences"
-"A " { $emphasis "repetition" } " is a virtual sequence consisting of a single element repeated multiple times:"
-{ $subsection repetition }
-{ $subsection <repetition> }
-"Reversing a sequence:"
-{ $subsection reverse }
-"A " { $emphasis "reversal" } " presents a reversed view of an underlying sequence:"
-{ $subsection reversed }
-{ $subsection <reversed> }
-"Transposing a matrix:"
-{ $subsection flip } ;
+HELP: set-nth
+{ $values { "elt" object } { "n" "a non-negative integer" } { "seq" "a mutable sequence" } }
+{ $contract "Sets the " { $snippet "n" } "th element of the sequence. Storing beyond the end of a resizable sequence such as a vector or string buffer grows the sequence." }
+{ $errors "Throws an error if the index is negative, or if the sequence is not resizable and the index is greater than or equal to the length of the sequence."
+$nl
+"Throws an error if the sequence cannot hold elements of the given type." }
+{ $side-effects "seq" } ;
 
-ARTICLE: "sequences-appending" "Appending sequences"
-{ $subsection append }
-{ $subsection prepend }
-{ $subsection 3append }
-{ $subsection concat }
-{ $subsection join }
-"A pair of words useful for aligning strings:"
-{ $subsection pad-left }
-{ $subsection pad-right } ;
+HELP: nths
+{ $values
+     { "indices" sequence } { "seq" sequence }
+     { "seq'" sequence } }
+{ $description "Ouptuts a sequence of elements from the input sequence indexed by the indices." }
+{ $examples 
+    { $example "USING: prettyprint sequences ;"
+               "{ 0 2 } { \"a\" \"b\" \"c\" } nths ."
+               "{ \"a\" \"c\" }"
+    }
+} ;
 
-ARTICLE: "sequences-slices" "Subsequences and slices"
-"Extracting a subsequence:"
-{ $subsection subseq }
-{ $subsection head }
-{ $subsection tail }
-{ $subsection head* }
-{ $subsection tail* }
-"Removing the first or last element:"
-{ $subsection rest }
-{ $subsection but-last }
-"Taking a sequence apart into a head and a tail:"
-{ $subsection unclip }
-{ $subsection unclip-last }
-{ $subsection cut }
-{ $subsection cut* }
-"A " { $emphasis "slice" } " is a virtual sequence which presents as view of a subsequence of an underlying sequence:"
-{ $subsection slice }
-{ $subsection slice? }
-"Creating slices:"
-{ $subsection <slice> }
-{ $subsection head-slice }
-{ $subsection tail-slice }
-{ $subsection but-last-slice }
-{ $subsection rest-slice }
-{ $subsection head-slice* }
-{ $subsection tail-slice* }
-"Taking a sequence apart into a head and a tail:"
-{ $subsection unclip-slice }
-{ $subsection cut-slice }
-"A utility for words which use slices as iterators:"
-{ $subsection <flat-slice> } ;
+HELP: immutable
+{ $values { "seq" sequence } }
+{ $description "Throws an " { $link immutable } " error." }
+{ $error-description "Thrown if an attempt is made to modify an immutable sequence." } ;
 
-ARTICLE: "sequences-combinators" "Sequence combinators"
-"Iteration:"
-{ $subsection each }
-{ $subsection reduce }
-{ $subsection interleave }
-{ $subsection replicate }
-{ $subsection replicate-as }
-"Mapping:"
-{ $subsection map }
-{ $subsection map-as }
-{ $subsection accumulate }
-{ $subsection produce }
-"Filtering:"
-{ $subsection push-if }
-{ $subsection filter }
-"Testing if a sequence contains elements satisfying a predicate:"
-{ $subsection contains? }
-{ $subsection all? }
-"Testing how elements are related:"
-{ $subsection monotonic? }
-{ $subsection "sequence-2combinators" } ;
+HELP: new-sequence
+{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a mutable sequence" } }
+{ $contract "Outputs a mutable sequence of length " { $snippet "n" } " which can hold the elements of " { $snippet "seq" } "." } ;
 
-ARTICLE: "sequence-2combinators" "Pair-wise sequence combinators"
-"There is a set of combinators which traverse two sequences pairwise. If one sequence is shorter than the other, than only the prefix having the length of the minimum of the two is examined."
-{ $subsection 2each }
-{ $subsection 2reduce }
-{ $subsection 2map }
-{ $subsection 2map-as }
-{ $subsection 2all? } ;
+HELP: new-resizable
+{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a resizable mutable sequence" } }
+{ $contract "Outputs a resizable mutable sequence with an initial capacity of " { $snippet "n" } " elements and zero length, which can hold the elements of " { $snippet "seq" } "." }
+{ $examples
+    { $example "USING: prettyprint sequences ;" "300 V{ } new-resizable ." "V{ }" }
+    { $example "USING: prettyprint sequences ;" "300 SBUF\" \" new-resizable ." "SBUF\" \"" }
+} ;
 
-ARTICLE: "sequences-tests" "Testing sequences"
-"Testing for an empty sequence:"
-{ $subsection empty? }
-"Testing indices:"
-{ $subsection bounds-check? }
-"Testing if a sequence contains an object:"
-{ $subsection member? }
-{ $subsection memq? }
-"Testing if a sequence contains a subsequence:"
-{ $subsection head? }
-{ $subsection tail? }
-{ $subsection subseq? }
-"Testing how elements are related:"
-{ $subsection all-eq? }
-{ $subsection all-equal? } ;
+HELP: like
+{ $values { "seq" sequence } { "exemplar" sequence } { "newseq" "a new sequence" } }
+{ $contract "Outputs a sequence with the same elements as " { $snippet "seq" } ", but " { $emphasis "like" } " the template sequence, in the sense that it either has the same class as the template sequence, or if the template sequence is a virtual sequence, the same class as the template sequence's underlying sequence."
+$nl
+"The default implementation does nothing." }
+{ $notes "Unlike " { $link clone-like } ", the output sequence might share storage with the input sequence." } ;
 
-ARTICLE: "sequences-search" "Searching sequences"
-"Finding the index of an element:"
-{ $subsection index }
-{ $subsection index-from }
-{ $subsection last-index }
-{ $subsection last-index-from }
-"Finding the start of a subsequence:"
-{ $subsection start }
-{ $subsection start* }
-"Finding the index of an element satisfying a predicate:"
-{ $subsection find }
-{ $subsection find-from }
-{ $subsection find-last }
-{ $subsection find-last-from } ;
+HELP: empty?
+{ $values { "seq" sequence } { "?" "a boolean" } }
+{ $description "Tests if the sequence has zero length." } ;
 
-ARTICLE: "sequences-trimming" "Trimming sequences"
-"Trimming words:"
-{ $subsection trim }
-{ $subsection trim-left }
-{ $subsection trim-right }
-"Potentially more efficient trim:"
-{ $subsection trim-slice }
-{ $subsection trim-left-slice }
-{ $subsection trim-right-slice } ;
-
-ARTICLE: "sequences-destructive" "Destructive operations"
-"These words modify their input, instead of creating a new sequence."
-$nl
-"In-place variant of " { $link reverse } ":"
-{ $subsection reverse-here }
-"In-place variant of " { $link append } ":"
-{ $subsection push-all }
-"In-place variant of " { $link remove } ":"
-{ $subsection delete }
-"In-place variant of " { $link map } ":"
-{ $subsection change-each }
-"Changing elements:"
-{ $subsection change-nth }
-{ $subsection cache-nth }
-"Deleting elements:"
-{ $subsection delete-nth }
-{ $subsection delete-slice }
-{ $subsection delete-all }
-"Other destructive words:"
-{ $subsection move }
-{ $subsection exchange }
-{ $subsection copy }
-{ $subsection replace-slice }
-{ $see-also set-nth push pop "sequences-stacks" } ;
-
-ARTICLE: "sequences-stacks" "Treating sequences as stacks"
-"The classical stack operations, modifying a sequence in place:"
-{ $subsection peek }
-{ $subsection push }
-{ $subsection pop }
-{ $subsection pop* }
-{ $see-also empty? } ;
-
-ARTICLE: "sequences-comparing" "Comparing sequences"
-"Element equality testing:"
-{ $subsection sequence= }
-{ $subsection mismatch }
-{ $subsection drop-prefix }
-"The " { $link <=> } " generic word performs lexicographic comparison when applied to sequences." ;
-
-ARTICLE: "sequences-f" "The f object as a sequence"
-"The " { $link f } " object supports the sequence protocol in a trivial way. It responds with a length of zero and throws an out of bounds error when an attempt is made to access elements." ;
-
-ARTICLE: "sequences" "Sequence operations"
-"A " { $emphasis "sequence" } " is a finite, linearly-ordered collection of elements. Words for working with sequences are in the " { $vocab-link "sequences" } " vocabulary."
-$nl
-"Sequences implement a protocol:"
-{ $subsection "sequence-protocol" }
-{ $subsection "sequences-f" }
-{ $subsection "sequences-integers" }
-"Sequence utility words can operate on any object whose class implements the sequence protocol. Most implementations are backed by storage. Some implementations obtain their elements from an underlying sequence, or compute them on the fly. These are known as " { $emphasis "virtual sequences" } "."
-{ $subsection "sequences-access" }
-{ $subsection "sequences-combinators" }
-{ $subsection "sequences-add-remove" }
-{ $subsection "sequences-appending" }
-{ $subsection "sequences-slices" }
-{ $subsection "sequences-reshape" }
-{ $subsection "sequences-tests" }
-{ $subsection "sequences-search" }
-{ $subsection "sequences-comparing" }
-{ $subsection "sequences-split" }
-{ $subsection "grouping" }
-{ $subsection "sequences-destructive" }
-{ $subsection "sequences-stacks" }
-{ $subsection "sequences-sorting" }
-{ $subsection "binary-search" }
-{ $subsection "sets" }
-{ $subsection "sequences-trimming" }
-"For inner loops:"
-{ $subsection "sequences-unsafe" } ;
-
-ABOUT: "sequences"
-
-HELP: sequence
-{ $class-description "A mixin class whose instances are sequences. Custom implementations of the sequence protocol should be declared as instances of this mixin for all sequence functionality to work correctly:"
-    { $code "INSTANCE: my-sequence sequence" }
-} ;
-
-HELP: length
-{ $values { "seq" sequence } { "n" "a non-negative integer" } }
-{ $contract "Outputs the length of the sequence. All sequences support this operation." } ;
-
-HELP: set-length
-{ $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } }
-{ $contract "Resizes the sequence. Not all sequences are resizable." }
-{ $errors "Throws a " { $link bounds-error } " if the new length is negative." }
-{ $side-effects "seq" } ;
-
-HELP: lengthen
-{ $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } }
-{ $contract "Ensures the sequence has a length of at least " { $snippet "n" } " elements. This word differs from " { $link set-length } " in two respects:"
-    { $list
-        { "This word does not shrink the sequence if " { $snippet "n" } " is less than its length." }
-        { "The word doubles the underlying storage of " { $snippet "seq" } ", whereas " { $link set-length } " is permitted to set it to equal " { $snippet "n" } ". This ensures that repeated calls to this word with constant increments of " { $snippet "n" } " do not result in a quadratic amount of copying, so that for example " { $link push-all } " can run efficiently when used in a loop." }
-    }
-} ;
-
-HELP: nth
-{ $values { "n" "a non-negative integer" } { "seq" 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 a " { $link bounds-error } " if the index is negative, or greater than or equal to the length of the sequence." } ;
-
-HELP: set-nth
-{ $values { "elt" object } { "n" "a non-negative integer" } { "seq" "a mutable sequence" } }
-{ $contract "Sets the " { $snippet "n" } "th element of the sequence. Storing beyond the end of a resizable sequence such as a vector or string buffer grows the sequence." }
-{ $errors "Throws an error if the index is negative, or if the sequence is not resizable and the index is greater than or equal to the length of the sequence."
-$nl
-"Throws an error if the sequence cannot hold elements of the given type." }
-{ $side-effects "seq" } ;
-
-HELP: immutable
-{ $values { "seq" sequence } }
-{ $description "Throws an " { $link immutable } " error." }
-{ $error-description "Thrown if an attempt is made to modify an immutable sequence." } ;
-
-HELP: new-sequence
-{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a mutable sequence" } }
-{ $contract "Outputs a mutable sequence of length " { $snippet "n" } " which can hold the elements of " { $snippet "seq" } "." } ;
-
-HELP: new-resizable
-{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a resizable mutable sequence" } }
-{ $contract "Outputs a resizable mutable sequence with an initial capacity of " { $snippet "n" } " elements and zero length, which can hold the elements of " { $snippet "seq" } "." }
-{ $examples
-    { $example "USING: prettyprint sequences ;" "300 V{ } new-resizable ." "V{ }" }
-    { $example "USING: prettyprint sequences ;" "300 SBUF\" \" new-resizable ." "SBUF\" \"" }
-} ;
-
-HELP: like
-{ $values { "seq" sequence } { "exemplar" sequence } { "newseq" "a new sequence" } }
-{ $contract "Outputs a sequence with the same elements as " { $snippet "seq" } ", but " { $emphasis "like" } " the template sequence, in the sense that it either has the same class as the template sequence, or if the template sequence is a virtual sequence, the same class as the template sequence's underlying sequence."
-$nl
-"The default implementation does nothing." }
-{ $notes "Unlike " { $link clone-like } ", the output sequence might share storage with the input sequence." } ;
-
-HELP: empty?
-{ $values { "seq" sequence } { "?" "a boolean" } }
-{ $description "Tests if the sequence has zero length." } ;
-
-HELP: if-empty
-{ $values { "seq" sequence } { "quot1" quotation } { "quot2" quotation } }
-{ $description "Makes an implicit check if the sequence is empty. An empty sequence is dropped and " { $snippet "quot1" } " is called. Otherwise, if the sequence has any elements, " { $snippet "quot2" } " is called on it." }
-{ $example
-    "USING: kernel prettyprint sequences ;"
-    "{ 1 2 3 } [ \"empty sequence\" ] [ sum ] if-empty ."
-    "6"
-} ;
+HELP: if-empty
+{ $values { "seq" sequence } { "quot1" quotation } { "quot2" quotation } }
+{ $description "Makes an implicit check if the sequence is empty. An empty sequence is dropped and " { $snippet "quot1" } " is called. Otherwise, if the sequence has any elements, " { $snippet "quot2" } " is called on it." }
+{ $example
+    "USING: kernel prettyprint sequences ;"
+    "{ 1 2 3 } [ \"empty sequence\" ] [ sum ] if-empty ."
+    "6"
+} ;
 
 HELP: when-empty
 { $values
@@ -511,6 +261,15 @@ HELP: reduce
     { $example "USING: math prettyprint sequences ;" "{ 1 5 3 } 0 [ + ] reduce ." "9" }
 } ;
 
+HELP: reduce-index
+{ $values
+     { "seq" sequence } { "identity" object } { "quot" quotation } }
+{ $description "Combines successive elements of the sequence and their indices binary operations, and outputs the final result. On the first iteration, the three inputs to the quotation are " { $snippet "identity" } ", the first element of the sequence, and its index, 0. On successive iterations, the first input is the result of the previous iteration, the second input is the corresponding element of the sequence, and the third is its index." }
+{ $examples { $example "USING: sequences prettyprint math ;"
+    "{ 10 50 90 } 0 [ + + ] reduce-index ."
+    "153"
+} } ;
+
 HELP: accumulate
 { $values { "identity" object } { "seq" sequence } { "quot" "a quotation with stack effect " { $snippet "( prev elt -- next )" } } { "final" "the final result" } { "newseq" "a new sequence" } }
 { $description "Combines successive elements of the sequence using a binary operation, and outputs a sequence of intermediate results together with the final result. On the first iteration, the two inputs to the quotation are " { $snippet "identity" } ", and the first element of the sequence. On successive iterations, the first input is the result of the previous iteration, and the second input is the corresponding element of the sequence."
@@ -533,6 +292,24 @@ HELP: map-as
     "Note that " { $link map } " could not be used here, because it would create another string to hold results, and one-element strings cannot themselves be elements of strings."
 } ;
 
+HELP: each-index
+{ $values
+     { "seq" sequence } { "quot" quotation } }
+{ $description "Calls the quotation with the element of the sequence and its index on the stack, with the index on the top of the stack." }
+{ $examples { $example "USING: sequences prettyprint math ;"
+"{ 10 20 30 } [ + . ] each-index"
+"10\n21\n32"
+} } ;
+
+HELP: map-index
+{ $values
+     { "seq" sequence } { "quot" quotation } }
+{ $description "Calls the quotation with the element of the sequence and its index on the stack, with the index on the top of the stack. Collects the outputs of the quotation and outputs them in a sequence of the same type as the input sequence." }
+{ $examples { $example "USING: sequences prettyprint math ;"
+"{ 10 20 30 } [ + ] map-index ."
+"{ 10 21 32 }"
+} } ;
+
 HELP: change-nth
 { $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" "a quotation with stack effect " { $snippet "( elt -- newelt )" } } }
 { $description "Applies the quotation to the " { $snippet "i" } "th element of the sequence, storing the result back into the sequence." }
@@ -674,6 +451,16 @@ HELP: remove
 { $values { "obj" object } { "seq" sequence } { "newseq" "a new sequence" } }
 { $description "Outputs a new sequence containing all elements of the input sequence except those equal to the given element." } ;
 
+HELP: remove-nth
+{ $values
+     { "n" integer } { "seq" sequence }
+     { "seq'" sequence } }
+{ $description "Creates a new sequence without the element at index " { $snippet "n" } "." }
+{ $examples "Notice that the original sequence is left intact:" { $example "USING: sequences prettyprint kernel ;"
+    "{ 1 2 3 } 1 over remove-nth . ."
+    "{ 1 3 }\n{ 1 2 3 }"
+} } ;
+
 HELP: move
 { $values { "from" "an index in " { $snippet "seq" } } { "to" "an index in " { $snippet "seq" } } { "seq" "a mutable sequence" } }
 { $description "Sets the element with index " { $snippet "m" } " to the element with index " { $snippet "n" } "." }
@@ -809,7 +596,8 @@ HELP: reverse
 
 HELP: <reversed> ( seq -- reversed )
 { $values { "seq" sequence } { "reversed" "a new sequence" } }
-{ $description "Creates an instance of the " { $link reversed } " virtual sequence." } ;
+{ $description "Creates an instance of the " { $link reversed } " class." }
+{ $see-also "virtual-sequences" } ;
 
 HELP: slice-error
 { $values { "str" "a reason" } }
@@ -999,7 +787,7 @@ HELP: tail?
 { delete-nth remove delete } related-words
 
 HELP: cut-slice
-{ $values { "seq" sequence } { "n" "a non-negative integer" } { "before" sequence } { "after" "a slice" } }
+{ $values { "seq" sequence } { "n" "a non-negative integer" } { "before-slice" sequence } { "after-slice" "a slice" } }
 { $description "Outputs a pair of sequences, where " { $snippet "before" } " consists of the first " { $snippet "n" } " elements of " { $snippet "seq" } " and has the same type, while " { $snippet "after" } " is a slice of the remaining elements." }
 { $notes "Unlike " { $link cut } ", the run time of this word is proportional to the length of " { $snippet "before" } ", not " { $snippet "after" } ", so it is suitable for use in an iterative algorithm which cuts successive pieces off a sequence." } ;
 
@@ -1036,7 +824,7 @@ HELP: unclip
 } ;
 
 HELP: unclip-slice
-{ $values { "seq" sequence } { "rest" slice } { "first" object } }
+{ $values { "seq" sequence } { "rest-slice" slice } { "first" object } }
 { $description "Outputs a tail sequence and the first element of " { $snippet "seq" } "; the tail sequence consists of all elements of " { $snippet "seq" } " but the first. Unlike " { $link unclip } ", this word does not make a copy of the input sequence, and runs in constant time." } ;
 
 HELP: unclip-last
@@ -1047,7 +835,7 @@ HELP: unclip-last
 } ;
 
 HELP: unclip-last-slice
-{ $values { "seq" sequence } { "butlast" slice } { "last" object } }
+{ $values { "seq" sequence } { "butlast-slice" slice } { "last" object } }
 { $description "Outputs a head sequence and the last element of " { $snippet "seq" } "; the head sequence consists of all elements of " { $snippet "seq" } " but the last Unlike " { $link unclip-last } ", this word does not make a copy of the input sequence, and runs in constant time." } ;
 
 HELP: sum
@@ -1278,3 +1066,455 @@ HELP: partition
         "{ 2 4 }\n{ 1 3 5 }"
     }
 } ;
+
+HELP: virtual-seq
+{ $values
+     { "seq" sequence }
+     { "seq'" sequence } }
+{ $description "Part of the virtual sequence protocol, this word is used to return an underlying array from which to look up a value at an index given by " { $link virtual@ } "." } ;
+
+HELP: virtual@
+{ $values
+     { "n" integer } { "seq" sequence }
+     { "n'" integer } { "seq'" sequence } }
+{ $description "Part of the sequence protocol, this word translates the input index " { $snippet "n" } " into an index into the underlying storage returned by " { $link virtual-seq } "." } ;
+
+HELP: 2change-each
+{ $values
+     { "seq1" sequence } { "seq2" sequence } { "quot" quotation } }
+{ $description "Calls the quotation on subsequent pairs of objects from the two input sequences. The resulting computation replaces the element in the first sequence." }
+{ $examples { $example "USING: kernel math sequences prettyprint ;"
+    "{ 10 20 30 } dup { 60 70 80 } [ + ] 2change-each ."
+    "{ 70 90 110 }"
+} } ;
+
+HELP: 2map-reduce
+{ $values
+     { "seq1" sequence } { "seq2" sequence } { "map-quot" quotation } { "reduce-quot" quotation }
+     { "result" object } }
+{ $description "Unclips the first element of each sequence and calls " { $snippet "map-quot" } " on both objects. The result of this calculation is passed, along with the rest of both sequences, to " { $link 2reduce } ", with the computed object as the identity." }
+{ $examples { $example "USING: sequences prettyprint math ;"
+    "{ 10 30 50 } { 200 400 600 } [ + ] [ + ] 2map-reduce ."
+    "1290"
+} } ;
+
+HELP: 2pusher
+{ $values
+     { "quot" quotation }
+     { "quot" quotation } { "accum1" vector } { "accum2" vector } }
+{ $description "Creates two new vectors to accumultate values based on a predicate. The first vector accumulates values for which the predicate yields true; the second for false." } ;
+
+HELP: 2reverse-each
+{ $values
+     { "seq1" sequence } { "seq2" sequence } { "quot" quotation } }
+{ $description "Reverse the sequences using the " { $link <reversed> } " word and calls " { $link 2each } " on the reversed sequences." }
+{ $examples { $example "USING: sequences math prettyprint ;"
+    "{ 10 20 30 } { 1 2 3 } [ + . ] 2reverse-each"
+    "33\n22\n11"
+} } ;
+
+HELP: 2unclip-slice
+{ $values
+     { "seq1" sequence } { "seq2" sequence }
+     { "rest-slice1" sequence } { "rest-slice2" sequence } { "first1" object } { "first2" object } }
+{ $description "Unclips the first element of each sequence and leaves two slice elements and the two unclipped objects on the stack." }
+{ $examples { $example "USING: sequences prettyprint kernel arrays ;"
+    "{ 1 2 } { 3 4 } 2unclip-slice 4array [ . ] each"
+    "T{ slice { from 1 } { to 2 } { seq { 1 2 } } }\nT{ slice { from 1 } { to 2 } { seq { 3 4 } } }\n1\n3"
+} } ;
+
+HELP: accumulator
+{ $values
+     { "quot" quotation }
+     { "quot'" quotation } { "vec" vector } }
+{ $description "Creates a new quotation that pushes its result to a vector and outputs that vector on the stack." }
+{ $examples { $example "USING: sequences prettyprint kernel math ;"
+    "{ 1 2 } [ 30 + ] accumulator [ each ] dip ."
+    "V{ 31 32 }"
+} } ;
+
+HELP: binary-reduce
+{ $values
+     { "seq" sequence } { "start" integer } { "quot" quotation }
+     { "value" object } }
+{ $description "Like " { $link reduce } ", but splits the sequence in half recursively until each sequence is small enough, and calls the quotation on these smaller sequences. If the quotation computes values that depend on the size of their input, such as bignum arithmetic, then this algorithm can be more efficient than using " { $link reduce } "." }
+{ $examples "Computing factorial:"
+    { $example "USING: prettyprint sequences math ;"
+    "40 rest-slice 1 [ * ] binary-reduce ."
+    "20397882081197443358640281739902897356800000000" }
+} ;
+
+HELP: follow
+{ $values
+     { "obj" object } { "quot" quotation }
+     { "seq" sequence } }
+{ $description "Outputs a sequence containing the input object and all of the objects generated by successively feeding the result of the quotation called on the input object to the quotation recursuively. Objects yielded by the quotation are added to the output sequence until the quotation yields " { $link f } ", at which point the recursion terminates." }
+{ $examples "Get random numbers until zero is reached:"
+    { $unchecked-example
+    "USING: random sequences prettyprint math ;"
+    "100 [ random dup zero? [ drop f ] when ] follow ."
+    "{ 100 86 34 32 24 11 7 2 }"
+} } ;
+
+HELP: halves
+{ $values
+     { "seq" sequence }
+     { "first-slice" slice } { "second-slice" slice } }
+{ $description "Splits a sequence into two slices at the midpoint. If the sequence has an odd number of elements, the extra element is returned in the second slice." }
+{ $examples { $example "USING: arrays sequences prettyprint kernel ;"
+    "{ 1 2 3 4 5 } halves [ >array . ] bi@"
+    "{ 1 2 }\n{ 3 4 5 }"
+} } ;
+
+HELP: indices
+{ $values
+     { "obj" object } { "seq" sequence }
+     { "indices" sequence } }
+{ $description "Compares the input object to every element in the sequence and returns a vector containing the index of every position where the element was found." }
+{ $examples { $example "USING: sequences prettyprint ;"
+    "2 { 2 4 2 6 2 8 2 10 } indices ."
+    "V{ 0 2 4 6 }"
+} } ;
+
+HELP: insert-nth
+{ $values
+     { "elt" object } { "n" integer } { "seq" sequence }
+     { "seq'" sequence } }
+{ $description "Creates a new sequence where the " { $snippet "n" } "th index is set to the input object." }
+{ $examples { $example "USING: prettyprint sequences ;"
+    "40 3 { 10 20 30 50 } insert-nth ."
+    "{ 10 20 30 40 50 }"
+} } ;
+
+HELP: map-reduce
+{ $values
+     { "seq" sequence } { "map-quot" quotation } { "reduce-quot" quotation }
+     { "result" object } }
+{ $description "Unclips the first element of the sequence, calls " { $snippet "map-quot" } " on that element, and proceeds like a " { $link reduce } ", where the calculated element is the identity element and the rest of the sequence is the sequence to reduce." }
+{ $examples { $example "USING: sequences prettyprint math ;"
+    "{ 1 3 5 } [ sq ] [ + ] map-reduce ."
+    "35"
+} } ;
+
+HELP: new-like
+{ $values
+     { "len" integer } { "exemplar" "an exemplar sequence" } { "quot" quotation }
+     { "seq" sequence } }
+{ $description "Creates a new sequence of length " { $snippet "len" } " and calls the quotation with this sequence on the stack. The output of the quotation and the original exemplar are then passed to " { $link like } " so that the output sequence is the exemplar's type." } ;
+
+HELP: push-either
+{ $values
+     { "elt" object } { "quot" quotation } { "accum1" vector } { "accum2" vector } }
+{ $description "Pushes the input object onto one of the accumualators; the first if the quotation yields true, the second if false." } ;
+
+HELP: sequence-hashcode
+{ $values
+     { "n" integer } { "seq" sequence }
+     { "x" integer } }
+{ $description "Iterates over a sequence, computes a hashcode with " { $link hashcode* } " for each element, and combines them using " { $link sequence-hashcode-step } "." } ;
+
+HELP: sequence-hashcode-step
+{ $values
+     { "oldhash" integer } { "newpart" integer }
+     { "newhash" integer } }
+{ $description "An implementation word that computes a running hashcode of a sequence using some bit-twiddling. The resulting hashcode is always a fixnum." } ;
+
+HELP: short
+{ $values
+     { "seq" sequence } { "n" integer }
+     { "seq" sequence } { "n'" integer } }
+{ $description "Returns the input sequence and its length or " { $snippet "n" } ", whichever is less." }
+{ $examples { $example "USING: sequences kernel prettyprint ;"
+    "\"abcd\" 3 short [ . ] bi@"
+    "\"abcd\"\n3"
+} } ;
+
+HELP: shorten
+{ $values
+     { "n" integer } { "seq" sequence } }
+{ $description "Shortens a " { $link "growable" } " sequence to by " { $snippet "n" } " elements long." }
+{ $examples { $example "USING: sequences prettyprint kernel ;"
+    "V{ 1 2 3 4 5 } 3 over shorten ."
+    "V{ 1 2 3 }"
+} } ;
+
+ARTICLE: "sequences-unsafe" "Unsafe sequence operations"
+"The " { $link nth-unsafe } " and " { $link set-nth-unsafe } " sequence protocol bypasses bounds checks for increased performance."
+$nl
+"These words assume the sequence index given is within bounds; if it is not, memory corruption can occur. Great care must be exercised when using these words. First, make sure the code in question is actually a bottleneck; next, try improving the algorithm first. If all else fails, then the unsafe sequence words can be used."
+$nl
+"There is a very important invariant these word must preserve: if at some point in time, the length of a sequence was " { $snippet "n" } ", then any future lookups of elements with indices below " { $snippet "n" } " must not crash the VM, even if the sequence length is now less than " { $snippet "n" } ". For example, vectors preserve this invariant by never shrinking the underlying storage, only growing it as necessary."
+$nl
+"The justification for this is that the VM should not crash if a resizable sequence is resized during the execution of an iteration combinator."
+$nl
+"Indeed, iteration combinators are the primary use-case for these words; if the iteration index is already guarded by a loop test which ensures it is within bounds, then additional bounds checks are redundant. For example, see the implementation of " { $link each } "." ;
+
+ARTICLE: "sequence-protocol" "Sequence protocol"
+"All sequences must be instances of a mixin class:"
+{ $subsection sequence }
+{ $subsection sequence? }
+"All sequences must know their length:"
+{ $subsection length }
+"At least one of the following two generic words must have a method for accessing elements; the " { $link sequence } " mixin has default definitions which are mutually recursive:"
+{ $subsection nth }
+{ $subsection nth-unsafe }
+"Note that sequences are always indexed starting from zero."
+$nl
+"At least one of the following two generic words must have a method for storing elements; the " { $link sequence } " mixin has default definitions which are mutually recursive:"
+{ $subsection set-nth }
+{ $subsection set-nth-unsafe }
+"Note that even if the sequence is immutable, at least one of the generic words must be specialized, otherwise calling them will result in an infinite recursion. There is a standard word which throws an error indicating a sequence is immutable:"
+{ $subsection immutable }
+"The following two generic words are optional, as not all sequences are resizable:"
+{ $subsection set-length }
+{ $subsection lengthen }
+"An optional generic word for creating sequences of the same class as a given sequence:"
+{ $subsection like }
+"Optional generic words for optimization purposes:"
+{ $subsection new-sequence }
+{ $subsection new-resizable }
+{ $see-also "sequences-unsafe" } ;
+
+ARTICLE: "virtual-sequences-protocol" "Virtual sequence protocol"
+"Virtual sequences must know their length:"
+{ $subsection length }
+"The underlying sequence to look up a value in:"
+{ $subsection virtual-seq }
+"The index of the value in the underlying sequence:"
+{ $subsection virtual@ } ;
+
+ARTICLE: "virtual-sequences" "Virtual sequences"
+"Virtual sequences allow different ways of accessing a sequence without having to create a new sequence or a new data structure altogether. To do this, they translate the virtual index into a normal index into an underlying sequence using the " { $link "virtual-sequences-protocol" } "."
+{ $subsection "virtual-sequences-protocol" } ;
+
+ARTICLE: "sequences-integers" "Integer sequences and counted loops"
+"Integers support the sequence protocol in a trivial fashion; a non-negative integer presents its non-negative predecessors as elements. For example, the integer 3, when viewed as a sequence, contains the elements 0, 1, and 2. This is very useful for performing counted loops."
+$nl
+"For example, the " { $link each } " combinator, given an integer, simply calls a quotation that number of times, pushing a counter on each iteration that ranges from 0 up to that integer:"
+{ $example "3 [ . ] each" "0\n1\n2" }
+"A common idiom is to iterate over a sequence, while also maintaining a loop counter. This can be done using " { $link each-index } ", " { $link map-index } " and " { $link reduce-index } "."
+$nl
+"Combinators that produce new sequences, such as " { $link map } ", will output an array if the input is an integer." ;
+
+ARTICLE: "sequences-access" "Accessing sequence elements"
+{ $subsection ?nth }
+"Concise way of extracting one of the first four elements:"
+{ $subsection first }
+{ $subsection second }
+{ $subsection third }
+{ $subsection fourth }
+"Unpacking sequences:"
+{ $subsection first2 }
+{ $subsection first3 }
+{ $subsection first4 }
+{ $see-also nth peek } ;
+
+ARTICLE: "sequences-add-remove" "Adding and removing sequence elements"
+"Adding elements:"
+{ $subsection prefix }
+{ $subsection suffix }
+"Removing elements:"
+{ $subsection remove }
+{ $subsection remove-nth } ;
+
+ARTICLE: "sequences-reshape" "Reshaping sequences"
+"A " { $emphasis "repetition" } " is a virtual sequence consisting of a single element repeated multiple times:"
+{ $subsection repetition }
+{ $subsection <repetition> }
+"Reversing a sequence:"
+{ $subsection reverse }
+"A " { $emphasis "reversal" } " presents a reversed view of an underlying sequence:"
+{ $subsection reversed }
+{ $subsection <reversed> }
+"Transposing a matrix:"
+{ $subsection flip } ;
+
+ARTICLE: "sequences-appending" "Appending sequences"
+{ $subsection append }
+{ $subsection prepend }
+{ $subsection 3append }
+{ $subsection concat }
+{ $subsection join }
+"A pair of words useful for aligning strings:"
+{ $subsection pad-left }
+{ $subsection pad-right } ;
+
+ARTICLE: "sequences-slices" "Subsequences and slices"
+"Extracting a subsequence:"
+{ $subsection subseq }
+{ $subsection head }
+{ $subsection tail }
+{ $subsection head* }
+{ $subsection tail* }
+"Removing the first or last element:"
+{ $subsection rest }
+{ $subsection but-last }
+"Taking a sequence apart into a head and a tail:"
+{ $subsection unclip }
+{ $subsection unclip-last }
+{ $subsection cut }
+{ $subsection cut* }
+"A " { $emphasis "slice" } " is a virtual sequence which presents as view of a subsequence of an underlying sequence:"
+{ $subsection slice }
+{ $subsection slice? }
+"Extracting a slice:"
+{ $subsection <slice> }
+{ $subsection head-slice }
+{ $subsection tail-slice }
+{ $subsection head-slice* }
+{ $subsection tail-slice* }
+"Removing the first or last element:"
+{ $subsection rest-slice }
+{ $subsection but-last-slice }
+"Taking a sequence apart into a head and a tail:"
+{ $subsection unclip-slice }
+{ $subsection unclip-last-slice }
+{ $subsection cut-slice }
+"A utility for words which use slices as iterators:"
+{ $subsection <flat-slice> } ;
+
+ARTICLE: "sequences-combinators" "Sequence combinators"
+"Iteration:"
+{ $subsection each }
+{ $subsection each-index }
+{ $subsection reduce }
+{ $subsection interleave }
+{ $subsection replicate }
+{ $subsection replicate-as }
+"Mapping:"
+{ $subsection map }
+{ $subsection map-as }
+{ $subsection map-index }
+{ $subsection accumulate }
+{ $subsection produce }
+"Filtering:"
+{ $subsection push-if }
+{ $subsection filter }
+"Testing if a sequence contains elements satisfying a predicate:"
+{ $subsection contains? }
+{ $subsection all? }
+"Testing how elements are related:"
+{ $subsection monotonic? }
+{ $subsection "sequence-2combinators" } ;
+
+ARTICLE: "sequence-2combinators" "Pair-wise sequence combinators"
+"There is a set of combinators which traverse two sequences pairwise. If one sequence is shorter than the other, than only the prefix having the length of the minimum of the two is examined."
+{ $subsection 2each }
+{ $subsection 2reduce }
+{ $subsection 2map }
+{ $subsection 2map-as }
+{ $subsection 2all? } ;
+
+ARTICLE: "sequences-tests" "Testing sequences"
+"Testing for an empty sequence:"
+{ $subsection empty? }
+"Testing indices:"
+{ $subsection bounds-check? }
+"Testing if a sequence contains an object:"
+{ $subsection member? }
+{ $subsection memq? }
+"Testing if a sequence contains a subsequence:"
+{ $subsection head? }
+{ $subsection tail? }
+{ $subsection subseq? }
+"Testing how elements are related:"
+{ $subsection all-eq? }
+{ $subsection all-equal? } ;
+
+ARTICLE: "sequences-search" "Searching sequences"
+"Finding the index of an element:"
+{ $subsection index }
+{ $subsection index-from }
+{ $subsection last-index }
+{ $subsection last-index-from }
+"Finding the start of a subsequence:"
+{ $subsection start }
+{ $subsection start* }
+"Finding the index of an element satisfying a predicate:"
+{ $subsection find }
+{ $subsection find-from }
+{ $subsection find-last }
+{ $subsection find-last-from } ;
+
+ARTICLE: "sequences-trimming" "Trimming sequences"
+"Trimming words:"
+{ $subsection trim }
+{ $subsection trim-left }
+{ $subsection trim-right }
+"Potentially more efficient trim:"
+{ $subsection trim-slice }
+{ $subsection trim-left-slice }
+{ $subsection trim-right-slice } ;
+
+ARTICLE: "sequences-destructive" "Destructive operations"
+"These words modify their input, instead of creating a new sequence."
+$nl
+"In-place variant of " { $link reverse } ":"
+{ $subsection reverse-here }
+"In-place variant of " { $link append } ":"
+{ $subsection push-all }
+"In-place variant of " { $link remove } ":"
+{ $subsection delete }
+"In-place variant of " { $link map } ":"
+{ $subsection change-each }
+"Changing elements:"
+{ $subsection change-nth }
+{ $subsection cache-nth }
+"Deleting elements:"
+{ $subsection delete-nth }
+{ $subsection delete-slice }
+{ $subsection delete-all }
+"Other destructive words:"
+{ $subsection move }
+{ $subsection exchange }
+{ $subsection copy }
+{ $subsection replace-slice }
+{ $see-also set-nth push pop "sequences-stacks" } ;
+
+ARTICLE: "sequences-stacks" "Treating sequences as stacks"
+"The classical stack operations, modifying a sequence in place:"
+{ $subsection peek }
+{ $subsection push }
+{ $subsection pop }
+{ $subsection pop* }
+{ $see-also empty? } ;
+
+ARTICLE: "sequences-comparing" "Comparing sequences"
+"Element equality testing:"
+{ $subsection sequence= }
+{ $subsection mismatch }
+{ $subsection drop-prefix }
+"The " { $link <=> } " generic word performs lexicographic comparison when applied to sequences." ;
+
+ARTICLE: "sequences-f" "The f object as a sequence"
+"The " { $link f } " object supports the sequence protocol in a trivial way. It responds with a length of zero and throws an out of bounds error when an attempt is made to access elements." ;
+
+ARTICLE: "sequences" "Sequence operations"
+"A " { $emphasis "sequence" } " is a finite, linearly-ordered collection of elements. Words for working with sequences are in the " { $vocab-link "sequences" } " vocabulary."
+$nl
+"Sequences implement a protocol:"
+{ $subsection "sequence-protocol" }
+{ $subsection "sequences-f" }
+{ $subsection "sequences-integers" }
+"Sequence utility words can operate on any object whose class implements the sequence protocol. Most implementations are backed by storage. Some implementations obtain their elements from an underlying sequence, or compute them on the fly. These are known as " { $link "virtual-sequences" } "."
+{ $subsection "sequences-access" }
+{ $subsection "sequences-combinators" }
+{ $subsection "sequences-add-remove" }
+{ $subsection "sequences-appending" }
+{ $subsection "sequences-slices" }
+{ $subsection "sequences-reshape" }
+{ $subsection "sequences-tests" }
+{ $subsection "sequences-search" }
+{ $subsection "sequences-comparing" }
+{ $subsection "sequences-split" }
+{ $subsection "grouping" }
+{ $subsection "sequences-destructive" }
+{ $subsection "sequences-stacks" }
+{ $subsection "sequences-sorting" }
+{ $subsection "binary-search" }
+{ $subsection "sets" }
+{ $subsection "sequences-trimming" }
+"For inner loops:"
+{ $subsection "sequences-unsafe" } ;
+
+ABOUT: "sequences"
index 6cda7fc73f2e9c4ae654c327408c449b2c404099..267238a50281050c3e15e3f849afba9591c79b53 100755 (executable)
@@ -289,6 +289,8 @@ M: immutable-sequence clone-like like ;
 
 : push-all ( src dest -- ) [ length ] [ copy ] bi ;
 
+<PRIVATE
+
 : ((append)) ( seq1 seq2 accum -- accum )
     [ >r over length r> copy ]
     [ 0 swap copy ] 
@@ -304,6 +306,8 @@ M: immutable-sequence clone-like like ;
         [ ((append)) ] bi
     ] new-like ; inline
 
+PRIVATE>
+
 : append ( seq1 seq2 -- newseq ) over (append) ;
 
 : prepend ( seq1 seq2 -- newseq ) swap append ; inline
@@ -402,7 +406,7 @@ PRIVATE>
 : 2map ( seq1 seq2 quot -- newseq )
     pick 2map-as ; inline
 
-: 2change-each ( seq1 seq2 quot -- newseq )
+: 2change-each ( seq1 seq2 quot -- )
     pick 2map-into ; inline
 
 : 2all? ( seq1 seq2 quot -- ? )
@@ -450,8 +454,11 @@ PRIVATE>
 : accumulator ( quot -- quot' vec )
     V{ } clone [ [ push ] curry compose ] keep ; inline
 
+: produce-as ( pred quot tail exemplar -- seq )
+    >r swap accumulator >r swap while r> r> like ; inline
+
 : produce ( pred quot tail -- seq )
-    swap accumulator >r swap while r> { } like ; inline
+    { } produce-as ; inline
 
 : follow ( obj quot -- seq )
     >r [ dup ] r> [ keep ] curry [ ] produce nip ; inline
@@ -543,6 +550,8 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
     2over number=
     [ 3drop ] [ [ nth swap ] [ set-nth ] bi ] if ; inline
 
+<PRIVATE
+
 : (delete) ( elt store scan seq -- elt store scan seq )
     2dup length < [
         3dup move
@@ -550,6 +559,8 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
         [ >r >r 1+ r> r> ] unless >r 1+ r> (delete)
     ] when ;
 
+PRIVATE>
+
 : delete ( elt seq -- ) 0 0 rot (delete) nip set-length drop ;
 
 : prefix ( seq elt -- newseq )
@@ -568,6 +579,8 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
 
 : pop* ( seq -- ) [ length 1- ] [ shorten ] bi ;
 
+<PRIVATE
+
 : move-backward ( shift from to seq -- )
     2over number= [
         2drop 2drop
@@ -591,6 +604,8 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
         >r >r over - r> r> move-backward
     ] if ;
 
+PRIVATE>
+
 : open-slice ( shift from seq -- )
     pick zero? [
         3drop
@@ -650,9 +665,13 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
         first like
     ] if-empty ;
 
+<PRIVATE
+
 : joined-length ( seq glue -- n )
     >r dup sum-lengths swap length 1 [-] r> length * + ;
 
+PRIVATE>
+
 : join ( seq glue -- newseq )
     [
         2dup joined-length over new-resizable spin
@@ -671,7 +690,7 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
 : pad-right ( seq n elt -- padded )
     [ append ] padding ;
 
-: shorter? ( seq1 seq2 -- ? ) >r length r> length < ;
+: shorter? ( seq1 seq2 -- ? ) [ length ] bi@ < ;
 
 : head? ( seq begin -- ? )
     2dup shorter? [
@@ -687,7 +706,7 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
         tuck length tail-slice* sequence=
     ] if ;
 
-: cut-slice ( seq n -- before after )
+: cut-slice ( seq n -- before-slice after-slice )
     [ head-slice ] [ tail-slice ] 2bi ;
 
 : insert-nth ( elt n seq -- seq' )
@@ -695,7 +714,7 @@ M: slice equal? over slice? [ sequence= ] [ 2drop f ] if ;
 
 : midpoint@ ( seq -- n ) length 2/ ; inline
 
-: halves ( seq -- first second )
+: halves ( seq -- first-slice second-slice )
     dup midpoint@ cut-slice ;
 
 : binary-reduce ( seq start quot: ( elt1 elt2 -- newelt ) -- value )
@@ -749,10 +768,10 @@ PRIVATE>
 : unclip-last ( seq -- butlast last )
     [ but-last ] [ peek ] bi ;
 
-: unclip-slice ( seq -- rest first )
+: unclip-slice ( seq -- rest-slice first )
     [ rest-slice ] [ first ] bi ; inline
 
-: 2unclip-slice ( seq1 seq2 -- seq1' seq2' elt1 elt2 )
+: 2unclip-slice ( seq1 seq2 -- rest-slice1 rest-slice2 first1 first2 )
     [ unclip-slice ] bi@ swapd ; inline
 
 : map-reduce ( seq map-quot reduce-quot -- result )
@@ -763,7 +782,7 @@ PRIVATE>
     [ [ 2unclip-slice ] dip [ call ] keep ] dip
     compose 2reduce ; inline
 
-: unclip-last-slice ( seq -- butlast last )
+: unclip-last-slice ( seq -- butlast-slice last )
     [ but-last-slice ] [ peek ] bi ; inline
 
 : <flat-slice> ( seq -- slice )
index b3fa649dd13af08cf040120a1361a2bd087b3cdb..5f7f4acf7accf00cfdae4ab1bfe5869b6fb6119c 100644 (file)
@@ -1,4 +1,4 @@
-USING: kernel help.markup help.syntax sequences ;
+USING: kernel help.markup help.syntax sequences quotations ;
 IN: sets
 
 ARTICLE: "sets" "Set-theoretic operations on sequences"
@@ -111,3 +111,9 @@ HELP: subset?
 HELP: set=
 { $values { "seq1" sequence } { "seq2" sequence } { "?" "a boolean" } }
 { $description "Tests if both sequences contain the same elements, disregrading order and duplicates." } ;
+
+HELP: gather
+{ $values
+     { "seq" sequence } { "quot" quotation }
+     { "newseq" sequence } }
+{ $description "Maps a quotation onto a sequence, concatenates the results of the mapping, and removes duplicates." } ;
index 8d2a9080d4ba8911963af25976ab665e40510552..88e47d5309433da87916eeaca3ba25585fdb8de7 100755 (executable)
@@ -23,7 +23,8 @@ $nl
 "Since strings are sequences, basic string manipulation can be performed using sequence operations (" { $link "sequences" } "). More advanced functionality can be found in other vocabularies, including but not limited to:"
 { $list
     { { $vocab-link "ascii" } " - traditional ASCII character classes" }
-    { { $vocab-link "unicode" } " - Unicode 5.0-aware character classes, case conversion, word breaks, ..." }
+    { { $vocab-link "unicode.categories" } " - Unicode character classes" }
+    { { $vocab-link "unicode.case" } " - Unicode case conversion" }
     { { $vocab-link "regexp" } " - regular expressions" }
     { { $vocab-link "peg" } " - parser expression grammars" }
 } ;
index cd76967e5ae4d199d06cbf84a6c6dabb4827ae03..2b7de36d562b8f0bfdd796e474af463092740305 100755 (executable)
@@ -519,7 +519,7 @@ HELP: UNION:
 HELP: INTERSECTION:
 { $syntax "INTERSECTION: class participants... ;" }
 { $values { "class" "a new class word to define" } { "participants" "a list of class words separated by whitespace" } }
-{ $description "Defines an intersection class. An object is an instance of a union class if it is an instance of all of its participants." } ;
+{ $description "Defines an intersection class. An object is an instance of an intersection class if it is an instance of all of its participants." } ;
 
 HELP: MIXIN:
 { $syntax "MIXIN: class" }
@@ -573,12 +573,12 @@ $nl
 } ;
 
 HELP: initial:
-{ $syntax "TUPLE: ... { \"slot\" initial: value } ... ;" }
+{ $syntax "TUPLE: ... { slot initial: value } ... ;" }
 { $values { "slot" "a slot name" } { "value" "any literal" } }
 { $description "Specifies an initial value for a tuple slot." } ;
 
 HELP: read-only
-{ $syntax "TUPLE: ... { \"slot\" read-only } ... ;" }
+{ $syntax "TUPLE: ... { slot read-only } ... ;" }
 { $values { "slot" "a slot name" } }
 { $description "Defines a tuple slot to be read-only. If a tuple has read-only slots, instances of the tuple should only be created by calling " { $link boa } ", instead of " { $link new } ". Using " { $link boa } " is the only way to set the value of a read-only slot." } ;
 
index 98dc605acc967c2abbda96a8faadc6e963ae3732..3c207c4ab5bf5c97513e11da101d334533b96383 100755 (executable)
@@ -55,15 +55,15 @@ UNION: unix bsd solaris linux ;
 
 PRIVATE>
 
+: image ( -- path ) \ image get-global ;
+
+: vm ( -- path ) \ vm get-global ;
+
 [
     8 getenv string>cpu \ cpu set-global
     9 getenv string>os \ os set-global
 ] "system" add-init-hook
 
-: image ( -- path ) 13 getenv ;
-
-: vm ( -- path ) 14 getenv ;
-
 : embedded? ( -- ? ) 15 getenv ;
 
 : os-envs ( -- assoc )
diff --git a/extra/benchmark/regex-dna/regex-dna-test-in.txt b/extra/benchmark/regex-dna/regex-dna-test-in.txt
new file mode 100644 (file)
index 0000000..fb23263
--- /dev/null
@@ -0,0 +1,1671 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC
+CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT
+GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC
+GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA
+GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA
+GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA
+GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG
+AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT
+CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA
+GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA
+AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC
+GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT
+ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG
+GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC
+GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC
+GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG
+TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA
+AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG
+GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT
+CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC
+TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG
+ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC
+GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA
+ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA
+CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA
+CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA
+ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG
+CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG
+AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC
+CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG
+AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC
+CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG
+CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG
+CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG
+CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC
+ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA
+AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC
+TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC
+ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG
+CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG
+AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT
+AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA
+TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC
+CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA
+TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG
+CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT
+GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG
+GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG
+CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG
+GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG
+GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT
+AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT
+GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT
+CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG
+GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC
+TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT
+CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG
+ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG
+CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG
+AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA
+CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG
+CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC
+ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC
+GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC
+GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG
+GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT
+TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG
+CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA
+GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG
+CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC
+GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG
+CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA
+CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG
+CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA
+ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC
+CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT
+GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA
+AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG
+ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC
+TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA
+GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC
+GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG
+TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC
+AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA
+ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA
+GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC
+AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG
+TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC
+CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT
+GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC
+CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA
+GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT
+TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC
+ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC
+TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG
+GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG
+TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG
+GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC
+GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT
+ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC
+GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC
+GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC
+CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA
+ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG
+AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC
+TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT
+CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG
+TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG
+CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC
+GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT
+GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC
+CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC
+TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG
+CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG
+AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG
+AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG
+AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT
+GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA
+TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC
+AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA
+AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG
+CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC
+TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG
+GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT
+CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG
+CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG
+GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA
+AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA
+GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC
+TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC
+CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA
+GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG
+CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG
+AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG
+ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC
+ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC
+AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC
+GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG
+GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT
+CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC
+GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC
+CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA
+GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA
+GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG
+GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT
+CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA
+AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG
+CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC
+CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG
+GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG
+GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT
+TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA
+ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG
+CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA
+ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA
+GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG
+TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC
+GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA
+GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT
+GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT
+GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG
+TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT
+TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC
+TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC
+GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT
+CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC
+TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA
+GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG
+GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT
+GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT
+ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG
+GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG
+CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA
+CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT
+CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC
+GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC
+TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG
+GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC
+AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG
+GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG
+CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG
+GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG
+ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG
+GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA
+AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC
+CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG
+TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA
+AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG
+GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA
+CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG
+AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG
+CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG
+GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT
+CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA
+AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG
+AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC
+CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT
+GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA
+CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG
+TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA
+CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC
+AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC
+TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA
+CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC
+CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA
+GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC
+GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA
+GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC
+CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC
+TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC
+CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC
+CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA
+CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA
+AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT
+GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA
+CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC
+TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA
+GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA
+GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT
+CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC
+TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT
+CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC
+CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG
+GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG
+GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC
+GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG
+GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGG
+TGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTA
+ATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTG
+CAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTC
+AAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGG
+GCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCT
+CTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTC
+GGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGA
+TCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGC
+GCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGA
+GGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATAC
+AAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGC
+AGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCA
+CTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACG
+CCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCG
+AGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGG
+GCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTT
+GAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGC
+GACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAG
+CACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGC
+CAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCG
+CGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGC
+GGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGAC
+TCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGC
+CGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAA
+CCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCC
+AGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTG
+AGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC
+CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT
+GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC
+GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA
+GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA
+GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA
+GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG
+AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT
+CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA
+GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA
+AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC
+GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT
+ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG
+GAGGCTGAGGCAGGAGAATC
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+aagacYRcaggattHaYgtKtaatgcVcaataMYacccatatcacgWDBtgaatcBaata
+cKcttRaRtgatgaBDacggtaattaaYtataStgVHDtDctgactcaaatKtacaatgc
+gYatBtRaDatHaactgtttatatDttttaaaKVccYcaaccNcBcgHaaVcattHctcg
+attaaatBtatgcaaaaatYMctSactHatacgaWacattacMBgHttcgaatVaaaaca
+BatatVtctgaaaaWtctRacgBMaatSgRgtgtcgactatcRtattaScctaStagKga
+DcWgtYtDDWKRgRtHatRtggtcgaHgggcgtattaMgtcagccaBggWVcWctVaaat
+tcgNaatcKWagcNaHtgaaaSaaagctcYctttRVtaaaatNtataaccKtaRgtttaM
+tgtKaBtRtNaggaSattHatatWactcagtgtactaKctatttgRYYatKatgtccgtR
+tttttatttaatatVgKtttgtatgtNtataRatWYNgtRtHggtaaKaYtKSDcatcKg
+taaYatcSRctaVtSMWtVtRWHatttagataDtVggacagVcgKWagBgatBtaaagNc
+aRtagcataBggactaacacRctKgttaatcctHgDgttKHHagttgttaatgHBtatHc
+DaagtVaBaRccctVgtgDtacRHSctaagagcggWYaBtSaKtHBtaaactYacgNKBa
+VYgtaacttagtVttcttaatgtBtatMtMtttaattaatBWccatRtttcatagVgMMt
+agctStKctaMactacDNYgKYHgaWcgaHgagattacVgtttgtRaSttaWaVgataat
+gtgtYtaStattattMtNgWtgttKaccaatagNYttattcgtatHcWtctaaaNVYKKt
+tWtggcDtcgaagtNcagatacgcattaagaccWctgcagcttggNSgaNcHggatgtVt
+catNtRaaBNcHVagagaaBtaaSggDaatWaatRccaVgggStctDaacataKttKatt
+tggacYtattcSatcttagcaatgaVBMcttDattctYaaRgatgcattttNgVHtKcYR
+aatRKctgtaaacRatVSagctgtWacBtKVatctgttttKcgtctaaDcaagtatcSat
+aWVgcKKataWaYttcccSaatgaaaacccWgcRctWatNcWtBRttYaattataaNgac
+acaatagtttVNtataNaYtaatRaVWKtBatKagtaatataDaNaaaaataMtaagaaS
+tccBcaatNgaataWtHaNactgtcDtRcYaaVaaaaaDgtttRatctatgHtgttKtga
+aNSgatactttcgagWaaatctKaaDaRttgtggKKagcDgataaattgSaacWaVtaNM
+acKtcaDaaatttctRaaVcagNacaScRBatatctRatcctaNatWgRtcDcSaWSgtt
+RtKaRtMtKaatgttBHcYaaBtgatSgaSWaScMgatNtctcctatttctYtatMatMt
+RRtSaattaMtagaaaaStcgVgRttSVaScagtgDtttatcatcatacRcatatDctta
+tcatVRtttataaHtattcYtcaaaatactttgVctagtaaYttagatagtSYacKaaac
+gaaKtaaatagataatSatatgaaatSgKtaatVtttatcctgKHaatHattagaaccgt
+YaaHactRcggSBNgtgctaaBagBttgtRttaaattYtVRaaaattgtaatVatttctc
+ttcatgBcVgtgKgaHaaatattYatagWacNctgaaMcgaattStagWaSgtaaKagtt
+ttaagaDgatKcctgtaHtcatggKttVDatcaaggtYcgccagNgtgcVttttagagat
+gctaccacggggtNttttaSHaNtatNcctcatSaaVgtactgBHtagcaYggYVKNgta
+KBcRttgaWatgaatVtagtcgattYgatgtaatttacDacSctgctaaaStttaWMagD
+aaatcaVYctccgggcgaVtaaWtStaKMgDtttcaaMtVgBaatccagNaaatcYRMBg
+gttWtaaScKttMWtYataRaDBMaDataatHBcacDaaKDactaMgagttDattaHatH
+taYatDtattDcRNStgaatattSDttggtattaaNSYacttcDMgYgBatWtaMagact
+VWttctttgYMaYaacRgHWaattgRtaagcattctMKVStatactacHVtatgatcBtV
+NataaBttYtSttacKgggWgYDtgaVtYgatDaacattYgatggtRDaVDttNactaSa
+MtgNttaacaaSaBStcDctaccacagacgcaHatMataWKYtaYattMcaMtgSttDag
+cHacgatcaHttYaKHggagttccgatYcaatgatRaVRcaagatcagtatggScctata
+ttaNtagcgacgtgKaaWaactSgagtMYtcttccaKtStaacggMtaagNttattatcg
+tctaRcactctctDtaacWYtgaYaSaagaWtNtatttRacatgNaatgttattgWDDcN
+aHcctgaaHacSgaataaRaataMHttatMtgaSDSKatatHHaNtacagtccaYatWtc
+actaactatKDacSaStcggataHgYatagKtaatKagStaNgtatactatggRHacttg
+tattatgtDVagDVaRctacMYattDgtttYgtctatggtKaRSttRccRtaaccttaga
+gRatagSaaMaacgcaNtatgaaatcaRaagataatagatactcHaaYKBctccaagaRa
+BaStNagataggcgaatgaMtagaatgtcaKttaaatgtaWcaBttaatRcggtgNcaca
+aKtttScRtWtgcatagtttWYaagBttDKgcctttatMggNttattBtctagVtacata
+aaYttacacaaRttcYtWttgHcaYYtaMgBaBatctNgcDtNttacgacDcgataaSat
+YaSttWtcctatKaatgcagHaVaacgctgcatDtgttaSataaaaYSNttatagtaNYt
+aDaaaNtggggacttaBggcHgcgtNtaaMcctggtVtaKcgNacNtatVaSWctWtgaW
+cggNaBagctctgaYataMgaagatBSttctatacttgtgtKtaattttRagtDtacata
+tatatgatNHVgBMtKtaKaNttDHaagatactHaccHtcatttaaagttVaMcNgHata
+tKtaNtgYMccttatcaaNagctggacStttcNtggcaVtattactHaSttatgNMVatt
+MMDtMactattattgWMSgtHBttStStgatatRaDaagattttctatMtaaaaaggtac
+taaVttaSacNaatactgMttgacHaHRttgMacaaaatagttaatatWKRgacDgaRta
+tatttattatcYttaWtgtBRtWatgHaaattHataagtVaDtWaVaWtgStcgtMSgaS
+RgMKtaaataVacataatgtaSaatttagtcgaaHtaKaatgcacatcggRaggSKctDc
+agtcSttcccStYtccRtctctYtcaaKcgagtaMttttcRaYDttgttatctaatcata
+NctctgctatcaMatactataggDaHaaSttMtaDtcNatataattctMcStaaBYtaNa
+gatgtaatHagagSttgWHVcttatKaYgDctcttggtgttMcRaVgSgggtagacaata
+aDtaattSaDaNaHaBctattgNtaccaaRgaVtKNtaaYggHtaKKgHcatctWtctDt
+ttctttggSDtNtaStagttataaacaattgcaBaBWggHgcaaaBtYgctaatgaaatW
+cDcttHtcMtWWattBHatcatcaaatctKMagtDNatttWaBtHaaaNgMttaaStagt
+tctctaatDtcRVaYttgttMtRtgtcaSaaYVgSWDRtaatagctcagDgcWWaaaBaa
+RaBctgVgggNgDWStNaNBKcBctaaKtttDcttBaaggBttgaccatgaaaNgttttt
+tttatctatgttataccaaDRaaSagtaVtDtcaWatBtacattaWacttaSgtattggD
+gKaaatScaattacgWcagKHaaccaYcRcaRttaDttRtttHgaHVggcttBaRgtccc
+tDatKaVtKtcRgYtaKttacgtatBtStaagcaattaagaRgBagSaattccSWYttta
+ttVaataNctgHgttaaNBgcVYgtRtcccagWNaaaacaDNaBcaaaaRVtcWMgBagM
+tttattacgDacttBtactatcattggaaatVccggttRttcatagttVYcatYaSHaHc
+ttaaagcNWaHataaaRWtctVtRYtagHtaaaYMataHYtNBctNtKaatattStgaMc
+BtRgctaKtgcScSttDgYatcVtggaaKtaagatWccHccgKYctaNNctacaWctttt
+gcRtgtVcgaKttcMRHgctaHtVaataaDtatgKDcttatBtDttggNtacttttMtga
+acRattaaNagaactcaaaBBVtcDtcgaStaDctgaaaSgttMaDtcgttcaccaaaag
+gWtcKcgSMtcDtatgtttStaaBtatagDcatYatWtaaaBacaKgcaDatgRggaaYc
+taRtccagattDaWtttggacBaVcHtHtaacDacYgtaatataMagaatgHMatcttat
+acgtatttttatattacHactgttataMgStYaattYaccaattgagtcaaattaYtgta
+tcatgMcaDcgggtcttDtKgcatgWRtataatatRacacNRBttcHtBgcRttgtgcgt
+catacMtttBctatctBaatcattMttMYgattaaVYatgDaatVagtattDacaacDMa
+tcMtHcccataagatgBggaccattVWtRtSacatgctcaaggggYtttDtaaNgNtaaB
+atggaatgtctRtaBgBtcNYatatNRtagaacMgagSaSDDSaDcctRagtVWSHtVSR
+ggaacaBVaccgtttaStagaacaMtactccagtttVctaaRaaHttNcttagcaattta
+ttaatRtaaaatctaacDaBttggSagagctacHtaaRWgattcaaBtctRtSHaNtgta
+cattVcaHaNaagtataccacaWtaRtaaVKgMYaWgttaKggKMtKcgWatcaDatYtK
+SttgtacgaccNctSaattcDcatcttcaaaDKttacHtggttHggRRaRcaWacaMtBW
+VHSHgaaMcKattgtaRWttScNattBBatYtaNRgcggaagacHSaattRtttcYgacc
+BRccMacccKgatgaacttcgDgHcaaaaaRtatatDtatYVtttttHgSHaSaatagct
+NYtaHYaVYttattNtttgaaaYtaKttWtctaNtgagaaaNctNDctaaHgttagDcRt
+tatagccBaacgcaRBtRctRtggtaMYYttWtgataatcgaataattattataVaaaaa
+ttacNRVYcaaMacNatRttcKatMctgaagactaattataaYgcKcaSYaatMNctcaa
+cgtgatttttBacNtgatDccaattattKWWcattttatatatgatBcDtaaaagttgaa
+VtaHtaHHtBtataRBgtgDtaataMttRtDgDcttattNtggtctatctaaBcatctaR
+atgNacWtaatgaagtcMNaacNgHttatactaWgcNtaStaRgttaaHacccgaYStac
+aaaatWggaYaWgaattattcMaactcBKaaaRVNcaNRDcYcgaBctKaacaaaaaSgc
+tccYBBHYaVagaatagaaaacagYtctVccaMtcgtttVatcaatttDRtgWctagtac
+RttMctgtDctttcKtWttttataaatgVttgBKtgtKWDaWagMtaaagaaattDVtag
+gttacatcatttatgtcgMHaVcttaBtVRtcgtaYgBRHatttHgaBcKaYWaatcNSc
+tagtaaaaatttacaatcactSWacgtaatgKttWattagttttNaggtctcaagtcact
+attcttctaagKggaataMgtttcataagataaaaatagattatDgcBVHWgaBKttDgc
+atRHaagcaYcRaattattatgtMatatattgHDtcaDtcaaaHctStattaatHaccga
+cNattgatatattttgtgtDtRatagSacaMtcRtcattcccgacacSattgttKaWatt
+NHcaacttccgtttSRtgtctgDcgctcaaMagVtBctBMcMcWtgtaacgactctcttR
+ggRKSttgYtYatDccagttDgaKccacgVatWcataVaaagaataMgtgataaKYaaat
+cHDaacgataYctRtcYatcgcaMgtNttaBttttgatttaRtStgcaacaaaataccVg
+aaDgtVgDcStctatatttattaaaaRKDatagaaagaKaaYYcaYSgKStctccSttac
+agtcNactttDVttagaaagMHttRaNcSaRaMgBttattggtttaRMggatggcKDgWR
+tNaataataWKKacttcKWaaagNaBttaBatMHtccattaacttccccYtcBcYRtaga
+ttaagctaaYBDttaNtgaaaccHcaRMtKtaaHMcNBttaNaNcVcgVttWNtDaBatg
+ataaVtcWKcttRggWatcattgaRagHgaattNtatttctctattaattaatgaDaaMa
+tacgttgggcHaYVaaNaDDttHtcaaHtcVVDgBVagcMacgtgttaaBRNtatRtcag
+taagaggtttaagacaVaaggttaWatctccgtVtaDtcDatttccVatgtacNtttccg
+tHttatKgScBatgtVgHtYcWagcaKtaMYaaHgtaattaSaHcgcagtWNaatNccNN
+YcacgVaagaRacttctcattcccRtgtgtaattagcSttaaStWaMtctNNcSMacatt
+ataaactaDgtatWgtagtttaagaaaattgtagtNagtcaataaatttgatMMYactaa
+tatcggBWDtVcYttcDHtVttatacYaRgaMaacaStaatcRttttVtagaDtcacWat
+ttWtgaaaagaaagNRacDtttStVatBaDNtaactatatcBSMcccaSttccggaMatg
+attaaWatKMaBaBatttgataNctgttKtVaagtcagScgaaaDggaWgtgttttKtWt
+atttHaatgtagttcactaaKMagttSYBtKtaYgaactcagagRtatagtVtatcaaaW
+YagcgNtaDagtacNSaaYDgatBgtcgataacYDtaaactacagWDcYKaagtttatta
+gcatcgagttKcatDaattgattatDtcagRtWSKtcgNtMaaaaacaMttKcaWcaaSV
+MaaaccagMVtaMaDtMaHaBgaacataBBVtaatVYaNSWcSgNtDNaaKacacBttta
+tKtgtttcaaHaMctcagtaacgtcgYtactDcgcctaNgagagcYgatattttaaattt
+ccattttacatttDaaRctattttWctttacgtDatYtttcagacgcaaVttagtaaKaa
+aRtgVtccataBggacttatttgtttaWNtgttVWtaWNVDaattgtatttBaagcBtaa
+BttaaVatcHcaVgacattccNggtcgacKttaaaRtagRtctWagaYggtgMtataatM
+tgaaRttattttgWcttNtDRRgMDKacagaaaaggaaaRStcccagtYccVattaNaaK
+StNWtgacaVtagaagcttSaaDtcacaacgDYacWDYtgtttKatcVtgcMaDaSKStV
+cgtagaaWaKaagtttcHaHgMgMtctataagBtKaaaKKcactggagRRttaagaBaaN
+atVVcgRcKSttDaactagtSttSattgttgaaRYatggttVttaataaHttccaagDtg
+atNWtaagHtgcYtaactRgcaatgMgtgtRaatRaNaacHKtagactactggaatttcg
+ccataacgMctRgatgttaccctaHgtgWaYcactcacYaattcttaBtgacttaaacct
+gYgaWatgBttcttVttcgttWttMcNYgtaaaatctYgMgaaattacNgaHgaacDVVM
+tttggtHtctaaRgtacagacgHtVtaBMNBgattagcttaRcttacaHcRctgttcaaD
+BggttKaacatgKtttYataVaNattccgMcgcgtagtRaVVaattaKaatggttRgaMc
+agtatcWBttNtHagctaatctagaaNaaacaYBctatcgcVctBtgcaaagDgttVtga
+HtactSNYtaaNccatgtgDacgaVtDcgKaRtacDcttgctaagggcagMDagggtBWR
+tttSgccttttttaacgtcHctaVtVDtagatcaNMaVtcVacatHctDWNaataRgcgt
+aVHaggtaaaaSgtttMtattDgBtctgatSgtRagagYtctSaKWaataMgattRKtaa
+catttYcgtaacacattRWtBtcggtaaatMtaaacBatttctKagtcDtttgcBtKYYB
+aKttctVttgttaDtgattttcttccacttgSaaacggaaaNDaattcYNNaWcgaaYat
+tttMgcBtcatRtgtaaagatgaWtgaccaYBHgaatagataVVtHtttVgYBtMctaMt
+cctgaDcYttgtccaaaRNtacagcMctKaaaggatttacatgtttaaWSaYaKttBtag
+DacactagctMtttNaKtctttcNcSattNacttggaacaatDagtattRtgSHaataat
+gccVgacccgatactatccctgtRctttgagaSgatcatatcgDcagWaaHSgctYYWta
+tHttggttctttatVattatcgactaagtgtagcatVgtgHMtttgtttcgttaKattcM
+atttgtttWcaaStNatgtHcaaaDtaagBaKBtRgaBgDtSagtatMtaacYaatYtVc
+KatgtgcaacVaaaatactKcRgtaYtgtNgBBNcKtcttaccttKgaRaYcaNKtactt
+tgagSBtgtRagaNgcaaaNcacagtVtttHWatgttaNatBgtttaatNgVtctgaata
+tcaRtattcttttttttRaaKcRStctcggDgKagattaMaaaKtcaHacttaataataK
+taRgDtKVBttttcgtKaggHHcatgttagHggttNctcgtatKKagVagRaaaggaaBt
+NatttVKcRttaHctaHtcaaatgtaggHccaBataNaNaggttgcWaatctgatYcaaa
+HaatWtaVgaaBttagtaagaKKtaaaKtRHatMaDBtBctagcatWtatttgWttVaaa
+ScMNattRactttgtYtttaaaagtaagtMtaMaSttMBtatgaBtttaKtgaatgagYg
+tNNacMtcNRacMMHcttWtgtRtctttaacaacattattcYaMagBaacYttMatcttK
+cRMtgMNccattaRttNatHaHNaSaaHMacacaVaatacaKaSttHatattMtVatWga
+ttttttaYctttKttHgScWaacgHtttcaVaaMgaacagNatcgttaacaaaaagtaca
+HBNaattgttKtcttVttaaBtctgctacgBgcWtttcaggacacatMgacatcccagcg
+gMgaVKaBattgacttaatgacacacaaaaaatRKaaBctacgtRaDcgtagcVBaacDS
+BHaaaaSacatatacagacRNatcttNaaVtaaaataHattagtaaaaSWccgtatWatg
+gDttaactattgcccatcttHaSgYataBttBaactattBtcHtgatcaataSttaBtat
+KSHYttWggtcYtttBttaataccRgVatStaHaKagaatNtagRMNgtcttYaaSaact
+cagDSgagaaYtMttDtMRVgWKWtgMaKtKaDttttgactatacataatcNtatNaHat
+tVagacgYgatatatttttgtStWaaatctWaMgagaRttRatacgStgattcttaagaD
+taWccaaatRcagcagaaNKagtaaDggcgccBtYtagSBMtactaaataMataBSacRM
+gDgattMMgtcHtcaYDtRaDaacggttDaggcMtttatgttaNctaattaVacgaaMMt
+aatDccSgtattgaRtWWaccaccgagtactMcgVNgctDctaMScatagcgtcaactat
+acRacgHRttgctatttaatgaattataYKttgtaagWgtYttgcHgMtaMattWaWVta
+RgcttgYgttBHtYataSccStBtgtagMgtDtggcVaaSBaatagDttgBgtctttctc
+attttaNagtHKtaMWcYactVcgcgtatMVtttRacVagDaatcttgctBBcRDgcaac
+KttgatSKtYtagBMagaRtcgBattHcBWcaactgatttaatttWDccatttatcgagS
+KaWttataHactaHMttaatHtggaHtHagaatgtKtaaRactgtttMatacgatcaagD
+gatKaDctataMggtHDtggHacctttRtatcttYattttgacttgaaSaataaatYcgB
+aaaaccgNatVBttMacHaKaataagtatKgtcaagactcttaHttcggaattgttDtct
+aaccHttttWaaatgaaatataaaWattccYDtKtaaaacggtgaggWVtctattagtga
+ctattaagtMgtttaagcatttgSgaaatatccHaaggMaaaattttcWtatKctagDtY
+tMcctagagHcactttactatacaaacattaacttaHatcVMYattYgVgtMttaaRtga
+aataaDatcaHgtHHatKcDYaatcttMtNcgatYatgSaMaNtcttKcWataScKggta
+tcttacgcttWaaagNatgMgHtctttNtaacVtgttcMaaRatccggggactcMtttaY
+MtcWRgNctgNccKatcttgYDcMgattNYaRagatHaaHgKctcataRDttacatBatc
+cattgDWttatttaWgtcggagaaaaatacaatacSNtgggtttccttacSMaagBatta
+caMaNcactMttatgaRBacYcYtcaaaWtagctSaacttWgDMHgaggatgBVgcHaDt
+ggaactttggtcNatNgtaKaBcccaNtaagttBaacagtatacDYttcctNgWgcgSMc
+acatStctHatgRcNcgtacacaatRttMggaNKKggataaaSaYcMVcMgtaMaHtgat
+tYMatYcggtcttcctHtcDccgtgRatcattgcgccgatatMaaYaataaYSggatagc
+gcBtNtaaaScaKgttBgagVagttaKagagtatVaactaSacWactSaKatWccaKaaa
+atBKgaaKtDMattttgtaaatcRctMatcaaMagMttDgVatggMaaWgttcgaWatga
+aatttgRtYtattaWHKcRgctacatKttctaccaaHttRatctaYattaaWatVNccat
+NgagtcKttKataStRaatatattcctRWatDctVagttYDgSBaatYgttttgtVaatt
+taatagcagMatRaacttBctattgtMagagattaaactaMatVtHtaaatctRgaaaaa
+aaatttWacaacaYccYDSaattMatgaccKtaBKWBattgtcaagcHKaagttMMtaat
+ttcKcMagNaaKagattggMagaggtaatttYacatcWaaDgatMgKHacMacgcVaaca
+DtaDatatYggttBcgtatgWgaSatttgtagaHYRVacaRtctHaaRtatgaactaata
+tctSSBgggaaHMWtcaagatKgagtDaSatagttgattVRatNtctMtcSaagaSHaat
+aNataataRaaRgattctttaataaagWaRHcYgcatgtWRcttgaaggaMcaataBRaa
+ccagStaaacNtttcaatataYtaatatgHaDgcStcWttaacctaRgtYaRtataKtgM
+ttttatgactaaaatttacYatcccRWtttHRtattaaatgtttatatttgttYaatMca
+RcSVaaDatcgtaYMcatgtagacatgaaattgRtcaaYaaYtRBatKacttataccaNa
+aattVaBtctggacaagKaaYaaatatWtMtatcYaaVNtcgHaactBaagKcHgtctac
+aatWtaDtSgtaHcataHtactgataNctRgttMtDcDttatHtcgtacatcccaggStt
+aBgtcacacWtccNMcNatMVaVgtccDYStatMaccDatggYaRKaaagataRatttHK
+tSaaatDgataaacttaHgttgVBtcttVttHgDacgaKatgtatatNYataactctSat
+atatattgcHRRYttStggaactHgttttYtttaWtatMcttttctatctDtagVHYgMR
+BgtHttcctaatYRttKtaagatggaVRataKDctaMtKBNtMtHNtWtttYcVtattMc
+gRaacMcctNSctcatttaaagDcaHtYccSgatgcaatYaaaaDcttcgtaWtaattct
+cgttttScttggtaatctttYgtctaactKataHacctMctcttacHtKataacacagcN
+RatgKatttttSaaatRYcgDttaMRcgaaattactMtgcgtaagcgttatBtttttaat
+taagtNacatHgttcRgacKcBBtVgatKttcgaBaatactDRgtRtgaNacWtcacYtt
+aaKcgttctHaKttaNaMgWgWaggtctRgaKgWttSttBtDcNtgtttacaaatYcDRt
+gVtgcctattcNtctaaaDMNttttNtggctgagaVctDaacVtWccaagtaacacaNct
+gaScattccDHcVBatcgatgtMtaatBgHaatDctMYgagaatgYWKcctaatNaStHa
+aaKccgHgcgtYaaYtattgtStgtgcaaRtattaKatattagaWVtcaMtBagttatta
+gNaWHcVgcaattttDcMtgtaRHVYtHtctgtaaaaHVtMKacatcgNaatttMatatg
+ttgttactagWYtaRacgataKagYNKcattataNaRtgaacKaYgcaaYYacaNccHat
+MatDcNgtHttRaWttagaaDcaaaaaatagggtKDtStaDaRtaVtHWKNtgtattVct
+SVgRgataDaRaWataBgaagaaKtaataaYgDcaStaNgtaDaaggtattHaRaWMYaY
+aWtggttHYgagVtgtgcttttcaaDKcagVcgttagacNaaWtagtaataDttctggtt
+VcatcataaagtgKaaaNaMtaBBaattaatWaattgctHaVKaSgDaaVKaHtatatat
+HatcatSBagNgHtatcHYMHgttDgtaHtBttWatcgtttaRaattgStKgSKNWKatc
+agDtctcagatttctRtYtBatBgHHtKaWtgYBgacVVWaKtacKcDttKMaKaVcggt
+gttataagaataaHaatattagtataatMHgttYgaRttagtaRtcaaVatacggtcMcg
+agtaaRttacWgactKRYataaaagSattYaWgagatYagKagatgSaagKgttaatMgg
+tataatgttWYttatgagaaacctNVataatHcccKtDctcctaatactggctHggaSag
+gRtKHaWaattcgSatMatttagaggcYtctaMcgctcataSatatgRagacNaaDagga
+VBagaYttKtacNaKgtSYtagttggaWcatcWttaatctatgaVtcgtgtMtatcaYcg
+tRccaaYgDctgcMgtgtWgacWtgataacacgcgctBtgttaKtYDtatDcatcagKaV
+MctaatcttgVcaaRgcRMtDcgattaHttcaNatgaatMtactacVgtRgatggaWttt
+actaaKatgagSaaKggtaNtactVaYtaaKRagaacccacaMtaaMtKtatBcttgtaa
+WBtMctaataaVcDaaYtcRHBtcgttNtaaHatttBNgRStVDattBatVtaagttaYa
+tVattaagaBcacggtSgtVtatttaRattgatgtaHDKgcaatattKtggcctatgaWD
+KRYcggattgRctatNgatacaatMNttctgtcRBYRaaaHctNYattcHtaWcaattct
+BtMKtVgYataatMgYtcagcttMDataVtggRtKtgaatgccNcRttcaMtRgattaac
+attRcagcctHtWMtgtDRagaKaBtgDttYaaaaKatKgatctVaaYaacWcgcatagB
+VtaNtRtYRaggBaaBtgKgttacataagagcatgtRattccacttaccatRaaatgWgD
+aMHaYVgVtaSctatcgKaatatattaDgacccYagtgtaYNaaatKcagtBRgagtcca
+tgKgaaaccBgaagBtgSttWtacgatWHaYatcgatttRaaNRgcaNaKVacaNtDgat
+tgHVaatcDaagcgtatgcNttaDataatcSataaKcaataaHWataBtttatBtcaKtK
+tatagttaDgSaYctacaRatNtaWctSaatatttYaKaKtaccWtatcRagacttaYtt
+VcKgSDcgagaagatccHtaattctSttatggtKYgtMaHagVaBRatttctgtRgtcta
+tgggtaHKgtHacHtSYacgtacacHatacKaaBaVaccaDtatcSaataaHaagagaat
+ScagactataaRttagcaaVcaHataKgDacatWccccaagcaBgagWatctaYttgaaa
+tctVNcYtttWagHcgcgcDcVaaatgttKcHtNtcaatagtgtNRaactttttcaatgg
+WgBcgDtgVgtttctacMtaaataaaRggaaacWaHttaRtNtgctaaRRtVBctYtVta
+tDcattDtgaccYatagatYRKatNYKttNgcctagtaWtgaactaMVaacctgaStttc
+tgaKVtaaVaRKDttVtVctaDNtataaaDtccccaagtWtcgatcactDgYaBcatcct
+MtVtacDaaBtYtMaKNatNtcaNacgDatYcatcgcaRatWBgaacWttKttagYtaat
+tcggttgSWttttDWctttacYtatatWtcatDtMgtBttgRtVDggttaacYtacgtac
+atgaattgaaWcttMStaDgtatattgaDtcRBcattSgaaVBRgagccaaKtttcDgcg
+aSMtatgWattaKttWtgDBMaggBBttBaatWttRtgcNtHcgttttHtKtcWtagHSt
+aacagttgatatBtaWSaWggtaataaMttaKacDaatactcBttcaatatHttcBaaSa
+aatYggtaRtatNtHcaatcaHtagVtgtattataNggaMtcttHtNagctaaaggtaga
+YctMattNaMVNtcKtactBKcaHHcBttaSagaKacataYgctaKaYgttYcgacWVtt
+WtSagcaacatcccHaccKtcttaacgaKttcacKtNtacHtatatRtaaatacactaBt
+ttgaHaRttggttWtatYagcatYDatcggagagcWBataagRtacctataRKgtBgatg
+aDatataSttagBaHtaatNtaDWcWtgtaattacagKttcNtMagtattaNgtctcgtc
+ctcttBaHaKcKccgtRcaaYagSattaagtKataDatatatagtcDtaacaWHcaKttD
+gaaRcgtgYttgtcatatNtatttttatggccHtgDtYHtWgttatYaacaattcaWtat
+NgctcaaaSttRgctaatcaaatNatcgtttaBtNNVtgttataagcaaagattBacgtD
+atttNatttaaaDcBgtaSKgacgtagataatttcHMVNttgttBtDtgtaWKaaRMcKM
+tHtaVtagataWctccNNaSWtVaHatctcMgggDgtNHtDaDttatatVWttgttattt
+aacctttcacaaggaSaDcggttttttatatVtctgVtaacaStDVaKactaMtttaSNa
+gtgaaattaNacttSKctattcctctaSagKcaVttaagNaVcttaVaaRNaHaaHttat
+gtHttgtgatMccaggtaDcgaccgtWgtWMtttaHcRtattgScctatttKtaaccaag
+tYagaHgtWcHaatgccKNRtttagtMYSgaDatctgtgaWDtccMNcgHgcaaacNDaa
+aRaStDWtcaaaaHKtaNBctagBtgtattaactaattttVctagaatggcWSatMaccc
+ttHttaSgSgtgMRcatRVKtatctgaaaccDNatYgaaVHNgatMgHRtacttaaaRta
+tStRtDtatDttYatattHggaBcttHgcgattgaKcKtttcRataMtcgaVttWacatN
+catacctRataDDatVaWNcggttgaHtgtMacVtttaBHtgagVttMaataattatgtt
+cttagtttgtgcDtSatttgBtcaacHattaaBagVWcgcaSYttMgcttacYKtVtatc
+aYaKctgBatgcgggcYcaaaaacgNtctagKBtattatctttKtaVttatagtaYtRag
+NtaYataaVtgaatatcHgcaaRataHtacacatgtaNtgtcgYatWMatttgaactacR
+ctaWtWtatacaatctBatatgYtaagtatgtgtatSttactVatcttYtaBcKgRaSgg
+RaaaaatgcagtaaaWgtaRgcgataatcBaataccgtatttttccatcNHtatWYgatH
+SaaaDHttgctgtccHtggggcctaataatttttctatattYWtcattBtgBRcVttaVM
+RSgctaatMagtYtttaaaaatBRtcBttcaaVtaacagctccSaaSttKNtHtKYcagc
+agaaaccccRtttttaaDcDtaStatccaagcgctHtatcttaDRYgatDHtWcaaaBcW
+gKWHttHataagHacgMNKttMKHccaYcatMVaacgttaKgYcaVaaBtacgcaacttt
+MctaaHaatgtBatgagaSatgtatgSRgHgWaVWgataaatatttccKagVgataattW
+aHNcYggaaatgctHtKtaDtctaaagtMaatVDVactWtSaaWaaMtaHtaSKtcBRaN
+cttStggtBttacNagcatagRgtKtgcgaacaacBcgKaatgataagatgaaaattgta
+ctgcgggtccHHWHaaNacaBttNKtKtcaaBatatgctaHNgtKcDWgtttatNgVDHg
+accaacWctKaaggHttgaRgYaatHcaBacaatgagcaaattactgtaVaaYaDtagat
+tgagNKggtggtgKtWKaatacagDRtatRaMRtgattDggtcaaYRtatttNtagaDtc
+acaaSDctDtataatcgtactaHttatacaatYaacaaHttHatHtgcgatRRttNgcat
+SVtacWWgaaggagtatVMaVaaattScDDKNcaYBYaDatHgtctatBagcaacaagaa
+tgagaaRcataaKNaRtBDatcaaacgcattttttaaBtcSgtacaRggatgtMNaattg
+gatatWtgagtattaaaVctgcaYMtatgatttttYgaHtgtcttaagWBttHttgtctt
+attDtcgtatWtataataSgctaHagcDVcNtaatcaagtaBDaWaDgtttagYctaNcc
+DtaKtaHcttaataacccaRKtacaVaatNgcWRaMgaattatgaBaaagattVYaHMDc
+aDHtcRcgYtcttaaaWaaaVKgatacRtttRRKYgaatacaWVacVcRtatMacaBtac
+tggMataaattttHggNagSctacHgtBagcgtcgtgattNtttgatSaaggMttctttc
+ttNtYNagBtaaacaaatttMgaccttacataattgYtcgacBtVMctgStgMDtagtaR
+ctHtatgttcatatVRNWataDKatWcgaaaaagttaaaagcacgHNacgtaatctttMR
+tgacttttDacctataaacgaaatatgattagaactccSYtaBctttaataacWgaaaYa
+tagatgWttcatKtNgatttttcaagHtaYgaaRaDaagtaggagcttatVtagtctttc
+attaaaatcgKtattaRttacagVaDatgcatVgattgggtctttHVtagKaaRBtaHta
+aggccccaaaaKatggtttaMWgtBtaaacttcactttKHtcgatctccctaYaBacMgt
+cttBaBaNgcgaaacaatctagtHccHtKttcRtRVttccVctttcatacYagMVtMcag
+aMaaacaataBctgYtaatRaaagattaaccatVRatHtaRagcgcaBcgDttStttttc
+VtttaDtKgcaaWaaaaatSccMcVatgtKgtaKgcgatatgtagtSaaaDttatacaaa
+catYaRRcVRHctKtcgacKttaaVctaDaatgttMggRcWaacttttHaDaKaDaBctg
+taggcgtttaHBccatccattcNHtDaYtaataMttacggctNVaacDattgatatttta
+cVttSaattacaaRtataNDgacVtgaacataVRttttaDtcaaacataYDBtttaatBa
+DtttYDaDaMccMttNBttatatgagaaMgaNtattHccNataattcaHagtgaaggDga
+tgtatatatgYatgaStcataaBStWacgtcccataRMaaDattggttaaattcMKtctM
+acaBSactcggaatDDgatDgcWctaacaccgggaVcacWKVacggtaNatatacctMta
+tgatagtgcaKagggVaDtgtaacttggagtcKatatcgMcttRaMagcattaBRaStct
+YSggaHYtacaactMBaagDcaBDRaaacMYacaHaattagcattaaaHgcgctaaggSc
+cKtgaaKtNaBtatDDcKBSaVtgatVYaagVtctSgMctacgttaacWaaattctSgtD
+actaaStaaattgcagBBRVctaatatacctNttMcRggctttMttagacRaHcaBaacV
+KgaataHttttMgYgattcYaNRgttMgcVaaacaVVcDHaatttgKtMYgtatBtVVct
+WgVtatHtacaaHttcacgatagcagtaaNattBatatatttcVgaDagcggttMaagtc
+ScHagaaatgcYNggcgtttttMtStggtRatctacttaaatVVtBacttHNttttaRca
+aatcacagHgagagtMgatcSWaNRacagDtatactaaDKaSRtgattctccatSaaRtt
+aaYctacacNtaRtaactggatgaccYtacactttaattaattgattYgttcagDtNKtt
+agDttaaaaaaaBtttaaNaYWKMBaaaacVcBMtatWtgBatatgaacVtattMtYatM
+NYDKNcKgDttDaVtaaaatgggatttctgtaaatWtctcWgtVVagtcgRgacttcccc
+taDcacagcRcagagtgtWSatgtacatgttaaSttgtaaHcgatgggMagtgaacttat
+RtttaVcaccaWaMgtactaatSSaHtcMgaaYtatcgaaggYgggcgtgaNDtgttMNg
+aNDMtaattcgVttttaacatgVatgtWVMatatcaKgaaattcaBcctccWcttgaaWH
+tWgHtcgNWgaRgctcBgSgaattgcaaHtgattgtgNagtDttHHgBttaaWcaaWagc
+aSaHHtaaaVctRaaMagtaDaatHtDMtcVaWMtagSagcttHSattaacaaagtRacM
+tRtctgttagcMtcaBatVKtKtKacgagaSNatSactgtatatcBctgagVtYactgta
+aattaaaggcYgDHgtaacatSRDatMMccHatKgttaacgactKtgKagtcttcaaHRV
+tccttKgtSataatttacaactggatDNgaacttcaRtVaagDcaWatcBctctHYatHa
+DaaatttagYatSatccaWtttagaaatVaacBatHcatcgtacaatatcgcNYRcaata
+YaRaYtgattVttgaatgaVaactcRcaNStgtgtattMtgaggtNttBaDRcgaaaagc
+tNgBcWaWgtSaDcVtgVaatMKBtttcgtttctaaHctaaagYactgMtatBDtcStga
+ccgtSDattYaataHctgggaYYttcggttaWaatctggtRagWMaDagtaacBccacta
+cgHWMKaatgatWatcctgHcaBaSctVtcMtgtDttacctaVgatYcWaDRaaaaRtag
+atcgaMagtggaRaWctctgMgcWttaagKBRtaaDaaWtctgtaagYMttactaHtaat
+cttcataacggcacBtSgcgttNHtgtHccatgttttaaagtatcgaKtMttVcataYBB
+aKtaMVaVgtattNDSataHcagtWMtaggtaSaaKgttgBtVtttgttatcatKcgHac
+acRtctHatNVagSBgatgHtgaRaSgttRcctaacaaattDNttgacctaaYtBgaaaa
+tagttattactcttttgatgtNNtVtgtatMgtcttRttcatttgatgacacttcHSaaa
+ccaWWDtWagtaRDDVNacVaRatgttBccttaatHtgtaaacStcVNtcacaSRttcYa
+gacagaMMttttgMcNttBcgWBtactgVtaRttctccaaYHBtaaagaBattaYacgat
+ttacatctgtaaMKaRYtttttactaaVatWgctBtttDVttctggcDaHaggDaagtcg
+aWcaagtagtWttHtgKtVataStccaMcWcaagataagatcactctHatgtcYgaKcat
+cagatactaagNSStHcctRRNtattgtccttagttagMVgtatagactaactctVcaat
+MctgtttgtgttgccttatWgtaBVtttctggMcaaKgDWtcgtaaYStgSactatttHg
+atctgKagtagBtVacRaagRtMctatgggcaaaKaaaatacttcHctaRtgtDcttDat
+taggaaatttcYHaRaaBttaatggcacKtgctHVcaDcaaaVDaaaVcgMttgtNagcg
+taDWgtcgttaatDgKgagcSatatcSHtagtagttggtgtHaWtaHKtatagctgtVga
+ttaBVaatgaataagtaatVatSttaHctttKtttgtagttaccttaatcgtagtcctgB
+cgactatttVcMacHaaaggaatgDatggKtaHtgStatattaaSagctWcctccRtata
+BaDYcgttgcNaagaggatRaaaYtaWgNtSMcaatttactaacatttaaWttHtatBat
+tgtcgacaatNgattgcNgtMaaaKaBDattHacttggtRtttaYaacgVactBtaBaKt
+gBttatgVttgtVttcaatcWcNctDBaaBgaDHacBttattNtgtDtatttVSaaacag
+gatgcRatSgtaSaNtgBatagttcHBgcBBaaattaHgtDattatDaKaatBaaYaaMa
+ataaataKtttYtagtBgMatNcatgtttgaNagtgttgtgKaNaSagtttgaSMaYBca
+aaacDStagttVacaaaaactaaWttBaagtctgtgcgtMgtaattctcctacctcaNtt
+taaccaaaaVtBcacataacaccccBcWMtatVtggaatgaWtcaaWaaaaaaaaWtDta
+atatRcctDWtcctaccMtVVatKttaWaaKaaatataaagScHBagaggBaSMtaWaVt
+atattactSaaaKNaactatNatccttgaYctattcaaaVgatttYHcRagattttaSat
+aggttattcVtaaagaKgtattattKtRttNcggcRgtgtgtWYtaacHgKatKgatYta
+cYagDtWcHBDctctgRaYKaYagcactKcacSaRtBttttBHKcMtNtcBatttatttt
+tgSatVgaaagaWtcDtagDatatgMacaacRgatatatgtttgtKtNRaatatNatgYc
+aHtgHataacKtgagtagtaacYttaNccaaatHcacaacaVDtagtaYtccagcattNt
+acKtBtactaaagaBatVtKaaHBctgStgtBgtatgaSNtgDataaccctgtagcaBgt
+gatcttaDataStgaMaccaSBBgWagtacKcgattgaDgNNaaaacacagtSatBacKD
+gcgtataBKcatacactaSaatYtYcDaactHttcatRtttaatcaattataRtttgtaa
+gMcgNttcatcBtYBagtNWNMtSHcattcRctttttRWgaKacKttgggagBcgttcgc
+MaWHtaatactgtctctatttataVgtttaBScttttaBMaNaatMacactYtBMggtHa
+cMagtaRtctgcatttaHtcaaaatttgagKtgNtactBacaHtcgtatttctMaSRagc
+agttaatgtNtaaattgagagWcKtaNttagVtacgatttgaatttcgRtgtWcVatcgt
+taaDVctgtttBWgaccagaaagtcSgtVtatagaBccttttcctaaattgHtatcggRa
+ttttcaaggcYSKaagWaWtRactaaaacccBatMtttBaatYtaagaactSttcgaaSc
+aatagtattgaccaagtgttttctaacatgtttNVaatcaaagagaaaNattaaRtttta
+VaaaccgcaggNMtatattVctcaagaggaacgBgtttaacaagttcKcYaatatactaa
+ccBaaaSggttcNtattctagttRtBacgScVctcaatttaatYtaaaaaaatgSaatga
+tagaMBRatgRcMcgttgaWHtcaVYgaatYtaatctttYttatRaWtctgBtDcgatNa
+tcKaBaDgatgtaNatWKctccgatattaacattNaaacDatgBgttctgtDtaaaMggt
+gaBaSHataacgccSctaBtttaRBtcNHcDatcDcctagagtcRtaBgWttDRVHagat
+tYatgtatcWtaHtttYcattWtaaagtctNgtStggRNcgcggagSSaaagaaaatYcH
+DtcgctttaatgYcKBVSgtattRaYBaDaaatBgtatgaHtaaRaRgcaSWNtagatHa
+acttNctBtcaccatctMcatattccaSatttgcgaDagDgtatYtaaaVDtaagtttWV
+aagtagYatRttaagDcNgacKBcScagHtattatcDaDactaaaaaYgHttBcgaDttg
+gataaaKSRcBMaBcgaBSttcWtgNBatRaccgattcatttataacggHVtaattcaca
+agagVttaaRaatVVRKcgWtVgacctgDgYaaHaWtctttcacMagggatVgactagMa
+aataKaaNWagKatagNaaWtaaaatttgaattttatttgctaaVgaHatBatcaaBWcB
+gttcMatcgBaaNgttcgSNaggSaRtttgHtRtattaNttcDcatSaVttttcgaaaaa
+ttgHatctaRaggSaNatMDaaatDcacgattttagaHgHaWtYgattaatHNSttatMS
+gggNtcKtYatRggtttgtMWVtttaYtagcagBagHaYagttatatggtBacYcattaR
+SataBatMtttaaatctHcaaaSaaaagttNSaaWcWRccRtKaagtBWtcaaattSttM
+tattggaaaccttaacgttBtWatttatatWcDaatagattcctScacctaagggRaaYt
+aNaatgVtBcttaaBaacaMVaaattatStYgRcctgtactatcMcVKatttcgSgatRH
+MaaaHtagtaaHtVgcaaataatatcgKKtgccaatBNgaaWcVttgagttaKatagttc
+aggKDatDtattgaKaVcaKtaataDataataHSaHcattagttaatRVYcNaHtaRcaa
+ggtNHcgtcaaccaBaaagYtHWaaaRcKgaYaaDttgcWYtataRgaatatgtYtgcKt
+aNttWacatYHctRaDtYtattcBttttatcSataYaYgttWaRagcacHMgtttHtYtt
+YaatcggtatStttcgtRSattaaDaKMaatatactaNBaWgctacacYtgaYVgtgHta
+aaRaaRgHtagtWattataaaSDaaWtgMattatcgaaaagtaYRSaWtSgNtBgagcRY
+aMDtactaacttaWgtatctagacaagNtattHggataatYttYatcataDcgHgttBtt
+ctttVttgccgaaWtaaaacgKgtatctaaaaaNtccDtaDatBMaMggaatNKtatBaa
+atVtccRaHtaSacataHattgtttKVYattcataVaattWtcgtgMttcttKtgtctaa
+cVtatctatatBRataactcgKatStatattcatHHRttKtccaacgtgggtgRgtgaMt
+attattggctatcgtgacMtRcBDtcttgtactaatRHttttaagatcgVMDStattatY
+BtttDttgtBtNttgRcMtYtgBacHaWaBaatDKctaagtgaaactaatgRaaKgatcc
+aagNaaaatattaggWNtaagtatacttttKcgtcggSYtcttgRctataYcttatataa
+agtatattaatttataVaacacaDHatctatttttKYVatHRactttaBHccaWagtact
+BtcacgaVgcgttRtttttttSVgtSagtBaaattctgaHgactcttgMcattttagVta
+agaattHctHtcaDaaNtaacRggWatagttcgtSttgaDatcNgNagctagDgatcNtt
+KgttgtaDtctttRaaYStRatDtgMggactSttaDtagSaVtBDttgtDgccatcacaM
+attaaaMtNacaVcgSWcVaaDatcaHaatgaattaMtatccVtctBtaattgtWattat
+BRcWcaatgNNtactWYtDaKttaaatcactcagtRaaRgatggtKgcgccaaHgaggat
+StattYcaNMtcaBttacttatgagDaNtaMgaaWtgtttcttctaHtMNgttatctaWW
+atMtBtaaatagDVatgtBYtatcggcttaagacMRtaHScgatatYgRDtcattatSDa
+HggaaataNgaWSRRaaaBaatagBattaDctttgHWNttacaataaaaaaatacggttt
+gHgVtaHtWMttNtBtctagtMcgKMgHgYtataHaNagWtcaacYattaataYRgtaWK
+gaBctataaccgatttaHaNBRaRaMtccggtNgacMtctcatttgcaattcWgMactta
+caaDaaNtactWatVtttagccttMaatcagVaagtctVaaDaBtattaattaYtNaYtg
+gattaKtaKctYaMtattYgatattataatKtVgDcttatatNBtcgttgtStttttMag
+aggttaHYSttcKgtcKtDNtataagttataagSgttatDtRttattgttttSNggRtca
+aKMNatgaatattgtBWtaMacctgggYgaSgaagYataagattacgagaatBtggtRcV
+HtgYggaDgaYaKagWagctatagacgaaHgtWaNgacttHRatVaWacKYtgRVNgVcS
+gRWctacatcKSactctgWYtBggtataagcttNRttVtgRcaWaaatDMatYattaact
+ttcgaagRatSctgccttgcRKaccHtttSNVagtagHagBagttagaccaRtataBcca
+taatSHatRtcHagacBWatagcaMtacaRtgtgaaBatctKRtScttccaNaatcNgta
+atatWtcaMgactctBtWtaaNactHaaaaRctcgcatggctMcaaNtcagaaaaacaca
+gtggggWttRttagtaagaVctVMtcgaatcttcMaaaHcaHBttcgattatgtcaDagc
+YRtBtYcgacMgtDcagcgaNgttaataatagcagKYYtcgtaBtYctMaRtaRtDagaa
+aacacatgYaBttgattattcgaaNttBctSataaMataWRgaHtttccgtDgaYtatgg
+tDgHKgMtatttVtMtVagttaRatMattRagataaccctKctMtSttgaHagtcStcta
+tttccSagatgttccacgaggYNttHRacgattcDatatDcataaaatBBttatcgaHtN
+HaaatatDNaggctgaNcaaggagttBttMgRagVatBcRtaWgatgBtSgaKtcgHttt
+gaatcaaDaHttcSBgHcagtVaaSttDcagccgttNBtgttHagYtattctttRWaaVt
+SttcatatKaaRaaaNacaVtVctMtSDtDtRHRcgtaatgctcttaaatSacacaatcg
+HattcaWcttaaaatHaaatcNctWttaNMcMtaKctVtcctaagYgatgatcYaaaRac
+tctaRDaYagtaacgtDgaggaaatctcaaacatcaScttcKttNtaccatNtaNataca
+tttHaaDHgcaDatMWaaBttcRggctMaagctVYcacgatcaDttatYtaatcKatWat
+caatVYtNagatttgattgaYttttYgacttVtcKaRagaaaHVgDtaMatKYagagttN
+atWttaccNtYtcDWgSatgaRgtMatgKtcgacaagWtacttaagtcgKtgatccttNc
+ttatagMatHVggtagcgHctatagccctYttggtaattKNaacgaaYatatVctaataM
+aaaYtgVtcKaYtaataacagaatHcacVagatYWHttagaaSMaatWtYtgtaaagNaa
+acaVgaWtcacNWgataNttcaSagctMDaRttgNactaccgataMaaatgtttattDtc
+aagacgctDHYYatggttcaagccNctccttcMctttagacBtaaWtaWVHggaaaaNat
+ttaDtDtgctaaHHtMtatNtMtagtcatttgcaaaRatacagRHtatDNtgtDgaatVg
+tVNtcaaatYBMaaaagcaKgtgatgatMgWWMaHttttMgMagatDtataaattaacca
+actMtacataaattgRataatacgBtKtaataattRgtatDagDtcRDacctatRcagag
+cSHatNtcaScNtttggacNtaaggaccgtgKNttgttNcttgaaRgYgRtNtcagttBc
+ttttcHtKtgcttYaaNgYagtaaatgaatggWaMattBHtatctatSgtcYtgcHtaat
+tHgaaMtHcagaaSatggtatgccaHBtYtcNattWtgtNgctttaggtttgtWatNtgH
+tgcDttactttttttgcNtactKtWRaVcttcatagtgSNKaNccgaataaBttataata
+YtSagctttaaatSttggctaaKSaatRccgWHgagDttaaatcatgagMtcgagtVtaD
+ggaBtatttgDacataaacgtagYRagBWtgDStKDgatgaagttcattatttaKWcata
+aatWRgatataRgttRacaaNKttNtKagaaYaStaactScattattaacgatttaaatg
+DtaattagatHgaYataaactatggggatVHtgccgtNgatNYcaStRtagaccacWcaM
+tatRagHgVactYtWHtcttcatgatWgagaKggagtatgaWtDtVtNaNtcgYYgtaaa
+ctttaDtBactagtaDctatagtaatatttatatataacgHaaaRagKattSagttYtSt
+>THREE Homo sapiens frequency
+agagagacgatgaaaattaatcgtcaatacgctggcgaacactgagggggacccaatgct
+cttctcggtctaaaaaggaatgtgtcagaaattggtcagttcaaaagtagaccggatctt
+tgcggagaacaattcacggaacgtagcgttgggaaatatcctttctaccacacatcggat
+tttcgccctctcccattatttattgtgttctcacatagaattattgtttagacatccctc
+gttgtatggagagttgcccgagcgtaaaggcataatccatataccgccgggtgagtgacc
+tgaaattgtttttagttgggatttcgctatggattagcttacacgaagagattctaatgg
+tactataggataattataatgctgcgtggcgcagtacaccgttacaaacgtcgttcgcat
+atgtggctaacacggtgaaaatacctacatcgtatttgcaatttcggtcgtttcatagag
+cgcattgaattactcaaaaattatatatgttgattatttgattagactgcgtggaaagaa
+ggggtactcaagccatttgtaaaagctgcatctcgcttaagtttgagagcttacattagt
+ctatttcagtcttctaggaaatgtctgtgtgagtggttgtcgtccataggtcactggcat
+atgcgattcatgacatgctaaactaagaaagtagattactattaccggcatgcctaatgc
+gattgcactgctatgaaggtgcggacgtcgcgcccatgtagccctgataataccaatact
+tacatttggtcagcaattctgacattatacctagcacccataaatttactcagacttgag
+gacaggctcttggagtcgatcttctgtttgtatgcatgtgatcatatagatgaataagcg
+atgcgactagttagggcatagtatagatctgtgtatacagttcagctgaacgtccgcgag
+tggaagtacagctgagatctatcctaaaatgcaaccatatcgttcacacatgatatgaac
+ccagggggaaacattgagttcagttaaattggcagcgaatcccccaagaagaaggcggag
+tgacgttgaacgggcttatggtttttcagtacttcctccgtataagttgagcgaaatgta
+aacagaataatcgttgtgttaacaacattaaaatcgcggaatatgatgagaatacacagt
+gtgagcatttcacttgtaaaatatctttggtagaacttactttgctttaaatatgttaaa
+ccgatctaataatctacaaaacggtagattttgcctagcacattgcgtccttctctattc
+agatagaggcaatactcagaaggttttatccaaagcactgtgttgactaacctaagtttt
+agtctaataatcatgattgattataggtgccgtggactacatgactcgtccacaaataat
+acttagcagatcagcaattggccaagcacccgacttttatttaatggttgtgcaatagtc
+cagattcgtattcgggactctttcaaataatagtttcctggcatctaagtaagaaaagct
+cataaggaagcgatattatgacacgctcttccgccgctgttttgaaacttgagtattgct
+cgtccgaaattgagggtcacttcaaaatttactgagaagacgaagatcgactaaagttaa
+aatgctagtccacagttggtcaagttgaattcatccacgagttatatagctattttaatt
+tatagtcgagtgtacaaaaaacatccacaataagatttatcttagaataacaacccccgt
+atcatcgaaatcctccgttatggcctgactcctcgagcttatagcatttgtgctggcgct
+cttgccaggaacttgctcgcgaggtggtgacgagtgagatgatcagtttcattatgatga
+tacgattttatcgcgactagttaatcatcatagcaagtaaaatttgaattatgtcattat
+catgctccattaacaggttatttaattgatactgacgaaattttttcacaatgggttttc
+tagaatttaatatcagtaattgaagccttcataggggtcctactagtatcctacacgacg
+caggtccgcagtatcctggagggacgtgttactgattaaaagggtcaaaggaatgaaggc
+tcacaatgttacctgcttcaccatagtgagccgatgagttttacattagtactaaatccc
+aaatcatactttacgatgaggcttgctagcgctaaagagaatacatacaccaccacatag
+aattgttagcgatgatatcaaatagactcctggaagtgtcagggggaaactgttcaatat
+ttcgtccacaggactgaccaggcatggaaaagactgacgttggaaactataccatctcac
+gcccgacgcttcactaattgatgatccaaaaaatatagcccggattcctgattagcaaag
+ggttcacagagaaagatattatcgacgtatatcccaaaaaacagacgtaatgtgcatctt
+cgaatcgggatgaatacttgtatcataaaaatgtgacctctagtatacaggttaatgtta
+gtgatacacaatactcgtgggccatgggttctcaaataaaatgtaatattgcgtcgatca
+ctcacccacgtatttggtctaattatgttttatttagtgacaatccaatagataaccggt
+cctattaagggctatatttttagcgaccacgcgtttaaacaaaggattgtatgtagatgg
+taccagtttaattgccagtgggcaatcctaagcaaaatgagattctatcctaaagtttgg
+gcttgatataagatttcggatgtatgggttttataatcgttggagagctcaatcatgagc
+taatacatggatttcgctacctcaccgagagaccttgcatgaagaattctaaccaaaagt
+ttaataggccggattggattgagttaattaagaccttgttcagtcatagtaaaaaccctt
+aaattttaccgattgacaaagtgagcagtcgcaataccctatgcgaaacgcctcgatagt
+gactaggtatacaaggtttttgagttcctttgaaatagttaactaatttaaaattaatta
+acgacatggaaatcacagaacctaatgctttgtaggagttatttatgctgtttactgcct
+ctacaaccctaataaagcagtcctaagaatgaaacgcatcttttagttcagaaagtggta
+tccagggtggtcaatttaataaattcaacatcgggtctcaggatattcggtcatataatt
+tattaagggctcttcgagtcttactctgagtgaaattggaaacagtcatccttttcgttg
+tgaggcatcttacaccgctatcgatatacaatgcattccaccgcggtgtcccgtacacaa
+ggaaacttgttaccttggggatataagaaaactcacacgtctcattattaaactgagtac
+aatttttgcacgagaaagtaatgcaatacaatatgatgaaagccagctaatgaaaaggga
+tggaacgcacctcggatctgttgcactggattaaaatccgattatttttaaaaatattca
+gtgctagagcatatcaggtctacttttttatctggtatgtaaagcccacggagcgatagt
+gagatccttacgactcaacgaaaagttataacataactcccgttagccaaagcccaatcc
+cgattactgccctaccctaacgtctgccatctaaatatcgaacttgttatgatcaatgtg
+actacctcccaccctttccccttcatttgttccactggggataagctagcgttttcagaa
+tcaatgcaataagaatagccaattgtctcacttcatcagagctcttggcaattccaggcg
+ctacgtggttctggaatatattcatttttcaaatagtaatacgtttagtgttgctattgt
+ctacacgtttggatattacgttatgtgagcggacatcaatagttgtctaactctttagta
+agccagagatagcactcttagcgaatggataccatcttccataagtttagttaatagtcc
+gaaacaactgcttcgagcatatttgaacctccttgtaggcaaatagcctcttcaaagcaa
+tcttactaatagatagagtttgttttaagggactactagaaatgggacaatcttaatagt
+atgacctaaactgacatttaaagatatatccaggtggcaagcataaagatcattgcgcca
+cctccaccgtgggattacttatcagtcgatatcctatatgctaagtttgcgacggcagaa
+tacaaactaagctgagttgatgctaaccttacctatgataccccattggaccggttaaca
+gccctacttattccaaataaaagaacttttatgctgtagaagctattatagtgatgcctg
+gtaacttcagtatattaaaatgacacacatacgccatatagagctcctggaactttgaat
+aatgagcgaacttcgaagttgaagagcaagaaaccatatgtcacggttgcctaaagcccg
+gtaaccagacatgtgctatcattgatcattatcgaggttttcataaccttgacccattat
+cggctgtgcgcggacaagtacttaaatcactagtttcttcacctgcttatcggtaagaaa
+taaggttggcaaagaatcgcataagacggacgtagagccgcagcgttgtgcgagtccagg
+tgcatgcgcagcaataggattttaaattttgttccatttttaatttagccgtaaggatgt
+ccgtaaatgattgaaaattggattcaatctttgggcctatgctactggaacctgatcgac
+aaaatttcaaacatacgttaactccgaaagaccgtatttttgcggctagaatagtcagtc
+gcttggagccatataccttaccacttaaacgacgtgctcctgtagttgaaatataaacag
+aacacaaagactaccgatcatatcaactgaagatctttgtaactttgaggcgaagcaccc
+tcttcgagacaactaagagtaaagtaccgggcgccgcaaggagtcgattgggaccctaaa
+tcttgacgaattgctaagaggctcagagctaccactgtaatttctctagagcccataata
+aatgaacgatacatccgtaggtagcacctaagggattataatggaagccaaatgcagtta
+ataatattatatactggcgtacacgattcgacggatctctcacatagtgattcacgaccc
+ccccctttgattgacacagcgtcagcattttgcaagaacgatcttctgcatagggtgcgc
+caccgtaaggatgacgtcgaagctacaactgggtataatttaccatgcttccctgatgct
+gagtgcaatacactaagaatgagtttttaccccatatcaccagtatttgttctgttattg
+cgaagaaatggctatgctgagttggcgactaaagtcacccatcctttttattaggtaacc
+ccctcccttaaactaactgatttgctggagctgccctgcatacatatactttatcattta
+tggacgtccgtgacgcttattatccaccatagtcgatatgctacacggattcattaatgg
+atcgtaggagtttaagttatatttactaagatcggtctcggctactatcccgccttaccc
+ggcgctatttacggccatttttaatatattgacggtaattattcctatggtttcgaccgc
+acgtccttggacaagaaagaatggcaaaaaaaatgtaaaagaaaaaaaatattgagtccc
+taccatcatataaaaaatatgtgatgagtaacttgacgaaatgttagtggttattaaaga
+ctatctattacaccttttgttttctgtcgtagtatattaaagtctagaagccttacagga
+aaatcagggttatacagccgatactccgcagcatgaatcatcgaggaggtgtcctaccat
+cgcgccttgtaatcttgtctgtgtatactgtatttagaccttttatacaaagtaaatatc
+tcggctttatgtgattgggaggggcctactcaaacatgatgacttgacctaataatcact
+gtgcgggcgtcttatgactagctattccttgaaatccaccaccaaatggttaatatgtaa
+aaactttgacgatgaaacaaggtgaatgtgtagttactttgtgtaattagctgcgtcgag
+cattgcttgtaaaaccgtcaatcgcacacgttacttccataaaatttctacgaatacacc
+cttcttaaaaaaaacgtaggaattcacgagtttaacaaacgataactgtataaagtggaa
+gtccgaagaaagcagatgcccgaactactcgaagatgtttcgttttcttaaccatagggg
+cttcttaatggcccactacgcacattttgttcaagcccgagagggacatccccattacgg
+gagtattactaaaactgttccgtaatacgttcagcaagggatgaaaaaggccactgctca
+agttattgacgtgggagtattacatcggaagcctgaatcccacactatgatggtctgtac
+aggcctagggactgcgtctagacggtattaccggcttctaatcatacgatcgtgagtctt
+aacgggaagtaaggctcacacctaccccaaaccatttatctatgtaagtataaaattgtg
+cgtaagtgttcaaagtggacaataaagacgtggcaaaaacccccgcacataagccgcttt
+agatttcacaaataccaatgcggttaaaaacatccttgagtcgtacatacaccatactcg
+cgttaaacggatataacagaagataataaatccggatgtggagtcggtgtaactatagaa
+agccaagtgaaataatgcttaccagtcatttagctatacggctttcatttcatgtcaaga
+gggtggagtttgacctgtacagttgatatatcaccgatacttagaactcacctaaagcta
+aaattgctcgcagcgtgtaatccgcatattacaaacaatagatgggattcattatacata
+agacacgatgatctgctttttcaggttgcgagatgttgcctatcgtcaatcgagtcctgc
+cttacaccacttaaacaaaagtattgacagggaacctattttcgaggtattatatagtcc
+agcttgaatatcaatttgacagttaacctagtgaaaatcagtaagaggaaatacgccaca
+ttctccagtgaaattctacgggttatcgtctagtccaactatcaattataactcacgaga
+tataagtaaattctcgtacttggcctgatttttattatactttggatccttagtaaacag
+gaagggagaaaccttcaacgaaaaacactggattttgttttactctcaaagctcttatat
+gacggaaataccctgtcaagtcttaactttattactagactaatgaaatgggcttggggt
+ggccagaatcatagtacaatttagcggatacactattcggactttcctatcggctgtctg
+gttggataagtatggggactaataggctagacatacctatacttaaactatacaggcgtc
+atctatctctgcaactttggagttccctgatgttctcccgccctttgggttcacatcttc
+tataccgacacccctaataacgattagtttgtgggttagagtaaattaatacggttaata
+ttaatgtatcgttgaaaagctggtgtcgccaataaggtaaccggctaggcagagtatatg
+tcacgaagtataactaccctaatgataagctgtaggaataaaattaatgctgtctctaag
+cgaagagatatttccgactctgttttaatgacgaatctcattacttctgacttgcaaatg
+ttcaatatggcacggtttcacggcacctttgtgacgcatataatgaacttagaagattat
+aacgacggaactttatatgataatccgttacgattaaagaatctgttaaatatcataatg
+gcattcagttctagaccgtgcatcatggtaaacttactttctctgcatggcgacatacat
+ttcgctattcaaattcgcgtgtggttacacccactcgcacctttggaatattaagagaag
+atgatcagaaaatccattcgctcaatttttctgacgtacgtctaatttatcctaggagac
+aaatcgttttatgtctctcacatttttgaagaaaggttcgagagacaatactcaggtcct
+gaactgctagaagatactcggtggagcgtggcaacaatgaaaaactcgtgacataaatga
+atgatacttttccaagttcagttaagtgaatatgtttaacatacccggcttttcgatctt
+aagctgacgctggacgtgcgagtaatgtcagtctcttacatacactagtgactccaagtt
+tcgtcaaaaacgccccctcccttctcgagcccactcacgctatgtattgacgcgaacttg
+ttcgggatcagacttttcaggagttcggtcgcgtgtccctatgtgctaatatataagtta
+gatcgcattagatgctaatctgaatacttatagacgaccttcaacgagaacgggtaccac
+cttgaggctagagttaggtgtgaaacgacaggtagggacatataaaatttgagtgcggct
+ttagttaagggtttaattacctactcaaacatcacgctcgcgcccttcgtacgtaatcga
+ccatctagaggctaaggggactgtactaggtagtgattaatgatatcctagacgcacgtg
+ccttagatcttcagactctgatggtccgcgatcaccgtaattgtagtcctccaactcgat
+cactttgttggcgtcaaagaaattacgatatctaaatacttataatacaataaccaagga
+tgagaatgactcatcgcgttggagttatattgcttgaagttctatggaatgaaagcacgt
+tatctgccgtcccaatatctccagtgagctaattcattggacggtccactttgatcaatc
+cccgaggagatgttcggacactttagtctgtaacacttagcgttgagaccacgaacaatt
+gattactcagtcttgaaggtgttttccaaagttcattttaaataagactacgataggcct
+ttcctattgatataaactacccggctctgttgttcgtgtgagtcgtacttctctgtgttt
+ttctgattatagcaagattcgattcttagtgtaaacagcgatttttatttgacccgtcaa
+tgagaagcgcataggatctaagcaaaattatcaagttgtgccacaaggtaagatctttcc
+agttattgcaggtaggatgtatcccacgttgatagtatgaggtctgacgtcaactgtcta
+ggagagttgaccgcgtgcgggtacaccggatttgcatcgatgttgagaacgcagaactcc
+cactgtcgtggcggcgttcctgatatttagcaagaggcgttgataaagccctcatcatct
+agatctcgacctcatctgccctcttgctccatcattttctacacagactactttcctatc
+tacgttagtataattgctttctatcttagtatcatttagagcttctccgtcaacaggttc
+gtgctattaaagttagtacgaaagggacaacttgtagcaacgcatttaatcggttttcga
+ctacttcgcacaaaatcagataaagaagtttgtcattctattagacattgaattgcgcaa
+ttgacttgtaccacttatgatcgaacactgaatcaagactgtgattaactaaaatagaca
+agccactatatcaactaataaaaacgcccctggtggtcgaacatagttgactacaggata
+attaattggactggagccattacattctctacaatcgtatcacttcccaagtagacaact
+ttgaccttgtagtttcatgtacaaaaaaatgctttcgcaggagcacattggtagttcaat
+agtttcatgggaacctcttgagccgtcttctgtgggtgtgttcggatagtaggtactgat
+aaagtcgtgtcgctttcgatgagagggaattcaccggaaaacaccttggttaacaggata
+gtctatgtaaacttcgagacatgtttaagagttaccagcttaatccacggtgctctacta
+gtatcatcagctgtcttgcctcgcctagaaatatgcattctatcgttatcctatcaacgg
+ttgccgtactgagcagccttattgtggaagagtaatatataaatgtagtcttgtctttac
+gaagcagacgtaagtaataatgacttggaataccaaaactaaacatagtggattatcata
+ctcaagaactctccagataaataacagtttttacgatacgtcaccaatgagcttaaagat
+taggatcctcaaaactgatacaaacgctaattcatttgttattggatccagtatcagtta
+aactgaatggagtgaagattgtagaatgttgttctggcctcgcatggggtctaggtgata
+tacaatttctcatacttacacggtagtggaaatctgattctagcttcgtagctgactata
+ctcaaggaaccactgctcaaggtaggagactagttccgaccctacagtcaaagtggccga
+agcttaaactatagactagttgttaaatgctgatttcaagatatcatctatatacagttt
+ggacaattatgtgtgcgaaactaaaattcatgctattcagatggatttcacttatgcctt
+agaaacagatattgcccgagctcaatcaacagttttagccggaaacaatcgaagcatagg
+gacaatgtatcttttcctaaattgccatgtgcagatttctgagtgtcacgaagcgcataa
+tagaatcttgtgttgcctcaactcgttgaaaagtttaaaacaatcgcagcagtctttttg
+gggtctactgtgtgtttgcaaaataactgaaagaaacgcttgaacaactctgaagtagct
+cgagtactcattaaagtgtaacacattagtgaatatcggccaatgaaccaaacgcttccc
+ggtacgctatctctctcatcgggaggcgatgtgcaggttatctacgaaagcatcccttta
+cgttgagagtgtcgatgcatgaacctcattgtaacaatagcccagcaaattctcatacgt
+gcctcagggtccgggcgtactcctccatggaagggcgcgcatctagtgttataccaactc
+gctttttaactactatgctgtagttctacaggcatagtggccagtattttctaacttctc
+tggatagatgctctcactcctcatccatcacggcttcagtttacgtcttacttgcttgtt
+cagcaacggatggaggcattaagtatcttcactgttccctaaaattgctgttcaatatca
+aagtaaggacgatacagggaaagctcaagcacactcattgaatactgccccagttgcaac
+ctcacttaatctgacaaaaataatgactactctaagtgttgcggaagcagtctcttccac
+gagcttgtctgtatcacttcgtataggcatgtaactcgatagacacgaacaccgagtgag
+aaactatattcttgcttccgtgtgtgtgacaccaggtaattgatgcggatataagctgga
+gatcactcacgcccacacaaggcgctgctacctctttattccaatgtgtaagaatttgct
+aacttcatttctagaccgcagctttgcggtcataatttcacggtacggacccttgggtta
+gagacttgataacacacttcgcagtttccaccgcgcacatgttttagtggcttctaacat
+agaatttttgttgtgacataaagagtgcgtgggagacttgcccgaccgttaagccataat
+caattgaaagccccgtgagtcacatctaattggttgtactgcgcatttagctatccttta
+gctgactcgaagagattcgattcctaatataggttaattagatggctgccgcgcgaagta
+aaacgtgaaaaacgtagtgcgcagatctgcataactcgcgcttaattacttatgagtagt
+tccaagttcgctacgttatgagagagattggaattaagcaaatatgttttatggtgattt
+tgggatgagaaggactgctaagtacggctactaaacaaatttctaaaaccgccatctacc
+ttatcttggagacatttaagttgtatatgtcactagtctagcttttgtctgtgggacgcg
+ttctcggaatgagggaaatgcaagagccgattcatcaaatgcttatctaagaaagtagtg
+gactattacaccaagcacgaatgccagggaactgctttcttgctcaggacctcgcgacaa
+ggtaccccgcataagtcctagaattacatttggtcagcaatgctgacatttgaccgtgaa
+aacataattttaatcagaaggcagctcacccgcttgctctagatcttatctttgtatgaa
+tgtcagaatttactgcaatatccgttccgaatagtgagggcttagtatagttctctgtat
+acaggtcacatcaaactccccctgtcctagtacagctctgagctttaattaattgcatac
+atttccttcaatcatcagatgaaaacaccgcgaatcatgctcttctcgtatagggcaaga
+gaagcaacaaacaactagcccgactcacgttcatccgccgtatccttgttcagttcttac
+tccgtattaggtcagcgaaatctaatcagaataatcggtcgcgtatcaaaattaaaatcc
+cgcttgaggttgacaattaaaacgctgagcagttatcggctattagatagtggggtgaaa
+gtaattggctggaattatgttaaaacgtgatattaagctaaaatacgctacttgttgccg
+acctaattcagtcattcgatattcagttagagccaagaataacaagcttgtataaattga
+acggggtgcactaaacgatgtgttactctaatattcagcttggagtatacctgaaggcga
+attcatgtatcggccaataataagacgttgaagatcacaatttggactagcaaaagaagg
+tgatttatgcgtggggattgagtccactgtacgagtacggtctctggaaaattataggtt
+cagggaatataaggaagtaaagataattaccaagagatttttggtatcgctatgacccag
+aggtgttctaacgtctgttttgatccgcagaatttctgcctcaatgcatatttgacggac
+ttgaactagagcctctaaagttaaatggcgacgcaactgttcctaaacttcaattattac
+tactctttttttcctagggtattgtagaggccagtggacaaaataaatcaaatttaagat
+gtttcggacattaacatcccccgtagcatagaaatcatcagttatccaatctctcatcga
+gcttttacaatttctgctggcgctatggacagcatatgccgcgagacctccgcaagactc
+acttgatcactgtaagtatcttcattagaggttagagcctatagttaagctgctgaccta
+gtaaaattggtattttctaattttattgctcaagttaaaggttagtgaagggataatgac
+gttatttttgaacaatgggttgtattcaattttatatcacgaatggaacccttcattccc
+ggcataatactagacgacacgaacaagctccgatctatcagccaggcacgtgttaaggtt
+taattccggcaaaccaatgaagcatcaaaaggtgacctgatgcaacttagggtcacgatg
+agtttttcaggactacttattacctattaataagttaacatgagccttcataccccgtaa
+gacaatacatactccaccaattagaattctgagccatcttatctttttgtatcatcgaag
+ggtatggccgaataggttaattagttactcctaacgtctctacaggcatgcatttgacgc
+accttcgaaaatagtcaatctctcgccacacgcgtctagtatgcagcatcaaaaatatag
+tccacggtttccggattaccaaacgcggcaaagagaaacattgtatcgacggagataact
+taatacagaaggaaggggcatcttcgaatacggatgaataattctatctgtttattctga
+catcttgttttcaggttaatcttacgcattcaaatgacgcctgccccatgcgtgcgcaat
+tattttctaatattgacgagagcaatctcactccttttgggtctatttatgttttattga
+ggcacaagcctatacagaacaggtactattaaggccgtgagtgtgagactcaaaccgtgg
+aaacaaaggatgggttgttcttggtacaagttttagtgcatgtgggcaatccttaccaaa
+atcagatgctatccttaactttgggctgcatttaagatggcggttggaggcctgtgagaa
+tcctgcgtgtcatctttaatgaccgaattcatccatgtagattcagatcacacactcatt
+ccttgatgttgtctaaacaaaagttgttgtggacgcattggagggagttaagtaacaact
+tgggatcgcatacttataaaaattatatgttaaactttcacaaacgctgaagtccaaagt
+aactagcccaaacgcctcgagagtcactaggtattaatggtgtttgagttcctgtgaaat
+agtgttcgaaggtaaaatttatgtaccaaatcgaaagaacacttaataaggcttgcttgc
+acggaggtatgatgtttactgactctacaaccctaattttccagtacgtacattcattcc
+aataggttagttctcaaagtgctatacaggctcctcaattgatgatatgcttcagccgct
+ctatggatattagctcattttatttaggaagcccgcttagaggcttactatgagggaaat
+gccaaaatgtcatacttttcggtgtgtcccatatgacaccgctttacatagaatttgaat
+taaaacgcgctctcccgttcactaccatacttggtaccgtgcgcatattacatatagata
+taggatcattttttaaagctgtactaggtttgatcgacaatcttatgctatactatatga
+tgtaaccctcataatcaataccgatcgtacgatcctagcataggtggcaagcgattttat
+gccgattattgtgttaaatagtctgtgagtgtgattatcagggctacgttggtagagggg
+ttgtatagacctcgcacacattgtgacatacttaacaatatacgaaaactgatataataa
+atccccttacccaaacaccaatcccgttgaatcaactaccataacgtctcccatataaat
+tgcctacttgtttgcataaatctgaatacataacaccattgcaccttcttgtgttccaat
+cccgttaagattgccttgtcagatgatatgcaagaacaatagcatttgctagcaattatt
+aacagctcttcgaattgcctccacataacgcgggagggtatattttaatttggcaaatac
+taagtactgttggcgtcatatgctattaacggttggatattaagttatgtcagccgtaag
+caagagtgggcgaaatattttgttacccagtgagagcactcttagagtttggatacaata
+ggccatatgttgacttaagaggacgtaactacgccgtacaccattgttcaaccgacttct
+tggcaaatagaatcgtattagcaatcttaagaatagagacacgttcgtgttagggtatac
+tacaaatccgaaaatcttaagaggatcacctaaactgaaatttatacatatttcaacgtg
+gatagatttaacataattcagccacctccaacctgggagtaattttcagtagatttacta
+gatgattagtggcccaacgcacttgactatataagatctggggatcctaacctgacctat
+gagacaaaattggaaacgttaacagcccttatgtgtacaaagaaaagtaagttgttgctg
+ttcaacagatgatagtcatgacgcgtaacttcactatagtaaattgaaacaaatacgcaa
+tttagacagaatggtacggtcatgaatgacagtaattcgaagtgctagaccaacttaaaa
+taggtaaacgtgcccgaaaccccccttaacagaaagctgctatcatggtgcagtatcgac
+gtgttcagaaacttgtaacttttgagcaggtccgagcacatggaagtatatcacgtgttt
+ctgaaccggcttatccctaagatatatccgtcgcaaactttcgatttagtcccacgtaga
+gcccaagcgttgtgcgactccacgtgcatgcccagaaatacgagtttaaatttggttaca
+tggttaattttgaccgaagcatcgcactttatgattgataattggattcaatatgtcgcc
+ctatgcgaatgcaacatgatccacaatttggctataagacgtttaatccgtatcacactt
+tgtttgcggctagtatagtaacgcccgtgcaccaagagtcagtaacaattataagtactc
+cgcaggtacttcaaatataaaaactaatcaaacacgacccatatgatcatctgaagatat
+ttggaactttctcgacaaccaccctcgtactcaatacttacactaatcgacaggcacacg
+caacgtgtacagtcgcaccatattgagtcaagatttgcttagtggcgatgagcgtacacg
+cttatttctctagtcacaattagttatctacgagacatcacgagggagcaaataagcgat
+gttatggctacacataggcacgtatgaatatgatataagccagttaaacagtcgaaccat
+cgagcaaattctcatgcaccaacccacacgttgaggcacaaagagtaagctgtttgaatg
+taacttcttctgctgagcgggccccaacgtaaggatcaactagaagagaaaactcggtat
+tagtttaaatgcgtcacggagcatgagtgcatttcactaagaatgtctgtgtaaccaata
+taacatctatttgttatctgattgcctacttatggctttgcggtcgtggcgactaatgtc
+tccaatccttttgaggtcggtaccaactccctttaaattacgctgtgcaggctcatgcac
+tgcatacatatacggtagcaggtagggacctcacgcacccttattataatcaatagtagt
+tatcagtcaacgaggcaggaatgctgaggtcgaggtgttggtatattttctatgtgccgt
+ctaggcgactatcacgcattaccaggcgagatttaagccaattttgaatatagtcaacgt
+aatttttactatgggttccaccgaaacgccttgcacaactaagaatcccataaaatatcg
+atatcaaataaaagattgtgtcaataccttcatatatattttttcggttgactaacgtga
+actaaggttaggggttttgtatgtctatataggaaacagtttcttttctgtcctacttta
+gtaaagtcttcaagccttactccaaaatcacggtgattaagccgttactcagcagcatga
+ttctgcctgctcgggtcctaaaatccagccttgtaagagtcgctgtgtattagctaggga
+gacctttgttaaaaaggatatatcgcggcgggatgtgagtgcgtggcgcatactcaatct
+tcagctcgtgtcattataatatctctcccccacgcttttcactagatatgccgtgtaagc
+aaacaccttatgcttaatttcgaaaatattggtacttgaaaaaagctgtaggggtactta
+atgtctggtaggagatcaggagagaattgagtgtaaaaccgtaaagccctcacctgactt
+catgtaaatggcttagaagactccatgatttaataaatactacgaaggaaagactggatc
+taaagataactctagtaaggccaactcccttcaatgctgttgccagttataatccaagag
+ctgtccttttctgaaccatagcggcttctgaagcgaactagaagcaaagttggttctagc
+cagacagccacataccctgtacgggtgtattactaaaactggtccggtattagttcacca
+agggaggaattaggcaaaggatctaggtatgcaagtcggagtattacatccctaccctga
+atccatcaataggttcctctgtactggccttcgcaatgagtattcaaggttgtacagccg
+tataataataagatagtgactatgaacgggaagtaacccgctcaccttccccaaaacatt
+gttatatctaagtattaaagtctgccgtagtgttaatactcgaaaataaacaactggcaa
+attacaccgcacttaagccgcttttgatttatatttttccaatgcgcttttaaaaataat
+tcagtcctacatactaattaagacccttaaacggagatatcacaagttaagttttaacca
+tctcgactaggtggaactatagatacccaactcaatttatcattacctgtaatgttccta
+gaaggattgcatttcatgtcaagacggtggagtttcacagcgaaacttcagtgtgaacag
+attctgagaaatcacctaaacctattagtcagagcacccggttagaaccagttgtcaaaa
+aatagagcggttgcatgagacagaagtaacgatgagatccgttgtaacgttgagacatct
+ggcctatcgtcaatacagtcctcccttaaaaatatttttaaatactaggcaaacccaaca
+taggttagtcctatgtgatacgccacatggtatatcattttgtaacgttacctagggata
+atcaggaagtggaattacgcaaaagtagacagtgaaatgcttagggttatagtctagtcc
+aaagataaaggataaagcacgtcagagaactatattagccgaatgggaatcattgttagg
+agactgtggatcatgtctaaaaagcaacgcagaaacagtcatcgaaaaaatctcgttttt
+gtttgaatctaaaagagctttgatgaccgatagtacctgtatactagttactgtattacg
+tgtctaatgatttcggattggggtccccagaatcagacgtcattgtagacgattcaagtt
+taccaatttaatttcccagctctccttggagaactatcgccaataattgcagtcactttc
+cttttctgaaacgataaagccgtcagagttctctgcaacgttggacttacctgaggttct
+aacccactttcggttctaatagtagttaacgacacaacgaataacctttactgtggggct
+ttcacgatattttttcgcttattattaatggttacgtcataagctggtgtccaaattaag
+gttaccggcttcgcagagtagttgtatccaagtataacttccctaatcataagatcgagg
+tagaaaattaatgctgtctctaaccgaacagatatgtcccactatgtggtatggacgttg
+ctaattacttctgaagggaaattggtcattatggatacgtgtctaccatcaggtcggacg
+cagatatggttctgtcttcagttgatccaccgttctttataggataataactgacgatta
+aagattatggtaaatagattaagccaattctcttcttgtcagtgaagcatccttaactga
+cttgctctgcagcccctcatacatttagctattcaaagtaccggctcgtttcaaactctc
+ccacctttggaagaggttgtcaacttgataagtatatcatttacagcattttttcggacg
+tacctctaatgtttcattgcagaaaattagttttttctatcgcacattttgcaagtaacg
+ttagagacacaattatctgcgaatgaactgctagatctgacgaccgggagcctcgcaaat
+atcaaaaaagactgacatatatcaaggagtcgttgacaagtgctggtaagtcaattggtt
+tatctgtcccggcgtttcgatcttaagctgaccatgcacggcagagtaatgtcactctcg
+ttcttacaagtctgtctccaagggtcggcaaaaaagacccctccattctcgagcccactc
+acgatatgtagggacgacaacttgtgcggcttatgaattgtctggactgcgggcgagggt
+ccatatctccgaagttagaagggacatacctttagatgataagatcaattcttattgacg
+aaattcatccacaacggggaacaacttcaccctagacttacgtctgaaaagacacctagc
+gtcttataaaaggtcagtgccccgtttcgtaaggctggaattacctacgcaaacttaaac
+ctcgcgcccttccttacgtatcgacaagatagaggctatcgcgaatgtactacggaggca
+tgaatcatatactagaaccaagtgcctgtgatattaacaagatgatccgacgcgagcacc
+gtaattctaggcataaaactccagcaatttgggggccgaaaacaaatgacgttagctaat
+taattatatgacatgatcaaaggaggtcaatcacgcatcgagttcgacgtatattcattg
+aacttcgtgcgtttgaaagaaacttttatgaaggcaaaattgatcctgtctcctatttca
+tgcgtacctcctagttgataattccccgagcagtggttaggacacttttgtcggtatcaa
+gttccggtctcaaaacgtaaaattctgtaatctgtatggatggtctgtgaattagttaat
+ttttatgaagtcgtcgagacgcagttcctattgatttattctaaacggagatgtgcttcg
+tgggactcggaagtagatctgtgtttatgattattgctactttagatgctgactgttaac
+tccgtgttgtttttcaaccgtatatcacaaccgaattggatagaacctatagtttcaagt
+tctgccacaaggtatcatatttacagttagtgctggttgcttctttcaaacgtggtgagt
+ttgtgctatcacgtcaacggtagagctcagtggaccgagtgcgcgttcaaccctgttcca
+gagagggtgtgatagcacatataccacgctcgtcgaggcgttcatgatagtttgcaagag
+ccggtgttaaacacatattattattgttatccaactaatcggacctatgcataaagcatt
+gtctaaacagaataattgcctatatacggtagttttagtgatttatatcttagtatcagt
+tagagcttcgaactcttcaggttcctcatatttaacgttcttcgaaagcgaaaacttcta
+caaacgaatgtaagcggttttccaagtagtacctataaatcacagaaagatctgtctcag
+tatagttgaaatggtattcagctagtgacgtgtaccaattatcatagttcactcaagcaa
+gacgctcattaacgaatatagacaagacactatatcatataataaaaaagaacatggtgc
+tcgaacatagttgaattcaccatattgaaggggaatgctgacatgtaattcgctactaga
+cgatcaattccctacttgtcaaagttgaactggtacgttcttggaattaaatatgattgc
+gctggaccaaattgcgacttcttgagtttcagggcaaacgattgagccggaggatgtccg
+tctcttacctttcttgcttatgataaacgacggtccctgtacatcactgggaattctcag
+caaaaataattgggtaaatcgagactcgatgtattcggccacaaaggtgttagacgttaa
+agattattcaacggggcgataataggatcataaccggtatgcaagcgcattgaaagagcc
+atgagatccttatccgataaacgctgcacggtatgtgcagccttattgtcgatcacgaat
+ttataaatgtagtctgggctgtaagttgaagacctaagttataatgaagtgcaataccaa
+atcgattcatagtggattatcagactcaagatatctcctgataaattacagttgttaaga
+tacggataaaatgagatttaagattagcagcctctaatctgtttcaatcccgttggaatg
+tggtatgcgatcaaggttaagttaaaatcaagcctgtcttcagtcttgattcttgttctg
+ccatcgcatgcggtctacgtgagttaatatgtagcttacgttctagcttgtgctaatctg
+agtatagattcgtagaggaatattatcaagcttccacgcctcaacgtacgtgtattggtc
+acacaagacactaaaagtggaagtagcgtaaactatagtctagttgttaaatgctcagtt
+cttgttatattcgatatactcttggctaatttatgtctgagtatataaaattaatgatat
+taacttgcatttcacggatcccttagaaaaagattttgaccgagcgcattataaacggtt
+acaccgaatcaatagaagcatacccaatagctttctttgaatttattgcctgcgcaactt
+ggctgactctctagatccgaataattctatatggtcgtgacgaaactagttcattactgt
+ttaaaatgccaacatgtcttttgggccgataatggctctttgcaaaattactcaatgata
+cgattgatcaaagcggtagttgctagtggtagcatgtaagtctatcaaatgtctgattat
+ccgaaaatcttccaaaagagtccacgtaccatatctatctcatagcgacgcgaggggaac
+cttatctaactatcattccatttaccgggtgactctcgatgcaggatccgattgggataa
+attgcccagaaatggctcattcctgactaagggtaaggccgttctcagcaagggaacccc
+gcgaatctaggcttataccatctagattgttaactacttgcctgtagttctacagccata
+ctggacagttgtttctaaatgatcgggattcatgctagcactcctctgaatgcaccgcgt
+aagtttaactattacgtccgtgggcagataaggatggaggctgtatgtatcttaactgtt
+acctaatatggctggtaattatcaaagtaaggaccttaatgccatagcgctagcaatcgc
+tttgtatactgaccatgtgccaacctctcttaatctgtaaaatataatgtcttagctaac
+tgtggacgatcatgtctctgcctagagcttcgctgtatcaattcctatagccagcgtact
+agtgacacaacaacaccgtgtgagaaaagatattagtccttacgtctgtctctctacagc
+ttattgatgaggattgaacatggacatatagctccccctcaaaagcagatgctacctctt
+tattccattctcgaacatttgccgaacttaatttcgacaaacctgaggtcacgtcttaat
+ttatcggtaacgtcacgtccctttgagactggataaatatattaccaggggccaacgagc
+aattgttggaggcgcttctataatacaaggtgtcttgtcaaagaaagacggcgtgcgtct
+cgtgcaactcacttaaccaatattaatgtgaaacccccctctctcacatcttatgcggtg
+tactgccctggtacatttcctgtacaggactccaacagtgtagattcctaagatagctgt
+tggagttgcctcacgccagatcgaaaaactgaataaactagtgagctgagctgcagaaat
+accgcttaattacttatgactagttcaaagggacctacgtgatgtcagacattgcaagga
+agaaattaggtttgtgcgtcattttggctggactagcactccttacttcccctactattc
+aaatgtcgtaaacagcatgagacaggatcgtgctgacatttaaggtctattgggaacgag
+gctacctttggtcgcgcgctcgcgttctccgaatgaccgaaatgcatgagcacagtatgc
+aattgcttatagatctaaggtctggtcgttgaaaccaagcacgtaggcctgggaaatcag
+ttcttcctcagcaactacacaaaagcgtccaagcattagtacttgtagtaaatgtccgaa
+cctatgcgctcatttgaaagtcaaaaaatatttttaagcagtaggcacctaacccgattc
+ctctacttagtagctttctttgattctcagaattgactgcaatatcactgcacaattctg
+tgccattactagacttctctgtattaacgtctcatcttactaacactcgcctaggacaca
+tctgagagtgaagtatttcaatacatttactgaaatcttcagttctaaaatccccgaata
+aggctcttatcggtttggccaacacaagaaaaaaacttcttgcaccactcaccttcatac
+gcaggagcctggggaacttagtaataactatttcggcagacaaagcttataacaagttgc
+cggcgcgtataatatttaaaagaccccttgagctgctcaattaaaacgctcacctggtat
+aggctattagatagtgccgtcttagtaaggggcgggaattatcggataaactgatatttt
+gataaaataaccgacttgttcacgacataagtcactaaggagattttatctttctccaaa
+gtatatcttccttggataatttcaaagcgctgcaatttaagttctgttactagtttatgc
+tgctgggaggtgaccggaaggcgtagtaatctagaggcaaattataagaagttcatcata
+tcattttcgactacaaaaacaaggtgttgtatgccggcgcattgtgtaaactggacgagt
+accctagatggaaaattatacgttaagccaagatttcgatgtaatgataattacctacac
+atttttgctatccataggaacaagagctgttctataggctcgtggcatacgaacatttgc
+tgccgctatgaatattggaagctcttcaactacagactctattcttaattgccgtcgaaa
+atgggccgaatcggctattattaatactcggtttttccgaggggattgttgtcgacagtc
+gtaattattattaatattgatgttggtgaggtcatttaaatacaaccttgcagacaatga
+ataagggatccaatctctcatactccttttacaattgctcatgcccctatgcaaacctta
+tgccgccacacctccgcaactctctcttctgaactgtaagtagcttcattactggtttga
+gactatactgaagctgatgacattctaaaatggctattttcgaatgtgattcataatgtt
+tatcgtttgggatggcagaatcacgttatttttgatatagcccgggtattctattgtata
+gaacgtatgctacaagtcattccccgaagaagactagaagtaaacaacatgcgaccatcg
+ttaagccacgcaaggctgtagctttatttcccgataacctatcttccataaatagcggac
+agcaggatactgacgctcaacatcagtggttatggtctaatttttaacttttaataaggt
+aacttcagcaggcatacacagtaactctttaatttataatcaaattagaagtctgacact
+tcttatatttttctatcatccaacgcgatcgcccattagcttattgtgttactaataacg
+tatctaaaccaatccttttcaagctactgcctatattgtcaatatatacaaacaacagga
+tagtaggctgcttaaaaaatattgtcaaccgtgtacgctttacaatacccggaaatcaca
+aactttgtagacaacgagtgaaatttatacactacgaagggccagcgtacaagacccatg
+aattaggcgatatgtttattctgacatattggtttatccttaatctgtcgctgtaaaatg
+aagccgcccccatccctgcgaattttttttcgaagattcacgactgaaatataaatacgt
+ttggctatatttatgttggagggaggcaatagcctttactgttaaccgaagatttagcca
+gtgagtgtgacactaaaacactggaataaatgcaggcgttcttctgggtaaaaggtttag
+tcaatctcgcctataagttcatatagctctggatataattatctggcccatgcatttatc
+atggcgcttggtgccctgtgtgaagccggcctctcatattgaaggtccgaagtattccat
+gtacattaagatcactctctcattcatgcatcttggcttaacaaatctggttgtccaagc
+tttccaggcacgtatggtacaaattcggatcgaatacttataaaaatgatatgttaaact
+gtctaaaacgctcatctacaaagtaaagtgcactaaccaatagagtctcaagaccgtgta
+atgctggtgcactgaatgtgtaatacggttagaagggattagttatgttacaaatccatt
+gaaaacttaagaagcattgcgtgctcggagggtgcatcttttatcaagagactaacatta
+ttttcaacgacgtacatgctttacaatagggtacttatcaaacgccgagaaacgcgccta
+tagtgatgttatgattatgacccgatatccattggaccgaattttatgtaggttcccagc
+gtactcgcgtaatatctcggtattgccataatgtaatacttgtcggtctctcccagatga
+aaaagcgttacagagtatttcaatgaaaaacagcgcgcaacgtcaatacctttaggggta
+acggccgctgatttcatatagatatacgataagttggtatagctctactaggtggcatcc
+acaatcgttgcatttactatagctggttacaatcataatctataccgttccttacatact
+accatagcgggatagcgtttttttgccgttgattgggtttaagaggatgtcagtctcatt
+atatccgattcggtgggagagccgttgttttcaaatcgcacactttgtgacataatgtac
+aagataacaaaactgatataagatataaactgtcaatatcaccttgacacttgaatcaaa
+gtaaattaactcgcaaatataatttgactaattgggtgcagatttctcaattaataaaaa
+aatggcaccggatgggcttacaagccccttatcattcacttgtatcatgatttccaagaa
+caatagaatttgctagcaagtatgaacagagattcgaattgcatccacagtacgccggag
+cgtttattttaatgtggatatgacgatgtactgttggcggcatttgctagtaaccggtcc
+ttatttacgtagcgcacacgtaagcatgtctgggagaaatatggtggtacaatctcagag
+aaagattacagtttggtttaaataggacttatcgggtcggaagtggaacttaataagcag
+tacacaattgggcaacagacgtcttgcctattacaataggattacaatgcgttagatttc
+agacacgttcgtgtttggctattcgtcaattccctaaatagttagacgatcaactattat
+caaagtgattctttgttcatcctccattcatgtaacagatggcacactacgcataacgcc
+gaggaattttaacgagatttaagagagcagttcgggcacaacccacttgactttataaca
+gctcggcagcataaacggtaatatgtgacaaatttccaaacgttataagaacgtatgtgt
+acttagaaaactaagtggttcatgttcaacagatgtgacgcagcaagcctaacttatcta
+ttggttttgctataaaagaacaaagttacacagaatcctaagggcttgtttcacacttat
+gcctagtgcttcaccatcttaaaatagcgaaaccggcacgaatcaaaccttaaaacaatg
+cgcagatattggtgatggtgactccgggtatgataatggtaactgttgaccagcgcccac
+ctcatcgaagtatagaaagtggttaggataaggatgagaccgaacttatttccggccata
+actttagattttctacctagtacacaacatcagggcggacacgaaaccgccatcacatca
+tataccaggtttaatttgcttaatgggggaagtgtcaacgaaccttcgaactttagcagg
+catatggccattatatatggccccagagcagaatgctacagcagacaaaatttggattta
+tgtagtttaatacctatcaaacttggtgtgaccatacttgtctaacgacagtgcacaaag
+tgtaagttacaattattactactcagcagcttctgcaatgataaaatcttatcatacacg
+tcacatatgataatatctacttagggggaacgggctccacaacctacatagtactcaata
+cttacactattcgacaggcacaccaaacctgtacagtcccaaaagattgagtcaactttg
+cagtactgcagatcacagtaatagcttagttagcgagtcaaaattagttttctacgagac
+tgcacgaccgtgcaaatttccgatgtgttggctacaaatagcaacgtatgaatttgtttg
+aagccacgtaaactgtacaaccttagagataagtctcaggctactaaaaacacgttgtgg
+cactaacaggatcatggttgattcttacttattcggctgaccggcccaataagtaacctt
+caactagaacagaataatcgggagtagtttaattcagtcaaggtgcaggtctcattgtaa
+ctaacaagctctgtgtaaccaagttaaaatcgttttcttagcggattccctacttatgga
+tttgagctcgtccacaatattcgatacaagaagtttgtggtccgtaacaacgaaatttta
+attacgctgtgcagcctcatccaaggaattaatagaaggttgatggtaggctccgaacgc
+tccatgattataatcaagtggactgtgcagtaaacgaggaaggtatcctgacgtcgtggt
+gttcgtttttgttatttgtgccctatacgagtagataaaccatgaacagcacagtgtgaa
+cccatggttgattttaggctaccttatttttaatttccgttacacagaaacgaattccac
+aactaacatgccattaatttttcgatatcttataaaagatggtcgaaattcattcattta
+ttttttttcggttctcgaaagtcaactaagctgtcgcgttttgtttctctttagaggtaa
+aagtggctttgatctcctacgtttggatactagtcaaccattactccatttgatccgtga
+gtatcacctgtctaacatccagcattatgactcctcggcgaagaaaagacacacttctta
+gagtcgatgtgtattagctagggacacagttgtttaatacgatagtgagcccagggaggg
+cagtgcgtcccccagtagatttattcagctagtgtaagtataagatatctcacccacgag
+gttcaagtgatatgcagtcttagaataatacttatcctgaatttcgatattatgggtact
+tcaataatccgctagcgctactttatgtctcgttggacagcaggacacatggcagtctta
+aacactaaagacatcacctgaatgaatgtaatgggattacaagaatcaatgaggtattat
+atacgacgtaggaaactctggatatatacagtaatctagttacgccatcgcacttcattc
+ctctggaaacttagaagacatcagctgtacgtggaggaaccagacccccgtatgtagcca
+aatagaaccaaagttgcttatacaaacacacccaatgacaatggaccgctggagttcgta
+aactcggaacgtagtactgcacaaacccagcatttagcaataggagctacgtatgcaact
+cccacgtggtaataccttcaagctatcaatatataggtgcctagctaatcgcattcgcaa
+gcagtattcaagcttgtaaaccagtataataattacagaggctctatgaaacccaacttt
+ccagctaaaagtcccaattaaatggttatttcgtacttttaaagtcgcccgttctgttat
+tacgcgaattgattctactccaaaattaaacacaaattatcaaccgtttcatttatattt
+gtcaatgcagctgtttaaaataaggctctactaaattataattaagacacttattaccag
+atttctctagttaagtttgaaccagctcgactaccgcgaaagatacattcccttctctat
+ttttcagttcatctatgggtcagagaagcattgaatttattctattcaccctcgtcgttc
+acagcgaatcgtcagtgtgatcagtgtatgagaaatatcctaaaccgtttagtcagacca
+cacgcttagaacaagtggtctaaaaagactgccctggaaggagtaagaagtatacagctg
+atccggtgtatccttcagtcatctgccctatactaattacacgacgcaaggaaaaatagg
+tttattttctaggcaaacccttcataggtgactccgatgtgttacgaatcatgcttgaga
+atgtgctatcgttaccgacggataataacgatctccaatgaaccaaatgtagaatgtcta
+ttgattacccttttactattcgacttagagataggagatagaacctcagtgtactttttt
+agccgaatgggaatctttgggaggtgaatggccataaggtcgtaaatccaaccctcttaa
+agtcttccatattatatcgttgttcgtggaatcgataacagatttgttgacccatagtaa
+atgtatactagtttatgttgtaagtgtagattgttttccgattgccgtccaaactttatg
+tcgtaattgtagaccagtaaagttgaccaaggtaagtgcccagcgatcctgcgagatcga
+tcgccaatttttccagtcactgtaagtgtaggtttagataaagccgtatgagttatatca
+taagggcctcggaaagcagcttcgaaccaaagttcccttataatagtagtttaactataa
+aagtatatactggtctgtcgccctttcacgatttgttttaccggtttatgaagcgttacg
+tcattagagcggctccaatttaaggttaacggcttccatgtgtagttgtatacaaggata
+acttaaagtatctgttcagcgagctagttaagttatcctcgatagaacacaactcagagg
+tcccaagatcgggtttgcaacttgctaatttattctcaaggcaaattgggaattatcgat
+acctgtataccataaggtcgctcgatgtgatgcttatgtcttctggtgatcctaccttag
+ttagtgctgattaacggaacattaatgtttatcgttttgagatttagccaattctctgat
+tctaactcaagatgccttatctgacgtgctatgcagcccctaagtattttacattgtaat
+aggacacgctcctttaaaactcgccaaaaggtcgttgtggttctctactggttaactata
+taatttacagctttgttgagctagttcctctttggtttaagtcctcaatattagttggtt
+cgagcgataagttggctagttaccttagtcactatattagatccgaatgttatgcttcat
+ctgaagaccgccaccctccaaaatttcttttaagactcacttattgcaaggtgtaggtga
+attcggctcgtttctcaagtggtgtatctgtacacgagtttccatattttcatcaacagc
+caccgcacacttatgtcactctaggtattaaaagtcgctctacaaggggacgcaattaag
+aaacagacatgctagtcaaaaataaacatagcgaggcaccactaattcggccgcttatca
+atgggatgctctgcgcgagacgcgccagagctcagtagttagttcggacatacatttact
+tcagatgatcaattagttttctacaaatgcttactctaccccgaaaaaagtcaccagact
+cttacgtctctttagtatccttccgtcttatataaggtcagtcccccgtttcggtaccct
+ggaatttactaagaataatgaaacagcccccaaggacgtacgtttacaaatgatagacca
+gatcgcctagcttattccgacgcatgttgcatagaattgaaccaacggaatgtgagagta
+actagatgagccgaccacagcacccgtttgcgtcgcagaatacgcctgatagttcggcca
+cgaaatcatatgtcctttgagtattaagtatttgtaatgatcaatcgagctcaagcaagc
+ttacacttcctcggatattcagggaacttagtgcctttgaaagatacgttgatcaacgaa
+aaattgataatggctcatatggaatgcctacctcatagtgctgaattaacacagcactgc
+ggacctaacttttcgaggtttcaagttcacgtctcaaaacctaataggctggaatatgta
+gggatcctcggtgaatttgtgattgggtttgttgtagtactgaccaagtgaatattcttt
+ttttctaaaagcagatctgctgccgggcactacgaaggagatctctgtgtatcattattg
+cttcttgacatgatgactcttaaatcactgtgggtgtgcaaaacgatagcacaacccaat
+tcgatagtacatattgttgatacttcgcactaaaccgttcatatttaaaggttgtgctcc
+ttccttcgttaaatactggtgacttggtcctatctactattagctagacctctggggaac
+cacgcccccgtaaaacctgtgcaagagagggggtcatacatcttagacatcgcgcctcca
+ccagggaagcattgggtgattgaccaggtgtgtaacaaatatgattattcttatactaat
+attagcaaagatgcataatgatttgtattaaatgtataattgaattgataagggtctttt
+agtcagtgatagagtagtataaggtagacattagaactcttaaccggacgcagatttttc
+ggtcttagtaagccaattagtcgacaaaacaaggtaagagcggttactagtagtacctat
+aatgcactgaatcttcggtcgaagtatagttctaatgctatgcagattgtgacggcgaca
+aatgttcagacttatatcatgaaacaagctcttgtaagtattgacaaatgaaaagattga
+atatttttaaatacaaaatgcgcctacttattaggggaattaaccagattgaaggccaat
+cctcacatgtaatgagataatagacgataaatgaaattcttgtaatagttgaactgctac
+gtgatgggtattatatatgattgagatcctccaattgccgacgtcttgtcttgatgccca
+aaagattgtcaacgaggagctccctcgcgtacctgtcgtccgtatcataaacgacgcgac
+atgtacagcactccgaagtataagcaataataatgcgggtaatccagactagatcttttc
+ggactcaatgcggtttcacggtaaacatgattaataccggagagtagtcgagcttatcag
+cgatgcaagcgaattcattgtgccaggagatacgttgcagataaaaccggcaacgtatgt
+caacaagttttggcgatctcgttgtttgtattcgacgaggcgcgggaacttcaagaacta
+tcgtatattcaagtccattaccttttagtttcagactggtggagctgactaaagttatat
+catcattttgtacactggtttagttaacgataatttcagatttaacatgaccagacgata
+atcgctgtatatccagttggaatgtggtttgccagaaaggttaacttataatcaagcctc
+tcttcagtcttgattcgtcgtatcccatccattgcgctatacctcagtgtatttggagct
+gtagttataccgtgtgctaagatcagtagacatgacgagagcaatattatctaccttaca
+agcatcaacggacgtctagtcggaacaaaagactctaaaactcgaacttcaggttaatat
+actatagttctgtattcagcagttattcttatattcgatattatcttgcctattggatgt
+ctgactttagtatattaatcatagtatctgccatgtaaaggtgccagtactaaatctgtt
+tcacagtgcgaattataaacggttacaaccattaaagacaacaagaccctatagctttat
+ttgaattttgtcaatgcgcaacttggagctcgcgatacatcccaattagtctatagggtc
+gggacgattctacggcatttctggttataatgacaacatggattgtggcccgagaatcgc
+tctttcattaattaagcaatcattacagtcttataagcgctacttccgagtggtagcagg
+taactcgatataaggtcgcatgagccgaatagcttaaaaaacaggccaccgaacattgat
+agagaataccgaccacagcgcaacctttgattactttcattaaattgtacggctcactcg
+acatcaagcttaagattgcgataatgtgaactcaaatggatcagtactgaagaaccgtaa
+cccacttcgcagaaagcgtacccagagaagatacgctgttacaatatacagggtgaaatt
+attgcctgttcttcgtaaccatttcgccaaacttggttagaaatgatagccattcatgat
+agaaataagctgaatgataccagtatctttaactatgtagtcagggggaagataacgatg
+gtccatgtatgtttctgatatgtgacagtattggccgcgtaatttgctaacgaagctact
+taatgcctttgagcttcatatagatttctttaatcaaaatcggcaaaaagatagtatgag
+ctataatatatgctagtagagaactctggaccatcatctatatgaatactgattcgagcg
+tgcaattactttagcctgcgtactactgactctacaaaacactctgagataagtttgtag
+tcagtaagtcgctctctataaaccttttggatgaccattgtacagccacttatagatccc
+aataaatagcacaggagacagagtttttcaatgctcgatcatttgccgatagtattttcg
+tctaacctcagggcacctattatttgatacctaacctaacggccctttcacaatggagaa
+atatatgacatcgggacaaacacaaatggtgggtggccaggagatatgacatggtggcgt
+ctctaagaaacacggactccctctaggcaaactcacgtaaccaattttaatgtcaaacaa
+aacgctcgaaaagattttgccgtgtaatgacctggtacattgactggtcaggaatacatc
+actgtagttgccgtagtgtcctgttggtgttccatcaagacacatcgtataacgcaattt
+acgacggacatcagatcaagttatacagattatttaagtatcacgtgtgcattgggacat
+aagggatctcacacatgccttggaacatttttgctttgtgccgctttttcgctgcactac
+caatccttacttaccagtatattcaaaggtcgttaacagaatgagaaaggttagggctct
+aagttatcgtcgattgggatagacgagacatttgcgagcgccctccacggatacgaatct
+cccatatcaatgtgaactggatgctatgcagtttagttcttacgtctcctagtggtaaaa
+atcaaagtagcactcgcatagcagttattcagaacctaatacacaaaaccgtcaaacatt
+ttctaattctaggtatgggccgatcataggagctaaggtgaaactcataaatgttttgtt
+agatctagcatcctaaaaagatgcatatactgagtagctggcgtgcattctctcaattgt
+atcctttttaactgaactagtcggtcccatttcgtgactgagatctattaaccgataaga
+ttaataacactcgcattcgtatcagctcagagtgaagtttttcaataatttgactgatat
+attaacttctaaaataaccctttaagcctcggatccgtttcccaatcacatcaaaaattc
+ttattccaactatctacggattaacaacgtgcatggggatcgtagtaagaacttgttccg
+atcactttgagtatatcaagttgacggcccggttattattgaatagaaacattcacctgc
+taaattaaataccgcacatcggatacccgatttcagagggccgtcttactaagggcaggc
+tttgttcggtttaactgagatgttcattattttacagtatgcttcaactaatatgtaacg
+aaggacagtggatctgtctccatagtagatcttcagtcgtgaatttcataccgctcctat
+ttaagttcgcgttcgagttgttgatcatggcacgtgaaagcaacccctagtattctagac
+gaaaattttttctagttcatctgataatttgccaattcaaaaacaaccgctggtttcccg
+gcgcattctctaaaatggaagtcgaacctagagccattatttgtcggtaacccatgagtt
+ccttcttttcagaagttaatacactgtggtcctatacagaggaaaaacagcggttatata
+cgatcgtggcataacaacattggatcaagatagcaatttggctacctattctaattctca
+ctagattcggtattccactacaatatcggcagattaggattggatgaataatcggtgttt
+aagtccggttgcgtctccaatctcctaatttttattaatattgatcttggtgacctattg
+taaataaaaacttcaagactttgaataacggtgaaaagatagaagactcatttgaaaatg
+gatcatccacagatccaaacattagcaagacactaatccccaactagctattctgatcgc
+gatcgtgctgcagtactcctgtcacaatagtctgttcatgatctaattctttttgggctt
+tgttcgatggtgattcagaatctttatccggtcgcttccctgtagctactttgtggggat
+attgcccggggattatagggttgagatcgtttcctaaaagtatttaaaccaagtagactt
+caactaaactacatcagaacatcgtgaagacaccatacgcggtacctttatttaccgata
+acatttcttcaagaaataccggtaagcagcataatgaccctaaacagctcggggtatcgt
+cgtagttttaaattttatttaggttactgctcaaggaataaaaactaactatttaattta
+taataatattacaaggctcacactgattagatttgtctataagacttcgcgatcccccat
+taccggattgtcttaagaataaactagataaaccatgcattttctagataaggcctttag
+tctaattagatacaaaaaacacgatagttgcatccttaatttattgtgtcaaacctggaa
+ccttttaattacccgcaaatcactttatgtcgagactacctctgaaatttattatctacc
+taccgcatgaggacttgaaccatcttgtaggagttatgtttattagctaagattcgttta
+tcctgtagcggtccatgtatattcaacaagcaaaaagcactcagaattgtttttagttga
+gtcaagactgatatataaataagtttccctagttttttcgtggtgggacgatattgaatt
+gaatcttaaccgaagagtttcccactctgtcgcacaataatacacgccaatatttccagc
+cctgcttatgccttaatcggttactcaatctcccattgaagttcattttgatctgcatag
+aagtttcgggcccagccttttttctgccaccttcctccaagctctgtagacgcactctaa
+gattgatgctcacatgtattaattctacattaacataaatatataagtcatgcatcttcg
+agtaaaatatctggttctccaacatgtcctggcacgtatcgttataatgcccatacatgt
+agtattaaaatgattgggttaactggatattaagatcatcgaaattgtaaagtcaaatta
+acaatactgtctcaagaccgtgtattcctcgtgctcggaagggctattacgcttacttcc
+gttttggtatcttaatatgactttcaaaaattaagttgcagtgagtcctacctgcgtgca
+tcggttagcaagagtataaaagttgtttaaacgaactacttgctttacaataccggtcgt
+atatatcgccgtgaatccagaagattgtcttctttggattatcaaccgagatcctgtgga
+ccgatgttttgggaccttcacagaggactccaggtagagctcgcttttgcattaatctaa
+gaattgtacctctctaaaagatctaaaacagtgaatgtgtatttcatggaaaaacacaga
+gaaacgtaaattactttaggccgaaaggcacatgagttattatacatatacgagatggtg
+gtatacatcgaattcggggcatacactatagttgcattgtatttagctgctttaaataat
+atgatattaccttccttacataagacattaccggcataccctggttttcaacttgtgggg
+ctttttgacgatcgcactctcatttgatccgagtagggcggtgacccctgcttttcaaat
+acaaaaatttcgctatgaaggtaatagattacttttcgctgttatgatagaaacggtaaa
+tttaaaattgaaacttctagaaaagtaaagtaacgagaaatgattttgtgaataatgcgg
+tcatgattgcgcaagtaagaaaaaaaggcaaaaggatgcgcggaatagaaacttatcagt
+cacgggtatcttgatttcattcttcttgtcaattgccgacataggatgaaatcagattcc
+aatgcaatacacagtaacccccacccttgattgtaatgtcgatttgaagttgtacgcgtc
+gacgaagtggatagtatacgggccttttgtacggtgcgatcaactatgaatctcggcgag
+ttagatggtcgtacaatctcacacatagaggtcacttgcctgtaatgacgaattttcggc
+taggtactcgaactttattagaagtaaaaatgtgggcaaaagaaggattccattttacaa
+gacgattacaatgagttacatgtctctcaacgtagtctttccctagtagtctttgaacta
+tttaggtactccagaaaattttagcaaagggtttctgtgtgaatccgccattcatgttta
+tgatggaacaataagaataacgccctcgtatgttatcgacagtgaagtcagcagttcggc
+caaaaacatattcaatttagtacagatccccagaagttaagctaagtgctctaaaatggc
+ctaaacggttatcaaagtaggtctaattactatactaacgggtgcatcgtaataactgct
+gtcgatgcaacactatatgatagtgtcgttttgctatatatgtacaatgtgacaaagaag
+ccttagcgattcttgcaaacttaggacttcggattctcaatcttaaatgtccgaaaacgc
+aaagattcaaaaatttaatctatgagcagatatgcctgatggtgactacgcgtatgttaa
+ggctaaatgttgacaaccgcacacataatcgaactattgatagtcgggagcataaccagg
+tgaacgtactttgttcacgacatttattgacatgttctaaatacgtctcaaaatcacggc
+gcactagaaaacgcaatcaaatcattgtcctggtttaagggccgtaatgccggtagtgtc
+aaacttcatgagaactttagctggcttttggccagtatttagggaccaagagcactagcc
+ttaagctgaatattttgccatttatctactgttataactttaaaacttggtggcaccaga
+cttgtcgatacacacgcatcaatctgtaacgtaaaaggtttactaagaacaagcgtagga
+attgagtttatattatatttaaactaaaagatgatattagcttctgagggcgatagggct
+ccaaatcataaagaggaatatattattacacgattagaaacccacaacatacctcgaatc
+gcccaaaagtttgacgaaacttggcagtactccacatctcagtaatacagttgggagagt
+ctcaaatgttgttttattactcaatgaaccaccctcataatttcactgctgttccattaa
+atttgcaaacgatcatttgctttgaagaaacgtaaaatcgacaaaattacagataagtag
+atgcataataaaaaaaactgctcgctataacacgatcatcgtgcattcttacttaggagc
+atcacccgcacaataacgtaccttaaactacaacactattagaccgagtactgtaattca
+cgaaagctcaagctcgcattgtaaagaacttgctctctcgtaaaatgtgataatagtttg
+cggagaggattcaattattttccattgcacctactccactagattcgataaaagaaggtg
+gtcctcccttaaaaagaaatgttaagtaacatcggaaccataagcaaagcatgtaagtga
+accgtcatccttccctaagaaacataaaggtttttaataatgtcgactgtgaactataac
+tgcatcctttcctgacctactccggttccttgttgttatttctgaacgagaccagtagat
+aaacaatgtaaaccacagtgggtaccaatggtgcatgtgacgctaccgttgttttaagtg
+cccgtacaaacataagaagtcataatcttacttgaaattaattttgccttttattttttt
+tcaggctcgaaattaatgatttgttttttttgaccttctagttacgctaatatgcggtcg
+cctgtggtttctattgagtcctataacgggatgggatctaatacgtttggttactagtaa
+acaaggtataaatttgataccggagtatcaactgtataacatcaagctttatgactcata
+cgcgaagtaatgacacaaggctttcaggagatcgcgagtacagagccactaaggggtgta
+ttacgatagtgacaccaccgagcgcactcactccccaagtagatttatgatcctacgcta
+agtattagatatataaccaaagaggttctagtcagtgcaactcttagaataataattagc
+cggttttgcctttttaggcctaatgcaatattcagctagcccttatgtatctcgcgttcc
+acagcaccactcatggcacgcgtttaaactaatcaaatataatctatgaatgttatgcca
+gtacttgaataaatcaggttttttataagtccttgcatactctcgttatatactgttaga
+gtcttaccccatagaaattctttcatctgcaaacttagaagaattctcagctacggggag
+cataaagtccccaggatgttgacaaatacaacaaatgtggcttatacaaacactccatat
+gaaaatcgaaccctcgtggtagttttagccgaaccttgtacggataaatccctccatttt
+ccaatagcagatacctatcctactacctcgtggtattaaattaaagcttgaaatatagag
+ctgcatagcttatccaattcccaagcacgagtctaccgtcgtaaccacgatttgatttac
+agacgctagagcaaacccatctttaaacatataagtaaaaattaaagggtgagtgcgtac
+gtgtttactagcaacttcgcttattaagacaattgtttataagccataattaaaaacata
+tgttcaacaggttcattgatatttgtaattgcacaggtttttaataaggatctacgtaag
+tataatgaacaaactttttaccagagttatattctgtactttgaaaatgctcctctaccg
+ccttagagactttcaattagattttttgcagttaatctatgcgtaagtgaaccatgcaag
+ggatgcgattcaaccgcctcgtgctaaccctatcgtctgtctcataactgtaggtctaat
+ataattttcagttttcgaacacataaccctttgaaaatctgctatttaatgtctcacctg
+catgcactatcttctatactgctcagaacggctatacgtcactatgctccaagtgacgat
+ttaaacgaagcaaggaataataggtttattttagtgcaaaacaattaagtgcggactacg
+tgctctttacaataagccttgtgattgggctataggttaagtcccatattaacgatctcc
+aatgtacaaaatcgacaatcgctttgcattacccggttactagtcgaattacagatagct
+gttagatactcactctaattttggacaacaatcccaatcttggggtcgtctatcgcctga
+agctcgtaaatccttccatcttaaacgattacatattatagacttgttcggggtagagat
+atcacagttgtgcaaacattgtaaatcgatactagtttatgttggtagtctagttgcttt
+taccattccccgaaaaacttgatctactatttcgacaacagtaaacttgaactaggtaag
+tgaaaacagagaatgcctcatagtgccactatttgtccactatatgtaagtgtagcttta
+cataatccactatgactgagatcattacggcctaggaaagcagcgtagaaaaaaagggcc
+cggatattacgactgtaactataaaactagttactggtagcgcgccatgtatagatttgt
+tttaccggttgtggttgcgttaacgaatttcagccgcgaaaattgatccgttaaccagtc
+catctcgacttctataaaacgataaagtaaagttgatgttcagcctccttcttatggttg
+catcgagagtacactactcagtgggaaatagatcggggttcctacttcagattgtattat
+ctaggcaattgccgattgtgccatacctggataaaataagctacctacatgtgatgctta
+tctattatcgtcatactaccttagggtgtcctgttgaacgctacattaatctttagccgt
+ttgagatgttccaatggataggagtctaacgcatgatgaagtttaggaaggcagagcatc
+ccactaagtatgtgacagtgtatttcgaaacgagacgttataaatagaaaaaaggtcctt
+ctggttctattctgctgaactattgaatggaaagattggttgacctacgtactatttgct
+tgaagtcatcaatttgacggggtgagagacatatggtgcatactttacggactctatatt
+ttagatcagaagcttagcagtcttctctacaccccctcacgacataattgcttttaagaa
+tctatgtttgattcctctacgggaattcggatccgttcgcatgtgcggtttatctaaacc
+aggggacatatgttcagctaaagcatacgaacactttgctaactagacgtatgtatagta
+gctataaatcccgacgatatttacaaaaagaaatgagactcaaatatatacatagcgacc
+ctacacttattcgcaccctgatctaggcgatcctagcacccacacccgaaagtgagcact
+agtgtcttccgtattaaatttactgcagttgagattttagttgtctactaaggattactc
+taacccgtaataaggatcaagactcggtactagctttactatcattccctatgtgttttc
+ctaactcacaagggtacgtaccagcctatgtaattacaataatgataaagacacaaagga
+agtaactttacaaatgagtctccagttacactagcttagtccctcccatcttgctttgaa
+gtctaaatacgcaatctctgaggatatacagcagaagaacactcataacgttggagtcca
+agaattagactcatagggcccccaacatttaatatgtactgtgagtttgaaggtgttcta
+ttgttaattcctgctcttgatacatgacacgtactccgtgtttaaggcttcggactgact
+ttctttcataagttgagcaacgaaaatttcagaatcgataagttggattcactaactaat
+acggctgattgaaaactccactccggacctatatggtcgacctttatacgtaaccgatat
+aaaacttataggctggtatatcgagccttcctagcgcaatttcggatggggtttcttcta
+ctactcaacaacggaatagtctttgtttagtaaaccagagctcaggacgcccaatacgta
+ggagagcgctgtggagcatgtgtcattatggactggagcactcttaaatcactctgcgtg
+tgctaaacgatagatcataacatgtcctgagtaaattttcttgatacgtcgcaatatacc
+gttattagttaaacgttctcatccgtcatgcgtgaaatacggctgtcgtgctcagatata
+ctattagcgactcatctcgcctaacacgcacacgtataaactcggaatgactgccgctct
+tacatattagaaatacagactacaccacggaagcattgggtcattctcaaccgctgtata
+aaagatgattagtcttataataagattaccaaagaggcagaatcatgggtagtaaatcta
+ttattcaagtgattaccgtcgtgtaggcagggagtgaggacgagatggtactcaggacaa
+atattaaccggacgaagtggtttacgtcgtactttcactattagtagtaaatacaaggta
+acaccggggaatagtactaaatataatgatatctatcttcgggagaacgagtcgtctatt
+gctttgaacattctcaaggcgtaaaatgtgctgacttatagcatgatacaaccgattgtt
+acttttgtctattcaaaagattgaatagttttttatacaaaagccgcatacttatgacgg
+ctagtatacagtttcatcccctagcatcaatgctatggacagtattgaacttataggaaa
+ttcttctaatagggcaaatccgtcgtgatgcctattttttttcagtcacatcctcaaatg
+gcactagtattgtcgggatcccattaacaggctcaaccacgagctcacgcgaggacatgt
+agtccgtatctttaacgaagcgacagcgacagaactcccatggataaccaattataaggc
+ccgtaatcctctagacatcgtttaccaataaatccgctttctccgtaatcatgttgaata
+ccccagagtagtccagatgataaccgatgaaacacaagtctttctcaatgcacttacggt
+gaacttattaccgccaacgtagctcatcaaggttgcgacatctagttgtgtgtttgcgac
+gagcccagcgaacttcatcaactttcgtatattcaacgccttgtaattttactttaagac
+gcctggtgatgtagattcttagataatcagtttgttatcggctgtactttaccataattt
+cacaggtttcaggtcaagaagattatagctgtatatacagttccatgctcggtgcacaga
+aacgtgatcggataataatcaatcgcttatgtcgtctttaggcgtatccaatacatgccc
+cgataccgcagtgtatttcgacatgtaggtataccgtcgcatttgagctcgagtcaggac
+gtcagctagattagattccttaatagaatataccgacctctagtccgaactaaactatag
+ataacgccaacttcaggttaattgtctagtcgtctgtttgcagatgggattcttagatga
+gtgagtatcggccatattggttcgagcactttagtttttgatgcataggatatgcaatgt
+atagctgaaagtactttatctgtttcaaactcacattgattaaaccggtaaacctttaaa
+gactacaagaaaatattcagtgagggcaattttgtcaatcacaatcttccagctagagat
+acttcacaatttgtcttgaggctacgcaacattagacggattttcgcgttttattgaaat
+aatcgaggggcccaagagtatccatagttcattttgtaagatttctttacaggcttatta
+cagcttcttcagactcctacatgcttacgagttatatgctagcatgtgaacaatagatta
+atatacaggaaaacgtacattgagagagatgaccctacacagcgcaaccgttgagtactt
+tcattaaagggtaacgctctcgagacagcatccttaagatggccttattgtcaaatcatt
+tgcagaagtacgcaagatccctaaccaacgtagaagaatccctacaaacacatgagacgc
+ggtgaaaatagacagggtgttagtattcaatcttcggagtatcaatttcgccaatcttgg
+tgagaaagcataccctttcttcagagaaagaagatcaatcataacactatctttaacgag
+gtacgcacgcgcatcattacctgcctccatggatctttaggatagcggaaagtattggca
+gcgtattgtgatttcgttcctactttatcaatttcacattcatatacatgtcttttatca
+aaatcgccaataagataggatgagctatattagatgctagtagagttcgcgccaacatca
+tcgataggaatactcaggacagcgtgataggacttttcaatccctaatactctctataat
+tataactctctcttaagtttggaggcagtaacgcgctctatataatcagtttgctgcacc
+attcttcagcctctgatacatacaaataaattccacagcagtaagagggtttaattgaga
+catcttgggaacttaggattttactctaacatcaccgaaacgattattggataccgtacc
+taaacgaactttctcaaggcagtaatataggacatccgcaataacacaaatgctgcctcc
+ccaggagttatgtcttcctggaggctatatcttacacccactcactataggcaaactaaa
+gtttaaatgttgattgtctaaaaaaaagatagataagagttggccggcgtagcacatgcg
+aaagtgaatcgtaagctataattctctggacttgaagttctgtcctgttcctctgcaaga
+aacaaacttcctttaaagctatttacgacgcacatctcagcaagttataaacatgttgga
+agtttctagtcggaattcccaaagaacggatctatctaatgcattcctacatttttcctg
+tctgccgatggtgccatcctattcaaagaatttcttaaaagtagattaaatgggactttt
+aacaatgagtaaccttacgcctctaagggttcctcgagtgccatacaccagtcaggtccg
+agccacatacacggagaacattctaacatagcattctcaactcgatcatttgcaggttac
+ttctttcctatcctagtgctaaaaatcatacttgcaatcccatagcacggattaagaacc
+taagaaacaattcagtaaaacatgttcgaattcttggtatgggaacatcattgcagctat
+ggtctaacgcattaatgtttgggtacatcttccatcatataaacaggaagagtctgacga
+cagggagtgcttgcgatcatgtctatcattgtgaaatcaaattgtagctcacatgtcgtc
+tatgagagcgtgtatccgataagatttagaaaaatagaagtcgtataagatctcactgaa
+cttttgaatgaatgtgaagcatatatgatctgctttaataaaactttatccataggatac
+gtttccaaatcaattcaataattattagtcaaaatagataaggatgaacaacctgaaggc
+cgatcggacgtagaaagtggtcccatcactttgagttgatattgttgaaccacacgttat
+tatggttttcaaacagtctcaggatattgtatatacagataatccgataccagttgtctg
+acgcccctcttacgtaccccaccctttgtgacgtttaaagcagttgttcagtattttaaa
+ctaggcggcaactaatttggaaagaagcacagtggatatgtctaaattcttgttattcag
+gcctgaatttaatacaccgcatagttaacttcgcggtagagttgttcatcatgcctcctc
+taagctaccacttctatgatacaccaatagttgttctacggaatctgataattggccaag
+tcataaacttccgctgcgttcaacccccttgctcgaatatccaactcgaaaagacagcct
+tttggtgtccggaacaaatcagttacttcttttctgatgttaattctctgtggtcagata
+cagaccaaaaactccgcggatttaccatcctccaagaacaaatttgcatcaacatagcat
+tttggctacatattctaagtctcaatagtttaggttttcaactacattatcccaacatta
+ggattggaggaataatagctgggtaagtccccttgcgtctacaatcgactattttttatg
+aatatgcttctgccgcacctatggttattaaaaaagtcatgactttgaagaaccctgaaa
+agatagatgaatcaggtgtaatggcagcagccaaagagcatataattagcaacactctaa
+gaacattatagatatgatgatagcgatcgtcatgatgttatccggtcacaatagtagctt
+catcagctaattcgttttgccagtggtgacttgcgctggaagaatcgttatacggtccct
+tccctcttgatacggtgggggcttattcaaccgcgtggattgggttgtcatacttgcatt
+aaacgatgtaaaccatctagtagtcaactatactaaatcacaaaatagtgatcaatacat
+acccgcttcatggttttaaccatttaattgattaaagatattccgctaagaaccattatc
+tacctaaactgatcgccgtatcctagtagtttgaaatttgatgtaccgtaatgatcaacg
+aagtaaaacgttatattgtatgtagaataataggtcttggagctaaatgatgtgattggt
+agtgaagacttacccttacaactttaccggtttctcggaagaatatactagagaatcaat
+gcatgggctacataagcactttagtctaatgagataaaaaatacacgagtcttccatcat
+gaattttttgtcgaaaaactcgaacctggtaatttaaaccatatatctttatgtcgtcaa
+taactctcatatgttttatataacttcccaatcacgacttgtaactgcttgttcgactga
+gctgtttgagctatgaggccgggatccggttgagctacatctatttgctacaagaaaaat
+gaaagcacatttgttgggagttctggctacactcatagagaaataagtggcccgagtggg
+tgcggcctgcctccatattcaagtgtatcttaaaccaagtggttccaacgctcgcgctaa
+agaattaaagcctttatttcctccacggagtagcccgtaatccggttcgaaagagaccat
+tgaagttaattttcatatccagtgaagtttaggcacaagcatgtgttctgccacatgcct
+caaagcgctcttcaaccaagatatgattcatcctaacttcgatgaatgcgtctgtaacat
+aaatatagaaggaatgattcggcgagttaattttcgccttctccaacatggcatccctac
+gttcgttataaggaccatacatgtaggttttaaaggtttgcggttaatcgatatttacat
+catagaaattctatagtcaaatttacaagactctagatactcactcgttgcagccggcta
+ggaagcgctttgtaccttacttcccttttcgttgcgtaatatgaatttcatatagtaagt
+tcaaggcactcatacctccgtgaagagggtagatagactattaaagttgtttaatagtac
+gtattgatggaaatgacccgtaggagatttaccactcaatccacaagattcgctgctgtg
+cattatcaaaacagtgcatgtcgaaacatgggttgggtccttcaaacacgaatccaggta
+gagatacctttgcaattttt
diff --git a/extra/benchmark/regex-dna/regex-dna-test-out.txt b/extra/benchmark/regex-dna/regex-dna-test-out.txt
new file mode 100644 (file)
index 0000000..d36baa5
--- /dev/null
@@ -0,0 +1,13 @@
+agggtaaa|tttaccct 0
+[cgt]gggtaaa|tttaccc[acg] 3
+a[act]ggtaaa|tttacc[agt]t 9
+ag[act]gtaaa|tttac[agt]ct 8
+agg[act]taaa|ttta[agt]cct 10
+aggg[acg]aaa|ttt[cgt]ccct 3
+agggt[cgt]aa|tt[acg]accct 4
+agggta[cgt]a|t[acg]taccct 3
+agggtaa[cgt]|[acg]ttaccct 5
+
+101745
+100000
+133640
diff --git a/extra/benchmark/regex-dna/regex-dna-tests.factor b/extra/benchmark/regex-dna/regex-dna-tests.factor
new file mode 100644 (file)
index 0000000..f1d4b7f
--- /dev/null
@@ -0,0 +1,10 @@
+USING: benchmark.regex-dna io io.files io.encodings.ascii
+io.streams.string kernel tools.test ;
+IN: benchmark.regex-dna.tests
+
+[ t ] [
+    "resource:extra/benchmark/regex-dna/regex-dna-test-in.txt"
+    [ regex-dna ] with-string-writer
+    "resource:extra/benchmark/regex-dna/regex-dna-test-out.txt"
+    ascii file-contents =
+] unit-test
diff --git a/extra/benchmark/regex-dna/regex-dna.factor b/extra/benchmark/regex-dna/regex-dna.factor
new file mode 100644 (file)
index 0000000..0c21de0
--- /dev/null
@@ -0,0 +1,60 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors regexp prettyprint io io.encodings.ascii
+io.files kernel sequences assocs namespaces ;
+IN: benchmark.regex-dna
+
+! Based on http://shootout.alioth.debian.org/gp4/benchmark.php?test=regexdna&lang=ruby&id=1
+
+: strip-line-breaks ( string -- string' )
+    R/ >.*\n|\n/ "" re-replace ;
+
+: count-patterns ( string -- )
+    {
+        R/ agggtaaa|tttaccct/i,
+        R/ [cgt]gggtaaa|tttaccc[acg]/i,
+        R/ a[act]ggtaaa|tttacc[agt]t/i,
+        R/ ag[act]gtaaa|tttac[agt]ct/i,
+        R/ agg[act]taaa|ttta[agt]cct/i,
+        R/ aggg[acg]aaa|ttt[cgt]ccct/i,
+        R/ agggt[cgt]aa|tt[acg]accct/i,
+        R/ agggta[cgt]a|t[acg]taccct/i,
+        R/ agggtaa[cgt]|[acg]ttaccct/i
+    } [
+        [ raw>> write bl ]
+        [ count-matches . ]
+        bi
+    ] with each ;
+
+: do-replacements ( string -- string' )
+    {
+        { R/ B/ "(c|g|t)" }
+        { R/ D/ "(a|g|t)" }
+        { R/ H/ "(a|c|t)" }
+        { R/ K/ "(g|t)" }
+        { R/ M/ "(a|c)" }
+        { R/ N/ "(a|c|g|t)" }
+        { R/ R/ "(a|g)" }
+        { R/ S/ "(c|t)" }
+        { R/ V/ "(a|c|g)" }
+        { R/ W/ "(a|t)" }
+        { R/ Y/ "(c|t)" }
+    } [ re-replace ] assoc-each ;
+
+SYMBOL: ilen
+SYMBOL: clen
+
+: regex-dna ( file -- )
+    ascii file-contents dup length ilen set
+    strip-line-breaks dup length clen set
+    dup count-patterns
+    do-replacements
+    nl
+    ilen get .
+    clen get .
+    length . ;
+
+: regex-dna-main ( -- )
+    "resource:extra/benchmark/regex-dna/regex-dna-test-in.txt" regex-dna ;
+
+MAIN: regex-dna-main
index 403cb4737e63b722b56beedf3d5625133fbda14e..c683ef6e0624eb7596a5e9d852be2aeebe7ac95a 100755 (executable)
@@ -1,15 +1,15 @@
 USING: tools.deploy.config ;
 H{
-    { deploy-word-props? f }
-    { deploy-random? f }
-    { deploy-compiler? f }
     { deploy-c-types? f }
-    { deploy-ui? f }
-    { deploy-reflection 1 }
+    { deploy-name "Hello world (console)" }
     { deploy-threads? f }
+    { deploy-word-props? f }
+    { deploy-reflection 2 }
+    { deploy-random? f }
     { deploy-io 2 }
-    { deploy-word-defs? f }
-    { "stop-after-last-window?" t }
-    { deploy-name "Hello world (console)" }
     { deploy-math? f }
+    { deploy-ui? f }
+    { deploy-compiler? f }
+    { "stop-after-last-window?" t }
+    { deploy-word-defs? f }
 }
index b82b5662dc0a28adb3227338883d20983af48630..5c640c6fb917d18d0b89620bf436922b640b40b8 100755 (executable)
@@ -1,7 +1,9 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
 USING: assocs html.parser kernel math sequences strings ascii
 arrays generalizations shuffle unicode.case namespaces make
-splitting http sequences.lib accessors io combinators
-http.client urls ;
+splitting http accessors io combinators http.client urls
+urls.encoding fry sequences.lib ;
 IN: html.parser.analyzer
 
 TUPLE: link attributes clickable ;
@@ -9,56 +11,54 @@ TUPLE: link attributes clickable ;
 : scrape-html ( url -- vector )
     http-get nip parse-html ;
 
-: (find-relative)
-    [ >r + dup r> ?nth* [ 2drop f f ] unless ] [ 2drop f ] if ; inline
+: find-all ( seq quot -- alist )
+   [ <enum> >alist ] [ '[ second @ ] ] bi* filter ; inline
 
-: find-relative ( seq quot n -- i elt )
-    >r over [ find drop ] dip r> swap pick
-    (find-relative) ; inline
+: find-nth ( seq quot n -- i elt )
+    [ <enum> >alist ] 2dip -rot
+    '[ _ [ second @ ] find-from rot drop swap 1+ ]
+    [ f 0 ] 2dip times drop first2 ; inline
 
-: (find-all) ( n seq quot -- )
-    2dup >r >r find-from [
-        dupd 2array , 1+ r> r> (find-all)
-    ] [
-        r> r> 3drop
-    ] if* ; inline
+: find-first-name ( str vector -- i/f tag/f )
+    [ >lower ] dip [ name>> = ] with find ; inline
 
-: find-all ( seq quot -- alist )
-    [ 0 -rot (find-all) ] { } make ; inline
-
-: (find-nth) ( offset seq quot n count -- obj )
-    >r >r [ find-from ] 2keep 4 npick [
-        r> r> 1+ 2dup <= [
-            4drop
-        ] [
-            >r >r >r >r drop 1+ r> r> r> r>
-            (find-nth)
-        ] if
+: find-matching-close ( str vector -- i/f tag/f )
+    [ >lower ] dip
+    [ [ name>> = ] [ closing?>> ] bi and ] with find ; inline
+
+: find-between* ( i/f tag/f vector -- vector )
+    pick integer? [
+        rot tail-slice
+        >r name>> r>
+        [ find-matching-close drop dup [ 1+ ] when ] keep
+        swap [ head ] [ first ] if*
     ] [
-        2drop r> r> 2drop
+        3drop V{ } clone
     ] if ; inline
+    
+: find-between ( i/f tag/f vector -- vector )
+    find-between* dup length 3 >= [
+        [ rest-slice but-last-slice ] keep like
+    ] when ; inline
 
-: find-nth ( seq quot n -- i elt )
-    0 -roll 0 (find-nth) ; inline
+: find-between-first ( string vector -- vector' )
+    [ find-first-name ] keep find-between ; inline
+
+: find-between-all ( vector quot -- seq )
+    [ [ [ closing?>> not ] bi and ] curry find-all ] curry
+    [ [ >r first2 r> find-between* ] curry map ] bi ; inline
 
-: find-nth-relative ( seq quot n offest -- i elt )
-    >r [ find-nth ] 3keep 2drop nip r> swap pick
-    (find-relative) ; inline
 
 : remove-blank-text ( vector -- vector' )
     [
-        dup name>> text = [
-            text>> [ blank? ] all? not
-        ] [
-            drop t
-        ] if
+        dup name>> text =
+        [ text>> [ blank? ] all? not ] [ drop t ] if
     ] filter ;
 
 : trim-text ( vector -- vector' )
     [
-        dup name>> text = [
-            [ [ blank? ] trim ] change-text
-        ] when
+        dup name>> text =
+        [ [ [ blank? ] trim ] change-text ] when
     ] map ;
 
 : find-by-id ( id vector -- vector )
@@ -68,53 +68,22 @@ TUPLE: link attributes clickable ;
     [ attributes>> "class" swap at = ] with filter ;
 
 : find-by-name ( str vector -- vector )
-    >r >lower r>
-    [ name>> = ] with filter ;
-
-: find-first-name ( str vector -- i/f tag/f )
-    >r >lower r>
-    [ name>> = ] with find ;
-
-: find-matching-close ( str vector -- i/f tag/f )
-    >r >lower r>
-    [ [ name>> = ] keep closing?>> and ] with find ;
+    [ >lower ] dip [ name>> = ] with filter ;
 
 : find-by-attribute-key ( key vector -- vector )
-    >r >lower r>
+    [ >lower ] dip
     [ attributes>> at ] with filter
     sift ;
 
 : find-by-attribute-key-value ( value key vector -- vector )
-    >r >lower r>
+    [ >lower ] dip
     [ attributes>> at over = ] with filter nip
     sift ;
 
 : find-first-attribute-key-value ( value key vector -- i/f tag/f )
-    >r >lower r>
+    [ >lower ] dip
     [ attributes>> at over = ] with find rot drop ;
 
-: find-between* ( i/f tag/f vector -- vector )
-    pick integer? [
-        rot tail-slice
-        >r name>> r>
-        [ find-matching-close drop dup [ 1+ ] when ] keep
-        swap [ head ] [ first ] if*
-    ] [
-        3drop V{ } clone
-    ] if ;
-    
-: find-between ( i/f tag/f vector -- vector )
-    find-between* dup length 3 >= [
-        [ rest-slice but-last-slice ] keep like
-    ] when ;
-
-: find-between-first ( string vector -- vector' )
-    [ find-first-name ] keep find-between ;
-
-: find-between-all ( vector quot -- seq )
-    [ [ [ closing?>> not ] bi and ] curry find-all ] curry
-    [ [ >r first2 r> find-between* ] curry map ] bi ;
-
 : tag-link ( tag -- link/f )
     attributes>> [ "href" swap at ] [ f ] if* ;
 
@@ -135,7 +104,7 @@ TUPLE: link attributes clickable ;
     [ dup name>> text = ] prepose find drop ;
 
 : find-opening-tags-by-name ( name seq -- seq )
-    [ [ name>> = ] keep closing?>> not and ] with find-all ;
+    [ [ name>> = ] [ closing?>> not ] bi and ] with find-all ;
 
 : href-contains? ( str tag -- ? )
     attributes>> "href" swap at* [ subseq? ] [ 2drop f ] if ;
@@ -154,7 +123,7 @@ TUPLE: link attributes clickable ;
 
 : find-html-objects ( string vector -- vector' )
     [ find-opening-tags-by-name ] keep
-    [ >r first2 r> find-between* ] curry map ;
+    [ [ first2 ] dip find-between* ] curry map ;
 
 : form-action ( vector -- string )
     [ name>> "form" = ] find nip 
index 95bfa938a25b717fe1d595782a5007fd63f4c76a..e084ea6806f3f8f4c48ccb0fd9f2df20239b329e 100644 (file)
@@ -1,7 +1,8 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays html.parser.utils hashtables io kernel
 namespaces make prettyprint quotations sequences splitting
-state-parser strings unicode.categories unicode.case
-sequences.lib ;
+state-parser strings unicode.categories unicode.case ;
 IN: html.parser
 
 TUPLE: tag name attributes text closing? ;
index 04b3687f7dd30bcf8d0b2f3cd082b7e3a880bcdc..976a5ba91f6ca8fdf9e108b7bf614f5d2af4639d 100644 (file)
@@ -1,7 +1,8 @@
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
 USING: assocs circular combinators continuations hashtables
-hashtables.private io kernel math
-namespaces prettyprint quotations sequences splitting
-state-parser strings sequences.lib ;
+hashtables.private io kernel math namespaces prettyprint
+quotations sequences splitting state-parser strings ;
 IN: html.parser.utils
 
 : string-parse-end? ( -- ? ) get-next not ;
index 932bdda472e0cb55a327ec6f49bdc0dd274509bb..c768c1a82ef47beb6c351757ba85260c7717fe31 100644 (file)
@@ -20,7 +20,7 @@ M: mb-writer stream-nl ( mb-writer -- )
     [ [ last-line>> concat ] [ lines>> ] bi push ] keep
     V{ } clone >>last-line drop ;
 
-: spawn-client ( lines listeners -- irc-client )
+: spawn-client ( -- irc-client )
     "someserver" irc-port "factorbot" f <irc-profile>
     <irc-client>
         t >>is-running
old mode 100644 (file)
new mode 100755 (executable)
index 2474fd6..569f6c4
@@ -68,12 +68,17 @@ SINGLETON: irc-end          ! sent when the client isn't running anymore
 SINGLETON: irc-disconnected ! sent when connection is lost
 SINGLETON: irc-connected    ! sent when connection is established
 
+<PRIVATE
+: end-loops ( irc-client -- )
+     [ listeners>> values [ out-messages>> ] map ]
+     [ in-messages>> ]
+     [ out-messages>> ] tri 2array prepend
+     [ irc-end swap mailbox-put ] each ;
+PRIVATE>
+
 : terminate-irc ( irc-client -- )
     [ is-running>> ] keep and [
-        [ [ irc-end ] dip in-messages>> mailbox-put ]
-        [ [ f ] dip (>>is-running) ]
-        [ stream>> dispose ]
-        tri
+        [ end-loops ] [ [ f ] dip (>>is-running) ] bi
     ] when* ;
 
 <PRIVATE
@@ -90,9 +95,8 @@ SYMBOL: current-irc-client
 : irc-print ( s -- ) irc-stream> [ stream-print ] keep stream-flush ;
 : irc-send ( irc-message -- ) irc> out-messages>> mailbox-put ;
 : listener> ( name -- listener/f ) irc> listeners>> at ;
-
-: maybe-mailbox-get ( mailbox quot: ( irc-message -- ) -- )
-    [ dup mailbox-empty? [ drop 0.1 sleep ] ] dip '[ mailbox-get @ ] if ; inline
+: channel-mode? ( mode -- ? ) name>> first "#&" member? ;
+: me? ( string -- ? ) irc> profile>> nickname>> = ;
 
 GENERIC: to-listener ( message obj -- )
 
@@ -139,10 +143,14 @@ M: irc-listener to-listener ( message irc-listener -- )
     swap dup listeners-with-participant [ rename-participant ] with with each ;
 
 : add-participant ( mode nick channel -- )
-    listener> [
-        [ participants>> set-at ]
-        [ [ +join+ f <participant-changed> ] dip to-listener ] 2bi
-    ] [ 2drop ] if* ;
+    listener>
+    [ participants>> set-at ]
+    [ [ +join+ f <participant-changed> ] dip to-listener ] 2bi ;
+
+: change-participant-mode ( channel mode nick -- )
+    rot listener>
+    [ participants>> set-at ]
+    [ [ [ +mode+ ] dip <participant-changed> ] dip to-listener ] 3bi ; ! FIXME
 
 DEFER: me?
 
@@ -176,14 +184,11 @@ DEFER: me?
 ! Server message handling
 ! ======================================
 
-: me? ( string -- ? )
-    irc> profile>> nickname>> = ;
-
 GENERIC: forward-name ( irc-message -- name )
 M: join forward-name ( join -- name ) trailing>> ;
 M: part forward-name ( part -- name ) channel>> ;
 M: kick forward-name ( kick -- name ) channel>> ;
-M: mode forward-name ( mode -- name ) channel>> ;
+M: mode forward-name ( mode -- name ) name>> ;
 M: privmsg forward-name ( privmsg -- name )
     dup name>> me? [ irc-message-sender ] [ name>> ] if ;
 
@@ -222,7 +227,8 @@ M: nick-in-use process-message ( nick-in-use -- )
     name>> "_" append /NICK ;
 
 M: join process-message ( join -- )
-    [ drop +normal+ ] [ irc-message-sender ] [ trailing>> ] tri add-participant ;
+    [ drop +normal+ ] [ irc-message-sender ] [ trailing>> ] tri
+    dup listener> [ add-participant ] [ 3drop ] if ;
 
 M: part process-message ( part -- )
     [ irc-message-sender ] [ channel>> ] bi remove-participant ;
@@ -238,6 +244,12 @@ M: quit process-message ( quit -- )
 M: nick process-message ( nick -- )
     [ irc-message-sender ] [ trailing>> ] bi rename-participant-in-all ;
 
+! M: mode process-message ( mode -- )
+!    [ channel-mode? ] keep and [
+!        [ name>> ] [ mode>> ] [ parameter>> ] tri
+!        [ change-participant-mode ] [ 2drop ] if*
+!    ] when* ;
+
 : >nick/mode ( string -- nick mode )
     dup first "+@" member? [ unclip ] [ 0 ] if participant-mode ;
 
@@ -251,15 +263,14 @@ M: names-reply process-message ( names-reply -- )
         [ [ f f f <participant-changed> ] dip name>> to-listener ] bi
     ] [ drop ] if* ;
 
-: handle-incoming-irc ( irc-message -- )
-    [ forward-message ] [ process-message ] bi ;
-
 ! ======================================
 ! Client message handling
 ! ======================================
 
-: handle-outgoing-irc ( irc-message -- )
-    irc-message>client-line irc-print ;
+GENERIC: handle-outgoing-irc ( irc-message -- ? )
+M: irc-end handle-outgoing-irc ( irc-end -- ? ) drop f ;
+M: irc-message handle-outgoing-irc ( irc-message -- ? )
+    irc-message>client-line irc-print t ;
 
 ! ======================================
 ! Reader/Writer
@@ -281,27 +292,28 @@ DEFER: (connect-irc)
 : handle-disconnect ( error -- )
     drop irc> is-running>> [ (handle-disconnect) ] when ;
 
-: (reader-loop) ( -- )
+: (reader-loop) ( -- )
     irc> stream>> [
         |dispose stream-readln [
-            parse-irc-line handle-reader-message
+            parse-irc-line handle-reader-message t
         ] [
-            irc> terminate-irc
+            irc> terminate-irc f
         ] if*
     ] with-destructors ;
 
 : reader-loop ( -- ? )
-    [ (reader-loop) ] [ handle-disconnect ] recover t ;
+    [ (reader-loop) ] [ handle-disconnect t ] recover ;
 
 : writer-loop ( -- ? )
-    irc> out-messages>> [ handle-outgoing-irc ] maybe-mailbox-get t ;
+    irc> out-messages>> mailbox-get handle-outgoing-irc ;
 
 ! ======================================
 ! Processing loops
 ! ======================================
 
 : in-multiplexer-loop ( -- ? )
-    irc> in-messages>> [ handle-incoming-irc ] maybe-mailbox-get t ;
+    irc> in-messages>> mailbox-get
+    [ forward-message ] [ process-message ] [ irc-end? not ] tri ;
 
 : strings>privmsg ( name string -- privmsg )
     privmsg new [ (>>trailing) ] keep [ (>>name) ] keep ;
@@ -312,21 +324,22 @@ DEFER: (connect-irc)
       [ nip ]
     } cond ;
 
+GENERIC: handle-listener-out ( irc-message -- ? )
+M: irc-end handle-listener-out ( irc-end -- ? ) drop f ;
+M: irc-message handle-listener-out ( irc-message -- ? )
+     irc> out-messages>> mailbox-put t ;
+    
 : listener-loop ( name -- ? )
     dup listener> [
-        out-messages>> [ maybe-annotate-with-name
-                         irc> out-messages>> mailbox-put ] with
-        maybe-mailbox-get t
+        out-messages>> mailbox-get
+        maybe-annotate-with-name handle-listener-out
     ] [ drop f ] if* ;
 
-: spawn-irc-loop ( quot: ( -- ? ) name -- )
-    [ '[ irc> is-running>> [ @ ] [ f ] if ] ] dip
-    spawn-server drop ;
-
 : spawn-irc ( -- )
-    [ reader-loop ] "irc-reader-loop" spawn-irc-loop
-    [ writer-loop ] "irc-writer-loop" spawn-irc-loop
-    [ in-multiplexer-loop ] "in-multiplexer-loop" spawn-irc-loop ;
+    [ reader-loop ] "irc-reader-loop" spawn-server
+    [ writer-loop ] "irc-writer-loop" spawn-server
+    [ in-multiplexer-loop ] "in-multiplexer-loop" spawn-server
+    3drop ;
 
 ! ======================================
 ! Listener join request handling
@@ -334,7 +347,7 @@ DEFER: (connect-irc)
 
 : set+run-listener ( name irc-listener -- )
     over irc> listeners>> set-at
-    '[ _ listener-loop ] "listener" spawn-irc-loop ;
+    '[ _ listener-loop ] "irc-listener-loop" spawn-server drop ;
 
 GENERIC: (add-listener) ( irc-listener -- )
 
index 20f4f1b2772189bb669bf3ea3f7c7ce97670e466..b61dd1644848eaf573dc8a6e57767a8fc786934a 100644 (file)
@@ -6,54 +6,60 @@ IN: irc.messages.tests
 
 { "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test
 
-irc-message new
-    ":someuser!n=user@some.where PRIVMSG #factortest :hi" >>line
-    "someuser!n=user@some.where" >>prefix
-                       "PRIVMSG" >>command
-               { "#factortest" } >>parameters
-                            "hi" >>trailing
-1array
+{ T{ irc-message
+     { line ":someuser!n=user@some.where PRIVMSG #factortest :hi" }
+     { prefix "someuser!n=user@some.where" }
+     { command  "PRIVMSG" }
+     { parameters { "#factortest" } }
+     { trailing "hi" } } }
 [ ":someuser!n=user@some.where PRIVMSG #factortest :hi"
   string>irc-message f >>timestamp ] unit-test
 
-privmsg new
-    ":someuser!n=user@some.where PRIVMSG #factortest :hi" >>line
-    "someuser!n=user@some.where" >>prefix
-                       "PRIVMSG" >>command
-               { "#factortest" } >>parameters
-                            "hi" >>trailing
-                   "#factortest" >>name
-1array
+{ T{ privmsg
+     { line ":someuser!n=user@some.where PRIVMSG #factortest :hi" }
+     { prefix  "someuser!n=user@some.where" }
+     { command "PRIVMSG" }
+     { parameters { "#factortest" } }
+     { trailing "hi" }
+     { name "#factortest" } } }
 [ ":someuser!n=user@some.where PRIVMSG #factortest :hi"
   parse-irc-line f >>timestamp ] unit-test
 
-join new
-    ":someuser!n=user@some.where JOIN :#factortest" >>line
-    "someuser!n=user@some.where" >>prefix
-                          "JOIN" >>command
-                             { } >>parameters
-                   "#factortest" >>trailing
-1array
+{ T{ join
+     { line ":someuser!n=user@some.where JOIN :#factortest" }
+     { prefix "someuser!n=user@some.where" }
+     { command "JOIN" }
+     { parameters { } }
+     { trailing "#factortest" } } }
 [ ":someuser!n=user@some.where JOIN :#factortest"
   parse-irc-line f >>timestamp ] unit-test
 
-mode new
-    ":ircserver.net MODE #factortest +ns" >>line
-                          "ircserver.net" >>prefix
-                                   "MODE" >>command
-                  { "#factortest" "+ns" } >>parameters
-                            "#factortest" >>channel
-                                    "+ns" >>mode
-1array
+{ T{ mode
+     { line ":ircserver.net MODE #factortest +ns" }
+     { prefix "ircserver.net" }
+     { command "MODE" }
+     { parameters { "#factortest" "+ns" } }
+     { name "#factortest" }
+     { mode "+ns" } } }
 [ ":ircserver.net MODE #factortest +ns"
   parse-irc-line f >>timestamp ] unit-test
 
-nick new
-    ":someuser!n=user@some.where NICK :someuser2" >>line
-                     "someuser!n=user@some.where" >>prefix
-                                           "NICK" >>command
-                                              { } >>parameters
-                                      "someuser2" >>trailing
-1array
+{ T{ mode
+     { line ":ircserver.net MODE #factortest +o someuser" }
+     { prefix "ircserver.net" }
+     { command "MODE" }
+     { parameters { "#factortest" "+o" "someuser" } }
+     { name "#factortest" }
+     { mode "+o" }
+     { parameter "someuser" } } }
+[ ":ircserver.net MODE #factortest +o someuser"
+  parse-irc-line f >>timestamp ] unit-test
+
+{ T{ nick
+     { line ":someuser!n=user@some.where NICK :someuser2" }
+     { prefix "someuser!n=user@some.where" }
+     { command "NICK" }
+     { parameters  { } }
+     { trailing "someuser2" } } }
 [ ":someuser!n=user@some.where NICK :someuser2"
   parse-irc-line f >>timestamp ] unit-test
\ No newline at end of file
index 16066199edef33ea6eb32ff75740d5f1c37d7437..9201f822dab80be6ca6d3e6138dbacb82a9e7d52 100755 (executable)
@@ -1,9 +1,10 @@
 ! Copyright (C) 2008 Bruno Deferrari
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel fry splitting ascii calendar accessors combinators qualified
-       arrays classes.tuple math.order quotations ;
+       arrays classes.tuple math.order ;
 RENAME: join sequences => sjoin
 EXCLUDE: sequences => join ;
+EXCLUDE: inverse => _ ;
 IN: irc.messages
 
 TUPLE: irc-message line prefix command parameters trailing timestamp ;
@@ -18,8 +19,8 @@ TUPLE: kick < irc-message channel who ;
 TUPLE: roomlist < irc-message channel names ;
 TUPLE: nick-in-use < irc-message asterisk name ;
 TUPLE: notice < irc-message type ;
-TUPLE: mode < irc-message channel mode ;
-TUPLE: names-reply < irc-message who channel ;
+TUPLE: mode < irc-message name mode parameter ;
+TUPLE: names-reply < irc-message who channel ;
 TUPLE: unhandled < irc-message ;
 
 : <irc-client-message> ( command parameters trailing -- irc-message )
@@ -28,41 +29,58 @@ TUPLE: unhandled < irc-message ;
 
 <PRIVATE
 
-GENERIC: irc-command-string ( irc-message -- string )
-
-M: irc-message irc-command-string ( irc-message -- string ) command>> ;
-M: ping        irc-command-string ( ping -- string )    drop "PING" ;
-M: join        irc-command-string ( join -- string )    drop "JOIN" ;
-M: part        irc-command-string ( part -- string )    drop "PART" ;
-M: quit        irc-command-string ( quit -- string )    drop "QUIT" ;
-M: nick        irc-command-string ( nick -- string )    drop "NICK" ;
-M: privmsg     irc-command-string ( privmsg -- string ) drop "PRIVMSG" ;
-M: notice      irc-command-string ( notice -- string )  drop "NOTICE" ;
-M: mode        irc-command-string ( mode -- string )    drop "MODE" ;
-M: kick        irc-command-string ( kick -- string )    drop "KICK" ;
-
-GENERIC: irc-command-parameters ( irc-message -- seq )
-
-M: irc-message irc-command-parameters ( irc-message -- seq ) parameters>> ;
-M: ping        irc-command-parameters ( ping -- seq )    drop { } ;
-M: join        irc-command-parameters ( join -- seq )    drop { } ;
-M: part        irc-command-parameters ( part -- seq )    channel>> 1array ;
-M: quit        irc-command-parameters ( quit -- seq )    drop { } ;
-M: nick        irc-command-parameters ( nick -- seq )    drop { } ;
-M: privmsg     irc-command-parameters ( privmsg -- seq ) name>> 1array ;
-M: notice      irc-command-parameters ( norice -- seq )  type>> 1array ;
-M: kick irc-command-parameters ( kick -- seq )
+GENERIC: command-string>> ( irc-message -- string )
+
+M: irc-message command-string>> ( irc-message -- string ) command>> ;
+M: ping        command-string>> ( ping -- string )    drop "PING" ;
+M: join        command-string>> ( join -- string )    drop "JOIN" ;
+M: part        command-string>> ( part -- string )    drop "PART" ;
+M: quit        command-string>> ( quit -- string )    drop "QUIT" ;
+M: nick        command-string>> ( nick -- string )    drop "NICK" ;
+M: privmsg     command-string>> ( privmsg -- string ) drop "PRIVMSG" ;
+M: notice      command-string>> ( notice -- string )  drop "NOTICE" ;
+M: mode        command-string>> ( mode -- string )    drop "MODE" ;
+M: kick        command-string>> ( kick -- string )    drop "KICK" ;
+
+GENERIC: command-parameters>> ( irc-message -- seq )
+
+M: irc-message command-parameters>> ( irc-message -- seq ) parameters>> ;
+M: ping        command-parameters>> ( ping -- seq )    drop { } ;
+M: join        command-parameters>> ( join -- seq )    drop { } ;
+M: part        command-parameters>> ( part -- seq )    channel>> 1array ;
+M: quit        command-parameters>> ( quit -- seq )    drop { } ;
+M: nick        command-parameters>> ( nick -- seq )    drop { } ;
+M: privmsg     command-parameters>> ( privmsg -- seq ) name>> 1array ;
+M: notice      command-parameters>> ( norice -- seq )  type>> 1array ;
+M: kick command-parameters>> ( kick -- seq )
     [ channel>> ] [ who>> ] bi 2array ;
-M: mode irc-command-parameters ( mode -- seq )
+M: mode command-parameters>> ( mode -- seq )
     [ name>> ] [ channel>> ] [ mode>> ] tri 3array ;
 
+GENERIC: (>>command-parameters) ( params irc-message -- )
+
+M: irc-message (>>command-parameters) ( params irc-message -- ) 2drop ;
+M: logged-in (>>command-parameters) ( params part -- )  [ first ] dip (>>name) ;
+M: privmsg (>>command-parameters) ( params privmsg -- ) [ first ] dip (>>name) ;
+M: notice  (>>command-parameters) ( params notice -- )  [ first ] dip (>>type) ;
+M: part    (>>command-parameters) ( params part -- )
+    [ first ] dip (>>channel) ;
+M: kick    (>>command-parameters) ( params kick -- )
+    [ first2 ] dip [ (>>who) ] [ (>>channel) ] bi ;
+M: names-reply (>>command-parameters) ( params names-reply -- )
+    [ [ first ] dip (>>who) ] [ [ third ] dip (>>channel) ] 2bi ;
+M: mode    (>>command-parameters) ( params mode -- )
+    { { [ >r 2array r> ] [ [ (>>mode) ] [ (>>name) ] bi ] }
+      { [ >r 3array r> ] [ [ (>>parameter) ] [ (>>mode) ] [ (>>name) ] tri ] }
+    } switch ;
+
 PRIVATE>
 
 GENERIC: irc-message>client-line ( irc-message -- string )
 
 M: irc-message irc-message>client-line ( irc-message -- string )
-    [ irc-command-string ]
-    [ irc-command-parameters " " sjoin ]
+    [ command-string>> ]
+    [ command-parameters>> " " sjoin ]
     [ trailing>> [ CHAR: : prefix ] [ "" ] if* ]
     tri 3array " " sjoin ;
 
@@ -77,10 +95,7 @@ M: irc-message irc-message>server-line ( irc-message -- string )
 ! ======================================
 
 : split-at-first ( seq separators -- before after )
-    dupd '[ _ member? ] find
-        [ cut 1 tail ]
-        [ swap ]
-    if ;
+    dupd '[ _ member? ] find [ cut 1 tail ] [ swap ] if ;
 
 : remove-heading-: ( seq -- seq ) dup ":" head? [ 1 tail ] when ;
 
@@ -96,6 +111,15 @@ M: irc-message irc-message>server-line ( irc-message -- string )
 : split-trailing ( string -- string string/f )
     ":" split1 ;
 
+: copy-message-in ( origin dest -- )
+    { [ [ parameters>> ] dip [ (>>command-parameters) ] [ (>>parameters) ] 2bi ]
+      [ [ line>>       ] dip (>>line) ]
+      [ [ prefix>>     ] dip (>>prefix) ]
+      [ [ command>>    ] dip (>>command) ]
+      [ [ trailing>>   ] dip (>>trailing) ]
+      [ [ timestamp>>  ] dip (>>timestamp) ]
+    } 2cleave ;
+
 PRIVATE>
 
 UNION: sender-in-prefix privmsg join part quit kick mode nick ;
@@ -111,20 +135,17 @@ M: sender-in-prefix irc-message-sender ( sender-in-prefix -- sender )
 : parse-irc-line ( string -- message )
     string>irc-message
     dup command>> {
-        { "PING" [ ping ] }
-        { "NOTICE" [ notice ] }
-        { "001" [ logged-in ] }
-        { "433" [ nick-in-use ] }
-        { "353" [ names-reply ] }
-        { "JOIN" [ join ] }
-        { "PART" [ part ] }
-        { "NICK" [ nick ] }
+        { "PING"    [ ping ] }
+        { "NOTICE"  [ notice ] }
+        { "001"     [ logged-in ] }
+        { "433"     [ nick-in-use ] }
+        { "353"     [ names-reply ] }
+        { "JOIN"    [ join ] }
+        { "PART"    [ part ] }
+        { "NICK"    [ nick ] }
         { "PRIVMSG" [ privmsg ] }
-        { "QUIT" [ quit ] }
-        { "MODE" [ mode ] }
-        { "KICK" [ kick ] }
+        { "QUIT"    [ quit ] }
+        { "MODE"    [ mode ] }
+        { "KICK"    [ kick ] }
         [ drop unhandled ]
-    } case
-    [ [ tuple-slots ] [ parameters>> ] bi append ] dip
-    [ all-slots over [ length ] bi@ min head >quotation ] keep
-    '[ @ _ boa ] call ;
+    } case new [ copy-message-in ] keep ;
diff --git a/extra/mason/authors.txt b/extra/mason/authors.txt
new file mode 100644 (file)
index 0000000..db8d844
--- /dev/null
@@ -0,0 +1,2 @@
+Eduardo Cavazos
+Slava Pestov
diff --git a/extra/mason/build/build-tests.factor b/extra/mason/build/build-tests.factor
new file mode 100644 (file)
index 0000000..1e37056
--- /dev/null
@@ -0,0 +1,5 @@
+USING: mason.build tools.test sequences ;
+IN: mason.build.tests
+
+{ create-build-dir enter-build-dir clone-builds-factor record-id }
+[ must-infer ] each
diff --git a/extra/mason/build/build.factor b/extra/mason/build/build.factor
new file mode 100644 (file)
index 0000000..8b8befc
--- /dev/null
@@ -0,0 +1,30 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.files io.launcher io.encodings.utf8 prettyprint arrays
+calendar namespaces mason.common mason.child
+mason.release mason.report mason.email mason.cleanup ;
+IN: mason.build
+
+: create-build-dir ( -- )
+    now datestamp stamp set
+    build-dir make-directory ;
+
+: enter-build-dir  ( -- ) build-dir set-current-directory ;
+
+: clone-builds-factor ( -- )
+    "git" "clone" builds/factor 3array try-process ;
+
+: record-id ( -- )
+    "factor" [ git-id ] with-directory "git-id" to-file ;
+
+: build ( -- )
+    create-build-dir
+    enter-build-dir
+    clone-builds-factor
+    record-id
+    build-child
+    release
+    email-report
+    cleanup ;
+
+MAIN: build
\ No newline at end of file
diff --git a/extra/mason/child/child-tests.factor b/extra/mason/child/child-tests.factor
new file mode 100644 (file)
index 0000000..7913d05
--- /dev/null
@@ -0,0 +1,34 @@
+IN: mason.child.tests
+USING: mason.child mason.config tools.test namespaces ;
+
+[ { "make" "clean" "winnt-x86-32" } ] [
+    [
+        "winnt" target-os set
+        "x86.32" target-cpu set
+        make-cmd
+    ] with-scope
+] unit-test
+
+[ { "make" "clean" "macosx-x86-32" } ] [
+    [
+        "macosx" target-os set
+        "x86.32" target-cpu set
+        make-cmd
+    ] with-scope
+] unit-test
+
+[ { "gmake" "clean" "netbsd-ppc" } ] [
+    [
+        "netbsd" target-os set
+        "ppc" target-cpu set
+        make-cmd
+    ] with-scope
+] unit-test
+
+[ { "./factor" "-i=boot.macosx-ppc.image" "-no-user-init" } ] [
+    [
+        "macosx" target-os set
+        "ppc" target-cpu set
+        boot-cmd
+    ] with-scope
+] unit-test
diff --git a/extra/mason/child/child.factor b/extra/mason/child/child.factor
new file mode 100644 (file)
index 0000000..02085a8
--- /dev/null
@@ -0,0 +1,80 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces make debugger sequences io.files
+io.launcher arrays accessors calendar continuations
+combinators.short-circuit mason.common mason.report mason.platform ;
+IN: mason.child
+
+: make-cmd ( -- args )
+    [ gnu-make , "clean" , platform , ] { } make ;
+
+: make-vm ( -- )
+    "factor" [
+        <process>
+            make-cmd >>command
+            "../compile-log" >>stdout
+            +stdout+ >>stderr
+        try-process
+    ] with-directory ;
+
+: builds-factor-image ( -- img )
+    builds/factor boot-image-name append-path ;
+
+: copy-image ( -- )
+    builds-factor-image "." copy-file-into
+    builds-factor-image "factor" copy-file-into ;
+
+: boot-cmd ( -- cmd )
+    "./factor"
+    "-i=" boot-image-name append
+    "-no-user-init"
+    3array ;
+
+: boot ( -- )
+    "factor" [
+        <process>
+            boot-cmd >>command
+            +closed+ >>stdin
+            "../boot-log" >>stdout
+            +stdout+ >>stderr
+            1 hours >>timeout
+        try-process
+    ] with-directory ;
+
+: test-cmd ( -- cmd ) { "./factor" "-run=mason.test" } ;
+
+: test ( -- )
+    "factor" [
+        <process>
+            test-cmd >>command
+            +closed+ >>stdin
+            "../test-log" >>stdout
+            +stdout+ >>stderr
+            4 hours >>timeout
+        try-process
+    ] with-directory ;
+
+: return-with ( obj -- ) return-continuation get continue-with ;
+
+: build-clean? ( -- ? )
+    {
+        [ load-everything-vocabs-file eval-file empty? ]
+        [ test-all-vocabs-file eval-file empty? ]
+        [ help-lint-vocabs-file eval-file empty? ]
+    } 0&& ;
+
+: build-child ( -- )
+    [
+        return-continuation set
+
+        copy-image
+
+        [ make-vm ] [ compile-failed-report status-error return-with ] recover
+        [ boot ] [ boot-failed-report status-error return-with ] recover
+        [ test ] [ test-failed-report status-error return-with ] recover
+
+        successful-report
+
+        build-clean? status-clean status-dirty ? return-with
+    ] callcc1
+    status set ;
\ No newline at end of file
diff --git a/extra/mason/cleanup/cleanup-tests.factor b/extra/mason/cleanup/cleanup-tests.factor
new file mode 100644 (file)
index 0000000..9158536
--- /dev/null
@@ -0,0 +1,4 @@
+USING: tools.test mason.cleanup ;
+IN: mason.cleanup.tests
+
+\ cleanup must-infer
diff --git a/extra/mason/cleanup/cleanup.factor b/extra/mason/cleanup/cleanup.factor
new file mode 100644 (file)
index 0000000..ae24f53
--- /dev/null
@@ -0,0 +1,22 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces arrays continuations io.files io.launcher
+mason.common mason.platform mason.config ;
+IN: mason.cleanup
+
+: compress-image ( -- )
+    "bzip2" boot-image-name 2array try-process ;
+
+: compress-test-log ( -- )
+    "test-log" exists? [
+        { "bzip2" "test-log" } try-process
+    ] when ;
+
+: cleanup ( -- )
+    builder-debug get [
+        build-dir [
+            compress-image
+            compress-test-log
+            "factor" delete-tree
+        ] with-directory
+    ] unless ;
diff --git a/extra/mason/common/common-tests.factor b/extra/mason/common/common-tests.factor
new file mode 100644 (file)
index 0000000..ed6ffec
--- /dev/null
@@ -0,0 +1,34 @@
+IN: mason.common.tests
+USING: prettyprint mason.common mason.config
+namespaces calendar tools.test io.files io.encodings.utf8 ;
+
+[ "00:01:01" ] [ 61000 milli-seconds>time ] unit-test
+
+[ "/home/bobby/builds/factor" ] [
+    [
+        "/home/bobby/builds" builds-dir set
+        builds/factor
+    ] with-scope
+] unit-test
+
+[ "/home/bobby/builds/2008-09-11-12-23" ] [
+    [
+        "/home/bobby/builds" builds-dir set
+        T{ timestamp
+            { year 2008 }
+            { month 9 }
+            { day 11 }
+            { hour 12 }
+            { minute 23 }
+        } datestamp stamp set
+        build-dir
+    ] with-scope
+] unit-test
+
+[ ] [ "empty-test" temp-file utf8 [ ] with-file-writer ] unit-test
+
+[ "empty-test" temp-file eval-file ] must-fail
+
+[ ] [ "eval-file-test" temp-file utf8 [ { 1 2 3 } . ] with-file-writer ] unit-test
+
+[ { 1 2 3 } ] [ "eval-file-test" temp-file eval-file ] unit-test
diff --git a/extra/mason/common/common.factor b/extra/mason/common/common.factor
new file mode 100644 (file)
index 0000000..dfda85e
--- /dev/null
@@ -0,0 +1,81 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces sequences splitting system accessors
+math.functions make io io.files io.launcher io.encodings.utf8
+prettyprint combinators.short-circuit parser combinators
+calendar calendar.format arrays mason.config ;
+IN: mason.common
+
+: short-running-process ( command -- )
+    #! Give network operations at most 15 minutes to complete.
+    <process>
+        swap >>command
+        15 minutes >>timeout
+    try-process ;
+
+: eval-file ( file -- obj )
+    dup utf8 file-lines parse-fresh
+    [ "Empty file: " swap append throw ] [ nip first ] if-empty ;
+
+: cat ( file -- ) utf8 file-contents print ;
+
+: cat-n ( file n -- ) [ utf8 file-lines ] dip short tail* [ print ] each ;
+
+: to-file ( object file -- ) utf8 [ . ] with-file-writer ;
+
+: datestamp ( timestamp -- string )
+    [
+        {
+            [ year>> , ]
+            [ month>> , ]
+            [ day>> , ]
+            [ hour>> , ]
+            [ minute>> , ]
+        } cleave
+    ] { } make [ pad-00 ] map "-" join ;
+
+: milli-seconds>time ( n -- string )
+    millis>timestamp
+    [ hour>> ] [ minute>> ] [ second>> floor ] tri 3array
+    [ pad-00 ] map ":" join ;
+
+SYMBOL: stamp
+
+: builds/factor ( -- path ) builds-dir get "factor" append-path ;
+: build-dir ( -- path ) builds-dir get stamp get append-path ;
+
+: prepare-build-machine ( -- )
+    builds-dir get make-directories
+    builds-dir get
+    [ { "git" "clone" "git://factorcode.org/git/factor.git" } try-process ]
+    with-directory ;
+
+: git-id ( -- id )
+    { "git" "show" } utf8 [ readln ] with-process-reader
+    " " split second ;
+
+: ?prepare-build-machine ( -- )
+    builds/factor exists? [ prepare-build-machine ] unless ;
+
+: load-everything-vocabs-file "load-everything-vocabs" ;
+: load-everything-errors-file "load-everything-errors" ;
+
+: test-all-vocabs-file "test-all-vocabs" ;
+: test-all-errors-file "test-all-errors" ;
+
+: help-lint-vocabs-file "help-lint-vocabs" ;
+: help-lint-errors-file "help-lint-errors" ;
+
+: boot-time-file "boot-time" ;
+: load-time-file "load-time" ;
+: test-time-file "test-time" ;
+: help-lint-time-file "help-lint-time" ;
+: benchmark-time-file "benchmark-time" ;
+
+: benchmarks-file "benchmarks" ;
+
+SYMBOL: status
+
+SYMBOL: status-error ! didn't bootstrap, or crashed
+SYMBOL: status-dirty ! bootstrapped but not all tests passed
+SYMBOL: status-clean ! everything good
diff --git a/extra/mason/config/config.factor b/extra/mason/config/config.factor
new file mode 100644 (file)
index 0000000..0ce059c
--- /dev/null
@@ -0,0 +1,66 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: system io.files namespaces kernel accessors ;
+IN: mason.config
+
+! (Optional) Location for build directories
+SYMBOL: builds-dir
+
+builds-dir get-global [
+    home "builds" append-path builds-dir set-global
+] unless
+
+! Who sends build reports.
+SYMBOL: builder-from
+
+! Who receives build reports.
+SYMBOL: builder-recipients
+
+! (Optional) CPU architecture to build for.
+SYMBOL: target-cpu
+
+target-cpu get-global [
+    cpu name>> target-cpu set-global
+] unless
+
+! (Optional) OS to build for.
+SYMBOL: target-os
+
+target-os get-global [
+    os name>> target-os set-global
+] unless
+
+! Keep test-log around?
+SYMBOL: builder-debug
+
+! Boolean. Do we release binaries and update the clean branch?
+SYMBOL: upload-to-factorcode
+
+! The below are only needed if upload-to-factorcode is true.
+
+! Host with clean git repo.
+SYMBOL: branch-host
+
+! Username to log in.
+SYMBOL: branch-username
+
+! Directory with git repo.
+SYMBOL: branch-directory
+
+! Host to upload clean image to.
+SYMBOL: image-host
+
+! Username to log in.
+SYMBOL: image-username
+
+! Directory with clean images.
+SYMBOL: image-directory
+
+! Host to upload binary package to.
+SYMBOL: upload-host
+
+! Username to log in.
+SYMBOL: upload-username
+
+! Directory with binary packages.
+SYMBOL: upload-directory
diff --git a/extra/mason/email/email-tests.factor b/extra/mason/email/email-tests.factor
new file mode 100644 (file)
index 0000000..5bde9a9
--- /dev/null
@@ -0,0 +1,11 @@
+IN: mason.email.tests
+USING: mason.email mason.common mason.config namespaces tools.test ;
+
+[ "mason on linux-x86-64: error" ] [
+    [
+        "linux" target-os set
+        "x86.64" target-cpu set
+        status-error status set
+        subject prefix-subject
+    ] with-scope
+] unit-test
diff --git a/extra/mason/email/email.factor b/extra/mason/email/email.factor
new file mode 100644 (file)
index 0000000..f25f7e5
--- /dev/null
@@ -0,0 +1,35 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces accessors combinators make smtp
+debugger prettyprint io io.streams.string io.encodings.utf8
+io.files io.sockets
+mason.common mason.platform mason.config ;
+IN: mason.email
+
+: prefix-subject ( str -- str' )
+    [ "mason on " % platform % ": " % % ] "" make ;
+
+: email-status ( body subject -- )
+    <email>
+        builder-from get >>from
+        builder-recipients get >>to
+        swap prefix-subject >>subject
+        swap >>body
+    send-email ;
+
+: subject ( -- str )
+    status get {
+        { status-clean [ "clean" ] }
+        { status-dirty [ "dirty" ] }
+        { status-error [ "error" ] }
+    } case ;
+
+: email-report ( -- )
+    "report" utf8 file-contents subject email-status ;
+
+: email-error ( error callstack -- )
+    [
+        "Fatal error on " write host-name print nl
+        [ error. ] [ callstack. ] bi*
+    ] with-string-writer "fatal error"
+    email-status ;
diff --git a/extra/mason/mason.factor b/extra/mason/mason.factor
new file mode 100644 (file)
index 0000000..4f9c8f6
--- /dev/null
@@ -0,0 +1,30 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel debugger io io.files threads debugger continuations
+namespaces accessors calendar mason.common mason.updates
+mason.build mason.email ;
+IN: mason
+
+: build-loop-error ( error -- )
+    error-continuation get call>> email-error ;
+
+: build-loop-fatal ( error -- )
+    "FATAL BUILDER ERROR:" print
+    error. flush ;
+
+: build-loop ( -- )
+    ?prepare-build-machine
+    [
+        [
+            builds/factor set-current-directory
+            new-code-available? [ build ] when
+        ] [
+            build-loop-error
+        ] recover
+    ] [
+        build-loop-fatal
+    ] recover
+    5 minutes sleep
+    build-loop ;
+
+MAIN: build-loop
\ No newline at end of file
diff --git a/extra/mason/platform/platform.factor b/extra/mason/platform/platform.factor
new file mode 100644 (file)
index 0000000..e4bba51
--- /dev/null
@@ -0,0 +1,19 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel system accessors namespaces splitting sequences make
+mason.config ;
+IN: mason.platform
+
+: platform ( -- string )
+    target-os get "-" target-cpu get "." split "-" join 3append ;
+
+: gnu-make ( -- string )
+    target-os get { "freebsd" "openbsd" "netbsd" } member? "gmake" "make" ? ;
+
+: boot-image-name ( -- string )
+    [
+        "boot." %
+        target-cpu get "ppc" = [ target-os get % "-" % ] when
+        target-cpu get %
+        ".image" %
+    ] "" make ;
diff --git a/extra/mason/release/archive/archive.factor b/extra/mason/release/archive/archive.factor
new file mode 100644 (file)
index 0000000..e76979d
--- /dev/null
@@ -0,0 +1,47 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel combinators sequences make namespaces io.files
+io.launcher prettyprint arrays
+mason.common mason.platform mason.config ;
+IN: mason.release.archive
+
+: base-name ( -- string )
+    [ "factor-" % platform % "-" % stamp get % ] "" make ;
+
+: extension ( -- extension )
+    target-os get {
+        { "winnt" [ ".zip" ] }
+        { "macosx" [ ".dmg" ] }
+        [ drop ".tar.gz" ]
+    } case ;
+
+: archive-name ( -- string ) base-name extension append ;
+
+: make-windows-archive ( -- )
+    [ "zip" , "-r" , archive-name , "factor" , ] { } make try-process ;
+
+: make-macosx-archive ( -- )
+    { "mkdir" "dmg-root" } try-process
+    { "cp" "-R" "factor" "dmg-root" } try-process
+    { "hdiutil" "create"
+        "-srcfolder" "dmg-root"
+        "-fs" "HFS+"
+    "-volname" "factor" }
+    archive-name suffix try-process
+    "dmg-root" delete-tree ;
+
+: make-unix-archive ( -- )
+    [ "tar" , "-cvzf" , archive-name , "factor" , ] { } make try-process ;
+
+: make-archive ( -- )
+    target-os get {
+        { "winnt" [ make-windows-archive ] }
+        { "macosx" [ make-macosx-archive ] }
+        [ drop make-unix-archive ]
+    } case ;
+
+: releases ( -- path )
+    builds-dir get "releases" append-path dup make-directories ;
+
+: save-archive ( -- )
+    archive-name releases move-file-into ;
\ No newline at end of file
diff --git a/extra/mason/release/branch/branch-tests.factor b/extra/mason/release/branch/branch-tests.factor
new file mode 100644 (file)
index 0000000..68046f7
--- /dev/null
@@ -0,0 +1,24 @@
+IN: mason.release.branch.tests
+USING: mason.release.branch mason.config tools.test namespaces ;
+
+[ { "git" "push" "joe@blah.com:/my/git" "master:clean-linux-x86-32" } ] [
+    [
+        "joe" branch-username set
+        "blah.com" branch-host set
+        "/my/git" branch-directory set
+        "linux" target-os set
+        "x86.32" target-cpu set
+        push-to-clean-branch-cmd
+    ] with-scope
+] unit-test
+
+[ { "scp" "boot.x86.64.image" "joe@blah.com:/stuff/clean/netbsd-x86-64" } ] [
+    [
+        "joe" image-username set
+        "blah.com" image-host set
+        "/stuff/clean" image-directory set
+        "netbsd" target-os set
+        "x86.64" target-cpu set
+        upload-clean-image-cmd
+    ] with-scope
+] unit-test
diff --git a/extra/mason/release/branch/branch.factor b/extra/mason/release/branch/branch.factor
new file mode 100644 (file)
index 0000000..8872cda
--- /dev/null
@@ -0,0 +1,48 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces sequences prettyprint io.files
+io.launcher make
+mason.common mason.platform mason.config ;
+IN: mason.release.branch
+
+: branch-name ( -- string ) "clean-" platform append ;
+
+: refspec ( -- string ) "master:" branch-name append ;
+
+: push-to-clean-branch-cmd ( -- args )
+    [
+        "git" , "push" ,
+        [
+            branch-username get % "@" %
+            branch-host get % ":" %
+            branch-directory get %
+        ] "" make ,
+        refspec ,
+    ] { } make ;
+
+: push-to-clean-branch ( -- )
+    push-to-clean-branch-cmd short-running-process ;
+
+: upload-clean-image-cmd ( -- args )
+    [
+        "scp" ,
+        boot-image-name ,
+        [
+            image-username get % "@" %
+            image-host get % ":" %
+            image-directory get % "/" %
+            platform %
+        ] "" make ,
+    ] { } make ;
+
+: upload-clean-image ( -- )
+    upload-clean-image-cmd short-running-process ;
+
+: (update-clean-branch) ( -- )
+    "factor" [
+        push-to-clean-branch
+        upload-clean-image
+    ] with-directory ;
+
+: update-clean-branch ( -- )
+    upload-to-factorcode get [ (update-clean-branch) ] when ;
diff --git a/extra/mason/release/release.factor b/extra/mason/release/release.factor
new file mode 100644 (file)
index 0000000..bbb47ba
--- /dev/null
@@ -0,0 +1,16 @@
+! Copyright (C) 2008 Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel debugger namespaces sequences splitting
+combinators io io.files io.launcher prettyprint bootstrap.image
+mason.common mason.release.branch mason.release.tidy
+mason.release.archive mason.release.upload ;
+IN: mason.release
+
+: (release) ( -- )
+    update-clean-branch
+    tidy
+    make-archive
+    upload
+    save-archive ;
+
+: release ( -- ) status get status-clean eq? [ (release) ] when ;
\ No newline at end of file
diff --git a/extra/mason/release/tidy/tidy-tests.factor b/extra/mason/release/tidy/tidy-tests.factor
new file mode 100644 (file)
index 0000000..e140926
--- /dev/null
@@ -0,0 +1,2 @@
+IN: mason.release.tidy.tests
+USING: mason.release.tidy tools.test ;
diff --git a/extra/mason/release/tidy/tidy.factor b/extra/mason/release/tidy/tidy.factor
new file mode 100644 (file)
index 0000000..a456e6f
--- /dev/null
@@ -0,0 +1,33 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces continuations debugger sequences fry
+io.files io.launcher mason.common mason.platform
+mason.config ;
+IN: mason.release.tidy
+
+: common-files ( -- seq )
+    {
+        "boot.x86.32.image"
+        "boot.x86.64.image"
+        "boot.macosx-ppc.image"
+        "boot.linux-ppc.image"
+        "vm"
+        "temp"
+        "logs"
+        ".git"
+        ".gitignore"
+        "Makefile"
+        "unmaintained"
+        "unfinished"
+        "build-support"
+    } ;
+
+: remove-common-files ( -- )
+    common-files [ delete-tree ] each ;
+
+: remove-factor-app ( -- )
+    target-os get "macosx" =
+    [ "Factor.app" delete-tree ] unless ;
+
+: tidy ( -- )
+    "factor" [ remove-factor-app remove-common-files ] with-directory ;
diff --git a/extra/mason/release/upload/upload-tests.factor b/extra/mason/release/upload/upload-tests.factor
new file mode 100644 (file)
index 0000000..9f5300b
--- /dev/null
@@ -0,0 +1,38 @@
+IN: mason.release.upload.tests
+USING: mason.release.upload mason.common mason.config
+mason.common namespaces calendar tools.test ;
+
+[
+    {
+        "scp"
+        "factor-linux-ppc-2008-09-11-23-12.tar.gz"
+        "slava@www.apple.com:/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz.incomplete"
+    }
+    {
+        "ssh"
+        "www.apple.com"
+        "-l" "slava"
+        "mv"
+        "/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz.incomplete"
+        "/uploads/linux-ppc/factor-linux-ppc-2008-09-11-23-12.tar.gz"
+    }
+] [
+    [
+        "slava" upload-username set
+        "www.apple.com" upload-host set
+        "/uploads" upload-directory set
+        "linux" target-os set
+        "ppc" target-cpu set
+        T{ timestamp
+            { year 2008 }
+            { month 09 }
+            { day 11 }
+            { hour 23 }
+            { minute 12 }
+        } datestamp stamp set
+        upload-command
+        rename-command
+    ] with-scope
+] unit-test
+
+\ upload must-infer
diff --git a/extra/mason/release/upload/upload.factor b/extra/mason/release/upload/upload.factor
new file mode 100644 (file)
index 0000000..2bf18f1
--- /dev/null
@@ -0,0 +1,47 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces make sequences arrays io io.files
+io.launcher mason.common mason.platform
+mason.release.archive mason.config ;
+IN: mason.release.upload
+
+: remote-location ( -- dest )
+    upload-directory get "/" platform 3append ;
+
+: remote-archive-name ( -- dest )
+    remote-location "/" archive-name 3append ;
+
+: temp-archive-name ( -- dest )
+    remote-archive-name ".incomplete" append ;
+
+: upload-command ( -- args )
+    "scp"
+    archive-name
+    [
+        upload-username get % "@" %
+        upload-host get % ":" %
+        temp-archive-name %
+    ] "" make
+    3array ;
+
+: rename-command ( -- args )
+    [
+        "ssh" ,
+        upload-host get ,
+        "-l" ,
+        upload-username get ,
+        "mv" ,
+        temp-archive-name ,
+        remote-archive-name ,
+    ] { } make ;
+
+: upload-temp-file ( -- )
+    upload-command short-running-process ;
+
+: rename-temp-file ( -- )
+    rename-command short-running-process ;
+
+: upload ( -- )
+    upload-to-factorcode get
+    [ upload-temp-file rename-temp-file ]
+    when ;
diff --git a/extra/mason/report/report-tests.factor b/extra/mason/report/report-tests.factor
new file mode 100644 (file)
index 0000000..7f5c4f1
--- /dev/null
@@ -0,0 +1,2 @@
+IN: mason.report.tests
+USING: mason.report tools.test ;
diff --git a/extra/mason/report/report.factor b/extra/mason/report/report.factor
new file mode 100644 (file)
index 0000000..145686d
--- /dev/null
@@ -0,0 +1,66 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces debugger fry io io.files io.sockets
+io.encodings.utf8 prettyprint benchmark mason.common
+mason.platform mason.config ;
+IN: mason.report
+
+: time. ( file -- )
+    [ write ": " write ] [ eval-file milli-seconds>time print ] bi ;
+
+: common-report ( -- )
+    "Build machine: " write host-name print
+    "CPU: " write target-cpu get print
+    "OS: " write target-os get print
+    "Build directory: " write build-dir print
+    "git id: " write "git-id" eval-file print nl ;
+
+: with-report ( quot -- )
+    [ "report" utf8 ] dip '[ common-report @ ] with-file-writer ;
+
+: compile-failed-report ( error -- )
+    [
+        "VM compile failed:" print nl
+        "compile-log" cat nl
+        error.
+    ] with-report ;
+
+: boot-failed-report ( error -- )
+    [
+        "Bootstrap failed:" print nl
+        "boot-log" 100 cat-n nl
+        error.
+    ] with-report ;
+
+: test-failed-report ( error -- )
+    [
+        "Tests failed:" print nl
+        "test-log" 100 cat-n nl
+        error.
+    ] with-report ;
+
+: successful-report ( -- )
+    [
+        boot-time-file time.
+        load-time-file time.
+        test-time-file time.
+        help-lint-time-file time.
+        benchmark-time-file time.
+
+        nl
+
+        "Did not pass load-everything:" print
+        load-everything-vocabs-file cat
+        load-everything-errors-file cat
+
+        "Did not pass test-all:" print
+        test-all-vocabs-file cat
+        test-all-errors-file cat
+
+        "Did not pass help-lint:" print
+        help-lint-vocabs-file cat
+        help-lint-errors-file cat
+
+        "Benchmarks:" print
+        benchmarks-file eval-file benchmarks.
+    ] with-report ;
\ No newline at end of file
diff --git a/extra/mason/summary.txt b/extra/mason/summary.txt
new file mode 100644 (file)
index 0000000..798064e
--- /dev/null
@@ -0,0 +1 @@
+Continuous build system for Factor
diff --git a/extra/mason/test/test.factor b/extra/mason/test/test.factor
new file mode 100644 (file)
index 0000000..5888417
--- /dev/null
@@ -0,0 +1,38 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces assocs io.files io.encodings.utf8
+prettyprint help.lint benchmark tools.time bootstrap.stage2
+tools.test tools.vocabs mason.common ;
+IN: mason.test
+
+: do-load ( -- )
+    try-everything
+    [ keys load-everything-vocabs-file to-file ]
+    [ load-everything-errors-file utf8 [ load-failures. ] with-file-writer ]
+    bi ;
+
+: do-tests ( -- )
+    run-all-tests
+    [ keys test-all-vocabs-file to-file ]
+    [ test-all-errors-file utf8 [ test-failures. ] with-file-writer ]
+    bi ;
+
+: do-help-lint ( -- )
+    "" run-help-lint
+    [ keys help-lint-vocabs-file to-file ]
+    [ help-lint-errors-file utf8 [ typos. ] with-file-writer ]
+    bi ;
+
+: do-benchmarks ( -- )
+    run-benchmarks benchmarks-file to-file ;
+
+: do-all ( -- )
+    ".." [
+        bootstrap-time get boot-time-file to-file
+        [ do-load ] benchmark load-time-file to-file
+        [ do-tests ] benchmark test-time-file to-file
+        [ do-help-lint ] benchmark help-lint-time-file to-file
+        [ do-benchmarks ] benchmark benchmark-time-file to-file
+    ] with-directory ;
+
+MAIN: do-all
\ No newline at end of file
diff --git a/extra/mason/updates/updates.factor b/extra/mason/updates/updates.factor
new file mode 100644 (file)
index 0000000..9c42ba2
--- /dev/null
@@ -0,0 +1,28 @@
+! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel io.launcher bootstrap.image.download
+mason.common mason.platform ;
+IN: mason.updates
+
+: git-pull-cmd ( -- cmd )
+    {
+        "git"
+        "pull"
+        "--no-summary"
+        "git://factorcode.org/git/factor.git"
+        "master"
+    } ;
+
+: updates-available? ( -- ? )
+    git-id
+    git-pull-cmd short-running-process
+    git-id
+    = not ;
+
+: new-image-available? ( -- ? )
+    boot-image-name need-new-image? [ download-my-image t ] [ f ] if ;
+
+: new-code-available? ( -- ? )
+    updates-available?
+    new-image-available?
+    or ;
\ No newline at end of file
diff --git a/extra/math/compare/authors.txt b/extra/math/compare/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/extra/math/compare/compare-docs.factor b/extra/math/compare/compare-docs.factor
new file mode 100644 (file)
index 0000000..eb199cd
--- /dev/null
@@ -0,0 +1,37 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: help.markup help.syntax ;
+
+IN: math.compare
+
+HELP: absmin
+{ $values { "a" "a number" } { "b" "a number" } { "x" "a number" } }
+{ $description 
+    "Returns the smaller absolute number with the original sign." 
+} ;
+
+HELP: absmax
+{ $values { "a" "a number" } { "b" "a number" } { "x" "a number" } }
+{ $description 
+    "Returns the larger absolute number with the original sign."
+} ;
+
+HELP: posmax
+{ $values { "a" "a number" } { "b" "a number" } { "x" "a number" } }
+{ $description 
+    "Returns the most-positive value, or zero if both are negative."
+} ;
+
+HELP: negmin
+{ $values { "a" "a number" } { "b" "a number" } { "x" "a number" } }
+{ $description 
+    "Returns the most-negative value, or zero if both are positive."
+} ;
+
+HELP: clamp
+{ $values { "a" "a number" } { "value" "a number" } { "b" "a number" } { "x" "a number" } }
+{ $description 
+    "Returns the value when between 'a' and 'b', 'a' if <= 'a', or 'b' if >= 'b'."
+} ;
+
diff --git a/extra/math/compare/compare-tests.factor b/extra/math/compare/compare-tests.factor
new file mode 100644 (file)
index 0000000..765f34e
--- /dev/null
@@ -0,0 +1,28 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: kernel math math.functions math.compare tools.test ;
+
+IN: math.compare.tests
+
+[ -1 ] [ -1 5 absmin ] unit-test
+[ -1 ] [ -1 -5 absmin ] unit-test
+
+[ -5 ] [ 1 -5 absmax ] unit-test
+[ 5 ] [ 1 5 absmax ] unit-test
+
+[ 0 ] [ -1 -3 posmax ] unit-test
+[ 1 ] [ 1 -3 posmax ] unit-test
+[ 3 ] [ -1 3 posmax ] unit-test
+
+[ 0 ] [ 1 3 negmin ] unit-test
+[ -3 ] [ 1 -3 negmin ] unit-test
+[ -1 ] [ -1 3 negmin ] unit-test
+
+[ 0 ] [ 0 -1 2 clamp ] unit-test
+[ 1 ] [ 0 1 2 clamp ] unit-test
+[ 2 ] [ 0 3 2 clamp ] unit-test
+
+
+
+
diff --git a/extra/math/compare/compare.factor b/extra/math/compare/compare.factor
new file mode 100644 (file)
index 0000000..28a8ead
--- /dev/null
@@ -0,0 +1,22 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: math math.order kernel ;
+
+IN: math.compare 
+
+: absmin ( a b -- x ) 
+   [ [ abs ] bi@ < ] 2keep ? ;
+
+: absmax ( a b -- x ) 
+   [ [ abs ] bi@ > ] 2keep ? ;
+
+: posmax ( a b -- x ) 
+   0 max max ;
+
+: negmin ( a b -- x ) 
+   0 min min ;
+
+: clamp ( a value b -- x )
+   min max ; 
+
diff --git a/extra/math/compare/summary.txt b/extra/math/compare/summary.txt
new file mode 100644 (file)
index 0000000..95edea5
--- /dev/null
@@ -0,0 +1 @@
+Comparison functions.
diff --git a/extra/math/finance/authors.txt b/extra/math/finance/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/extra/math/finance/finance-docs.factor b/extra/math/finance/finance-docs.factor
new file mode 100644 (file)
index 0000000..5024e83
--- /dev/null
@@ -0,0 +1,34 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: help.markup help.syntax ;
+
+IN: math.finance
+
+HELP: sma
+{ $values { "seq" "a sequence" } { "n" "number of periods" } { "newseq" "a sequence" } }
+{ $description "Returns the Simple Moving Average with the specified periodicity." } ;
+
+HELP: ema
+{ $values { "seq" "a sequence" } { "n" "number of periods" } { "newseq" "a sequence" } }
+{ $description 
+    "Returns the Exponential Moving Average with the specified periodicity, calculated by:\n" 
+    { $list 
+        "A = 2.0 / (N + 1)"
+        "EMA[t] = (A * SEQ[t]) + ((1-A) * EMA[t-1])" }
+} ;
+
+HELP: macd
+{ $values { "seq" "a sequence" } { "n1" "short number of periods" } { "n2" "long number of periods" } { "newseq" "a sequence" } }
+{ $description 
+    "Returns the Moving Average Converge of the sequence, calculated by:\n"
+    { $list "MACD[t] = EMA2[t] - EMA1[t]" }
+} ;
+
+HELP: momentum
+{ $values { "seq" "a sequence" } { "n" "number of periods" } { "newseq" "a sequence" } }
+{ $description
+    "Returns the Momentum of the sequence, calculated by:\n"
+    { $list "MOM[t] = SEQ[t] - SEQ[t-n]" }
+} ;
+
diff --git a/extra/math/finance/finance-tests.factor b/extra/math/finance/finance-tests.factor
new file mode 100644 (file)
index 0000000..dce701b
--- /dev/null
@@ -0,0 +1,8 @@
+USING: kernel math math.functions math.finance tools.test ;
+
+IN: math.finance.tests
+
+[ { 2 4 } ] [ { 1 3 5 } 2 sma ] unit-test
+
+[ { 1 3 1 } ] [ { 1 3 2 6 3 } 2 momentum ] unit-test
+
diff --git a/extra/math/finance/finance.factor b/extra/math/finance/finance.factor
new file mode 100644 (file)
index 0000000..db300a3
--- /dev/null
@@ -0,0 +1,31 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: arrays assocs kernel grouping sequences shuffle
+math math.functions math.statistics math.vectors ;
+
+IN: math.finance
+
+<PRIVATE
+
+: weighted ( x y a -- z ) 
+    tuck [ * ] [ 1 swap - * ] 2bi* + ;
+
+: a ( n -- a ) 
+    1 + 2 swap / ;
+
+PRIVATE>
+
+: ema ( seq n -- newseq )
+    a swap unclip [ [ dup ] 2dip swap rot weighted ] accumulate 2nip ;
+
+: sma ( seq n -- newseq )
+    clump [ mean ] map ;
+
+: macd ( seq n1 n2 -- newseq )
+    rot dup ema [ swap ema ] dip v- ;
+
+: momentum ( seq n -- newseq )
+    2dup tail-slice -rot swap [ length ] keep
+    [ - neg ] dip swap head-slice v- ;
+
diff --git a/extra/math/finance/summary.txt b/extra/math/finance/summary.txt
new file mode 100644 (file)
index 0000000..9fb3bc8
--- /dev/null
@@ -0,0 +1 @@
+Moving averages and other calculations useful for finance.
index f7295604cd9430031e5fa4d394d1ccd19783f24d..28cc05151bb5e76c7760d00589fc39953b433a72 100644 (file)
@@ -4,21 +4,21 @@ IN: math.statistics
 
 : mean ( seq -- n )
     #! arithmetic mean, sum divided by length
-    [ sum ] keep length / ;
+    [ sum ] [ length ] bi / ;
 
 : geometric-mean ( seq -- n )
     #! geometric mean, nth root of product
-    [ product ] keep length swap nth-root ;
+    [ length ] [ product ] bi nth-root ;
 
 : harmonic-mean ( seq -- n )
     #! harmonic mean, reciprocal of sum of reciprocals.
     #! positive reals only
-    0 [ recip + ] reduce recip ;
+    [ recip ] sigma recip ;
 
 : median ( seq -- n )
     #! middle number if odd, avg of two middle numbers if even
     natural-sort dup length dup even? [
-        1- 2 / swap [ nth ] 2keep >r 1+ r> nth + 2 /
+        1- 2 / swap [ nth ] [ >r 1+ r> nth ] 2bi + 2 /
     ] [
         2 / swap nth
     ] if ;
diff --git a/extra/parser-combinators/regexp/authors.txt b/extra/parser-combinators/regexp/authors.txt
new file mode 100755 (executable)
index 0000000..5674120
--- /dev/null
@@ -0,0 +1,2 @@
+Doug Coleman
+Slava Pestov
diff --git a/extra/parser-combinators/regexp/regexp-tests.factor b/extra/parser-combinators/regexp/regexp-tests.factor
new file mode 100755 (executable)
index 0000000..78abd8b
--- /dev/null
@@ -0,0 +1,235 @@
+USING: parser-combinators.regexp tools.test kernel ;
+IN: parser-combinators.regexp.tests
+
+[ f ] [ "b" "a*" f <regexp> matches? ] unit-test
+[ t ] [ "" "a*" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a*" f <regexp> matches? ] unit-test
+[ t ] [ "aaaaaaa" "a*" f <regexp> matches? ] unit-test
+[ f ] [ "ab" "a*" f <regexp> matches? ] unit-test
+
+[ t ] [ "abc" "abc" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a|b|c" f <regexp> matches? ] unit-test
+[ t ] [ "b" "a|b|c" f <regexp> matches? ] unit-test
+[ t ] [ "c" "a|b|c" f <regexp> matches? ] unit-test
+[ f ] [ "c" "d|e|f" f <regexp> matches? ] unit-test
+
+[ f ] [ "aa" "a|b|c" f <regexp> matches? ] unit-test
+[ f ] [ "bb" "a|b|c" f <regexp> matches? ] unit-test
+[ f ] [ "cc" "a|b|c" f <regexp> matches? ] unit-test
+[ f ] [ "cc" "d|e|f" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "a+" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a+" f <regexp> matches? ] unit-test
+[ t ] [ "aa" "a+" f <regexp> matches? ] unit-test
+
+[ t ] [ "" "a?" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a?" f <regexp> matches? ] unit-test
+[ f ] [ "aa" "a?" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "." f <regexp> matches? ] unit-test
+[ t ] [ "a" "." f <regexp> matches? ] unit-test
+[ t ] [ "." "." f <regexp> matches? ] unit-test
+! [ f ] [ "\n" "." f <regexp> matches? ] unit-test
+
+[ f ] [ "" ".+" f <regexp> matches? ] unit-test
+[ t ] [ "a" ".+" f <regexp> matches? ] unit-test
+[ t ] [ "ab" ".+" f <regexp> matches? ] unit-test
+
+[ t ] [ "" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+[ t ] [ "c" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+[ t ] [ "cc" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+[ f ] [ "ccd" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+[ t ] [ "d" "a|b*|c+|d?" f <regexp> matches? ] unit-test
+
+[ t ] [ "foo" "foo|bar" f <regexp> matches? ] unit-test
+[ t ] [ "bar" "foo|bar" f <regexp> matches? ] unit-test
+[ f ] [ "foobar" "foo|bar" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "(a)" f <regexp> matches? ] unit-test
+[ t ] [ "a" "(a)" f <regexp> matches? ] unit-test
+[ f ] [ "aa" "(a)" f <regexp> matches? ] unit-test
+[ t ] [ "aa" "(a*)" f <regexp> matches? ] unit-test
+
+[ f ] [ "aababaaabbac" "(a|b)+" f <regexp> matches? ] unit-test
+[ t ] [ "ababaaabba" "(a|b)+" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "a{1}" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a{1}" f <regexp> matches? ] unit-test
+[ f ] [ "aa" "a{1}" f <regexp> matches? ] unit-test
+
+[ f ] [ "a" "a{2,}" f <regexp> matches? ] unit-test
+[ t ] [ "aaa" "a{2,}" f <regexp> matches? ] unit-test
+[ t ] [ "aaaa" "a{2,}" f <regexp> matches? ] unit-test
+[ t ] [ "aaaaa" "a{2,}" f <regexp> matches? ] unit-test
+
+[ t ] [ "" "a{,2}" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a{,2}" f <regexp> matches? ] unit-test
+[ t ] [ "aa" "a{,2}" f <regexp> matches? ] unit-test
+[ f ] [ "aaa" "a{,2}" f <regexp> matches? ] unit-test
+[ f ] [ "aaaa" "a{,2}" f <regexp> matches? ] unit-test
+[ f ] [ "aaaaa" "a{,2}" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "a{1,3}" f <regexp> matches? ] unit-test
+[ t ] [ "a" "a{1,3}" f <regexp> matches? ] unit-test
+[ t ] [ "aa" "a{1,3}" f <regexp> matches? ] unit-test
+[ t ] [ "aaa" "a{1,3}" f <regexp> matches? ] unit-test
+[ f ] [ "aaaa" "a{1,3}" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "[a]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[a]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[abc]" f <regexp> matches? ] unit-test
+[ f ] [ "b" "[a]" f <regexp> matches? ] unit-test
+[ f ] [ "d" "[abc]" f <regexp> matches? ] unit-test
+[ t ] [ "ab" "[abc]{1,2}" f <regexp> matches? ] unit-test
+[ f ] [ "abc" "[abc]{1,2}" f <regexp> matches? ] unit-test
+
+[ f ] [ "" "[^a]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[^a]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[^abc]" f <regexp> matches? ] unit-test
+[ t ] [ "b" "[^a]" f <regexp> matches? ] unit-test
+[ t ] [ "d" "[^abc]" f <regexp> matches? ] unit-test
+[ f ] [ "ab" "[^abc]{1,2}" f <regexp> matches? ] unit-test
+[ f ] [ "abc" "[^abc]{1,2}" f <regexp> matches? ] unit-test
+
+[ t ] [ "]" "[]]" f <regexp> matches? ] unit-test
+[ f ] [ "]" "[^]]" f <regexp> matches? ] unit-test
+
+! [ "^" "[^]" f <regexp> matches? ] must-fail
+[ t ] [ "^" "[]^]" f <regexp> matches? ] unit-test
+[ t ] [ "]" "[]^]" f <regexp> matches? ] unit-test
+
+[ t ] [ "[" "[[]" f <regexp> matches? ] unit-test
+[ f ] [ "^" "[^^]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[^^]" f <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[-]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[-]" f <regexp> matches? ] unit-test
+[ f ] [ "-" "[^-]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[^-]" f <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[-a]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[-a]" f <regexp> matches? ] unit-test
+[ t ] [ "-" "[a-]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-]" f <regexp> matches? ] unit-test
+[ f ] [ "b" "[a-]" f <regexp> matches? ] unit-test
+[ f ] [ "-" "[^-]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[^-]" f <regexp> matches? ] unit-test
+
+[ f ] [ "-" "[a-c]" f <regexp> matches? ] unit-test
+[ t ] [ "-" "[^a-c]" f <regexp> matches? ] unit-test
+[ t ] [ "b" "[a-c]" f <regexp> matches? ] unit-test
+[ f ] [ "b" "[^a-c]" f <regexp> matches? ] unit-test
+
+[ t ] [ "-" "[a-c-]" f <regexp> matches? ] unit-test
+[ f ] [ "-" "[^a-c-]" f <regexp> matches? ] unit-test
+
+[ t ] [ "\\" "[\\\\]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\\\]" f <regexp> matches? ] unit-test
+[ f ] [ "\\" "[^\\\\]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[^\\\\]" f <regexp> matches? ] unit-test
+
+[ t ] [ "0" "[\\d]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\d]" f <regexp> matches? ] unit-test
+[ f ] [ "0" "[^\\d]" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[^\\d]" f <regexp> matches? ] unit-test
+
+[ t ] [ "a" "[a-z]{1,}|[A-Z]{2,4}|b*|c|(f|g)*" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}|b*|c|(f|g)*" f <regexp> matches? ] unit-test
+[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}" f <regexp> matches? ] unit-test
+
+[ t ] [ "1000" "\\d{4,6}" f <regexp> matches? ] unit-test
+[ t ] [ "1000" "[0-9]{4,6}" f <regexp> matches? ] unit-test
+
+[ t ] [ "abc" "\\p{Lower}{3}" f <regexp> matches? ] unit-test
+[ f ] [ "ABC" "\\p{Lower}{3}" f <regexp> matches? ] unit-test
+[ t ] [ "ABC" "\\p{Upper}{3}" f <regexp> matches? ] unit-test
+[ f ] [ "abc" "\\p{Upper}{3}" f <regexp> matches? ] unit-test
+
+[ f ] [ "abc" "[\\p{Upper}]{3}" f <regexp> matches? ] unit-test
+[ t ] [ "ABC" "[\\p{Upper}]{3}" f <regexp> matches? ] unit-test
+
+[ t ] [ "" "\\Q\\E" f <regexp> matches? ] unit-test
+[ f ] [ "a" "\\Q\\E" f <regexp> matches? ] unit-test
+[ t ] [ "|*+" "\\Q|*+\\E" f <regexp> matches? ] unit-test
+[ f ] [ "abc" "\\Q|*+\\E" f <regexp> matches? ] unit-test
+
+[ t ] [ "S" "\\0123" f <regexp> matches? ] unit-test
+[ t ] [ "SXY" "\\0123XY" f <regexp> matches? ] unit-test
+[ t ] [ "x" "\\x78" f <regexp> matches? ] unit-test
+[ f ] [ "y" "\\x78" f <regexp> matches? ] unit-test
+[ t ] [ "x" "\\u000078" f <regexp> matches? ] unit-test
+[ f ] [ "y" "\\u000078" f <regexp> matches? ] unit-test
+
+[ t ] [ "ab" "a+b" f <regexp> matches? ] unit-test
+[ f ] [ "b" "a+b" f <regexp> matches? ] unit-test
+[ t ] [ "aab" "a+b" f <regexp> matches? ] unit-test
+[ f ] [ "abb" "a+b" f <regexp> matches? ] unit-test
+
+[ t ] [ "abbbb" "ab*" f <regexp> matches? ] unit-test
+[ t ] [ "a" "ab*" f <regexp> matches? ] unit-test
+[ f ] [ "abab" "ab*" f <regexp> matches? ] unit-test
+
+[ f ] [ "x" "\\." f <regexp> matches? ] unit-test
+[ t ] [ "." "\\." f <regexp> matches? ] unit-test
+
+[ t ] [ "aaaab" "a+ab" f <regexp> matches? ] unit-test
+[ f ] [ "aaaxb" "a+ab" f <regexp> matches? ] unit-test
+[ t ] [ "aaacb" "a+cb" f <regexp> matches? ] unit-test
+[ f ] [ "aaaab" "a++ab" f <regexp> matches? ] unit-test
+[ t ] [ "aaacb" "a++cb" f <regexp> matches? ] unit-test
+
+[ 3 ] [ "aaacb" "a*" f <regexp> match-head ] unit-test
+[ 1 ] [ "aaacb" "a+?" f <regexp> match-head ] unit-test
+[ 2 ] [ "aaacb" "aa?" f <regexp> match-head ] unit-test
+[ 1 ] [ "aaacb" "aa??" f <regexp> match-head ] unit-test
+[ 3 ] [ "aacb" "aa?c" f <regexp> match-head ] unit-test
+[ 3 ] [ "aacb" "aa??c" f <regexp> match-head ] unit-test
+
+[ t ] [ "aaa" "AAA" t <regexp> matches? ] unit-test
+[ f ] [ "aax" "AAA" t <regexp> matches? ] unit-test
+[ t ] [ "aaa" "A*" t <regexp> matches? ] unit-test
+[ f ] [ "aaba" "A*" t <regexp> matches? ] unit-test
+[ t ] [ "b" "[AB]" t <regexp> matches? ] unit-test
+[ f ] [ "c" "[AB]" t <regexp> matches? ] unit-test
+[ t ] [ "c" "[A-Z]" t <regexp> matches? ] unit-test
+[ f ] [ "3" "[A-Z]" t <regexp> matches? ] unit-test
+
+[ ] [ 
+    "(0[lL]?|[1-9]\\d{0,9}(\\d{0,9}[lL])?|0[xX]\\p{XDigit}{1,8}(\\p{XDigit}{0,8}[lL])?|0[0-7]{1,11}([0-7]{0,11}[lL])?|([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][+-]?[0-9]+)?[fFdD]?|[0-9]+([eE][+-]?[0-9]+[fFdD]?|([eE][+-]?[0-9]+)?[fFdD]))"
+    f <regexp> drop
+] unit-test
+
+[ t ] [ "fxxbar" "(?!foo).{3}bar" f <regexp> matches? ] unit-test
+[ f ] [ "foobar" "(?!foo).{3}bar" f <regexp> matches? ] unit-test
+
+[ 3 ] [ "foobar" "foo(?=bar)" f <regexp> match-head ] unit-test
+[ f ] [ "foobxr" "foo(?=bar)" f <regexp> match-head ] unit-test
+
+[ f ] [ "foobxr" "foo\\z" f <regexp> match-head ] unit-test
+[ 3 ] [ "foo" "foo\\z" f <regexp> match-head ] unit-test
+
+[ 3 ] [ "foo bar" "foo\\b" f <regexp> match-head ] unit-test
+[ f ] [ "fooxbar" "foo\\b" f <regexp> matches? ] unit-test
+[ t ] [ "foo" "foo\\b" f <regexp> matches? ] unit-test
+[ t ] [ "foo bar" "foo\\b bar" f <regexp> matches? ] unit-test
+[ f ] [ "fooxbar" "foo\\bxbar" f <regexp> matches? ] unit-test
+[ f ] [ "foo" "foo\\bbar" f <regexp> matches? ] unit-test
+
+[ f ] [ "foo bar" "foo\\B" f <regexp> matches? ] unit-test
+[ 3 ] [ "fooxbar" "foo\\B" f <regexp> match-head ] unit-test
+[ t ] [ "foo" "foo\\B" f <regexp> matches? ] unit-test
+[ f ] [ "foo bar" "foo\\B bar" f <regexp> matches? ] unit-test
+[ t ] [ "fooxbar" "foo\\Bxbar" f <regexp> matches? ] unit-test
+[ f ] [ "foo" "foo\\Bbar" f <regexp> matches? ] unit-test
+
+[ t ] [ "s@f" "[a-z.-]@[a-z]" f <regexp> matches? ] unit-test
+[ f ] [ "a" "[a-z.-]@[a-z]" f <regexp> matches? ] unit-test
+[ t ] [ ".o" "\\.[a-z]" f <regexp> matches? ] unit-test
+
+! Bug in parsing word
+[ t ] [
+    "a"
+    R' a'
+    matches?
+] unit-test
diff --git a/extra/parser-combinators/regexp/regexp.factor b/extra/parser-combinators/regexp/regexp.factor
new file mode 100755 (executable)
index 0000000..40d4603
--- /dev/null
@@ -0,0 +1,329 @@
+USING: arrays combinators kernel lists math math.parser
+namespaces parser lexer parser-combinators parser-combinators.simple
+promises quotations sequences combinators.lib strings math.order
+assocs prettyprint.backend memoize unicode.case unicode.categories
+combinators.short-circuit accessors make io ;
+IN: parser-combinators.regexp
+
+<PRIVATE
+
+SYMBOL: ignore-case?
+
+: char=-quot ( ch -- quot )
+    ignore-case? get
+    [ ch>upper [ swap ch>upper = ] ] [ [ = ] ] if
+    curry ;
+
+: char-between?-quot ( ch1 ch2 -- quot )
+    ignore-case? get
+    [ [ ch>upper ] bi@ [ >r >r ch>upper r> r> between? ] ]
+    [ [ between? ] ]
+    if 2curry ;
+
+: <@literal ( parser obj -- action ) [ nip ] curry <@ ;
+
+: <@delay ( parser quot -- action ) [ curry ] curry <@ ;
+
+PRIVATE>
+
+: ascii? ( n -- ? ) 
+    0 HEX: 7f between? ;
+
+: octal-digit? ( n -- ? )
+    CHAR: 0 CHAR: 7 between? ;
+
+: decimal-digit? ( n -- ? )
+    CHAR: 0 CHAR: 9 between? ;
+
+: hex-digit? ( n -- ? )
+    dup decimal-digit?
+    over CHAR: a CHAR: f between? or
+    swap CHAR: A CHAR: F between? or ;
+
+: control-char? ( n -- ? )
+    dup 0 HEX: 1f between?
+    swap HEX: 7f = or ;
+
+: punct? ( n -- ? )
+    "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" member? ;
+
+: c-identifier-char? ( ch -- ? )
+    dup alpha? swap CHAR: _ = or ;
+
+: java-blank? ( n -- ? )
+    {
+        CHAR: \s
+        CHAR: \t CHAR: \n CHAR: \r
+        HEX: c HEX: 7 HEX: 1b
+    } member? ;
+
+: java-printable? ( n -- ? )
+    dup alpha? swap punct? or ;
+
+: 'ordinary-char' ( -- parser )
+    [ "\\^*+?|(){}[$" member? not ] satisfy
+    [ char=-quot ] <@ ;
+
+: 'octal-digit' ( -- parser ) [ octal-digit? ] satisfy ;
+
+: 'octal' ( -- parser )
+    "0" token 'octal-digit' 1 3 from-m-to-n &>
+    [ oct> ] <@ ;
+
+: 'hex-digit' ( -- parser ) [ hex-digit? ] satisfy ;
+
+: 'hex' ( -- parser )
+    "x" token 'hex-digit' 2 exactly-n &>
+    "u" token 'hex-digit' 6 exactly-n &> <|>
+    [ hex> ] <@ ;
+
+: satisfy-tokens ( assoc -- parser )
+    [ >r token r> <@literal ] { } assoc>map <or-parser> ;
+
+: 'simple-escape-char' ( -- parser )
+    {
+        { "\\" CHAR: \\ }
+        { "t"  CHAR: \t }
+        { "n"  CHAR: \n }
+        { "r"  CHAR: \r }
+        { "f"  HEX: c   }
+        { "a"  HEX: 7   }
+        { "e"  HEX: 1b  }
+    } [ char=-quot ] assoc-map satisfy-tokens ;
+
+: 'predefined-char-class' ( -- parser )
+    {
+        { "d" [ digit? ] }
+        { "D" [ digit? not ] }
+        { "s" [ java-blank? ] }
+        { "S" [ java-blank? not ] }
+        { "w" [ c-identifier-char? ] }
+        { "W" [ c-identifier-char? not ] }
+    } satisfy-tokens ;
+
+: 'posix-character-class' ( -- parser )
+    {
+        { "Lower" [ letter? ] }
+        { "Upper" [ LETTER? ] }
+        { "ASCII" [ ascii? ] }
+        { "Alpha" [ Letter? ] }
+        { "Digit" [ digit? ] }
+        { "Alnum" [ alpha? ] }
+        { "Punct" [ punct? ] }
+        { "Graph" [ java-printable? ] }
+        { "Print" [ java-printable? ] }
+        { "Blank" [ " \t" member? ] }
+        { "Cntrl" [ control-char? ] }
+        { "XDigit" [ hex-digit? ] }
+        { "Space" [ java-blank? ] }
+    } satisfy-tokens "p{" "}" surrounded-by ;
+
+: 'simple-escape' ( -- parser )
+    'octal'
+    'hex' <|>
+    "c" token [ LETTER? ] satisfy &> <|>
+    any-char-parser <|>
+    [ char=-quot ] <@ ;
+
+: 'escape' ( -- parser )
+    "\\" token
+    'simple-escape-char'
+    'predefined-char-class' <|>
+    'posix-character-class' <|>
+    'simple-escape' <|> &> ;
+
+: 'any-char' ( -- parser )
+    "." token [ drop t ] <@literal ;
+
+: 'char' ( -- parser )
+    'any-char' 'escape' 'ordinary-char' <|> <|> [ satisfy ] <@ ;
+
+DEFER: 'regexp'
+
+TUPLE: group-result str ;
+
+C: <group-result> group-result
+
+: 'non-capturing-group' ( -- parser )
+    "?:" token 'regexp' &> ;
+
+: 'positive-lookahead-group' ( -- parser )
+    "?=" token 'regexp' &> [ ensure ] <@ ;
+
+: 'negative-lookahead-group' ( -- parser )
+    "?!" token 'regexp' &> [ ensure-not ] <@ ;
+
+: 'simple-group' ( -- parser )
+    'regexp' [ [ <group-result> ] <@ ] <@ ;
+
+: 'group' ( -- parser )
+    'non-capturing-group'
+    'positive-lookahead-group'
+    'negative-lookahead-group'
+    'simple-group' <|> <|> <|>
+    "(" ")" surrounded-by ;
+
+: 'range' ( -- parser )
+    [ CHAR: ] = not ] satisfy "-" token <&
+    [ CHAR: ] = not ] satisfy <&>
+    [ first2 char-between?-quot ] <@ ;
+
+: 'character-class-term' ( -- parser )
+    'range'
+    'escape' <|>
+    [ "\\]" member? not ] satisfy [ char=-quot ] <@ <|> ;
+
+: 'positive-character-class' ( -- parser )
+    "]" token [ CHAR: ] = ] <@literal 'character-class-term' <*> <&:>
+    'character-class-term' <+> <|>
+    [ [ 1|| ] curry ] <@ ;
+
+: 'negative-character-class' ( -- parser )
+    "^" token 'positive-character-class' &>
+    [ [ not ] append ] <@ ;
+
+: 'character-class' ( -- parser )
+    'negative-character-class' 'positive-character-class' <|>
+    "[" "]" surrounded-by [ satisfy ] <@ ;
+
+: 'escaped-seq' ( -- parser )
+    any-char-parser <*>
+    [ ignore-case? get <token-parser> ] <@
+    "\\Q" "\\E" surrounded-by ;
+
+: 'break' ( quot -- parser )
+    satisfy ensure epsilon just <|> ;
+
+: 'break-escape' ( -- parser )
+    "$" token [ "\r\n" member? ] 'break' <@literal
+    "\\b" token [ blank? ] 'break' <@literal <|>
+    "\\B" token [ blank? not ] 'break' <@literal <|>
+    "\\z" token epsilon just <@literal <|> ;
+
+: 'simple' ( -- parser )
+    'escaped-seq'
+    'break-escape' <|>
+    'group' <|>
+    'character-class' <|>
+    'char' <|> ;
+
+: 'exactly-n' ( -- parser )
+    'integer' [ exactly-n ] <@delay ;
+
+: 'at-least-n' ( -- parser )
+    'integer' "," token <& [ at-least-n ] <@delay ;
+
+: 'at-most-n' ( -- parser )
+    "," token 'integer' &> [ at-most-n ] <@delay ;
+
+: 'from-m-to-n' ( -- parser )
+    'integer' "," token <& 'integer' <&> [ first2 from-m-to-n ] <@delay ;
+
+: 'greedy-interval' ( -- parser )
+    'exactly-n' 'at-least-n' <|> 'at-most-n' <|> 'from-m-to-n' <|> ;
+
+: 'interval' ( -- parser )
+    'greedy-interval'
+    'greedy-interval' "?" token <& [ "reluctant {}" print ] <@ <|>
+    'greedy-interval' "+" token <& [ "possessive {}" print ] <@ <|>
+    "{" "}" surrounded-by ;
+
+: 'repetition' ( -- parser )
+    ! Posessive
+    "*+" token [ <!*> ] <@literal
+    "++" token [ <!+> ] <@literal <|>
+    "?+" token [ <!?> ] <@literal <|>
+    ! Reluctant
+    "*?" token [ <(*)> ] <@literal <|>
+    "+?" token [ <(+)> ] <@literal <|>
+    "??" token [ <(?)> ] <@literal <|>
+    ! Greedy
+    "*" token [ <*> ] <@literal <|>
+    "+" token [ <+> ] <@literal <|>
+    "?" token [ <?> ] <@literal <|> ;
+
+: 'dummy' ( -- parser )
+    epsilon [ ] <@literal ;
+
+MEMO: 'term' ( -- parser )
+    'simple'
+    'repetition' 'interval' 'dummy' <|> <|> <&> [ first2 call ] <@
+    <!+> [ <and-parser> ] <@ ;
+
+LAZY: 'regexp' ( -- parser )
+    'term' "|" token nonempty-list-of [ <or-parser> ] <@ ;
+!    "^" token 'term' "|" token nonempty-list-of [ <or-parser> ] <@
+!        &> [ "caret" print ] <@ <|>
+!    'term' "|" token nonempty-list-of [ <or-parser> ] <@
+!        "$" token <& [ "dollar" print ] <@ <|>
+!    "^" token 'term' "|" token nonempty-list-of [ <or-parser> ] <@ &>
+!        "$" token [ "caret dollar" print ] <@ <& <|> ;
+
+TUPLE: regexp source parser ignore-case? ;
+
+: <regexp> ( string ignore-case? -- regexp )
+    [
+        ignore-case? [
+            dup 'regexp' just parse-1
+        ] with-variable
+    ] keep regexp boa ;
+
+: do-ignore-case ( string regexp -- string regexp )
+    dup ignore-case?>> [ >r >upper r> ] when ;
+
+: matches? ( string regexp -- ? )
+    do-ignore-case parser>> just parse nil? not ;
+
+: match-head ( string regexp -- end )
+    do-ignore-case parser>> parse dup nil?
+    [ drop f ] [ car unparsed>> from>> ] if ;
+
+! Literal syntax for regexps
+: parse-options ( string -- ? )
+    #! Lame
+    {
+        { "" [ f ] }
+        { "i" [ t ] }
+    } case ;
+
+: parse-regexp ( accum end -- accum )
+    lexer get dup skip-blank
+    [ [ index-from dup 1+ swap ] 2keep swapd subseq swap ] change-lexer-column
+    lexer get dup still-parsing-line?
+    [ (parse-token) parse-options ] [ drop f ] if
+    <regexp> parsed ;
+
+: R! CHAR: ! parse-regexp ; parsing
+: R" CHAR: " parse-regexp ; parsing
+: R# CHAR: # parse-regexp ; parsing
+: R' CHAR: ' parse-regexp ; parsing
+: R( CHAR: ) parse-regexp ; parsing
+: R/ CHAR: / parse-regexp ; parsing
+: R@ CHAR: @ parse-regexp ; parsing
+: R[ CHAR: ] parse-regexp ; parsing
+: R` CHAR: ` parse-regexp ; parsing
+: R{ CHAR: } parse-regexp ; parsing
+: R| CHAR: | parse-regexp ; parsing
+
+: find-regexp-syntax ( string -- prefix suffix )
+    {
+        { "R/ "  "/"  }
+        { "R! "  "!"  }
+        { "R\" " "\"" }
+        { "R# "  "#"  }
+        { "R' "  "'"  }
+        { "R( "  ")"  }
+        { "R@ "  "@"  }
+        { "R[ "  "]"  }
+        { "R` "  "`"  }
+        { "R{ "  "}"  }
+        { "R| "  "|"  }
+    } swap [ subseq? not nip ] curry assoc-find drop ;
+
+M: regexp pprint*
+    [
+        dup source>>
+        dup find-regexp-syntax swap % swap % %
+        dup ignore-case?>> [ "i" % ] when
+    ] "" make
+    swap present-text ;
diff --git a/extra/parser-combinators/regexp/summary.txt b/extra/parser-combinators/regexp/summary.txt
new file mode 100644 (file)
index 0000000..aa1e1c2
--- /dev/null
@@ -0,0 +1 @@
+Regular expressions
diff --git a/extra/parser-combinators/regexp/tags.txt b/extra/parser-combinators/regexp/tags.txt
new file mode 100755 (executable)
index 0000000..65bc471
--- /dev/null
@@ -0,0 +1,2 @@
+parsing
+text
index 769dc41f786ac0403c2e5f08a46342a6c1171ef5..a2c50952be18acb3c0c69015ebdc97431e00303a 100644 (file)
@@ -40,8 +40,7 @@ function foldl(f, initial, seq) {
    for(var i=0; i< seq.length; ++i)
      initial = f(initial, seq[i]);
    return initial;
-}
-"> main \ javascript rule (parse) remaining>> length zero?
+}"> main \ javascript rule (parse) remaining>> length zero?
 ] unit-test
 
 { t } [ 
@@ -51,7 +50,6 @@ ParseState.prototype.from = function(index) {
     r.cache = this.cache;
     r.length = this.length - index;
     return r;
-}
-"> main \ javascript rule (parse) remaining>> length zero?
+}"> main \ javascript rule (parse) remaining>> length zero?
 ] unit-test
 
index e84d37e5d4c699dd7f3641101eb8e3b55393cf08..873a4b760e438753febc5eb256353ac1e2fb792c 100644 (file)
@@ -57,8 +57,7 @@ BEGIN
       CALL square;
       x := x + 1;
    END
-END.
-"> main \ pl0 rule (parse) remaining>> empty?
+END."> main \ pl0 rule (parse) remaining>> empty?
 ] unit-test
 
 { f } [
diff --git a/extra/printf/authors.txt b/extra/printf/authors.txt
new file mode 100644 (file)
index 0000000..e091bb8
--- /dev/null
@@ -0,0 +1 @@
+John Benediktsson
diff --git a/extra/printf/printf-docs.factor b/extra/printf/printf-docs.factor
new file mode 100644 (file)
index 0000000..b28b5e1
--- /dev/null
@@ -0,0 +1,80 @@
+
+USING: help.syntax help.markup kernel prettyprint sequences strings ;
+
+IN: printf
+
+HELP: printf
+{ $values { "format-string" string } }
+{ $description "Writes the arguments (specified on the stack) formatted according to the format string." } 
+{ $examples 
+    { $example
+        "USING: printf ;"
+        "123 \"%05d\" printf"
+        "00123" }
+    { $example
+        "USING: printf ;"
+        "HEX: ff \"%04X\" printf"
+        "00FF" }
+    { $example
+        "USING: printf ;"
+        "1.23456789 \"%.3f\" printf"
+        "1.234" }
+    { $example 
+        "USING: printf ;"
+        "1234567890 \"%.5e\" printf"
+        "1.23456e+09" }
+    { $example
+        "USING: printf ;"
+        "12 \"%'#4d\" printf"
+        "##12" }
+    { $example
+        "USING: printf ;"
+        "1234 \"%+d\" printf"
+        "+1234" }
+} ;
+
+HELP: sprintf
+{ $values { "format-string" string } { "result" string } }
+{ $description "Returns the arguments (specified on the stack) formatted according to the format string as a result string." } 
+{ $see-also printf } ;
+
+ARTICLE: "printf" "Formatted printing"
+"The " { $vocab-link "printf" } " vocabulary is used for formatted printing.\n"
+{ $subsection printf }
+{ $subsection sprintf }
+"\n"
+"Several format specifications exist for handling arguments of different types, and specifying attributes for the result string, including such things as maximum width, padding, and decimals.\n"
+{ $table
+    { "%%"    "Single %" "" }
+    { "%P.Ds" "String format" "string" }
+    { "%P.DS" "String format uppercase" "string" }
+    { "%c"    "Character format" "char" } 
+    { "%C"    "Character format uppercase" "char" } 
+    { "%+Pd"   "Integer format"  "fixnum" }
+    { "%+P.De" "Scientific notation" "fixnum, float" }
+    { "%+P.DE" "Scientific notation" "fixnum, float" }
+    { "%+P.Df" "Fixed format" "fixnum, float" }
+    { "%+Px"   "Hexadecimal" "hex" }
+    { "%+PX"   "Hexadecimal uppercase" "hex" }
+}
+"\n"
+"A plus sign ('+') is used to optionally specify that the number should be formatted with a '+' preceeding it if positive.\n"
+"\n"
+"Padding ('P') is used to optionally specify the minimum width of the result string, the padding character, and the alignment.  By default, the padding character defaults to a space and the alignment defaults to right-aligned. For example:\n"
+{ $list
+    "\"%5s\" formats a string padding with spaces up to 5 characters wide."
+    "\"%08d\" formats an integer padding with zeros up to 3 characters wide."
+    "\"%'#5f\" formats a float padding with '#' up to 3 characters wide."
+    "\"%-10d\" formats an integer to 10 characters wide and left-aligns." 
+}
+"\n"
+"Digits ('D') is used to optionally specify the maximum digits in the result string. For example:\n"
+{ $list 
+    "\"%.3s\" formats a string to truncate at 3 characters (from the left)."
+    "\"%.10f\" formats a float to pad-right with zeros up to 10 digits beyond the decimal point."
+    "\"%.5E\" formats a float into scientific notation with zeros up to 5 digits beyond the decimal point, but before the exponent."
+} ;
+
+ABOUT: "printf"
+
+
diff --git a/extra/printf/printf-tests.factor b/extra/printf/printf-tests.factor
new file mode 100644 (file)
index 0000000..5302048
--- /dev/null
@@ -0,0 +1,130 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: kernel printf tools.test ;
+
+[ "%s" printf ] must-infer 
+
+[ "%s" sprintf ] must-infer
+
+[ t ] [ "" "" sprintf = ] unit-test
+
+[ t ] [ "asdf" "asdf" sprintf = ] unit-test
+
+[ t ] [ "10" 10 "%d" sprintf = ] unit-test
+
+[ t ] [ "+10" 10 "%+d" sprintf = ] unit-test
+
+[ t ] [ "-10" -10 "%d" sprintf = ] unit-test
+
+[ t ] [ "  -10" -10 "%5d" sprintf = ] unit-test
+
+[ t ] [ "-0010" -10 "%05d" sprintf = ] unit-test
+
+[ t ] [ "+0010" 10 "%+05d" sprintf = ] unit-test
+
+[ t ] [ "123.456" 123.456 "%f" sprintf = ] unit-test
+
+[ t ] [ "123.10" 123.1 "%01.2f" sprintf = ] unit-test
+
+[ t ] [ "1.2345" 1.23456789 "%.4f" sprintf = ] unit-test
+
+[ t ] [ "  1.23" 1.23456789 "%6.2f" sprintf = ] unit-test
+
+[ t ] [ "1.234e+08" 123400000 "%e" sprintf = ] unit-test
+
+[ t ] [ "-1.234e+08" -123400000 "%e" sprintf = ] unit-test
+
+[ t ] [ "1.234567e+08" 123456700 "%e" sprintf = ] unit-test
+
+[ t ] [ "3.625e+08" 362525200 "%.3e" sprintf = ] unit-test
+
+[ t ] [ "2.5e-03" 0.0025 "%e" sprintf = ] unit-test
+
+[ t ] [ "2.5E-03" 0.0025 "%E" sprintf = ] unit-test
+
+[ t ] [ "   1.0E+01" 10 "%10.1E" sprintf = ] unit-test
+
+[ t ] [ "  -1.0E+01" -10 "%10.1E" sprintf = ] unit-test
+
+[ t ] [ "  -1.0E+01" -10 "%+10.1E" sprintf = ] unit-test
+
+[ t ] [ "  +1.0E+01" 10 "%+10.1E" sprintf = ] unit-test
+
+[ t ] [ "-001.0E+01" -10 "%+010.1E" sprintf = ] unit-test
+
+[ t ] [ "+001.0E+01" 10 "%+010.1E" sprintf = ] unit-test
+
+[ t ] [ "ff" HEX: ff "%x" sprintf = ] unit-test
+
+[ t ] [ "FF" HEX: ff "%X" sprintf = ] unit-test
+
+[ t ] [ "0f" HEX: f "%02x" sprintf = ] unit-test
+
+[ t ] [ "0F" HEX: f "%02X" sprintf = ] unit-test
+
+[ t ] [ "2008-09-10" 
+        2008 9 10 "%04d-%02d-%02d" sprintf = ] unit-test
+
+[ t ] [ "Hello, World!" 
+        "Hello, World!" "%s" sprintf = ] unit-test
+
+[ t ] [ "printf test" 
+        "printf test" sprintf = ] unit-test
+
+[ t ] [ "char a = 'a'"
+        CHAR: a "char %c = 'a'" sprintf = ] unit-test
+
+[ t ] [ "00" HEX: 0 "%02x" sprintf = ] unit-test
+
+[ t ] [ "ff" HEX: ff "%02x" sprintf = ] unit-test
+
+[ t ] [ "0 message(s)"
+        0 "message" "%d %s(s)" sprintf = ] unit-test
+
+[ t ] [ "0 message(s) with %"
+        0 "message" "%d %s(s) with %%" sprintf = ] unit-test
+
+[ t ] [ "justif: \"left      \""
+        "left" "justif: \"%-10s\"" sprintf = ] unit-test
+
+[ t ] [ "justif: \"     right\""
+        "right" "justif: \"%10s\"" sprintf = ] unit-test
+
+[ t ] [ " 3: 0003 zero padded" 
+        3 " 3: %04d zero padded" sprintf = ] unit-test
+
+[ t ] [ " 3: 3    left justif" 
+        3 " 3: %-4d left justif" sprintf = ] unit-test
+
+[ t ] [ " 3:    3 right justif" 
+        3 " 3: %4d right justif" sprintf = ] unit-test
+
+[ t ] [ " -3: -003 zero padded"
+        -3 " -3: %04d zero padded" sprintf = ] unit-test
+
+[ t ] [ " -3: -3   left justif"
+        -3 " -3: %-4d left justif" sprintf = ] unit-test
+
+[ t ] [ " -3:   -3 right justif"
+        -3 " -3: %4d right justif" sprintf = ] unit-test
+
+[ t ] [ "There are 10 monkeys in the kitchen" 
+        10 "kitchen" "There are %d monkeys in the %s" sprintf = ] unit-test
+
+[ f ] [ "%d" 10 "%d" sprintf = ] unit-test
+
+[ t ] [ "[monkey]" "monkey" "[%s]" sprintf = ] unit-test
+
+[ t ] [ "[    monkey]" "monkey" "[%10s]" sprintf = ] unit-test
+
+[ t ] [ "[monkey    ]" "monkey" "[%-10s]" sprintf = ] unit-test
+
+[ t ] [ "[0000monkey]" "monkey" "[%010s]" sprintf = ] unit-test
+
+[ t ] [ "[####monkey]" "monkey" "[%'#10s]" sprintf = ] unit-test
+
+[ t ] [ "[many monke]" "many monkeys" "[%10.10s]" sprintf = ] unit-test
+
+
+
diff --git a/extra/printf/printf.factor b/extra/printf/printf.factor
new file mode 100644 (file)
index 0000000..c7a7153
--- /dev/null
@@ -0,0 +1,104 @@
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: io io.encodings.ascii io.files io.streams.string combinators
+kernel sequences splitting strings math math.parser macros
+fry peg.ebnf ascii unicode.case arrays quotations vectors ;
+
+IN: printf
+
+<PRIVATE
+
+: compose-all ( seq -- quot )
+    [ ] [ compose ] reduce ;
+
+: fix-sign ( string -- string )
+    dup CHAR: 0 swap index 0 = 
+      [ dup 0 swap [ [ CHAR: 0 = not ] keep digit? and ] find-from
+         [ dup 1- rot dup [ nth ] dip swap
+            {
+               { CHAR: - [ [ 1- ] dip remove-nth "-" prepend ] }
+               { CHAR: + [ [ 1- ] dip remove-nth "+" prepend ] }
+               [ drop swap drop ] 
+            } case 
+         ] [ drop ] if
+      ] when ;
+
+: >digits ( string -- digits ) 
+    [ 0 ] [ string>number ] if-empty ;
+
+: max-digits ( string digits -- string ) 
+    [ "." split1 ] dip [ CHAR: 0 pad-right ] [ head-slice ] bi "." swap 3append ;
+
+: max-width ( string length -- string ) 
+    short head ;
+
+: >exponential ( n -- base exp ) 
+    [ 0 < ] keep abs 0 
+    [ swap dup [ 10.0 >= ] keep 1.0 < or ] 
+    [ dup 10.0 >= 
+      [ 10.0 / [ 1+ ] dip swap ] 
+      [ 10.0 * [ 1- ] dip swap ] if
+    ] [ swap ] while 
+    [ number>string ] dip 
+    dup abs number>string 2 CHAR: 0 pad-left
+    [ 0 < "-" "+" ? ] dip append
+    "e" prepend 
+    rot [ [ "-" prepend ] dip ] when ; 
+
+EBNF: parse-format-string
+
+zero      = "0"                  => [[ CHAR: 0 ]]
+char      = "'" (.)              => [[ second ]]
+
+pad-char  = (zero|char)?         => [[ CHAR: \s or 1quotation ]]
+pad-align = ("-")?               => [[ [ pad-right ] [ pad-left ] ? ]] 
+pad-width = ([0-9])*             => [[ >digits 1quotation ]]
+pad       = pad-align pad-char pad-width => [[ reverse compose-all [ first ] keep swap 0 = [ drop [ ] ] when ]]
+
+sign      = ("+")?               => [[ [ dup CHAR: - swap index not [ "+" prepend ] when ] [ ] ? ]]
+
+width_    = "." ([0-9])*         => [[ second >digits '[ _ max-width ] ]]
+width     = (width_)?            => [[ [ ] or ]] 
+
+digits_   = "." ([0-9])*         => [[ second >digits '[ _ max-digits ] ]]
+digits    = (digits_)?           => [[ [ ] or ]]
+
+fmt-%     = "%"                  => [[ [ "%" ] ]] 
+fmt-c     = "c"                  => [[ [ 1string ] ]]
+fmt-C     = "C"                  => [[ [ 1string >upper ] ]]
+fmt-s     = "s"                  => [[ [ ] ]]
+fmt-S     = "S"                  => [[ [ >upper ] ]]
+fmt-d     = "d"                  => [[ [ >fixnum number>string ] ]]
+fmt-e     = "e"                  => [[ [ >exponential ] ]]
+fmt-E     = "E"                  => [[ [ >exponential >upper ] ]]
+fmt-f     = "f"                  => [[ [ >float number>string ] ]] 
+fmt-x     = "x"                  => [[ [ >hex ] ]]
+fmt-X     = "X"                  => [[ [ >hex >upper ] ]]
+unknown   = (.)*                 => [[ "Unknown directive" throw ]]
+
+chars     = fmt-c | fmt-C
+strings   = pad width (fmt-s|fmt-S) => [[ reverse compose-all ]]
+decimals  = fmt-d
+exps      = digits (fmt-e|fmt-E) => [[ reverse [ swap ] join [ swap append ] append ]] 
+floats    = digits fmt-f         => [[ reverse compose-all ]]
+hex       = fmt-x | fmt-X
+numbers   = sign pad (decimals|floats|hex|exps) => [[ reverse first3 swap 3append [ fix-sign ] append ]]
+
+formats   = "%" (chars|strings|numbers|fmt-%|unknown) => [[ second '[ _ dip ] ]]
+
+plain-text = (!("%").)+           => [[ >string '[ _ swap ] ]]
+
+text      = (formats|plain-text)* => [[ reverse [ [ dup [ push ] dip ] append ] map ]]
+
+;EBNF
+
+PRIVATE>
+
+MACRO: printf ( format-string -- )
+    parse-format-string [ length ] keep compose-all '[ _ <vector> @ reverse [ write ] each ] ;
+
+: sprintf ( format-string -- result )
+    [ printf ] with-string-writer ; inline
+
+
diff --git a/extra/printf/summary.txt b/extra/printf/summary.txt
new file mode 100644 (file)
index 0000000..da1aa31
--- /dev/null
@@ -0,0 +1 @@
+Format data according to a specified format string, and writes (or returns) the result string.  
diff --git a/extra/regexp/authors.txt b/extra/regexp/authors.txt
deleted file mode 100755 (executable)
index 5674120..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Doug Coleman
-Slava Pestov
diff --git a/extra/regexp/regexp-tests.factor b/extra/regexp/regexp-tests.factor
deleted file mode 100755 (executable)
index e9433c6..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-USING: regexp tools.test kernel ;
-IN: regexp-tests
-
-[ f ] [ "b" "a*" f <regexp> matches? ] unit-test
-[ t ] [ "" "a*" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a*" f <regexp> matches? ] unit-test
-[ t ] [ "aaaaaaa" "a*" f <regexp> matches? ] unit-test
-[ f ] [ "ab" "a*" f <regexp> matches? ] unit-test
-
-[ t ] [ "abc" "abc" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a|b|c" f <regexp> matches? ] unit-test
-[ t ] [ "b" "a|b|c" f <regexp> matches? ] unit-test
-[ t ] [ "c" "a|b|c" f <regexp> matches? ] unit-test
-[ f ] [ "c" "d|e|f" f <regexp> matches? ] unit-test
-
-[ f ] [ "aa" "a|b|c" f <regexp> matches? ] unit-test
-[ f ] [ "bb" "a|b|c" f <regexp> matches? ] unit-test
-[ f ] [ "cc" "a|b|c" f <regexp> matches? ] unit-test
-[ f ] [ "cc" "d|e|f" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "a+" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a+" f <regexp> matches? ] unit-test
-[ t ] [ "aa" "a+" f <regexp> matches? ] unit-test
-
-[ t ] [ "" "a?" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a?" f <regexp> matches? ] unit-test
-[ f ] [ "aa" "a?" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "." f <regexp> matches? ] unit-test
-[ t ] [ "a" "." f <regexp> matches? ] unit-test
-[ t ] [ "." "." f <regexp> matches? ] unit-test
-! [ f ] [ "\n" "." f <regexp> matches? ] unit-test
-
-[ f ] [ "" ".+" f <regexp> matches? ] unit-test
-[ t ] [ "a" ".+" f <regexp> matches? ] unit-test
-[ t ] [ "ab" ".+" f <regexp> matches? ] unit-test
-
-[ t ] [ "" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-[ t ] [ "c" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-[ t ] [ "cc" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-[ f ] [ "ccd" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-[ t ] [ "d" "a|b*|c+|d?" f <regexp> matches? ] unit-test
-
-[ t ] [ "foo" "foo|bar" f <regexp> matches? ] unit-test
-[ t ] [ "bar" "foo|bar" f <regexp> matches? ] unit-test
-[ f ] [ "foobar" "foo|bar" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "(a)" f <regexp> matches? ] unit-test
-[ t ] [ "a" "(a)" f <regexp> matches? ] unit-test
-[ f ] [ "aa" "(a)" f <regexp> matches? ] unit-test
-[ t ] [ "aa" "(a*)" f <regexp> matches? ] unit-test
-
-[ f ] [ "aababaaabbac" "(a|b)+" f <regexp> matches? ] unit-test
-[ t ] [ "ababaaabba" "(a|b)+" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "a{1}" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a{1}" f <regexp> matches? ] unit-test
-[ f ] [ "aa" "a{1}" f <regexp> matches? ] unit-test
-
-[ f ] [ "a" "a{2,}" f <regexp> matches? ] unit-test
-[ t ] [ "aaa" "a{2,}" f <regexp> matches? ] unit-test
-[ t ] [ "aaaa" "a{2,}" f <regexp> matches? ] unit-test
-[ t ] [ "aaaaa" "a{2,}" f <regexp> matches? ] unit-test
-
-[ t ] [ "" "a{,2}" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a{,2}" f <regexp> matches? ] unit-test
-[ t ] [ "aa" "a{,2}" f <regexp> matches? ] unit-test
-[ f ] [ "aaa" "a{,2}" f <regexp> matches? ] unit-test
-[ f ] [ "aaaa" "a{,2}" f <regexp> matches? ] unit-test
-[ f ] [ "aaaaa" "a{,2}" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "a{1,3}" f <regexp> matches? ] unit-test
-[ t ] [ "a" "a{1,3}" f <regexp> matches? ] unit-test
-[ t ] [ "aa" "a{1,3}" f <regexp> matches? ] unit-test
-[ t ] [ "aaa" "a{1,3}" f <regexp> matches? ] unit-test
-[ f ] [ "aaaa" "a{1,3}" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "[a]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[a]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[abc]" f <regexp> matches? ] unit-test
-[ f ] [ "b" "[a]" f <regexp> matches? ] unit-test
-[ f ] [ "d" "[abc]" f <regexp> matches? ] unit-test
-[ t ] [ "ab" "[abc]{1,2}" f <regexp> matches? ] unit-test
-[ f ] [ "abc" "[abc]{1,2}" f <regexp> matches? ] unit-test
-
-[ f ] [ "" "[^a]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[^a]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[^abc]" f <regexp> matches? ] unit-test
-[ t ] [ "b" "[^a]" f <regexp> matches? ] unit-test
-[ t ] [ "d" "[^abc]" f <regexp> matches? ] unit-test
-[ f ] [ "ab" "[^abc]{1,2}" f <regexp> matches? ] unit-test
-[ f ] [ "abc" "[^abc]{1,2}" f <regexp> matches? ] unit-test
-
-[ t ] [ "]" "[]]" f <regexp> matches? ] unit-test
-[ f ] [ "]" "[^]]" f <regexp> matches? ] unit-test
-
-! [ "^" "[^]" f <regexp> matches? ] must-fail
-[ t ] [ "^" "[]^]" f <regexp> matches? ] unit-test
-[ t ] [ "]" "[]^]" f <regexp> matches? ] unit-test
-
-[ t ] [ "[" "[[]" f <regexp> matches? ] unit-test
-[ f ] [ "^" "[^^]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[^^]" f <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[-]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[-]" f <regexp> matches? ] unit-test
-[ f ] [ "-" "[^-]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[^-]" f <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[-a]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[-a]" f <regexp> matches? ] unit-test
-[ t ] [ "-" "[a-]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-]" f <regexp> matches? ] unit-test
-[ f ] [ "b" "[a-]" f <regexp> matches? ] unit-test
-[ f ] [ "-" "[^-]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[^-]" f <regexp> matches? ] unit-test
-
-[ f ] [ "-" "[a-c]" f <regexp> matches? ] unit-test
-[ t ] [ "-" "[^a-c]" f <regexp> matches? ] unit-test
-[ t ] [ "b" "[a-c]" f <regexp> matches? ] unit-test
-[ f ] [ "b" "[^a-c]" f <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[a-c-]" f <regexp> matches? ] unit-test
-[ f ] [ "-" "[^a-c-]" f <regexp> matches? ] unit-test
-
-[ t ] [ "\\" "[\\\\]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[\\\\]" f <regexp> matches? ] unit-test
-[ f ] [ "\\" "[^\\\\]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[^\\\\]" f <regexp> matches? ] unit-test
-
-[ t ] [ "0" "[\\d]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[\\d]" f <regexp> matches? ] unit-test
-[ f ] [ "0" "[^\\d]" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[^\\d]" f <regexp> matches? ] unit-test
-
-[ t ] [ "a" "[a-z]{1,}|[A-Z]{2,4}|b*|c|(f|g)*" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}|b*|c|(f|g)*" f <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}" f <regexp> matches? ] unit-test
-
-[ t ] [ "1000" "\\d{4,6}" f <regexp> matches? ] unit-test
-[ t ] [ "1000" "[0-9]{4,6}" f <regexp> matches? ] unit-test
-
-[ t ] [ "abc" "\\p{Lower}{3}" f <regexp> matches? ] unit-test
-[ f ] [ "ABC" "\\p{Lower}{3}" f <regexp> matches? ] unit-test
-[ t ] [ "ABC" "\\p{Upper}{3}" f <regexp> matches? ] unit-test
-[ f ] [ "abc" "\\p{Upper}{3}" f <regexp> matches? ] unit-test
-
-[ f ] [ "abc" "[\\p{Upper}]{3}" f <regexp> matches? ] unit-test
-[ t ] [ "ABC" "[\\p{Upper}]{3}" f <regexp> matches? ] unit-test
-
-[ t ] [ "" "\\Q\\E" f <regexp> matches? ] unit-test
-[ f ] [ "a" "\\Q\\E" f <regexp> matches? ] unit-test
-[ t ] [ "|*+" "\\Q|*+\\E" f <regexp> matches? ] unit-test
-[ f ] [ "abc" "\\Q|*+\\E" f <regexp> matches? ] unit-test
-
-[ t ] [ "S" "\\0123" f <regexp> matches? ] unit-test
-[ t ] [ "SXY" "\\0123XY" f <regexp> matches? ] unit-test
-[ t ] [ "x" "\\x78" f <regexp> matches? ] unit-test
-[ f ] [ "y" "\\x78" f <regexp> matches? ] unit-test
-[ t ] [ "x" "\\u000078" f <regexp> matches? ] unit-test
-[ f ] [ "y" "\\u000078" f <regexp> matches? ] unit-test
-
-[ t ] [ "ab" "a+b" f <regexp> matches? ] unit-test
-[ f ] [ "b" "a+b" f <regexp> matches? ] unit-test
-[ t ] [ "aab" "a+b" f <regexp> matches? ] unit-test
-[ f ] [ "abb" "a+b" f <regexp> matches? ] unit-test
-
-[ t ] [ "abbbb" "ab*" f <regexp> matches? ] unit-test
-[ t ] [ "a" "ab*" f <regexp> matches? ] unit-test
-[ f ] [ "abab" "ab*" f <regexp> matches? ] unit-test
-
-[ f ] [ "x" "\\." f <regexp> matches? ] unit-test
-[ t ] [ "." "\\." f <regexp> matches? ] unit-test
-
-[ t ] [ "aaaab" "a+ab" f <regexp> matches? ] unit-test
-[ f ] [ "aaaxb" "a+ab" f <regexp> matches? ] unit-test
-[ t ] [ "aaacb" "a+cb" f <regexp> matches? ] unit-test
-[ f ] [ "aaaab" "a++ab" f <regexp> matches? ] unit-test
-[ t ] [ "aaacb" "a++cb" f <regexp> matches? ] unit-test
-
-[ 3 ] [ "aaacb" "a*" f <regexp> match-head ] unit-test
-[ 1 ] [ "aaacb" "a+?" f <regexp> match-head ] unit-test
-[ 2 ] [ "aaacb" "aa?" f <regexp> match-head ] unit-test
-[ 1 ] [ "aaacb" "aa??" f <regexp> match-head ] unit-test
-[ 3 ] [ "aacb" "aa?c" f <regexp> match-head ] unit-test
-[ 3 ] [ "aacb" "aa??c" f <regexp> match-head ] unit-test
-
-[ t ] [ "aaa" "AAA" t <regexp> matches? ] unit-test
-[ f ] [ "aax" "AAA" t <regexp> matches? ] unit-test
-[ t ] [ "aaa" "A*" t <regexp> matches? ] unit-test
-[ f ] [ "aaba" "A*" t <regexp> matches? ] unit-test
-[ t ] [ "b" "[AB]" t <regexp> matches? ] unit-test
-[ f ] [ "c" "[AB]" t <regexp> matches? ] unit-test
-[ t ] [ "c" "[A-Z]" t <regexp> matches? ] unit-test
-[ f ] [ "3" "[A-Z]" t <regexp> matches? ] unit-test
-
-[ ] [ 
-    "(0[lL]?|[1-9]\\d{0,9}(\\d{0,9}[lL])?|0[xX]\\p{XDigit}{1,8}(\\p{XDigit}{0,8}[lL])?|0[0-7]{1,11}([0-7]{0,11}[lL])?|([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][+-]?[0-9]+)?[fFdD]?|[0-9]+([eE][+-]?[0-9]+[fFdD]?|([eE][+-]?[0-9]+)?[fFdD]))"
-    f <regexp> drop
-] unit-test
-
-[ t ] [ "fxxbar" "(?!foo).{3}bar" f <regexp> matches? ] unit-test
-[ f ] [ "foobar" "(?!foo).{3}bar" f <regexp> matches? ] unit-test
-
-[ 3 ] [ "foobar" "foo(?=bar)" f <regexp> match-head ] unit-test
-[ f ] [ "foobxr" "foo(?=bar)" f <regexp> match-head ] unit-test
-
-[ f ] [ "foobxr" "foo\\z" f <regexp> match-head ] unit-test
-[ 3 ] [ "foo" "foo\\z" f <regexp> match-head ] unit-test
-
-[ 3 ] [ "foo bar" "foo\\b" f <regexp> match-head ] unit-test
-[ f ] [ "fooxbar" "foo\\b" f <regexp> matches? ] unit-test
-[ t ] [ "foo" "foo\\b" f <regexp> matches? ] unit-test
-[ t ] [ "foo bar" "foo\\b bar" f <regexp> matches? ] unit-test
-[ f ] [ "fooxbar" "foo\\bxbar" f <regexp> matches? ] unit-test
-[ f ] [ "foo" "foo\\bbar" f <regexp> matches? ] unit-test
-
-[ f ] [ "foo bar" "foo\\B" f <regexp> matches? ] unit-test
-[ 3 ] [ "fooxbar" "foo\\B" f <regexp> match-head ] unit-test
-[ t ] [ "foo" "foo\\B" f <regexp> matches? ] unit-test
-[ f ] [ "foo bar" "foo\\B bar" f <regexp> matches? ] unit-test
-[ t ] [ "fooxbar" "foo\\Bxbar" f <regexp> matches? ] unit-test
-[ f ] [ "foo" "foo\\Bbar" f <regexp> matches? ] unit-test
-
-[ t ] [ "s@f" "[a-z.-]@[a-z]" f <regexp> matches? ] unit-test
-[ f ] [ "a" "[a-z.-]@[a-z]" f <regexp> matches? ] unit-test
-[ t ] [ ".o" "\\.[a-z]" f <regexp> matches? ] unit-test
-
-! Bug in parsing word
-[ t ] [
-    "a"
-    R' a'
-    matches?
-] unit-test
diff --git a/extra/regexp/regexp.factor b/extra/regexp/regexp.factor
deleted file mode 100755 (executable)
index 5ef3eac..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-USING: arrays combinators kernel lists math math.parser
-namespaces parser lexer parser-combinators parser-combinators.simple
-promises quotations sequences combinators.lib strings math.order
-assocs prettyprint.backend memoize unicode.case unicode.categories
-combinators.short-circuit accessors make io ;
-IN: regexp
-
-<PRIVATE
-
-SYMBOL: ignore-case?
-
-: char=-quot ( ch -- quot )
-    ignore-case? get
-    [ ch>upper [ swap ch>upper = ] ] [ [ = ] ] if
-    curry ;
-
-: char-between?-quot ( ch1 ch2 -- quot )
-    ignore-case? get
-    [ [ ch>upper ] bi@ [ >r >r ch>upper r> r> between? ] ]
-    [ [ between? ] ]
-    if 2curry ;
-
-: <@literal ( parser obj -- action ) [ nip ] curry <@ ;
-
-: <@delay ( parser quot -- action ) [ curry ] curry <@ ;
-
-PRIVATE>
-
-: ascii? ( n -- ? ) 
-    0 HEX: 7f between? ;
-
-: octal-digit? ( n -- ? )
-    CHAR: 0 CHAR: 7 between? ;
-
-: decimal-digit? ( n -- ? )
-    CHAR: 0 CHAR: 9 between? ;
-
-: hex-digit? ( n -- ? )
-    dup decimal-digit?
-    over CHAR: a CHAR: f between? or
-    swap CHAR: A CHAR: F between? or ;
-
-: control-char? ( n -- ? )
-    dup 0 HEX: 1f between?
-    swap HEX: 7f = or ;
-
-: punct? ( n -- ? )
-    "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" member? ;
-
-: c-identifier-char? ( ch -- ? )
-    dup alpha? swap CHAR: _ = or ;
-
-: java-blank? ( n -- ? )
-    {
-        CHAR: \s
-        CHAR: \t CHAR: \n CHAR: \r
-        HEX: c HEX: 7 HEX: 1b
-    } member? ;
-
-: java-printable? ( n -- ? )
-    dup alpha? swap punct? or ;
-
-: 'ordinary-char' ( -- parser )
-    [ "\\^*+?|(){}[$" member? not ] satisfy
-    [ char=-quot ] <@ ;
-
-: 'octal-digit' ( -- parser ) [ octal-digit? ] satisfy ;
-
-: 'octal' ( -- parser )
-    "0" token 'octal-digit' 1 3 from-m-to-n &>
-    [ oct> ] <@ ;
-
-: 'hex-digit' ( -- parser ) [ hex-digit? ] satisfy ;
-
-: 'hex' ( -- parser )
-    "x" token 'hex-digit' 2 exactly-n &>
-    "u" token 'hex-digit' 6 exactly-n &> <|>
-    [ hex> ] <@ ;
-
-: satisfy-tokens ( assoc -- parser )
-    [ >r token r> <@literal ] { } assoc>map <or-parser> ;
-
-: 'simple-escape-char' ( -- parser )
-    {
-        { "\\" CHAR: \\ }
-        { "t"  CHAR: \t }
-        { "n"  CHAR: \n }
-        { "r"  CHAR: \r }
-        { "f"  HEX: c   }
-        { "a"  HEX: 7   }
-        { "e"  HEX: 1b  }
-    } [ char=-quot ] assoc-map satisfy-tokens ;
-
-: 'predefined-char-class' ( -- parser )
-    {
-        { "d" [ digit? ] }
-        { "D" [ digit? not ] }
-        { "s" [ java-blank? ] }
-        { "S" [ java-blank? not ] }
-        { "w" [ c-identifier-char? ] }
-        { "W" [ c-identifier-char? not ] }
-    } satisfy-tokens ;
-
-: 'posix-character-class' ( -- parser )
-    {
-        { "Lower" [ letter? ] }
-        { "Upper" [ LETTER? ] }
-        { "ASCII" [ ascii? ] }
-        { "Alpha" [ Letter? ] }
-        { "Digit" [ digit? ] }
-        { "Alnum" [ alpha? ] }
-        { "Punct" [ punct? ] }
-        { "Graph" [ java-printable? ] }
-        { "Print" [ java-printable? ] }
-        { "Blank" [ " \t" member? ] }
-        { "Cntrl" [ control-char? ] }
-        { "XDigit" [ hex-digit? ] }
-        { "Space" [ java-blank? ] }
-    } satisfy-tokens "p{" "}" surrounded-by ;
-
-: 'simple-escape' ( -- parser )
-    'octal'
-    'hex' <|>
-    "c" token [ LETTER? ] satisfy &> <|>
-    any-char-parser <|>
-    [ char=-quot ] <@ ;
-
-: 'escape' ( -- parser )
-    "\\" token
-    'simple-escape-char'
-    'predefined-char-class' <|>
-    'posix-character-class' <|>
-    'simple-escape' <|> &> ;
-
-: 'any-char' ( -- parser )
-    "." token [ drop t ] <@literal ;
-
-: 'char' ( -- parser )
-    'any-char' 'escape' 'ordinary-char' <|> <|> [ satisfy ] <@ ;
-
-DEFER: 'regexp'
-
-TUPLE: group-result str ;
-
-C: <group-result> group-result
-
-: 'non-capturing-group' ( -- parser )
-    "?:" token 'regexp' &> ;
-
-: 'positive-lookahead-group' ( -- parser )
-    "?=" token 'regexp' &> [ ensure ] <@ ;
-
-: 'negative-lookahead-group' ( -- parser )
-    "?!" token 'regexp' &> [ ensure-not ] <@ ;
-
-: 'simple-group' ( -- parser )
-    'regexp' [ [ <group-result> ] <@ ] <@ ;
-
-: 'group' ( -- parser )
-    'non-capturing-group'
-    'positive-lookahead-group'
-    'negative-lookahead-group'
-    'simple-group' <|> <|> <|>
-    "(" ")" surrounded-by ;
-
-: 'range' ( -- parser )
-    [ CHAR: ] = not ] satisfy "-" token <&
-    [ CHAR: ] = not ] satisfy <&>
-    [ first2 char-between?-quot ] <@ ;
-
-: 'character-class-term' ( -- parser )
-    'range'
-    'escape' <|>
-    [ "\\]" member? not ] satisfy [ char=-quot ] <@ <|> ;
-
-: 'positive-character-class' ( -- parser )
-    "]" token [ CHAR: ] = ] <@literal 'character-class-term' <*> <&:>
-    'character-class-term' <+> <|>
-    [ [ 1|| ] curry ] <@ ;
-
-: 'negative-character-class' ( -- parser )
-    "^" token 'positive-character-class' &>
-    [ [ not ] append ] <@ ;
-
-: 'character-class' ( -- parser )
-    'negative-character-class' 'positive-character-class' <|>
-    "[" "]" surrounded-by [ satisfy ] <@ ;
-
-: 'escaped-seq' ( -- parser )
-    any-char-parser <*>
-    [ ignore-case? get <token-parser> ] <@
-    "\\Q" "\\E" surrounded-by ;
-
-: 'break' ( quot -- parser )
-    satisfy ensure epsilon just <|> ;
-
-: 'break-escape' ( -- parser )
-    "$" token [ "\r\n" member? ] 'break' <@literal
-    "\\b" token [ blank? ] 'break' <@literal <|>
-    "\\B" token [ blank? not ] 'break' <@literal <|>
-    "\\z" token epsilon just <@literal <|> ;
-
-: 'simple' ( -- parser )
-    'escaped-seq'
-    'break-escape' <|>
-    'group' <|>
-    'character-class' <|>
-    'char' <|> ;
-
-: 'exactly-n' ( -- parser )
-    'integer' [ exactly-n ] <@delay ;
-
-: 'at-least-n' ( -- parser )
-    'integer' "," token <& [ at-least-n ] <@delay ;
-
-: 'at-most-n' ( -- parser )
-    "," token 'integer' &> [ at-most-n ] <@delay ;
-
-: 'from-m-to-n' ( -- parser )
-    'integer' "," token <& 'integer' <&> [ first2 from-m-to-n ] <@delay ;
-
-: 'greedy-interval' ( -- parser )
-    'exactly-n' 'at-least-n' <|> 'at-most-n' <|> 'from-m-to-n' <|> ;
-
-: 'interval' ( -- parser )
-    'greedy-interval'
-    'greedy-interval' "?" token <& [ "reluctant {}" print ] <@ <|>
-    'greedy-interval' "+" token <& [ "possessive {}" print ] <@ <|>
-    "{" "}" surrounded-by ;
-
-: 'repetition' ( -- parser )
-    ! Posessive
-    "*+" token [ <!*> ] <@literal
-    "++" token [ <!+> ] <@literal <|>
-    "?+" token [ <!?> ] <@literal <|>
-    ! Reluctant
-    "*?" token [ <(*)> ] <@literal <|>
-    "+?" token [ <(+)> ] <@literal <|>
-    "??" token [ <(?)> ] <@literal <|>
-    ! Greedy
-    "*" token [ <*> ] <@literal <|>
-    "+" token [ <+> ] <@literal <|>
-    "?" token [ <?> ] <@literal <|> ;
-
-: 'dummy' ( -- parser )
-    epsilon [ ] <@literal ;
-
-MEMO: 'term' ( -- parser )
-    'simple'
-    'repetition' 'interval' 'dummy' <|> <|> <&> [ first2 call ] <@
-    <!+> [ <and-parser> ] <@ ;
-
-LAZY: 'regexp' ( -- parser )
-    'term' "|" token nonempty-list-of [ <or-parser> ] <@ ;
-!    "^" token 'term' "|" token nonempty-list-of [ <or-parser> ] <@
-!        &> [ "caret" print ] <@ <|>
-!    'term' "|" token nonempty-list-of [ <or-parser> ] <@
-!        "$" token <& [ "dollar" print ] <@ <|>
-!    "^" token 'term' "|" token nonempty-list-of [ <or-parser> ] <@ &>
-!        "$" token [ "caret dollar" print ] <@ <& <|> ;
-
-TUPLE: regexp source parser ignore-case? ;
-
-: <regexp> ( string ignore-case? -- regexp )
-    [
-        ignore-case? [
-            dup 'regexp' just parse-1
-        ] with-variable
-    ] keep regexp boa ;
-
-: do-ignore-case ( string regexp -- string regexp )
-    dup ignore-case?>> [ >r >upper r> ] when ;
-
-: matches? ( string regexp -- ? )
-    do-ignore-case parser>> just parse nil? not ;
-
-: match-head ( string regexp -- end )
-    do-ignore-case parser>> parse dup nil?
-    [ drop f ] [ car unparsed>> from>> ] if ;
-
-! Literal syntax for regexps
-: parse-options ( string -- ? )
-    #! Lame
-    {
-        { "" [ f ] }
-        { "i" [ t ] }
-    } case ;
-
-: parse-regexp ( accum end -- accum )
-    lexer get dup skip-blank
-    [ [ index-from dup 1+ swap ] 2keep swapd subseq swap ] change-lexer-column
-    lexer get dup still-parsing-line?
-    [ (parse-token) parse-options ] [ drop f ] if
-    <regexp> parsed ;
-
-: R! CHAR: ! parse-regexp ; parsing
-: R" CHAR: " parse-regexp ; parsing
-: R# CHAR: # parse-regexp ; parsing
-: R' CHAR: ' parse-regexp ; parsing
-: R( CHAR: ) parse-regexp ; parsing
-: R/ CHAR: / parse-regexp ; parsing
-: R@ CHAR: @ parse-regexp ; parsing
-: R[ CHAR: ] parse-regexp ; parsing
-: R` CHAR: ` parse-regexp ; parsing
-: R{ CHAR: } parse-regexp ; parsing
-: R| CHAR: | parse-regexp ; parsing
-
-: find-regexp-syntax ( string -- prefix suffix )
-    {
-        { "R/ "  "/"  }
-        { "R! "  "!"  }
-        { "R\" " "\"" }
-        { "R# "  "#"  }
-        { "R' "  "'"  }
-        { "R( "  ")"  }
-        { "R@ "  "@"  }
-        { "R[ "  "]"  }
-        { "R` "  "`"  }
-        { "R{ "  "}"  }
-        { "R| "  "|"  }
-    } swap [ subseq? not nip ] curry assoc-find drop ;
-
-M: regexp pprint*
-    [
-        dup source>>
-        dup find-regexp-syntax swap % swap % %
-        dup ignore-case?>> [ "i" % ] when
-    ] "" make
-    swap present-text ;
diff --git a/extra/regexp/summary.txt b/extra/regexp/summary.txt
deleted file mode 100644 (file)
index aa1e1c2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Regular expressions
diff --git a/extra/regexp/tags.txt b/extra/regexp/tags.txt
deleted file mode 100755 (executable)
index 65bc471..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-parsing
-text
index 9975da00db05628c123072f7cd562aade7f9b3ec..e279230b1bcfa56f23c309fff4e9a5790bc3db32 100755 (executable)
@@ -18,3 +18,12 @@ HELP: each-withn
 "passed to the quotation given to each-withn for each element in the sequence."\r
 } \r
 { $see-also map-withn } ;\r
+\r
+HELP: randomize\r
+{ $values { "seq" sequence } { "seq'" sequence } }\r
+{ $description "Shuffle the elements in the sequence randomly, returning the new sequence." } ;\r
+\r
+HELP: enumerate\r
+{ $values { "seq" sequence } { "seq'" sequence } }\r
+{ $description "Returns a new sequence where each element is an array of { index, value }" } ;\r
+\r
index 18c9d7f7358fbd3405ca794bf12054b299422887..a44d41d98a6a061c1c3c31ee3841d7ee4e441daa 100755 (executable)
@@ -60,3 +60,6 @@ IN: sequences.lib.tests
 [ 1 2 { 3 4 } [ + + drop ] 2 each-withn  ] must-infer
 { 13 } [ 1 2 { 3 4 } [ + + ] 2 each-withn + ] unit-test
 [ { 910 911 912 } ] [ 10 900 3 [ + + ] map-with2 ] unit-test
+
+[ { { 0 1 } { 1 2 } { 2 3 } } ] [ { 1 2 3 } enumerate ] unit-test
+
index 690d7f4b76d5e44a5d0a35d6b377df85f90686d4..fe9d9bb587d26e50e244e68fa76fd39df7b79d47 100755 (executable)
@@ -160,3 +160,16 @@ PRIVATE>
 
 : ?nth* ( n seq -- elt/f ? )
     2dup bounds-check? [ nth-unsafe t ] [ 2drop f f ] if ; flushable
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+USE: math.ranges
+USE: random 
+: randomize ( seq -- seq' )
+    dup length 1 (a,b] [ dup random pick exchange ] each ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: enumerate ( seq -- seq' )
+    <enum> >alist ;
+
index 2858ad21f39e3bce9dac5ab58fa1534b6e3f5fb5..e035090fb0426b9b8b4bec46212729c13dba61c4 100644 (file)
@@ -90,7 +90,7 @@ M: comment entity-url
 
 : list-posts ( -- posts )
     f <post> "author" value >>author
-    select-tuples [ dup id>> f <comment> count-tuples >>comments ] map
+    select-tuples [ dup id>> f <comment> count-tuples >>comments ] map
     reverse-chronological-order ;
 
 : <list-posts-action> ( -- action )
diff --git a/extra/webapps/blogs/tags.txt b/extra/webapps/blogs/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/extra/webapps/calculator/calculator.factor b/extra/webapps/calculator/calculator.factor
new file mode 100644 (file)
index 0000000..f1416fb
--- /dev/null
@@ -0,0 +1,44 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: furnace.actions furnace.redirection
+http.server.dispatchers html.forms validators urls accessors
+math ;
+IN: webapps.calculator
+
+TUPLE: calculator < dispatcher ;
+
+: <calculator-action> ( -- action )
+    <page-action>
+
+    [
+        { { "z" [ [ v-number ] v-optional ] } } validate-params
+    ] >>init
+
+    { calculator "calculator" } >>template
+
+    [
+        {
+            { "x" [ v-number ] }
+            { "y" [ v-number ] }
+        } validate-params
+
+        URL" $calculator" "x" value "y" value + "z" set-query-param
+        <redirect>
+    ] >>submit ;
+
+: <calculator> ( -- responder )
+    calculator new-dispatcher
+        <calculator-action> >>default ;
+
+! Deployment example
+USING: db.sqlite furnace.alloy namespaces http.server ;
+
+: calculator-db ( -- params db ) "calculator.db" sqlite-db ;
+
+: run-calculator ( -- )
+    <calculator>
+        calculator-db <alloy>
+        main-responder set-global
+    8080 httpd ;
+
+MAIN: run-calculator
diff --git a/extra/webapps/calculator/calculator.xml b/extra/webapps/calculator/calculator.xml
new file mode 100644 (file)
index 0000000..ed8e60d
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version='1.0' ?>
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+       <head> <title>Calculator</title> </head>
+
+       <body>
+               <h1>Calculator</h1>
+
+               <t:form t:action="$calculator">
+
+                       <table>
+                               <tr><td>First value:</td><td> <t:field t:name="x" /> </td></tr>
+                               <tr><td>Second value:</td><td> <t:field t:name="y" /> </td></tr>
+                       </table>
+
+                       <input type="SUBMIT" value="Compute" />
+
+                       <t:if t:value="z">
+                               <br/>
+
+                               Result: <t:label t:name="z" />
+                       </t:if>
+
+               </t:form>
+       </body>
+
+</t:chloe>
diff --git a/extra/webapps/calculator/tags.txt b/extra/webapps/calculator/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index f3efb3868f2e231893e6f5a3273294b7b9944c68..a5c9fbc6b935eff1df0ade7595ae57b6cc9453db 100644 (file)
@@ -1,7 +1,8 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
 USING: math kernel accessors http.server http.server.dispatchers
 furnace furnace.actions furnace.sessions furnace.redirection
-html.components html.forms html.templates.chloe
-fry urls ;
+html.components html.forms fry urls ;
 IN: webapps.counter
 
 SYMBOL: count
@@ -26,5 +27,17 @@ M: counter-app init-session* drop 0 count sset ;
     counter-app new-dispatcher
         [ 1+ ] <counter-action> "inc" add-responder
         [ 1- ] <counter-action> "dec" add-responder
-        <display-action> "" add-responder
-    <sessions> ;
+        <display-action> "" add-responder ;
+
+! Deployment example
+USING: db.sqlite furnace.alloy namespaces ;
+
+: counter-db ( -- params db ) "counter.db" sqlite-db ;
+
+: run-counter ( -- )
+    <counter-app>
+        counter-db <alloy>
+        main-responder set-global
+    8080 httpd ;
+
+MAIN: run-counter
diff --git a/extra/webapps/counter/tags.txt b/extra/webapps/counter/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/extra/webapps/help/help.factor b/extra/webapps/help/help.factor
new file mode 100644 (file)
index 0000000..c209fe2
--- /dev/null
@@ -0,0 +1,38 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors http.server.dispatchers
+http.server.static furnace.actions furnace.redirection urls
+validators locals io.files html.forms help.html ;
+IN: webapps.help
+
+TUPLE: help-webapp < dispatcher ;
+
+:: <search-action> ( help-dir -- action )
+    <page-action>
+        { help-webapp "search" } >>template
+
+        [
+            {
+                { "search" [ 1 v-min-length 50 v-max-length v-one-line ] }
+            } validate-params
+
+            help-dir set-current-directory
+
+            "search" value article-apropos "articles" set-value
+            "search" value word-apropos "words" set-value
+            "search" value vocab-apropos "vocabs" set-value
+
+            { help-webapp "search" } <chloe-content>
+        ] >>submit ;
+
+: <main-action> ( -- action )
+    <page-action>
+        { help-webapp "help" } >>template ;
+
+: <help-webapp> ( help-dir -- webapp )
+    help-webapp new-dispatcher
+        <main-action> "" add-responder
+        over <search-action> "search" add-responder
+        swap <static> "content" add-responder ;
+
+
diff --git a/extra/webapps/help/help.xml b/extra/webapps/help/help.xml
new file mode 100644 (file)
index 0000000..7718b10
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+       <html xmlns="http://www.w3.org/1999/xhtml">
+               <head>
+                       <title>Factor Documentation</title>
+                       <t:base t:href="$help-webapp" />
+               </head>
+
+               <frameset cols="30%, 70%">
+                       <frame src="search" name="search" />
+                       <frame src="content/article-handbook.html" name="content" />
+               </frameset>
+       </html>
+
+</t:chloe>
diff --git a/extra/webapps/help/search.xml b/extra/webapps/help/search.xml
new file mode 100644 (file)
index 0000000..e5fa5d3
--- /dev/null
@@ -0,0 +1,75 @@
+<?xml version='1.0' ?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+       <head>
+               <t:base t:href="$help-webapp/content/" />
+
+               <style>
+                       body { font-family: sans-serif; font-size: 85%; }
+                       a:link { text-decoration: none; color: #00004c; }
+                       a:visited { text-decoration: none; color: #00004c; }
+                       a:active { text-decoration: none; color: #00004c; }
+                       a:hover { text-decoration: underline; color: #00004c; }
+               </style>
+       </head>
+
+       <body>
+               <h1><t:a t:href="$help-webapp/content/article-handbook.html"
+                       target="content">Factor documentation</t:a></h1>
+
+               <p>This is the <a href="http://factorcode.org" target="_top">Factor</a>
+               documentation, generated offline from a
+               <code>load-everything</code> image. If you want, you can also browse the
+               documentation from within the <a href="http://factorcode.org" target="_top">Factor</a> UI.</p>
+               
+               <p>You may search article titles below; for example, try searching for "HTTP".</p>
+               
+               <t:form t:action="$help-webapp/search">
+                       <t:field t:name="search" />
+                       <button>Search</button>
+               </t:form>
+               
+               <t:if t:value="articles">
+                       <hr/>
+                       
+                       <h2>Articles</h2>
+                       
+                       <ul>
+                               <t:each t:name="articles">
+                                       <li> <t:link t:name="value" t:target="content" /> </li>
+                               </t:each>
+                       </ul>
+               </t:if>
+               
+               <t:if t:value="vocabs">
+                       <hr/>
+                       
+                       <h2>Vocabularies</h2>
+                       
+                       <ul>
+                               <t:each t:name="vocabs">
+                                       <li> <t:link t:name="value" t:target="content" /> </li>
+                               </t:each>
+                       </ul>
+               </t:if>
+               
+               <t:if t:value="words">
+                       <hr/>
+                       
+                       <h2>Words</h2>
+                       
+                       <ul>
+                               <t:each t:name="words">
+                                       <li> <t:link t:name="value" t:target="content" /> </li>
+                               </t:each>
+                       </ul>
+               </t:if>
+
+       </body>
+</html>
+
+</t:chloe>
index 6abae4895ba502f74415a6f7a9178c46ff41502b..96339b6cf86a0b77438e74e2176522aafe176a2e 100644 (file)
@@ -18,6 +18,6 @@
                        </tr>
                </table>
 
-               <input type="SUBMIT" value="Submit" />
+               <p> <button>Submit</button> </p>
        </t:form>
 </t:chloe>
index 1c138fc8c0835ebd534fb77863d152e03b2b5633..8fe672049f07527188049e63fb05f5e3a127a5b4 100644 (file)
@@ -20,7 +20,7 @@
 
        <t:bind-each t:name="annotations">
 
-               <a name="@id"><h2>Annotation: <t:label t:name="summary" /></h2></a>
+               <h2><a name="@id">Annotation: <t:label t:name="summary" /></a></h2>
 
                <table>
                        <tr><th class="field-label">Author: </th><td><t:label t:name="author" /></td></tr>
@@ -52,7 +52,7 @@
                                </tr>
                        </table>
 
-                       <input type="SUBMIT" value="Done" />
+                       <p> <button>Done</button> </p>
 
                </t:form>
 
index b95f3f7b64aefbe5253e1f78f600d034afe5f7fe..6d524ad86fa34cd3c0013c8a309fedc06d82972f 100644 (file)
@@ -8,7 +8,7 @@
 
        <div class="navbar">
 
-                 <t:a t:href="$pastebin/list">Pastes</t:a>
+                 <t:a t:href="$pastebin">Pastes</t:a>
                | <t:a t:href="$pastebin/new-paste">New Paste</t:a>
 
                <t:if t:code="furnace.auth:logged-in?">
index 3aeb21420fb7fa218687ddec541a20885989ad27..01e068d35151c9e74c5b3015eab518ec630c992f 100644 (file)
@@ -2,8 +2,8 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: namespaces assocs sorting sequences kernel accessors
 hashtables sequences.lib db.types db.tuples db combinators
-calendar calendar.format math.parser syndication urls xml.writer
-xmode.catalog validators
+calendar calendar.format math.parser math.order syndication urls
+xml.writer xmode.catalog validators
 html.forms
 html.components
 html.templates.chloe
@@ -58,7 +58,9 @@ TUPLE: paste < entity annotations ;
         swap >>id ;
 
 : pastes ( -- pastes )
-    f <paste> select-tuples ;
+    f <paste> select-tuples
+    [ [ date>> ] compare ] sort
+    reverse ;
 
 TUPLE: annotation < entity parent ;
 
@@ -111,7 +113,7 @@ M: annotation entity-url
     <feed-action>
         [ pastebin-url ] >>url
         [ "Factor Pastebin" ] >>title
-        [ pastes <reversed> ] >>entries ;
+        [ pastes ] >>entries ;
 
 ! ! !
 ! PASTES
@@ -230,7 +232,7 @@ M: annotation entity-url
 
 : <pastebin> ( -- responder )
     pastebin new-dispatcher
-        <pastebin-action> "list" add-main-responder
+        <pastebin-action> "" add-responder
         <pastebin-feed-action> "list.atom" add-responder
         <paste-action> "paste" add-responder
         <paste-feed-action> "paste.atom" add-responder
index a6b3078aa793fb5f88432aa3422d3a2b91d96979..3c9cb7ce9676ac18bdb69985dcc97efdb55ecbdc 100644 (file)
@@ -5,9 +5,11 @@
        <t:title>Pastebin</t:title>
 
        <table width="100%">
-               <th align="left" width="50%">Summary:</th>
-               <th align="left" width="100">Paste by:</th>
-               <th align="left" width="200">Date:</th>
+               <tr>
+                       <th align="left" width="50%">Summary:</th>
+                       <th align="left" width="100">Paste by:</th>
+                       <th align="left" width="200">Date:</th>
+               </tr>
 
                <t:bind-each t:name="pastes">
                        <tr>
diff --git a/extra/webapps/pastebin/tags.txt b/extra/webapps/pastebin/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index d1c7013c68137f8c478102215f1db77b7167c1dc..9a4275b80b143ea72eb49decc41a19b6a0123a25 100644 (file)
 
                        <tr>
                                <th class="field-label">Home page:</th>
-                               <td><t:field t:name="www-url" /></td>
+                               <td><t:field t:name="www-url" t:size="40" /></td>
                        </tr>
 
                        <tr>
                                <th class="field-label">Feed:</th>
-                               <td><t:field t:name="feed-url" /></td>
+                               <td><t:field t:name="feed-url" t:size="40" /></td>
                        </tr>
 
                </table>
index 6f75addda55dd58ce21cc7072c67734ff028d6cf..0b5fde86e8aed8b43aecf3e53b8261971a9191d9 100644 (file)
 
                        <tr>
                                <th class="field-label">Home page:</th>
-                               <td><t:field t:name="www-url" /></td>
+                               <td><t:field t:name="www-url" t:size="40" /></td>
                        </tr>
 
                        <tr>
                                <th class="field-label">Feed:</th>
-                               <td><t:field t:name="feed-url" /></td>
+                               <td><t:field t:name="feed-url" t:size="40" /></td>
                        </tr>
 
                </table>
index f4e390056a6c5689a1886b286460435aedb76aed..486d5cc1ed92f6ccd5e57fee74d0d8df1980bbe1 100644 (file)
@@ -5,7 +5,7 @@
        <t:style t:include="resource:extra/webapps/planet/planet.css" />
 
        <div class="navbar">
-                 <t:a t:href="$planet/list">Front Page</t:a>
+                 <t:a t:href="$planet">Front Page</t:a>
                | <t:a t:href="$planet/feed.xml">Atom Feed</t:a>
                | <t:a t:href="$planet/admin">Admin</t:a>
 
index 721529de27b35224a5cf310a1ec6f35a902918b3..00d843573cc0eba8a7498a4641dbbf98621ac131 100755 (executable)
@@ -144,13 +144,8 @@ posting "POSTINGS"
             f <blog>
             [ deposit-blog-slots ]
             [ insert-tuple ]
-            [
-                <url>
-                    "$planet/admin/edit-blog" >>path
-                    swap id>> "id" set-query-param
-                <redirect>
-            ]
-            tri
+            bi
+            URL" $planet/admin" <redirect>
         ] >>submit ;
 
 : <edit-blog-action> ( -- action )
@@ -171,19 +166,19 @@ posting "POSTINGS"
         [
             f <blog>
             [ deposit-blog-slots ]
+            [ "id" value >>id ]
             [ update-tuple ]
-            [
-                <url>
-                    "$planet/admin" >>path
-                    swap id>> "id" set-query-param
-                <redirect>
-            ]
             tri
+
+            <url>
+                "$planet/admin" >>path
+                "id" value "id" set-query-param
+            <redirect>
         ] >>submit ;
 
 : <planet-admin> ( -- responder )
     planet-admin new-dispatcher
-        <edit-blogroll-action> "blogroll" add-main-responder
+        <edit-blogroll-action> "" add-responder
         <update-action> "update" add-responder
         <new-blog-action> "new-blog" add-responder
         <edit-blog-action> "edit-blog" add-responder
@@ -194,7 +189,7 @@ posting "POSTINGS"
 
 : <planet> ( -- responder )
     planet new-dispatcher
-        <planet-action> "list" add-main-responder
+        <planet-action> "" add-responder
         <planet-feed-action> "feed.xml" add-responder
         <planet-admin> "admin" add-responder
     <boilerplate>
index 340e6c4bee9a81fda7bed238437eac18b4485cd6..412f42c64e733ccf94af895cac11733f8409fe3f 100644 (file)
@@ -2,7 +2,7 @@
 
 <t:chloe xmlns:t="http://factorcode.org/chloe/1.0">
 
-       <t:title>Concatenative Planet</t:title>
+       <t:title>[ planet-factor ]</t:title>
 
        <table width="100%" cellpadding="10">
                <tr>
                                        </t:each>
                                </ul>
 
+                               <hr/>
+
+                               <p>
+                                   <strong>planet-factor</strong> is an Atom/RSS aggregator that collects the
+                                   contents of <a href="http://factorcode.org/">Factor</a>-related blogs. It is inspired by
+                                   <a href="http://planet.lisp.org">Planet Lisp</a>.
+                               </p>
+                               <p>
+                                   <img src="http://factorcode.org/feed-icon-14x14.png" />
+                                   <t:a t:href="$planet/feed.xml">Syndicate</t:a>
+                               </p>
                        </td>
                </tr>
        </table>
diff --git a/extra/webapps/planet/tags.txt b/extra/webapps/planet/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
diff --git a/extra/webapps/todo/tags.txt b/extra/webapps/todo/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index e726c4ed3628cd9623d89462c6ce41a55cb955fd..e1f6c8735a49aeacac268474002b374bf64ec300 100755 (executable)
@@ -106,7 +106,7 @@ todo "TODO"
 
 : <todo-list> ( -- responder )
     todo-list new-dispatcher
-        <list-action>   "list"   add-main-responder
+        <list-action>   ""       add-responder
         <view-action>   "view"   add-responder
         <new-action>    "new"    add-responder
         <edit-action>   "edit"   add-responder
index 252667462bd844b4e11065d10263aa62809f19c9..f41e8a97b481e2713ca6e5e719525f05cedb347a 100644 (file)
@@ -4,7 +4,7 @@
 
        <t:title>Edit User</t:title>
 
-       <t:form t:action="$user-admin/edit" t:for="username">
+       <t:form t:action="$user-admin/edit" t:for="username" autocomplete="off">
 
        <table>
        
index b1f35c979b4954feee18bfbd3e49084e656f09e5..7acdd384ba920e3c17715e866178551775465162 100644 (file)
@@ -4,7 +4,7 @@
 
        <t:title>New User</t:title>
 
-       <t:form t:action="$user-admin/new">
+       <t:form t:action="$user-admin/new" autocomplete="off">
 
        <table>
        
diff --git a/extra/webapps/user-admin/tags.txt b/extra/webapps/user-admin/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 2137abbc2ddf3156de1f6bc9c749824381518fe1..9d4e348596d14e9a0a7c26308b699786d45758d7 100644 (file)
@@ -149,7 +149,7 @@ can-administer-users? define-capability
 
 : <user-admin> ( -- responder )
     user-admin new-dispatcher
-        <user-list-action> "list" add-main-responder
+        <user-list-action> "" add-responder
         <new-user-action> "new" add-responder
         <edit-user-action> "edit" add-responder
         <delete-user-action> "delete" add-responder
index 8df7774fbad2a7d4851b6b7ff38dc0d54b59372f..53f611a8d8e47804af54c6842628647117d36d54 100644 (file)
@@ -4,7 +4,7 @@
 
         <t:form t:action="$wee-url">
                <p>Shorten URL: <t:field t:name="url" t:size="40" /></p>
-               <input type="submit" value="Shorten" />
+               <button>Shorten</button>
        </t:form>
 
 </t:chloe>
diff --git a/extra/webapps/wee-url/tags.txt b/extra/webapps/wee-url/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 90843a7140984e57aa1ab67ee25b5e2ff5ebcfcd..9cb2e92f932034e2db445cc505711c01c8355a07 100644 (file)
@@ -16,7 +16,7 @@
                </p>
 
                <p>
-                       <input type="submit" value="Save" />
+                       <button>Save</button>
                </p>
 
        </t:form>
index b8de408588b6a7981e3484eb07d218c77e8c364d..33b3a6c51a41292a67e729a006b958793293825e 100644 (file)
@@ -16,12 +16,22 @@ Images can be embedded in the text:
 
 [[image:http://factorcode.org/graphics/logo.png]]
 
-Lists:
+Unordered lists:
 
 - a list
 - with three
 - items
 
+Ordered lists:
+
+# a list
+# with three
+# numbered items
+
+Horizontal lines:
+
+___
+
 Tables:
 
 |a table|with|four|columns|
index 9c65876377f4c87f009c1902edefdac3355f544a..f7e357c86096671d099701b8533acfb93f57b80f 100644 (file)
@@ -1,5 +1,5 @@
 This Wiki uses [[Farkup]] to mark up text.
 
-Two special article names are recognized by the Wiki: [[Sidebar]] and [[Footer]]. They do not exist by default, but if you create them, they will be visible on every page.
+Two special article names are recognized by the Wiki: [[Contents]] and [[Footer]]. They do not exist by default, but if you create them, they will be visible on every page.
 
 The Wiki supports hierarchical article organization. You can separate components in article names with slashes, and Wiki links only display the last component. An example: [[Factor/Features]].
index 68f377e70bc1dcb1a8b3fec843df33cd36184385..1d9c01fd65edc1cb59776a614530ea057373e967 100644 (file)
@@ -32,7 +32,7 @@
                        </tr>
                </table>
 
-               <input type="submit" value="View" />
+               <button>View</button>
        </t:form>
 
 </t:chloe>
diff --git a/extra/webapps/wiki/tags.txt b/extra/webapps/wiki/tags.txt
new file mode 100644 (file)
index 0000000..c077218
--- /dev/null
@@ -0,0 +1 @@
+web
index 5136e4945db32e866c91f4565df3371081821988..e3774bbe0b063c6250e041a10fa6f262f6a5f56e 100644 (file)
@@ -5,7 +5,7 @@
        <t:title><t:label t:name="title" /></t:title>
 
        <div class="description">
-               <t:html t:name="html" />
+               <t:farkup t:name="parsed" t:parsed="true" />
        </div>
 
        <p>
index 978551a6380429050efc9f733fe3797aadadc73d..bca48ce26037e8204dfe4a7e8cd49212cb823e0f 100644 (file)
 
        <table width="100%">
                <tr>
-                       <t:if t:value="sidebar">
+                       <t:if t:value="contents">
                                <td valign="top" style="width: 210px;">
-                                       <div class="sidebar">
-                                               <t:bind t:name="sidebar">
+                                       <div class="contents">
+                                               <t:bind t:name="contents">
                                                        <h2>
                                                                <t:a t:href="$wiki/view" t:query="title">
                                                                        <t:label t:name="title" />
                                                                </t:a>
                                                        </h2>
 
-                                                       <t:html t:name="html" />
+                                                       <t:farkup t:name="parsed" t:parsed="true" />
                                                </t:bind>
                                        </div>
                                </td>
 
                <t:if t:value="footer">
                        <tr>
-                               <td colspan="2">
+                               <td colspan="2" class="footer">
                                        <t:bind t:name="footer">
-                                               <small>
-                                                       <t:html t:name="html" />
-                                               </small>
+                                               <t:farkup t:name="parsed" t:parsed="true" />
                                        </t:bind>
                                </td>
                        </tr>
index 67000ae63c9fbbd36b33f87a24295ab603be10b0..4ecc6e52821b29203d61d9cb82bae5ee1be911c5 100644 (file)
     border-width: 1px 1px 0 0;
 }
 
-.sidebar {
+.contents {
     padding: 4px;
     margin: 4px;
-    border: 1px dashed grey;
+    border: 1px dashed gray;
     background: #f5f1fd;
     width: 200px;
 }
+
+.footer {
+    font-size: 75%;
+}
index 9d1ad15aa4a0b592aee9b4d3394d4be92c8de51a..16c51a876b57e8a6b2716558eab76597c28a2ffe 100644 (file)
@@ -19,7 +19,7 @@ db.types db.tuples lcs farkup urls ;
 IN: webapps.wiki
 
 : wiki-url ( rest path -- url )
-    [ "$wiki/" % % "/" % % ] "" make
+    [ "$wiki/" % % "/" % present % ] "" make
     <url> swap >>path ;
 
 : view-url ( title -- url ) "view" wiki-url ;
@@ -47,7 +47,7 @@ article "ARTICLES" {
 
 : <article> ( title -- article ) article new swap >>title ;
 
-TUPLE: revision id title author date content html description ;
+TUPLE: revision id title author date content parsed description ;
 
 revision "REVISIONS" {
     { "id" "ID" INTEGER +db-assigned-id+ }
@@ -55,7 +55,7 @@ revision "REVISIONS" {
     { "author" "AUTHOR" { VARCHAR 256 } +not-null+ } ! uid
     { "date" "DATE" TIMESTAMP +not-null+ }
     { "content" "CONTENT" TEXT +not-null+ }
-    { "html" "HTML" TEXT +not-null+ } ! Farkup converted to HTML
+    { "parsed" "PARSED" FACTOR-BLOB +not-null+ } ! Farkup AST
     { "description" "DESCRIPTION" TEXT }
 } define-persistent
 
@@ -73,7 +73,7 @@ M: revision feed-entry-url id>> revision-url ;
     revision new swap >>id ;
 
 : compute-html ( revision -- )
-    dup content>> convert-farkup >>html drop ;
+    dup content>> parse-farkup >>parsed drop ;
 
 : validate-title ( -- )
     { { "title" [ v-one-line ] } } validate-params ;
@@ -344,10 +344,13 @@ M: revision feed-entry-url id>> revision-url ;
         [ "author" value user-edits-url ] >>url
         [ list-user-edits ] >>entries ;
 
-: init-sidebar ( -- )
-    "Sidebar" latest-revision [ "sidebar" [ from-object ] nest-form ] when*
+: init-sidebars ( -- )
+    "Contents" latest-revision [ "contents" [ from-object ] nest-form ] when*
     "Footer" latest-revision [ "footer" [ from-object ] nest-form ] when* ;
 
+: init-relative-link-prefix ( -- )
+    URL" $wiki/view/" adjust-url present relative-link-prefix set ;
+
 : <wiki> ( -- dispatcher )
     wiki new-dispatcher
         <main-article-action> "" add-responder
@@ -367,7 +370,7 @@ M: revision feed-entry-url id>> revision-url ;
         <list-changes-feed-action> "changes.atom" add-responder
         <delete-action> "delete" add-responder
     <boilerplate>
-        [ init-sidebar ] >>init
+        [ init-sidebars init-relative-link-prefix ] >>init
         { wiki "wiki-common" } >>template ;
 
 : init-wiki ( -- )
index a35358ae6b7166b67766578d5db40693799d6f45..5553fda740cbd8174d8736bd00ed1cb6b490c265 100644 (file)
@@ -8,6 +8,8 @@ html.templates.chloe
 http.server
 http.server.dispatchers
 http.server.redirection
+http.server.static
+http.server.cgi
 furnace.alloy
 furnace.auth.login
 furnace.auth.providers.db
@@ -17,13 +19,11 @@ furnace.auth.features.registration
 furnace.auth.features.deactivate-user
 furnace.boilerplate
 furnace.redirection
-webapps.blogs
 webapps.pastebin
 webapps.planet
-webapps.todo
 webapps.wiki
-webapps.wee-url
-webapps.user-admin ;
+webapps.user-admin
+webapps.help ;
 IN: websites.concatenative
 
 : test-db ( -- params db ) "resource:test.db" sqlite-db ;
@@ -33,43 +33,37 @@ IN: websites.concatenative
         init-furnace-tables
 
         {
-            post comment
             paste annotation
             blog posting
-            todo
-            short-url
             article revision
         } ensure-tables
     ] with-db ;
 
 TUPLE: factor-website < dispatcher ;
 
-: <factor-website> ( -- responder )
-    factor-website new-dispatcher
-        <blogs> "blogs" add-responder
-        <todo-list> "todo" add-responder
-        <pastebin> "pastebin" add-responder
-        <planet> "planet" add-responder
-        <wiki> "wiki" add-responder
-        <wee-url> "wee-url" add-responder
-        <user-admin> "user-admin" add-responder
-        URL" /wiki/view/Front Page" <redirect-responder> "" add-responder
+: <factor-boilerplate> ( responder -- responder' )
+    <boilerplate>
+        { factor-website "page" } >>template ;
+
+: <login-config> ( responder -- responder' )
     "Factor website" <login-realm>
         "Factor website" >>name
         allow-registration
         allow-password-recovery
         allow-edit-profile
-        allow-deactivation
-    <boilerplate>
-        { factor-website "page" } >>template
-    test-db <alloy> ;
+        allow-deactivation ;
+
+: <factor-website> ( -- responder )
+    factor-website new-dispatcher
+        <wiki> "wiki" add-responder
+        <user-admin> "user-admin" add-responder
+        URL" /wiki/view/Front Page" <redirect-responder> "" add-responder ;
 
 SYMBOL: key-password
 SYMBOL: key-file
 SYMBOL: dh-file
 
 : common-configuration ( -- )
-    reset-templates
     "concatenative.org" 25 <inet> smtp-server set-global
     "noreply@concatenative.org" lost-password-from set-global
     "website@concatenative.org" insomniac-sender set-global
@@ -81,16 +75,26 @@ SYMBOL: dh-file
     "resource:basis/openssl/test/server.pem" key-file set-global
     "password" key-password set-global
     common-configuration
-    <factor-website> main-responder set-global ;
+    <factor-website>
+        <pastebin> <factor-boilerplate> <login-config> "pastebin" add-responder
+        <planet> <factor-boilerplate> <login-config> "planet" add-responder
+        "/tmp/docs/" <help-webapp> "docs" add-responder
+    test-db <alloy>
+    main-responder set-global ;
 
-: no-www-prefix ( -- responder )
-    "http://concatenative.org" <permanent-redirect> <trivial-responder> ;
+: <gitweb> ( path -- responder )
+    <dispatcher>
+        swap <static> enable-cgi >>default
+        URL" /gitweb.cgi" <redirect-responder> "" add-responder ;
 
 : init-production ( -- )
     common-configuration
     <vhost-dispatcher>
-        <factor-website> "concatenative.org" add-responder
-        no-www-prefix "www.concatenative.org" add-responder
+        <factor-website> <login-config> <factor-boilerplate> test-db <alloy> "concatenative.org" add-responder
+        <pastebin> <login-config> <factor-boilerplate> test-db <alloy> "paste.factorcode.org" add-responder
+        <planet> <login-config> <factor-boilerplate> test-db <alloy> "planet.factorcode.org" add-responder
+        home "docs" append-path <help-webapp> test-db <alloy> "docs.factorcode.org" add-responder
+        home "cgi" append-path <gitweb> "gitweb.factorcode.org" add-responder
     main-responder set-global ;
 
 : <factor-secure-config> ( -- config )
index 129dcb154663a07751b40b6fb9391907e379c0fa..2a5cbf7024e5ca265cc063f51e38239239fb9f39 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0' ?>
 
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 
index cfe6cfea494d6d5adda2d91c26a3839108d8dff4..bb64f8fed68caade85dcec59ab5ae8063c7efc54 100644 (file)
@@ -42,6 +42,6 @@ HELP: wordtimer-call
 
     
 ARTICLE: "wordtimer" "Word Timer"
-"The " { $vocab-link "wordtimer" } " vocabulary measures accumulated execution time for words. If you just want to profile the accumulated time taken by all words in a vocab you can use " { $vocab-link "profile-vocab" } ". If you need more fine grained control then do the following: First annotate individual words with the " { $link add-timer } " word or whole vocabularies with " { $link add-timers } ". Then use " { $link wordtimer-call } " to invoke a quotation and print out the timings." ;
+"The " { $vocab-link "wordtimer" } " vocabulary measures accumulated execution time for words. If you just want to profile the accumulated time taken by all words in a vocab you can use " { $link profile-vocab } ". If you need more fine grained control then do the following: First annotate individual words with the " { $link add-timer } " word or whole vocabularies with " { $link add-timers } ". Then use " { $link wordtimer-call } " to invoke a quotation and print out the timings." ;
     
 ABOUT: "wordtimer"
index 5c9d050468995654569ed81c5ee3739f363dbec6..1ae8919559ca0d56779d302f02612a3e9bfbbe13 100644 (file)
@@ -76,7 +76,7 @@
     (modify-syntax-entry ?\" "\"    " factor-mode-syntax-table)))
 
 (defvar factor-mode-map (make-sparse-keymap))
-    
+
 (defcustom factor-mode-hook nil
   "Hook run when entering Factor mode."
   :type 'hook
   (use-local-map factor-mode-map)
   (setq major-mode 'factor-mode)
   (setq mode-name "Factor")
+  (set (make-local-variable 'indent-line-function) #'factor-indent-line)
   (make-local-variable 'comment-start)
   (setq comment-start "! ")
   (make-local-variable 'font-lock-defaults)
 (defun factor-clear ()
   (interactive)
   (factor-send-string "clear"))
-  
+
 (defun factor-comment-line ()
   (interactive)
   (beginning-of-line)
 (define-key factor-mode-map "\C-c\C-h" 'factor-help)
 (define-key factor-mode-map "\C-cc"    'comment-region)
 (define-key factor-mode-map [return]   'newline-and-indent)
+(define-key factor-mode-map [tab]      'indent-for-tab-command)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; indentation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst factor-word-starting-keywords
+  '("" ":" "TUPLE" "MACRO" "MACRO:" "M"))
+
+(defmacro factor-word-start-re (keywords)
+  `(format
+    "^\\(%s\\): "
+    (mapconcat 'identity ,keywords "\\|")))
+
+(defun factor-calculate-indentation ()
+  "Calculate Factor indentation for line at point."
+  (let ((not-indented t)
+        (cur-indent 0))
+    (save-excursion
+      (beginning-of-line)
+      (if (bobp)
+          (setq cur-indent 0)
+        (save-excursion
+          (while not-indented
+            ;; Check that we are inside open brackets
+            (save-excursion
+              (let ((cur-depth (factor-brackets-depth)))
+                (forward-line -1)
+                (setq cur-indent (+ (current-indentation)
+                                    (* default-tab-width
+                                       (- cur-depth (factor-brackets-depth)))))
+                (setq not-indented nil)))
+            (forward-line -1)
+              ;; Check that we are after the end of previous word
+              (if (looking-at ".*;[ \t]*$")
+                  (progn
+                    (setq cur-indent (- (current-indentation) default-tab-width))
+                    (setq not-indented nil))
+                ;; Check that we are after the start of word
+                (if (looking-at (factor-word-start-re factor-word-starting-keywords))
+;                (if (looking-at "^[A-Z:]*: ")
+                    (progn
+                      (message "inword")
+                      (setq cur-indent (+ (current-indentation) default-tab-width))
+                      (setq not-indented nil))
+                  (if (bobp)
+                      (setq not-indented nil))))))))
+    cur-indent))
+
+(defun factor-brackets-depth ()
+  "Returns number of brackets, not closed on previous lines."
+  (syntax-ppss-depth
+   (save-excursion
+     (syntax-ppss (line-beginning-position)))))
+
+(defun factor-indent-line ()
+  "Indent current line as Factor code"
+  (let ((target (factor-calculate-indentation))
+        (pos (- (point-max) (point))))
+    (if (= target (current-indentation))
+        (if (< (current-column) (current-indentation))
+            (back-to-indentation))
+      (beginning-of-line)
+      (delete-horizontal-space)
+      (indent-to target)
+      (if (> (- (point-max) pos) (point))
+          (goto-char (- (point-max) pos))))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; factor-listener-mode
 (defun factor-refresh-all ()
   (interactive)
   (comint-send-string "*factor*" "refresh-all\n"))
-
-
index d1c46cee0b0ca3a207af5f519e7d73bdad486759..90a3d46d5000cc7c6cb772ec0827aa3d4b0f5d53 100644 (file)
@@ -131,18 +131,18 @@ syn region factorStackEffect start=/\<(\>/ end=/\<)\>/ contained
 
 "adapted from lisp.vim
 if exists("g:factor_norainbow") 
-    syn region factorQuotation matchgroup=factorDelimiter start=/\<\[\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
+    syn region factorQuotation0 matchgroup=factorDelimiter start=/\<\'\?\[\>/ matchgroup=factorDelimiter end=/\<\]\>/ contains=ALL
 else
-    syn region factorQuotation0           matchgroup=hlLevel0 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
-    syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
-    syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
-    syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
-    syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
-    syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
-    syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
-    syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
-    syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
-    syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
+    syn region factorQuotation0           matchgroup=hlLevel0 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation1,factorArray1
+    syn region factorQuotation1 contained matchgroup=hlLevel1 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation2,factorArray2
+    syn region factorQuotation2 contained matchgroup=hlLevel2 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation3,factorArray3
+    syn region factorQuotation3 contained matchgroup=hlLevel3 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation4,factorArray4
+    syn region factorQuotation4 contained matchgroup=hlLevel4 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation5,factorArray5
+    syn region factorQuotation5 contained matchgroup=hlLevel5 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation6,factorArray6
+    syn region factorQuotation6 contained matchgroup=hlLevel6 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation7,factorArray7
+    syn region factorQuotation7 contained matchgroup=hlLevel7 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation8,factorArray8
+    syn region factorQuotation8 contained matchgroup=hlLevel8 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation9,factorArray9
+    syn region factorQuotation9 contained matchgroup=hlLevel9 start=/\<\'\?\[\>/ end=/\<\]\>/ contains=@factorCluster,factorQuotation0,factorArray0
 endif
 
 if exists("g:factor_norainbow") 
diff --git a/unfinished/compiler/backend/alien/alien.factor b/unfinished/compiler/backend/alien/alien.factor
deleted file mode 100644 (file)
index 0c5a6af..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-IN: compiler.backend.alien
-
-! #alien-invoke
-: set-stack-frame ( n -- )
-    dup [ frame-required ] when* \ stack-frame set ;
-
-: with-stack-frame ( n quot -- )
-    swap set-stack-frame
-    call
-    f set-stack-frame ; inline
-
-GENERIC: reg-size ( register-class -- n )
-
-M: int-regs reg-size drop cell ;
-
-M: single-float-regs reg-size drop 4 ;
-
-M: double-float-regs reg-size drop 8 ;
-
-GENERIC: reg-class-variable ( register-class -- symbol )
-
-M: reg-class reg-class-variable ;
-
-M: float-regs reg-class-variable drop float-regs ;
-
-GENERIC: inc-reg-class ( register-class -- )
-
-M: reg-class inc-reg-class
-    dup reg-class-variable inc
-    fp-shadows-int? [ reg-size stack-params +@ ] [ drop ] if ;
-
-M: float-regs inc-reg-class
-    dup call-next-method
-    fp-shadows-int? [ reg-size cell /i int-regs +@ ] [ drop ] if ;
-
-GENERIC: reg-class-full? ( class -- ? )
-
-M: stack-params reg-class-full? drop t ;
-
-M: object reg-class-full?
-    [ reg-class-variable get ] [ param-regs length ] bi >= ;
-
-: spill-param ( reg-class -- n reg-class )
-    stack-params get
-    >r reg-size stack-params +@ r>
-    stack-params ;
-
-: fastcall-param ( reg-class -- n reg-class )
-    [ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
-
-: alloc-parameter ( parameter -- reg reg-class )
-    c-type-reg-class dup reg-class-full?
-    [ spill-param ] [ fastcall-param ] if
-    [ param-reg ] keep ;
-
-: (flatten-int-type) ( size -- )
-    cell /i "void*" c-type <repetition> % ;
-
-GENERIC: flatten-value-type ( type -- )
-
-M: object flatten-value-type , ;
-
-M: struct-type flatten-value-type ( type -- )
-    stack-size cell align (flatten-int-type) ;
-
-M: long-long-type flatten-value-type ( type -- )
-    stack-size cell align (flatten-int-type) ;
-
-: flatten-value-types ( params -- params )
-    #! Convert value type structs to consecutive void*s.
-    [
-        0 [
-            c-type
-            [ parameter-align (flatten-int-type) ] keep
-            [ stack-size cell align + ] keep
-            flatten-value-type
-        ] reduce drop
-    ] { } make ;
-
-: each-parameter ( parameters quot -- )
-    >r [ parameter-sizes nip ] keep r> 2each ; inline
-
-: reverse-each-parameter ( parameters quot -- )
-    >r [ parameter-sizes nip ] keep r> 2reverse-each ; inline
-
-: reset-freg-counts ( -- )
-    { int-regs float-regs stack-params } [ 0 swap set ] each ;
-
-: with-param-regs ( quot -- )
-    #! In quot you can call alloc-parameter
-    [ reset-freg-counts call ] with-scope ; inline
-
-: move-parameters ( node word -- )
-    #! Moves values from C stack to registers (if word is
-    #! %load-param-reg) and registers to C stack (if word is
-    #! %save-param-reg).
-    >r
-    alien-parameters
-    flatten-value-types
-    r> [ >r alloc-parameter r> execute ] curry each-parameter ;
-    inline
-
-: unbox-parameters ( offset node -- )
-    parameters>> [
-        %prepare-unbox >r over + r> unbox-parameter
-    ] reverse-each-parameter drop ;
-
-: prepare-box-struct ( node -- offset )
-    #! Return offset on C stack where to store unboxed
-    #! parameters. If the C function is returning a structure,
-    #! the first parameter is an implicit target area pointer,
-    #! so we need to use a different offset.
-    return>> dup large-struct?
-    [ heap-size %prepare-box-struct cell ] [ drop 0 ] if ;
-
-: objects>registers ( params -- )
-    #! Generate code for unboxing a list of C types, then
-    #! generate code for moving these parameters to register on
-    #! architectures where parameters are passed in registers.
-    [
-        [ prepare-box-struct ] keep
-        [ unbox-parameters ] keep
-        \ %load-param-reg move-parameters
-    ] with-param-regs ;
-
-: box-return* ( node -- )
-    return>> [ ] [ box-return ] if-void ;
-
-TUPLE: no-such-library name ;
-
-M: no-such-library summary
-    drop "Library not found" ;
-
-M: no-such-library compiler-error-type
-    drop +linkage+ ;
-
-: no-such-library ( name -- )
-    \ no-such-library boa
-    compiling-word get compiler-error ;
-
-TUPLE: no-such-symbol name ;
-
-M: no-such-symbol summary
-    drop "Symbol not found" ;
-
-M: no-such-symbol compiler-error-type
-    drop +linkage+ ;
-
-: no-such-symbol ( name -- )
-    \ no-such-symbol boa
-    compiling-word get compiler-error ;
-
-: check-dlsym ( symbols dll -- )
-    dup dll-valid? [
-        dupd [ dlsym ] curry contains?
-        [ drop ] [ no-such-symbol ] if
-    ] [
-        dll-path no-such-library drop
-    ] if ;
-
-: stdcall-mangle ( symbol node -- symbol )
-    "@"
-    swap parameters>> parameter-sizes drop
-    number>string 3append ;
-
-: alien-invoke-dlsym ( params -- symbols dll )
-    dup function>> dup pick stdcall-mangle 2array
-    swap library>> library dup [ dll>> ] when
-    2dup check-dlsym ;
-
-M: #alien-invoke generate-node
-    params>>
-    dup alien-invoke-frame [
-        end-basic-block
-        %prepare-alien-invoke
-        dup objects>registers
-        %prepare-var-args
-        dup alien-invoke-dlsym %alien-invoke
-        dup %cleanup
-        box-return*
-        iterate-next
-    ] with-stack-frame ;
-
-! #alien-indirect
-M: #alien-indirect generate-node
-    params>>
-    dup alien-invoke-frame [
-        ! Flush registers
-        end-basic-block
-        ! Save registers for GC
-        %prepare-alien-invoke
-        ! Save alien at top of stack to temporary storage
-        %prepare-alien-indirect
-        dup objects>registers
-        %prepare-var-args
-        ! Call alien in temporary storage
-        %alien-indirect
-        dup %cleanup
-        box-return*
-        iterate-next
-    ] with-stack-frame ;
-
-! #alien-callback
-: box-parameters ( params -- )
-    alien-parameters [ box-parameter ] each-parameter ;
-
-: registers>objects ( node -- )
-    [
-        dup \ %save-param-reg move-parameters
-        "nest_stacks" f %alien-invoke
-        box-parameters
-    ] with-param-regs ;
-
-TUPLE: callback-context ;
-
-: current-callback 2 getenv ;
-
-: wait-to-return ( token -- )
-    dup current-callback eq? [
-        drop
-    ] [
-        yield wait-to-return
-    ] if ;
-
-: do-callback ( quot token -- )
-    init-catchstack
-    dup 2 setenv
-    slip
-    wait-to-return ; inline
-
-: callback-return-quot ( ctype -- quot )
-    return>> {
-        { [ dup "void" = ] [ drop [ ] ] }
-        { [ dup large-struct? ] [ heap-size [ memcpy ] curry ] }
-        [ c-type c-type-unboxer-quot ]
-    } cond ;
-
-: callback-prep-quot ( params -- quot )
-    parameters>> [ c-type c-type-boxer-quot ] map spread>quot ;
-
-: wrap-callback-quot ( params -- quot )
-    [
-        [ callback-prep-quot ]
-        [ quot>> ]
-        [ callback-return-quot ] tri 3append ,
-        [ callback-context new do-callback ] %
-    ] [ ] make ;
-
-: %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ;
-
-: callback-unwind ( params -- n )
-    {
-        { [ dup abi>> "stdcall" = ] [ alien-stack-frame ] }
-        { [ dup return>> large-struct? ] [ drop 4 ] }
-        [ drop 0 ]
-    } cond ;
-
-: %callback-return ( params -- )
-    #! All the extra book-keeping for %unwind is only for x86.
-    #! On other platforms its an alias for %return.
-    dup alien-return
-    [ %unnest-stacks ] [ %callback-value ] if-void
-    callback-unwind %unwind ;
-
-: generate-callback ( params -- )
-    dup xt>> dup [
-        init-templates
-        %prologue
-        dup alien-stack-frame [
-            [ registers>objects ]
-            [ wrap-callback-quot %alien-callback ]
-            [ %callback-return ]
-            tri
-        ] with-stack-frame
-    ] with-cfg-builder ;
-
-M: #alien-callback generate-node
-    end-basic-block
-    params>> generate-callback iterate-next ;
index c1944eb9a715fa9e223d40db420cbc772f3490d7..2efd22610eb8fa4b72c2309c0da7d9c16fbeb7d7 100644 (file)
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: system ;
+USING: accessors assocs arrays generic kernel kernel.private
+math memory namespaces make sequences layouts system hashtables
+classes alien byte-arrays combinators words ;
 IN: compiler.backend
 
-! Is this structure small enough to be returned in registers?
-HOOK: struct-small-enough? cpu ( size -- ? )
+! Labels
+TUPLE: label offset ;
+
+: <label> ( -- label ) label new ;
+: define-label ( name -- ) <label> swap set ;
+: resolve-label ( label/name -- ) dup label? [ get ] unless , ;
 
 ! Mapping from register class to machine registers
 HOOK: machine-registers cpu ( -- assoc )
+
+! A pseudo-register class for parameters spilled on the stack
+SINGLETON: stack-params
+
+! Return values of this class go here
+GENERIC: return-reg ( register-class -- reg )
+
+! Sequence of registers used for parameter passing in class
+GENERIC: param-regs ( register-class -- regs )
+
+GENERIC: param-reg ( n register-class -- reg )
+
+M: object param-reg param-regs nth ;
+
+! Load a literal (immediate or indirect)
+GENERIC# load-literal 1 ( obj reg -- )
+
+HOOK: load-indirect cpu ( obj reg -- )
+
+HOOK: stack-frame cpu ( frame-size -- n )
+
+: stack-frame* ( -- n )
+    \ stack-frame get stack-frame ;
+
+! Set up caller stack frame
+HOOK: %prologue cpu ( n -- )
+
+! Tear down stack frame
+HOOK: %epilogue cpu ( n -- )
+
+! Call another word
+HOOK: %call cpu ( word -- )
+
+! Local jump for branches
+HOOK: %jump-label cpu ( label -- )
+
+! Test if vreg is 'f' or not
+HOOK: %jump-f cpu ( label reg -- )
+
+! Test if vreg is 't' or not
+HOOK: %jump-t cpu ( label reg -- )
+
+HOOK: %dispatch cpu ( -- )
+
+HOOK: %dispatch-label cpu ( word -- )
+
+! Return to caller
+HOOK: %return cpu ( -- )
+
+! Change datastack height
+HOOK: %inc-d cpu ( n -- )
+
+! Change callstack height
+HOOK: %inc-r cpu ( n -- )
+
+! Load stack into vreg
+HOOK: %peek cpu ( reg loc -- )
+
+! Store vreg to stack
+HOOK: %replace cpu ( reg loc -- )
+
+! Copy values between vregs
+HOOK: %copy cpu ( dst src -- )
+HOOK: %copy-float cpu ( dst src -- )
+
+! Box and unbox floats
+HOOK: %unbox-float cpu ( dst src -- )
+HOOK: %box-float cpu ( dst src -- )
+
+! FFI stuff
+
+! Is this integer small enough to appear in value template
+! slots?
+HOOK: small-enough? cpu ( n -- ? )
+
+! Is this structure small enough to be returned in registers?
+HOOK: struct-small-enough? cpu ( heap-size -- ? )
+
+! Do we pass explode value structs?
+HOOK: value-structs? cpu ( -- ? )
+
+! If t, fp parameters are shadowed by dummy int parameters
+HOOK: fp-shadows-int? cpu ( -- ? )
+
+HOOK: %prepare-unbox cpu ( -- )
+
+HOOK: %unbox cpu ( n reg-class func -- )
+
+HOOK: %unbox-long-long cpu ( n func -- )
+
+HOOK: %unbox-small-struct cpu ( c-type -- )
+
+HOOK: %unbox-large-struct cpu ( n c-type -- )
+
+HOOK: %box cpu ( n reg-class func -- )
+
+HOOK: %box-long-long cpu ( n func -- )
+
+HOOK: %prepare-box-struct cpu ( size -- )
+
+HOOK: %box-small-struct cpu ( c-type -- )
+
+HOOK: %box-large-struct cpu ( n c-type -- )
+
+GENERIC: %save-param-reg ( stack reg reg-class -- )
+
+GENERIC: %load-param-reg ( stack reg reg-class -- )
+
+HOOK: %prepare-alien-invoke cpu ( -- )
+
+HOOK: %prepare-var-args cpu ( -- )
+
+M: object %prepare-var-args ;
+
+HOOK: %alien-invoke cpu ( function library -- )
+
+HOOK: %cleanup cpu ( alien-node -- )
+
+HOOK: %alien-callback cpu ( quot -- )
+
+HOOK: %callback-value cpu ( ctype -- )
+
+! Return to caller with stdcall unwinding (only for x86)
+HOOK: %unwind cpu ( n -- )
+
+HOOK: %prepare-alien-indirect cpu ( -- )
+
+HOOK: %alien-indirect cpu ( -- )
+
+M: stack-params param-reg drop ;
+
+M: stack-params param-regs drop f ;
+
+M: object load-literal load-indirect ;
+
+PREDICATE: small-slot < integer cells small-enough? ;
+
+PREDICATE: small-tagged < integer tag-fixnum small-enough? ;
+
+: if-small-struct ( n size true false -- ? )
+    [ over not over struct-small-enough? and ] 2dip
+    [ [ nip ] prepose ] dip if ;
+    inline
+
+: %unbox-struct ( n c-type -- )
+    [
+        %unbox-small-struct
+    ] [
+        %unbox-large-struct
+    ] if-small-struct ;
+
+: %box-struct ( n c-type -- )
+    [
+        %box-small-struct
+    ] [
+        %box-large-struct
+    ] if-small-struct ;
+
+! Alien accessors
+HOOK: %unbox-byte-array cpu ( dst src -- )
+
+HOOK: %unbox-alien cpu ( dst src -- )
+
+HOOK: %unbox-f cpu ( dst src -- )
+
+HOOK: %unbox-any-c-ptr cpu ( dst src -- )
+
+HOOK: %box-alien cpu ( dst src -- )
+
+! Allocation
+HOOK: %allot cpu ( dst size type tag temp -- )
+
+HOOK: %write-barrier cpu ( src temp -- )
+
+! GC check
+HOOK: %gc cpu ( -- )
index 85df673839472251bf4408cdd16003c5bf426848..73fc81bd00f26c37acc6150c9b99ccf41a1d7d3c 100644 (file)
-! Copyright (C) 2008 Slava Pestov.
+! Copyright (C) 2005, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: system cpu.x86.assembler compiler.registers compiler.backend ;
+USING: alien.c-types arrays kernel kernel.private math
+namespaces sequences stack-checker.known-words system layouts
+combinators command-line io vocabs.loader accessors init
+compiler compiler.units compiler.constants compiler.codegen
+compiler.cfg.builder compiler.alien compiler.codegen.fixup
+cpu.x86 compiler.backend compiler.backend.x86 ;
 IN: compiler.backend.x86.32
 
+! We implement the FFI for Linux, OS X and Windows all at once.
+! OS X requires that the stack be 16-byte aligned, and we do
+! this on all platforms, sacrificing some stack space for
+! code simplicity.
+
 M: x86.32 machine-registers
     {
         { int-regs { EAX ECX EDX EBP EBX } }
-        { float-regs { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } }
+        { double-float-regs { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } }
     } ;
+
+M: x86.32 ds-reg ESI ;
+M: x86.32 rs-reg EDI ;
+M: x86.32 stack-reg ESP ;
+M: x86.32 stack-save-reg EDX ;
+M: x86.32 temp-reg-1 EAX ;
+M: x86.32 temp-reg-2 ECX ;
+
+M: x86.32 %alien-global 0 [] MOV rc-absolute-cell rel-dlsym ;
+
+M: x86.32 %alien-invoke (CALL) rel-dlsym ;
+
+M: x86.32 struct-small-enough? ( size -- ? )
+    heap-size { 1 2 4 8 } member?
+    os { linux netbsd solaris } member? not and ;
+
+! On x86, parameters are never passed in registers.
+M: int-regs return-reg drop EAX ;
+M: int-regs param-regs drop { } ;
+M: int-regs push-return-reg return-reg PUSH ;
+: load/store-int-return ( n reg-class -- src dst )
+    return-reg stack-reg rot [+] ;
+M: int-regs load-return-reg load/store-int-return MOV ;
+M: int-regs store-return-reg load/store-int-return swap MOV ;
+
+M: float-regs param-regs drop { } ;
+
+: FSTP ( operand size -- ) 4 = [ FSTPS ] [ FSTPL ] if ;
+
+M: float-regs push-return-reg
+    stack-reg swap reg-size [ SUB  stack-reg [] ] keep FSTP ;
+
+: FLD ( operand size -- ) 4 = [ FLDS ] [ FLDL ] if ;
+
+: load/store-float-return ( n reg-class -- op size )
+    [ stack@ ] [ reg-size ] bi* ;
+M: float-regs load-return-reg load/store-float-return FLD ;
+M: float-regs store-return-reg load/store-float-return FSTP ;
+
+: align-sub ( n -- )
+    dup 16 align swap - ESP swap SUB ;
+
+: align-add ( n -- )
+    16 align ESP swap ADD ;
+
+: with-aligned-stack ( n quot -- )
+    swap dup align-sub slip align-add ; inline
+
+M: x86.32 fixnum>slot@ 1 SHR ;
+
+M: x86.32 prepare-division CDQ ;
+
+M: x86.32 load-indirect
+    0 [] MOV rc-absolute-cell rel-literal ;
+
+M: object %load-param-reg 3drop ;
+
+M: object %save-param-reg 3drop ;
+
+: box@ ( n reg-class -- stack@ )
+    #! Used for callbacks; we want to box the values given to
+    #! us by the C function caller. Computes stack location of
+    #! nth parameter; note that we must go back one more stack
+    #! frame, since %box sets one up to call the one-arg boxer
+    #! function. The size of this stack frame so far depends on
+    #! the reg-class of the boxer's arg.
+    reg-size neg + stack-frame* + 20 + ;
+
+: (%box) ( n reg-class -- )
+    #! If n is f, push the return register onto the stack; we
+    #! are boxing a return value of a C function. If n is an
+    #! integer, push [ESP+n] on the stack; we are boxing a
+    #! parameter being passed to a callback from C.
+    over [ [ box@ ] keep [ load-return-reg ] keep ] [ nip ] if
+    push-return-reg ;
+
+M: x86.32 %box ( n reg-class func -- )
+    over reg-size [
+        >r (%box) r> f %alien-invoke
+    ] with-aligned-stack ;
+    
+: (%box-long-long) ( n -- )
+    #! If n is f, push the return registers onto the stack; we
+    #! are boxing a return value of a C function. If n is an
+    #! integer, push [ESP+n]:[ESP+n+4] on the stack; we are
+    #! boxing a parameter being passed to a callback from C.
+    [
+        int-regs box@
+        EDX over stack@ MOV
+        EAX swap cell - stack@ MOV 
+    ] when*
+    EDX PUSH
+    EAX PUSH ;
+
+M: x86.32 %box-long-long ( n func -- )
+    8 [
+        [ (%box-long-long) ] [ f %alien-invoke ] bi*
+    ] with-aligned-stack ;
+
+: struct-return@ ( size n -- n )
+    [ stack-frame* cell + + ] [ \ stack-frame get swap - ] ?if ;
+
+M: x86.32 %box-large-struct ( n c-type -- )
+    ! Compute destination address
+    heap-size
+    [ swap struct-return@ ] keep
+    ECX ESP roll [+] LEA
+    8 [
+        ! Push struct size
+        PUSH
+        ! Push destination address
+        ECX PUSH
+        ! Copy the struct from the C stack
+        "box_value_struct" f %alien-invoke
+    ] with-aligned-stack ;
+
+M: x86.32 %prepare-box-struct ( size -- )
+    ! Compute target address for value struct return
+    EAX ESP rot f struct-return@ [+] LEA
+    ! Store it as the first parameter
+    ESP [] EAX MOV ;
+
+M: x86.32 %box-small-struct ( c-type -- )
+    #! Box a <= 8-byte struct returned in EAX:EDX. OS X only.
+    12 [
+        heap-size PUSH
+        EDX PUSH
+        EAX PUSH
+        "box_small_struct" f %alien-invoke
+    ] with-aligned-stack ;
+
+M: x86.32 %prepare-unbox ( -- )
+    #! Move top of data stack to EAX.
+    EAX ESI [] MOV
+    ESI 4 SUB ;
+
+: (%unbox) ( func -- )
+    4 [
+        ! Push parameter
+        EAX PUSH
+        ! Call the unboxer
+        f %alien-invoke
+    ] with-aligned-stack ;
+
+M: x86.32 %unbox ( n reg-class func -- )
+    #! The value being unboxed must already be in EAX.
+    #! If n is f, we're unboxing a return value about to be
+    #! returned by the callback. Otherwise, we're unboxing
+    #! a parameter to a C function about to be called.
+    (%unbox)
+    ! Store the return value on the C stack
+    over [ store-return-reg ] [ 2drop ] if ;
+
+M: x86.32 %unbox-long-long ( n func -- )
+    (%unbox)
+    ! Store the return value on the C stack
+    [
+        dup stack@ EAX MOV
+        cell + stack@ EDX MOV
+    ] when* ;
+
+: %unbox-struct-1 ( -- )
+    #! Alien must be in EAX.
+    4 [
+        EAX PUSH
+        "alien_offset" f %alien-invoke
+        ! Load first cell
+        EAX EAX [] MOV
+    ] with-aligned-stack ;
+
+: %unbox-struct-2 ( -- )
+    #! Alien must be in EAX.
+    4 [
+        EAX PUSH
+        "alien_offset" f %alien-invoke
+        ! Load second cell
+        EDX EAX 4 [+] MOV
+        ! Load first cell
+        EAX EAX [] MOV
+    ] with-aligned-stack ;
+
+M: x86 %unbox-small-struct ( size -- )
+    #! Alien must be in EAX.
+    heap-size cell align cell /i {
+        { 1 [ %unbox-struct-1 ] }
+        { 2 [ %unbox-struct-2 ] }
+    } case ;
+
+M: x86.32 %unbox-large-struct ( n c-type -- )
+    #! Alien must be in EAX.
+    heap-size
+    ! Compute destination address
+    ECX ESP roll [+] LEA
+    12 [
+        ! Push struct size
+        PUSH
+        ! Push destination address
+        ECX PUSH
+        ! Push source address
+        EAX PUSH
+        ! Copy the struct to the stack
+        "to_value_struct" f %alien-invoke
+    ] with-aligned-stack ;
+
+M: x86.32 %prepare-alien-indirect ( -- )
+    "unbox_alien" f %alien-invoke
+    cell temp@ EAX MOV ;
+
+M: x86.32 %alien-indirect ( -- )
+    cell temp@ CALL ;
+
+M: x86.32 %alien-callback ( quot -- )
+    4 [
+        EAX load-indirect
+        EAX PUSH
+        "c_to_factor" f %alien-invoke
+    ] with-aligned-stack ;
+
+M: x86.32 %callback-value ( ctype -- )
+    ! Align C stack
+    ESP 12 SUB
+    ! Save top of data stack
+    %prepare-unbox
+    EAX PUSH
+    ! Restore data/call/retain stacks
+    "unnest_stacks" f %alien-invoke
+    ! Place top of data stack in EAX
+    EAX POP
+    ! Restore C stack
+    ESP 12 ADD
+    ! Unbox EAX
+    unbox-return ;
+
+M: x86.32 %cleanup ( alien-node -- )
+    #! a) If we just called an stdcall function in Windows, it
+    #! cleaned up the stack frame for us. But we don't want that
+    #! so we 'undo' the cleanup since we do that in %epilogue.
+    #! b) If we just called a function returning a struct, we
+    #! have to fix ESP.
+    {
+        {
+            [ dup abi>> "stdcall" = ]
+            [ alien-stack-frame ESP swap SUB ]
+        } {
+            [ dup return>> large-struct? ]
+            [ drop EAX PUSH ]
+        }
+        [ drop ]
+    } cond ;
+
+M: x86.32 %unwind ( n -- ) RET ;
+
+os windows? [
+    cell "longlong" c-type (>>align)
+    cell "ulonglong" c-type (>>align)
+    4 "double" c-type (>>align)
+] unless
+
+: (sse2?) ( -- ? ) "Intrinsic" throw ;
+
+<<
+
+\ (sse2?) [
+    { EAX EBX ECX EDX } [ PUSH ] each
+    EAX 1 MOV
+    CPUID
+    EDX 26 SHR
+    EDX 1 AND
+    { EAX EBX ECX EDX } [ POP ] each
+    JE
+] { } define-if-intrinsic
+
+\ (sse2?) { } { object } define-primitive
+
+>>
+
+: sse2? ( -- ? ) (sse2?) ;
+
+"-no-sse2" cli-args member? [
+    "Checking if your CPU supports SSE2..." print flush
+    [ optimized-recompile-hook ] recompile-hook [
+        [ sse2? ] compile-call
+    ] with-variable
+    [
+        " - yes" print
+        "compiler.backend.x86.sse2" require
+        [
+            sse2? [
+                "This image was built to use SSE2, which your CPU does not support." print
+                "You will need to bootstrap Factor again." print
+                flush
+                1 exit
+            ] unless
+        ] "compiler.backend.x86" add-init-hook
+    ] [
+        " - no" print
+    ] if
+] unless
diff --git a/unfinished/compiler/backend/x86/64/64.factor b/unfinished/compiler/backend/x86/64/64.factor
new file mode 100644 (file)
index 0000000..c8760e5
--- /dev/null
@@ -0,0 +1,226 @@
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types arrays kernel kernel.private math
+namespaces make sequences system layouts alien alien.accessors
+alien.structs slots splitting assocs combinators
+cpu.x86 compiler.codegen compiler.constants
+compiler.codegen.fixup compiler.cfg.registers compiler.backend
+compiler.backend.x86 compiler.backend.x86.sse2 ;
+IN: compiler.backend.x86.64
+
+M: x86.64 machine-registers
+    {
+        { int-regs { RAX RCX RDX RBP RSI RDI R8 R9 R10 R11 R12 R13 } }
+        { double-float-regs {
+            XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
+            XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
+        } }
+    } ;
+
+M: x86.64 ds-reg R14 ;
+M: x86.64 rs-reg R15 ;
+M: x86.64 stack-reg RSP ;
+M: x86.64 stack-save-reg RSI ;
+M: x86.64 temp-reg-1 RAX ;
+M: x86.64 temp-reg-2 RCX ;
+
+M: int-regs return-reg drop RAX ;
+M: int-regs param-regs drop { RDI RSI RDX RCX R8 R9 } ;
+
+M: float-regs return-reg drop XMM0 ;
+
+M: float-regs param-regs
+    drop { XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7 } ;
+
+M: x86.64 fixnum>slot@ drop ;
+
+M: x86.64 prepare-division CQO ;
+
+M: x86.64 load-indirect ( literal reg -- )
+    0 [] MOV rc-relative rel-literal ;
+
+M: stack-params %load-param-reg
+    drop
+    >r R11 swap stack@ MOV
+    r> stack@ R11 MOV ;
+
+M: stack-params %save-param-reg
+    >r stack-frame* + cell + swap r> %load-param-reg ;
+
+: with-return-regs ( quot -- )
+    [
+        V{ RDX RAX } clone int-regs set
+        V{ XMM1 XMM0 } clone float-regs set
+        call
+    ] with-scope ; inline
+
+! The ABI for passing structs by value is pretty messed up
+<< "void*" c-type clone "__stack_value" define-primitive-type
+stack-params "__stack_value" c-type (>>reg-class) >>
+
+: struct-types&offset ( struct-type -- pairs )
+    fields>> [
+        [ type>> ] [ offset>> ] bi 2array
+    ] map ;
+
+: split-struct ( pairs -- seq )
+    [
+        [ 8 mod zero? [ t , ] when , ] assoc-each
+    ] { } make { t } split harvest ;
+
+: flatten-small-struct ( c-type -- seq )
+    struct-types&offset split-struct [
+        [ c-type c-type-reg-class ] map
+        int-regs swap member? "void*" "double" ? c-type
+    ] map ;
+
+: flatten-large-struct ( c-type -- seq )
+    heap-size cell align
+    cell /i "__stack_value" c-type <repetition> ;
+
+M: struct-type flatten-value-type ( type -- seq )
+    dup heap-size 16 > [
+        flatten-large-struct
+    ] [
+        flatten-small-struct
+    ] if ;
+
+M: x86.64 %prepare-unbox ( -- )
+    ! First parameter is top of stack
+    RDI R14 [] MOV
+    R14 cell SUB ;
+
+M: x86.64 %unbox ( n reg-class func -- )
+    ! Call the unboxer
+    f %alien-invoke
+    ! Store the return value on the C stack
+    over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
+
+M: x86.64 %unbox-long-long ( n func -- )
+    int-regs swap %unbox ;
+
+: %unbox-struct-field ( c-type i -- )
+    ! Alien must be in RDI.
+    RDI swap cells [+] swap reg-class>> {
+        { int-regs [ int-regs get pop swap MOV ] }
+        { double-float-regs [ float-regs get pop swap MOVSD ] }
+    } case ;
+
+M: x86.64 %unbox-small-struct ( c-type -- )
+    ! Alien must be in RDI.
+    "alien_offset" f %alien-invoke
+    ! Move alien_offset() return value to RDI so that we don't
+    ! clobber it.
+    RDI RAX MOV
+    [
+        flatten-small-struct [ %unbox-struct-field ] each-index
+    ] with-return-regs ;
+
+M: x86.64 %unbox-large-struct ( n c-type -- )
+    ! Source is in RDI
+    heap-size
+    ! Load destination address
+    RSI RSP roll [+] LEA
+    ! Load structure size
+    RDX swap MOV
+    ! Copy the struct to the C stack
+    "to_value_struct" f %alien-invoke ;
+
+: load-return-value ( reg-class -- )
+    0 over param-reg swap return-reg
+    2dup eq? [ 2drop ] [ MOV ] if ;
+
+M: x86.64 %box ( n reg-class func -- )
+    rot [
+        rot [ 0 swap param-reg ] keep %load-param-reg
+    ] [
+        swap load-return-value
+    ] if*
+    f %alien-invoke ;
+
+M: x86.64 %box-long-long ( n func -- )
+    int-regs swap %box ;
+
+M: x86.64 struct-small-enough? ( size -- ? )
+    heap-size 2 cells <= ;
+
+: box-struct-field@ ( i -- operand ) RSP swap 1+ cells [+] ;
+
+: %box-struct-field ( c-type i -- )
+    box-struct-field@ swap reg-class>> {
+        { int-regs [ int-regs get pop MOV ] }
+        { double-float-regs [ float-regs get pop MOVSD ] }
+    } case ;
+
+M: x86.64 %box-small-struct ( c-type -- )
+    #! Box a <= 16-byte struct.
+    [
+        [ flatten-small-struct [ %box-struct-field ] each-index ]
+        [ RDX swap heap-size MOV ] bi
+        RDI 0 box-struct-field@ MOV
+        RSI 1 box-struct-field@ MOV
+        "box_small_struct" f %alien-invoke
+    ] with-return-regs ;
+
+: struct-return@ ( size n -- n )
+    [ ] [ \ stack-frame get swap - ] ?if ;
+
+M: x86.64 %box-large-struct ( n c-type -- )
+    ! Struct size is parameter 2
+    heap-size
+    RSI over MOV
+    ! Compute destination address
+    swap struct-return@ RDI RSP rot [+] LEA
+    ! Copy the struct from the C stack
+    "box_value_struct" f %alien-invoke ;
+
+M: x86.64 %prepare-box-struct ( size -- )
+    ! Compute target address for value struct return
+    RAX RSP rot f struct-return@ [+] LEA
+    RSP 0 [+] RAX MOV ;
+
+M: x86.64 %prepare-var-args RAX RAX XOR ;
+
+M: x86.64 %alien-global
+    [ 0 MOV rc-absolute-cell rel-dlsym ] [ dup [] MOV ] bi ;
+
+M: x86.64 %alien-invoke
+    R11 0 MOV
+    rc-absolute-cell rel-dlsym
+    R11 CALL ;
+
+M: x86.64 %prepare-alien-indirect ( -- )
+    "unbox_alien" f %alien-invoke
+    cell temp@ RAX MOV ;
+
+M: x86.64 %alien-indirect ( -- )
+    cell temp@ CALL ;
+
+M: x86.64 %alien-callback ( quot -- )
+    RDI load-indirect "c_to_factor" f %alien-invoke ;
+
+M: x86.64 %callback-value ( ctype -- )
+    ! Save top of data stack
+    %prepare-unbox
+    ! Put former top of data stack in RDI
+    cell temp@ RDI MOV
+    ! Restore data/call/retain stacks
+    "unnest_stacks" f %alien-invoke
+    ! Put former top of data stack in RDI
+    RDI cell temp@ MOV
+    ! Unbox former top of data stack to return registers
+    unbox-return ;
+
+M: x86.64 %cleanup ( alien-node -- ) drop ;
+
+M: x86.64 %unwind ( n -- ) drop 0 RET ;
+
+USE: cpu.x86.intrinsics
+
+! On 64-bit systems, the result of reading 4 bytes from memory
+! is a fixnum.
+\ alien-unsigned-4 small-reg-32 define-unsigned-getter
+\ set-alien-unsigned-4 small-reg-32 define-setter
+
+\ alien-signed-4 small-reg-32 define-signed-getter
+\ set-alien-signed-4 small-reg-32 define-setter
diff --git a/unfinished/compiler/backend/x86/sse2/sse2.factor b/unfinished/compiler/backend/x86/sse2/sse2.factor
new file mode 100644 (file)
index 0000000..4364a8c
--- /dev/null
@@ -0,0 +1,106 @@
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.accessors arrays generic kernel system
+kernel.private math math.private memory namespaces sequences
+words math.floats.private layouts quotations locals cpu.x86
+compiler.codegen compiler.cfg.templates compiler.cfg.builder
+compiler.cfg.registers compiler.constants compiler.backend
+compiler.backend.x86 ;
+IN: compiler.backend.x86.sse2
+
+M:: x86 %box-float ( dst src temp -- )
+    #! Only called by pentium4 backend, uses SSE2 instruction
+    dst 16 float float temp %allot
+    dst 8 float tag-number - [+] src MOVSD ;
+
+M: x86 %unbox-float ( dst src -- )
+    float-offset [+] MOVSD ;
+
+: define-float-op ( word op -- )
+    [ "x" operand "y" operand ] swap suffix T{ template
+        { input { { float "x" } { float "y" } } }
+        { output { "x" } }
+    } define-intrinsic ;
+
+{
+    { float+ ADDSD }
+    { float- SUBSD }
+    { float* MULSD }
+    { float/f DIVSD }
+} [
+    first2 define-float-op
+] each
+
+: define-float-jump ( word op -- )
+    [ "x" operand "y" operand UCOMISD ] swap suffix
+    { { float "x" } { float "y" } } define-if-intrinsic ;
+
+{
+    { float< JAE }
+    { float<= JA }
+    { float> JBE }
+    { float>= JB }
+    { float= JNE }
+} [
+    first2 define-float-jump
+] each
+
+\ float>fixnum [
+    "out" operand "in" operand CVTTSD2SI
+    "out" operand tag-bits get SHL
+] T{ template
+    { input { { float "in" } } }
+    { scratch { { f "out" } } }
+    { output { "out" } }
+} define-intrinsic
+
+\ fixnum>float [
+    "in" operand %untag-fixnum
+    "out" operand "in" operand CVTSI2SD
+] T{ template
+    { input { { f "in" } } }
+    { scratch { { float "out" } } }
+    { output { "out" } }
+    { clobber { "in" } }
+} define-intrinsic
+
+: alien-float-get-template
+    T{ template
+        { input {
+            { unboxed-c-ptr "alien" c-ptr }
+            { f "offset" fixnum }
+        } }
+        { scratch { { float "value" } } }
+        { output { "value" } }
+        { clobber { "offset" } }
+    } ;
+
+: alien-float-set-template
+    T{ template
+        { input {
+            { float "value" float }
+            { unboxed-c-ptr "alien" c-ptr }
+            { f "offset" fixnum }
+        } }
+        { clobber { "offset" } }
+    } ;
+
+: define-alien-float-intrinsics ( word get-quot word set-quot -- )
+    [ "value" operand swap %alien-accessor ] curry
+    alien-float-set-template
+    define-intrinsic
+    [ "value" operand swap %alien-accessor ] curry
+    alien-float-get-template
+    define-intrinsic ;
+
+\ alien-double
+[ MOVSD ]
+\ set-alien-double
+[ swap MOVSD ]
+define-alien-float-intrinsics
+
+\ alien-float
+[ dupd MOVSS dup CVTSS2SD ]
+\ set-alien-float
+[ swap dup dup CVTSD2SS MOVSS ]
+define-alien-float-intrinsics
diff --git a/unfinished/compiler/backend/x86/x86.factor b/unfinished/compiler/backend/x86/x86.factor
new file mode 100644 (file)
index 0000000..da0586a
--- /dev/null
@@ -0,0 +1,643 @@
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays byte-arrays alien.accessors
+compiler.backend kernel kernel.private math memory namespaces
+make sequences words system layouts combinators math.order
+math.private alien alien.c-types slots.private cpu.x86
+cpu.x86.private locals compiler.backend compiler.codegen.fixup
+compiler.constants compiler.intrinsics compiler.cfg.builder
+compiler.cfg.registers compiler.cfg.stacks
+compiler.cfg.templates compiler.codegen ;
+IN: compiler.backend.x86
+
+HOOK: ds-reg cpu ( -- reg )
+HOOK: rs-reg cpu ( -- reg )
+HOOK: stack-reg cpu ( -- reg )
+HOOK: stack-save-reg cpu ( -- reg )
+
+: stack@ ( n -- op ) stack-reg swap [+] ;
+
+: reg-stack ( n reg -- op ) swap cells neg [+] ;
+
+GENERIC: loc>operand ( loc -- operand )
+
+M: ds-loc loc>operand n>> ds-reg reg-stack ;
+M: rs-loc loc>operand n>> rs-reg reg-stack ;
+
+M: int-regs %save-param-reg drop >r stack@ r> MOV ;
+M: int-regs %load-param-reg drop swap stack@ MOV ;
+
+GENERIC: MOVSS/D ( dst src reg-class -- )
+
+M: single-float-regs MOVSS/D drop MOVSS ;
+M: double-float-regs MOVSS/D drop MOVSD ;
+
+M: float-regs %save-param-reg >r >r stack@ r> r> MOVSS/D ;
+M: float-regs %load-param-reg >r swap stack@ r> MOVSS/D ;
+
+GENERIC: push-return-reg ( reg-class -- )
+GENERIC: load-return-reg ( stack@ reg-class -- )
+GENERIC: store-return-reg ( stack@ reg-class -- )
+
+! Only used by inline allocation
+HOOK: temp-reg-1 cpu ( -- reg )
+HOOK: temp-reg-2 cpu ( -- reg )
+
+HOOK: fixnum>slot@ cpu ( op -- )
+
+HOOK: prepare-division cpu ( -- )
+
+M: f load-literal
+    \ f tag-number MOV drop ;
+
+M: fixnum load-literal
+    swap tag-fixnum MOV ;
+
+M: x86 stack-frame ( n -- i )
+    3 cells + 16 align cell - ;
+
+: factor-area-size ( -- n ) 4 cells ;
+
+M: x86 %prologue ( n -- )
+    temp-reg-1 0 MOV rc-absolute-cell rel-this
+    dup cell + PUSH
+    temp-reg-1 PUSH
+    stack-reg swap 2 cells - SUB ;
+
+M: x86 %epilogue ( n -- )
+    stack-reg swap ADD ;
+
+HOOK: %alien-global cpu ( symbol dll register -- )
+
+M: x86 %prepare-alien-invoke
+    #! Save Factor stack pointers in case the C code calls a
+    #! callback which does a GC, which must reliably trace
+    #! all roots.
+    "stack_chain" f temp-reg-1 %alien-global
+    temp-reg-1 [] stack-reg MOV
+    temp-reg-1 [] cell SUB
+    temp-reg-1 2 cells [+] ds-reg MOV
+    temp-reg-1 3 cells [+] rs-reg MOV ;
+
+M: x86 %call ( label -- ) CALL ;
+
+M: x86 %jump-label ( label -- ) JMP ;
+
+M: x86 %jump-f ( label vreg -- ) \ f tag-number CMP JE ;
+
+M: x86 %jump-t ( label vreg -- ) \ f tag-number CMP JNE ;
+
+: code-alignment ( -- n )
+    building get length dup cell align swap - ;
+
+: align-code ( n -- )
+    0 <repetition> % ;
+
+M:: x86 %dispatch ( src temp -- )
+    ! Load jump table base. We use a temporary register
+    ! since on AMD64 we have to load a 64-bit immediate. On
+    ! x86, this is redundant.
+    ! Untag and multiply to get a jump table offset
+    src fixnum>slot@
+    ! Add jump table base
+    temp HEX: ffffffff MOV rc-absolute-cell rel-here
+    src temp ADD
+    src HEX: 7f [+] JMP
+    ! Fix up the displacement above
+    code-alignment dup bootstrap-cell 8 = 15 9 ? +
+    building get dup pop* push
+    align-code ;
+
+M: x86 %dispatch-label ( word -- )
+    0 cell, rc-absolute-cell rel-word ;
+
+M: x86 %peek loc>operand MOV ;
+
+M: x86 %replace loc>operand swap MOV ;
+
+: (%inc) ( n reg -- ) swap cells dup 0 > [ ADD ] [ neg SUB ] if ;
+
+M: x86 %inc-d ( n -- ) ds-reg (%inc) ;
+
+M: x86 %inc-r ( n -- ) rs-reg (%inc) ;
+
+M: x86 fp-shadows-int? ( -- ? ) f ;
+
+M: x86 value-structs? t ;
+
+M: x86 small-enough? ( n -- ? )
+    HEX: -80000000 HEX: 7fffffff between? ;
+
+: %untag ( reg -- ) tag-mask get bitnot AND ;
+
+: %untag-fixnum ( reg -- ) tag-bits get SAR ;
+
+: %tag-fixnum ( reg -- ) tag-bits get SHL ;
+
+: temp@ ( n -- op ) stack-reg \ stack-frame get rot - [+] ;
+
+M: x86 %return ( -- ) 0 %unwind ;
+
+! Alien intrinsics
+M: x86 %unbox-byte-array ( dst src -- )
+    byte-array-offset [+] LEA ;
+
+M: x86 %unbox-alien ( dst src -- )
+    alien-offset [+] MOV ;
+
+M: x86 %unbox-f ( dst src -- )
+    drop 0 MOV ;
+
+M: x86 %unbox-any-c-ptr ( dst src -- )
+    { "is-byte-array" "end" "start" } [ define-label ] each
+    ! Address is computed in ds-reg
+    ds-reg PUSH
+    ds-reg 0 MOV
+    ! Object is stored in ds-reg
+    rs-reg PUSH
+    rs-reg swap MOV
+    ! We come back here with displaced aliens
+    "start" resolve-label
+    ! Is the object f?
+    rs-reg \ f tag-number CMP
+    "end" get JE
+    ! Is the object an alien?
+    rs-reg header-offset [+] alien type-number tag-fixnum CMP
+    "is-byte-array" get JNE
+    ! If so, load the offset and add it to the address
+    ds-reg rs-reg alien-offset [+] ADD
+    ! Now recurse on the underlying alien
+    rs-reg rs-reg underlying-alien-offset [+] MOV
+    "start" get JMP
+    "is-byte-array" resolve-label
+    ! Add byte array address to address being computed
+    ds-reg rs-reg ADD
+    ! Add an offset to start of byte array's data
+    ds-reg byte-array-offset ADD
+    "end" resolve-label
+    ! Done, store address in destination register
+    ds-reg MOV
+    ! Restore rs-reg
+    rs-reg POP
+    ! Restore ds-reg
+    ds-reg POP ;
+
+M:: x86 %write-barrier ( src temp -- )
+    #! Mark the card pointed to by vreg.
+    ! Mark the card
+    src card-bits SHR
+    "cards_offset" f temp %alien-global
+    temp temp [+] card-mark <byte> MOV
+
+    ! Mark the card deck
+    temp deck-bits card-bits - SHR
+    "decks_offset" f temp %alien-global
+    temp temp [+] card-mark <byte> MOV ;
+
+: load-zone-ptr ( reg -- )
+    #! Load pointer to start of zone array
+    0 MOV "nursery" f rc-absolute-cell rel-dlsym ;
+
+: load-allot-ptr ( temp -- )
+    [ load-zone-ptr ] [ PUSH ] [ dup cell [+] MOV ] tri ;
+
+: inc-allot-ptr ( n temp -- )
+    [ POP ] [ cell [+] swap 8 align ADD ] bi ;
+
+: store-header ( temp type -- )
+    [ 0 [+] ] [ type-number tag-fixnum ] bi* MOV ;
+
+: store-tagged ( dst temp tag -- )
+    dupd tag-number OR MOV ;
+
+M:: x86 %allot ( dst size type tag temp -- )
+    temp load-allot-ptr
+    temp type store-header
+    temp size inc-allot-ptr
+    dst temp store-tagged ;
+
+M: x86 %gc ( -- )
+    "end" define-label
+    temp-reg-1 load-zone-ptr
+    temp-reg-2 temp-reg-1 cell [+] MOV
+    temp-reg-2 1024 ADD
+    temp-reg-1 temp-reg-1 3 cells [+] MOV
+    temp-reg-2 temp-reg-1 CMP
+    "end" get JLE
+    %prepare-alien-invoke
+    "minor_gc" f %alien-invoke
+    "end" resolve-label ;
+
+: bignum@ ( reg n -- op ) cells bignum tag-number - [+] ;
+
+:: %allot-bignum-signed-1 ( dst src temp -- )
+    #! on entry, inreg is a signed 32-bit quantity
+    #! exits with tagged ptr to bignum in outreg
+    #! 1 cell header, 1 cell length, 1 cell sign, + digits
+    #! length is the # of digits + sign
+    [
+        { "end" "nonzero" "positive" "store" } [ define-label ] each
+        src 0 CMP ! is it zero?
+        "nonzero" get JNE
+        ! Use cached zero value
+        0 >bignum dst load-indirect
+        "end" get JMP
+        "nonzero" resolve-label
+        ! Allocate a bignum
+        dst 4 cells bignum bignum temp %allot
+        ! Write length
+        dst 1 bignum@ 2 MOV
+        ! Test sign
+        src 0 CMP
+        "positive" get JGE
+        dst 2 bignum@ 1 MOV ! negative sign
+        src NEG
+        "store" get JMP
+        "positive" resolve-label
+        dst 2 bignum@ 0 MOV ! positive sign
+        "store" resolve-label
+        dst 3 bignum@ src MOV
+        "end" resolve-label
+    ] with-scope ;
+
+: alien@ ( reg n -- op ) cells object tag-number - [+] ;
+
+M:: x86 %box-alien ( dst src temp -- )
+    [
+        { "end" "f" } [ define-label ] each
+        src 0 CMP
+        "f" get JE
+        dst 4 cells alien object temp %allot
+        dst 1 alien@ \ f tag-number MOV
+        dst 2 alien@ \ f tag-number MOV
+        ! Store src in alien-offset slot
+        dst 3 alien@ src MOV
+        "end" get JMP
+        "f" resolve-label
+        \ f tag-number MOV
+        "end" resolve-label
+    ] with-scope ;
+
+! Type checks
+\ tag [
+    "in" operand tag-mask get AND
+    "in" operand %tag-fixnum
+] T{ template
+    { input { { f "in" } } }
+    { output { "in" } }
+} define-intrinsic
+
+! Slots
+: %slot-literal-known-tag ( -- op )
+    "obj" operand
+    "n" get cells
+    "obj" operand-tag - [+] ;
+
+: %slot-literal-any-tag ( -- op )
+    "obj" operand %untag
+    "obj" operand "n" get cells [+] ;
+
+: %slot-any ( -- op )
+    "obj" operand %untag
+    "n" operand fixnum>slot@
+    "obj" operand "n" operand [+] ;
+
+\ slot {
+    ! Slot number is literal and the tag is known
+    {
+        [ "val" operand %slot-literal-known-tag MOV ] T{ template
+            { input { { f "obj" known-tag } { small-slot "n" } } }
+            { scratch { { f "val" } } }
+            { output { "val" } }
+        }
+    }
+    ! Slot number is literal
+    {
+        [ "obj" operand %slot-literal-any-tag MOV ] T{ template
+            { input { { f "obj" } { small-slot "n" } } }
+            { output { "obj" } }
+        }
+    }
+    ! Slot number in a register
+    {
+        [ "obj" operand %slot-any MOV ] T{ template
+            { input { { f "obj" } { f "n" } } }
+            { output { "obj" } }
+            { clobber { "n" } }
+        }
+    }
+} define-intrinsics
+
+\ (set-slot) {
+    ! Slot number is literal and the tag is known
+    {
+        [ %slot-literal-known-tag "val" operand MOV ] T{ template
+            { input { { f "val" } { f "obj" known-tag } { small-slot "n" } } }
+            { scratch { { f "scratch" } } }
+            { clobber { "obj" } }
+        }
+    }
+    ! Slot number is literal
+    {
+        [ %slot-literal-any-tag "val" operand MOV ] T{ template
+            { input { { f "val" } { f "obj" } { small-slot "n" } } }
+            { scratch { { f "scratch" } } }
+            { clobber { "obj" } }
+        }
+    }
+    ! Slot number in a register
+    {
+        [ %slot-any "val" operand MOV ] T{ template
+            { input { { f "val" } { f "obj" } { f "n" } } }
+            { scratch { { f "scratch" } } }
+            { clobber { "obj" "n" } }
+        }
+    }
+} define-intrinsics
+
+! Sometimes, we need to do stuff with operands which are
+! less than the word size. Instead of teaching the register
+! allocator about the different sized registers, with all
+! the complexity this entails, we just push/pop a register
+! which is guaranteed to be unused (the tempreg)
+: small-reg cell 8 = RBX EBX ? ; inline
+: small-reg-8 BL ; inline
+: small-reg-16 BX ; inline
+: small-reg-32 EBX ; inline
+
+! Fixnums
+: fixnum-op ( op hash -- pair )
+    >r [ "x" operand "y" operand ] swap suffix r> 2array ;
+
+: fixnum-value-op ( op -- pair )
+    T{ template
+        { input { { f "x" } { small-tagged "y" } } }
+        { output { "x" } }
+    } fixnum-op ;
+
+: fixnum-register-op ( op -- pair )
+    T{ template
+        { input { { f "x" } { f "y" } } }
+        { output { "x" } }
+    } fixnum-op ;
+
+: define-fixnum-op ( word op -- )
+    [ fixnum-value-op ] keep fixnum-register-op
+    2array define-intrinsics ;
+
+{
+    { fixnum+fast ADD }
+    { fixnum-fast SUB }
+    { fixnum-bitand AND }
+    { fixnum-bitor OR }
+    { fixnum-bitxor XOR }
+} [
+    first2 define-fixnum-op
+] each
+
+\ fixnum-bitnot [
+    "x" operand NOT
+    "x" operand tag-mask get XOR
+] T{ template
+    { input { { f "x" } } }
+    { output { "x" } }
+} define-intrinsic
+
+\ fixnum*fast {
+    {
+        [
+            "x" operand "y" get IMUL2
+        ] T{ template
+            { input { { f "x" } { [ small-tagged? ] "y" } } }
+            { output { "x" } }
+        }
+    } {
+        [
+            "out" operand "x" operand MOV
+            "out" operand %untag-fixnum
+            "y" operand "out" operand IMUL2
+        ] T{ template
+            { input { { f "x" } { f "y" } } }
+            { scratch { { f "out" } } }
+            { output { "out" } }
+        }
+    }
+} define-intrinsics
+
+: %untag-fixnums ( seq -- )
+    [ %untag-fixnum ] unique-operands ;
+
+\ fixnum-shift-fast [
+    "x" operand "y" get
+    dup 0 < [ neg SAR ] [ SHL ] if
+    ! Mask off low bits
+    "x" operand %untag
+] T{ template
+    { input { { f "x" } { [ ] "y" } } }
+    { output { "x" } }
+} define-intrinsic
+
+: overflow-check ( word -- )
+    "end" define-label
+    "z" operand "x" operand MOV
+    "z" operand "y" operand pick execute
+    ! If the previous arithmetic operation overflowed, then we
+    ! turn the result into a bignum and leave it in EAX.
+    "end" get JNO
+    ! There was an overflow. Recompute the original operand.
+    { "y" "x" } %untag-fixnums
+    "x" operand "y" operand rot execute
+    "z" operand "x" operand "y" operand %allot-bignum-signed-1
+    "end" resolve-label ; inline
+
+: overflow-template ( word insn -- )
+    [ overflow-check ] curry T{ template
+        { input { { f "x" } { f "y" } } }
+        { scratch { { f "z" } } }
+        { output { "z" } }
+        { clobber { "x" "y" } }
+        { gc t }
+    } define-intrinsic ;
+
+\ fixnum+ \ ADD overflow-template
+\ fixnum- \ SUB overflow-template
+
+: fixnum-jump ( op inputs -- pair )
+    >r [ "x" operand "y" operand CMP ] swap suffix r> 2array ;
+
+: fixnum-value-jump ( op -- pair )
+    { { f "x" } { [ small-tagged? ] "y" } } fixnum-jump ;
+
+: fixnum-register-jump ( op -- pair )
+    { { f "x" } { f "y" } } fixnum-jump ;
+
+: define-fixnum-jump ( word op -- )
+    [ fixnum-value-jump ] keep fixnum-register-jump
+    2array define-if-intrinsics ;
+
+{
+    { fixnum< JL }
+    { fixnum<= JLE }
+    { fixnum> JG }
+    { fixnum>= JGE }
+    { eq? JE }
+} [
+    first2 define-fixnum-jump
+] each
+
+\ fixnum>bignum [
+    "x" operand %untag-fixnum
+    "x" operand dup "scratch" operand %allot-bignum-signed-1
+] T{ template
+    { input { { f "x" } } }
+    { scratch { { f "scratch" } } }
+    { output { "x" } }
+    { gc t }
+} define-intrinsic
+
+\ bignum>fixnum [
+    "nonzero" define-label
+    "positive" define-label
+    "end" define-label
+    "x" operand %untag
+    "y" operand "x" operand cell [+] MOV
+     ! if the length is 1, its just the sign and nothing else,
+     ! so output 0
+    "y" operand 1 tag-fixnum CMP
+    "nonzero" get JNE
+    "y" operand 0 MOV
+    "end" get JMP
+    "nonzero" resolve-label
+    ! load the value
+    "y" operand "x" operand 3 cells [+] MOV
+    ! load the sign
+    "x" operand "x" operand 2 cells [+] MOV
+    ! is the sign negative?
+    "x" operand 0 CMP
+    "positive" get JE
+    "y" operand -1 IMUL2
+    "positive" resolve-label
+    "y" operand 3 SHL
+    "end" resolve-label
+] T{ template
+    { input { { f "x" } } }
+    { scratch { { f "y" } } }
+    { clobber { "x" } }
+    { output { "y" } }
+} define-intrinsic
+
+! User environment
+: %userenv ( -- )
+    "x" operand 0 MOV
+    "userenv" f rc-absolute-cell rel-dlsym
+    "n" operand fixnum>slot@
+    "n" operand "x" operand ADD ;
+
+\ getenv [
+    %userenv  "n" operand dup [] MOV
+] T{ template
+    { input { { f "n" } } }
+    { scratch { { f "x" } } }
+    { output { "n" } }
+} define-intrinsic
+
+\ setenv [
+    %userenv  "n" operand [] "val" operand MOV
+] T{ template
+    { input { { f "val" } { f "n" } } }
+    { scratch { { f "x" } } }
+    { clobber { "n" } }
+} define-intrinsic
+
+! Alien intrinsics
+: %alien-accessor ( quot -- )
+    "offset" operand %untag-fixnum
+    "offset" operand "alien" operand ADD
+    "offset" operand [] swap call ; inline
+
+: %alien-integer-get ( quot reg -- )
+    small-reg PUSH
+    swap %alien-accessor
+    "value" operand small-reg MOV
+    "value" operand %tag-fixnum
+    small-reg POP ; inline
+
+: alien-integer-get-template
+    T{ template
+        { input {
+            { unboxed-c-ptr "alien" c-ptr }
+            { f "offset" fixnum }
+        } }
+        { scratch { { f "value" } } }
+        { output { "value" } }
+        { clobber { "offset" } }
+    } ;
+
+: define-getter ( word quot reg -- )
+    [ %alien-integer-get ] 2curry
+    alien-integer-get-template
+    define-intrinsic ;
+
+: define-unsigned-getter ( word reg -- )
+    [ small-reg dup XOR MOV ] swap define-getter ;
+
+: define-signed-getter ( word reg -- )
+    [ [ >r MOV small-reg r> MOVSX ] curry ] keep define-getter ;
+
+: %alien-integer-set ( quot reg -- )
+    small-reg PUSH
+    small-reg "value" operand MOV
+    small-reg %untag-fixnum
+    swap %alien-accessor
+    small-reg POP ; inline
+
+: alien-integer-set-template
+    T{ template
+        { input {
+            { f "value" fixnum }
+            { unboxed-c-ptr "alien" c-ptr }
+            { f "offset" fixnum }
+        } }
+        { clobber { "value" "offset" } }
+    } ;
+
+: define-setter ( word reg -- )
+    [ swap MOV ] swap
+    [ %alien-integer-set ] 2curry
+    alien-integer-set-template
+    define-intrinsic ;
+
+\ alien-unsigned-1 small-reg-8 define-unsigned-getter
+\ set-alien-unsigned-1 small-reg-8 define-setter
+
+\ alien-signed-1 small-reg-8 define-signed-getter
+\ set-alien-signed-1 small-reg-8 define-setter
+
+\ alien-unsigned-2 small-reg-16 define-unsigned-getter
+\ set-alien-unsigned-2 small-reg-16 define-setter
+
+\ alien-signed-2 small-reg-16 define-signed-getter
+\ set-alien-signed-2 small-reg-16 define-setter
+
+\ alien-cell [
+    "value" operand [ MOV ] %alien-accessor
+] T{ template
+    { input {
+        { unboxed-c-ptr "alien" c-ptr }
+        { f "offset" fixnum }
+    } }
+    { scratch { { unboxed-alien "value" } } }
+    { output { "value" } }
+    { clobber { "offset" } }
+} define-intrinsic
+
+\ set-alien-cell [
+    "value" operand [ swap MOV ] %alien-accessor
+] T{ template
+    { input {
+        { unboxed-c-ptr "value" pinned-c-ptr }
+        { unboxed-c-ptr "alien" c-ptr }
+        { f "offset" fixnum }
+    } }
+    { clobber { "offset" } }
+} define-intrinsic
index 86e69a50b788314f711703e809bcc45d5cf2a25e..ff1ddd974741c7d8b3dd1c0b23b5151b2b245716 100755 (executable)
@@ -1,7 +1,10 @@
  ! Copyright (C) 2004, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays assocs combinators hashtables kernel
-math fry namespaces make sequences words stack-checker.inlining
+math fry namespaces make sequences words byte-arrays
+locals layouts
+stack-checker.inlining
+compiler.intrinsics
 compiler.tree
 compiler.tree.builder
 compiler.tree.combinators
@@ -10,9 +13,9 @@ compiler.cfg
 compiler.cfg.stacks
 compiler.cfg.templates
 compiler.cfg.iterator
-compiler.alien
-compiler.instructions
-compiler.registers ;
+compiler.cfg.instructions
+compiler.cfg.registers
+compiler.alien ;
 IN: compiler.cfg.builder
 
 ! Convert tree SSA IR to CFG (not quite SSA yet) IR.
@@ -32,18 +35,9 @@ IN: compiler.cfg.builder
 
 : stop-iterating ( -- next ) end-basic-block f ;
 
-USE: qualified
-FROM: compiler.generator.registers => +input+   ;
-FROM: compiler.generator.registers => +output+  ;
-FROM: compiler.generator.registers => +scratch+ ;
-FROM: compiler.generator.registers => +clobber+ ;
-
 SYMBOL: procedures
-
 SYMBOL: current-word
-
 SYMBOL: current-label
-
 SYMBOL: loops
 
 ! Basic block after prologue, makes recursion faster
@@ -81,8 +75,8 @@ GENERIC: emit-node ( node -- next )
     #! labelled by the current word, so that self-recursive
     #! calls can skip an epilogue/prologue.
     init-phantoms
-    %prologue
-    %branch
+    ##prologue
+    ##branch
     begin-basic-block
     current-label get remember-loop ;
 
@@ -92,27 +86,30 @@ GENERIC: emit-node ( node -- next )
         [ emit-nodes ] with-node-iterator
     ] with-cfg-builder ;
 
-: build-cfg ( nodes word label -- procedures )
+: build-cfg ( nodes word -- procedures )
     V{ } clone [
         procedures [
-            (build-cfg)
+            dup (build-cfg)
         ] with-variable
     ] keep ;
 
+SYMBOL: +intrinsics+
+SYMBOL: +if-intrinsics+
+
 : if-intrinsics ( #call -- quot )
-    word>> "if-intrinsics" word-prop ;
+    word>> +if-intrinsics+ word-prop ;
 
 : local-recursive-call ( basic-block -- next )
-    %branch
+    ##branch
     basic-block get successors>> push
     stop-iterating ;
 
 : emit-call ( word -- next )
     finalize-phantoms
     {
-        { [ tail-call? not ] [ 0 %frame-required %call iterate-next ] }
+        { [ tail-call? not ] [ 0 ##frame-required ##call iterate-next ] }
         { [ dup loops get key? ] [ loops get at local-recursive-call ] }
-        [ %epilogue %jump stop-iterating ]
+        [ ##epilogue ##jump stop-iterating ]
     } cond ;
 
 ! #recursive
@@ -130,50 +127,53 @@ M: #recursive emit-node
     dup label>> loop?>> [ compile-loop ] [ compile-recursive ] if ;
 
 ! #if
-: emit-branch ( nodes -- final-bb )
-    [
+: emit-branch ( obj quot -- final-bb )
+    '[
         begin-basic-block copy-phantoms
-        emit-nodes
-        basic-block get dup [ %branch ] when
+        @
+        basic-block get dup [ ##branch ] when
     ] with-scope ;
 
-: emit-if ( node -- next )
-    children>> [ emit-branch ] map
+: emit-branches ( seq quot -- )
+    '[ _ emit-branch ] map
     end-basic-block
     begin-basic-block
     basic-block get '[ [ _ swap successors>> push ] when* ] each
-    init-phantoms
-    iterate-next ;
+    init-phantoms ;
+
+: emit-if ( node -- next )
+    children>> [ emit-nodes ] emit-branches ;
 
 M: #if emit-node
-    { { f "flag" } } lazy-load first %branch-t
-    emit-if ;
+    phantom-pop ##branch-t emit-if iterate-next ;
 
 ! #dispatch
 : dispatch-branch ( nodes word -- label )
+    #! The order here is important, dispatch-branches must
+    #! run after ##dispatch, so that each branch gets the
+    #! correct register state
     gensym [
         [
             copy-phantoms
-            %prologue
+            ##prologue
             [ emit-nodes ] with-node-iterator
-            %epilogue
-            %return
+            ##epilogue
+            ##return
         ] with-cfg-builder
     ] keep ;
 
 : dispatch-branches ( node -- )
     children>> [
         current-word get dispatch-branch
-        %dispatch-label
+        ##dispatch-label
     ] each ;
 
 : emit-dispatch ( node -- )
-    %dispatch dispatch-branches init-phantoms ;
+    phantom-pop int-regs next-vreg
+    [ finalize-contents finalize-heights ##epilogue ] 2dip ##dispatch
+    dispatch-branches init-phantoms ;
 
 M: #dispatch emit-node
-    #! The order here is important, dispatch-branches must
-    #! run after %dispatch, so that each branch gets the
-    #! correct register state
     tail-call? [
         emit-dispatch iterate-next
     ] [
@@ -187,23 +187,23 @@ M: #dispatch emit-node
 
 ! #call
 : define-intrinsics ( word intrinsics -- )
-    "intrinsics" set-word-prop ;
+    +intrinsics+ set-word-prop ;
 
 : define-intrinsic ( word quot assoc -- )
     2array 1array define-intrinsics ;
 
 : define-if-intrinsics ( word intrinsics -- )
-    [ +input+ associate ] assoc-map
-    "if-intrinsics" set-word-prop ;
+    [ template new swap >>input ] assoc-map
+    +if-intrinsics+ set-word-prop ;
 
 : define-if-intrinsic ( word quot inputs -- )
     2array 1array define-if-intrinsics ;
 
 : find-intrinsic ( #call -- pair/f )
-    word>> "intrinsics" word-prop find-template ;
+    word>> +intrinsics+ word-prop find-template ;
 
 : find-boolean-intrinsic ( #call -- pair/f )
-    word>> "if-intrinsics" word-prop find-template ;
+    word>> +if-intrinsics+ word-prop find-template ;
 
 : find-if-intrinsic ( #call -- pair/f )
     node@ {
@@ -213,25 +213,61 @@ M: #dispatch emit-node
     } cond ;
 
 : do-if-intrinsic ( pair -- next )
-    [ %if-intrinsic ] apply-template skip-next emit-if ;
+    [ ##if-intrinsic ] apply-template skip-next emit-if
+    iterate-next ;
 
 : do-boolean-intrinsic ( pair -- next )
-    [
-        f alloc-vreg [ %boolean-intrinsic ] keep phantom-push
-    ] apply-template iterate-next ;
+    [ ##if-intrinsic ] apply-template
+    { t f } [
+        <constant> phantom-push finalize-phantoms
+    ] emit-branches
+    iterate-next ;
 
 : do-intrinsic ( pair -- next )
-    [ %intrinsic ] apply-template iterate-next ;
+    [ ##intrinsic ] apply-template iterate-next ;
+
+: setup-value-classes ( #call -- )
+    node-input-infos [ class>> ] map set-value-classes ;
+
+{
+    (tuple) (array) (byte-array)
+    (complex) (ratio) (wrapper)
+    (write-barrier)
+} [ t "intrinsic" set-word-prop ] each
 
-: setup-operand-classes ( #call -- )
-    node-input-infos [ class>> ] map set-operand-classes ;
+: allot-size ( #call -- n )
+    1 phantom-datastack get phantom-input first value>> ;
+
+:: emit-allot ( size type tag -- )
+    int-regs next-vreg
+    dup fresh-object
+    dup size type tag int-regs next-vreg ##allot
+    type tagged boa phantom-push ;
+
+: emit-write-barrier ( -- )
+    phantom-pop dup >vreg fresh-object? [ drop ] [
+        int-regs next-vreg ##write-barrier
+    ] if ;
+
+: emit-intrinsic ( word -- next )
+    {
+        { \ (tuple) [ allot-size 2 cells + tuple tuple emit-allot ] }
+        { \ (array) [ allot-size 2 cells + array object emit-allot ] }
+        { \ (byte-array) [ allot-size cells 2 + byte-array object emit-allot ] }
+        { \ (complex) [ 3 cells complex complex emit-allot ] }
+        { \ (ratio) [ 3 cells ratio ratio emit-allot ] }
+        { \ (wrapper) [ 2 cells wrapper object emit-allot ] }
+        { \ (write-barrier) [ emit-write-barrier ] }
+    } case
+    iterate-next ;
 
 M: #call emit-node
-    dup setup-operand-classes
+    dup setup-value-classes
     dup find-if-intrinsic [ do-if-intrinsic ] [
         dup find-boolean-intrinsic [ do-boolean-intrinsic ] [
             dup find-intrinsic [ do-intrinsic ] [
-                word>> emit-call
+                word>> dup "intrinsic" word-prop
+                [ emit-intrinsic ] [ emit-call ] if
             ] ?if
         ] ?if
     ] ?if ;
@@ -259,12 +295,12 @@ M: #r> emit-node
 
 ! #return
 M: #return emit-node
-    drop finalize-phantoms %epilogue %return f ;
+    drop finalize-phantoms ##epilogue ##return f ;
 
 M: #return-recursive emit-node
     finalize-phantoms
     label>> id>> loops get key?
-    [ %epilogue %return ] unless f ;
+    [ ##epilogue ##return ] unless f ;
 
 ! #terminate
 M: #terminate emit-node drop stop-iterating ;
@@ -272,19 +308,19 @@ M: #terminate emit-node drop stop-iterating ;
 ! FFI
 M: #alien-invoke emit-node
     params>>
-    [ alien-invoke-frame %frame-required ]
-    [ %alien-invoke iterate-next ]
+    [ alien-invoke-frame ##frame-required ]
+    [ ##alien-invoke iterate-next ]
     bi ;
 
 M: #alien-indirect emit-node
     params>>
-    [ alien-invoke-frame %frame-required ]
-    [ %alien-indirect iterate-next ]
+    [ alien-invoke-frame ##frame-required ]
+    [ ##alien-indirect iterate-next ]
     bi ;
 
 M: #alien-callback emit-node
     params>> dup xt>> dup
-    [ init-phantoms %alien-callback ] with-cfg-builder
+    [ init-phantoms ##alien-callback ] with-cfg-builder
     iterate-next ;
 
 ! No-op nodes
index 9acf0897b944c3f81a65b6042a600c75850d5e42..140d406c4cacc6a12b102f683057d589d9b55e32 100644 (file)
@@ -11,17 +11,18 @@ C: <cfg> cfg
 TUPLE: basic-block < identity-tuple
 visited
 number
-label
 instructions
-successors
-predecessors ;
+successors ;
 
 : <basic-block> ( -- basic-block )
     basic-block new
         V{ } clone >>instructions
-        V{ } clone >>successors
-        V{ } clone >>predecessors ;
+        V{ } clone >>successors ;
 
-TUPLE: mr instructions word label ;
+TUPLE: mr instructions word label frame-size spill-counts ;
 
-C: <mr> mr
+: <mr> ( instructions word label -- mr )
+    mr new
+        swap >>label
+        swap >>word
+        swap >>instructions ;
index 65b0b97476644ac74680a3c568aad965572b7c89..1da954c22e00b6edc1a7916d402e28487da96d20 100644 (file)
@@ -9,11 +9,10 @@ IN: compiler.cfg.debugger
 GENERIC: test-cfg ( quot -- cfgs )
 
 M: callable test-cfg
-    build-tree optimize-tree gensym gensym build-cfg ;
+    build-tree optimize-tree gensym build-cfg ;
 
 M: word test-cfg
-    [ build-tree-from-word nip optimize-tree ] keep dup
-    build-cfg ;
+    [ build-tree-from-word nip optimize-tree ] keep build-cfg ;
 
 : test-mr ( quot -- mrs ) test-cfg [ build-mr ] map ;
 
diff --git a/unfinished/compiler/cfg/instructions/instructions.factor b/unfinished/compiler/cfg/instructions/instructions.factor
new file mode 100644 (file)
index 0000000..9bb576d
--- /dev/null
@@ -0,0 +1,124 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs accessors arrays kernel sequences namespaces
+math compiler.cfg.registers compiler.cfg.instructions.syntax ;
+IN: compiler.cfg.instructions
+
+! Virtual CPU instructions, used by CFG and machine IRs
+
+TUPLE: ##cond-branch < insn src ;
+TUPLE: ##unary < insn dst src ;
+TUPLE: ##nullary < insn dst ;
+
+! Stack operations
+INSN: ##load-literal < ##nullary obj ;
+INSN: ##peek < ##nullary loc ;
+INSN: ##replace src loc ;
+INSN: ##inc-d n ;
+INSN: ##inc-r n ;
+
+! Calling convention
+INSN: ##return ;
+
+! Subroutine calls
+INSN: ##call word ;
+INSN: ##jump word ;
+INSN: ##intrinsic quot defs-vregs uses-vregs ;
+
+! Jump tables
+INSN: ##dispatch-label label ;
+INSN: ##dispatch src temp ;
+
+! Boxing and unboxing
+INSN: ##copy < ##unary ;
+INSN: ##copy-float < ##unary ;
+INSN: ##unbox-float < ##unary ;
+INSN: ##unbox-f < ##unary ;
+INSN: ##unbox-alien < ##unary ;
+INSN: ##unbox-byte-array < ##unary ;
+INSN: ##unbox-any-c-ptr < ##unary ;
+INSN: ##box-float < ##unary temp ;
+INSN: ##box-alien < ##unary temp ;
+
+! Memory allocation
+INSN: ##allot < ##nullary size type tag temp ;
+INSN: ##write-barrier src temp ;
+INSN: ##gc ;
+
+! FFI
+INSN: ##alien-invoke params ;
+INSN: ##alien-indirect params ;
+INSN: ##alien-callback params ;
+
+GENERIC: defs-vregs ( insn -- seq )
+GENERIC: uses-vregs ( insn -- seq )
+
+M: ##nullary defs-vregs dst>> >vreg 1array ;
+M: ##unary defs-vregs dst>> >vreg 1array ;
+M: ##write-barrier defs-vregs temp>> >vreg 1array ;
+
+: allot-defs-vregs ( insn -- seq )
+    [ dst>> >vreg ] [ temp>> >vreg ] bi 2array ;
+
+M: ##box-float defs-vregs allot-defs-vregs ;
+M: ##box-alien defs-vregs allot-defs-vregs ;
+M: ##allot defs-vregs allot-defs-vregs ;
+M: ##dispatch defs-vregs temp>> >vreg 1array ;
+M: insn defs-vregs drop f ;
+
+M: ##replace uses-vregs src>> >vreg 1array ;
+M: ##unary uses-vregs src>> >vreg 1array ;
+M: ##write-barrier uses-vregs src>> >vreg 1array ;
+M: ##dispatch uses-vregs src>> >vreg 1array ;
+M: insn uses-vregs drop f ;
+
+: intrinsic-vregs ( assoc -- seq' )
+    [ nip >vreg ] { } assoc>map sift ;
+
+: intrinsic-defs-vregs ( insn -- seq )
+    defs-vregs>> intrinsic-vregs ;
+
+: intrinsic-uses-vregs ( insn -- seq )
+    uses-vregs>> intrinsic-vregs ;
+
+M: ##intrinsic defs-vregs intrinsic-defs-vregs ;
+M: ##intrinsic uses-vregs intrinsic-uses-vregs ;
+
+! Instructions used by CFG IR only.
+INSN: ##prologue ;
+INSN: ##epilogue ;
+INSN: ##frame-required n ;
+
+INSN: ##branch ;
+INSN: ##branch-f < ##cond-branch ;
+INSN: ##branch-t < ##cond-branch ;
+INSN: ##if-intrinsic quot defs-vregs uses-vregs ;
+
+M: ##cond-branch uses-vregs src>> >vreg 1array ;
+
+M: ##if-intrinsic defs-vregs intrinsic-defs-vregs ;
+M: ##if-intrinsic uses-vregs intrinsic-uses-vregs ;
+
+! Instructions used by machine IR only.
+INSN: _prologue ;
+INSN: _epilogue ;
+
+INSN: _label id ;
+
+TUPLE: _cond-branch < insn src label ;
+
+INSN: _branch label ;
+INSN: _branch-f < _cond-branch ;
+INSN: _branch-t < _cond-branch ;
+INSN: _if-intrinsic label quot defs-vregs uses-vregs ;
+
+M: _cond-branch uses-vregs src>> >vreg 1array ;
+
+M: _if-intrinsic defs-vregs intrinsic-defs-vregs ;
+M: _if-intrinsic uses-vregs intrinsic-uses-vregs ;
+
+INSN: _spill-integer src n ;
+INSN: _reload-integer dst n ;
+
+INSN: _spill-float src n ;
+INSN: _reload-float dst n ;
diff --git a/unfinished/compiler/cfg/instructions/syntax/syntax.factor b/unfinished/compiler/cfg/instructions/syntax/syntax.factor
new file mode 100644 (file)
index 0000000..6d533d2
--- /dev/null
@@ -0,0 +1,15 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: classes.tuple classes.tuple.parser kernel words
+make fry sequences parser ;
+IN: compiler.cfg.instructions.syntax
+
+TUPLE: insn ;
+
+: INSN:
+    parse-tuple-definition "regs" suffix
+    [ dup tuple eq? [ drop insn ] when ] dip
+    [ define-tuple-class ]
+    [ 2drop save-location ]
+    [ 2drop dup '[ f _ boa , ] define-inline ]
+    3tri ; parsing
index 37e1d512cd720306dc3de703d88cf0b1bcc5a531..4a9646c88a602f316a1ec9c0bcb0ed5f3b8c4a5e 100644 (file)
@@ -1,18 +1,22 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: namespaces sequences math math.order kernel assocs
-accessors vectors fry
+accessors vectors fry heaps
+compiler.cfg.registers
 compiler.cfg.linear-scan.live-intervals
 compiler.backend ;
 IN: compiler.cfg.linear-scan.allocation
 
-! Mapping from vregs to machine registers
-SYMBOL: register-allocation
+! Mapping from register classes to sequences of machine registers
+SYMBOL: free-registers
 
-! Mapping from vregs to spill locations
-SYMBOL: spill-locations
+: free-registers-for ( vreg -- seq )
+    reg-class>> free-registers get at ;
 
-! Vector of active live intervals, in order of increasing end point
+: deallocate-register ( live-interval -- )
+    [ reg>> ] [ vreg>> ] bi free-registers-for push ;
+
+! Vector of active live intervals
 SYMBOL: active-intervals
 
 : add-active ( live-interval -- )
@@ -21,70 +25,134 @@ SYMBOL: active-intervals
 : delete-active ( live-interval -- )
     active-intervals get delete ;
 
-! Mapping from register classes to sequences of machine registers
-SYMBOL: free-registers
+: expire-old-intervals ( n -- )
+    active-intervals get
+    swap '[ end>> _ < ] partition
+    active-intervals set
+    [ deallocate-register ] each ;
 
-! Counter of spill locations
-SYMBOL: spill-counter
+: expire-old-uses ( n -- )
+    active-intervals get
+    swap '[ uses>> dup peek _ < [ pop* ] [ drop ] if ] each ;
 
-: next-spill-location ( -- n )
-    spill-counter [ dup 1+ ] change ;
+: update-state ( live-interval -- )
+    start>> [ expire-old-intervals ] [ expire-old-uses ] bi ;
 
-: assign-spill ( live-interval -- )
-    next-spill-location swap vreg>> spill-locations get set-at ;
+! Minheap of live intervals which still need a register allocation
+SYMBOL: unhandled-intervals
 
-: free-registers-for ( vreg -- seq )
-    reg-class>> free-registers get at ;
+! Start index of current live interval. We ensure that all
+! live intervals added to the unhandled set have a start index
+! strictly greater than ths one. This ensures that we can catch
+! infinite loop situations.
+SYMBOL: progress
 
-: free-register ( vreg -- )
-    #! Free machine register currently assigned to vreg.
-    [ register-allocation get at ] [ free-registers-for ] bi push ;
+: check-progress ( live-interval -- )
+    start>> progress get <= [ "No progress" throw ] when ; inline
 
-: expire-old-intervals ( live-interval -- )
-    active-intervals get
-    swap '[ end>> _ start>> < ] partition
-    active-intervals set
-    [ vreg>> free-register ] each ;
+: add-unhandled ( live-interval -- )
+    [ check-progress ]
+    [ dup start>> unhandled-intervals get heap-push ]
+    bi ;
+
+: init-unhandled ( live-intervals -- )
+    [ [ start>> ] keep ] { } map>assoc
+    unhandled-intervals get heap-push-all ;
+
+: assign-free-register ( live-interval registers -- )
+    #! If the live interval does not have any uses, it means it
+    #! will be spilled immediately, so it still needs a register
+    #! to compute the new value, but we don't add the interval
+    #! to the active set and we don't remove the register from
+    #! the free list.
+    over uses>> empty?
+    [ peek >>reg drop ] [ pop >>reg add-active ] if ;
+
+! Spilling
+SYMBOL: spill-counts
+
+: next-spill-location ( reg-class -- n )
+    spill-counts get [ dup 1+ ] change-at ;
 
 : interval-to-spill ( -- live-interval )
-    #! We spill the interval with the longest remaining range.
+    #! We spill the interval with the most distant use location.
     active-intervals get unclip-slice [
-        [ [ end>> ] bi@ > ] most
+        [ [ uses>> peek ] bi@ > ] most
     ] reduce ;
 
-: reuse-register ( live-interval to-spill -- )
-    vreg>> swap vreg>>
-    register-allocation get
-    tuck [ at ] [ set-at ] 2bi* ;
-
-: spill-at-interval ( live-interval -- )
+: check-split ( live-interval -- )
+    [ start>> ] [ end>> ] bi = [ "Cannot split any further" throw ] when ;
+
+: split-interval ( live-interval -- before after )
+    #! Split the live interval at the location of its first use.
+    #! 'Before' now starts and ends on the same instruction.
+    [ check-split ]
+    [ clone [ uses>> delete-all ] [ dup start>> >>end ] bi ]
+    [ clone f >>reg dup uses>> peek >>start ]
+    tri ;
+
+: record-split ( live-interval before after -- )
+    [ >>split-before ] [ >>split-after ] bi* drop ;
+
+: assign-spill ( before after -- before after )
+    #! If it has been spilled already, reuse spill location.
+    over reload-from>> [ next-spill-location ] unless*
+    tuck [ >>spill-to ] [ >>reload-from ] 2bi* ;
+
+: split-and-spill ( live-interval -- before after )
+    dup split-interval [ record-split ] [ assign-spill ] 2bi ;
+
+: reuse-register ( new existing -- )
+    reg>> >>reg
+    dup uses>> empty? [ deallocate-register ] [ add-active ] if ;
+
+: spill-existing ( new existing -- )
+    #! Our new interval will be used before the active interval
+    #! with the most distant use location. Spill the existing
+    #! interval, then process the new interval and the tail end
+    #! of the existing interval again.
+    [ reuse-register ]
+    [ delete-active ]
+    [ split-and-spill [ drop ] [ add-unhandled ] bi* ] tri ;
+
+: spill-new ( new existing -- )
+    #! Our new interval will be used after the active interval
+    #! with the most distant use location. Split the new
+    #! interval, then process both parts of the new interval
+    #! again.
+    [ split-and-spill add-unhandled ] dip spill-existing ;
+
+: spill-existing? ( new existing -- ? )
+    over uses>> empty? [ 2drop t ] [ [ uses>> peek ] bi@ < ] if ;
+
+: assign-blocked-register ( live-interval -- )
     interval-to-spill
-    2dup [ end>> ] bi@ > [
-        [ reuse-register ]
-        [ nip assign-spill ]
-        [ [ add-active ] [ delete-active ] bi* ]
-        2tri
-    ] [ drop assign-spill ] if ;
-
-: init-allocator ( -- )
-    H{ } clone register-allocation set
-    H{ } clone spill-locations set
-    V{ } clone active-intervals set
-    machine-registers [ >vector ] assoc-map free-registers set
-    0 spill-counter set ;
-
-: assign-register ( live-interval register -- )
-    swap vreg>> register-allocation get set-at ;
+    2dup spill-existing?
+    [ spill-existing ] [ spill-new ] if ;
 
-: allocate-register ( live-interval -- )
+: assign-register ( live-interval -- )
     dup vreg>> free-registers-for [
-        spill-at-interval
+        assign-blocked-register
     ] [
-        [ pop assign-register ]
-        [ drop add-active ]
-        2bi
+        assign-free-register
     ] if-empty ;
 
-: allocate-registers ( live-intervals -- )
+! Main loop
+: init-allocator ( registers -- )
+    V{ } clone active-intervals set
+    <min-heap> unhandled-intervals set
+    [ reverse >vector ] assoc-map free-registers set
+    H{ { int-regs 0 } { double-float-regs 0 } } clone spill-counts set
+    -1 progress set ;
+
+: handle-interval ( live-interval -- )
+    [ start>> progress set ] [ update-state ] [ assign-register ] tri ;
+
+: (allocate-registers) ( -- )
+    unhandled-intervals get [ handle-interval ] slurp-heap ;
+
+: allocate-registers ( live-intervals machine-registers -- live-intervals )
+    #! This modifies the input live-intervals.
     init-allocator
-    [ [ expire-old-intervals ] [ allocate-register ] bi ] each ;
+    dup init-unhandled
+    (allocate-registers) ;
diff --git a/unfinished/compiler/cfg/linear-scan/assignment/assignment-tests.factor b/unfinished/compiler/cfg/linear-scan/assignment/assignment-tests.factor
new file mode 100644 (file)
index 0000000..9efc236
--- /dev/null
@@ -0,0 +1,4 @@
+USING: compiler.cfg.linear-scan.assignment tools.test ;
+IN: compiler.cfg.linear-scan.assignment.tests
+
+\ assign-registers must-infer
diff --git a/unfinished/compiler/cfg/linear-scan/assignment/assignment.factor b/unfinished/compiler/cfg/linear-scan/assignment/assignment.factor
new file mode 100644 (file)
index 0000000..ffe8e6b
--- /dev/null
@@ -0,0 +1,91 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel math assocs namespaces sequences heaps
+fry make combinators
+compiler.cfg.registers
+compiler.cfg.instructions
+compiler.cfg.linear-scan.live-intervals ;
+IN: compiler.cfg.linear-scan.assignment
+
+! A vector of live intervals. There is linear searching involved
+! but since we never have too many machine registers (around 30
+! at most) and we probably won't have that many live at any one
+! time anyway, it is not a problem to check each element.
+SYMBOL: active-intervals
+
+: add-active ( live-interval -- )
+    active-intervals get push ;
+
+: lookup-register ( vreg -- reg )
+    active-intervals get [ vreg>> = ] with find nip reg>> ;
+
+! Minheap of live intervals which still need a register allocation
+SYMBOL: unhandled-intervals
+
+: add-unhandled ( live-interval -- )
+    dup split-before>> [
+        [ split-before>> ] [ split-after>> ] bi
+        [ add-unhandled ] bi@
+    ] [
+        dup start>> unhandled-intervals get heap-push
+    ] if ;
+
+: init-unhandled ( live-intervals -- )
+    [ add-unhandled ] each ;
+
+: insert-spill ( live-interval -- )
+    [ reg>> ] [ spill-to>> ] [ vreg>> reg-class>> ] tri
+    over [
+        {
+            { int-regs [ _spill-integer ] }
+            { double-float-regs [ _spill-float ] }
+        } case
+    ] [ 3drop ] if ;
+
+: expire-old-intervals ( n -- )
+    active-intervals get
+    swap '[ end>> _ = ] partition
+    active-intervals set
+    [ insert-spill ] each ;
+
+: insert-reload ( live-interval -- )
+    [ reg>> ] [ reload-from>> ] [ vreg>> reg-class>> ] tri
+    over [
+        {
+            { int-regs [ _reload-integer ] }
+            { double-float-regs [ _reload-float ] }
+        } case
+    ] [ 3drop ] if ;
+
+: activate-new-intervals ( n -- )
+    #! Any live intervals which start on the current instruction
+    #! are added to the active set.
+    unhandled-intervals get dup heap-empty? [ 2drop ] [
+        2dup heap-peek drop start>> = [
+            heap-pop drop [ add-active ] [ insert-reload ] bi
+            activate-new-intervals
+        ] [ 2drop ] if
+    ] if ;
+
+: (assign-registers) ( insn -- )
+    dup
+    [ defs-vregs ] [ uses-vregs ] bi append
+    active-intervals get swap '[ vreg>> _ member? ] filter
+    [ [ vreg>> ] [ reg>> ] bi ] { } map>assoc
+    >>regs drop ;
+
+: init-assignment ( live-intervals -- )
+    V{ } clone active-intervals set
+    <min-heap> unhandled-intervals set
+    init-unhandled ;
+
+: assign-registers ( insns live-intervals -- insns' )
+    [
+        init-assignment
+        [
+            [ activate-new-intervals ]
+            [ drop [ (assign-registers) ] [ , ] bi ]
+            [ expire-old-intervals ]
+            tri
+        ] each-index
+    ] { } make ;
diff --git a/unfinished/compiler/cfg/linear-scan/debugger/debugger.factor b/unfinished/compiler/cfg/linear-scan/debugger/debugger.factor
new file mode 100644 (file)
index 0000000..89bf81d
--- /dev/null
@@ -0,0 +1,23 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel sequences sets arrays
+compiler.cfg.linear-scan.live-intervals
+compiler.cfg.linear-scan.allocation ;
+IN: compiler.cfg.linear-scan.debugger
+
+: check-assigned ( live-intervals -- )
+    [
+        reg>>
+        [ "Not all intervals have registers" throw ] unless
+    ] each ;
+
+: split-children ( live-interval -- seq )
+    dup split-before>> [
+        [ split-before>> ] [ split-after>> ] bi
+        [ split-children ] bi@
+        append
+    ] [ 1array ] if ;
+
+: check-linear-scan ( live-intervals machine-registers -- )
+    [ [ clone ] map ] dip allocate-registers
+    [ split-children ] map concat check-assigned ;
diff --git a/unfinished/compiler/cfg/linear-scan/linear-scan-tests.factor b/unfinished/compiler/cfg/linear-scan/linear-scan-tests.factor
new file mode 100644 (file)
index 0000000..8f13787
--- /dev/null
@@ -0,0 +1,105 @@
+IN: compiler.cfg.linear-scan.tests
+USING: tools.test random sorting sequences sets hashtables assocs
+kernel fry arrays splitting namespaces math accessors vectors
+math.order
+compiler.cfg.registers
+compiler.cfg.linear-scan
+compiler.cfg.linear-scan.live-intervals
+compiler.cfg.linear-scan.debugger ;
+
+[ ] [
+    {
+        T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
+    }
+    H{ { f { "A" } } }
+    check-linear-scan
+] unit-test
+
+[ ] [
+    {
+        T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 10 } { uses V{ 10 } } }
+        T{ live-interval { vreg T{ vreg { n 2 } } } { start 11 } { end 20 } { uses V{ 20 } } }
+    }
+    H{ { f { "A" } } }
+    check-linear-scan
+] unit-test
+
+[ ] [
+    {
+        T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
+        T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 60 } { uses V{ 60 } } }
+    }
+    H{ { f { "A" } } }
+    check-linear-scan
+] unit-test
+
+[ ] [
+    {
+        T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
+        T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 200 } { uses V{ 200 } } }
+    }
+    H{ { f { "A" } } }
+    check-linear-scan
+] unit-test
+
+[
+    {
+        T{ live-interval { vreg T{ vreg { n 1 } } } { start 0 } { end 100 } { uses V{ 100 } } }
+        T{ live-interval { vreg T{ vreg { n 2 } } } { start 30 } { end 100 } { uses V{ 100 } } }
+    }
+    H{ { f { "A" } } }
+    check-linear-scan
+] must-fail
+
+SYMBOL: available
+
+SYMBOL: taken
+
+SYMBOL: max-registers
+
+SYMBOL: max-insns
+
+SYMBOL: max-uses
+
+: not-taken ( -- n )
+    available get keys dup empty? [ "Oops" throw ] when
+    random
+    dup taken get nth 1 + max-registers get = [
+        dup available get delete-at
+    ] [
+        dup taken get [ 1 + ] change-nth
+    ] if ;
+
+: random-live-intervals ( num-intervals max-uses max-registers max-insns -- seq )
+    [
+        max-insns set
+        max-registers set
+        max-uses set
+        max-insns get [ 0 ] replicate taken set
+        max-insns get [ dup ] H{ } map>assoc available set
+        [
+            live-interval new
+                swap f swap vreg boa >>vreg
+                max-uses get random 2 max [ not-taken ] replicate natural-sort
+                unclip [ >vector >>uses ] [ >>start ] bi*
+                dup uses>> first >>end
+        ] map
+    ] with-scope ;
+
+: random-test ( num-intervals max-uses max-registers max-insns -- )
+    over >r random-live-intervals r> f associate check-linear-scan ;
+
+[ ] [ 30 2 1 60 random-test ] unit-test
+[ ] [ 60 2 2 60 random-test ] unit-test
+[ ] [ 80 2 3 200 random-test ] unit-test
+[ ] [ 70 2 5 30 random-test ] unit-test
+[ ] [ 60 2 6 30 random-test ] unit-test
+[ ] [ 1 2 10 10 random-test ] unit-test
+
+[ ] [ 10 4 2 60 random-test ] unit-test
+[ ] [ 10 20 2 400 random-test ] unit-test
+[ ] [ 10 20 4 300 random-test ] unit-test
+
+USING: math.private compiler.cfg.debugger ;
+
+[ ] [ [ float+ float>fixnum 3 fixnum*fast ] test-mr first linear-scan drop ] unit-test
index 307eecf53a06284ff5b45750243df2159055e41f..f62e3a39d1d6d2aa3f1d9fafbcb91ae5202db111 100644 (file)
@@ -1,6 +1,33 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors namespaces
+compiler.backend
+compiler.cfg
+compiler.cfg.linear-scan.live-intervals
+compiler.cfg.linear-scan.allocation
+compiler.cfg.linear-scan.assignment ;
 IN: compiler.cfg.linear-scan
 
-! See http://www.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf
+! References:
 
+! Linear Scan Register Allocation
+! by Massimiliano Poletto and Vivek Sarkar
+! http://www.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf
+
+! Linear Scan Register Allocation for the Java HotSpot Client Compiler
+! by Christian Wimmer
+! and http://www.ssw.uni-linz.ac.at/Research/Papers/Wimmer04Master/
+
+! Quality and Speed in Linear-scan Register Allocation
+! by Omri Traub, Glenn Holloway, Michael D. Smith
+! http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.8435
+
+: linear-scan ( mr -- mr' )
+    [
+        [
+            dup compute-live-intervals
+            machine-registers allocate-registers
+            assign-registers
+        ] change-instructions
+        spill-counts get >>spill-counts
+    ] with-scope ;
index 6a3514c4e25ec025b73c088a03c8f87b67791ff8..a0699b80bd9ef7658eb97badf1a9f6fe02832ccb 100644 (file)
@@ -1,32 +1,48 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces kernel assocs accessors sequences math
-math.order sorting compiler.instructions compiler.registers ;
+USING: namespaces kernel assocs accessors sequences math fry
+compiler.cfg.instructions compiler.cfg.registers ;
 IN: compiler.cfg.linear-scan.live-intervals
 
-TUPLE: live-interval < identity-tuple vreg start end ;
+TUPLE: live-interval < identity-tuple
+vreg
+reg spill-to reload-from split-before split-after
+start end uses ;
 
-M: live-interval hashcode* nip [ start>> ] [ end>> 1000 * ] bi + ;
+: <live-interval> ( start vreg -- live-interval )
+    live-interval new
+        swap >>vreg
+        swap >>start
+        V{ } clone >>uses ;
+
+M: live-interval hashcode*
+    nip [ start>> ] [ end>> 1000 * ] bi + ;
+
+M: live-interval clone
+    call-next-method [ clone ] change-uses ;
 
 ! Mapping from vreg to live-interval
 SYMBOL: live-intervals
 
-: update-live-interval ( n vreg -- )
-    >vreg
-    live-intervals get
-    [ over f live-interval boa ] cache
-    (>>end) ;
+: add-use ( n vreg live-intervals -- )
+    at [ (>>end) ] [ uses>> push ] 2bi ;
 
-: compute-live-intervals* ( n insn -- )
-    uses-vregs [ update-live-interval ] with each ;
+: new-live-interval ( n vreg live-intervals -- )
+    2dup key? [ "Multiple defs" throw ] when
+    [ [ <live-interval> ] keep ] dip set-at ;
+
+: compute-live-intervals* ( insn n -- )
+    live-intervals get
+    [ [ uses-vregs ] 2dip '[ _ swap _ add-use ] each ]
+    [ [ defs-vregs ] 2dip '[ _ swap _ new-live-interval ] each ]
+    3bi ;
 
-: sort-live-intervals ( assoc -- seq' )
-    #! Sort by increasing start location.
-    values [ [ start>> ] compare ] sort ;
+: finalize-live-intervals ( assoc -- seq' )
+    #! Reverse uses lists so that we can pop values off.
+    values dup [ uses>> reverse-here ] each ;
 
 : compute-live-intervals ( instructions -- live-intervals )
     H{ } clone [
-        live-intervals [
-            [ swap compute-live-intervals* ] each-index
-        ] with-variable
-    ] keep sort-live-intervals ;
+        live-intervals set
+        [ compute-live-intervals* ] each-index
+    ] keep finalize-live-intervals ;
index 2aa7c667777517f4c8dca8b0c8ea62f54df89a2f..24730cd17fb8db2c4236f804615b0c2087b7428e 100644 (file)
@@ -1,18 +1,14 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel math accessors sequences namespaces make
-combinators compiler.cfg compiler.cfg.rpo compiler.instructions
-compiler.instructions.syntax ;
+combinators
+compiler.cfg
+compiler.cfg.rpo
+compiler.cfg.instructions
+compiler.cfg.instructions.syntax ;
 IN: compiler.cfg.linearization
 
 ! Convert CFG IR to machine IR.
-SYMBOL: frame-size
-
-: compute-frame-size ( rpo -- )
-    [ instructions>> [ %frame-required? ] filter ] map concat
-    [ f ] [ [ n>> ] map supremum ] if-empty
-    frame-size set ;
-
 GENERIC: linearize-insn ( basic-block insn -- )
 
 : linearize-insns ( basic-block -- )
@@ -20,14 +16,6 @@ GENERIC: linearize-insn ( basic-block insn -- )
 
 M: insn linearize-insn , drop ;
 
-M: %frame-required linearize-insn 2drop ;
-
-M: %prologue linearize-insn
-    2drop frame-size get [ _prologue ] when* ;
-
-M: %epilogue linearize-insn
-    2drop frame-size get [ _epilogue ] when* ;
-
 : useless-branch? ( basic-block successor -- ? )
     #! If our successor immediately follows us in RPO, then we
     #! don't need to branch.
@@ -36,58 +24,45 @@ M: %epilogue linearize-insn
 : branch-to-return? ( successor -- ? )
     #! A branch to a block containing just a return is cloned.
     instructions>> dup length 2 = [
-        [ first %epilogue? ] [ second %return? ] bi and
+        [ first ##epilogue? ] [ second ##return? ] bi and
     ] [ drop f ] if ;
 
 : emit-branch ( basic-block successor -- )
     {
         { [ 2dup useless-branch? ] [ 2drop ] }
         { [ dup branch-to-return? ] [ nip linearize-insns ] }
-        [ nip label>> _branch ]
+        [ nip number>> _branch ]
     } cond ;
 
-M: %branch linearize-insn
+M: ##branch linearize-insn
     drop dup successors>> first emit-branch ;
 
 : conditional ( basic-block -- basic-block successor1 label2 )
-    dup successors>> first2 swap label>> ; inline
+    dup successors>> first2 swap number>> ; inline
 
 : boolean-conditional ( basic-block insn -- basic-block successor vreg label2 )
-    [ conditional ] [ vreg>> ] bi* swap ; inline
+    [ conditional ] [ src>> ] bi* swap ; inline
 
-M: %branch-f linearize-insn
+M: ##branch-f linearize-insn
     boolean-conditional _branch-f emit-branch ;
 
-M: %branch-t linearize-insn
+M: ##branch-t linearize-insn
     boolean-conditional _branch-t emit-branch ;
 
-M: %if-intrinsic linearize-insn
-    [ conditional ] [ [ quot>> ] [ vregs>> ] bi ] bi*
-    _if-intrinsic emit-branch ;
+: >intrinsic< ( insn -- quot defs uses )
+    [ quot>> ] [ defs-vregs>> ] [ uses-vregs>> ] tri ;
 
-M: %boolean-intrinsic linearize-insn
-    [
-        "false" define-label
-        "end" define-label
-        "false" get over [ quot>> ] [ vregs>> ] bi _if-intrinsic
-        t over out>> %load-literal
-        "end" get _branch
-        "false" resolve-label
-        f over out>> %load-literal
-        "end" resolve-label
-    ] with-scope
-    2drop ;
+M: ##if-intrinsic linearize-insn
+    [ conditional ] [ >intrinsic< ] bi*
+    _if-intrinsic emit-branch ;
 
 : linearize-basic-block ( bb -- )
-    [ label>> _label ] [ linearize-insns ] bi ;
+    [ number>> _label ] [ linearize-insns ] bi ;
 
 : linearize-basic-blocks ( rpo -- insns )
     [ [ linearize-basic-block ] each ] { } make ;
 
 : build-mr ( cfg -- mr )
-    [
-        entry>> reverse-post-order [
-            [ compute-frame-size ]
-            [ linearize-basic-blocks ] bi
-        ] with-scope
-    ] [ word>> ] [ label>> ] tri <mr> ;
+    [ entry>> reverse-post-order linearize-basic-blocks ]
+    [ word>> ] [ label>> ]
+    tri <mr> ;
diff --git a/unfinished/compiler/cfg/registers/registers.factor b/unfinished/compiler/cfg/registers/registers.factor
new file mode 100644 (file)
index 0000000..ebc8382
--- /dev/null
@@ -0,0 +1,110 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors namespaces math kernel alien classes ;
+IN: compiler.cfg.registers
+
+! Virtual CPU registers, used by CFG and machine IRs
+
+MIXIN: value
+
+GENERIC: >vreg ( obj -- vreg )
+GENERIC: set-value-class ( class obj -- )
+GENERIC: value-class* ( operand -- class )
+
+: value-class ( operand -- class ) value-class* object or ;
+
+M: value >vreg drop f ;
+M: value set-value-class 2drop ;
+M: value value-class* drop f ;
+
+! Register classes
+SINGLETON: int-regs
+SINGLETON: single-float-regs
+SINGLETON: double-float-regs
+UNION: float-regs single-float-regs double-float-regs ;
+UNION: reg-class int-regs float-regs ;
+
+! Virtual registers
+TUPLE: vreg reg-class n ;
+SYMBOL: vreg-counter
+: next-vreg ( reg-class -- vreg ) \ vreg-counter counter vreg boa ;
+
+M: vreg >vreg ;
+
+INSTANCE: vreg value
+
+! Stack locations
+TUPLE: loc n class ;
+
+! A data stack location.
+TUPLE: ds-loc < loc ;
+: <ds-loc> ( n -- loc ) f ds-loc boa ;
+
+TUPLE: rs-loc < loc ;
+: <rs-loc> ( n -- loc ) f rs-loc boa ;
+
+INSTANCE: loc value
+
+! A stack location which has been loaded into a register. To
+! read the location, we just read the register, but when time
+! comes to save it back to the stack, we know the register just
+! contains a stack value so we don't have to redundantly write
+! it back.
+TUPLE: cached loc vreg ;
+C: <cached> cached
+
+M: cached set-value-class vreg>> set-value-class ;
+M: cached value-class* vreg>> value-class* ;
+M: cached >vreg vreg>> >vreg ;
+
+INSTANCE: cached value
+
+! A tagged pointer
+TUPLE: tagged vreg class ;
+: <tagged> ( vreg -- tagged ) f tagged boa ;
+
+M: tagged set-value-class (>>class) ;
+M: tagged value-class* class>> ;
+M: tagged >vreg vreg>> ;
+
+INSTANCE: tagged value
+
+! Unboxed value
+TUPLE: unboxed vreg ;
+C: <unboxed> unboxed
+
+M: unboxed >vreg vreg>> ;
+
+INSTANCE: unboxed value
+
+! Unboxed alien pointer
+TUPLE: unboxed-alien < unboxed ;
+C: <unboxed-alien> unboxed-alien
+
+M: unboxed-alien value-class* drop simple-alien ;
+
+! Untagged byte array pointer
+TUPLE: unboxed-byte-array < unboxed ;
+C: <unboxed-byte-array> unboxed-byte-array
+
+M: unboxed-byte-array value-class* drop c-ptr ;
+
+! A register set to f
+TUPLE: unboxed-f < unboxed ;
+C: <unboxed-f> unboxed-f
+
+M: unboxed-f value-class* drop \ f ;
+
+! An alien, byte array or f
+TUPLE: unboxed-c-ptr < unboxed ;
+C: <unboxed-c-ptr> unboxed-c-ptr
+
+M: unboxed-c-ptr value-class* drop c-ptr ;
+
+! A constant value
+TUPLE: constant value ;
+C: <constant> constant
+
+M: constant value-class* value>> class ;
+
+INSTANCE: constant value
index d5280a814258ee8f153b0822a38f932a95327a73..9fe6d3c90aaf506cf3d3cbe8ee2b0b6cbebd4327 100644 (file)
@@ -1,13 +1,12 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel accessors namespaces make math sequences
-compiler.instructions ;
+compiler.cfg.instructions ;
 IN: compiler.cfg.rpo
 
 : post-order-traversal ( basic-block -- )
     dup visited>> [ drop ] [
         t >>visited
-        <label> >>label
         [ successors>> [ post-order-traversal ] each ] [ , ] bi
     ] if ;
 
diff --git a/unfinished/compiler/cfg/stack-frame/stack-frame.factor b/unfinished/compiler/cfg/stack-frame/stack-frame.factor
new file mode 100644 (file)
index 0000000..56282cf
--- /dev/null
@@ -0,0 +1,59 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces accessors math.order assocs kernel sequences
+make compiler.cfg.instructions compiler.cfg.instructions.syntax
+compiler.cfg.registers ;
+IN: compiler.cfg.stack-frame
+
+SYMBOL: frame-required?
+
+SYMBOL: frame-size
+
+SYMBOL: spill-counts
+
+: init-stack-frame-builder ( -- )
+    frame-required? off
+    0 frame-size set ;
+
+GENERIC: compute-frame-size* ( insn -- )
+
+M: ##frame-required compute-frame-size*
+    frame-required? on
+    n>> frame-size [ max ] change ;
+
+M: _spill-integer compute-frame-size*
+    drop frame-required? on ;
+
+M: _spill-float compute-frame-size*
+    drop frame-required? on ;
+
+M: insn compute-frame-size* drop ;
+
+: compute-frame-size ( insns -- )
+    [ compute-frame-size* ] each ;
+
+GENERIC: insert-pro/epilogues* ( insn -- )
+
+M: ##frame-required insert-pro/epilogues* drop ;
+
+M: ##prologue insert-pro/epilogues*
+    drop frame-required? get [ _prologue ] when ;
+
+M: ##epilogue insert-pro/epilogues*
+    drop frame-required? get [ _epilogue ] when ;
+
+M: insn insert-pro/epilogues* , ;
+
+: insert-pro/epilogues ( insns -- insns )
+    [ [ insert-pro/epilogues* ] each ] { } make ;
+
+: build-stack-frame ( mr -- mr )
+    [
+        init-stack-frame-builder
+        [
+            [ compute-frame-size ]
+            [ insert-pro/epilogues ]
+            bi
+        ] change-instructions
+        frame-size get >>frame-size
+    ] with-scope ;
index f2cfbb70a1214aa239ffe27fe6c49ac1b8384aa2..39cd942bb2f4979c380ca069cec2cad9140508de 100755 (executable)
@@ -3,23 +3,15 @@
 USING: arrays assocs classes classes.private classes.algebra
 combinators hashtables kernel layouts math fry namespaces
 quotations sequences system vectors words effects alien
-byte-arrays accessors sets math.order compiler.instructions
-compiler.registers ;
+byte-arrays accessors sets math.order compiler.backend
+compiler.cfg.instructions compiler.cfg.registers ;
 IN: compiler.cfg.stacks
 
 ! Converting stack operations into register operations, while
 ! doing a bit of optimization along the way.
-
-USE: qualified
-FROM: compiler.generator.registers => +input+   ;
-FROM: compiler.generator.registers => +output+  ;
-FROM: compiler.generator.registers => +scratch+ ;
-FROM: compiler.generator.registers => +clobber+ ;
 SYMBOL: known-tag
 
 ! Value protocol
-GENERIC: set-operand-class ( class obj -- )
-GENERIC: operand-class* ( operand -- class )
 GENERIC: move-spec ( obj -- spec )
 GENERIC: live-loc? ( actual current -- ? )
 GENERIC# (lazy-load) 1 ( value spec -- value )
@@ -32,23 +24,19 @@ DEFER: %move
 
 PRIVATE>
 
-: operand-class ( operand -- class )
-    operand-class* object or ;
-
 ! Default implementation
-M: value set-operand-class 2drop ;
-M: value operand-class* drop f ;
 M: value live-loc? 2drop f ;
 M: value minimal-ds-loc* drop ;
 M: value lazy-store 2drop ;
 
 M: vreg move-spec reg-class>> move-spec ;
+M: vreg value-class* reg-class>> value-class* ;
 
 M: int-regs move-spec drop f ;
-M: int-regs operand-class* drop object ;
+M: int-regs value-class* drop object ;
 
 M: float-regs move-spec drop float ;
-M: float-regs operand-class* drop float ;
+M: float-regs value-class* drop float ;
 
 M: ds-loc minimal-ds-loc* n>> min ;
 M: ds-loc live-loc?
@@ -57,15 +45,13 @@ M: ds-loc live-loc?
 M: rs-loc live-loc?
     over rs-loc? [ [ n>> ] bi@ = not ] [ 2drop t ] if ;
 
-M: loc operand-class* class>> ;
-M: loc set-operand-class (>>class) ;
+M: loc value-class* class>> ;
+M: loc set-value-class (>>class) ;
 M: loc move-spec drop loc ;
 
 M: f move-spec drop loc ;
-M: f operand-class* ;
+M: f value-class* ;
 
-M: cached set-operand-class vreg>> set-operand-class ;
-M: cached operand-class* vreg>> operand-class* ;
 M: cached move-spec drop cached ;
 M: cached live-loc? loc>> live-loc? ;
 M: cached (lazy-load) >r vreg>> r> (lazy-load) ;
@@ -75,70 +61,71 @@ M: cached lazy-store
     [ "live-locs" get at %move ] [ 2drop ] if ;
 M: cached minimal-ds-loc* loc>> minimal-ds-loc* ;
 
-M: tagged set-operand-class (>>class) ;
-M: tagged operand-class* class>> ;
 M: tagged move-spec drop f ;
 
-M: unboxed-alien operand-class* drop simple-alien ;
 M: unboxed-alien move-spec class ;
 
-M: unboxed-byte-array operand-class* drop c-ptr ;
 M: unboxed-byte-array move-spec class ;
 
-M: unboxed-f operand-class* drop \ f ;
 M: unboxed-f move-spec class ;
 
-M: unboxed-c-ptr operand-class* drop c-ptr ;
 M: unboxed-c-ptr move-spec class ;
 
-M: constant operand-class* value>> class ;
 M: constant move-spec class ;
 
 ! Moving values between locations and registers
 : %move-bug ( -- * ) "Bug in generator.registers" throw ;
 
 : %unbox-c-ptr ( dst src -- )
-    dup operand-class {
-        { [ dup \ f class<= ] [ drop %unbox-f ] }
-        { [ dup simple-alien class<= ] [ drop %unbox-alien ] }
-        { [ dup byte-array class<= ] [ drop %unbox-byte-array ] }
-        [ drop %unbox-any-c-ptr ]
+    dup value-class {
+        { [ dup \ f class<= ] [ drop ##unbox-f ] }
+        { [ dup simple-alien class<= ] [ drop ##unbox-alien ] }
+        { [ dup byte-array class<= ] [ drop ##unbox-byte-array ] }
+        [ drop ##unbox-any-c-ptr ]
     } cond ; inline
 
 : %move-via-temp ( dst src -- )
     #! For many transfers, such as loc to unboxed-alien, we
     #! don't have an intrinsic, so we transfer the source to
     #! temp then temp to the destination.
-    int-regs next-vreg [ over %move operand-class ] keep
+    int-regs next-vreg [ over %move value-class ] keep
     tagged new
         swap >>vreg
         swap >>class
     %move ;
 
+! Operands holding pointers to freshly-allocated objects which
+! are guaranteed to be in the nursery
+SYMBOL: fresh-objects
+
+: fresh-object ( vreg/t -- ) fresh-objects get push ;
+
+: fresh-object? ( vreg -- ? ) fresh-objects get memq? ;
+
 : %move ( dst src -- )
     2dup [ move-spec ] bi@ 2array {
-        { { f f } [ %copy ] }
-        { { unboxed-alien unboxed-alien } [ %copy ] }
-        { { unboxed-byte-array unboxed-byte-array } [ %copy ] }
-        { { unboxed-f unboxed-f } [ %copy ] }
-        { { unboxed-c-ptr unboxed-c-ptr } [ %copy ] }
-        { { float float } [ %copy-float ] }
+        { { f f } [ ##copy ] }
+        { { unboxed-alien unboxed-alien } [ ##copy ] }
+        { { unboxed-byte-array unboxed-byte-array } [ ##copy ] }
+        { { unboxed-f unboxed-f } [ ##copy ] }
+        { { unboxed-c-ptr unboxed-c-ptr } [ ##copy ] }
+        { { float float } [ ##copy-float ] }
 
         { { f unboxed-c-ptr } [ %move-bug ] }
         { { f unboxed-byte-array } [ %move-bug ] }
 
-        { { f constant } [ value>> swap %load-literal ] }
+        { { f constant } [ value>> ##load-literal ] }
 
-        { { f float } [ %box-float ] }
-        { { f unboxed-alien } [ %box-alien ] }
-        { { f loc } [ %peek ] }
+        { { f float } [ int-regs next-vreg ##box-float t fresh-object ] }
+        { { f unboxed-alien } [ int-regs next-vreg ##box-alien t fresh-object ] }
+        { { f loc } [ ##peek ] }
 
-        { { float f } [ %unbox-float ] }
-        { { unboxed-alien f } [ %unbox-alien ] }
-        { { unboxed-byte-array f } [ %unbox-byte-array ] }
-        { { unboxed-f f } [ %unbox-f ] }
+        { { float f } [ ##unbox-float ] }
+        { { unboxed-alien f } [ ##unbox-alien ] }
+        { { unboxed-byte-array f } [ ##unbox-byte-array ] }
+        { { unboxed-f f } [ ##unbox-f ] }
         { { unboxed-c-ptr f } [ %unbox-c-ptr ] }
-        { { loc f } [ swap %replace ] }
+        { { loc f } [ swap ##replace ] }
 
         [ drop %move-via-temp ]
     } case ;
@@ -174,7 +161,7 @@ TUPLE: phantom-datastack < phantom-stack ;
 M: phantom-datastack <loc> (loc) <ds-loc> ;
 
 M: phantom-datastack finalize-height
-    \ %inc-d (finalize-height) ;
+    \ ##inc-d (finalize-height) ;
 
 TUPLE: phantom-retainstack < phantom-stack ;
 
@@ -184,7 +171,7 @@ TUPLE: phantom-retainstack < phantom-stack ;
 M: phantom-retainstack <loc> (loc) <rs-loc> ;
 
 M: phantom-retainstack finalize-height
-    \ %inc-r (finalize-height) ;
+    \ ##inc-r (finalize-height) ;
 
 : phantom-locs ( n phantom -- locs )
     #! A sequence of n ds-locs or rs-locs indexing the stack.
@@ -238,10 +225,6 @@ M: phantom-retainstack finalize-height
 : live-locs ( -- seq )
     [ (live-locs) ] each-phantom append prune ;
 
-! Operands holding pointers to freshly-allocated objects which
-! are guaranteed to be in the nursery
-SYMBOL: fresh-objects
-
 : reg-spec>class ( spec -- class )
     float eq? double-float-regs int-regs ? ;
 
@@ -265,12 +248,12 @@ SYMBOL: fresh-objects
     } cond 2nip ;
 
 : alloc-vreg-for ( value spec -- vreg )
-    alloc-vreg swap operand-class
+    alloc-vreg swap value-class
     over tagged? [ >>class ] [ drop ] if ;
 
 M: value (lazy-load)
     {
-        { [ dup quotation? ] [ drop ] }
+        { [ dup { small-slot small-tagged } memq? ] [ drop ] }
         { [ 2dup compatible? ] [ drop ] }
         [ (eager-load) ]
     } cond ;
@@ -295,23 +278,11 @@ M: loc lazy-store
         dup loc? over cached? or [ 2drop ] [ %move ] if
     ] each-loc ;
 
-: reset-phantom ( phantom -- )
-    #! Kill register assignments but preserve constants and
-    #! class information.
-    dup phantom-locs*
-    over stack>> [
-        dup constant? [ nip ] [
-            operand-class over set-operand-class
-        ] if
-    ] 2map
-    over stack>> delete-all
-    swap stack>> push-all ;
-
-: reset-phantoms ( -- )
-    [ reset-phantom ] each-phantom ;
+: clear-phantoms ( -- )
+    [ stack>> delete-all ] each-phantom ;
 
 : finalize-contents ( -- )
-    finalize-locs finalize-vregs reset-phantoms ;
+    finalize-locs finalize-vregs clear-phantoms ;
 
 ! Loading stacks to vregs
 : vreg-substitution ( value vreg -- pair )
@@ -327,26 +298,22 @@ M: loc lazy-store
     [ substitute-vreg? ] assoc-filter >hashtable
     '[ stack>> _ substitute-here ] each-phantom ;
 
-: clear-phantoms ( -- )
-    [ stack>> delete-all ] each-phantom ;
-
-: set-operand-classes ( classes -- )
+: set-value-classes ( classes -- )
     phantom-datastack get
     over length over add-locs
-    stack>> [ set-operand-class ] 2reverse-each ;
+    stack>> [
+        [ value-class class-and ] keep set-value-class
+    ] 2reverse-each ;
 
 : finalize-phantoms ( -- )
     #! Commit all deferred stacking shuffling, and ensure the
     #! in-memory data and retain stacks are up to date with
     #! respect to the compiler's current picture.
     finalize-contents
-    clear-phantoms
     finalize-heights
-    fresh-objects get [ empty? [ %gc ] unless ] [ delete-all ] bi ;
-
-: fresh-object ( obj -- ) fresh-objects get push ;
-
-: fresh-object? ( obj -- ? ) fresh-objects get memq? ;
+    fresh-objects get [
+        empty? [ 0 ##frame-required ##gc ] unless
+    ] [ delete-all ] bi ;
 
 : init-phantoms ( -- )
     V{ } clone fresh-objects set
@@ -358,14 +325,6 @@ M: loc lazy-store
     phantom-datastack [ clone ] change
     phantom-retainstack [ clone ] change ;
 
-: operand-tag ( operand -- tag/f )
-    operand-class dup [ class-tag ] when ;
-
-UNION: immediate fixnum POSTPONE: f ;
-
-: operand-immediate? ( operand -- ? )
-    operand-class immediate class<= ;
-
 : phantom-push ( obj -- )
     1 phantom-datastack get adjust-phantom
     phantom-datastack get stack>> push ;
@@ -387,3 +346,7 @@ UNION: immediate fixnum POSTPONE: f ;
 
 : phantom-rdrop ( n -- )
     phantom-retainstack get phantom-input drop ;
+
+: phantom-pop ( -- vreg )
+    1 phantom-datastack get phantom-input dup first f (lazy-load)
+    [ 1array substitute-vregs ] keep ;
index 798e1fd563e67110ba6e1b5933eb876a0a9c687c..12a56704d07c602dce03c50af61a726ca6ca0c5e 100644 (file)
@@ -1,20 +1,11 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: assocs accessors sequences kernel fry namespaces
-quotations combinators classes.algebra compiler.instructions
-compiler.registers compiler.cfg.stacks ;
+quotations combinators classes.algebra compiler.backend
+compiler.cfg.instructions compiler.cfg.registers compiler.cfg.stacks ;
 IN: compiler.cfg.templates
 
-USE: qualified
-FROM: compiler.generator.registers => +input+   ;
-FROM: compiler.generator.registers => +output+  ;
-FROM: compiler.generator.registers => +scratch+ ;
-FROM: compiler.generator.registers => +clobber+ ;
-
-: template-input +input+ swap at ; inline
-: template-output +output+ swap at ; inline
-: template-scratch +scratch+ swap at ; inline
-: template-clobber +clobber+ swap at ; inline
+TUPLE: template input output scratch clobber gc ;
 
 : phantom&spec ( phantom specs -- phantom' specs' )
     >r stack>> r>
@@ -28,7 +19,7 @@ FROM: compiler.generator.registers => +clobber+ ;
     [ stack>> [ >vreg ] map sift ] each-phantom append ;
 
 : clobbered ( template -- seq )
-    [ template-output ] [ template-clobber ] bi append ;
+    [ output>> ] [ clobber>> ] bi append ;
 
 : clobbered? ( value name -- ? )
     \ clobbered get member? [
@@ -49,25 +40,27 @@ FROM: compiler.generator.registers => +clobber+ ;
     [
         live-vregs \ live-vregs set
         dup clobbered \ clobbered set
-        template-input [ values ] [ lazy-load ] bi zip
+        input>> [ values ] [ lazy-load ] bi zip
     ] with-scope ;
 
 : alloc-scratch ( template -- assoc )
-    template-scratch [ swap alloc-vreg ] assoc-map ;
+    scratch>> [ swap alloc-vreg ] assoc-map ;
 
-: do-template-inputs ( template -- inputs )
+: do-template-inputs ( template -- defs uses )
     #! Load input values into registers and allocates scratch
     #! registers.
-    [ load-inputs ] [ alloc-scratch ] bi assoc-union ;
+    [ alloc-scratch ] [ load-inputs ] bi ;
 
-: do-template-outputs ( template inputs -- )
-    [ template-output ] dip '[ _ at ] map
+: do-template-outputs ( template defs uses -- )
+    [ output>> ] 2dip assoc-union '[ _ at ] map
     phantom-datastack get phantom-append ;
 
 : apply-template ( pair quot -- vregs )
     [
-        first2 dup do-template-inputs
-        [ do-template-outputs ] keep
+        first2
+        dup gc>> [ t fresh-object ] when
+        dup do-template-inputs
+        [ do-template-outputs ] 2keep
     ] dip call ; inline
 
 : value-matches? ( value spec -- ? )
@@ -76,12 +69,11 @@ FROM: compiler.generator.registers => +clobber+ ;
     #! to the fixnum. Otherwise, the values don't match. If the
     #! spec is not a quotation, its a reg-class, in which case
     #! the value is always good.
-    dup quotation? [
-        over constant?
-        [ >r value>> r> 2drop f ] [ 2drop f ] if
-    ] [
-        2drop t
-    ] if ;
+    {
+        { [ dup small-slot eq? ] [ drop dup constant? [ value>> small-slot? ] [ drop f ] if ] }
+        { [ dup small-tagged eq? ] [ drop dup constant? [ value>> small-tagged? ] [ drop f ] if ] }
+        [ 2drop t ]
+    } cond ;
 
 : class-matches? ( actual expected -- ? )
     {
@@ -92,10 +84,10 @@ FROM: compiler.generator.registers => +clobber+ ;
 
 : spec-matches? ( value spec -- ? )
     2dup first value-matches?
-    >r >r operand-class 2 r> ?nth class-matches? r> and ;
+    >r >r value-class 2 r> ?nth class-matches? r> and ;
 
 : template-matches? ( template -- ? )
-    template-input phantom-datastack get swap
+    input>> phantom-datastack get swap
     [ spec-matches? ] phantom&spec-agree? ;
 
 : find-template ( templates -- pair/f )
diff --git a/unfinished/compiler/codegen/codegen.factor b/unfinished/compiler/codegen/codegen.factor
new file mode 100644 (file)
index 0000000..15ebd69
--- /dev/null
@@ -0,0 +1,433 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces make math math.parser sequences accessors
+kernel kernel.private layouts assocs words summary arrays
+combinators classes.algebra alien alien.c-types alien.structs
+alien.strings sets threads libc continuations.private
+compiler.errors
+compiler.alien
+compiler.backend
+compiler.codegen.fixup
+compiler.cfg
+compiler.cfg.instructions
+compiler.cfg.registers ;
+IN: compiler.codegen
+
+GENERIC: generate-insn ( insn -- )
+
+GENERIC: v>operand ( obj -- operand )
+
+SYMBOL: registers
+
+M: constant v>operand
+    value>> [ tag-fixnum ] [ \ f tag-number ] if* ;
+
+M: value v>operand
+    >vreg [ registers get at ] [ "Bad value" throw ] if* ;
+
+: generate-insns ( insns -- code )
+    [
+        [
+            dup regs>> registers set
+            generate-insn
+        ] each
+    ] { } make fixup ;
+
+TUPLE: asm label code calls ;
+
+SYMBOL: calls
+
+: add-call ( word -- )
+    #! Compile this word later.
+    calls get push ;
+
+SYMBOL: compiling-word
+
+: compiled-stack-traces? ( -- ? ) 59 getenv ;
+
+! Mapping _label IDs to label instances
+SYMBOL: labels
+
+: init-generator ( word -- )
+    H{ } clone labels set
+    V{ } clone literal-table set
+    V{ } clone calls set
+    compiling-word set
+    compiled-stack-traces? compiling-word get f ? add-literal drop ;
+
+: generate ( mr -- asm )
+    [
+        [ label>> ]
+        [ word>> init-generator ]
+        [ instructions>> generate-insns ] tri
+        calls get
+        asm boa
+    ] with-scope ;
+
+: lookup-label ( id -- label )
+    labels get [ drop <label> ] cache ;
+
+M: _label generate-insn
+    id>> lookup-label , ;
+
+M: _prologue generate-insn
+    drop %prologue ;
+
+M: _epilogue generate-insn
+    drop %epilogue ;
+
+M: ##load-literal generate-insn
+    [ obj>> ] [ dst>> v>operand ] bi load-literal ;
+
+M: ##peek generate-insn
+    [ dst>> v>operand ] [ loc>> ] bi %peek ;
+
+M: ##replace generate-insn
+    [ src>> ] [ loc>> ] bi %replace ;
+
+M: ##inc-d generate-insn n>> %inc-d ;
+
+M: ##inc-r generate-insn n>> %inc-r ;
+
+M: ##return generate-insn drop %return ;
+
+M: ##call generate-insn word>> [ add-call ] [ %call ] bi ;
+
+M: ##jump generate-insn word>> [ add-call ] [ %jump-label ] bi ;
+
+SYMBOL: operands
+
+: init-intrinsic ( insn -- )
+    [ defs-vregs>> ] [ uses-vregs>> ] bi append operands set ;
+
+M: ##intrinsic generate-insn
+    [ init-intrinsic ] [ quot>> call ] bi ;
+
+: (operand) ( name -- operand )
+    operands get at* [ "Bad operand name" throw ] unless ;
+
+: operand ( name -- operand )
+    (operand) v>operand ;
+
+: operand-class ( var -- class )
+    (operand) value-class ;
+
+: operand-tag ( operand -- tag/f )
+    operand-class dup [ class-tag ] when ;
+
+: operand-immediate? ( operand -- ? )
+    operand-class immediate class<= ;
+
+: unique-operands ( operands quot -- )
+    >r [ operand ] map prune r> each ; inline
+
+M: _if-intrinsic generate-insn
+    [ init-intrinsic ]
+    [ [ label>> lookup-label ] [ quot>> ] bi call ] bi ;
+
+M: _branch generate-insn
+    label>> lookup-label %jump-label ;
+
+M: _branch-f generate-insn
+    [ src>> v>operand ] [ label>> lookup-label ] bi %jump-f ;
+
+M: _branch-t generate-insn
+    [ src>> v>operand ] [ label>> lookup-label ] bi %jump-t ;
+
+M: ##dispatch-label generate-insn label>> %dispatch-label ;
+
+M: ##dispatch generate-insn drop %dispatch ;
+
+: dst/src ( insn -- dst src )
+    [ dst>> v>operand ] [ src>> v>operand ] bi ;
+
+M: ##copy generate-insn dst/src %copy ;
+
+M: ##copy-float generate-insn dst/src %copy-float ;
+
+M: ##unbox-float generate-insn dst/src %unbox-float ;
+
+M: ##unbox-f generate-insn dst/src %unbox-f ;
+
+M: ##unbox-alien generate-insn dst/src %unbox-alien ;
+
+M: ##unbox-byte-array generate-insn dst/src %unbox-byte-array ;
+
+M: ##unbox-any-c-ptr generate-insn dst/src %unbox-any-c-ptr ;
+
+M: ##box-float generate-insn dst/src %box-float ;
+
+M: ##box-alien generate-insn dst/src %box-alien ;
+
+M: ##allot generate-insn
+    {
+        [ dst>> v>operand ]
+        [ size>> ]
+        [ type>> ]
+        [ tag>> ]
+        [ temp>> v>operand ]
+    } cleave
+    %allot ;
+
+M: ##write-barrier generate-insn
+    [ src>> v>operand ] [ temp>> v>operand ] bi %write-barrier ;
+
+M: ##gc generate-insn drop %gc ;
+
+! #alien-invoke
+GENERIC: reg-size ( register-class -- n )
+
+M: int-regs reg-size drop cell ;
+
+M: single-float-regs reg-size drop 4 ;
+
+M: double-float-regs reg-size drop 8 ;
+
+GENERIC: reg-class-variable ( register-class -- symbol )
+
+M: reg-class reg-class-variable ;
+
+M: float-regs reg-class-variable drop float-regs ;
+
+GENERIC: inc-reg-class ( register-class -- )
+
+M: reg-class inc-reg-class
+    dup reg-class-variable inc
+    fp-shadows-int? [ reg-size stack-params +@ ] [ drop ] if ;
+
+M: float-regs inc-reg-class
+    dup call-next-method
+    fp-shadows-int? [ reg-size cell /i int-regs +@ ] [ drop ] if ;
+
+GENERIC: reg-class-full? ( class -- ? )
+
+M: stack-params reg-class-full? drop t ;
+
+M: object reg-class-full?
+    [ reg-class-variable get ] [ param-regs length ] bi >= ;
+
+: spill-param ( reg-class -- n reg-class )
+    stack-params get
+    >r reg-size stack-params +@ r>
+    stack-params ;
+
+: fastcall-param ( reg-class -- n reg-class )
+    [ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
+
+: alloc-parameter ( parameter -- reg reg-class )
+    c-type-reg-class dup reg-class-full?
+    [ spill-param ] [ fastcall-param ] if
+    [ param-reg ] keep ;
+
+: (flatten-int-type) ( size -- seq )
+    cell /i "void*" c-type <repetition> ;
+
+GENERIC: flatten-value-type ( type -- types )
+
+M: object flatten-value-type 1array ;
+
+M: struct-type flatten-value-type ( type -- types )
+    stack-size cell align (flatten-int-type) ;
+
+M: long-long-type flatten-value-type ( type -- types )
+    stack-size cell align (flatten-int-type) ;
+
+: flatten-value-types ( params -- params )
+    #! Convert value type structs to consecutive void*s.
+    [
+        0 [
+            c-type
+            [ parameter-align (flatten-int-type) % ] keep
+            [ stack-size cell align + ] keep
+            flatten-value-type %
+        ] reduce drop
+    ] { } make ;
+
+: each-parameter ( parameters quot -- )
+    >r [ parameter-sizes nip ] keep r> 2each ; inline
+
+: reverse-each-parameter ( parameters quot -- )
+    >r [ parameter-sizes nip ] keep r> 2reverse-each ; inline
+
+: reset-freg-counts ( -- )
+    { int-regs float-regs stack-params } [ 0 swap set ] each ;
+
+: with-param-regs ( quot -- )
+    #! In quot you can call alloc-parameter
+    [ reset-freg-counts call ] with-scope ; inline
+
+: move-parameters ( node word -- )
+    #! Moves values from C stack to registers (if word is
+    #! %load-param-reg) and registers to C stack (if word is
+    #! %save-param-reg).
+    >r
+    alien-parameters
+    flatten-value-types
+    r> [ >r alloc-parameter r> execute ] curry each-parameter ;
+    inline
+
+: unbox-parameters ( offset node -- )
+    parameters>> [
+        %prepare-unbox >r over + r> unbox-parameter
+    ] reverse-each-parameter drop ;
+
+: prepare-box-struct ( node -- offset )
+    #! Return offset on C stack where to store unboxed
+    #! parameters. If the C function is returning a structure,
+    #! the first parameter is an implicit target area pointer,
+    #! so we need to use a different offset.
+    return>> dup large-struct?
+    [ heap-size %prepare-box-struct cell ] [ drop 0 ] if ;
+
+: objects>registers ( params -- )
+    #! Generate code for unboxing a list of C types, then
+    #! generate code for moving these parameters to register on
+    #! architectures where parameters are passed in registers.
+    [
+        [ prepare-box-struct ] keep
+        [ unbox-parameters ] keep
+        \ %load-param-reg move-parameters
+    ] with-param-regs ;
+
+: box-return* ( node -- )
+    return>> [ ] [ box-return ] if-void ;
+
+TUPLE: no-such-library name ;
+
+M: no-such-library summary
+    drop "Library not found" ;
+
+M: no-such-library compiler-error-type
+    drop +linkage+ ;
+
+: no-such-library ( name -- )
+    \ no-such-library boa
+    compiling-word get compiler-error ;
+
+TUPLE: no-such-symbol name ;
+
+M: no-such-symbol summary
+    drop "Symbol not found" ;
+
+M: no-such-symbol compiler-error-type
+    drop +linkage+ ;
+
+: no-such-symbol ( name -- )
+    \ no-such-symbol boa
+    compiling-word get compiler-error ;
+
+: check-dlsym ( symbols dll -- )
+    dup dll-valid? [
+        dupd [ dlsym ] curry contains?
+        [ drop ] [ no-such-symbol ] if
+    ] [
+        dll-path no-such-library drop
+    ] if ;
+
+: stdcall-mangle ( symbol node -- symbol )
+    "@"
+    swap parameters>> parameter-sizes drop
+    number>string 3append ;
+
+: alien-invoke-dlsym ( params -- symbols dll )
+    dup function>> dup pick stdcall-mangle 2array
+    swap library>> library dup [ dll>> ] when
+    2dup check-dlsym ;
+
+M: ##alien-invoke generate-insn
+    params>>
+    ! Save registers for GC
+    %prepare-alien-invoke
+    ! Unbox parameters
+    dup objects>registers
+    %prepare-var-args
+    ! Call function
+    dup alien-invoke-dlsym %alien-invoke
+    ! Box return value
+    dup %cleanup
+    box-return* ;
+
+! ##alien-indirect
+M: ##alien-indirect generate-insn
+    params>>
+    ! Save registers for GC
+    %prepare-alien-invoke
+    ! Save alien at top of stack to temporary storage
+    %prepare-alien-indirect
+    ! Unbox parameters
+    dup objects>registers
+    %prepare-var-args
+    ! Call alien in temporary storage
+    %alien-indirect
+    ! Box return value
+    dup %cleanup
+    box-return* ;
+
+! ##alien-callback
+: box-parameters ( params -- )
+    alien-parameters [ box-parameter ] each-parameter ;
+
+: registers>objects ( node -- )
+    [
+        dup \ %save-param-reg move-parameters
+        "nest_stacks" f %alien-invoke
+        box-parameters
+    ] with-param-regs ;
+
+TUPLE: callback-context ;
+
+: current-callback 2 getenv ;
+
+: wait-to-return ( token -- )
+    dup current-callback eq? [
+        drop
+    ] [
+        yield wait-to-return
+    ] if ;
+
+: do-callback ( quot token -- )
+    init-catchstack
+    dup 2 setenv
+    slip
+    wait-to-return ; inline
+
+: callback-return-quot ( ctype -- quot )
+    return>> {
+        { [ dup "void" = ] [ drop [ ] ] }
+        { [ dup large-struct? ] [ heap-size [ memcpy ] curry ] }
+        [ c-type c-type-unboxer-quot ]
+    } cond ;
+
+: callback-prep-quot ( params -- quot )
+    parameters>> [ c-type c-type-boxer-quot ] map spread>quot ;
+
+: wrap-callback-quot ( params -- quot )
+    [
+        [ callback-prep-quot ]
+        [ quot>> ]
+        [ callback-return-quot ] tri 3append ,
+        [ callback-context new do-callback ] %
+    ] [ ] make ;
+
+: %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ;
+
+: callback-unwind ( params -- n )
+    {
+        { [ dup abi>> "stdcall" = ] [ alien-stack-frame ] }
+        { [ dup return>> large-struct? ] [ drop 4 ] }
+        [ drop 0 ]
+    } cond ;
+
+: %callback-return ( params -- )
+    #! All the extra book-keeping for %unwind is only for x86.
+    #! On other platforms its an alias for %return.
+    dup alien-return
+    [ %unnest-stacks ] [ %callback-value ] if-void
+    callback-unwind %unwind ;
+
+M: ##alien-callback generate-insn
+    params>>
+    [ registers>objects ]
+    [ wrap-callback-quot %alien-callback ]
+    [ %callback-return ]
+    tri ;
index 1f1cf81cb9789c2b50adaf1a9638e3d67ffae555..5e8c1809a556219819e8bbd9a89904b82fdb4b0a 100755 (executable)
@@ -3,76 +3,20 @@
 USING: arrays byte-arrays generic assocs hashtables io.binary
 kernel kernel.private math namespaces make sequences words
 quotations strings alien.accessors alien.strings layouts system
-combinators math.bitwise words.private cpu.architecture
-math.order accessors growable ;
-IN: compiler.cfg.fixup
+combinators math.bitwise words.private math.order accessors
+growable compiler.constants compiler.backend ;
+IN: compiler.codegen.fixup
 
-: no-stack-frame -1 ; inline
-
-TUPLE: frame-required n ;
-
-: frame-required ( n -- ) \ frame-required boa , ;
-
-: stack-frame-size ( code -- n )
-    no-stack-frame [
-        dup frame-required? [ n>> max ] [ drop ] if
-    ] reduce ;
-
-GENERIC: fixup* ( frame-size obj -- frame-size )
+GENERIC: fixup* ( obj -- )
 
 : code-format 22 getenv ;
 
 : compiled-offset ( -- n ) building get length code-format * ;
 
-TUPLE: label offset ;
-
-: <label> ( -- label ) label new ;
-
-M: label fixup*
-    compiled-offset >>offset drop ;
-
-: define-label ( name -- ) <label> swap set ;
-
-: resolve-label ( label/name -- ) dup label? [ get ] unless , ;
-
-: if-stack-frame ( frame-size quot -- )
-    swap dup no-stack-frame =
-    [ 2drop ] [ stack-frame swap call ] if ; inline
-
-M: word fixup*
-    {
-        { \ %prologue-later [ dup [ %prologue ] if-stack-frame ] }
-        { \ %epilogue-later [ dup [ %epilogue ] if-stack-frame ] }
-    } case ;
-
 SYMBOL: relocation-table
 SYMBOL: label-table
 
-! Relocation classes
-: rc-absolute-cell     0 ;
-: rc-absolute          1 ;
-: rc-relative          2 ;
-: rc-absolute-ppc-2/2  3 ;
-: rc-relative-ppc-2    4 ;
-: rc-relative-ppc-3    5 ;
-: rc-relative-arm-3    6 ;
-: rc-indirect-arm      7 ;
-: rc-indirect-arm-pc   8 ;
-
-: rc-absolute? ( n -- ? )
-    dup rc-absolute-cell =
-    over rc-absolute =
-    rot rc-absolute-ppc-2/2 = or or ;
-
-! Relocation types
-: rt-primitive 0 ;
-: rt-dlsym     1 ;
-: rt-literal   2 ;
-: rt-dispatch  3 ;
-: rt-xt        4 ;
-: rt-here      5 ;
-: rt-label     6 ;
-: rt-immediate 7 ;
+M: label fixup* compiled-offset >>offset drop ;
 
 TUPLE: label-fixup label class ;
 
@@ -81,7 +25,7 @@ TUPLE: label-fixup label class ;
 M: label-fixup fixup*
     dup class>> rc-absolute?
     [ "Absolute labels not supported" throw ] when
-    dup label>> swap class>> compiled-offset 4 - rot
+    [ label>> ] [ class>> ] bi compiled-offset 4 - rot
     3array label-table get push ;
 
 TUPLE: rel-fixup arg class type ;
@@ -97,8 +41,6 @@ M: rel-fixup fixup*
     [ class>> rc-absolute-cell = cell 4 ? compiled-offset swap - ] bi
     [ relocation-table get push-4 ] bi@ ;
 
-M: frame-required fixup* drop ;
-
 M: integer fixup* , ;
 
 : adjoin* ( obj table -- n )
@@ -143,12 +85,11 @@ SYMBOL: literal-table
         3array
     ] map concat ;
 
-: fixup ( code -- literals relocation labels code )
+: fixup ( fixup-directives -- code )
     [
         init-fixup
-        dup stack-frame-size swap [ fixup* ] each drop
-
+        [ fixup* ] each
         literal-table get >array
         relocation-table get >byte-array
         label-table get resolve-labels
-    ] { } make ;
+    ] { } make 4array ;
diff --git a/unfinished/compiler/instructions/instructions.factor b/unfinished/compiler/instructions/instructions.factor
deleted file mode 100644 (file)
index 57b3ff5..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: assocs accessors arrays kernel sequences namespaces
-math compiler.instructions.syntax ;
-IN: compiler.instructions
-
-! Virtual CPU instructions, used by CFG and machine IRs
-
-INSN: %cond-branch vreg ;
-INSN: %unary dst src ;
-
-! Stack operations
-INSN: %peek vreg loc ;
-INSN: %replace vreg loc ;
-INSN: %inc-d n ;
-INSN: %inc-r n ;
-INSN: %load-literal obj vreg ;
-
-! Calling convention
-INSN: %return ;
-
-! Subroutine calls
-INSN: %call word ;
-INSN: %jump word ;
-INSN: %intrinsic quot vregs ;
-
-! Jump tables
-INSN: %dispatch-label label ;
-INSN: %dispatch ;
-
-! Boxing and unboxing
-INSN: %copy < %unary ;
-INSN: %copy-float < %unary ;
-INSN: %unbox-float < %unary ;
-INSN: %unbox-f < %unary ;
-INSN: %unbox-alien < %unary ;
-INSN: %unbox-byte-array < %unary ;
-INSN: %unbox-any-c-ptr < %unary ;
-INSN: %box-float < %unary ;
-INSN: %box-alien < %unary ;
-
-INSN: %gc ;
-
-! FFI
-INSN: %alien-invoke params ;
-INSN: %alien-indirect params ;
-INSN: %alien-callback params ;
-
-GENERIC: uses-vregs ( insn -- seq )
-
-M: insn uses-vregs drop f ;
-M: %peek uses-vregs vreg>> 1array ;
-M: %replace uses-vregs vreg>> 1array ;
-M: %load-literal uses-vregs vreg>> 1array ;
-M: %unary uses-vregs [ dst>> ] [ src>> ] bi 2array ;
-M: %intrinsic uses-vregs vregs>> values ;
-
-! Instructions used by CFG IR only.
-INSN: %prologue ;
-INSN: %epilogue ;
-INSN: %frame-required n ;
-
-INSN: %branch ;
-INSN: %branch-f < %cond-branch ;
-INSN: %branch-t < %cond-branch ;
-INSN: %if-intrinsic quot vregs ;
-INSN: %boolean-intrinsic quot vregs out ;
-
-M: %cond-branch uses-vregs vreg>> 1array ;
-M: %if-intrinsic uses-vregs vregs>> values ;
-M: %boolean-intrinsic uses-vregs
-    [ vregs>> values ] [ out>> ] bi suffix ;
-
-! Instructions used by machine IR only.
-INSN: _prologue n ;
-INSN: _epilogue n ;
-
-TUPLE: label id ;
-
-INSN: _label label ;
-
-: <label> ( -- label ) \ <label> counter label boa ;
-: define-label ( name -- ) <label> swap set ;
-
-: resolve-label ( label/name -- )
-    dup label? [ get ] unless _label ;
-
-TUPLE: _cond-branch vreg label ;
-
-INSN: _branch label ;
-INSN: _branch-f < _cond-branch ;
-INSN: _branch-t < _cond-branch ;
-INSN: _if-intrinsic label quot vregs ;
-
-M: _cond-branch uses-vregs vreg>> 1array ;
-M: _if-intrinsic uses-vregs vregs>> values ;
diff --git a/unfinished/compiler/instructions/syntax/syntax.factor b/unfinished/compiler/instructions/syntax/syntax.factor
deleted file mode 100644 (file)
index 0a4ffae..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: classes.tuple classes.tuple.parser kernel words
-make parser ;
-IN: compiler.instructions.syntax
-
-TUPLE: insn ;
-
-: INSN:
-    parse-tuple-definition
-    [ dup tuple eq? [ drop insn ] when ] dip
-    [ define-tuple-class ]
-    [ 2drop save-location ]
-    [ 2drop dup [ boa , ] curry define-inline ]
-    3tri ; parsing
diff --git a/unfinished/compiler/new/new.factor b/unfinished/compiler/new/new.factor
new file mode 100644 (file)
index 0000000..fd40291
--- /dev/null
@@ -0,0 +1,122 @@
+! Copyright (C) 2004, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel namespaces arrays sequences io debugger
+words fry continuations vocabs assocs dlists definitions math
+threads graphs generic combinators deques search-deques
+stack-checker stack-checker.state stack-checker.inlining
+compiler.errors compiler.units compiler.tree.builder
+compiler.tree.optimizer compiler.cfg.builder
+compiler.cfg.linearization compiler.cfg.linear-scan
+compiler.cfg.stack-frame compiler.codegen ;
+IN: compiler.new
+
+SYMBOL: compile-queue
+SYMBOL: compiled
+
+: queue-compile ( word -- )
+    {
+        { [ dup "forgotten" word-prop ] [ ] }
+        { [ dup compiled get key? ] [ ] }
+        { [ dup inlined-block? ] [ ] }
+        { [ dup primitive? ] [ ] }
+        [ dup compile-queue get push-front ]
+    } cond drop ;
+
+: maybe-compile ( word -- )
+    dup compiled>> [ drop ] [ queue-compile ] if ;
+
+SYMBOL: +failed+
+
+: ripple-up ( words -- )
+    dup "compiled-effect" word-prop +failed+ eq?
+    [ usage [ word? ] filter ] [ compiled-usage keys ] if
+    [ queue-compile ] each ;
+
+: ripple-up? ( word effect -- ? )
+    #! If the word has previously been compiled and had a
+    #! different stack effect, we have to recompile any callers.
+    swap "compiled-effect" word-prop [ = not ] keep and ;
+
+: save-effect ( word effect -- )
+    [ dupd ripple-up? [ ripple-up ] [ drop ] if ]
+    [ "compiled-effect" set-word-prop ]
+    2bi ;
+
+: start ( word -- )
+    H{ } clone dependencies set
+    H{ } clone generic-dependencies set
+    f swap compiler-error ;
+
+: fail ( word error -- )
+    [ swap compiler-error ]
+    [
+        drop
+        [ compiled-unxref ]
+        [ f swap compiled get set-at ]
+        [ +failed+ save-effect ]
+        tri
+    ] 2bi
+    return ;
+
+: frontend ( word -- effect nodes )
+    [ build-tree-from-word ] [ fail ] recover optimize-tree ;
+
+: finish ( effect word -- )
+    [ swap save-effect ]
+    [ compiled-unxref ]
+    [
+        dup crossref?
+        [
+            dependencies get >alist
+            generic-dependencies get >alist
+            compiled-xref
+        ] [ drop ] if
+    ] tri ;
+
+: save-asm ( asm -- )
+    [ [ code>> ] [ label>> ] bi compiled get set-at ]
+    [ calls>> [ queue-compile ] each ]
+    bi ;
+
+: backend ( nodes word -- )
+    build-cfg [
+        build-mr
+        linear-scan
+        build-stack-frame
+        generate
+        save-asm
+    ] each ;
+
+: (compile) ( word -- )
+    '[
+        _ {
+            [ start ]
+            [ frontend ]
+            [ backend ]
+            [ finish ]
+        } cleave
+    ] with-return ;
+
+: compile-loop ( deque -- )
+    [ (compile) yield ] slurp-deque ;
+
+: decompile ( word -- )
+    f 2array 1array t modify-code-heap ;
+
+: optimized-recompile-hook ( words -- alist )
+    [
+        <hashed-dlist> compile-queue set
+        H{ } clone compiled set
+        [ queue-compile ] each
+        compile-queue get compile-loop
+        compiled get >alist
+    ] with-scope ;
+
+: enable-compiler ( -- )
+    [ optimized-recompile-hook ] recompile-hook set-global ;
+
+: disable-compiler ( -- )
+    [ default-recompile-hook ] recompile-hook set-global ;
+
+: recompile-all ( -- )
+    forget-errors all-words compile ;
diff --git a/unfinished/compiler/registers/registers.factor b/unfinished/compiler/registers/registers.factor
deleted file mode 100644 (file)
index 6087064..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors namespaces math kernel ;
-IN: compiler.registers
-
-! Virtual CPU registers, used by CFG and machine IRs
-
-MIXIN: value
-
-GENERIC: >vreg ( obj -- vreg )
-
-M: value >vreg drop f ;
-
-! Register classes
-SINGLETON: int-regs
-SINGLETON: single-float-regs
-SINGLETON: double-float-regs
-UNION: float-regs single-float-regs double-float-regs ;
-UNION: reg-class int-regs float-regs ;
-
-! Virtual registers
-TUPLE: vreg reg-class n ;
-SYMBOL: vreg-counter
-: next-vreg ( reg-class -- vreg ) \ vreg-counter counter vreg boa ;
-
-M: vreg >vreg ;
-
-INSTANCE: vreg value
-
-! Stack locations
-TUPLE: loc n class ;
-
-! A data stack location.
-TUPLE: ds-loc < loc ;
-: <ds-loc> ( n -- loc ) f ds-loc boa ;
-
-TUPLE: rs-loc < loc ;
-: <rs-loc> ( n -- loc ) f rs-loc boa ;
-
-INSTANCE: loc value
-
-! A stack location which has been loaded into a register. To
-! read the location, we just read the register, but when time
-! comes to save it back to the stack, we know the register just
-! contains a stack value so we don't have to redundantly write
-! it back.
-TUPLE: cached loc vreg ;
-C: <cached> cached
-
-M: cached >vreg vreg>> >vreg ;
-
-INSTANCE: cached value
-
-! A tagged pointer
-TUPLE: tagged vreg class ;
-: <tagged> ( vreg -- tagged ) f tagged boa ;
-
-M: tagged >vreg vreg>> ;
-
-INSTANCE: tagged value
-
-! Unboxed value
-TUPLE: unboxed vreg ;
-C: <unboxed> unboxed
-
-M: unboxed >vreg vreg>> ;
-
-INSTANCE: unboxed value
-
-! Unboxed alien pointer
-TUPLE: unboxed-alien < unboxed ;
-C: <unboxed-alien> unboxed-alien
-
-! Untagged byte array pointer
-TUPLE: unboxed-byte-array < unboxed ;
-C: <unboxed-byte-array> unboxed-byte-array
-
-! A register set to f
-TUPLE: unboxed-f < unboxed ;
-C: <unboxed-f> unboxed-f
-
-! An alien, byte array or f
-TUPLE: unboxed-c-ptr < unboxed ;
-C: <unboxed-c-ptr> unboxed-c-ptr
-
-! A constant value
-TUPLE: constant value ;
-C: <constant> constant
-
-INSTANCE: constant value
diff --git a/unfinished/cpu/x86/syntax/syntax.factor b/unfinished/cpu/x86/syntax/syntax.factor
new file mode 100644 (file)
index 0000000..061cf0d
--- /dev/null
@@ -0,0 +1,16 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel words sequences lexer parser fry ;
+IN: cpu.x86.syntax
+
+: define-register ( name num size -- )
+    [ "cpu.x86" create dup define-symbol ]
+    [ dupd "register" set-word-prop ]
+    [ "register-size" set-word-prop ]
+    tri* ;
+
+: define-registers ( names size -- )
+    [ dup length ] dip '[ _ define-register ] 2each ;
+
+: REGISTERS: ( -- )
+    scan-word ";" parse-tokens swap define-registers ; parsing
diff --git a/unfinished/cpu/x86/syntax/tags.txt b/unfinished/cpu/x86/syntax/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/unfinished/cpu/x86/x86.factor b/unfinished/cpu/x86/x86.factor
new file mode 100755 (executable)
index 0000000..97003ca
--- /dev/null
@@ -0,0 +1,470 @@
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays compiler.constants compiler.backend
+compiler.codegen.fixup io.binary kernel combinators
+kernel.private math namespaces make sequences words system
+layouts math.order accessors cpu.x86.syntax ;
+IN: cpu.x86
+
+! A postfix assembler for x86 and AMD64.
+
+! In 32-bit mode, { 1234 } is absolute indirect addressing.
+! In 64-bit mode, { 1234 } is RIP-relative.
+! Beware!
+
+! Register operands -- eg, ECX
+REGISTERS: 8 AL CL DL BL ;
+
+REGISTERS: 16 AX CX DX BX SP BP SI DI ;
+
+REGISTERS: 32 EAX ECX EDX EBX ESP EBP ESI EDI ;
+
+REGISTERS: 64
+RAX RCX RDX RBX RSP RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 ;
+
+REGISTERS: 128
+XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
+XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15 ;
+
+TUPLE: byte value ;
+
+C: <byte> byte
+
+<PRIVATE
+
+#! Extended AMD64 registers (R8-R15) return true.
+GENERIC: extended? ( op -- ? )
+
+M: object extended? drop f ;
+
+PREDICATE: register < word
+    "register" word-prop ;
+
+PREDICATE: register-8 < register
+    "register-size" word-prop 8 = ;
+
+PREDICATE: register-16 < register
+    "register-size" word-prop 16 = ;
+
+PREDICATE: register-32 < register
+    "register-size" word-prop 32 = ;
+
+PREDICATE: register-64 < register
+    "register-size" word-prop 64 = ;
+
+PREDICATE: register-128 < register
+    "register-size" word-prop 128 = ;
+
+M: register extended? "register" word-prop 7 > ;
+
+! Addressing modes
+TUPLE: indirect base index scale displacement ;
+
+M: indirect extended? base>> extended? ;
+
+: canonicalize-EBP ( indirect -- indirect )
+    #! { EBP } ==> { EBP 0 }
+    dup base>> { EBP RBP R13 } member? [
+        dup displacement>> [ 0 >>displacement ] unless
+    ] when ;
+
+: canonicalize-ESP ( indirect -- indirect )
+    #! { ESP } ==> { ESP ESP }
+    dup base>> { ESP RSP R12 } member? [ ESP >>index ] when ;
+
+: canonicalize ( indirect -- indirect )
+    #! Modify the indirect to work around certain addressing mode
+    #! quirks.
+    canonicalize-EBP canonicalize-ESP ;
+
+: <indirect> ( base index scale displacement -- indirect )
+    indirect boa canonicalize ;
+
+: reg-code ( reg -- n ) "register" word-prop 7 bitand ;
+
+: indirect-base* ( op -- n ) base>> EBP or reg-code ;
+
+: indirect-index* ( op -- n ) index>> ESP or reg-code ;
+
+: indirect-scale* ( op -- n ) scale>> 0 or ;
+
+GENERIC: sib-present? ( op -- ? )
+
+M: indirect sib-present?
+    [ base>> { ESP RSP } member? ] [ index>> ] [ scale>> ] tri or or ;
+
+M: register sib-present? drop f ;
+
+GENERIC: r/m ( operand -- n )
+
+M: indirect r/m
+    dup sib-present?
+    [ drop ESP reg-code ] [ indirect-base* ] if ;
+
+M: register r/m reg-code ;
+
+! Immediate operands
+UNION: immediate byte integer ;
+
+GENERIC: fits-in-byte? ( value -- ? )
+
+M: byte fits-in-byte? drop t ;
+
+M: integer fits-in-byte? -128 127 between? ;
+
+GENERIC: modifier ( op -- n )
+
+M: indirect modifier
+    dup base>> [
+        displacement>> {
+            { [ dup not ] [ BIN: 00 ] }
+            { [ dup fits-in-byte? ] [ BIN: 01 ] }
+            { [ dup immediate? ] [ BIN: 10 ] }
+        } cond nip
+    ] [
+        drop BIN: 00
+    ] if ;
+
+M: register modifier drop BIN: 11 ;
+
+GENERIC# n, 1 ( value n -- )
+
+M: integer n, >le % ;
+M: byte n, >r value>> r> n, ;
+: 1, ( n -- ) 1 n, ; inline
+: 4, ( n -- ) 4 n, ; inline
+: 2, ( n -- ) 2 n, ; inline
+: cell, ( n -- ) bootstrap-cell n, ; inline
+
+: mod-r/m, ( reg# indirect -- )
+    [ 3 shift ] [ [ modifier 6 shift ] [ r/m ] bi ] bi* bitor bitor , ;
+
+: sib, ( indirect -- )
+    dup sib-present? [
+        [ indirect-base* ]
+        [ indirect-index* 3 shift ]
+        [ indirect-scale* 6 shift ] tri bitor bitor ,
+    ] [
+        drop
+    ] if ;
+
+GENERIC: displacement, ( op -- )
+
+M: indirect displacement,
+    dup displacement>> dup [
+        swap base>>
+        [ dup fits-in-byte? [ , ] [ 4, ] if ] [ 4, ] if
+    ] [
+        2drop
+    ] if ;
+
+M: register displacement, drop ;
+
+: addressing ( reg# indirect -- )
+    [ mod-r/m, ] [ sib, ] [ displacement, ] tri ;
+
+! Utilities
+UNION: operand register indirect ;
+
+GENERIC: operand-64? ( operand -- ? )
+
+M: indirect operand-64?
+    [ base>> ] [ index>> ] bi [ operand-64? ] either? ;
+
+M: register-64 operand-64? drop t ;
+
+M: object operand-64? drop f ;
+
+: rex.w? ( rex.w reg r/m -- ? )
+    {
+        { [ dup register-128? ] [ drop operand-64? ] }
+        { [ dup not ] [ drop operand-64? ] }
+        [ nip operand-64? ]
+    } cond and ;
+
+: rex.r ( m op -- n )
+    extended? [ BIN: 00000100 bitor ] when ;
+
+: rex.b ( m op -- n )
+    [ extended? [ BIN: 00000001 bitor ] when ] keep
+    dup indirect? [
+        index>> extended? [ BIN: 00000010 bitor ] when
+    ] [
+        drop
+    ] if ;
+
+: rex-prefix ( reg r/m rex.w -- )
+    #! Compile an AMD64 REX prefix.
+    2over rex.w? BIN: 01001000 BIN: 01000000 ?
+    swap rex.r swap rex.b
+    dup BIN: 01000000 = [ drop ] [ , ] if ;
+
+: 16-prefix ( reg r/m -- )
+    [ register-16? ] either? [ HEX: 66 , ] when ;
+
+: prefix ( reg r/m rex.w -- ) 2over 16-prefix rex-prefix ;
+
+: prefix-1 ( reg rex.w -- ) f swap prefix ;
+
+: short-operand ( reg rex.w n -- )
+    #! Some instructions encode their single operand as part of
+    #! the opcode.
+    >r dupd prefix-1 reg-code r> + , ;
+
+: opcode, ( opcode -- ) dup array? [ % ] [ , ] if ;
+
+: extended-opcode ( opcode -- opcode' ) OCT: 17 swap 2array ;
+
+: extended-opcode, ( opcode -- ) extended-opcode opcode, ;
+
+: opcode-or ( opcode mask -- opcode' )
+    swap dup array?
+    [ unclip-last rot bitor suffix ] [ bitor ] if ;
+
+: 1-operand ( op reg,rex.w,opcode -- )
+    #! The 'reg' is not really a register, but a value for the
+    #! 'reg' field of the mod-r/m byte.
+    first3 >r >r over r> prefix-1 r> opcode, swap addressing ;
+
+: immediate-operand-size-bit ( imm dst reg,rex.w,opcode -- imm dst reg,rex.w,opcode )
+    pick integer? [ first3 BIN: 1 opcode-or 3array ] when ;
+
+: immediate-1 ( imm dst reg,rex.w,opcode -- )
+    immediate-operand-size-bit 1-operand 1, ;
+
+: immediate-4 ( imm dst reg,rex.w,opcode -- )
+    immediate-operand-size-bit 1-operand 4, ;
+
+: immediate-fits-in-size-bit ( imm dst reg,rex.w,opcode -- imm dst reg,rex.w,opcode )
+    pick integer? [ first3 BIN: 10 opcode-or 3array ] when ;
+
+: immediate-1/4 ( imm dst reg,rex.w,opcode -- )
+    #! If imm is a byte, compile the opcode and the byte.
+    #! Otherwise, set the 8-bit operand flag in the opcode, and
+    #! compile the cell. The 'reg' is not really a register, but
+    #! a value for the 'reg' field of the mod-r/m byte.
+    pick fits-in-byte? [
+        immediate-fits-in-size-bit immediate-1
+    ] [
+        immediate-4
+    ] if ;
+
+: (2-operand) ( dst src op -- )
+    >r 2dup t rex-prefix r> opcode,
+    reg-code swap addressing ;
+
+: direction-bit ( dst src op -- dst' src' op' )
+    pick register? [ BIN: 10 opcode-or swapd ] when ;
+
+: operand-size-bit ( dst src op -- dst' src' op' )
+    over register-8? [ BIN: 1 opcode-or ] unless ;
+
+: 2-operand ( dst src op -- )
+    #! Sets the opcode's direction bit. It is set if the
+    #! destination is a direct register operand.
+    2over 16-prefix
+    direction-bit
+    operand-size-bit
+    (2-operand) ;
+
+PRIVATE>
+
+: [] ( reg/displacement -- indirect )
+    dup integer? [ >r f f f r> ] [ f f f ] if <indirect> ;
+
+: [+] ( reg displacement -- indirect )
+    dup integer?
+    [ dup zero? [ drop f ] when >r f f r> ]
+    [ f f ] if
+    <indirect> ;
+
+! Moving stuff
+GENERIC: PUSH ( op -- )
+M: register PUSH f HEX: 50 short-operand ;
+M: immediate PUSH HEX: 68 , 4, ;
+M: operand PUSH { BIN: 110 f HEX: ff } 1-operand ;
+
+GENERIC: POP ( op -- )
+M: register POP f HEX: 58 short-operand ;
+M: operand POP { BIN: 000 f HEX: 8f } 1-operand ;
+
+! MOV where the src is immediate.
+GENERIC: (MOV-I) ( src dst -- )
+M: register (MOV-I) t HEX: b8 short-operand cell, ;
+M: operand (MOV-I)
+    { BIN: 000 t HEX: c6 }
+    pick byte? [ immediate-1 ] [ immediate-4 ] if ;
+
+GENERIC: MOV ( dst src -- )
+M: immediate MOV swap (MOV-I) ;
+M: word MOV 0 rot (MOV-I) rc-absolute-cell rel-word ;
+M: operand MOV HEX: 88 2-operand ;
+
+: LEA ( dst src -- ) swap HEX: 8d 2-operand ;
+
+! Control flow
+GENERIC: JMP ( op -- )
+: (JMP) ( -- rel-class ) HEX: e9 , 0 4, rc-relative ;
+M: word JMP (JMP) rel-word ;
+M: label JMP (JMP) label-fixup ;
+M: operand JMP { BIN: 100 t HEX: ff } 1-operand ;
+
+GENERIC: CALL ( op -- )
+: (CALL) ( -- rel-class ) HEX: e8 , 0 4, rc-relative ;
+M: word CALL (CALL) rel-word ;
+M: label CALL (CALL) label-fixup ;
+M: operand CALL { BIN: 010 t HEX: ff } 1-operand ;
+
+GENERIC# JUMPcc 1 ( addr opcode -- )
+: (JUMPcc) ( n -- rel-class ) extended-opcode, 0 4, rc-relative ;
+M: word JUMPcc (JUMPcc) rel-word ;
+M: label JUMPcc (JUMPcc) label-fixup ;
+
+: JO  ( dst -- ) HEX: 80 JUMPcc ;
+: JNO ( dst -- ) HEX: 81 JUMPcc ;
+: JB  ( dst -- ) HEX: 82 JUMPcc ;
+: JAE ( dst -- ) HEX: 83 JUMPcc ;
+: JE  ( dst -- ) HEX: 84 JUMPcc ; ! aka JZ
+: JNE ( dst -- ) HEX: 85 JUMPcc ;
+: JBE ( dst -- ) HEX: 86 JUMPcc ;
+: JA  ( dst -- ) HEX: 87 JUMPcc ;
+: JS  ( dst -- ) HEX: 88 JUMPcc ;
+: JNS ( dst -- ) HEX: 89 JUMPcc ;
+: JP  ( dst -- ) HEX: 8a JUMPcc ;
+: JNP ( dst -- ) HEX: 8b JUMPcc ;
+: JL  ( dst -- ) HEX: 8c JUMPcc ;
+: JGE ( dst -- ) HEX: 8d JUMPcc ;
+: JLE ( dst -- ) HEX: 8e JUMPcc ;
+: JG  ( dst -- ) HEX: 8f JUMPcc ;
+
+: LEAVE ( -- ) HEX: c9 , ;
+: NOP ( -- ) HEX: 90 , ;
+
+: RET ( n -- )
+    dup zero? [ drop HEX: c3 , ] [ HEX: C2 , 2, ] if ;
+
+! Arithmetic
+
+GENERIC: ADD ( dst src -- )
+M: immediate ADD swap { BIN: 000 t HEX: 80 } immediate-1/4 ;
+M: operand ADD OCT: 000 2-operand ;
+
+GENERIC: OR ( dst src -- )
+M: immediate OR swap { BIN: 001 t HEX: 80 } immediate-1/4 ;
+M: operand OR OCT: 010 2-operand ;
+
+GENERIC: ADC ( dst src -- )
+M: immediate ADC swap { BIN: 010 t HEX: 80 } immediate-1/4 ;
+M: operand ADC OCT: 020 2-operand ;
+
+GENERIC: SBB ( dst src -- )
+M: immediate SBB swap { BIN: 011 t HEX: 80 } immediate-1/4 ;
+M: operand SBB OCT: 030 2-operand ;
+
+GENERIC: AND ( dst src -- )
+M: immediate AND swap { BIN: 100 t HEX: 80 } immediate-1/4 ;
+M: operand AND OCT: 040 2-operand ;
+
+GENERIC: SUB ( dst src -- )
+M: immediate SUB swap { BIN: 101 t HEX: 80 } immediate-1/4 ;
+M: operand SUB OCT: 050 2-operand ;
+
+GENERIC: XOR ( dst src -- )
+M: immediate XOR swap { BIN: 110 t HEX: 80 } immediate-1/4 ;
+M: operand XOR OCT: 060 2-operand ;
+
+GENERIC: CMP ( dst src -- )
+M: immediate CMP swap { BIN: 111 t HEX: 80 } immediate-1/4 ;
+M: operand CMP OCT: 070 2-operand ;
+
+: NOT  ( dst -- ) { BIN: 010 t HEX: f7 } 1-operand ;
+: NEG  ( dst -- ) { BIN: 011 t HEX: f7 } 1-operand ;
+: MUL  ( dst -- ) { BIN: 100 t HEX: f7 } 1-operand ;
+: IMUL ( src -- ) { BIN: 101 t HEX: f7 } 1-operand ;
+: DIV  ( dst -- ) { BIN: 110 t HEX: f7 } 1-operand ;
+: IDIV ( src -- ) { BIN: 111 t HEX: f7 } 1-operand ;
+
+: CDQ ( -- ) HEX: 99 , ;
+: CQO ( -- ) HEX: 48 , CDQ ;
+
+: ROL ( dst n -- ) swap { BIN: 000 t HEX: c0 } immediate-1 ;
+: ROR ( dst n -- ) swap { BIN: 001 t HEX: c0 } immediate-1 ;
+: RCL ( dst n -- ) swap { BIN: 010 t HEX: c0 } immediate-1 ;
+: RCR ( dst n -- ) swap { BIN: 011 t HEX: c0 } immediate-1 ;
+: SHL ( dst n -- ) swap { BIN: 100 t HEX: c0 } immediate-1 ;
+: SHR ( dst n -- ) swap { BIN: 101 t HEX: c0 } immediate-1 ;
+: SAR ( dst n -- ) swap { BIN: 111 t HEX: c0 } immediate-1 ;
+
+GENERIC: IMUL2 ( dst src -- )
+M: immediate IMUL2 swap dup reg-code t HEX: 68 3array immediate-1/4 ;
+M: operand IMUL2 OCT: 257 extended-opcode (2-operand) ;
+
+: MOVSX ( dst src -- )
+    dup register-32? OCT: 143 OCT: 276 extended-opcode ?
+    over register-16? [ BIN: 1 opcode-or ] when
+    swapd
+    (2-operand) ;
+
+! Conditional move
+: MOVcc ( dst src cc -- ) extended-opcode swapd (2-operand) ;
+
+: CMOVO  ( dst src -- ) HEX: 40 MOVcc ;
+: CMOVNO ( dst src -- ) HEX: 41 MOVcc ;
+: CMOVB  ( dst src -- ) HEX: 42 MOVcc ;
+: CMOVAE ( dst src -- ) HEX: 43 MOVcc ;
+: CMOVE  ( dst src -- ) HEX: 44 MOVcc ; ! aka CMOVZ
+: CMOVNE ( dst src -- ) HEX: 45 MOVcc ;
+: CMOVBE ( dst src -- ) HEX: 46 MOVcc ;
+: CMOVA  ( dst src -- ) HEX: 47 MOVcc ;
+: CMOVS  ( dst src -- ) HEX: 48 MOVcc ;
+: CMOVNS ( dst src -- ) HEX: 49 MOVcc ;
+: CMOVP  ( dst src -- ) HEX: 4a MOVcc ;
+: CMOVNP ( dst src -- ) HEX: 4b MOVcc ;
+: CMOVL  ( dst src -- ) HEX: 4c MOVcc ;
+: CMOVGE ( dst src -- ) HEX: 4d MOVcc ;
+: CMOVLE ( dst src -- ) HEX: 4e MOVcc ;
+: CMOVG  ( dst src -- ) HEX: 4f MOVcc ;
+
+! CPU Identification
+
+: CPUID ( -- ) HEX: a2 extended-opcode, ;
+
+! x87 Floating Point Unit
+
+: FSTPS ( operand -- ) { BIN: 011 f HEX: d9 } 1-operand ;
+: FSTPL ( operand -- ) { BIN: 011 f HEX: dd } 1-operand ;
+
+: FLDS ( operand -- ) { BIN: 000 f HEX: d9 } 1-operand ;
+: FLDL ( operand -- ) { BIN: 000 f HEX: dd } 1-operand ;
+
+! SSE multimedia instructions
+
+<PRIVATE
+
+: direction-bit-sse ( dst src op1 -- dst' src' op1' )
+    pick register-128? [ swapd ] [ BIN: 1 bitor ] if ;
+
+: 2-operand-sse ( dst src op1 op2 -- )
+    , direction-bit-sse extended-opcode (2-operand) ;
+
+: 2-operand-int/sse ( dst src op1 op2 -- )
+    , swapd extended-opcode (2-operand) ;
+
+PRIVATE>
+
+: MOVSS   ( dest src -- ) HEX: 10 HEX: f3 2-operand-sse ;
+: MOVSD   ( dest src -- ) HEX: 10 HEX: f2 2-operand-sse ;
+: ADDSD   ( dest src -- ) HEX: 58 HEX: f2 2-operand-sse ;
+: MULSD   ( dest src -- ) HEX: 59 HEX: f2 2-operand-sse ;
+: SUBSD   ( dest src -- ) HEX: 5c HEX: f2 2-operand-sse ;
+: DIVSD   ( dest src -- ) HEX: 5e HEX: f2 2-operand-sse ;
+: SQRTSD  ( dest src -- ) HEX: 51 HEX: f2 2-operand-sse ;
+: UCOMISD ( dest src -- ) HEX: 2e HEX: 66 2-operand-sse ;
+: COMISD  ( dest src -- ) HEX: 2f HEX: 66 2-operand-sse ;
+
+: CVTSS2SD ( dest src -- ) HEX: 5a HEX: f3 2-operand-sse ;
+: CVTSD2SS ( dest src -- ) HEX: 5a HEX: f2 2-operand-sse ;
+
+: CVTSI2SD  ( dest src -- ) HEX: 2a HEX: f2 2-operand-int/sse ;
+: CVTSD2SI  ( dest src -- ) HEX: 2d HEX: f2 2-operand-int/sse ;
+: CVTTSD2SI ( dest src -- ) HEX: 2c HEX: f2 2-operand-int/sse ;
diff --git a/unfinished/regexp2/authors.txt b/unfinished/regexp2/authors.txt
deleted file mode 100644 (file)
index 7c1b2f2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Doug Coleman
diff --git a/unfinished/regexp2/backend/backend.factor b/unfinished/regexp2/backend/backend.factor
deleted file mode 100644 (file)
index fa5c1f7..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors hashtables kernel math state-tables vars vectors ;
-IN: regexp2.backend
-
-TUPLE: regexp
-    raw
-    { stack vector }
-    parse-tree
-    { options hashtable }
-    nfa-table
-    dfa-table
-    minimized-table
-    { nfa-traversal-flags hashtable }
-    { dfa-traversal-flags hashtable }
-    { state integer }
-    { new-states vector }
-    { visited-states hashtable } ;
-
-: reset-regexp ( regexp -- regexp )
-    0 >>state
-    V{ } clone >>stack
-    V{ } clone >>new-states
-    H{ } clone >>visited-states ;
-
-SYMBOL: current-regexp
diff --git a/unfinished/regexp2/classes/classes.factor b/unfinished/regexp2/classes/classes.factor
deleted file mode 100644 (file)
index 7737e02..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math math.order symbols regexp2.parser
-words regexp2.utils unicode.categories combinators.short-circuit ;
-IN: regexp2.classes
-
-GENERIC: class-member? ( obj class -- ? )
-
-M: word class-member? ( obj class -- ? ) 2drop f ;
-M: integer class-member? ( obj class -- ? ) 2drop f ;
-
-M: character-class-range class-member? ( obj class -- ? )
-    [ from>> ] [ to>> ] bi between? ;
-
-M: any-char class-member? ( obj class -- ? )
-    2drop t ;
-    
-M: letter-class class-member? ( obj class -- ? )
-    drop letter? ;
-            
-M: LETTER-class class-member? ( obj class -- ? )
-    drop LETTER? ;
-
-M: Letter-class class-member? ( obj class -- ? )
-    drop Letter? ;
-
-M: ascii-class class-member? ( obj class -- ? )
-    drop ascii? ;
-
-M: digit-class class-member? ( obj class -- ? )
-    drop digit? ;
-
-M: alpha-class class-member? ( obj class -- ? )
-    drop alpha? ;
-
-M: punctuation-class class-member? ( obj class -- ? )
-    drop punct? ;
-
-M: java-printable-class class-member? ( obj class -- ? )
-    drop java-printable? ;
-
-M: non-newline-blank-class class-member? ( obj class -- ? )
-    drop { [ blank? ] [ CHAR: \n = not ] } 1&& ;
-
-M: control-character-class class-member? ( obj class -- ? )
-    drop control-char? ;
-
-M: hex-digit-class class-member? ( obj class -- ? )
-    drop hex-digit? ;
-
-M: java-blank-class class-member? ( obj class -- ? )
-    drop java-blank? ;
-
-M: unmatchable-class class-member? ( obj class -- ? )
-    2drop f ;
diff --git a/unfinished/regexp2/dfa/dfa.factor b/unfinished/regexp2/dfa/dfa.factor
deleted file mode 100644 (file)
index cd2f418..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs combinators fry kernel locals
-math math.order regexp2.nfa regexp2.transition-tables sequences
-sets sorting vectors regexp2.utils sequences.lib combinators.lib
-sequences.deep ;
-USING: io prettyprint threads ;
-IN: regexp2.dfa
-
-: find-delta ( states transition regexp -- new-states )
-    nfa-table>> transitions>>
-    rot [ swap at at ] with with map sift concat prune ;
-
-: (find-epsilon-closure) ( states regexp -- new-states )
-    eps swap find-delta ;
-
-: find-epsilon-closure ( states regexp -- new-states )
-    '[ dup _ (find-epsilon-closure) union ] [ length ] while-changes
-    natural-sort ;
-
-: find-closure ( states transition regexp -- new-states )
-    [ find-delta ] 2keep nip find-epsilon-closure ;
-
-: find-start-state ( regexp -- state )
-    [ nfa-table>> start-state>> 1vector ] keep find-epsilon-closure ;
-
-: find-transitions ( seq1 regexp -- seq2 )
-    nfa-table>> transitions>>
-    [ at keys ] curry map concat eps swap remove ;
-
-: add-todo-state ( state regexp -- )
-    2dup visited-states>> key? [
-        2drop
-    ] [
-        [ visited-states>> conjoin ]
-        [ new-states>> push ] 2bi
-    ] if ;
-
-: new-transitions ( regexp -- )
-    dup new-states>> [
-        drop
-    ] [
-        dupd pop dup pick find-transitions rot
-        [
-            [ [ find-closure ] 2keep nip dupd add-todo-state ] 3keep
-            >r swapd transition make-transition r> dfa-table>> add-transition 
-        ] curry with each
-        new-transitions
-    ] if-empty ;
-
-: states ( hashtable -- array )
-    [ keys ]
-    [ values [ values concat ] map concat append ] bi ;
-
-: set-final-states ( regexp -- )
-    dup
-    [ nfa-table>> final-states>> keys ]
-    [ dfa-table>> transitions>> states ] bi
-    [ intersect empty? not ] with filter
-
-    swap dfa-table>> final-states>>
-    [ conjoin ] curry each ;
-
-: set-initial-state ( regexp -- )
-    dup
-    [ dfa-table>> ] [ find-start-state ] bi
-    [ >>start-state drop ] keep
-    1vector >>new-states drop ;
-
-: set-traversal-flags ( regexp -- )
-    [ dfa-table>> transitions>> keys ]
-    [ nfa-traversal-flags>> ]
-    bi 2drop ;
-
-: construct-dfa ( regexp -- )
-    [ set-initial-state ]
-    [ new-transitions ]
-    [ set-final-states ] tri ;
-    ! [ set-traversal-flags ] quad ;
diff --git a/unfinished/regexp2/nfa/nfa.factor b/unfinished/regexp2/nfa/nfa.factor
deleted file mode 100644 (file)
index 792d9fe..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs grouping kernel regexp2.backend
-locals math namespaces regexp2.parser sequences state-tables fry
-quotations math.order math.ranges vectors unicode.categories
-regexp2.utils regexp2.transition-tables words sequences.lib sets ;
-IN: regexp2.nfa
-
-SYMBOL: negation-mode
-: negated? ( -- ? ) negation-mode get 0 or odd? ; 
-
-SINGLETON: eps
-
-MIXIN: traversal-flag
-SINGLETON: lookahead-on INSTANCE: lookahead-on traversal-flag
-SINGLETON: lookahead-off INSTANCE: lookahead-off traversal-flag
-SINGLETON: capture-group-on INSTANCE: capture-group-on traversal-flag
-SINGLETON: capture-group-off INSTANCE: capture-group-off traversal-flag
-
-: next-state ( regexp -- state )
-    [ state>> ] [ [ 1+ ] change-state drop ] bi ;
-
-: set-start-state ( regexp -- )
-    dup stack>> [
-        drop
-    ] [
-        [ nfa-table>> ] [ pop first ] bi* >>start-state drop
-    ] if-empty ;
-
-GENERIC: nfa-node ( node -- )
-
-:: add-simple-entry ( obj class -- )
-    [let* | regexp [ current-regexp get ]
-            s0 [ regexp next-state ]
-            s1 [ regexp next-state ]
-            stack [ regexp stack>> ]
-            table [ regexp nfa-table>> ] |
-        negated? [
-            s0 f obj class make-transition table add-transition
-            s0 s1 <default-transition> table add-transition
-        ] [
-            s0 s1 obj class make-transition table add-transition
-        ] if
-        s0 s1 2array stack push
-        t s1 table final-states>> set-at ] ;
-
-: add-traversal-flag ( flag -- )
-    stack peek second
-    current-regexp get nfa-traversal-flags>> push-at ;
-
-:: concatenate-nodes ( -- )
-    [let* | regexp [ current-regexp get ]
-            stack [ regexp stack>> ]
-            table [ regexp nfa-table>> ]
-            s2 [ stack peek first ]
-            s3 [ stack pop second ]
-            s0 [ stack peek first ]
-            s1 [ stack pop second ] |
-        s1 s2 eps <literal-transition> table add-transition
-        s1 table final-states>> delete-at
-        s0 s3 2array stack push ] ;
-
-:: alternate-nodes ( -- )
-    [let* | regexp [ current-regexp get ]
-            stack [ regexp stack>> ]
-            table [ regexp nfa-table>> ]
-            s2 [ stack peek first ]
-            s3 [ stack pop second ]
-            s0 [ stack peek first ]
-            s1 [ stack pop second ]
-            s4 [ regexp next-state ]
-            s5 [ regexp next-state ] |
-        s4 s0 eps <literal-transition> table add-transition
-        s4 s2 eps <literal-transition> table add-transition
-        s1 s5 eps <literal-transition> table add-transition
-        s3 s5 eps <literal-transition> table add-transition
-        s1 table final-states>> delete-at
-        s3 table final-states>> delete-at
-        t s5 table final-states>> set-at
-        s4 s5 2array stack push ] ;
-
-M: kleene-star nfa-node ( node -- )
-    term>> nfa-node
-    [let* | regexp [ current-regexp get ]
-            stack [ regexp stack>> ]
-            s0 [ stack peek first ]
-            s1 [ stack pop second ]
-            s2 [ regexp next-state ]
-            s3 [ regexp next-state ]
-            table [ regexp nfa-table>> ] |
-        s1 table final-states>> delete-at
-        t s3 table final-states>> set-at
-        s1 s0 eps <literal-transition> table add-transition
-        s2 s0 eps <literal-transition> table add-transition
-        s2 s3 eps <literal-transition> table add-transition
-        s1 s3 eps <literal-transition> table add-transition
-        s2 s3 2array stack push ] ;
-
-M: concatenation nfa-node ( node -- )
-    seq>>
-    [ [ nfa-node ] each ]
-    [ length 1- [ concatenate-nodes ] times ] bi ;
-
-M: alternation nfa-node ( node -- )
-    seq>>
-    [ [ nfa-node ] each ]
-    [ length 1- [ alternate-nodes ] times ] bi ;
-
-M: constant nfa-node ( node -- )
-    char>> literal-transition add-simple-entry ;
-
-M: epsilon nfa-node ( node -- )
-    drop eps literal-transition add-simple-entry ;
-
-M: word nfa-node ( node -- )
-    class-transition add-simple-entry ;
-
-M: character-class-range nfa-node ( node -- )
-    class-transition add-simple-entry ;
-
-M: capture-group nfa-node ( node -- )
-    term>> nfa-node ;
-
-M: negation nfa-node ( node -- )
-    negation-mode inc
-    term>> nfa-node 
-    negation-mode dec ;
-
-M: lookahead nfa-node ( node -- )
-    eps literal-transition add-simple-entry
-    lookahead-on add-traversal-flag
-    term>> nfa-node
-    eps literal-transition add-simple-entry
-    lookahead-off add-traversal-flag
-    2 [ concatenate-nodes ] times ;
-
-: construct-nfa ( regexp -- )
-    [
-        reset-regexp
-        negation-mode off
-        [ current-regexp set ]
-        [ parse-tree>> nfa-node ]
-        [ set-start-state ] tri
-    ] with-scope ;
diff --git a/unfinished/regexp2/parser/parser-tests.factor b/unfinished/regexp2/parser/parser-tests.factor
deleted file mode 100644 (file)
index 6911e8e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-USING: kernel tools.test regexp2.backend regexp2 ;
-IN: regexp2.parser
-
-: test-regexp ( string -- )
-    default-regexp parse-regexp ;
-
-: test-regexp2 ( string -- regexp )
-    default-regexp dup parse-regexp ;
-
-[ "(" ] [ unmatched-parentheses? ] must-fail-with
-
-[ ] [ "a|b" test-regexp ] unit-test
-[ ] [ "a.b" test-regexp ] unit-test
-[ ] [ "a|b|c" test-regexp ] unit-test
-[ ] [ "abc|b" test-regexp ] unit-test
-[ ] [ "a|bcd" test-regexp ] unit-test
-[ ] [ "a|(b)" test-regexp ] unit-test
-[ ] [ "(a)|b" test-regexp ] unit-test
-[ ] [ "(a|b)" test-regexp ] unit-test
-[ ] [ "((a)|(b))" test-regexp ] unit-test
-
-[ ] [ "(?:a)" test-regexp ] unit-test
-[ ] [ "(?i:a)" test-regexp ] unit-test
-[ ] [ "(?-i:a)" test-regexp ] unit-test
-[ "(?z:a)" test-regexp ] [ bad-option? ] must-fail-with
-[ "(?-z:a)" test-regexp ] [ bad-option? ] must-fail-with
-
-[ ] [ "(?=a)" test-regexp ] unit-test
-
-[ ] [ "[abc]" test-regexp ] unit-test
-[ ] [ "[a-c]" test-regexp ] unit-test
-[ ] [ "[^a-c]" test-regexp ] unit-test
-[ "[^]" test-regexp ] must-fail
-
-[ ] [ "|b" test-regexp ] unit-test
-[ ] [ "b|" test-regexp ] unit-test
-[ ] [ "||" test-regexp ] unit-test
diff --git a/unfinished/regexp2/parser/parser.factor b/unfinished/regexp2/parser/parser.factor
deleted file mode 100644 (file)
index fb1bd08..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs combinators io io.streams.string
-kernel math math.parser multi-methods namespaces qualified sets
-quotations sequences sequences.lib splitting symbols vectors
-dlists math.order combinators.lib unicode.categories strings
-sequences.lib regexp2.backend regexp2.utils unicode.case ;
-IN: regexp2.parser
-
-FROM: math.ranges => [a,b] ;
-
-MIXIN: node
-TUPLE: concatenation seq ; INSTANCE: concatenation node
-TUPLE: alternation seq ; INSTANCE: alternation node
-TUPLE: kleene-star term ; INSTANCE: kleene-star node
-
-! !!!!!!!!
-TUPLE: possessive-question term ; INSTANCE: possessive-question node
-TUPLE: possessive-kleene-star term ; INSTANCE: possessive-kleene-star node
-
-! !!!!!!!!
-TUPLE: reluctant-question term ; INSTANCE: reluctant-question node
-TUPLE: reluctant-kleene-star term ; INSTANCE: reluctant-kleene-star node
-
-TUPLE: negation term ; INSTANCE: negation node
-TUPLE: constant char ; INSTANCE: constant node
-TUPLE: range from to ; INSTANCE: range node
-TUPLE: lookahead term ; INSTANCE: lookahead node
-TUPLE: lookbehind term ; INSTANCE: lookbehind node
-TUPLE: capture-group term ; INSTANCE: capture-group node
-TUPLE: non-capture-group term ; INSTANCE: non-capture-group node
-TUPLE: independent-group term ; INSTANCE: independent-group node ! atomic group
-TUPLE: character-class-range from to ; INSTANCE: character-class-range node
-SINGLETON: epsilon INSTANCE: epsilon node
-SINGLETON: any-char INSTANCE: any-char node
-SINGLETON: front-anchor INSTANCE: front-anchor node
-SINGLETON: back-anchor INSTANCE: back-anchor node
-
-TUPLE: option-on option ; INSTANCE: option-on node
-TUPLE: option-off option ; INSTANCE: option-off node
-SINGLETONS: unix-lines dotall multiline comments case-insensitive unicode-case reversed-regexp ;
-
-SINGLETONS: letter-class LETTER-class Letter-class digit-class
-alpha-class non-newline-blank-class
-ascii-class punctuation-class java-printable-class blank-class
-control-character-class hex-digit-class java-blank-class c-identifier-class
-unmatchable-class ;
-
-SINGLETONS: beginning-of-group end-of-group
-beginning-of-character-class end-of-character-class
-left-parenthesis pipe caret dash ;
-
-: get-option ( option -- ? ) current-regexp get options>> at ;
-: get-unix-lines ( -- ? ) unix-lines get-option ;
-: get-dotall ( -- ? ) dotall get-option ;
-: get-multiline ( -- ? ) multiline get-option ;
-: get-comments ( -- ? ) comments get-option ;
-: get-case-insensitive ( -- ? ) case-insensitive get-option ;
-: get-unicode-case ( -- ? ) unicode-case get-option ;
-: get-reversed-regexp ( -- ? ) reversed-regexp get-option ;
-
-: <possessive-kleene-star> ( obj -- kleene ) possessive-kleene-star boa ;
-: <reluctant-kleene-star> ( obj -- kleene ) reluctant-kleene-star boa ;
-: <possessive-question> ( obj -- kleene ) possessive-question boa ;
-: <reluctant-question> ( obj -- kleene ) reluctant-question boa ;
-
-: <negation> ( obj -- negation ) negation boa ;
-: <concatenation> ( seq -- concatenation )
-    >vector get-reversed-regexp [ reverse ] when
-    [ epsilon ] [ concatenation boa ] if-empty ;
-: <alternation> ( seq -- alternation ) >vector alternation boa ;
-: <capture-group> ( obj -- capture-group ) capture-group boa ;
-: <kleene-star> ( obj -- kleene-star ) kleene-star boa ;
-: <constant> ( obj -- constant )
-    dup Letter? get-case-insensitive and [
-        [ ch>lower constant boa ]
-        [ ch>upper constant boa ] bi 2array <alternation>
-    ] [
-        constant boa
-    ] if ;
-
-: first|concatenation ( seq -- first/concatenation )
-    dup length 1 = [ first ] [ <concatenation> ] if ;
-
-: first|alternation ( seq -- first/alternation )
-    dup length 1 = [ first ] [ <alternation> ] if ;
-
-: <character-class-range> ( from to -- obj )
-    2dup [ Letter? ] bi@ or get-case-insensitive and [
-        [ [ ch>lower ] bi@ character-class-range boa ]
-        [ [ ch>upper ] bi@ character-class-range boa ] 2bi
-        2array [ [ from>> ] [ to>> ] bi < ] filter
-        [ unmatchable-class ] [ first|alternation ] if-empty
-    ] [
-        2dup <
-        [ character-class-range boa ] [ 2drop unmatchable-class ] if
-    ] if ;
-
-ERROR: unmatched-parentheses ;
-
-: make-positive-lookahead ( string -- )
-    lookahead boa push-stack ;
-
-: make-negative-lookahead ( string -- )
-    <negation> lookahead boa push-stack ;
-
-: make-independent-group ( string -- )
-    #! no backtracking
-    independent-group boa push-stack ;
-
-: make-positive-lookbehind ( string -- )
-    lookbehind boa push-stack ;
-
-: make-negative-lookbehind ( string -- )
-    <negation> lookbehind boa push-stack ;
-
-: make-non-capturing-group ( string -- )
-    non-capture-group boa push-stack ;
-
-ERROR: bad-option ch ;
-
-: option ( ch -- singleton )
-    {
-        { CHAR: i [ case-insensitive ] }
-        { CHAR: d [ unix-lines ] }
-        { CHAR: m [ multiline ] }
-        { CHAR: n [ multiline ] }
-        { CHAR: r [ reversed-regexp ] }
-        { CHAR: s [ dotall ] }
-        { CHAR: u [ unicode-case ] }
-        { CHAR: x [ comments ] }
-        [ bad-option ]
-    } case ;
-
-: option-on ( option -- ) current-regexp get options>> conjoin ;
-: option-off ( option -- ) current-regexp get options>> delete-at ;
-
-: toggle-option ( ch ? -- ) [ option ] dip [ option-on ] [ option-off ] if ;
-: (parse-options) ( string ? -- ) [ toggle-option ] curry each ;
-
-: parse-options ( string -- )
-    "-" split1 [ t (parse-options) ] [ f (parse-options) ] bi* ;
-
-DEFER: (parse-regexp)
-: parse-special-group ( -- )
-    beginning-of-group push-stack
-    (parse-regexp) pop-stack make-non-capturing-group ;
-
-ERROR: bad-special-group string ;
-
-DEFER: nested-parse-regexp
-: (parse-special-group) ( -- )
-    read1 {
-        { [ dup CHAR: # = ]
-            [ drop nested-parse-regexp pop-stack drop ] }
-        { [ dup CHAR: : = ]
-            [ drop nested-parse-regexp pop-stack make-non-capturing-group ] }
-        { [ dup CHAR: = = ]
-            [ drop nested-parse-regexp pop-stack make-positive-lookahead ] }
-        { [ dup CHAR: ! = ]
-            [ drop nested-parse-regexp pop-stack make-negative-lookahead ] }
-        { [ dup CHAR: > = ]
-            [ drop nested-parse-regexp pop-stack make-independent-group ] }
-        { [ dup CHAR: < = peek1 CHAR: = = and ]
-            [ drop drop1 nested-parse-regexp pop-stack make-positive-lookbehind ] }
-        { [ dup CHAR: < = peek1 CHAR: ! = and ]
-            [ drop drop1 nested-parse-regexp pop-stack make-negative-lookbehind ] }
-        [
-            ":)" read-until
-            [ swap prefix ] dip
-            {
-                { CHAR: : [ parse-options parse-special-group ] }
-                { CHAR: ) [ parse-options ] }
-                [ drop bad-special-group ]
-            } case
-        ]
-    } cond ;
-
-: handle-left-parenthesis ( -- )
-    peek1 CHAR: ? =
-    [ drop1 (parse-special-group) ]
-    [ nested-parse-regexp ] if ;
-
-: handle-dot ( -- ) any-char push-stack ;
-: handle-pipe ( -- ) pipe push-stack ;
-: (handle-star) ( obj -- kleene-star )
-    peek1 {
-        { CHAR: + [ drop1 <possessive-kleene-star> ] }
-        { CHAR: ? [ drop1 <reluctant-kleene-star> ] }
-        [ drop <kleene-star> ]
-    } case ;
-: handle-star ( -- ) stack pop (handle-star) push-stack ;
-: handle-question ( -- )
-    stack pop peek1 {
-        { CHAR: + [ drop1 <possessive-question> ] }
-        { CHAR: ? [ drop1 <reluctant-question> ] }
-        [ drop epsilon 2array <alternation> ]
-    } case push-stack ;
-: handle-plus ( -- )
-    stack pop dup (handle-star)
-    2array <concatenation> push-stack ;
-
-ERROR: unmatched-brace ;
-: parse-repetition ( -- start finish ? )
-    "}" read-until [ unmatched-brace ] unless
-    [ "," split1 [ string>number ] bi@ ]
-    [ CHAR: , swap index >boolean ] bi ;
-
-: replicate/concatenate ( n obj -- obj' )
-    over zero? [ 2drop epsilon ]
-    [ <repetition> first|concatenation ] if ;
-
-: exactly-n ( n -- )
-    stack pop replicate/concatenate push-stack ;
-
-: at-least-n ( n -- )
-    stack pop
-    [ replicate/concatenate ] keep
-    <kleene-star> 2array <concatenation> push-stack ;
-
-: at-most-n ( n -- )
-    1+
-    stack pop
-    [ replicate/concatenate ] curry map <alternation> push-stack ;
-
-: from-m-to-n ( m n -- )
-    [a,b]
-    stack pop
-    [ replicate/concatenate ] curry map
-    <alternation> push-stack ;
-
-ERROR: invalid-range a b ;
-
-: handle-left-brace ( -- )
-    parse-repetition
-    >r 2dup [ [ 0 < [ invalid-range ] when ] when* ] bi@ r>
-    [
-        2dup and [ from-m-to-n ]
-        [ [ nip at-most-n ] [ at-least-n ] if* ] if
-    ] [ drop 0 max exactly-n ] if ;
-
-: handle-front-anchor ( -- ) front-anchor push-stack ;
-: handle-back-anchor ( -- ) back-anchor push-stack ;
-
-ERROR: bad-character-class obj ;
-ERROR: expected-posix-class ;
-
-: parse-posix-class ( -- obj )
-    read1 CHAR: { = [ expected-posix-class ] unless
-    "}" read-until [ bad-character-class ] unless
-    {
-        { "Lower" [ get-case-insensitive Letter-class letter-class ? ] }
-        { "Upper" [ get-case-insensitive Letter-class LETTER-class ? ] }
-        { "Alpha" [ Letter-class ] }
-        { "ASCII" [ ascii-class ] }
-        { "Digit" [ digit-class ] }
-        { "Alnum" [ alpha-class ] }
-        { "Punct" [ punctuation-class ] }
-        { "Graph" [ java-printable-class ] }
-        { "Print" [ java-printable-class ] }
-        { "Blank" [ non-newline-blank-class ] }
-        { "Cntrl" [ control-character-class ] }
-        { "XDigit" [ hex-digit-class ] }
-        { "Space" [ java-blank-class ] }
-        ! TODO: unicode-character-class, fallthrough in unicode is bad-char-clss
-        [ bad-character-class ]
-    } case ;
-
-: parse-octal ( -- n ) 3 read oct> check-octal ;
-: parse-short-hex ( -- n ) 2 read hex> check-hex ;
-: parse-long-hex ( -- n ) 6 read hex> check-hex ;
-: parse-control-character ( -- n ) read1 ;
-
-ERROR: bad-escaped-literals seq ;
-: parse-escaped-literals ( -- obj )
-    "\\E" read-until [ bad-escaped-literals ] unless
-    drop1
-    [ epsilon ] [
-        [ <constant> ] V{ } map-as
-        first|concatenation
-    ] if-empty ;
-
-: parse-escaped ( -- obj )
-    read1
-    {
-        { CHAR: \ [ CHAR: \ <constant> ] }
-        { CHAR: . [ CHAR: . <constant> ] }
-        { CHAR: t [ CHAR: \t <constant> ] }
-        { CHAR: n [ CHAR: \n <constant> ] }
-        { CHAR: r [ CHAR: \r <constant> ] }
-        { CHAR: f [ HEX: c <constant> ] }
-        { CHAR: a [ HEX: 7 <constant> ] }
-        { CHAR: e [ HEX: 1b <constant> ] }
-        { CHAR: $ [ CHAR: $ <constant> ] }
-        { CHAR: ^ [ CHAR: ^ <constant> ] }
-
-        { CHAR: d [ digit-class ] }
-        { CHAR: D [ digit-class <negation> ] }
-        { CHAR: s [ java-blank-class ] }
-        { CHAR: S [ java-blank-class <negation> ] }
-        { CHAR: w [ c-identifier-class ] }
-        { CHAR: W [ c-identifier-class <negation> ] }
-
-        { CHAR: p [ parse-posix-class ] }
-        { CHAR: P [ parse-posix-class <negation> ] }
-        { CHAR: x [ parse-short-hex <constant> ] }
-        { CHAR: u [ parse-long-hex <constant> ] }
-        { CHAR: 0 [ parse-octal <constant> ] }
-        { CHAR: c [ parse-control-character ] }
-
-        ! { CHAR: b [ handle-word-boundary ] }
-        ! { CHAR: B [ handle-word-boundary <negation> ] }
-        ! { CHAR: A [ handle-beginning-of-input ] }
-        ! { CHAR: G [ end of previous match ] }
-        ! { CHAR: Z [ handle-end-of-input ] }
-        ! { CHAR: z [ handle-end-of-input ] } ! except for terminator
-
-        { CHAR: Q [ parse-escaped-literals ] }
-    } case ;
-
-: handle-escape ( -- ) parse-escaped push-stack ;
-
-: handle-dash ( vector -- vector' )
-    H{ { dash CHAR: - } } substitute ;
-
-: character-class>alternation ( seq -- alternation )
-    [ dup number? [ <constant> ] when ] map first|alternation ;
-
-: handle-caret ( vector -- vector' )
-    dup [ length 2 >= ] [ first caret eq? ] bi and [
-        rest-slice character-class>alternation <negation>
-    ] [
-        character-class>alternation
-    ] if ;
-
-: make-character-class ( -- character-class )
-    [ beginning-of-character-class swap cut-stack ] change-whole-stack
-    handle-dash handle-caret ;
-
-: apply-dash ( -- )
-    stack [ pop3 nip <character-class-range> ] keep push ;
-
-: apply-dash? ( -- ? )
-    stack dup length 3 >=
-    [ [ length 2 - ] keep nth dash eq? ] [ drop f ] if ;
-
-ERROR: empty-negated-character-class ;
-DEFER: handle-left-bracket
-: (parse-character-class) ( -- )
-    read1 [ empty-negated-character-class ] unless* {
-        { CHAR: [ [ handle-left-bracket t ] }
-        { CHAR: ] [ make-character-class push-stack f ] }
-        { CHAR: - [ dash push-stack t ] }
-        { CHAR: \ [ parse-escaped push-stack t ] }
-        [ push-stack apply-dash? [ apply-dash ] when t ]
-    } case
-    [ (parse-character-class) ] when ;
-
-: parse-character-class-second ( -- )
-    read1 {
-        { CHAR: [ [ CHAR: [ <constant> push-stack ] }
-        { CHAR: ] [ CHAR: ] <constant> push-stack ] }
-        { CHAR: - [ CHAR: - <constant> push-stack ] }
-        [ push1 ]
-    } case ;
-
-: parse-character-class-first ( -- )
-    read1 {
-        { CHAR: ^ [ caret push-stack parse-character-class-second ] }
-        { CHAR: [ [ CHAR: [ <constant> push-stack ] }
-        { CHAR: ] [ CHAR: ] <constant> push-stack ] }
-        { CHAR: - [ CHAR: - <constant> push-stack ] }
-        [ push1 ]
-    } case ;
-
-: handle-left-bracket ( -- )
-    beginning-of-character-class push-stack
-    parse-character-class-first (parse-character-class) ;
-
-: finish-regexp-parse ( stack -- obj )
-    { pipe } split
-    [ first|concatenation ] map first|alternation ;
-
-: handle-right-parenthesis ( -- )
-    stack beginning-of-group over last-index cut rest
-    [ current-regexp get swap >>stack drop ]
-    [ finish-regexp-parse <capture-group> push-stack ] bi* ;
-
-: nested-parse-regexp ( -- )
-    beginning-of-group push-stack (parse-regexp) ;
-
-: ((parse-regexp)) ( token -- ? )
-    {
-        { CHAR: . [ handle-dot t ] }
-        { CHAR: ( [ handle-left-parenthesis t ] }
-        { CHAR: ) [ handle-right-parenthesis f ] }
-        { CHAR: | [ handle-pipe t ] }
-        { CHAR: ? [ handle-question t ] }
-        { CHAR: * [ handle-star t ] }
-        { CHAR: + [ handle-plus t ] }
-        { CHAR: { [ handle-left-brace t ] }
-        { CHAR: [ [ handle-left-bracket t ] }
-        { CHAR: ^ [ handle-front-anchor t ] }
-        { CHAR: $ [ handle-back-anchor t ] }
-        { CHAR: \ [ handle-escape t ] }
-        [ <constant> push-stack t ]
-    } case ;
-
-: (parse-regexp) ( -- )
-    read1 [ ((parse-regexp)) [ (parse-regexp) ] when ] when* ;
-
-: parse-regexp ( regexp -- )
-    dup current-regexp [
-        raw>> [
-            <string-reader> [ (parse-regexp) ] with-input-stream
-        ] unless-empty
-        current-regexp get
-        stack finish-regexp-parse
-            >>parse-tree drop
-    ] with-variable ;
diff --git a/unfinished/regexp2/regexp2-docs.factor b/unfinished/regexp2/regexp2-docs.factor
deleted file mode 100644 (file)
index f903c14..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel strings help.markup help.syntax regexp2.backend ;
-IN: regexp2
-
-HELP: <regexp>
-{ $values { "string" string } { "regexp" regexp } }
-{ $description "Compiles a regular expression into a DFA and returns this object.  Regular expressions only have to be compiled once and can then be used multiple times to match input strings." } ;
-
-HELP: <iregexp>
-{ $values { "string" string } { "regexp" regexp } }
-{ $description "Compiles a case-insensitive regular expression into a DFA and returns this object.  Otherwise, exactly the same as " { $link <regexp> } } ;
-
-{ <regexp> <iregexp> } related-words
diff --git a/unfinished/regexp2/regexp2-tests.factor b/unfinished/regexp2/regexp2-tests.factor
deleted file mode 100644 (file)
index e77a7a4..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-USING: regexp2 tools.test kernel sequences regexp2.parser
-regexp2.traversal ;
-IN: regexp2-tests
-
-[ f ] [ "b" "a*" <regexp> matches? ] unit-test
-[ t ] [ "" "a*" <regexp> matches? ] unit-test
-[ t ] [ "a" "a*" <regexp> matches? ] unit-test
-[ t ] [ "aaaaaaa" "a*"  <regexp> matches? ] unit-test
-[ f ] [ "ab" "a*" <regexp> matches? ] unit-test
-
-[ t ] [ "abc" "abc" <regexp> matches? ] unit-test
-[ t ] [ "a" "a|b|c" <regexp> matches? ] unit-test
-[ t ] [ "b" "a|b|c" <regexp> matches? ] unit-test
-[ t ] [ "c" "a|b|c" <regexp> matches? ] unit-test
-[ f ] [ "c" "d|e|f" <regexp> matches? ] unit-test
-
-[ t ] [ "b" "|b" <regexp> matches? ] unit-test
-[ t ] [ "b" "b|" <regexp> matches? ] unit-test
-[ t ] [ "" "b|" <regexp> matches? ] unit-test
-[ t ] [ "" "b|" <regexp> matches? ] unit-test
-[ f ] [ "" "|" <regexp> matches? ] unit-test
-[ f ] [ "" "|||||||" <regexp> matches? ] unit-test
-
-[ f ] [ "aa" "a|b|c" <regexp> matches? ] unit-test
-[ f ] [ "bb" "a|b|c" <regexp> matches? ] unit-test
-[ f ] [ "cc" "a|b|c" <regexp> matches? ] unit-test
-[ f ] [ "cc" "d|e|f" <regexp> matches? ] unit-test
-
-[ f ] [ "" "a+" <regexp> matches? ] unit-test
-[ t ] [ "a" "a+" <regexp> matches? ] unit-test
-[ t ] [ "aa" "a+" <regexp> matches? ] unit-test
-
-[ t ] [ "" "a?" <regexp> matches? ] unit-test
-[ t ] [ "a" "a?" <regexp> matches? ] unit-test
-[ f ] [ "aa" "a?" <regexp> matches? ] unit-test
-
-[ f ] [ "" "." <regexp> matches? ] unit-test
-[ t ] [ "a" "." <regexp> matches? ] unit-test
-[ t ] [ "." "." <regexp> matches? ] unit-test
-! [ f ] [ "\n" "." <regexp> matches? ] unit-test
-
-[ f ] [ "" ".+" <regexp> matches? ] unit-test
-[ t ] [ "a" ".+" <regexp> matches? ] unit-test
-[ t ] [ "ab" ".+" <regexp> matches? ] unit-test
-
-
-[ t ] [ "" "a|b*|c+|d?" <regexp> matches? ] unit-test
-[ t ] [ "a" "a|b*|c+|d?" <regexp> matches? ] unit-test
-[ t ] [ "c" "a|b*|c+|d?" <regexp> matches? ] unit-test
-[ t ] [ "cc" "a|b*|c+|d?" <regexp> matches? ] unit-test
-[ f ] [ "ccd" "a|b*|c+|d?" <regexp> matches? ] unit-test
-[ t ] [ "d" "a|b*|c+|d?" <regexp> matches? ] unit-test
-
-[ t ] [ "foo" "foo|bar" <regexp> matches? ] unit-test
-[ t ] [ "bar" "foo|bar" <regexp> matches? ] unit-test
-[ f ] [ "foobar" "foo|bar" <regexp> matches? ] unit-test
-
-[ f ] [ "" "(a)" <regexp> matches? ] unit-test
-[ t ] [ "a" "(a)" <regexp> matches? ] unit-test
-[ f ] [ "aa" "(a)" <regexp> matches? ] unit-test
-[ t ] [ "aa" "(a*)" <regexp> matches? ] unit-test
-
-[ f ] [ "aababaaabbac" "(a|b)+" <regexp> matches? ] unit-test
-[ t ] [ "ababaaabba" "(a|b)+" <regexp> matches? ] unit-test
-
-[ f ] [ "" "a{1}" <regexp> matches? ] unit-test
-[ t ] [ "a" "a{1}" <regexp> matches? ] unit-test
-[ f ] [ "aa" "a{1}" <regexp> matches? ] unit-test
-
-[ f ] [ "a" "a{2,}" <regexp> matches? ] unit-test
-[ t ] [ "aaa" "a{2,}" <regexp> matches? ] unit-test
-[ t ] [ "aaaa" "a{2,}" <regexp> matches? ] unit-test
-[ t ] [ "aaaaa" "a{2,}" <regexp> matches? ] unit-test
-
-[ t ] [ "" "a{,2}" <regexp> matches? ] unit-test
-[ t ] [ "a" "a{,2}" <regexp> matches? ] unit-test
-[ t ] [ "aa" "a{,2}" <regexp> matches? ] unit-test
-[ f ] [ "aaa" "a{,2}" <regexp> matches? ] unit-test
-[ f ] [ "aaaa" "a{,2}" <regexp> matches? ] unit-test
-[ f ] [ "aaaaa" "a{,2}" <regexp> matches? ] unit-test
-
-[ f ] [ "" "a{1,3}" <regexp> matches? ] unit-test
-[ t ] [ "a" "a{1,3}" <regexp> matches? ] unit-test
-[ t ] [ "aa" "a{1,3}" <regexp> matches? ] unit-test
-[ t ] [ "aaa" "a{1,3}" <regexp> matches? ] unit-test
-[ f ] [ "aaaa" "a{1,3}" <regexp> matches? ] unit-test
-
-[ f ] [ "" "[a]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[a]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[abc]" <regexp> matches? ] unit-test
-[ f ] [ "b" "[a]" <regexp> matches? ] unit-test
-[ f ] [ "d" "[abc]" <regexp> matches? ] unit-test
-[ t ] [ "ab" "[abc]{1,2}" <regexp> matches? ] unit-test
-[ f ] [ "abc" "[abc]{1,2}" <regexp> matches? ] unit-test
-
-[ f ] [ "" "[^a]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[^a]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[^abc]" <regexp> matches? ] unit-test
-[ t ] [ "b" "[^a]" <regexp> matches? ] unit-test
-[ t ] [ "d" "[^abc]" <regexp> matches? ] unit-test
-[ f ] [ "ab" "[^abc]{1,2}" <regexp> matches? ] unit-test
-[ f ] [ "abc" "[^abc]{1,2}" <regexp> matches? ] unit-test
-
-[ t ] [ "]" "[]]" <regexp> matches? ] unit-test
-[ f ] [ "]" "[^]]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^]]" <regexp> matches? ] unit-test
-
-[ "^" "[^]" <regexp> matches? ] must-fail
-[ t ] [ "^" "[]^]" <regexp> matches? ] unit-test
-[ t ] [ "]" "[]^]" <regexp> matches? ] unit-test
-
-[ t ] [ "[" "[[]" <regexp> matches? ] unit-test
-[ f ] [ "^" "[^^]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^^]" <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[-]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[-]" <regexp> matches? ] unit-test
-[ f ] [ "-" "[^-]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^-]" <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[-a]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[-a]" <regexp> matches? ] unit-test
-[ t ] [ "-" "[a-]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-]" <regexp> matches? ] unit-test
-[ f ] [ "b" "[a-]" <regexp> matches? ] unit-test
-[ f ] [ "-" "[^-]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^-]" <regexp> matches? ] unit-test
-
-[ f ] [ "-" "[a-c]" <regexp> matches? ] unit-test
-[ t ] [ "-" "[^a-c]" <regexp> matches? ] unit-test
-[ t ] [ "b" "[a-c]" <regexp> matches? ] unit-test
-[ f ] [ "b" "[^a-c]" <regexp> matches? ] unit-test
-
-[ t ] [ "-" "[a-c-]" <regexp> matches? ] unit-test
-[ f ] [ "-" "[^a-c-]" <regexp> matches? ] unit-test
-
-[ t ] [ "\\" "[\\\\]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[\\\\]" <regexp> matches? ] unit-test
-[ f ] [ "\\" "[^\\\\]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^\\\\]" <regexp> matches? ] unit-test
-
-[ t ] [ "0" "[\\d]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[\\d]" <regexp> matches? ] unit-test
-[ f ] [ "0" "[^\\d]" <regexp> matches? ] unit-test
-[ t ] [ "a" "[^\\d]" <regexp> matches? ] unit-test
-
-[ t ] [ "a" "[a-z]{1,}|[A-Z]{2,4}|b*|c|(f|g)*" <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}|b*|c|(f|g)*" <regexp> matches? ] unit-test
-[ t ] [ "a" "[a-z]{1,2}|[A-Z]{3,3}" <regexp> matches? ] unit-test
-
-[ t ] [ "1000" "\\d{4,6}" <regexp> matches? ] unit-test
-[ t ] [ "1000" "[0-9]{4,6}" <regexp> matches? ] unit-test
-
-[ t ] [ "abc" "\\p{Lower}{3}" <regexp> matches? ] unit-test
-[ f ] [ "ABC" "\\p{Lower}{3}" <regexp> matches? ] unit-test
-[ t ] [ "ABC" "\\p{Upper}{3}" <regexp> matches? ] unit-test
-[ f ] [ "abc" "\\p{Upper}{3}" <regexp> matches? ] unit-test
-! 
-[ f ] [ "abc" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
-[ t ] [ "ABC" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
-
-[ f ] [ "" "\\Q\\E" <regexp> matches? ] unit-test
-[ f ] [ "a" "\\Q\\E" <regexp> matches? ] unit-test
-[ t ] [ "|*+" "\\Q|*+\\E" <regexp> matches? ] unit-test
-[ f ] [ "abc" "\\Q|*+\\E" <regexp> matches? ] unit-test
-[ t ] [ "s" "\\Qs\\E" <regexp> matches? ] unit-test
-
-[ t ] [ "S" "\\0123" <regexp> matches? ] unit-test
-[ t ] [ "SXY" "\\0123XY" <regexp> matches? ] unit-test
-[ t ] [ "x" "\\x78" <regexp> matches? ] unit-test
-[ f ] [ "y" "\\x78" <regexp> matches? ] unit-test
-[ t ] [ "x" "\\u000078" <regexp> matches? ] unit-test
-[ f ] [ "y" "\\u000078" <regexp> matches? ] unit-test
-
-[ t ] [ "ab" "a+b" <regexp> matches? ] unit-test
-[ f ] [ "b" "a+b" <regexp> matches? ] unit-test
-[ t ] [ "aab" "a+b" <regexp> matches? ] unit-test
-[ f ] [ "abb" "a+b" <regexp> matches? ] unit-test
-
-[ t ] [ "abbbb" "ab*" <regexp> matches? ] unit-test
-[ t ] [ "a" "ab*" <regexp> matches? ] unit-test
-[ f ] [ "abab" "ab*" <regexp> matches? ] unit-test
-
-[ f ] [ "x" "\\." <regexp> matches? ] unit-test
-[ t ] [ "." "\\." <regexp> matches? ] unit-test
-
-[ t ] [ "aaaab" "a+ab" <regexp> matches? ] unit-test
-[ f ] [ "aaaxb" "a+ab" <regexp> matches? ] unit-test
-[ t ] [ "aaacb" "a+cb" <regexp> matches? ] unit-test
-
-[ 3 ] [ "aaacb" "a*" <regexp> match-head ] unit-test
-[ 2 ] [ "aaacb" "aa?" <regexp> match-head ] unit-test
-
-[ t ] [ "aaa" "AAA" <iregexp> matches? ] unit-test
-[ f ] [ "aax" "AAA" <iregexp> matches? ] unit-test
-[ t ] [ "aaa" "A*" <iregexp> matches? ] unit-test
-[ f ] [ "aaba" "A*" <iregexp> matches? ] unit-test
-[ t ] [ "b" "[AB]" <iregexp> matches? ] unit-test
-[ f ] [ "c" "[AB]" <iregexp> matches? ] unit-test
-[ t ] [ "c" "[A-Z]" <iregexp> matches? ] unit-test
-[ f ] [ "3" "[A-Z]" <iregexp> matches? ] unit-test
-
-[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
-[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
-[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
-[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
-
-[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
-[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
-[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
-[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
-
-[ f ] [ "A" "[a-z]" <regexp> matches? ] unit-test
-[ t ] [ "A" "[a-z]" <iregexp> matches? ] unit-test
-
-[ f ] [ "A" "\\p{Lower}" <regexp> matches? ] unit-test
-[ t ] [ "A" "\\p{Lower}" <iregexp> matches? ] unit-test
-
-[ t ] [ "abc" <reversed> "abc" <rregexp> matches? ] unit-test
-[ t ] [ "abc" <reversed> "a[bB][cC]" <rregexp> matches? ] unit-test
-[ t ] [ "adcbe" "a(?r)(bcd)(?-r)e" <rregexp> matches? ] unit-test
-
-[ t ] [ "s@f" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
-[ f ] [ "a" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
-[ t ] [ ".o" "\\.[a-z]" <regexp> matches? ] unit-test
-
-[ ] [
-    "(0[lL]?|[1-9]\\d{0,9}(\\d{0,9}[lL])?|0[xX]\\p{XDigit}{1,8}(\\p{XDigit}{0,8}[lL])?|0[0-7]{1,11}([0-7]{0,11}[lL])?|([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][+-]?[0-9]+)?[fFdD]?|[0-9]+([eE][+-]?[0-9]+[fFdD]?|([eE][+-]?[0-9]+)?[fFdD]))"
-    <regexp> drop
-] unit-test
-
-[ ] [ "(\\$[\\p{XDigit}]|[\\p{Digit}])" <regexp> drop ] unit-test
-
-! Comment
-[ t ] [ "ac" "a(?#boo)c" <regexp> matches? ] unit-test
-
-
-
-[ "{Lower}" <regexp> ] [ invalid-range? ] must-fail-with
-
-[ 1 ] [ "aaacb" "a+?" <regexp> match-head ] unit-test
-[ 1 ] [ "aaacb" "aa??" <regexp> match-head ] unit-test
-[ f ] [ "aaaab" "a++ab" <regexp> matches? ] unit-test
-[ t ] [ "aaacb" "a++cb" <regexp> matches? ] unit-test
-[ 3 ] [ "aacb" "aa?c" <regexp> match-head ] unit-test
-[ 3 ] [ "aacb" "aa??c" <regexp> match-head ] unit-test
-
-[ t ] [ "fxxbar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
-[ f ] [ "foobar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
-
-[ 3 ] [ "foobar" "foo(?=bar)" <regexp> match-head ] unit-test
-[ f ] [ "foobxr" "foo(?=bar)" <regexp> match-head ] unit-test
-
-! [ f ] [ "foobxr" "foo\\z" <regexp> match-head ] unit-test
-! [ 3 ] [ "foo" "foo\\z" <regexp> match-head ] unit-test
-
-! [ 3 ] [ "foo bar" "foo\\b" <regexp> match-head ] unit-test
-! [ f ] [ "fooxbar" "foo\\b" <regexp> matches? ] unit-test
-! [ t ] [ "foo" "foo\\b" <regexp> matches? ] unit-test
-! [ t ] [ "foo bar" "foo\\b bar" <regexp> matches? ] unit-test
-! [ f ] [ "fooxbar" "foo\\bxbar" <regexp> matches? ] unit-test
-! [ f ] [ "foo" "foo\\bbar" <regexp> matches? ] unit-test
-
-! [ f ] [ "foo bar" "foo\\B" <regexp> matches? ] unit-test
-! [ 3 ] [ "fooxbar" "foo\\B" <regexp> match-head ] unit-test
-! [ t ] [ "foo" "foo\\B" <regexp> matches? ] unit-test
-! [ f ] [ "foo bar" "foo\\B bar" <regexp> matches? ] unit-test
-! [ t ] [ "fooxbar" "foo\\Bxbar" <regexp> matches? ] unit-test
-! [ f ] [ "foo" "foo\\Bbar" <regexp> matches? ] unit-test
-
-! Bug in parsing word
-! [ t ] [ "a" R' a' matches?  ] unit-test
-
-! ((A)(B(C)))
-! 1.  ((A)(B(C)))
-! 2. (A)
-! 3. (B(C))
-! 4. (C) 
diff --git a/unfinished/regexp2/regexp2.factor b/unfinished/regexp2/regexp2.factor
deleted file mode 100644 (file)
index feec8ea..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators kernel math math.ranges
-sequences regexp2.backend regexp2.utils memoize sets
-regexp2.parser regexp2.nfa regexp2.dfa regexp2.traversal
-regexp2.transition-tables assocs prettyprint.backend
-make ;
-IN: regexp2
-
-: default-regexp ( string -- regexp )
-    regexp new
-        swap >>raw
-        <transition-table> >>nfa-table
-        <transition-table> >>dfa-table
-        <transition-table> >>minimized-table
-        H{ } clone >>nfa-traversal-flags
-        H{ } clone >>dfa-traversal-flags
-        H{ } clone >>options
-        reset-regexp ;
-
-: construct-regexp ( regexp -- regexp' )
-    {
-        [ parse-regexp ]
-        [ construct-nfa ]
-        [ construct-dfa ]
-        [ ]
-    } cleave ;
-
-: match ( string regexp -- pair )
-    <dfa-traverser> do-match return-match ;
-
-: matches? ( string regexp -- ? )
-    dupd match
-    [ [ length ] [ length>> 1- ] bi* = ] [ drop f ] if* ;
-
-: match-head ( string regexp -- end ) match length>> 1- ;
-
-: initial-option ( regexp option -- regexp' )
-    over options>> conjoin ;
-
-: <regexp> ( string -- regexp )
-    default-regexp construct-regexp ;
-
-: <iregexp> ( string -- regexp )
-    default-regexp
-    case-insensitive initial-option
-    construct-regexp ;
-
-: <rregexp> ( string -- regexp )
-    default-regexp
-    reversed-regexp initial-option
-    construct-regexp ;
-
-: R! CHAR: ! <regexp> ; parsing
-: R" CHAR: " <regexp> ; parsing
-: R# CHAR: # <regexp> ; parsing
-: R' CHAR: ' <regexp> ; parsing
-: R( CHAR: ) <regexp> ; parsing
-: R/ CHAR: / <regexp> ; parsing
-: R@ CHAR: @ <regexp> ; parsing
-: R[ CHAR: ] <regexp> ; parsing
-: R` CHAR: ` <regexp> ; parsing
-: R{ CHAR: } <regexp> ; parsing
-: R| CHAR: | <regexp> ; parsing
-
-: find-regexp-syntax ( string -- prefix suffix )
-    {
-        { "R/ "  "/"  }
-        { "R! "  "!"  }
-        { "R\" " "\"" }
-        { "R# "  "#"  }
-        { "R' "  "'"  }
-        { "R( "  ")"  }
-        { "R@ "  "@"  }
-        { "R[ "  "]"  }
-        { "R` "  "`"  }
-        { "R{ "  "}"  }
-        { "R| "  "|"  }
-    } swap [ subseq? not nip ] curry assoc-find drop ;
-
-: option? ( option regexp -- ? )
-    options>> key? ;
-
-M: regexp pprint*
-    [
-        [
-            dup raw>>
-            dup find-regexp-syntax swap % swap % %
-            case-insensitive swap option? [ "i" % ] when
-        ] "" make
-    ] keep present-text ;
diff --git a/unfinished/regexp2/summary.txt b/unfinished/regexp2/summary.txt
deleted file mode 100644 (file)
index aa1e1c2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Regular expressions
diff --git a/unfinished/regexp2/tags.txt b/unfinished/regexp2/tags.txt
deleted file mode 100644 (file)
index 65bc471..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-parsing
-text
diff --git a/unfinished/regexp2/transition-tables/transition-tables.factor b/unfinished/regexp2/transition-tables/transition-tables.factor
deleted file mode 100644 (file)
index c67985a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs fry hashtables kernel sequences
-vectors regexp2.utils ;
-IN: regexp2.transition-tables
-
-TUPLE: transition from to obj ;
-TUPLE: literal-transition < transition ;
-TUPLE: class-transition < transition ;
-TUPLE: default-transition < transition ;
-
-TUPLE: literal obj ;
-TUPLE: class obj ;
-TUPLE: default ;
-: make-transition ( from to obj class -- obj )
-    new
-        swap >>obj
-        swap >>to
-        swap >>from ;
-
-: <literal-transition> ( from to obj -- transition )
-    literal-transition make-transition ;
-: <class-transition> ( from to obj -- transition )
-    class-transition make-transition ;
-: <default-transition> ( from to -- transition )
-    t default-transition make-transition ;
-
-TUPLE: transition-table transitions start-state final-states ;
-
-: <transition-table> ( -- transition-table )
-    transition-table new
-        H{ } clone >>transitions
-        H{ } clone >>final-states ;
-
-: set-transition ( transition hash -- )
-    [ [ to>> ] [ obj>> ] [ from>> ] tri ] dip
-    2dup at* [ 2nip insert-at ]
-    [ drop >r >r H{ } clone [ insert-at ] keep r> r> set-at ] if ;
-
-: add-transition ( transition transition-table -- )
-    transitions>> set-transition ;
diff --git a/unfinished/regexp2/traversal/traversal.factor b/unfinished/regexp2/traversal/traversal.factor
deleted file mode 100644 (file)
index ba9284c..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs combinators combinators.lib kernel
-math math.ranges quotations sequences regexp2.parser
-regexp2.classes combinators.short-circuit assocs.lib
-sequences.lib regexp2.utils ;
-IN: regexp2.traversal
-
-TUPLE: dfa-traverser
-    dfa-table
-    traversal-flags
-    capture-groups
-    { capture-group-index integer }
-    { lookahead-counter integer }
-    last-state current-state
-    text
-    start-index current-index
-    matches ;
-
-: <dfa-traverser> ( text regexp -- match )
-    [ dfa-table>> ] [ dfa-traversal-flags>> ] bi
-    dfa-traverser new
-        swap >>traversal-flags
-        swap [ start-state>> >>current-state ] keep
-        >>dfa-table
-        swap >>text
-        0 >>start-index
-        0 >>current-index
-        V{ } clone >>matches
-        V{ } clone >>capture-groups ;
-
-: final-state? ( dfa-traverser -- ? )
-    [ current-state>> ] [ dfa-table>> final-states>> ] bi
-    key? ;
-
-: text-finished? ( dfa-traverser -- ? )
-    [ current-index>> ] [ text>> length ] bi >= ;
-
-: save-final-state ( dfa-straverser -- )
-    [ current-index>> ] [ matches>> ] bi push ;
-
-: match-done? ( dfa-traverser -- ? )
-    dup final-state? [
-        dup save-final-state
-    ] when text-finished? ;
-
-: increment-state ( dfa-traverser state -- dfa-traverser )
-    [
-        [ 1+ ] change-current-index dup current-state>> >>last-state
-    ] dip
-    first >>current-state ;
-
-: match-failed ( dfa-traverser -- dfa-traverser )
-    V{ } clone >>matches ;
-
-: match-literal ( transition from-state table -- to-state/f )
-    transitions>> [ at ] [ 2drop f ] if-at ;
-
-: match-class ( transition from-state table -- to-state/f )
-    transitions>> at* [
-        [ drop class-member? ] assoc-with assoc-find [ nip ] [ drop ] if
-    ] [ drop ] if ;
-
-: match-default ( transition from-state table -- to-state/f )
-    [ nip ] dip transitions>>
-    [ t swap [ drop f ] unless-at ] [ drop f ] if-at ;
-
-: match-transition ( obj from-state dfa -- to-state/f )
-    { [ match-literal ] [ match-class ] [ match-default ] } 3|| ;
-
-: setup-match ( match -- obj state dfa-table )
-    {
-        [ current-index>> ] [ text>> ]
-        [ current-state>> ] [ dfa-table>> ]
-    } cleave
-    [ nth ] 2dip ;
-
-: do-match ( dfa-traverser -- dfa-traverser )
-    dup match-done? [
-        dup setup-match match-transition
-        [ increment-state do-match ] when*
-    ] unless ;
-
-: return-match ( dfa-traverser -- interval/f )
-    dup matches>>
-    [ drop f ]
-    [ [ start-index>> ] [ peek ] bi* 1 <range> ] if-empty ;
diff --git a/unfinished/regexp2/utils/utils.factor b/unfinished/regexp2/utils/utils.factor
deleted file mode 100644 (file)
index ab51436..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs combinators.lib io kernel
-math math.order namespaces regexp2.backend sequences
-sequences.lib unicode.categories math.ranges fry
-combinators.short-circuit vectors ;
-IN: regexp2.utils
-
-: (while-changes) ( obj quot pred pred-ret -- obj )
-    ! quot: ( obj -- obj' )
-    ! pred: ( obj -- <=> )
-    [ [ dup slip ] dip pick over call ] dip dupd =
-    [ 3drop ] [ (while-changes) ] if ; inline recursive
-
-: while-changes ( obj quot pred -- obj' )
-    pick over call (while-changes) ; inline
-
-: assoc-with ( param assoc quot -- assoc curry )
-    swapd [ [ -rot ] dip call ] 2curry ; inline
-
-: insert-at ( value key hash -- )
-    2dup at* [
-        2nip push
-    ] [
-        drop
-        [ dup vector? [ 1vector ] unless ] 2dip set-at
-    ] if ;
-
-: ?insert-at ( value key hash/f -- hash )
-    [ H{ } clone ] unless* [ insert-at ] keep ;
-
-: last-state ( regexp -- range ) stack>> peek first2 [a,b] ;
-: push1 ( obj -- ) input-stream get stream>> push ;
-: peek1 ( -- obj ) input-stream get stream>> [ f ] [ peek ] if-empty ;
-: pop3 ( seq -- obj1 obj2 obj3 ) [ pop ] [ pop ] [ pop ] tri spin ;
-: drop1 ( -- ) read1 drop ;
-
-: stack ( -- obj ) current-regexp get stack>> ;
-: change-whole-stack ( quot -- )
-    current-regexp get
-    [ stack>> swap call ] keep (>>stack) ; inline
-: push-stack ( obj -- ) stack push ;
-: pop-stack ( -- obj ) stack pop ;
-: cut-out ( vector n -- vector' vector ) cut rest ;
-ERROR: cut-stack-error ;
-: cut-stack ( obj vector -- vector' vector )
-    tuck last-index [ cut-stack-error ] unless* cut-out swap ;
-
-ERROR: bad-octal number ;
-ERROR: bad-hex number ;
-: check-octal ( octal -- octal ) dup 255 > [ bad-octal ] when ;
-: check-hex ( hex -- hex ) dup number? [ bad-hex ] unless ;
-
-: ascii? ( n -- ? ) 0 HEX: 7f between? ;
-: octal-digit? ( n -- ? ) CHAR: 0 CHAR: 7 between? ;
-: decimal-digit? ( n -- ? ) CHAR: 0 CHAR: 9 between? ;
-
-: hex-digit? ( n -- ? )
-    [
-        [ decimal-digit? ]
-        [ CHAR: a CHAR: f between? ]
-        [ CHAR: A CHAR: F between? ]
-    ] 1|| ;
-
-: control-char? ( n -- ? )
-    [
-        [ 0 HEX: 1f between? ]
-        [ HEX: 7f = ]
-    ] 1|| ;
-
-: punct? ( n -- ? )
-    "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" member? ;
-
-: c-identifier-char? ( ch -- ? )
-    [ [ alpha? ] [ CHAR: _ = ] ] 1|| ;
-
-: java-blank? ( n -- ? )
-    {
-        CHAR: \s CHAR: \t CHAR: \n
-        HEX: b HEX: 7 CHAR: \r
-    } member? ;
-
-: java-printable? ( n -- ? )
-    [ [ alpha? ] [ punct? ] ] 1|| ;
index a0fa48d504f5f2855b030bd400cf73a32301ed7c..62f9e1c906c2ea83f832e19f9b8e77ddfa6d2fd7 100755 (executable)
@@ -169,12 +169,33 @@ DEFINE_PRIMITIVE(save_image)
        save_image(unbox_native_string());
 }
 
+void strip_compiled_quotations(void)
+{
+       begin_scan();
+       CELL obj;
+       while((obj = next_object()) != F)
+       {
+               if(type_of(obj) == QUOTATION_TYPE)
+               {
+                       F_QUOTATION *quot = untag_object(obj);
+                       quot->compiledp = F;
+               }
+       }
+       gc_off = false;
+}
+
 DEFINE_PRIMITIVE(save_image_and_exit)
 {
+       /* We unbox this before doing anything else. This is the only point
+       where we might throw an error, so we have to throw an error here since
+       later steps destroy the current image. */
        F_CHAR *path = unbox_native_string();
 
        REGISTER_C_STRING(path);
 
+       /* This reduces deployed image size */
+       strip_compiled_quotations();
+
        /* strip out userenv data which is set on startup anyway */
        CELL i;
        for(i = 0; i < FIRST_SAVE_ENV; i++)
index 3097ee73f8fdf3de28dbdb1dafb531e2a0deebdb..ccc7cbdba30f3b7f79d01d6bdcc6183b79164fdd 100755 (executable)
@@ -470,6 +470,7 @@ F_STRING* reallot_string(F_STRING* string, CELL capacity, CELL fill)
                UNREGISTER_UNTAGGED(new_string);
                UNREGISTER_UNTAGGED(string);
 
+               write_barrier((CELL)new_string);
                new_string->aux = tag_object(new_aux);
 
                F_BYTE_ARRAY *aux = untag_object(string->aux);
@@ -477,7 +478,9 @@ F_STRING* reallot_string(F_STRING* string, CELL capacity, CELL fill)
        }
 
        REGISTER_UNTAGGED(string);
+       REGISTER_UNTAGGED(new_string);
        fill_string(new_string,to_copy,capacity,fill);
+       UNREGISTER_UNTAGGED(new_string);
        UNREGISTER_UNTAGGED(string);
 
        return new_string;