]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Wed, 18 Mar 2009 00:06:56 +0000 (19:06 -0500)
committerSlava Pestov <slava@slava-pestovs-macbook-pro.local>
Wed, 18 Mar 2009 00:06:56 +0000 (19:06 -0500)
25 files changed:
basis/db/db-docs.factor
basis/openssl/libcrypto/libcrypto.factor
basis/regexp/ast/ast.factor
basis/regexp/classes/classes.factor
basis/regexp/compiler/compiler.factor
basis/regexp/disambiguate/disambiguate.factor
basis/regexp/nfa/nfa.factor
basis/regexp/parser/parser.factor
basis/regexp/regexp-docs.factor
basis/regexp/regexp-tests.factor
basis/unicode/data/data.factor
basis/xml/tests/test.factor
basis/xml/traversal/traversal-docs.factor
basis/xml/xml-docs.factor
basis/xml/xml.factor
extra/chess960/chess960.factor [new file with mode: 0644]
extra/ecdsa/authors.txt [new file with mode: 0644]
extra/ecdsa/ecdsa-tests.factor [new file with mode: 0644]
extra/ecdsa/ecdsa.factor [new file with mode: 0644]
extra/ecdsa/summary.txt [new file with mode: 0644]
extra/io/serial/unix/unix-tests.factor
extra/math/affine-transforms/affine-transforms-tests.factor
extra/math/affine-transforms/affine-transforms.factor
extra/quadtrees/quadtrees.factor
extra/svg/svg-tests.factor

index c392ec6b8514a894db0ba1ab6b46cdfb52cf7685..154d8961a2d93afd30354275ec10089bf131aa06 100644 (file)
@@ -279,7 +279,7 @@ ARTICLE: "db-custom-database-combinators" "Custom database combinators"
 
 "SQLite example combinator:"
 { $code <"
-USING: db.sqlite db io.files ;
+USING: db.sqlite db io.files io.files.temp ;
 : with-sqlite-db ( quot -- )
     "my-database.db" temp-file <sqlite-db> swap with-db ; inline"> } 
 
index 9cbed1f752e961dab54e20c53eed411730713263..1a25b4d01966c868d2c4184c399259cd85d0c369 100644 (file)
@@ -1,4 +1,4 @@
-! Copyright (C) 2007 Elie CHAFTARI
+! Copyright (C) 2007 Elie CHAFTARI, 2009 Maxim Savchenko
 ! See http://factorcode.org/license.txt for BSD license.
 !
 ! Tested with OpenSSL 0.9.8a_0 on Mac OS X 10.4.9 PowerPC
@@ -159,3 +159,65 @@ FUNCTION: int RSA_check_key ( void* rsa ) ;
 FUNCTION: void RSA_free ( void* rsa ) ;
 
 FUNCTION: int RSA_print_fp ( void* fp, void* x, int offset ) ;
+
+! ===============================================
+! objects.h
+! ===============================================
+
+FUNCTION: int OBJ_sn2nid ( char* s ) ;
+
+! ===============================================
+! bn.h
+! ===============================================
+
+FUNCTION: int BN_num_bits ( void* a ) ;
+
+FUNCTION: void* BN_bin2bn ( void* s, int len, void* ret ) ;
+
+FUNCTION: int BN_bn2bin ( void* a, void* to ) ;
+
+FUNCTION: void BN_clear_free ( void* a ) ;
+
+! ===============================================
+! ec.h
+! ===============================================
+
+CONSTANT: POINT_CONVERSION_COMPRESSED 2
+CONSTANT: POINT_CONVERSION_UNCOMPRESSED 4
+CONSTANT: POINT_CONVERSION_HYBRID 6
+
+FUNCTION: int EC_GROUP_get_degree ( void* group ) ;
+
+FUNCTION: void* EC_POINT_new ( void* group ) ;
+
+FUNCTION: void EC_POINT_clear_free ( void* point ) ;
+
+FUNCTION: int EC_POINT_point2oct ( void* group, void* point, int form, void* buf, int len, void* ctx ) ;
+
+FUNCTION: int EC_POINT_oct2point ( void* group, void* point, void* buf, int len, void* ctx ) ;
+
+FUNCTION: void* EC_KEY_new_by_curve_name ( int nid ) ;
+
+FUNCTION: void EC_KEY_free ( void* r ) ;
+
+FUNCTION: int EC_KEY_set_private_key ( void* key, void* priv_key ) ;
+
+FUNCTION: int EC_KEY_set_public_key ( void* key, void* pub_key ) ;
+
+FUNCTION: int EC_KEY_generate_key ( void* eckey ) ;
+
+FUNCTION: void* EC_KEY_get0_group ( void* key ) ;
+
+FUNCTION: void* EC_KEY_get0_private_key ( void* key ) ;
+
+FUNCTION: void* EC_KEY_get0_public_key ( void* key ) ;
+
+! ===============================================
+! ecdsa.h
+! ===============================================
+
+FUNCTION: int ECDSA_size ( void* eckey ) ;
+
+FUNCTION: int ECDSA_sign ( int type, void* dgst, int dgstlen, void* sig, void* siglen, void* eckey ) ;
+
+FUNCTION: int ECDSA_verify ( int type, void* dgst, int dgstlen, void* sig, int siglen, void* eckey ) ;
index ffaed2db62367001df0bec3c848bc9b05133ef84..1c11ed5c7d58070ba5e51d29d48d2fb605963714 100644 (file)
@@ -37,8 +37,7 @@ C: <with-options> with-options
 TUPLE: options on off ;
 C: <options> options
 
-SINGLETONS: unix-lines dotall multiline comments case-insensitive
-unicode-case reversed-regexp ;
+SINGLETONS: unix-lines dotall multiline case-insensitive reversed-regexp ;
 
 : <maybe> ( term -- term' )
     f <concatenation> 2array <alternation> ;
index d26ff7f69ceab3e20812c1d96a5f34a3b233456b..e3a177458591bff0d0b99d4ce6f2ebd75e31afef 100644 (file)
@@ -12,7 +12,7 @@ ascii-class punctuation-class java-printable-class blank-class
 control-character-class hex-digit-class java-blank-class c-identifier-class
 unmatchable-class terminator-class word-boundary-class ;
 
-SINGLETONS: beginning-of-input ^ end-of-input $ end-of-file word-break ;
+SINGLETONS: beginning-of-input ^ end-of-input $ end-of-file ^unix $unix word-break ;
 
 TUPLE: range from to ;
 C: <range> range
index a0646002f93e2acd417313f7413828ebd8b4dcfe..6c7896dccac3a8c87c58d488d5e3103093c1109c 100644 (file)
@@ -17,9 +17,6 @@ SYMBOL: backwards?
 M: t question>quot drop [ 2drop t ] ;
 M: f question>quot drop [ 2drop f ] ;
 
-M: not-class question>quot
-    class>> question>quot [ not ] compose ;
-
 M: beginning-of-input question>quot
     drop [ drop zero? ] ;
 
@@ -40,6 +37,12 @@ M: $ question>quot
 M: ^ question>quot
     drop [ { [ drop zero? ] [ [ 1- ] dip ?nth "\r\n" member? ] } 2|| ] ;
 
+M: $unix question>quot
+    drop [ { [ length = ] [ ?nth CHAR: \n = ] } 2|| ] ;
+
+M: ^unix question>quot
+    drop [ { [ drop zero? ] [ [ 1- ] dip ?nth CHAR: \n = ] } 2|| ] ;
+
 M: word-break question>quot
     drop [ word-break-at? ] ;
 
index 67b1503f9b7b9ca33851d11f6dffb4e51b1582af..876d898cb4e48ca36ad058bf5758b704bdbc7f4e 100644 (file)
@@ -1,7 +1,8 @@
 ! Copyright (C) 2009 Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel accessors regexp.classes math.bits assocs sequences
-arrays sets regexp.dfa math fry regexp.minimize regexp.ast regexp.transition-tables ;
+arrays sets regexp.dfa math fry regexp.minimize regexp.ast
+locals regexp.transition-tables ;
 IN: regexp.disambiguate
 
 TUPLE: parts in out ;
@@ -9,7 +10,7 @@ TUPLE: parts in out ;
 : make-partition ( choices classes -- partition )
     zip [ first ] partition [ values ] bi@ parts boa ;
 
-: powerset-partition ( classes -- partitions )
+: powerset-partition ( sequence -- partitions )
     [ length [ 2^ ] keep ] keep '[
         _ <bits> _ make-partition
     ] map rest ;
@@ -19,19 +20,49 @@ TUPLE: parts in out ;
     [ in>> <and-class> ] bi
     prefix <and-class> ;
 
-: get-transitions ( partition state-transitions -- next-states )
-    [ in>> ] dip '[ _ at ] gather sift ;
+: singleton-partition ( integer non-integers -- {class,partition} )
+    dupd
+    '[ _ [ class-member? ] with filter ] keep
+    prefix f parts boa
+    2array ;
+
+: add-out ( seq partition -- partition' )
+    [ out>> append ] [ in>> ] bi swap parts boa ;
+
+: intersection ( seq -- elts )
+    [ f ] [ unclip [ intersect ] reduce ] if-empty ;
+
+: meaningful-integers ( partition table -- integers )
+    [ [ in>> ] [ out>> ] bi ] dip
+    '[ [ _ at ] map intersection ] bi@ diff ;
+
+: class-integers ( classes integers -- table )
+    '[ _ over '[ _ class-member? ] filter ] H{ } map>assoc ;
+
+: add-integers ( partitions classes integers -- partitions )
+    class-integers '[
+        [ _ meaningful-integers ] keep add-out
+    ] map ;
+
+: class-partitions ( classes -- assoc )
+    [ integer? ] partition [
+        dup powerset-partition spin add-integers
+        [ [ partition>class ] keep 2array ] map
+        [ first ] filter
+    ] [ '[ _ singleton-partition ] map ] 2bi append ;
 
 : new-transitions ( transitions -- assoc ) ! assoc is class, partition
     values [ keys ] gather
     [ tagged-epsilon? not ] filter
-    powerset-partition
-    [ [ partition>class ] keep ] { } map>assoc
-    [ drop ] assoc-filter ;
+    class-partitions ;
+
+: get-transitions ( partition state-transitions -- next-states )
+    [ in>> ] dip '[ _ at ] gather sift ;
 
 : preserving-epsilon ( state-transitions quot -- new-state-transitions )
     [ [ drop tagged-epsilon? ] assoc-filter ] bi
     assoc-union H{ } assoc-like ; inline
+
 : disambiguate ( nfa -- nfa )  
     expand-ors [
         dup new-transitions '[
index 20be6b87d852678755b071a29ebcb78e97ad9afc..d59d4818ec7ef5926a8dbd13ca4f9c5c61bdf347 100644 (file)
@@ -60,11 +60,16 @@ GENERIC: modify-epsilon ( tag -- newtag )
 
 M: object modify-epsilon ;
 
+: line-option ( multiline unix-lines default -- option )
+    multiline option? [
+        drop [ unix-lines option? ] 2dip swap ?
+    ] [ 2nip ] if ;
+
 M: $ modify-epsilon
-    multiline option? [ drop end-of-input ] unless ;
+    $unix end-of-input line-option ;
 
 M: ^ modify-epsilon
-    multiline option? [ drop beginning-of-input ] unless ;
+    ^unix beginning-of-input line-option ;
 
 M: tagged-epsilon nfa-node
     clone [ modify-epsilon ] change-tag add-simple-entry ;
index c6a69f250875a2ddf999844f19c10a0f79dda013..7b2d6af2c1d17afb1fc8cd0de6d73ce5f22330e5 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: peg.ebnf kernel math.parser sequences assocs arrays fry math
 combinators regexp.classes strings splitting peg locals accessors
-regexp.ast ;
+regexp.ast unicode.case ;
 IN: regexp.parser
 
 : allowed-char? ( ch -- ? )
@@ -19,20 +19,19 @@ ERROR: bad-number ;
 ERROR: bad-class name ;
 
 : name>class ( name -- class )
-    {
-        { "Lower" letter-class }
-        { "Upper" 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 }
+    >string >case-fold {
+        { "lower" letter-class }
+        { "upper" LETTER-class }
+        { "alpha" Letter-class }
+        { "ascii" ascii-class }
+        { "digit" digit-class }
+        { "alnum" alpha-class }
+        { "punct" punctuation-class }
+        { "graph" java-printable-class }
+        { "blank" non-newline-blank-class }
+        { "cntrl" control-character-class }
+        { "xdigit" hex-digit-class }
+        { "space" java-blank-class }
         ! TODO: unicode-character-class
     } [ bad-class ] at-error ;
 
@@ -66,11 +65,8 @@ ERROR: bad-class name ;
         { 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 }
     } ;
 
 : ch>option ( ch -- singleton )
@@ -101,8 +97,8 @@ CharacterInBracket = !("}") Character
 
 QuotedCharacter = !("\\E") .
 
-Escape = "p{" CharacterInBracket*:s "}" => [[ s >string name>class <primitive-class> ]]
-       | "P{" CharacterInBracket*:s "}" => [[ s >string name>class <primitive-class> <negation> ]]
+Escape = "p{" CharacterInBracket*:s "}" => [[ s name>class <primitive-class> ]]
+       | "P{" CharacterInBracket*:s "}" => [[ s name>class <primitive-class> <negation> ]]
        | "Q" QuotedCharacter*:s "\\E" => [[ s <concatenation> ]]
        | "u" Character:a Character:b Character:c Character:d
             => [[ { a b c d } hex> ensure-number ]]
index b35f8d1cf31fff64b20a6260810aabd186d0114c..6ad340a82ddbff38031e4de1f2f5b69385d4f887 100644 (file)
@@ -1,6 +1,7 @@
 ! Copyright (C) 2008, 2009 Doug Coleman, Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel strings help.markup help.syntax math regexp.parser regexp.ast ;
+USING: kernel strings help.markup help.syntax math regexp.parser
+regexp.ast multiline ;
 IN: regexp
 
 ABOUT: "regexp"
@@ -21,8 +22,17 @@ ARTICLE: "regexp" "Regular expressions"
 { $subsection { "regexp" "deploy" } } ;
 
 ARTICLE: { "regexp" "intro" } "A quick introduction to regular expressions"
-
-;
+"Regular expressions are a terse way to do certain simple string processing tasks. For example, to replace all instances of " { $snippet "foo" } " in one string with " { $snippet "bar" } ", the following can be used:"
+{ $code "R/ foo/ \"bar\" re-replace" }
+"That could be done with sequence operations, but consider doing this replacement for an arbitrary number of o's, at least two:"
+{ $code "R/ foo+/ \"bar\" re-replace" }
+"The " { $snippet "+" } " operator matches one or more occurrences of the previous expression; in this case " { $snippet "o" } ". Another useful feature is alternation. Say we want to do this replacement with fooooo or boooo. Then we could use the code"
+{ $code "R/ (f|b)oo+/ \"bar\" re-replace" }
+"To search a file for all lines that match a given regular expression, you could use code like this:"
+{ $code <" "file.txt" ascii file-lines [ R/ (f|b)oo+/ re-contains? ] filter "> }
+"To test if a string in its entirety matches a regular expression, the following can be used:"
+{ $example <" USING: regexp prettyprint ; "fooo" R/ (b|f)oo+/ matches? . "> "t" }
+"Regular expressions can't be used for all parsing tasks. For example, they are not powerful enough to match balancing parentheses." ;
 
 ARTICLE: { "regexp" "construction" } "Constructing regular expressions"
 "Most of the time, regular expressions are literals and the parsing word should be used, to construct them at parse time. This ensures that they are only compiled once, and gives parse time syntax checking."
@@ -33,20 +43,71 @@ ARTICLE: { "regexp" "construction" } "Constructing regular expressions"
 "Another approach is to use " { $vocab-link "regexp.combinators" } "." ;
 
 ARTICLE: { "regexp" "syntax" } "Regular expression syntax"
-"Regexp syntax is largely compatible with Perl, Java and extended POSIX regexps, but not completely. A new addition is the inclusion of a negation operator, with the syntax " { $snippet "(?~foo)" } " to match everything that does not match " { $snippet "foo" } "."
+"Regexp syntax is largely compatible with Perl, Java and extended POSIX regexps, but not completely. Below, the syntax is documented."
 { $heading "Characters" }
+"At its core, regular expressions consist of character literals. For example, " { $snippet "R/ f/" } " is a regular expression matching just the string 'f'. In addition, the normal escape codes are provided, like " { $snippet "\\t" } " for the tab character and " { $snippet "\\uxxxxxx" } "for an arbitrary Unicode code point, by its hex value. In addition, any character can be preceded by a backslash to escape it, unless this has special meaning. For example, to match a literal opening parenthesis, use " { $snippet "\\(" } "."
+{ $heading "Concatenation, alternation and grouping" }
+"Regular expressions can be built out of multiple characters by concatenation. For example, " { $snippet "R/ ab/" } " matches a followed by b. The " { $snippet "|" } " (alternation) operator can construct a regexp which matches one of two alternatives. Parentheses can be used for gropuing. So " { $snippet "R/ f(oo|ar)/" } " would match either 'foo' or 'far'."
 { $heading "Character classes" }
+"Square brackets define a convenient way to refer to a set of characters. For example, " { $snippet "[ab]" } " refers to either a or b. And " { $snippet "[a-z]" } " refers to all of the characters between a and z, in code point order. You can use these together, as in " { $snippet "[ac-fz]" } " which matches all of the characters between c and f, in addition to a and z. Character classes can be negated using a carat, as in " { $snippet "[^a]" } " which matches all characters which are not a."
 { $heading "Predefined character classes" }
+"Several character classes are predefined, both for convenience and because they are too large to represent directly. In Factor regular expressions, all character classes are Unicode-aware."
+{ $table
+    { { $snippet "\\d" } "Digits" }
+    { { $snippet "\\D" } "Not digits" }
+    { { $snippet "\\s" } "Whitespace" }
+    { { $snippet "\\S" } "Not whitespace" }
+    { { $snippet "\\w" } "Word character (alphanumeric or underscore)" }
+    { { $snippet "\\W" } "Not word character" }
+    { { $snippet "\\p{property}" } "Character which fulfils the property" }
+    { { $snippet "\\P{property}" } "Character which does not fulfil the property" } }
+"Properties for " { $snippet "\\p" } " and " { $snippet "\\P" } " (case-insensitive):"
+{ $table
+    { { $snippet "\\p{lower}" } "Lower case letters" }
+    { { $snippet "\\p{upper}" } "Upper case letters" }
+    { { $snippet "\\p{alpha}" } "Letters" }
+    { { $snippet "\\p{ascii}" } "Characters in the ASCII range" }
+    { { $snippet "\\p{alnum}" } "Letters or numbers" }
+    { { $snippet "\\p{punct}" } "Punctuation" }
+    { { $snippet "\\p{blank}" } "Non-newline whitespace" }
+    { { $snippet "\\p{cntrl}" } "Control character" }
+    { { $snippet "\\p{space}" } "Whitespace" }
+    { { $snippet "\\p{xdigit}" } "Hexidecimal digit" } } ! In the future: Unicode
+"Full unicode properties are not yet supported."
 { $heading "Boundaries" }
+"Special operators exist to match certain points in the string. These are called 'zero-width' because they do not consume any characters."
+{ $table
+    { { $snippet "^" } "Beginning of a line" }
+    { { $snippet "$" } "End of a line" }
+    { { $snippet "\\A" } "Beginning of text" }
+    { { $snippet "\\z" } "End of text" }
+    { { $snippet "\\Z" } "Almost end of text: only thing after is newline" }
+    { { $snippet "\\b" } "Word boundary (by Unicode word boundaries)" }
+    { { $snippet "\\b" } "Not word boundary (by Unicode word boundaries)" } }
 { $heading "Greedy quantifiers" }
-{ $heading "Reluctant quantifiers" }
-{ $heading "Posessive quantifiers" }
-{ $heading "Logical operations" }
+"It is possible to have a regular expression which matches a variable number of occurrences of another regular expression."
+{ $table
+    { { $snippet "a*" } "Zero or more occurrences of a" }
+    { { $snippet "a+" } "One or more occurrences of a" }
+    { { $snippet "a?" } "Zero or one occurrences of a" }
+    { { $snippet "a{n}" } "n occurrences of a" }
+    { { $snippet "a{n,}" } "At least n occurrences of a" }
+    { { $snippet "a{,m}" } "At most m occurrences of a" }
+    { { $snippet "a{n,m}" } "Between n and m occurrences of a" } }
+"All of these quantifiers are " { $emphasis "greedy" } ", meaning that they take as many repetitions as possible within the larger regular expression. Reluctant and posessive quantifiers are not yet supported."
 { $heading "Lookaround" }
+"Operators are provided to look ahead and behind the current point in the regular expression. These can be used in any context, but they're the most useful at the beginning or end of a regular expression."
+{ $table
+    { { $snippet "(?=a)" } "Asserts that the current position is immediately followed by a" }
+    { { $snippet "(?!a)" } "Asserts that the current position is not immediately followed by a" }
+    { { $snippet "(?<=a)" } "Asserts that the current position is immediately preceded by a" }
+    { { $snippet "(?<!a)" } "Asserts that the current position is not immediately preceded by a" } }
+{ $heading "Quotation" }
+"To make it convenient to have a long string which uses regexp operators, a special syntax is provided. If a substring begins with " { $snippet "\\Q" } " then everything until " { $snippet "\\E" } " is quoted (escaped). For example, " { $snippet "R/ \\Qfoo\\bar|baz()\\E/" } " matches exactly the string " { $snippet "\"foo\\bar|baz()\"" } "."
 { $heading "Unsupported features" }
 "One missing feature is backreferences. This is because of a design decision to allow only regular expressions following the formal theory of regular languages. For more information, see " { $link { "regexp" "theory" } } ". You can create a new regular expression to match a particular string using " { $vocab-link "regexp.combinators" } " and group capture is available to extract parts of a regular expression match." $nl
 "Another feature is Perl's " { $snippet "\\G" } " syntax, which references the previous match, is not included. This is because that sequence is inherently stateful, and Factor regexps don't hold state." $nl
-"Additionally, none of the operations which embed code into a regexp are supported, as this would require the inclusion of the Factor parser and compiler in any application which wants to expose regexps to the user. None of the casing operations are included, for simplicity." ; ! Also describe syntax, from the beginning
+"None of the operations which embed code into a regexp are supported, as this would require the inclusion of the Factor parser and compiler in any application which wants to expose regexps to the user. None of the casing operations are included of Perl like \\L, for simplicity." ; ! Also describe syntax, from the beginning
 
 ARTICLE: { "regexp" "options" } "Regular expression options"
 "When " { $link { "regexp" "construction" } } ", various options can be provided. Options have single-character names. A string of options has one of the following two forms:"
@@ -58,13 +119,30 @@ $nl
   { "i" { $link case-insensitive } }
   { "d" { $link unix-lines } }
   { "m" { $link multiline } }
-  { "n" { $link multiline } }
-  { "r" { $link reversed-regexp } }
   { "s" { $link dotall } }
-  { "u" { $link unicode-case } }
-  { "x" { $link comments } }
+  { "r" { $link reversed-regexp } }
 } ;
 
+HELP: case-insensitive
+{ $syntax "R/ .../i" }
+{ $description "On regexps, the " { $snippet "i" } " option makes the match case-insenstive. Currently, this is handled incorrectly with respect to Unicode, as characters like ÃŸ do not expand into SS in upper case. This should be fixed in a future version." } ;
+
+HELP: unix-lines
+{ $syntax "R/ .../d" }
+{ $description "With this mode, only newlines (" { $snippet "\\n" } ") are recognized for line breaking. This affects " { $snippet "$" } " and " { $snippet "^" } " when in multiline mode." } ;
+
+HELP: multiline
+{ $syntax "R/ .../m" }
+{ $description "This mode makes the zero-width constraints " { $snippet "$" } " and " { $snippet "^" } " match the beginning or end of a line. Otherwise, they only match the beginning or end of the input text. This can be used together with " { $link dotall } "." } ;
+
+HELP: dotall
+{ $syntax "R/ .../s" }
+{ $description "This mode, traditionally called single line mode, makes " { $snippet "." } " match everything, including line breaks. By default, it does not match line breaking characters. This can be used together with " { $link multiline } "." } ;
+
+HELP: reversed-regexp
+{ $syntax "R/ .../r" }
+{ $description "When running a regexp compiled with this mode, matches will start from the end of the input string, going towards the beginning." } ;
+
 ARTICLE: { "regexp" "theory" } "The theory of regular expressions"
 "Far from being just a practical tool invented by Unix hackers, regular expressions were studied formally before computer programs were written to process them." $nl
 "A regular language is a set of strings that is matched by a regular expression, which is defined to have characters and the empty string, along with the operations concatenation, disjunction and Kleene star. Another way to define the class of regular languages is as the class of languages which can be recognized with constant space overhead, ie with a DFA. These two definitions are provably equivalent." $nl
index a449b3e2f0b0891bbaa01aecdf68cc1642d90784..0836c0988b1a434efb880f7da3061ba2d6fb42ca 100644 (file)
@@ -470,3 +470,13 @@ IN: regexp-tests
 [ t ] [ "abcdefg" "a(?:bcdefg)" <regexp> matches? ] unit-test
 
 [ 3 ] [ "caba" "(?<=b)a" <regexp> first-match from>> ] unit-test
+
+[ t ] [ "\ra" R/ .^a/ms matches? ] unit-test
+[ f ] [ "\ra" R/ .^a/mds matches? ] unit-test
+[ t ] [ "\na" R/ .^a/ms matches? ] unit-test
+[ t ] [ "\na" R/ .^a/mds matches? ] unit-test
+
+[ t ] [ "a\r" R/ a$./ms matches? ] unit-test
+[ f ] [ "a\r" R/ a$./mds matches? ] unit-test
+[ t ] [ "a\n" R/ a$./ms matches? ] unit-test
+[ t ] [ "a\n" R/ a$./mds matches? ] unit-test
index bff4ddeaab3856507e3606cc52aaf08e4f44aead..74914e8537cd37b6a31935281b0322f7483fe943 100644 (file)
@@ -5,7 +5,7 @@ io.files hashtables quotations splitting grouping arrays io
 math.parser hash2 math.order byte-arrays words namespaces words
 compiler.units parser io.encodings.ascii values interval-maps
 ascii sets combinators locals math.ranges sorting make
-strings.parser io.encodings.utf8 ;
+strings.parser io.encodings.utf8 memoize ;
 IN: unicode.data
 
 VALUE: simple-lower
@@ -108,6 +108,9 @@ CONSTANT: categories
       "Zs" "Zl" "Zp"
       "Cc" "Cf" "Cs" "Co" }
 
+MEMO: categories-map ( -- hashtable )
+    categories <enum> [ swap ] H{ } assoc-map-as ;
+
 CONSTANT: num-chars HEX: 2FA1E
 
 ! the maximum unicode char in the first 3 planes
@@ -124,10 +127,10 @@ CONSTANT: num-chars HEX: 2FA1E
     ] assoc-each table ;
 
 :: process-category ( data -- category-listing )
-    [let | table [ num-chars <byte-array> ] |
-        2 data (process-data) [| char cat |
-            cat categories index char table ?set-nth
-        ] assoc-each table fill-ranges ] ;
+    num-chars <byte-array> :> table
+    2 data (process-data) [| char cat |
+        cat categories-map at char table ?set-nth
+    ] assoc-each table fill-ranges ;
 
 : process-names ( data -- names-hash )
     1 swap (process-data) [
index 818a28c892896584e9385da9083fd6e524b06d7d..1d07aa94063ad07f2c28a979b5d74154846cd84e 100644 (file)
@@ -74,3 +74,4 @@ SYMBOL: xml-file
 [ "foo" ] [ "<!DOCTYPE foo [<!ENTITY bar 'foo'>]><x>&bar;</x>" string>xml children>string ] unit-test
 [ T{ xml-chunk f V{ "hello" } } ] [ "hello" string>xml-chunk ] unit-test
 [ "1.1" ] [ "<?xml version='1.1'?><x/>" string>xml prolog>> version>> ] unit-test
+[ "ß" ] [ "<x>ß</x>" <string-reader> read-xml children>string ] unit-test
index 1329c4975e438cfbc133cc3faefe953314b1e702..9f26774647868f015e35b547e9f0822d1d788aa8 100644 (file)
@@ -1,6 +1,6 @@
 ! Copyright (C) 2005, 2009 Daniel Ehrenberg
 ! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax xml.data sequences strings ;
+USING: help.markup help.syntax xml.data sequences strings multiline ;
 IN: xml.traversal
 
 ABOUT: "xml.traversal"
@@ -8,7 +8,7 @@ ABOUT: "xml.traversal"
 ARTICLE: "xml.traversal" "Utilities for traversing XML"
     "The " { $vocab-link "xml.traversal" } " vocabulary provides utilities for traversing an XML DOM tree and viewing the contents of a single tag. The following words are defined:"
     $nl
-    "Note: the difference between deep-tag-named and tag-named is that the former searches recursively among all children and children of children of the tag, while the latter only looks at the direct children, and is therefore more efficient."
+    { $subsection { "xml.traversal" "intro" } }
     { $subsection tag-named }
     { $subsection tags-named }
     { $subsection deep-tag-named }
@@ -20,6 +20,20 @@ ARTICLE: "xml.traversal" "Utilities for traversing XML"
     { $subsection first-child-tag }
     { $subsection assert-tag } ;
 
+ARTICLE: { "xml.traversal" "intro" } "An example of XML processing"
+"To illustrate how to use the XML library, we develop a simple Atom parser in Factor. Atom is an XML-based syndication format, like RSS. To see the full version of what we develop here, look at " { $snippet "basis/syndication" } " at the " { $snippet "atom1.0" } " word. First, we want to load a file and get a DOM tree for it."
+{ $code <" "file.xml" file>xml "> }
+"No encoding descriptor is needed, because XML files contain sufficient information to auto-detect the encoding. Next, we want to extract information from the tree. To get the title, we can use the following:"
+{ $code <" "title" tag-named children>string "> }
+"The " { $link tag-named } " word finds the first tag named " { $snippet "title" } " in the top level (just under the main tag). Then, with a tag on the stack, its children are asserted to be a string, and the string is returned." $nl
+"For a slightly more complicated example, we can look at how entries are parsed. To get a sequence of tags with the name " { $snippet "entry" } ":"
+{ $code <" "entry" tags-named "> }
+"Imagine that, for each of these, we want to get the URL of the entry. In Atom, the URLs are in a " { $snippet "link" } " tag which is contained in the " { $snippet "entry" } " tag. There are multiple " { $snippet "link" } " tags, but one of them contains the attribute " { $snippet "rel=alternate" } ", and the " { $snippet "href" } " attribute has the URL. So, given an element of the sequence produced in the above quotation, we run the code:"
+{ $code <" "link" tags-named [ "rel" attr "alternate" = ] find nip "> }
+"to get the link tag on the stack, and"
+{ $code <" "href" attr >url "> }
+"to extract the URL from it." ;
+
 HELP: deep-tag-named
 { $values { "tag" "an XML tag or document" } { "name/string" "an XML name or string representing a name" } { "matching-tag" tag } }
 { $description "Finds an XML tag with a matching name, recursively searching children and children of children." }
index 77969c55cde415545dc554c7ee8d1cabf2dfba70..434209620b9b837c9674fb2809ab022c7393346f 100644 (file)
@@ -67,9 +67,9 @@ HELP: string>dtd
 \r
 ARTICLE: { "xml" "reading" } "Reading XML"\r
     "The following words are used to read something into an XML document"\r
-    { $subsection string>xml }\r
     { $subsection read-xml }\r
     { $subsection read-xml-chunk }\r
+    { $subsection string>xml }\r
     { $subsection string>xml-chunk }\r
     { $subsection file>xml }\r
     { $subsection bytes>xml }\r
@@ -90,10 +90,16 @@ ARTICLE: { "xml" "events" } "Event-based XML parsing"
     { $subsection pull-event }\r
     { $subsection pull-elem } ;\r
 \r
+ARTICLE: { "xml" "namespaces" } "Working with XML namespaces"\r
+"The Factor XML parser implements XML namespaces, and provides convenient utilities for working with them. Anywhere in the public API that a name is accepted as an argument, either a string or an XML name is accepted. If a string is used, it is coerced into a name by giving it a null namespace. Names are stored as " { $link name } " tuples, which have slots for the namespace prefix and namespace URL as well as the main part of the tag name." $nl\r
+"To make it easier to create XML names, the parsing word " { $snippet "XML-NS:" } " is provided in the " { $vocab-link "xml.syntax" } " vocabulary." $nl\r
+"When parsing XML, names are automatically augmented with the appropriate namespace URL when the information is available. This does not take into account any XML schema which might allow for such prefixes to be omitted. When generating XML to be written, keep in mind that the XML writer knows only about the literal prefixes and ignores the URLs. It is your job to make sure that they match up correctly, and that there is the appropriate " { $snippet "xmlns" } " declaration." ;\r
+\r
 ARTICLE: "xml" "XML parser"\r
 "The " { $vocab-link "xml" } " vocabulary implements the XML 1.0 and 1.1 standards, converting strings of text into XML and vice versa. The parser checks for well-formedness but is not validating. There is only partial support for processing DTDs."\r
     { $subsection { "xml" "reading" } }\r
     { $subsection { "xml" "events" } }\r
+    { $subsection { "xml" "namespaces" } }\r
     { $vocab-subsection "Writing XML" "xml.writer" }\r
     { $vocab-subsection "XML parsing errors" "xml.errors" }\r
     { $vocab-subsection "XML entities" "xml.entities" }\r
index 073f46cbae3314a7c390ed56f14921f5a00f9830..fba2eafaba84f72f40364c4eca307950a9077cfb 100755 (executable)
@@ -4,7 +4,8 @@ USING: accessors arrays io io.encodings.binary io.files
 io.streams.string kernel namespaces sequences strings io.encodings.utf8
 xml.data xml.errors xml.elements ascii xml.entities
 xml.writer xml.state xml.autoencoding assocs xml.tokenize
-combinators.short-circuit xml.name splitting io.streams.byte-array ;
+combinators.short-circuit xml.name splitting io.streams.byte-array
+combinators ;
 IN: xml
 
 <PRIVATE
@@ -159,6 +160,9 @@ PRIVATE>
         xml-stack get first second
     ] with-state ; inline
 
+: make-xml ( stream quot -- xml )
+    0 read-seq make-xml-doc ; inline
+
 PRIVATE>
 
 : each-element ( stream quot: ( xml-elem -- ) -- )
@@ -169,14 +173,16 @@ PRIVATE>
     ] with-state ; inline
 
 : read-xml ( stream -- xml )
-    [ start-document [ process ] when* ]
-    0 read-seq make-xml-doc ;
+    dup stream-element-type {
+        { +character+ [ [ check ] make-xml ] }
+        { +byte+ [ [ start-document [ process ] when* ] make-xml ] }
+    } case ;
 
 : read-xml-chunk ( stream -- seq )
     [ check ] 1 read-seq <xml-chunk> ;
 
 : string>xml ( string -- xml )
-    <string-reader> [ check ] 0 read-seq make-xml-doc ;
+    <string-reader> read-xml ;
 
 : string>xml-chunk ( string -- xml )
     <string-reader> read-xml-chunk ;
diff --git a/extra/chess960/chess960.factor b/extra/chess960/chess960.factor
new file mode 100644 (file)
index 0000000..6535cc1
--- /dev/null
@@ -0,0 +1,43 @@
+USING: math.ranges kernel random sequences arrays combinators ;
+IN: chess960
+
+SYMBOLS: pawn rook knight bishop queen king ;
+
+: all-positions ( -- range ) 0 8 [a,b) ;
+
+: black-bishop-positions ( -- range ) 0 6 2 <range> ;
+: white-bishop-positions ( -- range ) 1 7 2 <range> ;
+
+: frisk ( position positions -- position positions' )
+    [ drop ] [ remove ] 2bi ;
+
+: white-bishop ( positions -- position positions' )
+    [ white-bishop-positions random ] dip frisk ;
+: black-bishop ( positions -- position positions' )
+    [ black-bishop-positions random ] dip frisk ;
+
+: random-position ( positions -- position positions' )
+    [ random ] keep frisk ;
+
+: make-position ( white-bishop black-bishop knight knight queen {r,k,r} -- position )
+    first3
+    8 f <array> {
+        [ [ rook ] 2dip set-nth ]
+        [ [ king ] 2dip set-nth ]
+        [ [ rook ] 2dip set-nth ]
+        [ [ queen ] 2dip set-nth ]
+        [ [ knight ] 2dip set-nth ]
+        [ [ knight ] 2dip set-nth ]
+        [ [ bishop ] 2dip set-nth ]
+        [ [ bishop ] 2dip set-nth ]
+        [ ]
+    } cleave ;
+
+: chess960-position ( -- position )
+    all-positions
+    white-bishop
+    black-bishop
+    random-position
+    random-position
+    random-position
+    make-position ;
diff --git a/extra/ecdsa/authors.txt b/extra/ecdsa/authors.txt
new file mode 100644 (file)
index 0000000..f97e1bf
--- /dev/null
@@ -0,0 +1 @@
+Maxim Savchenko
diff --git a/extra/ecdsa/ecdsa-tests.factor b/extra/ecdsa/ecdsa-tests.factor
new file mode 100644 (file)
index 0000000..897ee63
--- /dev/null
@@ -0,0 +1,30 @@
+! Copyright (C) 2009 Maxim Savchenko
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: namespaces ecdsa tools.test checksums checksums.openssl ;
+IN: ecdsa.tests
+
+SYMBOLS: priv-key pub-key signature ;
+
+: message ( -- msg ) "Hello world!" ;
+
+[ ] ! Generating keys
+[
+    "prime256v1" [ generate-key get-private-key get-public-key ] with-ec
+    pub-key set priv-key set
+] unit-test
+
+[ ] ! Signing message
+[
+    message "sha256" <openssl-checksum> checksum-bytes
+    priv-key get
+    "prime256v1" [ set-private-key ecdsa-sign ] with-ec
+    signature set
+] unit-test
+
+[ t ] ! Verifying signature
+[
+    message "sha256" <openssl-checksum> checksum-bytes
+    signature get pub-key get
+    "prime256v1" [ set-public-key ecdsa-verify ] with-ec
+] unit-test
\ No newline at end of file
diff --git a/extra/ecdsa/ecdsa.factor b/extra/ecdsa/ecdsa.factor
new file mode 100644 (file)
index 0000000..d76b93a
--- /dev/null
@@ -0,0 +1,75 @@
+! Copyright (C) 2009 Maxim Savchenko
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: kernel accessors sequences sequences.private destructors math namespaces
+       locals openssl openssl.libcrypto byte-arrays bit-arrays.private
+       alien.c-types alien.destructors ;
+
+IN: ecdsa
+
+<PRIVATE
+
+TUPLE: ec-key handle ;
+
+M: ec-key dispose
+    [ EC_KEY_free f ] change-handle drop ;
+
+: <ec-key> ( curve -- key )
+    OBJ_sn2nid dup zero? [ "Unknown curve name" throw ] when
+    EC_KEY_new_by_curve_name dup ssl-error ec-key boa ;
+
+: ec-key-handle ( -- handle )
+    ec-key get dup handle>> [ nip ] [ already-disposed ] if* ;
+
+DESTRUCTOR: BN_clear_free
+
+DESTRUCTOR: EC_POINT_clear_free
+
+PRIVATE>
+
+: with-ec ( curve quot -- )
+    swap <ec-key> [ ec-key rot with-variable ] with-disposal ; inline
+
+: generate-key ( -- )
+    ec-key get handle>> EC_KEY_generate_key ssl-error ;
+
+: set-private-key ( bin -- )
+    ec-key-handle swap
+    dup length f BN_bin2bn dup ssl-error
+    [ &BN_clear_free EC_KEY_set_private_key ssl-error ] with-destructors ;
+
+:: set-public-key ( BIN -- )
+    ec-key-handle :> KEY
+    KEY EC_KEY_get0_group :> GROUP
+    GROUP EC_POINT_new dup ssl-error
+    [
+        &EC_POINT_clear_free :> POINT
+        GROUP POINT BIN dup length f EC_POINT_oct2point ssl-error
+        KEY POINT EC_KEY_set_public_key ssl-error
+    ] with-destructors ;
+
+: get-private-key ( -- bin/f )
+    ec-key-handle EC_KEY_get0_private_key
+    dup [ dup BN_num_bits bits>bytes <byte-array> tuck BN_bn2bin drop ] when ;
+
+:: get-public-key ( -- bin/f )
+    ec-key-handle :> KEY
+    KEY EC_KEY_get0_public_key dup 
+    [| PUB |
+        KEY EC_KEY_get0_group :> GROUP
+        GROUP EC_GROUP_get_degree bits>bytes 1+ :> LEN
+        LEN <byte-array> :> BIN
+        GROUP PUB POINT_CONVERSION_COMPRESSED BIN LEN f
+        EC_POINT_point2oct ssl-error
+        BIN
+    ] when ;
+
+:: ecdsa-sign ( DGST -- sig )
+    ec-key-handle :> KEY
+    KEY ECDSA_size dup ssl-error <byte-array> :> SIG
+    "uint" <c-object> :> LEN
+    0 DGST dup length SIG LEN KEY ECDSA_sign ssl-error
+    LEN *uint SIG resize ;
+
+: ecdsa-verify ( dgst sig -- ? )
+    ec-key-handle [ 0 -rot [ dup length ] bi@ ] dip ECDSA_verify 0 > ;
\ No newline at end of file
diff --git a/extra/ecdsa/summary.txt b/extra/ecdsa/summary.txt
new file mode 100644 (file)
index 0000000..8f952c3
--- /dev/null
@@ -0,0 +1 @@
+Elliptic Curve Digital Signature Algorithm (OpenSSL realisation)
index e9b8d78e4b7fd9ffd5540026bd5b13bf94cb4590..f4c0c6b45a4cbc91ce9862867c11dc20291c4b2b 100644 (file)
@@ -5,7 +5,10 @@ IN: io.serial.unix
 
 : serial-obj ( -- obj )
     serial new
-    "/dev/ttyS0" >>path
+    "/dev/ttyS0" >>path ! linux
+    ! "/dev/dty00" >>path ! netbsd
+    ! "/dev/ttyd0" >>path ! freebsd
+    ! "/dev/ttyU0" >>path ! openbsd
     19200 >>baud
     { IGNPAR ICRNL } flags >>iflag
     { } flags >>oflag
index 1d10e07ceaaf9be7fdac9c3a332c522e563ed19e..cdbd5eef39c283385a769c1c4b46fd851f5f605c 100644 (file)
@@ -33,6 +33,12 @@ IN: math.affine-transforms.tests
     dup inverse-transform a.
 ] unit-test
 
+{ 2.0 -1.0 } { -1.0 -2.0 } { 5.0 -6.0 } <affine-transform> 1array [
+    { 1.0 0.0 } { 0.0 -1.0 } { 0.0 0.0 } <affine-transform>
+    { 2.0 1.0 } { -1.0 2.0 } { 5.0 6.0 } <affine-transform>
+    a.
+] unit-test
+
 [ t ] [
     { 0.01  0.02  } { 0.03  0.04  } { 0.05  0.06  } <affine-transform>
     { 0.011 0.021 } { 0.031 0.041 } { 0.051 0.061 } <affine-transform> 0.01 a~
index 822af51614eb7f1d61c49882864a2697f122a215..20b73ba67884c2bdddb34e9399f4a6d4f0844151 100644 (file)
@@ -3,11 +3,14 @@ USING: accessors arrays combinators combinators.short-circuit kernel math math.v
 math.functions sequences ;
 IN: math.affine-transforms
 
-TUPLE: affine-transform x y origin ;
+TUPLE: affine-transform { x read-only } { y read-only } { origin read-only } ;
 C: <affine-transform> affine-transform
 
 CONSTANT: identity-transform T{ affine-transform f { 1.0 0.0 } { 0.0 1.0 } { 0.0 0.0 } }
 
+: axes ( a -- a' )
+     [ x>> ] [ y>> ] bi { 0.0 0.0 } <affine-transform> ;
+
 : a.v ( a v -- v )
     [ [ x>> ] [ first  ] bi* v*n ]
     [ [ y>> ] [ second ] bi* v*n ]
@@ -23,7 +26,7 @@ CONSTANT: identity-transform T{ affine-transform f { 1.0 0.0 } { 0.0 1.0 } { 0.0
     [ 0.0 2array ] [ 0.0 swap 2array ] bi* { 0.0 0.0 } <affine-transform> ;
 
 : center-rotation ( transform center -- transform )
-    [ clone dup ] dip [ vneg a.v ] [ v+ ] bi >>origin ;
+    [ [ x>> ] [ y>> ] [ ] tri ] dip [ vneg a.v ] [ v+ ] bi <affine-transform> ;
     
 : flatten-transform ( transform -- array )
     [ x>> ] [ y>> ] [ origin>> ] tri 3append ;
@@ -42,8 +45,8 @@ CONSTANT: identity-transform T{ affine-transform f { 1.0 0.0 } { 0.0 1.0 } { 0.0
     (inverted-axes) { 0.0 0.0 } <affine-transform> ;
 
 : inverse-transform ( a -- a^-1 )
-    [ inverse-axes dup ] [ origin>> ] bi
-    a.v vneg >>origin ;
+    [ inverse-axes [ x>> ] [ y>> ] [ ] tri ] [ origin>> ] bi
+    a.v vneg <affine-transform> ;
 
 : transpose-axes ( a -- a^T )
     [ [ x>> first  ] [ y>> first  ] bi 2array ]
@@ -51,11 +54,11 @@ CONSTANT: identity-transform T{ affine-transform f { 1.0 0.0 } { 0.0 1.0 } { 0.0
     [ origin>> ] tri <affine-transform> ;
 
 : a. ( a a -- a )
-    transpose-axes {
-        [ [ x>> ] [ x>> ] bi* v. ]
-        [ [ x>> ] [ y>> ] bi* v. ]
-        [ [ y>> ] [ x>> ] bi* v. ]
-        [ [ y>> ] [ y>> ] bi* v. ]
+    {
+        [ [ transpose-axes x>> ] [ x>> ] bi* v. ]
+        [ [ transpose-axes y>> ] [ x>> ] bi* v. ]
+        [ [ transpose-axes x>> ] [ y>> ] bi* v. ]
+        [ [ transpose-axes y>> ] [ y>> ] bi* v. ]
         [ origin>> a.v ]
     } 2cleave
     [ [ 2array ] 2bi@ ] dip <affine-transform> ;
index 1a916c74f4aa79ef01c03a29b26982add1842006..6fe361b556c565ae6a39052a925fde8243909f57 100644 (file)
@@ -194,5 +194,5 @@ M: quadtree clear-assoc ( assoc -- )
 : swizzle ( sequence quot -- sequence' )
     [ dup ] dip map
     [ zip ] [ rect-containing <quadtree> ] bi
-    [ '[ first2 _ set-at ] each ] [ values ] bi ;
+    [ '[ first2 _ set-at ] each ] [ values ] bi ; inline
 
index 0f0c349b8ea761c6b91b393e61172bfb23180f41..932904eff40bcabecb522c9e2aaaca97d0a75843 100644 (file)
@@ -3,8 +3,8 @@ USING: accessors arrays literals math math.affine-transforms
 math.functions multiline sequences svg tools.test xml xml.traversal ;
 IN: svg.tests
 
-{ 1.0 2.25 } { -3.0 4.0 } { 5.5 0.000001 } <affine-transform> 1array [
-    "matrix ( 1 +2.25 -3  , 0.4e+1  ,5.5, 1e-6 )" svg-transform>affine-transform
+{ 1.0 2.25 } { -3.0 4.0 } { 5.5 0.5 } <affine-transform> 1array [
+    "matrix ( 1 +2.25 -3  , 0.4e+1  ,5.5, 5e-1 )" svg-transform>affine-transform
 ] unit-test
 
 { 1.0 0.0 } { 0.0 1.0 } { 5.0 10.0 } <affine-transform> 1array [
@@ -27,17 +27,22 @@ IN: svg.tests
     "scale(2.0 4.0)" svg-transform>affine-transform
 ] unit-test
 
-{ 1.0 0.0 } { $[ 45 degrees tan ] 1.0 } { 0.0 0.0 } <affine-transform> 1array [
+[ t ] [
     "skewX(45)" svg-transform>affine-transform
+    { 1.0 0.0 } { 1.0 1.0 } { 0.0 0.0 } <affine-transform> 0.001 a~
 ] unit-test
 
-{ 1.0 $[ -45 degrees tan ] } { 0.0 1.0 } { 0.0 0.0 } <affine-transform> 1array [
+[ t ] [
     "skewY(-4.5e1)" svg-transform>affine-transform
+    { 1.0 -1.0 } { 0.0 1.0 } { 0.0 0.0 } <affine-transform> 0.001 a~
 ] unit-test
 
-{ $[  30 degrees cos ] $[ 30 degrees sin ] }
-{ $[ -30 degrees sin ] $[ 30 degrees cos ] } { 0.0 0.0 } <affine-transform> 1array [
+[ t ] [
     "rotate(30)" svg-transform>affine-transform
+    { $[ 0.75 sqrt ] 0.5            }
+    { -0.5           $[ 0.75 sqrt ] }
+    {  0.0           0.0            } <affine-transform> 
+    0.001 a~
 ] unit-test
 
 [ t ] [