diff options
-rw-r--r-- | stdlib/source/lux/data/format/json.lux | 20 | ||||
-rw-r--r-- | stdlib/source/lux/lexer.lux | 34 | ||||
-rw-r--r-- | stdlib/source/lux/macro/syntax.lux | 2 | ||||
-rw-r--r-- | stdlib/source/lux/pipe.lux | 10 | ||||
-rw-r--r-- | stdlib/source/lux/regex.lux | 100 | ||||
-rw-r--r-- | stdlib/test/test/lux/lexer.lux | 349 | ||||
-rw-r--r-- | stdlib/test/test/lux/pipe.lux | 105 | ||||
-rw-r--r-- | stdlib/test/test/lux/regex.lux | 361 | ||||
-rw-r--r-- | stdlib/test/tests.lux | 7 |
9 files changed, 599 insertions, 389 deletions
diff --git a/stdlib/source/lux/data/format/json.lux b/stdlib/source/lux/data/format/json.lux index 280aab24b..e8189a594 100644 --- a/stdlib/source/lux/data/format/json.lux +++ b/stdlib/source/lux/data/format/json.lux @@ -217,19 +217,19 @@ (def: data-sep (Lexer [Text Char Text]) - ($_ lexer;seq space~ (lexer;this-char #",") space~)) + ($_ lexer;seq space~ (lexer;char #",") space~)) (def: null~ (Lexer Null) (do Monad<Lexer> - [_ (lexer;this "null")] + [_ (lexer;text "null")] (wrap []))) (do-template [<name> <token> <value>] [(def: <name> (Lexer Boolean) (do Monad<Lexer> - [_ (lexer;this <token>)] + [_ (lexer;text <token>)] (wrap <value>)))] [t~ "true" true] @@ -244,12 +244,12 @@ (Lexer Number) (do Monad<Lexer> [?sign (: (Lexer (Maybe Text)) - (lexer;opt (lexer;this "-"))) + (lexer;opt (lexer;text "-"))) digits (: (Lexer Text) (lexer;many' lexer;digit)) ?decimals (: (Lexer (Maybe Text)) (lexer;opt (do @ - [_ (lexer;this ".")] + [_ (lexer;text ".")] (lexer;many' lexer;digit))))] (case (: (Error Real) (Real/decode (format (default "" ?sign) @@ -290,9 +290,9 @@ (def: string~ (Lexer String) (do Monad<Lexer> - [_ (lexer;this "\"") + [_ (lexer;text "\"") string-body string-body~ - _ (lexer;this "\"")] + _ (lexer;text "\"")] (wrap string-body))) (def: (kv~ json~) @@ -300,7 +300,7 @@ (do Monad<Lexer> [key string~ _ space~ - _ (lexer;this-char #":") + _ (lexer;char #":") _ space~ value (json~ [])] (wrap [key value]))) @@ -309,11 +309,11 @@ [(def: (<name> json~) (-> (-> Unit (Lexer JSON)) (Lexer <type>)) (do Monad<Lexer> - [_ (lexer;this-char <open>) + [_ (lexer;char <open>) _ space~ elems (lexer;sep-by data-sep <elem-parser>) _ space~ - _ (lexer;this-char <close>)] + _ (lexer;char <close>)] (wrap (<prep> elems))))] [array~ Array #"[" #"]" (json~ []) vector;from-list] diff --git a/stdlib/source/lux/lexer.lux b/stdlib/source/lux/lexer.lux index 6d54f2614..e27e1925a 100644 --- a/stdlib/source/lux/lexer.lux +++ b/stdlib/source/lux/lexer.lux @@ -147,8 +147,8 @@ output output))) -(def: #export (assert test message) - (-> Bool Text (Lexer Unit)) +(def: #export (assert message test) + (-> Text Bool (Lexer Unit)) (lambda [input] (if test (#;Right [input []]) @@ -225,14 +225,14 @@ (#;Right [input (#;Some value)]) ))) -(def: #export (this text) +(def: #export (text test) (-> Text (Lexer Text)) (lambda [input] - (if (text;starts-with? text input) - (case (text;split (text;size text) input) + (if (text;starts-with? test input) + (case (text;split (text;size test) input) #;None (#;Left "") - (#;Some [_ input']) (#;Right [input' text])) - (#;Left (format "Invalid match: " text " @ " (:: text;Codec<Text,Text> encode input)))) + (#;Some [_ input']) (#;Right [input' test])) + (#;Left (format "Invalid match: " test " @ " (:: text;Codec<Text,Text> encode input)))) )) (def: #export (sep-by sep p) @@ -268,15 +268,15 @@ (#;Left "Can't peek character from empty text.")) )) -(def: #export (this-char char) +(def: #export (char test) (-> Char (Lexer Char)) (lambda [input] (case [(text;at +0 input) (text;split +1 input)] [(#;Some char') (#;Some [_ input'])] - (if (Char/= char char') - (#;Right [input' char]) - (#;Left (format "Expected " (:: char;Codec<Text,Char> encode char) " @ " (:: text;Codec<Text,Text> encode input) - " " (Int/encode (c2l char))" " (Int/encode (c2l [char']))))) + (if (Char/= test char') + (#;Right [input' test]) + (#;Left (format "Expected " (:: char;Codec<Text,Char> encode test) " @ " (:: text;Codec<Text,Text> encode input) + " " (Int/encode (c2l test))" " (Int/encode (c2l [char']))))) _ (#;Left "Can't parse character from empty text.")) @@ -292,9 +292,9 @@ (do Monad<Lexer> [input get-input char any - _ (assert (and (Char/>= bottom char) - (Char/<= top char)) - (format "Character is not within range: " (:: char;Codec<Text,Char> encode bottom) "-" (:: char;Codec<Text,Char> encode top) " @ " (:: text;Codec<Text,Text> encode input)))] + _ (assert (format "Character is not within range: " (:: char;Codec<Text,Char> encode bottom) "-" (:: char;Codec<Text,Char> encode top) " @ " (:: text;Codec<Text,Text> encode input)) + (and (Char/>= bottom char) + (Char/<= top char)))] (wrap char))) (do-template [<name> <bottom> <top>] @@ -434,6 +434,6 @@ (def: #export (enclosed [start end] lexer) (All [a] (-> [Text Text] (Lexer a) (Lexer a))) - (_& (this start) + (_& (text start) (&_ lexer - (this end)))) + (text end)))) diff --git a/stdlib/source/lux/macro/syntax.lux b/stdlib/source/lux/macro/syntax.lux index 00a2ba96e..ce36cef19 100644 --- a/stdlib/source/lux/macro/syntax.lux +++ b/stdlib/source/lux/macro/syntax.lux @@ -446,7 +446,7 @@ (wrap [(ast;symbol var-name) (` any)]) _ - (compiler;fail "Syntax pattern expects records or symbols.")))) + (compiler;fail "Syntax pattern expects tuples or symbols.")))) args) #let [g!state (ast;symbol ["" "*compiler*"]) g!end (ast;symbol ["" ""]) diff --git a/stdlib/source/lux/pipe.lux b/stdlib/source/lux/pipe.lux index 95167f7f2..5c553b7ec 100644 --- a/stdlib/source/lux/pipe.lux +++ b/stdlib/source/lux/pipe.lux @@ -31,13 +31,17 @@ _ (undefined))) -(syntax: #export (@> [body body^] +(syntax: #export (@> [name (s;default "@" s;local-symbol)] + [body body^] prev) {#;doc (doc "Gives the name '@' to the piped-argument, within the given expression." (|> 5 - (@> [(i.+ @ @)])))} + (@> [(i.+ @ @)])) + + (|> 5 + (@> X [(i.+ X X)])))} (wrap (list (fold (lambda [next prev] - (` (let% [(~' @) (~ prev)] + (` (let% [(~ (ast;symbol ["" name])) (~ prev)] (~ next)))) prev body)))) diff --git a/stdlib/source/lux/regex.lux b/stdlib/source/lux/regex.lux index 95599852c..e3cd95811 100644 --- a/stdlib/source/lux/regex.lux +++ b/stdlib/source/lux/regex.lux @@ -31,7 +31,7 @@ (def: escaped-char^ (Lexer Char) (do Monad<Lexer> - [? (&;opt (&;this-char #"\\")) + [? (&;opt (&;char #"\\")) char (case ? (#;Some _) &;any #;None regex-char^)] @@ -57,7 +57,7 @@ (def: #hidden word^ (Lexer Char) (&;either &;alpha-num - (&;this-char #"_"))) + (&;char #"_"))) (def: #hidden (join-text^ part^) (-> (Lexer (List Text)) (Lexer Text)) @@ -82,9 +82,9 @@ (do Monad<Lexer> [] ($_ &;either - (&;seq (wrap current-module) (&;_& (&;this ";;") identifier-part^)) - (&;seq identifier-part^ (&;_& (&;this ";") identifier-part^)) - (&;seq (wrap "lux") (&;_& (&;this ";") identifier-part^)) + (&;seq (wrap current-module) (&;_& (&;text ";;") identifier-part^)) + (&;seq identifier-part^ (&;_& (&;text ";") identifier-part^)) + (&;seq (wrap "lux") (&;_& (&;text ";") identifier-part^)) (&;seq (wrap "") identifier-part^)))) (def: (re-var^ current-module) @@ -97,7 +97,7 @@ (Lexer AST) (do Monad<Lexer> [from regex-char^ - _ (&;this-char #"-") + _ (&;char #"-") to regex-char^] (wrap (` (&;char-range (~ (ast;char from)) (~ (ast;char to))))))) @@ -105,7 +105,7 @@ (Lexer AST) (do Monad<Lexer> [char escaped-char^] - (wrap (` (&;this-char (~ (ast;char char))))))) + (wrap (` (&;char (~ (ast;char char))))))) (def: re-char+^ (Lexer AST) @@ -122,7 +122,7 @@ (def: re-user-class^' (Lexer AST) (do Monad<Lexer> - [negate? (&;opt (&;this-char #"^")) + [negate? (&;opt (&;char #"^")) parts (&;many ($_ &;either re-char-range^ re-char-options^))] @@ -135,7 +135,7 @@ (do Monad<Lexer> [_ (wrap []) init re-user-class^' - rest (&;some (&;_& (&;this "&&") (&;enclosed ["[" "]"] re-user-class^')))] + rest (&;some (&;_& (&;text "&&") (&;enclosed ["[" "]"] re-user-class^')))] (wrap (fold (lambda [refinement base] (` (refine^ (~ refinement) (~ base)))) init @@ -152,7 +152,7 @@ (def: #hidden control^ (Lexer Char) (&;either (&;char-range #"\u0000" #"\u001F") - (&;this-char #"\u007F"))) + (&;char #"\u007F"))) (def: #hidden punct^ (Lexer Char) @@ -165,36 +165,36 @@ (def: #hidden print^ (Lexer Char) (&;either graph^ - (&;this-char #"\u0020"))) + (&;char #"\u0020"))) (def: re-system-class^ (Lexer AST) (do Monad<Lexer> [] ($_ &;either - (&;_& (&;this-char #".") (wrap (` (->Text &;any)))) - (&;_& (&;this "\\d") (wrap (` (->Text &;digit)))) - (&;_& (&;this "\\D") (wrap (` (->Text (&;not &;digit))))) - (&;_& (&;this "\\s") (wrap (` (->Text &;space)))) - (&;_& (&;this "\\S") (wrap (` (->Text (&;not &;space))))) - (&;_& (&;this "\\w") (wrap (` (->Text word^)))) - (&;_& (&;this "\\W") (wrap (` (->Text (&;not word^))))) - (&;_& (&;this "\\d") (wrap (` (->Text &;digit)))) - - (&;_& (&;this "\\p{Lower}") (wrap (` (->Text &;lower)))) - (&;_& (&;this "\\p{Upper}") (wrap (` (->Text &;upper)))) - (&;_& (&;this "\\p{Alpha}") (wrap (` (->Text &;alpha)))) - (&;_& (&;this "\\p{Digit}") (wrap (` (->Text &;digit)))) - (&;_& (&;this "\\p{Alnum}") (wrap (` (->Text &;alpha-num)))) - (&;_& (&;this "\\p{Space}") (wrap (` (->Text &;space)))) - (&;_& (&;this "\\p{HexDigit}") (wrap (` (->Text &;hex-digit)))) - (&;_& (&;this "\\p{OctDigit}") (wrap (` (->Text &;oct-digit)))) - (&;_& (&;this "\\p{Blank}") (wrap (` (->Text blank^)))) - (&;_& (&;this "\\p{ASCII}") (wrap (` (->Text ascii^)))) - (&;_& (&;this "\\p{Contrl}") (wrap (` (->Text control^)))) - (&;_& (&;this "\\p{Punct}") (wrap (` (->Text punct^)))) - (&;_& (&;this "\\p{Graph}") (wrap (` (->Text graph^)))) - (&;_& (&;this "\\p{Print}") (wrap (` (->Text print^)))) + (&;_& (&;char #".") (wrap (` (->Text &;any)))) + (&;_& (&;text "\\d") (wrap (` (->Text &;digit)))) + (&;_& (&;text "\\D") (wrap (` (->Text (&;not &;digit))))) + (&;_& (&;text "\\s") (wrap (` (->Text &;space)))) + (&;_& (&;text "\\S") (wrap (` (->Text (&;not &;space))))) + (&;_& (&;text "\\w") (wrap (` (->Text word^)))) + (&;_& (&;text "\\W") (wrap (` (->Text (&;not word^))))) + (&;_& (&;text "\\d") (wrap (` (->Text &;digit)))) + + (&;_& (&;text "\\p{Lower}") (wrap (` (->Text &;lower)))) + (&;_& (&;text "\\p{Upper}") (wrap (` (->Text &;upper)))) + (&;_& (&;text "\\p{Alpha}") (wrap (` (->Text &;alpha)))) + (&;_& (&;text "\\p{Digit}") (wrap (` (->Text &;digit)))) + (&;_& (&;text "\\p{Alnum}") (wrap (` (->Text &;alpha-num)))) + (&;_& (&;text "\\p{Space}") (wrap (` (->Text &;space)))) + (&;_& (&;text "\\p{HexDigit}") (wrap (` (->Text &;hex-digit)))) + (&;_& (&;text "\\p{OctDigit}") (wrap (` (->Text &;oct-digit)))) + (&;_& (&;text "\\p{Blank}") (wrap (` (->Text blank^)))) + (&;_& (&;text "\\p{ASCII}") (wrap (` (->Text ascii^)))) + (&;_& (&;text "\\p{Contrl}") (wrap (` (->Text control^)))) + (&;_& (&;text "\\p{Punct}") (wrap (` (->Text punct^)))) + (&;_& (&;text "\\p{Graph}") (wrap (` (->Text graph^)))) + (&;_& (&;text "\\p{Print}") (wrap (` (->Text print^)))) ))) (def: re-class^ @@ -209,14 +209,14 @@ (def: re-back-reference^ (Lexer AST) (&;either (do Monad<Lexer> - [_ (&;this-char #"\\") + [_ (&;char #"\\") id int^] - (wrap (` (&;this (~ (ast;symbol ["" (Int/encode id)])))))) + (wrap (` (&;text (~ (ast;symbol ["" (Int/encode id)])))))) (do Monad<Lexer> - [_ (&;this "\\k<") + [_ (&;text "\\k<") captured-name identifier-part^ - _ (&;this ">")] - (wrap (` (&;this (~ (ast;symbol ["" captured-name])))))))) + _ (&;text ">")] + (wrap (` (&;text (~ (ast;symbol ["" captured-name])))))))) (def: (re-simple^ current-module) (-> Text (Lexer AST)) @@ -250,15 +250,15 @@ (&;enclosed ["{" "}"] ($_ &;either (do @ - [[from to] (&;seq int^ (&;_& (&;this-char #",") int^))] + [[from to] (&;seq int^ (&;_& (&;char #",") int^))] (wrap (` (join-text^ (&;between (~ (ast;nat (int-to-nat from))) (~ (ast;nat (int-to-nat to))) (~ base)))))) (do @ - [limit (&;_& (&;this-char #",") int^)] + [limit (&;_& (&;char #",") int^)] (wrap (` (join-text^ (&;at-most (~ (ast;nat (int-to-nat limit))) (~ base)))))) (do @ - [limit (&;&_ int^ (&;this-char #","))] + [limit (&;&_ int^ (&;char #","))] (wrap (` (join-text^ (&;at-least (~ (ast;nat (int-to-nat limit))) (~ base)))))) (do @ [limit int^] @@ -382,7 +382,7 @@ (do Monad<Lexer> [#let [sub^ (re-sequential^ capturing? re-scoped^ current-module)] head sub^ - tail (&;some (&;_& (&;this-char #"|") sub^)) + tail (&;some (&;_& (&;char #"|") sub^)) #let [g!op (if capturing? (` |||^) (` |||_^))]] @@ -395,24 +395,24 @@ (-> Text (Lexer [Re-Group AST])) ($_ &;either (do Monad<Lexer> - [_ (&;this "(?:") + [_ (&;text "(?:") [_ scoped] (re-alternative^ false re-scoped^ current-module) - _ (&;this-char #")")] + _ (&;char #")")] (wrap [#Non-Capturing scoped])) (do Monad<Lexer> [complex (re-complex^ current-module)] (wrap [#Non-Capturing complex])) (do Monad<Lexer> - [_ (&;this "(?<") + [_ (&;text "(?<") captured-name identifier-part^ - _ (&;this ">") + _ (&;text ">") [num-captures pattern] (re-alternative^ true re-scoped^ current-module) - _ (&;this-char #")")] + _ (&;char #")")] (wrap [(#Capturing [(#;Some captured-name) num-captures]) pattern])) (do Monad<Lexer> - [_ (&;this-char #"(") + [_ (&;char #"(") [num-captures pattern] (re-alternative^ true re-scoped^ current-module) - _ (&;this-char #")")] + _ (&;char #")")] (wrap [(#Capturing [#;None num-captures]) pattern])))) (def: (regex^ current-module) diff --git a/stdlib/test/test/lux/lexer.lux b/stdlib/test/test/lux/lexer.lux index d0b17fe4b..fc51deafd 100644 --- a/stdlib/test/test/lux/lexer.lux +++ b/stdlib/test/test/lux/lexer.lux @@ -4,130 +4,247 @@ ## You can obtain one at http://mozilla.org/MPL/2.0/. (;module: - [lux #- not] + lux (lux (control monad) (codata [io]) - (data error) - [test #- fail assert] - lexer)) + (data [error #- fail] + [text "T/" Eq<Text>] + text/format + [char "C/" Eq<Char>] + (struct [list])) + (math ["R" random]) + pipe + ["&" lexer]) + lux/test) + +## [Utils] +(def: (should-fail input) + (All [a] (-> (Error a) Bool)) + (case input + (#;Left _) true + _ false)) + +(def: (should-passC test input) + (-> Char (Error Char) Bool) + (case input + (#;Right output) + (C/= test output) + + _ + false)) + +(def: (should-passT test input) + (-> Text (Error Text) Bool) + (case input + (#;Right output) + (T/= test output) + + _ + false)) + +(def: (should-passL test input) + (-> (List Char) (Error (List Char)) Bool) + (let [(^open "L/") (list;Eq<List> char;Eq<Char>)] + (case input + (#;Right output) + (L/= test output) + + _ + false))) + +(def: (should-passE test input) + (-> (Either Char Char) (Error (Either Char Char)) Bool) + (case input + (#;Right output) + (case [test output] + [(#;Left test) (#;Left output)] + (C/= test output) + + [(#;Right test) (#;Right output)] + (C/= test output) + + _ + false) + + _ + false)) ## [Tests] -(test: "Lexer end works" - (test-all (should-pass (run end "")) - (should-fail (run end "YOLO")))) +(test: "End" + ($_ seq + (assert "Can detect the end of the input." + (|> (&;run &;end "") + (case> (#;Right _) true _ false))) + + (assert "Won't mistake non-empty text for no more input." + (|> (&;run &;end "YOLO") + (case> (#;Left _) true _ false))) + )) -(test: "Simple text lexers" - (test-all (match (#;Right "YO") - (run (this "YO") "YOLO")) - (should-fail (run (this "YO") "MEME")))) +(test: "Literals" + [size (|> R;nat (:: @ map (|>. (n.% +100) (n.max +10)))) + pre (R;text size) + post (|> (R;text size) + (R;filter (|>. (text;starts-with? pre) not)))] + ($_ seq + (assert "Can find literal text fragments." + (and (|> (&;run (&;text pre) (format pre post)) + (case> (#;Right found) (T/= pre found) _ false)) + (|> (&;run (&;text pre) post) + (case> (#;Left _) true _ false)))) + )) (test: "Char lexers" - (test-all (match (#;Right #"Y") - (run (this-char #"Y") "YOLO")) - (should-fail (run (this-char #"Y") "MEME")) - (match (#;Right #"Y") - (run (char-range #"X" #"Z") "YOLO")) - (should-fail (run (char-range #"X" #"Z") "MEME")) - (match (#;Right #"Y") - (run upper "YOLO")) - (should-fail (run upper "meme")) - (match (#;Right #"y") - (run lower "yolo")) - (should-fail (run lower "MEME")) - (match (#;Right #"1") - (run digit "1")) - (should-fail (run digit " ")) - (match (#;Right #"7") - (run oct-digit "7")) - (should-fail (run oct-digit "8")) - (match (#;Right #"A") - (run any "A")) - (should-fail (run any "")))) + ($_ seq + (assert "Can lex characters." + (and (|> (&;run (&;char #"Y") "YOLO") + (case> (#;Right #"Y") true _ false)) + (|> (&;run (&;char #"Y") "MEME") + (case> (#;Left _) true _ false)))) + + (assert "Can lex characters ranges." + (and (should-passC #"Y" (&;run (&;char-range #"X" #"Z") "YOLO")) + (should-fail (&;run (&;char-range #"X" #"Z") "MEME")))) + )) + +(test: "Custom lexers" + ($_ seq + (assert "Can lex anything" + (and (should-passC #"A" (&;run &;any "A")) + (should-fail (&;run &;any "")))) + + (assert "Can lex upper-case and &;lower-case letters." + (and (should-passC #"Y" (&;run &;upper "YOLO")) + (should-fail (&;run &;upper "meme")) + + (should-passC #"y" (&;run &;lower "yolo")) + (should-fail (&;run &;lower "MEME")))) + + (assert "Can lex numbers." + (and (should-passC #"1" (&;run &;digit "1")) + (should-fail (&;run &;digit " ")) + + (should-passC #"7" (&;run &;oct-digit "7")) + (should-fail (&;run &;oct-digit "8")) + + (should-passC #"1" (&;run &;hex-digit "1")) + (should-passC #"a" (&;run &;hex-digit "a")) + (should-passC #"A" (&;run &;hex-digit "A")) + (should-fail (&;run &;hex-digit " ")) + )) + + (assert "Can lex alphabetic characters." + (and (should-passC #"A" (&;run &;alpha "A")) + (should-passC #"a" (&;run &;alpha "a")) + (should-fail (&;run &;alpha "1")))) + + (assert "Can lex alphanumeric characters." + (and (should-passC #"A" (&;run &;alpha-num "A")) + (should-passC #"a" (&;run &;alpha-num "a")) + (should-passC #"1" (&;run &;alpha-num "1")) + (should-fail (&;run &;alpha-num " ")))) + + (assert "Can lex white-space." + (and (should-passC #" " (&;run &;space " ")) + (should-fail (&;run &;space "8")))) + )) (test: "Combinators" - (test-all (match (#;Right [#"Y" #"O"]) - (run (seq any any) "YOLO")) - (should-fail (run (seq any any) "Y")) - (match+ (#;Left #"0") - (should-pass (run (alt digit upper) "0"))) - (match+ (#;Right #"A") - (should-pass (run (alt digit upper) "A"))) - (should-fail (run (alt digit upper) "a")) - (should-pass (run (not (alt digit upper)) "a")) - (should-fail (run (not (alt digit upper)) "A")) - (match (#;Right #"0") - (run (either digit upper) "0")) - (match (#;Right #"A") - (run (either digit upper) "A")) - (should-fail (run (either digit upper) "a")) - (match (#;Right #"A") - (run alpha "A")) - (match (#;Right #"a") - (run alpha "a")) - (should-fail (run alpha "1")) - (match (#;Right #"A") - (run alpha-num "A")) - (match (#;Right #"a") - (run alpha-num "a")) - (match (#;Right #"1") - (run alpha-num "1")) - (should-fail (run alpha-num " ")) - (match (#;Right #"1") - (run hex-digit "1")) - (match (#;Right #"a") - (run hex-digit "a")) - (match (#;Right #"A") - (run hex-digit "A")) - (should-fail (run hex-digit " ")) - (match (#;Right #" ") - (run space " ")) - (should-fail (run space "8")) - (match (#;Right #"C") - (run (one-of "ABC") "C")) - (should-fail (run (one-of "ABC") "D")) - (match (#;Right #"D") - (run (none-of "ABC") "D")) - (should-fail (run (none-of "ABC") "C")) - (match (#;Right #"D") - (run (satisfies (lambda [c] true)) "D")) - (should-fail (run (satisfies (lambda [c] false)) "C")) - (match (#;Right "0123456789ABCDEF") - (run (many' hex-digit) "0123456789ABCDEF yolo")) - (should-fail (run (many' hex-digit) "yolo")) - (match (#;Right "") - (run (some' hex-digit) "yolo")) - )) + ($_ seq + (assert "Can combine lexers sequentially." + (and (|> (&;run (&;seq &;any &;any) "YOLO") + (case> (#;Right [#"Y" #"O"]) true + _ false)) + (should-fail (&;run (&;seq &;any &;any) "Y")))) + + (assert "Can combine lexers alternatively." + (and (should-passE (#;Left #"0") (&;run (&;alt &;digit &;upper) "0")) + (should-passE (#;Right #"A") (&;run (&;alt &;digit &;upper) "A")) + (should-fail (&;run (&;alt &;digit &;upper) "a")))) + + (assert "Can create the opposite of a lexer." + (and (should-passC #"a" (&;run (&;not (&;alt &;digit &;upper)) "a")) + (should-fail (&;run (&;not (&;alt &;digit &;upper)) "A")))) + + (assert "Can use either lexer." + (and (should-passC #"0" (&;run (&;either &;digit &;upper) "0")) + (should-passC #"A" (&;run (&;either &;digit &;upper) "A")) + (should-fail (&;run (&;either &;digit &;upper) "a")))) + + (assert "Can select from among a set of characters." + (and (should-passC #"C" (&;run (&;one-of "ABC") "C")) + (should-fail (&;run (&;one-of "ABC") "D")))) + + (assert "Can avoid a set of characters." + (and (should-passC #"D" (&;run (&;none-of "ABC") "D")) + (should-fail (&;run (&;none-of "ABC") "C")))) + + (assert "Can lex using arbitrary predicates." + (and (should-passC #"D" (&;run (&;satisfies (lambda [c] true)) "D")) + (should-fail (&;run (&;satisfies (lambda [c] false)) "C")))) + + (assert "Can apply a lexer multiple times." + (and (should-passT "0123456789ABCDEF" (&;run (&;many' &;hex-digit) "0123456789ABCDEF yolo")) + (should-fail (&;run (&;many' &;hex-digit) "yolo")) + + (should-passT "" (&;run (&;some' &;hex-digit) "yolo")))) + )) (test: "Yet more combinators..." - (test-all (should-fail (run (fail "Well, it really SHOULD fail...") "yolo")) - (should-fail (run (assert false "Well, it really SHOULD fail...") "yolo")) - (should-pass (run (assert true "GO, GO, GO!") "yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (many hex-digit) "0123456789ABCDEF yolo")) - (should-fail (run (many hex-digit) "yolo")) - (match (^ (#;Right (list))) - (run (some hex-digit) "yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (exactly +16 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2"))) - (run (exactly +3 hex-digit) "0123456789ABCDEF yolo")) - (should-fail (run (exactly +17 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (at-most +16 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2"))) - (run (at-most +3 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (at-most +17 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (between +0 +16 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (between +3 +16 hex-digit) "0123456789ABCDEF yolo")) - (should-fail (run (between +17 +100 hex-digit) "0123456789ABCDEF yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F"))) - (run (between +15 +20 hex-digit) "0123456789ABCDEF yolo")) - (match (#;Right (#;Some #"1")) (run (opt hex-digit) "123abc")) - (match (#;Right #;None) (run (opt hex-digit) "yolo")) - (match (^ (#;Right (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"a" #"b" #"c" #"d" #"e" #"f"))) - (run (sep-by space hex-digit) "0 1 2 3 4 5 6 7 8 9 a b c d e f YOLO")) - (match (#;Right "yolo") (run get-input "yolo")) - )) + ($_ seq + (assert "Can fail at will." + (should-fail (&;run (&;fail "Well, it really SHOULD fail...") "yolo"))) + + (assert "Can make assertions." + (and (should-fail (&;run (&;assert "Well, it really SHOULD fail..." false) "yolo")) + (|> (&;run (&;assert "GO, GO, GO!" true) "yolo") + (case> (#;Right []) true + _ false)))) + + (assert "Can apply a lexer multiple times." + (and (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;many &;hex-digit) "0123456789ABCDEF yolo")) + (should-fail (&;run (&;many &;hex-digit) "yolo")) + + (should-passL (list) + (&;run (&;some &;hex-digit) "yolo")))) + + (assert "Can lex exactly N elements." + (and (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;exactly +16 &;hex-digit) "0123456789ABCDEF yolo")) + (should-passL (list #"0" #"1" #"2") + (&;run (&;exactly +3 &;hex-digit) "0123456789ABCDEF yolo")) + (should-fail (&;run (&;exactly +17 &;hex-digit) "0123456789ABCDEF yolo")))) + + (assert "Can lex at-most N elements." + (and (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;at-most +16 &;hex-digit) "0123456789ABCDEF yolo")) + (should-passL (list #"0" #"1" #"2") + (&;run (&;at-most +3 &;hex-digit) "0123456789ABCDEF yolo")) + (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;at-most +17 &;hex-digit) "0123456789ABCDEF yolo")))) + + (assert "Can lex tokens between lower and upper boundaries of quantity." + (and (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;between +0 +16 &;hex-digit) "0123456789ABCDEF yolo")) + (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;between +3 +16 &;hex-digit) "0123456789ABCDEF yolo")) + (should-fail (&;run (&;between +17 +100 &;hex-digit) "0123456789ABCDEF yolo")) + (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"A" #"B" #"C" #"D" #"E" #"F") + (&;run (&;between +15 +20 &;hex-digit) "0123456789ABCDEF yolo")))) + + (assert "Can optionally lex a token." + (and (|> (&;run (&;opt &;hex-digit) "123abc") + (case> (#;Right (#;Some #"1")) true + _ false)) + (|> (&;run (&;opt &;hex-digit) "yolo") + (case> (#;Right #;None) true + _ false)))) + + (assert "Can take into account separators during lexing." + (should-passL (list #"0" #"1" #"2" #"3" #"4" #"5" #"6" #"7" #"8" #"9" #"a" #"b" #"c" #"d" #"e" #"f") + (&;run (&;sep-by &;space &;hex-digit) "0 1 2 3 4 5 6 7 8 9 a b c d e f YOLO"))) + + (assert "Can obtain the whole of the remaining input." + (should-passT "yolo" (&;run &;get-input "yolo"))) + )) diff --git a/stdlib/test/test/lux/pipe.lux b/stdlib/test/test/lux/pipe.lux index 681c4bf71..92ca205b8 100644 --- a/stdlib/test/test/lux/pipe.lux +++ b/stdlib/test/test/lux/pipe.lux @@ -1,3 +1,8 @@ +## Copyright (c) Eduardo Julian. All rights reserved. +## This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +## If a copy of the MPL was not distributed with this file, +## You can obtain one at http://mozilla.org/MPL/2.0/. + (;module: lux (lux (codata [io]) @@ -5,43 +10,71 @@ (data text/format [number] [product] - identity) + identity + [text "T/" Eq<Text>]) (codata function) + (math ["R" random]) pipe) lux/test) -(test: "lux/pipe exports" - (test-all (match 1 (|> 20 - (i.* 3) - (i.+ 4) - (_> 0 i.inc))) - (match 10 (|> 5 - (@> [(i.+ @ @)]))) - (match 15 (|> 5 - (?> [i.even?] [(i.* 2)] - [i.odd?] [(i.* 3)] - [(_> -1)]))) - (match 15 (|> 5 - (?> [i.even?] [(i.* 2)] - [i.odd?] [(i.* 3)]))) - (match 10 (|> 1 - (!> [(i.< 10)] - [i.inc]))) - (match 20 (|> 5 - (%> Monad<Identity> - [(i.* 3)] - [(i.+ 4)] - [i.inc]))) - (match "five" (|> 5 - (case> 0 "zero" - 1 "one" - 2 "two" - 3 "three" - 4 "four" - 5 "five" - 6 "six" - 7 "seven" - 8 "eight" - 9 "nine" - _ "???"))) - )) +(test: "Pipes" + ($_ seq + (assert "Can dismiss previous pipeline results and begin a new line." + (|> 20 + (i.* 3) + (i.+ 4) + (_> 0 i.inc) + (i.= 1))) + + (assert "Can give names to piped values within a pipeline's scope." + (and (|> 5 + (@> [(i.+ @ @)]) + (i.= 10)) + (|> 5 + (@> X [(i.+ X X)]) + (i.= 10)))) + + (assert "Can do branching in pipelines." + (and (|> 5 + (?> [i.even?] [(i.* 2)] + [i.odd?] [(i.* 3)] + [(_> -1)]) + (i.= 15)) + (|> 4 + (?> [i.even?] [(i.* 2)] + [i.odd?] [(i.* 3)]) + (i.= 8)) + (|> 5 + (?> [i.even?] [(i.* 2)] + [(_> -1)]) + (i.= -1)))) + + (assert "Can loop within pipelines." + (|> 1 + (!> [(i.< 10)] + [i.inc]) + (i.= 10))) + + (assert "Can use monads within pipelines." + (|> 5 + (%> Monad<Identity> + [(i.* 3)] + [(i.+ 4)] + [i.inc]) + (i.= 20))) + + (assert "Can pattern-match against piped values." + (|> 5 + (case> 0 "zero" + 1 "one" + 2 "two" + 3 "three" + 4 "four" + 5 "five" + 6 "six" + 7 "seven" + 8 "eight" + 9 "nine" + _ "???") + (T/= "five"))) + )) diff --git a/stdlib/test/test/lux/regex.lux b/stdlib/test/test/lux/regex.lux index 66355bdca..bb366ac90 100644 --- a/stdlib/test/test/lux/regex.lux +++ b/stdlib/test/test/lux/regex.lux @@ -7,194 +7,251 @@ lux (lux (codata [io]) (control monad) - (data error - [product]) + (data [error #- fail] + [product] + [text "T/" Eq<Text>] + text/format) [compiler] (macro [ast] ["s" syntax #+ syntax:]) - test + (math ["R" random]) + pipe [lexer] - regex)) - -(syntax: (should-regex {veredict (s;alt s;bool s;any)} {regex s;text} {input s;text}) - (case veredict - (+0 ?) - (if ? - (wrap (list (` (match+ (~ (ast;text input)) - (should-pass (lexer;run (regex (~ (ast;text regex))) - (~ (ast;text input)))))))) - (wrap (list (` (should-fail (lexer;run (regex (~ (ast;text regex))) - (~ (ast;text input)))))))) - - (+1 result) - (wrap (list (` (match+ (~ result) - (should-pass (lexer;run (regex (~ (ast;text regex))) - (~ (ast;text input)))))))))) + ["&" regex]) + lux/test) -## [Tests] -(test: "Regular Expressions [Basics]" - (test-all (should-regex true "a" "a") - (should-regex false "a" ".") - (should-regex true "\\." ".") - (should-regex false "\\." "a") - )) +## [Utils] +(def: (should-pass regex input) + (-> (lexer;Lexer Text) Text Bool) + (|> (lexer;run regex input) + (case> (#;Right parsed) + (T/= parsed input) -(test: "Regular Expressions [System character classes]" - (test-all (should-regex true "." "a") + _ + false))) - (should-regex true "\\d" "0") - (should-regex false "\\d" "m") - (should-regex true "\\D" "m") - (should-regex false "\\D" "0") +(def: (should-passT test regex input) + (-> Text (lexer;Lexer Text) Text Bool) + (|> (lexer;run regex input) + (case> (#;Right parsed) + (T/= test parsed) - (should-regex true "\\s" " ") - (should-regex false "\\s" "m") - (should-regex true "\\S" "m") - (should-regex false "\\S" " ") + _ + false))) - (should-regex true "\\w" "_") - (should-regex false "\\w" "^") - (should-regex true "\\W" ".") - (should-regex false "\\W" "a") +(def: (should-fail regex input) + (All [a] (-> (lexer;Lexer a) Text Bool)) + (|> (lexer;run regex input) + (case> (#;Left _) true _ false))) - (should-regex true "\\p{Lower}" "m") - (should-regex false "\\p{Lower}" "M") +(syntax: (should-check pattern regex input) + (wrap (list (` (|> (lexer;run (~ regex) (~ input)) + (case> (^ (#;Right (~ pattern))) + true - (should-regex true "\\p{Upper}" "M") - (should-regex false "\\p{Upper}" "m") + (~' _) + false)))))) - (should-regex true "\\p{Alpha}" "M") - (should-regex false "\\p{Alpha}" "0") +## [Tests] +(test: "Regular Expressions [Basics]" + (assert "Can parse character literals." + (and (should-pass (&;regex "a") "a") + (should-fail (&;regex "a") ".") + (should-pass (&;regex "\\.") ".") + (should-fail (&;regex "\\.") "a")))) - (should-regex true "\\p{Digit}" "1") - (should-regex false "\\p{Digit}" "n") +(test: "Regular Expressions [System character classes]" + ($_ seq + (assert "Can parse anything." + (should-pass (&;regex ".") "a")) - (should-regex true "\\p{Alnum}" "1") - (should-regex false "\\p{Alnum}" ".") + (assert "Can parse digits." + (and (should-pass (&;regex "\\d") "0") + (should-fail (&;regex "\\d") "m"))) + + (assert "Can parse non digits." + (and (should-pass (&;regex "\\D") "m") + (should-fail (&;regex "\\D") "0"))) - (should-regex true "\\p{Space}" " ") - (should-regex false "\\p{Space}" ".") + (assert "Can parse white-space." + (and (should-pass (&;regex "\\s") " ") + (should-fail (&;regex "\\s") "m"))) + + (assert "Can parse non white-space." + (and (should-pass (&;regex "\\S") "m") + (should-fail (&;regex "\\S") " "))) - (should-regex true "\\p{HexDigit}" "a") - (should-regex false "\\p{HexDigit}" ".") + (assert "Can parse word characters." + (and (should-pass (&;regex "\\w") "_") + (should-fail (&;regex "\\w") "^"))) + + (assert "Can parse non word characters." + (and (should-pass (&;regex "\\W") ".") + (should-fail (&;regex "\\W") "a"))) - (should-regex true "\\p{OctDigit}" "6") - (should-regex false "\\p{OctDigit}" ".") + (assert "Can parse using special character classes." + (and (and (should-pass (&;regex "\\p{Lower}") "m") + (should-fail (&;regex "\\p{Lower}") "M")) - (should-regex true "\\p{Blank}" "\t") - (should-regex false "\\p{Blank}" ".") + (and (should-pass (&;regex "\\p{Upper}") "M") + (should-fail (&;regex "\\p{Upper}") "m")) - (should-regex true "\\p{ASCII}" "\t") - (should-regex false "\\p{ASCII}" "\u1234") + (and (should-pass (&;regex "\\p{Alpha}") "M") + (should-fail (&;regex "\\p{Alpha}") "0")) - (should-regex true "\\p{Contrl}" "\u0012") - (should-regex false "\\p{Contrl}" "a") + (and (should-pass (&;regex "\\p{Digit}") "1") + (should-fail (&;regex "\\p{Digit}") "n")) - (should-regex true "\\p{Punct}" "@") - (should-regex false "\\p{Punct}" "a") + (and (should-pass (&;regex "\\p{Alnum}") "1") + (should-fail (&;regex "\\p{Alnum}") ".")) - (should-regex true "\\p{Graph}" "@") - (should-regex false "\\p{Graph}" " ") + (and (should-pass (&;regex "\\p{Space}") " ") + (should-fail (&;regex "\\p{Space}") ".")) - (should-regex true "\\p{Print}" "\u0020") - (should-regex false "\\p{Print}" "\u1234") - )) + (and (should-pass (&;regex "\\p{HexDigit}") "a") + (should-fail (&;regex "\\p{HexDigit}") ".")) -(test: "Regular Expressions [Custom character classes]" - (test-all (should-regex true "[abc]" "a") - (should-regex false "[abc]" "m") + (and (should-pass (&;regex "\\p{OctDigit}") "6") + (should-fail (&;regex "\\p{OctDigit}") ".")) - (should-regex true "[a-z]" "a") - (should-regex true "[a-z]" "m") - (should-regex true "[a-z]" "z") + (and (should-pass (&;regex "\\p{Blank}") "\t") + (should-fail (&;regex "\\p{Blank}") ".")) - (should-regex true "[a-zA-Z]" "a") - (should-regex true "[a-zA-Z]" "m") - (should-regex true "[a-zA-Z]" "z") - (should-regex true "[a-zA-Z]" "A") - (should-regex true "[a-zA-Z]" "M") - (should-regex true "[a-zA-Z]" "Z") + (and (should-pass (&;regex "\\p{ASCII}") "\t") + (should-fail (&;regex "\\p{ASCII}") "\u1234")) - (should-regex false "[^abc]" "a") - (should-regex true "[^abc]" "m") + (and (should-pass (&;regex "\\p{Contrl}") "\u0012") + (should-fail (&;regex "\\p{Contrl}") "a")) - (should-regex false "[^a-z]" "a") - (should-regex true "[^a-z]" "0") - (should-regex false "[^a-zA-Z]" "a") - (should-regex true "[^a-zA-Z]" "0") + (and (should-pass (&;regex "\\p{Punct}") "@") + (should-fail (&;regex "\\p{Punct}") "a")) - (should-regex false "[a-z&&[def]]" "a") - (should-regex true "[a-z&&[def]]" "d") + (and (should-pass (&;regex "\\p{Graph}") "@") + (should-fail (&;regex "\\p{Graph}") " ")) - (should-regex true "[a-z&&[^bc]]" "a") - (should-regex false "[a-z&&[^bc]]" "b") + (and (should-pass (&;regex "\\p{Print}") "\u0020") + (should-fail (&;regex "\\p{Print}") "\u1234")))) + )) - (should-regex true "[a-z&&[^m-p]]" "a") - (should-regex false "[a-z&&[^m-p]]" "m") - (should-regex false "[a-z&&[^m-p]]" "p") - )) +(test: "Regular Expressions [Custom character classes]" + ($_ seq + (assert "Can parse using custom character classes." + (and (should-pass (&;regex "[abc]") "a") + (should-fail (&;regex "[abc]") "m"))) + + (assert "Can parse using character ranges." + (and (should-pass (&;regex "[a-z]") "a") + (should-pass (&;regex "[a-z]") "m") + (should-pass (&;regex "[a-z]") "z"))) + + (assert "Can combine character ranges." + (and (should-pass (&;regex "[a-zA-Z]") "a") + (should-pass (&;regex "[a-zA-Z]") "m") + (should-pass (&;regex "[a-zA-Z]") "z") + (should-pass (&;regex "[a-zA-Z]") "A") + (should-pass (&;regex "[a-zA-Z]") "M") + (should-pass (&;regex "[a-zA-Z]") "Z"))) + + (assert "Can negate custom character classes." + (and (should-fail (&;regex "[^abc]") "a") + (should-pass (&;regex "[^abc]") "m"))) + + (assert "Can negate character ranges.." + (and (should-fail (&;regex "[^a-z]") "a") + (should-pass (&;regex "[^a-z]") "0"))) + + (assert "Can parse negate combinations of character ranges." + (and (should-fail (&;regex "[^a-zA-Z]") "a") + (should-pass (&;regex "[^a-zA-Z]") "0"))) + + (assert "Can make custom character classes more specific." + (and (and (should-fail (&;regex "[a-z&&[def]]") "a") + (should-pass (&;regex "[a-z&&[def]]") "d")) + + (and (should-pass (&;regex "[a-z&&[^bc]]") "a") + (should-fail (&;regex "[a-z&&[^bc]]") "b")) + + (and (should-pass (&;regex "[a-z&&[^m-p]]") "a") + (should-fail (&;regex "[a-z&&[^m-p]]") "m") + (should-fail (&;regex "[a-z&&[^m-p]]") "p")))) + )) (test: "Regular Expressions [Reference]" - (test-all (let [number (regex "\\d+")] - (should-regex ["809-345-6789" "809" "345" "6789"] "(\\@<number>)-(\\@<number>)-(\\@<number>)" "809-345-6789")) - )) + (let [number (&;regex "\\d+")] + (assert "Can build complex regexs by combining simpler ones." + (should-check ["809-345-6789" "809" "345" "6789"] (&;regex "(\\@<number>)-(\\@<number>)-(\\@<number>)") "809-345-6789")))) (test: "Regular Expressions [Quantifiers]" - (test-all (should-regex "aa" "aa" "aa") - - (should-regex "a" "a?" "a") - (should-regex "" "a?" "") - - (should-regex "aaa" "a*" "aaa") - (should-regex "" "a*" "") - - (should-regex "aaa" "a+" "aaa") - (should-regex "a" "a+" "a") - (should-regex false "a+" "") - - (should-regex "aa" "a{2}" "aa") - (should-regex "a" "a{1}" "aa") - (should-regex false "a{3}" "aa") - - (should-regex "aa" "a{1,}" "aa") - (should-regex "aa" "a{2,}" "aa") - (should-regex false "a{3,}" "aa") - - (should-regex "a" "a{,1}" "aa") - (should-regex "aa" "a{,2}" "aa") - (should-regex "aa" "a{,3}" "aa") - - (should-regex "a" "a{1,2}" "a") - (should-regex "aa" "a{1,2}" "aa") - (should-regex "aa" "a{1,2}" "aaa") - )) + ($_ seq + (assert "Can sequentially combine patterns." + (should-passT "aa" (&;regex "aa") "aa")) + + (assert "Can match patterns optionally." + (and (should-passT "a" (&;regex "a?") "a") + (should-passT "" (&;regex "a?") ""))) + + (assert "Can match a pattern 0 or more times." + (and (should-passT "aaa" (&;regex "a*") "aaa") + (should-passT "" (&;regex "a*") ""))) + + (assert "Can match a pattern 1 or more times." + (and (should-passT "aaa" (&;regex "a+") "aaa") + (should-passT "a" (&;regex "a+") "a") + (should-fail (&;regex "a+") ""))) + + (assert "Can match a pattern N times." + (and (should-passT "aa" (&;regex "a{2}") "aa") + (should-passT "a" (&;regex "a{1}") "aa") + (should-fail (&;regex "a{3}") "aa"))) + + (assert "Can match a pattern at-least N times." + (and (should-passT "aa" (&;regex "a{1,}") "aa") + (should-passT "aa" (&;regex "a{2,}") "aa") + (should-fail (&;regex "a{3,}") "aa"))) + + (assert "Can match a pattern at-most N times." + (and (should-passT "a" (&;regex "a{,1}") "aa") + (should-passT "aa" (&;regex "a{,2}") "aa") + (should-passT "aa" (&;regex "a{,3}") "aa"))) + + (assert "Can match a pattern between N and M times." + (and (should-passT "a" (&;regex "a{1,2}") "a") + (should-passT "aa" (&;regex "a{1,2}") "aa") + (should-passT "aa" (&;regex "a{1,2}") "aaa"))) + )) (test: "Regular Expressions [Groups]" - (test-all (should-regex ["abc" "b"] "a(.)c" "abc") - (should-regex ["abbbbbc" "bbbbb"] "a(b+)c" "abbbbbc") - (should-regex ["809-345-6789" "809" "345" "6789"] "(\\d{3})-(\\d{3})-(\\d{4})" "809-345-6789") - (should-regex ["809-345-6789" "809" "6789"] "(\\d{3})-(?:\\d{3})-(\\d{4})" "809-345-6789") - (should-regex ["809-809-6789" "809" "6789"] "(\\d{3})-\\0-(\\d{4})" "809-809-6789") - (should-regex ["809-809-6789" "809" "6789"] "(?<code>\\d{3})-\\k<code>-(\\d{4})" "809-809-6789") - (should-regex ["809-809-6789-6789" "809" "6789"] "(?<code>\\d{3})-\\k<code>-(\\d{4})-\\0" "809-809-6789-6789") - - (should-regex ["809-345-6789" "809" ["345-6789" "345" "6789"]] "(\\d{3})-((\\d{3})-(\\d{4}))" "809-345-6789") - )) + ($_ seq + (assert "Can extract groups of sub-matches specified in a pattern." + (and (should-check ["abc" "b"] (&;regex "a(.)c") "abc") + (should-check ["abbbbbc" "bbbbb"] (&;regex "a(b+)c") "abbbbbc") + (should-check ["809-345-6789" "809" "345" "6789"] (&;regex "(\\d{3})-(\\d{3})-(\\d{4})") "809-345-6789") + (should-check ["809-345-6789" "809" "6789"] (&;regex "(\\d{3})-(?:\\d{3})-(\\d{4})") "809-345-6789") + (should-check ["809-809-6789" "809" "6789"] (&;regex "(\\d{3})-\\0-(\\d{4})") "809-809-6789") + (should-check ["809-809-6789" "809" "6789"] (&;regex "(?<code>\\d{3})-\\k<code>-(\\d{4})") "809-809-6789") + (should-check ["809-809-6789-6789" "809" "6789"] (&;regex "(?<code>\\d{3})-\\k<code>-(\\d{4})-\\0") "809-809-6789-6789"))) + + (assert "Can specify groups within groups." + (should-check ["809-345-6789" "809" ["345-6789" "345" "6789"]] (&;regex "(\\d{3})-((\\d{3})-(\\d{4}))") "809-345-6789")) + )) (test: "Regular Expressions [Alternation]" - (test-all (should-regex ["a" (+0 [])] "a|b" "a") - (should-regex ["b" (+1 [])] "a|b" "b") - (should-regex false "a|b" "c") - - (should-regex ["abc" (+0 "b")] "a(.)c|b(.)d" "abc") - (should-regex ["bcd" (+1 "c")] "a(.)c|b(.)d" "bcd") - (should-regex false "a(.)c|b(.)d" "cde") - - (should-regex ["abc" (+0 ["b" "c"])] "a(.)(.)|b(.)(.)" "abc") - (should-regex ["bcd" (+1 ["c" "d"])] "a(.)(.)|b(.)(.)" "bcd") - (should-regex false "a(.)(.)|b(.)(.)" "cde") - - (should-regex ["809-345-6789" (+0 ["809" "345-6789" "345" "6789"])] - "(\\d{3})-((\\d{3})-(\\d{4}))|b(.)d" - "809-345-6789") - )) + ($_ seq + (assert "Can specify alternative patterns." + (and (should-check ["a" (+0 [])] (&;regex "a|b") "a") + (should-check ["b" (+1 [])] (&;regex "a|b") "b") + (should-fail (&;regex "a|b") "c"))) + + (assert "Can have groups within alternations." + (and (should-check ["abc" (+0 "b")] (&;regex "a(.)c|b(.)d") "abc") + (should-check ["bcd" (+1 "c")] (&;regex "a(.)c|b(.)d") "bcd") + (should-fail (&;regex "a(.)c|b(.)d") "cde") + + (should-check ["abc" (+0 ["b" "c"])] (&;regex "a(.)(.)|b(.)(.)") "abc") + (should-check ["bcd" (+1 ["c" "d"])] (&;regex "a(.)(.)|b(.)(.)") "bcd") + (should-fail (&;regex "a(.)(.)|b(.)(.)") "cde") + + (should-check ["809-345-6789" (+0 ["809" "345-6789" "345" "6789"])] + (&;regex "(\\d{3})-((\\d{3})-(\\d{4}))|b(.)d") + "809-345-6789"))) + )) diff --git a/stdlib/test/tests.lux b/stdlib/test/tests.lux index 4b46a7cd5..857d5c25c 100644 --- a/stdlib/test/tests.lux +++ b/stdlib/test/tests.lux @@ -13,6 +13,9 @@ (test lux (lux ["_;" cli] ["_;" host] + ["_;" pipe] + ["_;" lexer] + ["_;" regex] (codata ["_;" io] [env] [state] @@ -52,10 +55,6 @@ ## ["_;" random] ["_;" simple] ) - ## ["_;" pipe] - ## ["_;" lexer] - ## ["_;" regex] - ## (macro [ast] ## [syntax]) ## [type] |