Merge branch 'master' of git://factorcode.org/git/factor
commit
d829fc19ba
|
@ -2,17 +2,17 @@
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: arrays assocs classes continuations destructors kernel math
|
USING: arrays assocs classes continuations destructors kernel math
|
||||||
namespaces sequences classes.tuple words strings
|
namespaces sequences classes.tuple words strings
|
||||||
tools.walker accessors combinators fry ;
|
tools.walker accessors combinators fry db.errors ;
|
||||||
IN: db
|
IN: db
|
||||||
|
|
||||||
<PRIVATE
|
|
||||||
|
|
||||||
TUPLE: db-connection
|
TUPLE: db-connection
|
||||||
handle
|
handle
|
||||||
insert-statements
|
insert-statements
|
||||||
update-statements
|
update-statements
|
||||||
delete-statements ;
|
delete-statements ;
|
||||||
|
|
||||||
|
<PRIVATE
|
||||||
|
|
||||||
: new-db-connection ( class -- obj )
|
: new-db-connection ( class -- obj )
|
||||||
new
|
new
|
||||||
H{ } clone >>insert-statements
|
H{ } clone >>insert-statements
|
||||||
|
@ -23,6 +23,7 @@ PRIVATE>
|
||||||
|
|
||||||
GENERIC: db-open ( db -- db-connection )
|
GENERIC: db-open ( db -- db-connection )
|
||||||
HOOK: db-close db-connection ( handle -- )
|
HOOK: db-close db-connection ( handle -- )
|
||||||
|
HOOK: parse-db-error db-connection ( error -- error' )
|
||||||
|
|
||||||
: dispose-statements ( assoc -- ) values dispose-each ;
|
: dispose-statements ( assoc -- ) values dispose-each ;
|
||||||
|
|
||||||
|
@ -77,7 +78,11 @@ GENERIC: bind-tuple ( tuple statement -- )
|
||||||
GENERIC: execute-statement* ( statement type -- )
|
GENERIC: execute-statement* ( statement type -- )
|
||||||
|
|
||||||
M: object execute-statement* ( statement type -- )
|
M: object execute-statement* ( statement type -- )
|
||||||
drop query-results dispose ;
|
'[
|
||||||
|
_ _ drop query-results dispose
|
||||||
|
] [
|
||||||
|
parse-db-error rethrow
|
||||||
|
] recover ;
|
||||||
|
|
||||||
: execute-one-statement ( statement -- )
|
: execute-one-statement ( statement -- )
|
||||||
dup type>> execute-statement* ;
|
dup type>> execute-statement* ;
|
||||||
|
|
|
@ -1,10 +1,54 @@
|
||||||
! Copyright (C) 2008 Doug Coleman.
|
! Copyright (C) 2008 Doug Coleman.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: kernel ;
|
USING: accessors kernel continuations fry words ;
|
||||||
IN: db.errors
|
IN: db.errors
|
||||||
|
|
||||||
ERROR: db-error ;
|
ERROR: db-error ;
|
||||||
ERROR: sql-error ;
|
ERROR: sql-error location ;
|
||||||
|
|
||||||
ERROR: table-exists ;
|
|
||||||
ERROR: bad-schema ;
|
ERROR: bad-schema ;
|
||||||
|
|
||||||
|
ERROR: sql-unknown-error < sql-error message ;
|
||||||
|
: <sql-unknown-error> ( message -- error )
|
||||||
|
\ sql-unknown-error new
|
||||||
|
swap >>message ;
|
||||||
|
|
||||||
|
ERROR: sql-table-exists < sql-error table ;
|
||||||
|
: <sql-table-exists> ( table -- error )
|
||||||
|
\ sql-table-exists new
|
||||||
|
swap >>table ;
|
||||||
|
|
||||||
|
ERROR: sql-table-missing < sql-error table ;
|
||||||
|
: <sql-table-missing> ( table -- error )
|
||||||
|
\ sql-table-missing new
|
||||||
|
swap >>table ;
|
||||||
|
|
||||||
|
ERROR: sql-syntax-error < sql-error message ;
|
||||||
|
: <sql-syntax-error> ( message -- error )
|
||||||
|
\ sql-syntax-error new
|
||||||
|
swap >>message ;
|
||||||
|
|
||||||
|
ERROR: sql-function-exists < sql-error message ;
|
||||||
|
: <sql-function-exists> ( message -- error )
|
||||||
|
\ sql-function-exists new
|
||||||
|
swap >>message ;
|
||||||
|
|
||||||
|
ERROR: sql-function-missing < sql-error message ;
|
||||||
|
: <sql-function-missing> ( message -- error )
|
||||||
|
\ sql-function-missing new
|
||||||
|
swap >>message ;
|
||||||
|
|
||||||
|
: ignore-error ( quot word -- )
|
||||||
|
'[ dup _ execute [ drop ] [ rethrow ] if ] recover ; inline
|
||||||
|
|
||||||
|
: ignore-table-exists ( quot -- )
|
||||||
|
\ sql-table-exists? ignore-error ; inline
|
||||||
|
|
||||||
|
: ignore-table-missing ( quot -- )
|
||||||
|
\ sql-table-missing? ignore-error ; inline
|
||||||
|
|
||||||
|
: ignore-function-exists ( quot -- )
|
||||||
|
\ sql-function-exists? ignore-error ; inline
|
||||||
|
|
||||||
|
: ignore-function-missing ( quot -- )
|
||||||
|
\ sql-function-missing? ignore-error ; inline
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -0,0 +1,32 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: accessors combinators.short-circuit db db.errors
|
||||||
|
db.errors.postgresql db.postgresql io.files.unique kernel namespaces
|
||||||
|
tools.test db.tester continuations ;
|
||||||
|
IN: db.errors.postgresql.tests
|
||||||
|
|
||||||
|
postgresql-test-db [
|
||||||
|
|
||||||
|
[ "drop table foo;" sql-command ] ignore-errors
|
||||||
|
[ "drop table ship;" sql-command ] ignore-errors
|
||||||
|
|
||||||
|
[
|
||||||
|
"insert into foo (id) values('1');" sql-command
|
||||||
|
] [
|
||||||
|
{ [ sql-table-missing? ] [ table>> "foo" = ] } 1&&
|
||||||
|
] must-fail-with
|
||||||
|
|
||||||
|
[
|
||||||
|
"create table ship(id integer);" sql-command
|
||||||
|
"create table ship(id integer);" sql-command
|
||||||
|
] [
|
||||||
|
{ [ sql-table-exists? ] [ table>> "ship" = ] } 1&&
|
||||||
|
] must-fail-with
|
||||||
|
|
||||||
|
[
|
||||||
|
"create table foo(id) lol;" sql-command
|
||||||
|
] [
|
||||||
|
sql-syntax-error?
|
||||||
|
] must-fail-with
|
||||||
|
|
||||||
|
] with-db
|
|
@ -0,0 +1,53 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: kernel db.errors peg.ebnf strings sequences math
|
||||||
|
combinators.short-circuit accessors math.parser quoting ;
|
||||||
|
IN: db.errors.postgresql
|
||||||
|
|
||||||
|
EBNF: parse-postgresql-sql-error
|
||||||
|
|
||||||
|
Error = "ERROR:" [ ]+
|
||||||
|
|
||||||
|
TableError =
|
||||||
|
Error ("relation "|"table ")(!(" already exists").)+:table " already exists"
|
||||||
|
=> [[ table >string unquote <sql-table-exists> ]]
|
||||||
|
| Error ("relation "|"table ")(!(" does not exist").)+:table " does not exist"
|
||||||
|
=> [[ table >string unquote <sql-table-missing> ]]
|
||||||
|
|
||||||
|
FunctionError =
|
||||||
|
Error "function" (!(" already exists").)+:table " already exists"
|
||||||
|
=> [[ table >string <sql-function-exists> ]]
|
||||||
|
| Error "function" (!(" does not exist").)+:table " does not exist"
|
||||||
|
=> [[ table >string <sql-function-missing> ]]
|
||||||
|
|
||||||
|
SyntaxError =
|
||||||
|
Error "syntax error at end of input":error
|
||||||
|
=> [[ error >string <sql-syntax-error> ]]
|
||||||
|
| Error "syntax error at or near " .+:syntaxerror
|
||||||
|
=> [[ syntaxerror >string unquote <sql-syntax-error> ]]
|
||||||
|
|
||||||
|
UnknownError = .* => [[ >string <sql-unknown-error> ]]
|
||||||
|
|
||||||
|
PostgresqlSqlError = (TableError | FunctionError | SyntaxError | UnknownError)
|
||||||
|
|
||||||
|
;EBNF
|
||||||
|
|
||||||
|
|
||||||
|
ERROR: parse-postgresql-location column line text ;
|
||||||
|
C: <parse-postgresql-location> parse-postgresql-location
|
||||||
|
|
||||||
|
EBNF: parse-postgresql-line-error
|
||||||
|
|
||||||
|
Line = "LINE " [0-9]+:line ": " .+:sql
|
||||||
|
=> [[ f line >string string>number sql >string <parse-postgresql-location> ]]
|
||||||
|
|
||||||
|
;EBNF
|
||||||
|
|
||||||
|
:: set-caret-position ( error caret-line -- error )
|
||||||
|
caret-line length
|
||||||
|
error line>> number>string length "LINE : " length +
|
||||||
|
- [ error ] dip >>column ;
|
||||||
|
|
||||||
|
: postgresql-location ( line column -- obj )
|
||||||
|
[ parse-postgresql-line-error ] dip
|
||||||
|
set-caret-position ;
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -0,0 +1,26 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: accessors combinators.short-circuit db db.errors
|
||||||
|
db.errors.sqlite db.sqlite io.files.unique kernel namespaces
|
||||||
|
tools.test ;
|
||||||
|
IN: db.errors.sqlite.tests
|
||||||
|
|
||||||
|
: sqlite-error-test-db-path ( -- path )
|
||||||
|
"sqlite" "error-test" make-unique-file ;
|
||||||
|
|
||||||
|
sqlite-error-test-db-path <sqlite-db> [
|
||||||
|
|
||||||
|
[
|
||||||
|
"insert into foo (id) values('1');" sql-command
|
||||||
|
] [
|
||||||
|
{ [ sql-table-missing? ] [ table>> "foo" = ] } 1&&
|
||||||
|
] must-fail-with
|
||||||
|
|
||||||
|
[
|
||||||
|
"create table foo(id);" sql-command
|
||||||
|
"create table foo(id);" sql-command
|
||||||
|
] [
|
||||||
|
{ [ sql-table-exists? ] [ table>> "foo" = ] } 1&&
|
||||||
|
] must-fail-with
|
||||||
|
|
||||||
|
] with-db
|
|
@ -0,0 +1,25 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: accessors combinators db kernel sequences peg.ebnf
|
||||||
|
strings db.errors ;
|
||||||
|
IN: db.errors.sqlite
|
||||||
|
|
||||||
|
ERROR: unparsed-sqlite-error error ;
|
||||||
|
|
||||||
|
SINGLETONS: table-exists table-missing ;
|
||||||
|
|
||||||
|
: sqlite-table-error ( table message -- error )
|
||||||
|
{
|
||||||
|
{ table-exists [ <sql-table-exists> ] }
|
||||||
|
} case ;
|
||||||
|
|
||||||
|
EBNF: parse-sqlite-sql-error
|
||||||
|
|
||||||
|
TableMessage = " already exists" => [[ table-exists ]]
|
||||||
|
|
||||||
|
SqliteError =
|
||||||
|
"table " (!(TableMessage).)+:table TableMessage:message
|
||||||
|
=> [[ table >string message sqlite-table-error ]]
|
||||||
|
| "no such table: " .+:table
|
||||||
|
=> [[ table >string <sql-table-missing> ]]
|
||||||
|
;EBNF
|
|
@ -1,20 +1,13 @@
|
||||||
USING: kernel db.postgresql alien continuations io classes
|
USING: kernel db.postgresql alien continuations io classes
|
||||||
prettyprint sequences namespaces tools.test db db.private
|
prettyprint sequences namespaces tools.test db db.private
|
||||||
db.tuples db.types unicode.case accessors system ;
|
db.tuples db.types unicode.case accessors system db.tester ;
|
||||||
IN: db.postgresql.tests
|
IN: db.postgresql.tests
|
||||||
|
|
||||||
: test-db ( -- postgresql-db )
|
|
||||||
<postgresql-db>
|
|
||||||
"localhost" >>host
|
|
||||||
"postgres" >>username
|
|
||||||
"thepasswordistrust" >>password
|
|
||||||
"factor-test" >>database ;
|
|
||||||
|
|
||||||
os windows? cpu x86.64? and [
|
os windows? cpu x86.64? and [
|
||||||
[ ] [ test-db [ ] with-db ] unit-test
|
[ ] [ postgresql-test-db [ ] with-db ] unit-test
|
||||||
|
|
||||||
[ ] [
|
[ ] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
[ "drop table person;" sql-command ] ignore-errors
|
[ "drop table person;" sql-command ] ignore-errors
|
||||||
"create table person (name varchar(30), country varchar(30));"
|
"create table person (name varchar(30), country varchar(30));"
|
||||||
sql-command
|
sql-command
|
||||||
|
@ -30,7 +23,7 @@ os windows? cpu x86.64? and [
|
||||||
{ "Jane" "New Zealand" }
|
{ "Jane" "New Zealand" }
|
||||||
}
|
}
|
||||||
] [
|
] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
"select * from person" sql-query
|
"select * from person" sql-query
|
||||||
] with-db
|
] with-db
|
||||||
] unit-test
|
] unit-test
|
||||||
|
@ -40,11 +33,11 @@ os windows? cpu x86.64? and [
|
||||||
{ "John" "America" }
|
{ "John" "America" }
|
||||||
{ "Jane" "New Zealand" }
|
{ "Jane" "New Zealand" }
|
||||||
}
|
}
|
||||||
] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
|
] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
|
||||||
|
|
||||||
[
|
[
|
||||||
] [
|
] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
"insert into person(name, country) values('Jimmy', 'Canada')"
|
"insert into person(name, country) values('Jimmy', 'Canada')"
|
||||||
sql-command
|
sql-command
|
||||||
] with-db
|
] with-db
|
||||||
|
@ -56,10 +49,10 @@ os windows? cpu x86.64? and [
|
||||||
{ "Jane" "New Zealand" }
|
{ "Jane" "New Zealand" }
|
||||||
{ "Jimmy" "Canada" }
|
{ "Jimmy" "Canada" }
|
||||||
}
|
}
|
||||||
] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
|
] [ postgresql-test-db [ "select * from person" sql-query ] with-db ] unit-test
|
||||||
|
|
||||||
[
|
[
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
[
|
[
|
||||||
"insert into person(name, country) values('Jose', 'Mexico')" sql-command
|
"insert into person(name, country) values('Jose', 'Mexico')" sql-command
|
||||||
"insert into person(name, country) values('Jose', 'Mexico')" sql-command
|
"insert into person(name, country) values('Jose', 'Mexico')" sql-command
|
||||||
|
@ -69,14 +62,14 @@ os windows? cpu x86.64? and [
|
||||||
] must-fail
|
] must-fail
|
||||||
|
|
||||||
[ 3 ] [
|
[ 3 ] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
"select * from person" sql-query length
|
"select * from person" sql-query length
|
||||||
] with-db
|
] with-db
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
[
|
[
|
||||||
] [
|
] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
[
|
[
|
||||||
"insert into person(name, country) values('Jose', 'Mexico')"
|
"insert into person(name, country) values('Jose', 'Mexico')"
|
||||||
sql-command
|
sql-command
|
||||||
|
@ -87,7 +80,7 @@ os windows? cpu x86.64? and [
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
[ 5 ] [
|
[ 5 ] [
|
||||||
test-db [
|
postgresql-test-db [
|
||||||
"select * from person" sql-query length
|
"select * from person" sql-query length
|
||||||
] with-db
|
] with-db
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
|
@ -5,8 +5,8 @@ kernel math math.parser namespaces make prettyprint quotations
|
||||||
sequences debugger db db.postgresql.lib db.postgresql.ffi
|
sequences debugger db db.postgresql.lib db.postgresql.ffi
|
||||||
db.tuples db.types tools.annotations math.ranges
|
db.tuples db.types tools.annotations math.ranges
|
||||||
combinators classes locals words tools.walker db.private
|
combinators classes locals words tools.walker db.private
|
||||||
nmake accessors random db.queries destructors db.tuples.private ;
|
nmake accessors random db.queries destructors db.tuples.private
|
||||||
USE: tools.walker
|
db.postgresql db.errors.postgresql splitting ;
|
||||||
IN: db.postgresql
|
IN: db.postgresql
|
||||||
|
|
||||||
TUPLE: postgresql-db host port pgopts pgtty database username password ;
|
TUPLE: postgresql-db host port pgopts pgtty database username password ;
|
||||||
|
@ -280,3 +280,14 @@ M: postgresql-db-connection compound ( string object -- string' )
|
||||||
{ "references" [ >reference-string ] }
|
{ "references" [ >reference-string ] }
|
||||||
[ drop no-compound-found ]
|
[ drop no-compound-found ]
|
||||||
} case ;
|
} case ;
|
||||||
|
|
||||||
|
M: postgresql-db-connection parse-db-error
|
||||||
|
"\n" split dup length {
|
||||||
|
{ 1 [ first parse-postgresql-sql-error ] }
|
||||||
|
{ 3 [
|
||||||
|
first3
|
||||||
|
[ parse-postgresql-sql-error ] 2dip
|
||||||
|
postgresql-location >>location
|
||||||
|
] }
|
||||||
|
} case ;
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,17 @@ IN: db.sqlite.lib
|
||||||
ERROR: sqlite-error < db-error n string ;
|
ERROR: sqlite-error < db-error n string ;
|
||||||
ERROR: sqlite-sql-error < sql-error n string ;
|
ERROR: sqlite-sql-error < sql-error n string ;
|
||||||
|
|
||||||
|
: <sqlite-sql-error> ( n string -- error )
|
||||||
|
\ sqlite-sql-error new
|
||||||
|
swap >>string
|
||||||
|
swap >>n ;
|
||||||
|
|
||||||
: throw-sqlite-error ( n -- * )
|
: throw-sqlite-error ( n -- * )
|
||||||
dup sqlite-error-messages nth sqlite-error ;
|
dup sqlite-error-messages nth sqlite-error ;
|
||||||
|
|
||||||
: sqlite-statement-error ( -- * )
|
: sqlite-statement-error ( -- * )
|
||||||
SQLITE_ERROR
|
SQLITE_ERROR
|
||||||
db-connection get handle>> sqlite3_errmsg sqlite-sql-error ;
|
db-connection get handle>> sqlite3_errmsg <sqlite-sql-error> throw ;
|
||||||
|
|
||||||
: sqlite-check-result ( n -- )
|
: sqlite-check-result ( n -- )
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,12 +123,8 @@ hi "HELLO" {
|
||||||
] with-db
|
] with-db
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
[ ] [
|
|
||||||
test.db [
|
! Test SQLite triggers
|
||||||
hi create-table
|
|
||||||
hi drop-table
|
|
||||||
] with-db
|
|
||||||
] unit-test
|
|
||||||
|
|
||||||
TUPLE: show id ;
|
TUPLE: show id ;
|
||||||
TUPLE: user username data ;
|
TUPLE: user username data ;
|
||||||
|
@ -144,12 +140,12 @@ show "SHOW" {
|
||||||
} define-persistent
|
} define-persistent
|
||||||
|
|
||||||
watch "WATCH" {
|
watch "WATCH" {
|
||||||
{ "user" "USER" TEXT +not-null+
|
{ "user" "USER" TEXT +not-null+ +user-assigned-id+
|
||||||
{ +foreign-id+ user "USERNAME" } +user-assigned-id+ }
|
{ +foreign-id+ user "USERNAME" } }
|
||||||
{ "show" "SHOW" BIG-INTEGER +not-null+
|
{ "show" "SHOW" BIG-INTEGER +not-null+ +user-assigned-id+
|
||||||
{ +foreign-id+ show "ID" } +user-assigned-id+ }
|
{ +foreign-id+ show "ID" } }
|
||||||
} define-persistent
|
} define-persistent
|
||||||
|
|
||||||
[ T{ user { username "littledan" } { data "foo" } } ] [
|
[ T{ user { username "littledan" } { data "foo" } } ] [
|
||||||
test.db [
|
test.db [
|
||||||
user create-table
|
user create-table
|
||||||
|
@ -160,7 +156,7 @@ watch "WATCH" {
|
||||||
show new insert-tuple
|
show new insert-tuple
|
||||||
show new select-tuple
|
show new select-tuple
|
||||||
"littledan" f user boa select-tuple
|
"littledan" f user boa select-tuple
|
||||||
swap [ username>> ] [ id>> ] bi*
|
[ id>> ] [ username>> ] bi*
|
||||||
watch boa insert-tuple
|
watch boa insert-tuple
|
||||||
watch new select-tuple
|
watch new select-tuple
|
||||||
user>> f user boa select-tuple
|
user>> f user boa select-tuple
|
||||||
|
|
|
@ -6,7 +6,8 @@ sequences strings classes.tuple alien.c-types continuations
|
||||||
db.sqlite.lib db.sqlite.ffi db.tuples words db.types combinators
|
db.sqlite.lib db.sqlite.ffi db.tuples words db.types combinators
|
||||||
math.intervals io nmake accessors vectors math.ranges random
|
math.intervals io nmake accessors vectors math.ranges random
|
||||||
math.bitwise db.queries destructors db.tuples.private interpolate
|
math.bitwise db.queries destructors db.tuples.private interpolate
|
||||||
io.streams.string multiline make db.private sequences.deep ;
|
io.streams.string multiline make db.private sequences.deep
|
||||||
|
db.errors.sqlite ;
|
||||||
IN: db.sqlite
|
IN: db.sqlite
|
||||||
|
|
||||||
TUPLE: sqlite-db path ;
|
TUPLE: sqlite-db path ;
|
||||||
|
@ -204,7 +205,7 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
CREATE TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
CREATE TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
||||||
BEFORE INSERT ON ${table-name}
|
BEFORE INSERT ON ${table-name}
|
||||||
FOR EACH ROW BEGIN
|
FOR EACH ROW BEGIN
|
||||||
SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
|
SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fki_${table-name}_$table-id}_${foreign-table-name}_${foreign-table-id}_id"')
|
||||||
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
||||||
END;
|
END;
|
||||||
"> interpolate
|
"> interpolate
|
||||||
|
@ -216,28 +217,21 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
CREATE TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
CREATE TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
||||||
BEFORE INSERT ON ${table-name}
|
BEFORE INSERT ON ${table-name}
|
||||||
FOR EACH ROW BEGIN
|
FOR EACH ROW BEGIN
|
||||||
SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
|
SELECT RAISE(ROLLBACK, 'insert on table "${table-name}" violates foreign key constraint "fki_${table-name}_$table-id}_${foreign-table-name}_${foreign-table-id}_id"')
|
||||||
WHERE NEW.${foreign-table-id} IS NOT NULL
|
WHERE NEW.${table-id} IS NOT NULL
|
||||||
AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
||||||
END;
|
END;
|
||||||
"> interpolate
|
"> interpolate
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
|
||||||
: drop-insert-trigger ( -- string )
|
|
||||||
[
|
|
||||||
<"
|
|
||||||
DROP TRIGGER fki_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
|
|
||||||
"> interpolate
|
|
||||||
] with-string-writer ;
|
|
||||||
|
|
||||||
: update-trigger ( -- string )
|
: update-trigger ( -- string )
|
||||||
[
|
[
|
||||||
<"
|
<"
|
||||||
CREATE TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
CREATE TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
||||||
BEFORE UPDATE ON ${table-name}
|
BEFORE UPDATE ON ${table-name}
|
||||||
FOR EACH ROW BEGIN
|
FOR EACH ROW BEGIN
|
||||||
SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
|
SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fku_${table-name}_$table-id}_${foreign-table-name}_${foreign-table-id}_id"')
|
||||||
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
||||||
END;
|
END;
|
||||||
"> interpolate
|
"> interpolate
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
@ -248,39 +242,25 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
CREATE TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
CREATE TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
||||||
BEFORE UPDATE ON ${table-name}
|
BEFORE UPDATE ON ${table-name}
|
||||||
FOR EACH ROW BEGIN
|
FOR EACH ROW BEGIN
|
||||||
SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
|
SELECT RAISE(ROLLBACK, 'update on table "${table-name}" violates foreign key constraint "fku_${table-name}_$table-id}_${foreign-table-name}_${foreign-table-id}_id"')
|
||||||
WHERE NEW.${foreign-table-id} IS NOT NULL
|
WHERE NEW.${table-id} IS NOT NULL
|
||||||
AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
AND (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = NEW.${table-id}) IS NULL;
|
||||||
END;
|
END;
|
||||||
"> interpolate
|
"> interpolate
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
|
||||||
: drop-update-trigger ( -- string )
|
|
||||||
[
|
|
||||||
<"
|
|
||||||
DROP TRIGGER fku_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
|
|
||||||
"> interpolate
|
|
||||||
] with-string-writer ;
|
|
||||||
|
|
||||||
: delete-trigger-restrict ( -- string )
|
: delete-trigger-restrict ( -- string )
|
||||||
[
|
[
|
||||||
<"
|
<"
|
||||||
CREATE TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
CREATE TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id
|
||||||
BEFORE DELETE ON ${foreign-table-name}
|
BEFORE DELETE ON ${foreign-table-name}
|
||||||
FOR EACH ROW BEGIN
|
FOR EACH ROW BEGIN
|
||||||
SELECT RAISE(ROLLBACK, 'delete on table "${foreign-table-name}" violates foreign key constraint "fk_${foreign-table-name}_id"')
|
SELECT RAISE(ROLLBACK, 'delete on table "${foreign-table-name}" violates foreign key constraint "fkd_${table-name}_$table-id}_${foreign-table-name}_${foreign-table-id}_id"')
|
||||||
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = OLD.${foreign-table-id}) IS NOT NULL;
|
WHERE (SELECT ${foreign-table-id} FROM ${foreign-table-name} WHERE ${foreign-table-id} = OLD.${foreign-table-id}) IS NOT NULL;
|
||||||
END;
|
END;
|
||||||
"> interpolate
|
"> interpolate
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
|
||||||
: drop-delete-trigger-restrict ( -- string )
|
|
||||||
[
|
|
||||||
<"
|
|
||||||
DROP TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
|
|
||||||
"> interpolate
|
|
||||||
] with-string-writer ;
|
|
||||||
|
|
||||||
: delete-trigger-cascade ( -- string )
|
: delete-trigger-cascade ( -- string )
|
||||||
[
|
[
|
||||||
<"
|
<"
|
||||||
|
@ -292,13 +272,6 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
"> interpolate
|
"> interpolate
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
|
||||||
: drop-delete-trigger-cascade ( -- string )
|
|
||||||
[
|
|
||||||
<"
|
|
||||||
DROP TRIGGER fkd_${table-name}_${table-id}_${foreign-table-name}_${foreign-table-id}_id;
|
|
||||||
"> interpolate
|
|
||||||
] with-string-writer ;
|
|
||||||
|
|
||||||
: can-be-null? ( -- ? )
|
: can-be-null? ( -- ? )
|
||||||
"sql-spec" get modifiers>> [ +not-null+ = ] any? not ;
|
"sql-spec" get modifiers>> [ +not-null+ = ] any? not ;
|
||||||
|
|
||||||
|
@ -322,31 +295,22 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
delete-trigger-restrict sqlite-trigger,
|
delete-trigger-restrict sqlite-trigger,
|
||||||
] if ;
|
] if ;
|
||||||
|
|
||||||
: drop-sqlite-triggers ( -- )
|
: create-db-triggers ( sql-specs -- )
|
||||||
drop-insert-trigger sqlite-trigger,
|
[ modifiers>> [ +foreign-id+ = ] deep-any? ] filter
|
||||||
drop-update-trigger sqlite-trigger,
|
[
|
||||||
delete-cascade? [
|
[ class>> db-table-name "db-table" set ]
|
||||||
drop-delete-trigger-cascade sqlite-trigger,
|
|
||||||
] [
|
|
||||||
drop-delete-trigger-restrict sqlite-trigger,
|
|
||||||
] if ;
|
|
||||||
|
|
||||||
: db-triggers ( sql-specs word -- )
|
|
||||||
'[
|
|
||||||
[ modifiers>> [ +foreign-id+ = ] deep-any? ] filter
|
|
||||||
[
|
[
|
||||||
[ class>> db-table-name "db-table" set ]
|
[ "sql-spec" set ]
|
||||||
[ column-name>> "table-id" set ]
|
[ column-name>> "table-id" set ]
|
||||||
|
[ ] tri
|
||||||
|
modifiers>> [ [ +foreign-id+ = ] deep-any? ] filter
|
||||||
[
|
[
|
||||||
modifiers>> [ [ +foreign-id+ = ] deep-any? ] filter
|
[ second db-table-name "foreign-table-name" set ]
|
||||||
[
|
[ third "foreign-table-id" set ] bi
|
||||||
[ second db-table-name "foreign-table-name" set ]
|
create-sqlite-triggers
|
||||||
[ third "foreign-table-id" set ] bi
|
] each
|
||||||
_ execute
|
] bi
|
||||||
] each
|
] each ;
|
||||||
] tri
|
|
||||||
] each
|
|
||||||
] call ;
|
|
||||||
|
|
||||||
: sqlite-create-table ( sql-specs class-name -- )
|
: sqlite-create-table ( sql-specs class-name -- )
|
||||||
[
|
[
|
||||||
|
@ -371,16 +335,12 @@ M: sqlite-db-connection persistent-table ( -- assoc )
|
||||||
|
|
||||||
M: sqlite-db-connection create-sql-statement ( class -- statement )
|
M: sqlite-db-connection create-sql-statement ( class -- statement )
|
||||||
[
|
[
|
||||||
! specs name
|
|
||||||
[ sqlite-create-table ]
|
[ sqlite-create-table ]
|
||||||
[ drop \ create-sqlite-triggers db-triggers ] 2bi
|
[ drop create-db-triggers ] 2bi
|
||||||
] query-make ;
|
] query-make ;
|
||||||
|
|
||||||
M: sqlite-db-connection drop-sql-statement ( class -- statements )
|
M: sqlite-db-connection drop-sql-statement ( class -- statements )
|
||||||
[
|
[ nip "drop table " 0% 0% ";" 0% ] query-make ;
|
||||||
[ nip "drop table " 0% 0% ";" 0% ]
|
|
||||||
[ drop \ drop-sqlite-triggers db-triggers ] 2bi
|
|
||||||
] query-make ;
|
|
||||||
|
|
||||||
M: sqlite-db-connection compound ( string seq -- new-string )
|
M: sqlite-db-connection compound ( string seq -- new-string )
|
||||||
over {
|
over {
|
||||||
|
@ -388,3 +348,9 @@ M: sqlite-db-connection compound ( string seq -- new-string )
|
||||||
{ "references" [ >reference-string ] }
|
{ "references" [ >reference-string ] }
|
||||||
[ 2drop ]
|
[ 2drop ]
|
||||||
} case ;
|
} case ;
|
||||||
|
|
||||||
|
M: sqlite-db-connection parse-db-error
|
||||||
|
dup n>> {
|
||||||
|
{ 1 [ string>> parse-sqlite-sql-error ] }
|
||||||
|
[ drop ]
|
||||||
|
} case ;
|
||||||
|
|
|
@ -2,9 +2,42 @@
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: concurrency.combinators db.pools db.sqlite db.tuples
|
USING: concurrency.combinators db.pools db.sqlite db.tuples
|
||||||
db.types kernel math random threads tools.test db sequences
|
db.types kernel math random threads tools.test db sequences
|
||||||
io prettyprint ;
|
io prettyprint db.postgresql db.sqlite accessors io.files.temp
|
||||||
|
namespaces fry system ;
|
||||||
IN: db.tester
|
IN: db.tester
|
||||||
|
|
||||||
|
: postgresql-test-db ( -- postgresql-db )
|
||||||
|
<postgresql-db>
|
||||||
|
"localhost" >>host
|
||||||
|
"postgres" >>username
|
||||||
|
"thepasswordistrust" >>password
|
||||||
|
"factor-test" >>database ;
|
||||||
|
|
||||||
|
: sqlite-test-db ( -- sqlite-db )
|
||||||
|
"tuples-test.db" temp-file <sqlite-db> ;
|
||||||
|
|
||||||
|
|
||||||
|
! These words leak resources, but are useful for interactivel testing
|
||||||
|
: set-sqlite-db ( -- )
|
||||||
|
sqlite-db db-open db-connection set ;
|
||||||
|
|
||||||
|
: set-postgresql-db ( -- )
|
||||||
|
postgresql-db db-open db-connection set ;
|
||||||
|
|
||||||
|
|
||||||
|
: test-sqlite ( quot -- )
|
||||||
|
'[
|
||||||
|
[ ] [ sqlite-test-db _ with-db ] unit-test
|
||||||
|
] call ; inline
|
||||||
|
|
||||||
|
: test-postgresql ( quot -- )
|
||||||
|
'[
|
||||||
|
os windows? cpu x86.64? and [
|
||||||
|
[ ] [ postgresql-test-db _ with-db ] unit-test
|
||||||
|
] unless
|
||||||
|
] call ; inline
|
||||||
|
|
||||||
|
|
||||||
TUPLE: test-1 id a b c ;
|
TUPLE: test-1 id a b c ;
|
||||||
|
|
||||||
test-1 "TEST1" {
|
test-1 "TEST1" {
|
||||||
|
@ -23,9 +56,6 @@ test-2 "TEST2" {
|
||||||
{ "z" "Z" { VARCHAR 256 } +not-null+ }
|
{ "z" "Z" { VARCHAR 256 } +not-null+ }
|
||||||
} define-persistent
|
} define-persistent
|
||||||
|
|
||||||
: sqlite-test-db ( -- db ) "test.db" <sqlite-db> ;
|
|
||||||
: test-db ( -- db ) "test.db" <sqlite-db> ;
|
|
||||||
|
|
||||||
: db-tester ( test-db -- )
|
: db-tester ( test-db -- )
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
|
|
|
@ -4,40 +4,10 @@ USING: io.files io.files.temp kernel tools.test db db.tuples classes
|
||||||
db.types continuations namespaces math math.ranges
|
db.types continuations namespaces math math.ranges
|
||||||
prettyprint calendar sequences db.sqlite math.intervals
|
prettyprint calendar sequences db.sqlite math.intervals
|
||||||
db.postgresql accessors random math.bitwise system
|
db.postgresql accessors random math.bitwise system
|
||||||
math.ranges strings urls fry db.tuples.private db.private ;
|
math.ranges strings urls fry db.tuples.private db.private
|
||||||
|
db.tester ;
|
||||||
IN: db.tuples.tests
|
IN: db.tuples.tests
|
||||||
|
|
||||||
: sqlite-db ( -- sqlite-db )
|
|
||||||
"tuples-test.db" temp-file <sqlite-db> ;
|
|
||||||
|
|
||||||
: test-sqlite ( quot -- )
|
|
||||||
'[
|
|
||||||
[ ] [
|
|
||||||
"tuples-test.db" temp-file <sqlite-db> _ with-db
|
|
||||||
] unit-test
|
|
||||||
] call ; inline
|
|
||||||
|
|
||||||
: postgresql-db ( -- postgresql-db )
|
|
||||||
<postgresql-db>
|
|
||||||
"localhost" >>host
|
|
||||||
"postgres" >>username
|
|
||||||
"thepasswordistrust" >>password
|
|
||||||
"factor-test" >>database ;
|
|
||||||
|
|
||||||
: test-postgresql ( quot -- )
|
|
||||||
'[
|
|
||||||
os windows? cpu x86.64? and [
|
|
||||||
[ ] [ postgresql-db _ with-db ] unit-test
|
|
||||||
] unless
|
|
||||||
] call ; inline
|
|
||||||
|
|
||||||
! These words leak resources, but are useful for interactivel testing
|
|
||||||
: sqlite-test-db ( -- )
|
|
||||||
sqlite-db db-open db-connection set ;
|
|
||||||
|
|
||||||
: postgresql-test-db ( -- )
|
|
||||||
postgresql-db db-open db-connection set ;
|
|
||||||
|
|
||||||
TUPLE: person the-id the-name the-number the-real
|
TUPLE: person the-id the-name the-number the-real
|
||||||
ts date time blob factor-blob url ;
|
ts date time blob factor-blob url ;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ USING: arrays assocs classes db kernel namespaces
|
||||||
classes.tuple words sequences slots math accessors
|
classes.tuple words sequences slots math accessors
|
||||||
math.parser io prettyprint db.types continuations
|
math.parser io prettyprint db.types continuations
|
||||||
destructors mirrors sets db.types db.private fry
|
destructors mirrors sets db.types db.private fry
|
||||||
combinators.short-circuit ;
|
combinators.short-circuit db.errors ;
|
||||||
IN: db.tuples
|
IN: db.tuples
|
||||||
|
|
||||||
HOOK: create-sql-statement db-connection ( class -- object )
|
HOOK: create-sql-statement db-connection ( class -- object )
|
||||||
|
@ -118,13 +118,15 @@ ERROR: no-defined-persistent object ;
|
||||||
ensure-defined-persistent
|
ensure-defined-persistent
|
||||||
[
|
[
|
||||||
'[
|
'[
|
||||||
_ drop-sql-statement [ execute-statement ] with-disposals
|
[
|
||||||
] ignore-errors
|
_ drop-sql-statement [ execute-statement ] with-disposals
|
||||||
|
] ignore-table-missing
|
||||||
|
] ignore-function-missing
|
||||||
] [ create-table ] bi ;
|
] [ create-table ] bi ;
|
||||||
|
|
||||||
: ensure-table ( class -- )
|
: ensure-table ( class -- )
|
||||||
ensure-defined-persistent
|
ensure-defined-persistent
|
||||||
'[ _ create-table ] ignore-errors ;
|
'[ [ _ create-table ] ignore-table-exists ] ignore-function-exists ;
|
||||||
|
|
||||||
: ensure-tables ( classes -- ) [ ensure-table ] each ;
|
: ensure-tables ( classes -- ) [ ensure-table ] each ;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
USING: definitions io.launcher kernel parser words sequences math
|
USING: definitions io.launcher kernel parser words sequences math
|
||||||
math.parser namespaces editors make system ;
|
math.parser namespaces editors make system combinators.short-circuit
|
||||||
|
fry threads ;
|
||||||
IN: editors.emacs
|
IN: editors.emacs
|
||||||
|
|
||||||
|
SYMBOL: emacsclient-path
|
||||||
|
|
||||||
|
HOOK: default-emacsclient os ( -- path )
|
||||||
|
|
||||||
|
M: object default-emacsclient ( -- path ) "emacsclient" ;
|
||||||
|
|
||||||
: emacsclient ( file line -- )
|
: emacsclient ( file line -- )
|
||||||
[
|
[
|
||||||
\ emacsclient get "emacsclient" or ,
|
{ [ \ emacsclient-path get ] [ default-emacsclient ] } 0|| ,
|
||||||
os windows? [ "--no-wait" , ] unless
|
"--no-wait" ,
|
||||||
"+" swap number>string append ,
|
number>string "+" prepend ,
|
||||||
,
|
,
|
||||||
] { } make try-process ;
|
] { } make
|
||||||
|
os windows? [ run-detached drop ] [ try-process ] if ;
|
||||||
|
|
||||||
: emacs ( word -- )
|
: emacs ( word -- )
|
||||||
where first2 emacsclient ;
|
where first2 emacsclient ;
|
||||||
|
|
||||||
[ emacsclient ] edit-hook set-global
|
[ emacsclient ] edit-hook set-global
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -0,0 +1,12 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: editors.emacs io.directories.search.windows kernel sequences
|
||||||
|
system combinators.short-circuit ;
|
||||||
|
IN: editors.emacs.windows
|
||||||
|
|
||||||
|
M: windows default-emacsclient
|
||||||
|
{
|
||||||
|
[ "Emacs" t [ "emacsclientw.exe" tail? ] find-in-program-files ]
|
||||||
|
[ "Emacs" t [ "emacsclient.exe" tail? ] find-in-program-files ]
|
||||||
|
[ "emacsclient.exe" ]
|
||||||
|
} 0|| ;
|
|
@ -57,8 +57,14 @@ PRIVATE>
|
||||||
pusher [ [ f ] compose iterate-directory drop ] dip
|
pusher [ [ f ] compose iterate-directory drop ] dip
|
||||||
] [ drop f ] recover ; inline
|
] [ drop f ] recover ; inline
|
||||||
|
|
||||||
|
ERROR: file-not-found ;
|
||||||
|
|
||||||
: find-in-directories ( directories bfs? quot: ( obj -- ? ) -- path'/f )
|
: find-in-directories ( directories bfs? quot: ( obj -- ? ) -- path'/f )
|
||||||
'[ _ _ find-file ] attempt-all ;
|
[
|
||||||
|
'[ _ _ find-file [ file-not-found ] unless* ] attempt-all
|
||||||
|
] [
|
||||||
|
drop f
|
||||||
|
] recover ;
|
||||||
|
|
||||||
: find-all-in-directories ( directories bfs? quot: ( obj -- ? ) -- paths/f )
|
: find-all-in-directories ( directories bfs? quot: ( obj -- ? ) -- paths/f )
|
||||||
'[ _ _ find-all-files ] map concat ;
|
'[ _ _ find-all-files ] map concat ;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Daniel Ehrenberg
|
|
@ -0,0 +1,26 @@
|
||||||
|
! Copyright (C) 2009 Daniel Ehrenberg
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: help.syntax help.markup math ;
|
||||||
|
IN: math.bits
|
||||||
|
|
||||||
|
ABOUT: "math.bits"
|
||||||
|
|
||||||
|
ARTICLE: "math.bits" "Number bits virtual sequence"
|
||||||
|
{ $subsection bits }
|
||||||
|
{ $subsection <bits> }
|
||||||
|
{ $subsection make-bits } ;
|
||||||
|
|
||||||
|
HELP: bits
|
||||||
|
{ $class-description "Virtual sequence class of bits of a number. The first bit is the least significant bit. This can be constructed with " { $link <bits> } " or " { $link make-bits } "." } ;
|
||||||
|
|
||||||
|
HELP: <bits>
|
||||||
|
{ $values { "number" integer } { "length" integer } { "bits" bits } }
|
||||||
|
{ $description "Creates a virtual sequence of bits of a number in little endian order, with the given length." } ;
|
||||||
|
|
||||||
|
HELP: make-bits
|
||||||
|
{ $values { "number" integer } { "bits" bits } }
|
||||||
|
{ $description "Creates a " { $link bits } " object out of the given number, using its log base 2 as the length. This implies that the last element, corresponding to the most significant bit, will be 1." }
|
||||||
|
{ $examples
|
||||||
|
{ $example "USING: math.bits prettyprint arrays ;" "BIN: 1101 make-bits >array ." "{ t f t t }" }
|
||||||
|
{ $example "USING: math.bits prettyprint arrays ;" "-3 make-bits >array ." "{ t f }" }
|
||||||
|
} ;
|
|
@ -0,0 +1,16 @@
|
||||||
|
! Copyright (C) 2009 Daniel Ehrenberg
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: tools.test math.bits sequences arrays ;
|
||||||
|
IN: math.bits.tests
|
||||||
|
|
||||||
|
[ t ] [ BIN: 111111 3 <bits> second ] unit-test
|
||||||
|
[ { t t t } ] [ BIN: 111111 3 <bits> >array ] unit-test
|
||||||
|
[ f ] [ BIN: 111101 3 <bits> second ] unit-test
|
||||||
|
[ { f f t } ] [ BIN: 111100 3 <bits> >array ] unit-test
|
||||||
|
[ 3 ] [ BIN: 111111 3 <bits> length ] unit-test
|
||||||
|
[ 6 ] [ BIN: 111111 make-bits length ] unit-test
|
||||||
|
[ 0 ] [ 0 make-bits length ] unit-test
|
||||||
|
[ 2 ] [ 3 make-bits length ] unit-test
|
||||||
|
[ 2 ] [ -3 make-bits length ] unit-test
|
||||||
|
[ 1 ] [ 1 make-bits length ] unit-test
|
||||||
|
[ 1 ] [ -1 make-bits length ] unit-test
|
|
@ -0,0 +1,16 @@
|
||||||
|
! Copyright (C) 2009 Daniel Ehrenberg
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: sequences kernel math accessors sequences.private ;
|
||||||
|
IN: math.bits
|
||||||
|
|
||||||
|
TUPLE: bits { number read-only } { length read-only } ;
|
||||||
|
C: <bits> bits
|
||||||
|
|
||||||
|
: make-bits ( number -- bits )
|
||||||
|
dup zero? [ drop T{ bits f 0 0 } ] [ dup abs log2 1+ <bits> ] if ; inline
|
||||||
|
|
||||||
|
M: bits length length>> ;
|
||||||
|
|
||||||
|
M: bits nth-unsafe number>> swap bit? ;
|
||||||
|
|
||||||
|
INSTANCE: bits immutable-sequence
|
|
@ -0,0 +1 @@
|
||||||
|
Virtual sequence for bits of an integer
|
|
@ -1,6 +1,6 @@
|
||||||
! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman.
|
! Copyright (C) 2007, 2008 Slava Pestov, Doug Coleman.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: arrays kernel math math.functions sequences
|
USING: arrays kernel math sequences accessors math.bits
|
||||||
sequences.private words namespaces macros hints
|
sequences.private words namespaces macros hints
|
||||||
combinators fry io.binary combinators.smart ;
|
combinators fry io.binary combinators.smart ;
|
||||||
IN: math.bitwise
|
IN: math.bitwise
|
||||||
|
@ -65,7 +65,7 @@ DEFER: byte-bit-count
|
||||||
|
|
||||||
\ byte-bit-count
|
\ byte-bit-count
|
||||||
256 [
|
256 [
|
||||||
0 swap [ [ 1+ ] when ] each-bit
|
8 <bits> 0 [ [ 1+ ] when ] reduce
|
||||||
] B{ } map-as '[ HEX: ff bitand _ nth-unsafe ]
|
] B{ } map-as '[ HEX: ff bitand _ nth-unsafe ]
|
||||||
(( byte -- table )) define-declared
|
(( byte -- table )) define-declared
|
||||||
|
|
||||||
|
|
|
@ -278,14 +278,6 @@ HELP: mod-inv
|
||||||
{ $example "USING: math prettyprint ;" "173 815 * 1119 mod ." "1" }
|
{ $example "USING: math prettyprint ;" "173 815 * 1119 mod ." "1" }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
HELP: each-bit
|
|
||||||
{ $values { "n" integer } { "quot" { $quotation "( ? -- )" } } }
|
|
||||||
{ $description "Applies the quotation to each bit of the integer, starting from the least significant bit, and stopping at the last bit from which point on all bits are either clear (if the integer is positive) or all bits are set (if the integer is negataive)." }
|
|
||||||
{ $examples
|
|
||||||
{ $example "USING: math.functions make prettyprint ;" "[ BIN: 1101 [ , ] each-bit ] { } make ." "{ t f t t }" }
|
|
||||||
{ $example "USING: math.functions make prettyprint ;" "[ -3 [ , ] each-bit ] { } make ." "{ t f }" }
|
|
||||||
} ;
|
|
||||||
|
|
||||||
HELP: ~
|
HELP: ~
|
||||||
{ $values { "x" real } { "y" real } { "epsilon" real } { "?" "a boolean" } }
|
{ $values { "x" real } { "y" real } { "epsilon" real } { "?" "a boolean" } }
|
||||||
{ $description "Tests if " { $snippet "x" } " and " { $snippet "y" } " are approximately equal to each other. There are three possible comparison tests, chosen based on the sign of " { $snippet "epsilon" } ":"
|
{ $description "Tests if " { $snippet "x" } " and " { $snippet "y" } " are approximately equal to each other. There are three possible comparison tests, chosen based on the sign of " { $snippet "epsilon" } ":"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
! Copyright (C) 2004, 2008 Slava Pestov.
|
! Copyright (C) 2004, 2008 Slava Pestov.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: math kernel math.constants math.private
|
USING: math kernel math.constants math.private math.bits
|
||||||
math.libm combinators math.order sequences ;
|
math.libm combinators math.order sequences ;
|
||||||
IN: math.functions
|
IN: math.functions
|
||||||
|
|
||||||
|
@ -26,16 +26,6 @@ GENERIC: sqrt ( x -- y ) foldable
|
||||||
M: real sqrt
|
M: real sqrt
|
||||||
>float dup 0.0 < [ neg fsqrt 0.0 swap rect> ] [ fsqrt ] if ;
|
>float dup 0.0 < [ neg fsqrt 0.0 swap rect> ] [ fsqrt ] if ;
|
||||||
|
|
||||||
: each-bit ( n quot: ( ? -- ) -- )
|
|
||||||
over [ 0 = ] [ -1 = ] bi or [
|
|
||||||
2drop
|
|
||||||
] [
|
|
||||||
2dup { [ odd? ] [ call ] [ 2/ ] [ each-bit ] } spread
|
|
||||||
] if ; inline recursive
|
|
||||||
|
|
||||||
: map-bits ( n quot: ( ? -- obj ) -- seq )
|
|
||||||
accumulator [ each-bit ] dip ; inline
|
|
||||||
|
|
||||||
: factor-2s ( n -- r s )
|
: factor-2s ( n -- r s )
|
||||||
#! factor an integer into 2^r * s
|
#! factor an integer into 2^r * s
|
||||||
dup 0 = [ 1 ] [
|
dup 0 = [ 1 ] [
|
||||||
|
@ -47,7 +37,7 @@ M: real sqrt
|
||||||
GENERIC# ^n 1 ( z w -- z^w )
|
GENERIC# ^n 1 ( z w -- z^w )
|
||||||
|
|
||||||
: (^n) ( z w -- z^w )
|
: (^n) ( z w -- z^w )
|
||||||
1 swap [ [ dupd * ] when [ sq ] dip ] each-bit nip ; inline
|
make-bits 1 [ [ dupd * ] when [ sq ] dip ] reduce nip ; inline
|
||||||
|
|
||||||
M: integer ^n
|
M: integer ^n
|
||||||
[ factor-2s ] dip [ (^n) ] keep rot * shift ;
|
[ factor-2s ] dip [ (^n) ] keep rot * shift ;
|
||||||
|
@ -94,9 +84,9 @@ PRIVATE>
|
||||||
dup zero? [ drop 0./0. ] [ 0 < 1./0. 0 ? ] if ; inline
|
dup zero? [ drop 0./0. ] [ 0 < 1./0. 0 ? ] if ; inline
|
||||||
|
|
||||||
: (^mod) ( n x y -- z )
|
: (^mod) ( n x y -- z )
|
||||||
1 swap [
|
make-bits 1 [
|
||||||
[ dupd * pick mod ] when [ sq over mod ] dip
|
[ dupd * pick mod ] when [ sq over mod ] dip
|
||||||
] each-bit 2nip ; inline
|
] reduce 2nip ; inline
|
||||||
|
|
||||||
: (gcd) ( b a x y -- a d )
|
: (gcd) ( b a x y -- a d )
|
||||||
over zero? [
|
over zero? [
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
USING: multiline kernel sequences io splitting fry namespaces
|
USING: multiline kernel sequences io splitting fry namespaces
|
||||||
http.parsers hashtables assocs combinators ascii io.files.unique
|
http.parsers hashtables assocs combinators ascii io.files.unique
|
||||||
accessors io.encodings.binary io.files byte-arrays math
|
accessors io.encodings.binary io.files byte-arrays math
|
||||||
io.streams.string combinators.short-circuit strings math.order ;
|
io.streams.string combinators.short-circuit strings math.order
|
||||||
|
quoting ;
|
||||||
IN: mime.multipart
|
IN: mime.multipart
|
||||||
|
|
||||||
CONSTANT: buffer-size 65536
|
CONSTANT: buffer-size 65536
|
||||||
|
@ -75,18 +76,6 @@ ERROR: end-of-stream multipart ;
|
||||||
: empty-name? ( string -- ? )
|
: empty-name? ( string -- ? )
|
||||||
{ "''" "\"\"" "" f } member? ;
|
{ "''" "\"\"" "" f } member? ;
|
||||||
|
|
||||||
: quote? ( ch -- ? ) "'\"" member? ;
|
|
||||||
|
|
||||||
: quoted? ( str -- ? )
|
|
||||||
{
|
|
||||||
[ length 1 > ]
|
|
||||||
[ first quote? ]
|
|
||||||
[ [ first ] [ peek ] bi = ]
|
|
||||||
} 1&& ;
|
|
||||||
|
|
||||||
: unquote ( str -- newstr )
|
|
||||||
dup quoted? [ but-last-slice rest-slice >string ] when ;
|
|
||||||
|
|
||||||
: save-uploaded-file ( multipart -- )
|
: save-uploaded-file ( multipart -- )
|
||||||
dup filename>> empty-name? [
|
dup filename>> empty-name? [
|
||||||
drop
|
drop
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -0,0 +1,32 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: help.markup help.syntax strings ;
|
||||||
|
IN: quoting
|
||||||
|
|
||||||
|
HELP: quote?
|
||||||
|
{ $values
|
||||||
|
{ "ch" "a character" }
|
||||||
|
{ "?" "a boolean" }
|
||||||
|
}
|
||||||
|
{ $description "Returns true if the character is a single or double quote." } ;
|
||||||
|
|
||||||
|
HELP: quoted?
|
||||||
|
{ $values
|
||||||
|
{ "str" string }
|
||||||
|
{ "?" "a boolean" }
|
||||||
|
}
|
||||||
|
{ $description "Returns true if a string is surrounded by matching single or double quotes as the first and last characters." } ;
|
||||||
|
|
||||||
|
HELP: unquote
|
||||||
|
{ $values
|
||||||
|
{ "str" string }
|
||||||
|
{ "newstr" string }
|
||||||
|
}
|
||||||
|
{ $description "Removes a pair of matching single or double quotes from a string." } ;
|
||||||
|
|
||||||
|
ARTICLE: "quoting" "Quotation marks"
|
||||||
|
"The " { $vocab-link "quoting" } " vocabulary is for removing quotes from a string." $nl
|
||||||
|
"Removing quotes:"
|
||||||
|
{ $subsection unquote } ;
|
||||||
|
|
||||||
|
ABOUT: "quoting"
|
|
@ -0,0 +1,10 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: tools.test quoting ;
|
||||||
|
IN: quoting.tests
|
||||||
|
|
||||||
|
|
||||||
|
[ "abc" ] [ "'abc'" unquote ] unit-test
|
||||||
|
[ "abc" ] [ "\"abc\"" unquote ] unit-test
|
||||||
|
[ "'abc" ] [ "'abc" unquote ] unit-test
|
||||||
|
[ "abc'" ] [ "abc'" unquote ] unit-test
|
|
@ -0,0 +1,16 @@
|
||||||
|
! Copyright (C) 2009 Doug Coleman.
|
||||||
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
|
USING: combinators.short-circuit kernel math sequences strings ;
|
||||||
|
IN: quoting
|
||||||
|
|
||||||
|
: quote? ( ch -- ? ) "'\"" member? ;
|
||||||
|
|
||||||
|
: quoted? ( str -- ? )
|
||||||
|
{
|
||||||
|
[ length 1 > ]
|
||||||
|
[ first quote? ]
|
||||||
|
[ [ first ] [ peek ] bi = ]
|
||||||
|
} 1&& ;
|
||||||
|
|
||||||
|
: unquote ( str -- newstr )
|
||||||
|
dup quoted? [ but-last-slice rest-slice >string ] when ;
|
|
@ -1,6 +1,6 @@
|
||||||
! Copyright (C) 2008 Doug Coleman.
|
! Copyright (C) 2008 Doug Coleman.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: help.markup help.syntax kernel strings words ;
|
USING: help.markup help.syntax kernel strings words vocabs ;
|
||||||
IN: tools.scaffold
|
IN: tools.scaffold
|
||||||
|
|
||||||
HELP: developer-name
|
HELP: developer-name
|
||||||
|
@ -13,7 +13,7 @@ HELP: help.
|
||||||
{ $description "Prints out scaffold help markup for a given word." } ;
|
{ $description "Prints out scaffold help markup for a given word." } ;
|
||||||
|
|
||||||
HELP: scaffold-help
|
HELP: scaffold-help
|
||||||
{ $values { "string" string } }
|
{ $values { "vocab" vocab } }
|
||||||
{ $description "Takes an existing vocabulary and creates a help file with scaffolded help for each word. This word only works if no help file yet exists." } ;
|
{ $description "Takes an existing vocabulary and creates a help file with scaffolded help for each word. This word only works if no help file yet exists." } ;
|
||||||
|
|
||||||
HELP: scaffold-undocumented
|
HELP: scaffold-undocumented
|
||||||
|
@ -28,6 +28,21 @@ HELP: scaffold-vocab
|
||||||
{ "vocab-root" "a vocabulary root string" } { "string" string } }
|
{ "vocab-root" "a vocabulary root string" } { "string" string } }
|
||||||
{ $description "Creates a directory in the given root for a new vocabulary and adds a main .factor file, a tests file, and an authors.txt file." } ;
|
{ $description "Creates a directory in the given root for a new vocabulary and adds a main .factor file, a tests file, and an authors.txt file." } ;
|
||||||
|
|
||||||
|
HELP: scaffold-emacs
|
||||||
|
{ $description "Touches the .emacs file in your home directory and provides a clickable link to open it in an editor." } ;
|
||||||
|
|
||||||
|
HELP: scaffold-factor-boot-rc
|
||||||
|
{ $description "Touches the .factor-boot-rc file in your home directory and provides a clickable link to open it in an editor." } ;
|
||||||
|
|
||||||
|
HELP: scaffold-factor-rc
|
||||||
|
{ $description "Touches the .factor-rc file in your home directory and provides a clickable link to open it in an editor." } ;
|
||||||
|
|
||||||
|
HELP: scaffold-rc
|
||||||
|
{ $values
|
||||||
|
{ "path" "a pathname string" }
|
||||||
|
}
|
||||||
|
{ $description "Touches the given path in your home directory and provides a clickable link to open it in an editor." } ;
|
||||||
|
|
||||||
HELP: using
|
HELP: using
|
||||||
{ $description "Stores the vocabularies that are pulled into the documentation file from looking up the stack effect types." } ;
|
{ $description "Stores the vocabularies that are pulled into the documentation file from looking up the stack effect types." } ;
|
||||||
|
|
||||||
|
@ -40,7 +55,12 @@ ARTICLE: "tools.scaffold" "Scaffold tool"
|
||||||
{ $subsection scaffold-help }
|
{ $subsection scaffold-help }
|
||||||
{ $subsection scaffold-undocumented }
|
{ $subsection scaffold-undocumented }
|
||||||
{ $subsection help. }
|
{ $subsection help. }
|
||||||
"Types that are unrecognized by the scaffold generator will be of type " { $link null } ". The developer should change these to strings that describe the stack effect names instead."
|
"Types that are unrecognized by the scaffold generator will be of type " { $link null } ". The developer should change these to strings that describe the stack effect names instead." $nl
|
||||||
|
"Scaffolding a configuration file:"
|
||||||
|
{ $subsection scaffold-rc }
|
||||||
|
{ $subsection scaffold-factor-boot-rc }
|
||||||
|
{ $subsection scaffold-factor-rc }
|
||||||
|
{ $subsection scaffold-emacs }
|
||||||
;
|
;
|
||||||
|
|
||||||
ABOUT: "tools.scaffold"
|
ABOUT: "tools.scaffold"
|
||||||
|
|
|
@ -5,7 +5,7 @@ io.encodings.utf8 hashtables kernel namespaces sequences
|
||||||
vocabs.loader io combinators calendar accessors math.parser
|
vocabs.loader io combinators calendar accessors math.parser
|
||||||
io.streams.string ui.tools.operations quotations strings arrays
|
io.streams.string ui.tools.operations quotations strings arrays
|
||||||
prettyprint words vocabs sorting sets classes math alien urls
|
prettyprint words vocabs sorting sets classes math alien urls
|
||||||
splitting ascii ;
|
splitting ascii combinators.short-circuit ;
|
||||||
IN: tools.scaffold
|
IN: tools.scaffold
|
||||||
|
|
||||||
SYMBOL: developer-name
|
SYMBOL: developer-name
|
||||||
|
@ -18,37 +18,61 @@ ERROR: no-vocab vocab ;
|
||||||
|
|
||||||
<PRIVATE
|
<PRIVATE
|
||||||
|
|
||||||
: root? ( string -- ? ) vocab-roots get member? ;
|
: vocab-root? ( string -- ? ) vocab-roots get member? ;
|
||||||
|
|
||||||
: contains-dot? ( string -- ? ) ".." swap subseq? ;
|
: contains-dot? ( string -- ? ) ".." swap subseq? ;
|
||||||
|
|
||||||
: contains-separator? ( string -- ? ) [ path-separator? ] any? ;
|
: contains-separator? ( string -- ? ) [ path-separator? ] any? ;
|
||||||
|
|
||||||
: check-vocab-name ( string -- string )
|
: check-vocab-name ( string -- string )
|
||||||
dup contains-dot? [ vocab-name-contains-dot ] when
|
[ ]
|
||||||
dup contains-separator? [ vocab-name-contains-separator ] when ;
|
[ contains-dot? [ vocab-name-contains-dot ] when ]
|
||||||
|
[ contains-separator? [ vocab-name-contains-separator ] when ] tri ;
|
||||||
|
|
||||||
: check-root ( string -- string )
|
: check-root ( string -- string )
|
||||||
dup root? [ not-a-vocab-root ] unless ;
|
dup vocab-root? [ not-a-vocab-root ] unless ;
|
||||||
|
|
||||||
|
: check-vocab ( vocab -- vocab )
|
||||||
|
dup find-vocab-root [ no-vocab ] unless ;
|
||||||
|
|
||||||
|
: check-vocab-root/vocab ( vocab-root string -- vocab-root string )
|
||||||
|
[ check-root ] [ check-vocab-name ] bi* ;
|
||||||
|
|
||||||
|
: replace-vocab-separators ( vocab -- path )
|
||||||
|
path-separator first CHAR: . associate substitute ; inline
|
||||||
|
|
||||||
|
: vocab-root/vocab>path ( vocab-root vocab -- path )
|
||||||
|
check-vocab-root/vocab
|
||||||
|
[ ] [ replace-vocab-separators ] bi* append-path ;
|
||||||
|
|
||||||
|
: vocab>path ( vocab -- path )
|
||||||
|
check-vocab
|
||||||
|
[ find-vocab-root ] keep vocab-root/vocab>path ;
|
||||||
|
|
||||||
|
: vocab-root/vocab/file>path ( vocab-root vocab file -- path )
|
||||||
|
[ vocab-root/vocab>path ] dip append-path ;
|
||||||
|
|
||||||
|
: vocab-root/vocab/suffix>path ( vocab-root vocab suffix -- path )
|
||||||
|
[ vocab-root/vocab>path dup file-name append-path ] dip append ;
|
||||||
|
|
||||||
|
: vocab/suffix>path ( vocab suffix -- path )
|
||||||
|
[ vocab>path dup file-name append-path ] dip append ;
|
||||||
|
|
||||||
: directory-exists ( path -- )
|
: directory-exists ( path -- )
|
||||||
"Not creating a directory, it already exists: " write print ;
|
"Not creating a directory, it already exists: " write print ;
|
||||||
|
|
||||||
: scaffold-directory ( path -- )
|
: scaffold-directory ( vocab-root vocab -- )
|
||||||
|
vocab-root/vocab>path
|
||||||
dup exists? [ directory-exists ] [ make-directories ] if ;
|
dup exists? [ directory-exists ] [ make-directories ] if ;
|
||||||
|
|
||||||
: not-scaffolding ( path -- )
|
: not-scaffolding ( path -- path )
|
||||||
"Not creating scaffolding for " write <pathname> . ;
|
"Not creating scaffolding for " write dup <pathname> . ;
|
||||||
|
|
||||||
: scaffolding ( path -- )
|
: scaffolding ( path -- path )
|
||||||
"Creating scaffolding for " write <pathname> . ;
|
"Creating scaffolding for " write dup <pathname> . ;
|
||||||
|
|
||||||
: (scaffold-path) ( path string -- path )
|
: scaffolding? ( path -- path ? )
|
||||||
dupd [ file-name ] dip append append-path ;
|
dup exists? [ not-scaffolding f ] [ scaffolding t ] if ;
|
||||||
|
|
||||||
: scaffold-path ( path string -- path ? )
|
|
||||||
(scaffold-path)
|
|
||||||
dup exists? [ dup not-scaffolding f ] [ dup scaffolding t ] if ;
|
|
||||||
|
|
||||||
: scaffold-copyright ( -- )
|
: scaffold-copyright ( -- )
|
||||||
"! Copyright (C) " write now year>> number>string write
|
"! Copyright (C) " write now year>> number>string write
|
||||||
|
@ -62,37 +86,25 @@ ERROR: no-vocab vocab ;
|
||||||
"IN: " write print
|
"IN: " write print
|
||||||
] with-string-writer ;
|
] with-string-writer ;
|
||||||
|
|
||||||
: set-scaffold-main-file ( path vocab -- )
|
: set-scaffold-main-file ( vocab path -- )
|
||||||
main-file-string swap utf8 set-file-contents ;
|
[ main-file-string ] dip utf8 set-file-contents ;
|
||||||
|
|
||||||
: scaffold-main ( path vocab -- )
|
: scaffold-main ( vocab-root vocab -- )
|
||||||
[ ".factor" scaffold-path ] dip
|
tuck ".factor" vocab-root/vocab/suffix>path scaffolding? [
|
||||||
swap [ set-scaffold-main-file ] [ 2drop ] if ;
|
set-scaffold-main-file
|
||||||
|
|
||||||
: tests-file-string ( vocab -- string )
|
|
||||||
[
|
|
||||||
scaffold-copyright
|
|
||||||
"USING: tools.test " write dup write " ;" print
|
|
||||||
"IN: " write write ".tests" print
|
|
||||||
] with-string-writer ;
|
|
||||||
|
|
||||||
: set-scaffold-tests-file ( path vocab -- )
|
|
||||||
tests-file-string swap utf8 set-file-contents ;
|
|
||||||
|
|
||||||
: scaffold-tests ( path vocab -- )
|
|
||||||
[ "-tests.factor" scaffold-path ] dip
|
|
||||||
swap [ set-scaffold-tests-file ] [ 2drop ] if ;
|
|
||||||
|
|
||||||
: scaffold-authors ( path -- )
|
|
||||||
"authors.txt" append-path dup exists? [
|
|
||||||
not-scaffolding
|
|
||||||
] [
|
] [
|
||||||
dup scaffolding
|
2drop
|
||||||
developer-name get swap utf8 set-file-contents
|
] if ;
|
||||||
|
|
||||||
|
: scaffold-authors ( vocab-root vocab -- )
|
||||||
|
"authors.txt" vocab-root/vocab/file>path scaffolding? [
|
||||||
|
[ developer-name get ] dip utf8 set-file-contents
|
||||||
|
] [
|
||||||
|
drop
|
||||||
] if ;
|
] if ;
|
||||||
|
|
||||||
: lookup-type ( string -- object/string ? )
|
: lookup-type ( string -- object/string ? )
|
||||||
"new" ?head drop [ [ CHAR: ' = ] [ digit? ] bi or ] trim-tail
|
"new" ?head drop [ { [ CHAR: ' = ] [ digit? ] } 1|| ] trim-tail
|
||||||
H{
|
H{
|
||||||
{ "object" object } { "obj" object }
|
{ "object" object } { "obj" object }
|
||||||
{ "quot" quotation }
|
{ "quot" quotation }
|
||||||
|
@ -134,6 +146,9 @@ ERROR: no-vocab vocab ;
|
||||||
" }" write
|
" }" write
|
||||||
] each ;
|
] each ;
|
||||||
|
|
||||||
|
: 4bl ( -- )
|
||||||
|
" " write ; inline
|
||||||
|
|
||||||
: $values. ( word -- )
|
: $values. ( word -- )
|
||||||
"declared-effect" word-prop [
|
"declared-effect" word-prop [
|
||||||
[ in>> ] [ out>> ] bi
|
[ in>> ] [ out>> ] bi
|
||||||
|
@ -141,8 +156,8 @@ ERROR: no-vocab vocab ;
|
||||||
2drop
|
2drop
|
||||||
] [
|
] [
|
||||||
"{ $values" print
|
"{ $values" print
|
||||||
[ " " write ($values.) ]
|
[ 4bl ($values.) ]
|
||||||
[ [ nl " " write ($values.) ] unless-empty ] bi*
|
[ [ nl 4bl ($values.) ] unless-empty ] bi*
|
||||||
nl "}" print
|
nl "}" print
|
||||||
] if
|
] if
|
||||||
] when* ;
|
] when* ;
|
||||||
|
@ -151,21 +166,21 @@ ERROR: no-vocab vocab ;
|
||||||
drop
|
drop
|
||||||
"{ $description \"\" } ;" print ;
|
"{ $description \"\" } ;" print ;
|
||||||
|
|
||||||
: help-header. ( word -- )
|
: docs-header. ( word -- )
|
||||||
"HELP: " write name>> print ;
|
"HELP: " write name>> print ;
|
||||||
|
|
||||||
: (help.) ( word -- )
|
: (help.) ( word -- )
|
||||||
[ help-header. ] [ $values. ] [ $description. ] tri ;
|
[ docs-header. ] [ $values. ] [ $description. ] tri ;
|
||||||
|
|
||||||
: interesting-words ( vocab -- array )
|
: interesting-words ( vocab -- array )
|
||||||
words
|
words
|
||||||
[ [ "help" word-prop ] [ predicate? ] bi or not ] filter
|
[ { [ "help" word-prop ] [ predicate? ] } 1|| not ] filter
|
||||||
natural-sort ;
|
natural-sort ;
|
||||||
|
|
||||||
: interesting-words. ( vocab -- )
|
: interesting-words. ( vocab -- )
|
||||||
interesting-words [ (help.) nl ] each ;
|
interesting-words [ (help.) nl ] each ;
|
||||||
|
|
||||||
: help-file-string ( vocab -- str2 )
|
: docs-file-string ( vocab -- str2 )
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
[ "IN: " write print nl ]
|
[ "IN: " write print nl ]
|
||||||
|
@ -186,62 +201,68 @@ ERROR: no-vocab vocab ;
|
||||||
[ bl write ] each
|
[ bl write ] each
|
||||||
" ;" print ;
|
" ;" print ;
|
||||||
|
|
||||||
: set-scaffold-help-file ( path vocab -- )
|
: set-scaffold-docs-file ( vocab path -- )
|
||||||
swap utf8 <file-writer> [
|
utf8 <file-writer> [
|
||||||
scaffold-copyright
|
scaffold-copyright
|
||||||
[ help-file-string ] [ write-using ] bi
|
[ docs-file-string ] [ write-using ] bi
|
||||||
write
|
write
|
||||||
] with-output-stream ;
|
] with-output-stream ;
|
||||||
|
|
||||||
: check-scaffold ( vocab-root string -- vocab-root string )
|
|
||||||
[ check-root ] [ check-vocab-name ] bi* ;
|
|
||||||
|
|
||||||
: vocab>scaffold-path ( vocab-root string -- path )
|
|
||||||
path-separator first CHAR: . associate substitute
|
|
||||||
append-path ;
|
|
||||||
|
|
||||||
: prepare-scaffold ( vocab-root string -- string path )
|
|
||||||
check-scaffold [ vocab>scaffold-path ] keep ;
|
|
||||||
|
|
||||||
: with-scaffold ( quot -- )
|
: with-scaffold ( quot -- )
|
||||||
[ H{ } clone using ] dip with-variable ; inline
|
[ H{ } clone using ] dip with-variable ; inline
|
||||||
|
|
||||||
: check-vocab ( vocab -- vocab )
|
|
||||||
dup find-vocab-root [ no-vocab ] unless ;
|
|
||||||
|
|
||||||
PRIVATE>
|
|
||||||
|
|
||||||
: link-vocab ( vocab -- )
|
: link-vocab ( vocab -- )
|
||||||
check-vocab
|
check-vocab
|
||||||
"Edit documentation: " write
|
"Edit documentation: " write
|
||||||
[ find-vocab-root ]
|
"-docs.factor" vocab/suffix>path <pathname> . ;
|
||||||
[ vocab>scaffold-path ] bi
|
|
||||||
"-docs.factor" (scaffold-path) <pathname> . ;
|
PRIVATE>
|
||||||
|
|
||||||
: help. ( word -- )
|
: help. ( word -- )
|
||||||
[ (help.) ] [ nl vocabulary>> link-vocab ] bi ;
|
[ (help.) ] [ nl vocabulary>> link-vocab ] bi ;
|
||||||
|
|
||||||
: scaffold-help ( string -- )
|
: scaffold-help ( vocab -- )
|
||||||
[
|
[
|
||||||
[ find-vocab-root ] [ check-vocab ] bi
|
dup "-docs.factor" vocab/suffix>path scaffolding? [
|
||||||
prepare-scaffold
|
set-scaffold-docs-file
|
||||||
[ "-docs.factor" scaffold-path ] dip
|
] [
|
||||||
swap [ set-scaffold-help-file ] [ 2drop ] if
|
2drop
|
||||||
|
] if
|
||||||
] with-scaffold ;
|
] with-scaffold ;
|
||||||
|
|
||||||
: scaffold-undocumented ( string -- )
|
: scaffold-undocumented ( string -- )
|
||||||
[ interesting-words. ] [ link-vocab ] bi ;
|
[ interesting-words. ] [ link-vocab ] bi ;
|
||||||
|
|
||||||
: scaffold-vocab ( vocab-root string -- )
|
: scaffold-vocab ( vocab-root string -- )
|
||||||
prepare-scaffold
|
|
||||||
{
|
{
|
||||||
[ drop scaffold-directory ]
|
[ scaffold-directory ]
|
||||||
[ scaffold-main ]
|
[ scaffold-main ]
|
||||||
[ scaffold-tests ]
|
[ scaffold-authors ]
|
||||||
[ drop scaffold-authors ]
|
|
||||||
[ nip require ]
|
[ nip require ]
|
||||||
} 2cleave ;
|
} 2cleave ;
|
||||||
|
|
||||||
|
<PRIVATE
|
||||||
|
|
||||||
|
: tests-file-string ( vocab -- string )
|
||||||
|
[
|
||||||
|
scaffold-copyright
|
||||||
|
"USING: tools.test " write dup write " ;" print
|
||||||
|
"IN: " write write ".tests" print
|
||||||
|
] with-string-writer ;
|
||||||
|
|
||||||
|
: set-scaffold-tests-file ( vocab path -- )
|
||||||
|
[ tests-file-string ] dip utf8 set-file-contents ;
|
||||||
|
|
||||||
|
PRIVATE>
|
||||||
|
|
||||||
|
: scaffold-tests ( vocab -- )
|
||||||
|
dup "-tests.factor" vocab/suffix>path
|
||||||
|
scaffolding? [
|
||||||
|
set-scaffold-tests-file
|
||||||
|
] [
|
||||||
|
2drop
|
||||||
|
] if ;
|
||||||
|
|
||||||
SYMBOL: examples-flag
|
SYMBOL: examples-flag
|
||||||
|
|
||||||
: example ( -- )
|
: example ( -- )
|
||||||
|
@ -250,7 +271,7 @@ SYMBOL: examples-flag
|
||||||
" \"\""
|
" \"\""
|
||||||
" \"\""
|
" \"\""
|
||||||
"}"
|
"}"
|
||||||
} [ examples-flag get [ " " write ] when print ] each ;
|
} [ examples-flag get [ 4bl ] when print ] each ;
|
||||||
|
|
||||||
: examples ( n -- )
|
: examples ( n -- )
|
||||||
t \ examples-flag [
|
t \ examples-flag [
|
||||||
|
@ -260,10 +281,11 @@ SYMBOL: examples-flag
|
||||||
] with-variable ;
|
] with-variable ;
|
||||||
|
|
||||||
: scaffold-rc ( path -- )
|
: scaffold-rc ( path -- )
|
||||||
|
[ home ] dip append-path
|
||||||
[ touch-file ] [ "Click to edit: " write <pathname> . ] bi ;
|
[ touch-file ] [ "Click to edit: " write <pathname> . ] bi ;
|
||||||
|
|
||||||
: scaffold-factor-boot-rc ( -- )
|
: scaffold-factor-boot-rc ( -- ) ".factor-boot-rc" scaffold-rc ;
|
||||||
home ".factor-boot-rc" append-path scaffold-rc ;
|
|
||||||
|
|
||||||
: scaffold-factor-rc ( -- )
|
: scaffold-factor-rc ( -- ) ".factor-rc" scaffold-rc ;
|
||||||
home ".factor-rc" append-path scaffold-rc ;
|
|
||||||
|
: scaffold-emacs ( -- ) ".emacs" scaffold-rc ;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
! Copyright (C) 2008 Doug Coleman.
|
! Copyright (C) 2008 Doug Coleman.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: kernel base64 checksums.md5 sequences checksums
|
USING: kernel base64 checksums.md5 sequences checksums
|
||||||
locals prettyprint math math.bitwise grouping io combinators
|
locals prettyprint math math.bits grouping io combinators
|
||||||
fry make combinators.short-circuit math.functions splitting ;
|
fry make combinators.short-circuit math.functions splitting ;
|
||||||
IN: crypto.passwd-md5
|
IN: crypto.passwd-md5
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ PRIVATE>
|
||||||
password length
|
password length
|
||||||
[ 16 / ceiling swap <repetition> concat ] keep
|
[ 16 / ceiling swap <repetition> concat ] keep
|
||||||
head-slice append
|
head-slice append
|
||||||
password [ length ] [ first ] bi
|
password [ length make-bits ] [ first ] bi
|
||||||
'[ [ CHAR: \0 _ ? , ] each-bit ] "" make append
|
'[ CHAR: \0 _ ? ] "" map-as append
|
||||||
md5 checksum-bytes ] |
|
md5 checksum-bytes ] |
|
||||||
1000 [
|
1000 [
|
||||||
"" swap
|
"" swap
|
||||||
|
|
Loading…
Reference in New Issue