aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--stdlib/source/test/lux.lux6
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/case.lux198
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/function.lux118
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/primitive.lux100
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/procedure/common.lux187
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/reference.lux107
-rw-r--r--stdlib/source/test/lux/compiler/default/phase/analysis/structure.lux297
-rw-r--r--stdlib/source/test/lux/tool.lux13
-rw-r--r--stdlib/source/test/lux/tool/compiler/default/syntax.lux30
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis.lux24
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis/case.lux201
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis/function.lux125
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis/primitive.lux108
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis/reference.lux106
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/analysis/structure.lux303
-rw-r--r--stdlib/source/test/lux/tool/compiler/phase/extension/analysis/common.lux202
16 files changed, 1088 insertions, 1037 deletions
diff --git a/stdlib/source/test/lux.lux b/stdlib/source/test/lux.lux
index 77f0e1bbd..bad2e5500 100644
--- a/stdlib/source/test/lux.lux
+++ b/stdlib/source/test/lux.lux
@@ -18,6 +18,7 @@
["." io (#+ io)]
["." function]]
[data
+ ["." name]
[number
["." i64]]]
["." math]
@@ -296,7 +297,7 @@
on-default))))))
(def: test
- (<| (_.context (%name (name-of /._)))
+ (<| (_.context (name.module (name-of /._)))
($_ _.and
(<| (_.context "Identity.")
..identity)
@@ -348,8 +349,7 @@
/math.test
(<| (_.context "/time")
/time.test)
- (<| (_.context "/tool")
- /tool.test)
+ /tool.test
/type.test
/world.test
(<| (_.context "/host")
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/case.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/case.lux
deleted file mode 100644
index 5c47960c1..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/case.lux
+++ /dev/null
@@ -1,198 +0,0 @@
-(.module:
- [lux #*
- [control
- ["." monad (#+ do)]
- pipe]
- [data
- ["." product]
- ["." maybe]
- ["." text ("#;." equivalence)]
- [collection
- ["." list ("#;." monad)]
- ["." set]]]
- [math
- ["r" random ("#;." monad)]]
- ["." type
- ["." check]]
- [macro
- ["." code]]
- [compiler
- [default
- ["." phase
- ["." analysis
- ["." module]
- [".A" type]
- ["/" case]]]]]
- test]
- [//
- ["_." primitive]
- ["_." structure]])
-
-(def: (exhaustive-weaving branchings)
- (-> (List (List Code)) (List (List Code)))
- (case branchings
- #.Nil
- #.Nil
-
- (#.Cons head+ #.Nil)
- (list;map (|>> list) head+)
-
- (#.Cons head+ tail++)
- (do list.monad
- [tail+ (exhaustive-weaving tail++)
- head head+]
- (wrap (#.Cons head tail+)))))
-
-(def: #export (exhaustive-branches allow-literals? variantTC inputC)
- (-> Bit (List [Code Code]) Code (r.Random (List Code)))
- (case inputC
- [_ (#.Bit _)]
- (r;wrap (list (' #1) (' #0)))
-
- (^template [<tag> <gen> <wrapper>]
- [_ (<tag> _)]
- (if allow-literals?
- (do r.monad
- [?sample (r.maybe <gen>)]
- (case ?sample
- (#.Some sample)
- (do @
- [else (exhaustive-branches allow-literals? variantTC inputC)]
- (wrap (list& (<wrapper> sample) else)))
-
- #.None
- (wrap (list (' _)))))
- (r;wrap (list (' _)))))
- ([#.Nat r.nat code.nat]
- [#.Int r.int code.int]
- [#.Rev r.rev code.rev]
- [#.Frac r.frac code.frac]
- [#.Text (r.unicode 5) code.text])
-
- (^ [_ (#.Tuple (list))])
- (r;wrap (list (' [])))
-
- (^ [_ (#.Record (list))])
- (r;wrap (list (' {})))
-
- [_ (#.Tuple members)]
- (do r.monad
- [member-wise-patterns (monad.map @ (exhaustive-branches allow-literals? variantTC) members)]
- (wrap (|> member-wise-patterns
- exhaustive-weaving
- (list;map code.tuple))))
-
- [_ (#.Record kvs)]
- (do r.monad
- [#let [ks (list;map product.left kvs)
- vs (list;map product.right kvs)]
- member-wise-patterns (monad.map @ (exhaustive-branches allow-literals? variantTC) vs)]
- (wrap (|> member-wise-patterns
- exhaustive-weaving
- (list;map (|>> (list.zip2 ks) code.record)))))
-
- (^ [_ (#.Form (list [_ (#.Tag _)] _))])
- (do r.monad
- [bundles (monad.map @
- (function (_ [_tag _code])
- (do @
- [v-branches (exhaustive-branches allow-literals? variantTC _code)]
- (wrap (list;map (function (_ pattern) (` ((~ _tag) (~ pattern))))
- v-branches))))
- variantTC)]
- (wrap (list;join bundles)))
-
- _
- (r;wrap (list))
- ))
-
-(def: #export (input variant-tags record-tags primitivesC)
- (-> (List Code) (List Code) (List Code) (r.Random Code))
- (r.rec
- (function (_ input)
- ($_ r.either
- (r;map product.right _primitive.primitive)
- (do r.monad
- [choice (|> r.nat (:: @ map (n/% (list.size variant-tags))))
- #let [choiceT (maybe.assume (list.nth choice variant-tags))
- choiceC (maybe.assume (list.nth choice primitivesC))]]
- (wrap (` ((~ choiceT) (~ choiceC)))))
- (do r.monad
- [size (|> r.nat (:: @ map (n/% 3)))
- elems (r.list size input)]
- (wrap (code.tuple elems)))
- (r;wrap (code.record (list.zip2 record-tags primitivesC)))
- ))))
-
-(def: (branch body pattern)
- (-> Code Code [Code Code])
- [pattern body])
-
-(context: "Pattern-matching."
- ## #seed 9253409297339902486
- ## #seed 3793366152923578600
- (<| (seed 5004137551292836565)
- ## (times 100)
- (do @
- [module-name (r.unicode 5)
- variant-name (r.unicode 5)
- record-name (|> (r.unicode 5) (r.filter (|>> (text;= variant-name) not)))
- size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- variant-tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
- record-tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
- primitivesTC (r.list size _primitive.primitive)
- #let [primitivesT (list;map product.left primitivesTC)
- primitivesC (list;map product.right primitivesTC)
- code-tag (|>> [module-name] code.tag)
- variant-tags+ (list;map code-tag variant-tags)
- record-tags+ (list;map code-tag record-tags)
- variantTC (list.zip2 variant-tags+ primitivesC)]
- inputC (input variant-tags+ record-tags+ primitivesC)
- [outputT outputC] _primitive.primitive
- [heterogeneousT heterogeneousC] (r.filter (|>> product.left (check.checks? outputT) not)
- _primitive.primitive)
- exhaustive-patterns (exhaustive-branches #1 variantTC inputC)
- redundant-patterns (exhaustive-branches #0 variantTC inputC)
- redundancy-idx (|> r.nat (:: @ map (n/% (list.size redundant-patterns))))
- heterogeneous-idx (|> r.nat (:: @ map (n/% (list.size exhaustive-patterns))))
- #let [exhaustive-branchesC (list;map (branch outputC)
- exhaustive-patterns)
- non-exhaustive-branchesC (list.take (dec (list.size exhaustive-branchesC))
- exhaustive-branchesC)
- redundant-branchesC (<| (list;map (branch outputC))
- list.concat
- (list (list.take redundancy-idx redundant-patterns)
- (list (maybe.assume (list.nth redundancy-idx redundant-patterns)))
- (list.drop redundancy-idx redundant-patterns)))
- heterogeneous-branchesC (list.concat (list (list.take heterogeneous-idx exhaustive-branchesC)
- (list (let [[_pattern _body] (maybe.assume (list.nth heterogeneous-idx exhaustive-branchesC))]
- [_pattern heterogeneousC]))
- (list.drop (inc heterogeneous-idx) exhaustive-branchesC)))
- analyse-pm (|>> (/.case _primitive.phase inputC)
- (typeA.with-type outputT)
- analysis.with-scope
- (do phase.monad
- [_ (module.declare-tags variant-tags #0
- (#.Named [module-name variant-name]
- (type.variant primitivesT)))
- _ (module.declare-tags record-tags #0
- (#.Named [module-name record-name]
- (type.tuple primitivesT)))])
- (module.with-module 0 module-name))]]
- ($_ seq
- (test "Will reject empty pattern-matching (no branches)."
- (|> (analyse-pm (list))
- _structure.check-fails))
- (test "Can analyse exhaustive pattern-matching."
- (|> (analyse-pm exhaustive-branchesC)
- _structure.check-succeeds))
- (test "Will reject non-exhaustive pattern-matching."
- (|> (analyse-pm non-exhaustive-branchesC)
- _structure.check-fails))
- (test "Will reject redundant pattern-matching."
- (|> (analyse-pm redundant-branchesC)
- _structure.check-fails))
- (test "Will reject pattern-matching if the bodies of the branches do not all have the same type."
- (|> (analyse-pm heterogeneous-branchesC)
- _structure.check-fails)))
- )))
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/function.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/function.lux
deleted file mode 100644
index acdb9e7ff..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/function.lux
+++ /dev/null
@@ -1,118 +0,0 @@
-(.module:
- [lux #*
- [control
- [monad (#+ do)]
- pipe]
- [data
- ["." error]
- ["." maybe]
- ["." product]
- ["." text ("#;." equivalence)
- format]
- [collection
- ["." list ("#;." functor)]]]
- [math
- ["r" random]]
- ["." type]
- ["." macro
- ["." code]]
- [compiler
- [default
- ["." reference]
- ["." init]
- ["." phase
- ["." analysis (#+ Analysis Operation)
- [".A" type]
- ["." expression]
- ["/" function]]
- [extension
- [".E" analysis]]]]]
- test]
- [//
- ["_." primitive]
- ["_." structure]])
-
-(def: (check-apply expectedT num-args analysis)
- (-> Type Nat (Operation Analysis) Bit)
- (|> analysis
- (typeA.with-type expectedT)
- (phase.run _primitive.state)
- (case> (#error.Success applyA)
- (let [[funcA argsA] (analysis.application applyA)]
- (n/= num-args (list.size argsA)))
-
- (#error.Failure error)
- #0)))
-
-(context: "Function definition."
- (<| (times 100)
- (do @
- [func-name (r.unicode 5)
- arg-name (|> (r.unicode 5) (r.filter (|>> (text;= func-name) not)))
- [outputT outputC] _primitive.primitive
- [inputT _] _primitive.primitive
- #let [g!arg (code.local-identifier arg-name)]]
- ($_ seq
- (test "Can analyse function."
- (and (|> (typeA.with-type (All [a] (-> a outputT))
- (/.function _primitive.phase func-name arg-name outputC))
- _structure.check-succeeds)
- (|> (typeA.with-type (All [a] (-> a a))
- (/.function _primitive.phase func-name arg-name g!arg))
- _structure.check-succeeds)))
- (test "Generic functions can always be specialized."
- (and (|> (typeA.with-type (-> inputT outputT)
- (/.function _primitive.phase func-name arg-name outputC))
- _structure.check-succeeds)
- (|> (typeA.with-type (-> inputT inputT)
- (/.function _primitive.phase func-name arg-name g!arg))
- _structure.check-succeeds)))
- (test "The function's name is bound to the function's type."
- (|> (typeA.with-type (Rec self (-> inputT self))
- (/.function _primitive.phase func-name arg-name (code.local-identifier func-name)))
- _structure.check-succeeds))
- ))))
-
-(context: "Function application."
- (<| (times 100)
- (do @
- [full-args (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- partial-args (|> r.nat (:: @ map (n/% full-args)))
- var-idx (|> r.nat (:: @ map (|>> (n/% full-args) (n/max 1))))
- inputsTC (r.list full-args _primitive.primitive)
- #let [inputsT (list;map product.left inputsTC)
- inputsC (list;map product.right inputsTC)]
- [outputT outputC] _primitive.primitive
- #let [funcT (type.function inputsT outputT)
- partialT (type.function (list.drop partial-args inputsT) outputT)
- varT (#.Parameter 1)
- polyT (<| (type.univ-q 1)
- (type.function (list.concat (list (list.take var-idx inputsT)
- (list varT)
- (list.drop (inc var-idx) inputsT))))
- varT)
- poly-inputT (maybe.assume (list.nth var-idx inputsT))
- partial-poly-inputsT (list.drop (inc var-idx) inputsT)
- partial-polyT1 (<| (type.function partial-poly-inputsT)
- poly-inputT)
- partial-polyT2 (<| (type.univ-q 1)
- (type.function (#.Cons varT partial-poly-inputsT))
- varT)
- dummy-function (#analysis.Function (list) (#analysis.Reference (reference.local 1)))]]
- ($_ seq
- (test "Can analyse monomorphic type application."
- (|> (/.apply _primitive.phase funcT dummy-function inputsC)
- (check-apply outputT full-args)))
- (test "Can partially apply functions."
- (|> (/.apply _primitive.phase funcT dummy-function (list.take partial-args inputsC))
- (check-apply partialT partial-args)))
- (test "Can apply polymorphic functions."
- (|> (/.apply _primitive.phase polyT dummy-function inputsC)
- (check-apply poly-inputT full-args)))
- (test "Polymorphic partial application propagates found type-vars."
- (|> (/.apply _primitive.phase polyT dummy-function (list.take (inc var-idx) inputsC))
- (check-apply partial-polyT1 (inc var-idx))))
- (test "Polymorphic partial application preserves quantification for type-vars."
- (|> (/.apply _primitive.phase polyT dummy-function (list.take var-idx inputsC))
- (check-apply partial-polyT2 var-idx)))
- ))))
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/primitive.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/primitive.lux
deleted file mode 100644
index e60a7c40c..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/primitive.lux
+++ /dev/null
@@ -1,100 +0,0 @@
-(.module:
- [lux (#- primitive)
- [control
- [monad (#+ do)]
- pipe
- ["ex" exception (#+ exception:)]]
- [data
- ["." error (#+ Error)]
- [text
- format]]
- [math
- ["r" random ("#;." monad)]]
- ["." type ("#;." equivalence)]
- [macro
- ["." code]]
- [compiler
- [default
- ["." init]
- [evaluation (#+ Eval)]
- ["." phase
- ["." analysis (#+ Analysis Operation)
- [".A" type]
- ["." expression]]
- [extension
- [".E" analysis]]]]]
- test])
-
-(def: #export phase
- analysis.Phase
- expression.compile)
-
-(def: #export state
- analysis.State+
- [(analysisE.bundle (:coerce Eval [])) (init.compiler [])])
-
-(def: unit
- (r.Random Code)
- (r;wrap (' [])))
-
-(def: #export primitive
- (r.Random [Type Code])
- (`` ($_ r.either
- (~~ (template [<type> <code-wrapper> <value-gen>]
- [(r.and (r;wrap <type>) (r;map <code-wrapper> <value-gen>))]
-
- [Any code.tuple (r.list 0 ..unit)]
- [Bit code.bit r.bit]
- [Nat code.nat r.nat]
- [Int code.int r.int]
- [Rev code.rev r.rev]
- [Frac code.frac r.frac]
- [Text code.text (r.unicode 5)]
- )))))
-
-(exception: (wrong-inference {expected Type} {inferred Type})
- (ex.report ["Expected" (%type expected)]
- ["Inferred" (%type inferred)]))
-
-(def: (infer-primitive expected-type analysis)
- (-> Type (Operation Analysis) (Error Analysis))
- (|> analysis
- typeA.with-inference
- (phase.run ..state)
- (case> (#error.Success [inferred-type output])
- (if (is? expected-type inferred-type)
- (#error.Success output)
- (ex.throw wrong-inference [expected-type inferred-type]))
-
- (#error.Failure error)
- (#error.Failure error))))
-
-(context: "Primitives"
- ($_ seq
- (test "Can analyse unit."
- (|> (infer-primitive Any (..phase (' [])))
- (case> (^ (#error.Success (#analysis.Primitive (#analysis.Unit output))))
- (is? [] output)
-
- _
- #0)))
- (<| (times 100)
- (`` ($_ seq
- (~~ (template [<desc> <type> <tag> <random> <constructor>]
- [(do @
- [sample <random>]
- (test (format "Can analyse " <desc> ".")
- (|> (infer-primitive <type> (..phase (<constructor> sample)))
- (case> (#error.Success (#analysis.Primitive (<tag> output)))
- (is? sample output)
-
- _
- #0))))]
-
- ["bit" Bit #analysis.Bit r.bit code.bit]
- ["nat" Nat #analysis.Nat r.nat code.nat]
- ["int" Int #analysis.Int r.int code.int]
- ["rev" Rev #analysis.Rev r.rev code.rev]
- ["frac" Frac #analysis.Frac r.frac code.frac]
- ["text" Text #analysis.Text (r.unicode 5) code.text]
- )))))))
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/procedure/common.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/procedure/common.lux
deleted file mode 100644
index bf7de5cec..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/procedure/common.lux
+++ /dev/null
@@ -1,187 +0,0 @@
-(.module:
- [lux #*
- [io]
- [control
- [monad (#+ do)]
- pipe]
- [concurrency
- ["." atom]]
- [data
- ["." error]
- ["." product]
- [text
- format]]
- [math
- ["r" random]]
- ["." type ("#;." equivalence)]
- [macro
- ["." code]]
- [compiler
- [default
- ["." init]
- ["." phase
- [analysis
- ["." scope]
- [".A" type]]
- [extension
- [".E" analysis]]]]]
- test]
- [///
- ["_." primitive]])
-
-(template [<name> <success> <failure>]
- [(def: (<name> procedure params output-type)
- (-> Text (List Code) Type Bit)
- (|> (scope.with-scope ""
- (typeA.with-type output-type
- (_primitive.phase (` ((~ (code.text procedure)) (~+ params))))))
- (phase.run _primitive.state)
- (case> (#error.Success _)
- <success>
-
- (#error.Failure error)
- <failure>)))]
-
- [check-success+ #1 #0]
- [check-failure+ #0 #1]
- )
-
-(context: "Lux procedures"
- (<| (times 100)
- (do @
- [[primT primC] _primitive.primitive
- [antiT antiC] (|> _primitive.primitive
- (r.filter (|>> product.left (type;= primT) not)))]
- ($_ seq
- (test "Can test for reference equality."
- (check-success+ "lux is" (list primC primC) Bit))
- (test "Reference equality must be done with elements of the same type."
- (check-failure+ "lux is" (list primC antiC) Bit))
- (test "Can 'try' risky IO computations."
- (check-success+ "lux try"
- (list (` ([(~' _) (~' _)] (~ primC))))
- (type (Either Text primT))))
- ))))
-
-(context: "Bit procedures"
- (<| (times 100)
- (do @
- [subjectC (|> r.nat (:: @ map code.nat))
- signedC (|> r.int (:: @ map code.int))
- paramC (|> r.nat (:: @ map code.nat))]
- ($_ seq
- (test "Can perform bit 'and'."
- (check-success+ "lux bit and" (list subjectC paramC) Nat))
- (test "Can perform bit 'or'."
- (check-success+ "lux bit or" (list subjectC paramC) Nat))
- (test "Can perform bit 'xor'."
- (check-success+ "lux bit xor" (list subjectC paramC) Nat))
- (test "Can shift bit pattern to the left."
- (check-success+ "lux bit left-shift" (list subjectC paramC) Nat))
- (test "Can shift bit pattern to the right."
- (check-success+ "lux bit logical-right-shift" (list subjectC paramC) Nat))
- (test "Can shift signed bit pattern to the right."
- (check-success+ "lux bit arithmetic-right-shift" (list signedC paramC) Int))
- ))))
-
-(context: "Int procedures"
- (<| (times 100)
- (do @
- [subjectC (|> r.int (:: @ map code.int))
- paramC (|> r.int (:: @ map code.int))]
- ($_ seq
- (test "Can add integers."
- (check-success+ "lux int +" (list paramC subjectC) Int))
- (test "Can subtract integers."
- (check-success+ "lux int -" (list paramC subjectC) Int))
- (test "Can multiply integers."
- (check-success+ "lux int *" (list paramC subjectC) Int))
- (test "Can divide integers."
- (check-success+ "lux int /" (list paramC subjectC) Int))
- (test "Can calculate remainder of integers."
- (check-success+ "lux int %" (list paramC subjectC) Int))
- (test "Can test equivalence of integers."
- (check-success+ "lux int =" (list paramC subjectC) Bit))
- (test "Can compare integers."
- (check-success+ "lux int <" (list paramC subjectC) Bit))
- (test "Can convert integer to fraction."
- (check-success+ "lux int to-frac" (list subjectC) Frac))
- (test "Can convert integer to text."
- (check-success+ "lux int char" (list subjectC) Text))
- ))))
-
-(context: "Frac procedures"
- (<| (times 100)
- (do @
- [subjectC (|> r.frac (:: @ map code.frac))
- paramC (|> r.frac (:: @ map code.frac))
- encodedC (|> (r.unicode 5) (:: @ map code.text))]
- ($_ seq
- (test "Can add frac numbers."
- (check-success+ "lux frac +" (list paramC subjectC) Frac))
- (test "Can subtract frac numbers."
- (check-success+ "lux frac -" (list paramC subjectC) Frac))
- (test "Can multiply frac numbers."
- (check-success+ "lux frac *" (list paramC subjectC) Frac))
- (test "Can divide frac numbers."
- (check-success+ "lux frac /" (list paramC subjectC) Frac))
- (test "Can calculate remainder of frac numbers."
- (check-success+ "lux frac %" (list paramC subjectC) Frac))
- (test "Can test equivalence of frac numbers."
- (check-success+ "lux frac =" (list paramC subjectC) Bit))
- (test "Can compare frac numbers."
- (check-success+ "lux frac <" (list paramC subjectC) Bit))
- (test "Can obtain minimum frac number."
- (check-success+ "lux frac min" (list) Frac))
- (test "Can obtain maximum frac number."
- (check-success+ "lux frac max" (list) Frac))
- (test "Can obtain smallest frac number."
- (check-success+ "lux frac smallest" (list) Frac))
- (test "Can convert frac number to integer."
- (check-success+ "lux frac to-int" (list subjectC) Int))
- (test "Can convert frac number to text."
- (check-success+ "lux frac encode" (list subjectC) Text))
- (test "Can convert text to frac number."
- (check-success+ "lux frac decode" (list encodedC) (type (Maybe Frac))))
- ))))
-
-(context: "Text procedures"
- (<| (times 100)
- (do @
- [subjectC (|> (r.unicode 5) (:: @ map code.text))
- paramC (|> (r.unicode 5) (:: @ map code.text))
- replacementC (|> (r.unicode 5) (:: @ map code.text))
- fromC (|> r.nat (:: @ map code.nat))
- toC (|> r.nat (:: @ map code.nat))]
- ($_ seq
- (test "Can test text equivalence."
- (check-success+ "lux text =" (list paramC subjectC) Bit))
- (test "Compare texts in lexicographical order."
- (check-success+ "lux text <" (list paramC subjectC) Bit))
- (test "Can concatenate one text to another."
- (check-success+ "lux text concat" (list subjectC paramC) Text))
- (test "Can find the index of a piece of text inside a larger one that (may) contain it."
- (check-success+ "lux text index" (list fromC paramC subjectC) (type (Maybe Nat))))
- (test "Can query the size/length of a text."
- (check-success+ "lux text size" (list subjectC) Nat))
- (test "Can obtain the character code of a text at a given index."
- (check-success+ "lux text char" (list fromC subjectC) Nat))
- (test "Can clip a piece of text between 2 indices."
- (check-success+ "lux text clip" (list fromC toC subjectC) Text))
- ))))
-
-(context: "IO procedures"
- (<| (times 100)
- (do @
- [logC (|> (r.unicode 5) (:: @ map code.text))
- exitC (|> r.int (:: @ map code.int))]
- ($_ seq
- (test "Can log messages to standard output."
- (check-success+ "lux io log" (list logC) Any))
- (test "Can throw a run-time error."
- (check-success+ "lux io error" (list logC) Nothing))
- (test "Can exit the program."
- (check-success+ "lux io exit" (list exitC) Nothing))
- (test "Can query the current time (as milliseconds since epoch)."
- (check-success+ "lux io current-time" (list) Int))
- ))))
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/reference.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/reference.lux
deleted file mode 100644
index a73e6c3cb..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/reference.lux
+++ /dev/null
@@ -1,107 +0,0 @@
-(.module:
- [lux #*
- [control
- [monad (#+ do)]
- pipe]
- [data
- ["." error (#+ Error)]
- ["." name ("#;." equivalence)]
- ["." text ("#;." equivalence)]]
- [math
- ["r" random]]
- ["." type ("#;." equivalence)]
- [macro
- ["." code]]
- [compiler
- [default
- ["." reference]
- ["." init]
- ["." phase
- ["." analysis
- ["." scope]
- ["." module]
- [".A" type]
- ["." expression]]
- [extension
- [".E" analysis]]]]]
- test]
- [//
- ["_." primitive]])
-
-(type: Check (-> (Error Any) Bit))
-
-(template [<name> <on-success> <on-failure>]
- [(def: <name>
- Check
- (|>> (case> (#error.Success _)
- <on-success>
-
- (#error.Failure _)
- <on-failure>)))]
-
- [success? #1 #0]
- [failure? #0 #1]
- )
-
-(def: (reach-test var-name [export? def-module] [import? dependent-module] check!)
- (-> Text [Bit Text] [Bit Text] Check Bit)
- (|> (do phase.monad
- [_ (module.with-module 0 def-module
- (module.define var-name [Any
- (if export?
- (' {#.export? #1})
- (' {}))
- []]))]
- (module.with-module 0 dependent-module
- (do @
- [_ (if import?
- (module.import def-module)
- (wrap []))]
- (typeA.with-inference
- (_primitive.phase (code.identifier [def-module var-name]))))))
- (phase.run _primitive.state)
- check!))
-
-(context: "References"
- (<| (times 100)
- (do @
- [[expectedT _] _primitive.primitive
- def-module (r.unicode 5)
- scope-name (r.unicode 5)
- var-name (r.unicode 5)
- dependent-module (|> (r.unicode 5)
- (r.filter (|>> (text;= def-module) not)))]
- ($_ seq
- (test "Can analyse variable."
- (|> (scope.with-scope scope-name
- (scope.with-local [var-name expectedT]
- (typeA.with-inference
- (_primitive.phase (code.local-identifier var-name)))))
- (phase.run _primitive.state)
- (case> (^ (#error.Success [inferredT (#analysis.Reference (reference.local var))]))
- (and (type;= expectedT inferredT)
- (n/= 0 var))
-
- _
- #0)))
- (test "Can analyse definition (in the same module)."
- (let [def-name [def-module var-name]]
- (|> (do phase.monad
- [_ (module.define var-name [expectedT (' {}) []])]
- (typeA.with-inference
- (_primitive.phase (code.identifier def-name))))
- (module.with-module 0 def-module)
- (phase.run _primitive.state)
- (case> (^ (#error.Success [_ inferredT (#analysis.Reference (reference.constant constant-name))]))
- (and (type;= expectedT inferredT)
- (name;= def-name constant-name))
-
- _
- #0))))
- (test "Can analyse definition (if exported from imported module)."
- (reach-test var-name [#1 def-module] [#1 dependent-module] success?))
- (test "Cannot analyse definition (if not exported from imported module)."
- (reach-test var-name [#0 def-module] [#1 dependent-module] failure?))
- (test "Cannot analyse definition (if exported from non-imported module)."
- (reach-test var-name [#1 def-module] [#0 dependent-module] failure?))
- ))))
diff --git a/stdlib/source/test/lux/compiler/default/phase/analysis/structure.lux b/stdlib/source/test/lux/compiler/default/phase/analysis/structure.lux
deleted file mode 100644
index 186c961e9..000000000
--- a/stdlib/source/test/lux/compiler/default/phase/analysis/structure.lux
+++ /dev/null
@@ -1,297 +0,0 @@
-(.module:
- [lux #*
- [control
- [monad (#+ do)]
- pipe]
- [data
- ["." bit ("#;." equivalence)]
- ["e" error]
- ["." product]
- ["." maybe]
- ["." text]
- [collection
- ["." list ("#;." functor)]
- ["." set]]]
- [math
- ["r" random]]
- ["." type ("#;." equivalence)
- ["." check]]
- [macro
- ["." code]]
- [compiler
- [default
- ["." init]
- ["." phase
- ["." analysis (#+ Analysis Variant Tag Operation)
- ["." module]
- [".A" type]
- ["/" structure]
- ["." expression]]
- [extension
- [".E" analysis]]]]]
- test]
- [//
- ["_." primitive]])
-
-(template [<name> <on-success> <on-error>]
- [(def: #export <name>
- (All [a] (-> (Operation a) Bit))
- (|>> (phase.run _primitive.state)
- (case> (#e.Success _)
- <on-success>
-
- _
- <on-error>)))]
-
- [check-succeeds #1 #0]
- [check-fails #0 #1]
- )
-
-(def: (check-sum' size tag variant)
- (-> Nat Tag (Variant Analysis) Bit)
- (let [variant-tag (if (get@ #analysis.right? variant)
- (inc (get@ #analysis.lefts variant))
- (get@ #analysis.lefts variant))]
- (|> size dec (n/= tag)
- (bit;= (get@ #analysis.right? variant))
- (and (n/= tag variant-tag)))))
-
-(def: (check-sum type size tag analysis)
- (-> Type Nat Tag (Operation Analysis) Bit)
- (|> analysis
- (typeA.with-type type)
- (phase.run _primitive.state)
- (case> (^ (#e.Success (analysis.variant variant)))
- (check-sum' size tag variant)
-
- _
- #0)))
-
-(def: (tagged module tags type)
- (All [a] (-> Text (List module.Tag) Type (Operation a) (Operation [Module a])))
- (|>> (do phase.monad
- [_ (module.declare-tags tags #0 type)])
- (module.with-module 0 module)))
-
-(def: (check-variant module tags type size tag analysis)
- (-> Text (List module.Tag) Type Nat Tag (Operation Analysis) Bit)
- (|> analysis
- (tagged module tags type)
- (typeA.with-type type)
- (phase.run _primitive.state)
- (case> (^ (#e.Success [_ (analysis.variant variant)]))
- (check-sum' size tag variant)
-
- _
- #0)))
-
-(def: (right-size? size)
- (-> Nat (-> Analysis Bit))
- (|>> (case> (^ (analysis.tuple elems))
- (|> elems
- list.size
- (n/= size))
-
- _
- false)))
-
-(def: (check-record-inference module tags type size analysis)
- (-> Text (List module.Tag) Type Nat (Operation [Type Analysis]) Bit)
- (|> analysis
- (tagged module tags type)
- (phase.run _primitive.state)
- (case> (#e.Success [_ productT productA])
- (and (type;= type productT)
- (right-size? size productA))
-
- _
- #0)))
-
-(context: "Sums"
- (<| (times 100)
- (do @
- [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- choice (|> r.nat (:: @ map (n/% size)))
- primitives (r.list size _primitive.primitive)
- +choice (|> r.nat (:: @ map (n/% (inc size))))
- [_ +valueC] _primitive.primitive
- #let [variantT (type.variant (list;map product.left primitives))
- [valueT valueC] (maybe.assume (list.nth choice primitives))
- +size (inc size)
- +primitives (list.concat (list (list.take choice primitives)
- (list [(#.Parameter 1) +valueC])
- (list.drop choice primitives)))
- [+valueT +valueC] (maybe.assume (list.nth +choice +primitives))
- +variantT (type.variant (list;map product.left +primitives))]]
- ($_ seq
- (test "Can analyse sum."
- (check-sum variantT size choice
- (/.sum _primitive.phase choice valueC)))
- (test "Can analyse sum through bound type-vars."
- (|> (do phase.monad
- [[_ varT] (typeA.with-env check.var)
- _ (typeA.with-env
- (check.check varT variantT))]
- (typeA.with-type varT
- (/.sum _primitive.phase choice valueC)))
- (phase.run _primitive.state)
- (case> (^ (#e.Success (analysis.variant variant)))
- (check-sum' size choice variant)
-
- _
- #0)))
- (test "Cannot analyse sum through unbound type-vars."
- (|> (do phase.monad
- [[_ varT] (typeA.with-env check.var)]
- (typeA.with-type varT
- (/.sum _primitive.phase choice valueC)))
- check-fails))
- (test "Can analyse sum through existential quantification."
- (|> (typeA.with-type (type.ex-q 1 +variantT)
- (/.sum _primitive.phase +choice +valueC))
- check-succeeds))
- (test "Can analyse sum through universal quantification."
- (let [check-outcome (if (not (n/= choice +choice))
- check-succeeds
- check-fails)]
- (|> (typeA.with-type (type.univ-q 1 +variantT)
- (/.sum _primitive.phase +choice +valueC))
- check-outcome)))
- ))))
-
-(context: "Products"
- (<| (times 100)
- (do @
- [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- primitives (r.list size _primitive.primitive)
- choice (|> r.nat (:: @ map (n/% size)))
- [_ +valueC] _primitive.primitive
- #let [tupleT (type.tuple (list;map product.left primitives))
- [singletonT singletonC] (|> primitives (list.nth choice) maybe.assume)
- +primitives (list.concat (list (list.take choice primitives)
- (list [(#.Parameter 1) +valueC])
- (list.drop choice primitives)))
- +tupleT (type.tuple (list;map product.left +primitives))]]
- ($_ seq
- (test "Can analyse product."
- (|> (typeA.with-type tupleT
- (/.product _primitive.phase (list;map product.right primitives)))
- (phase.run _primitive.state)
- (case> (#e.Success tupleA)
- (right-size? size tupleA)
-
- _
- #0)))
- (test "Can infer product."
- (|> (typeA.with-inference
- (/.product _primitive.phase (list;map product.right primitives)))
- (phase.run _primitive.state)
- (case> (#e.Success [_type tupleA])
- (and (type;= tupleT _type)
- (right-size? size tupleA))
-
- _
- #0)))
- (test "Can analyse pseudo-product (singleton tuple)"
- (|> (typeA.with-type singletonT
- (_primitive.phase (` [(~ singletonC)])))
- check-succeeds))
- (test "Can analyse product through bound type-vars."
- (|> (do phase.monad
- [[_ varT] (typeA.with-env check.var)
- _ (typeA.with-env
- (check.check varT (type.tuple (list;map product.left primitives))))]
- (typeA.with-type varT
- (/.product _primitive.phase (list;map product.right primitives))))
- (phase.run _primitive.state)
- (case> (#e.Success tupleA)
- (right-size? size tupleA)
-
- _
- #0)))
- (test "Can analyse product through existential quantification."
- (|> (typeA.with-type (type.ex-q 1 +tupleT)
- (/.product _primitive.phase (list;map product.right +primitives)))
- check-succeeds))
- (test "Cannot analyse product through universal quantification."
- (|> (typeA.with-type (type.univ-q 1 +tupleT)
- (/.product _primitive.phase (list;map product.right +primitives)))
- check-fails))
- ))))
-
-(context: "Tagged Sums"
- (<| (times 100)
- (do @
- [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
- choice (|> r.nat (:: @ map (n/% size)))
- other-choice (|> r.nat (:: @ map (n/% size)) (r.filter (|>> (n/= choice) not)))
- primitives (r.list size _primitive.primitive)
- module-name (r.unicode 5)
- type-name (r.unicode 5)
- #let [varT (#.Parameter 1)
- primitivesT (list;map product.left primitives)
- [choiceT choiceC] (maybe.assume (list.nth choice primitives))
- [other-choiceT other-choiceC] (maybe.assume (list.nth other-choice primitives))
- variantT (type.variant primitivesT)
- namedT (#.Named [module-name type-name] variantT)
- named-polyT (|> (type.variant (list.concat (list (list.take choice primitivesT)
- (list varT)
- (list.drop (inc choice) primitivesT))))
- (type.univ-q 1)
- (#.Named [module-name type-name]))
- choice-tag (maybe.assume (list.nth choice tags))
- other-choice-tag (maybe.assume (list.nth other-choice tags))]]
- ($_ seq
- (test "Can infer tagged sum."
- (|> (/.tagged-sum _primitive.phase [module-name choice-tag] choiceC)
- (check-variant module-name tags namedT choice size)))
- (test "Tagged sums specialize when type-vars get bound."
- (|> (/.tagged-sum _primitive.phase [module-name choice-tag] choiceC)
- (check-variant module-name tags named-polyT choice size)))
- (test "Tagged sum inference retains universal quantification when type-vars are not bound."
- (|> (/.tagged-sum _primitive.phase [module-name other-choice-tag] other-choiceC)
- (check-variant module-name tags named-polyT other-choice size)))
- (test "Can specialize generic tagged sums."
- (|> (typeA.with-type variantT
- (/.tagged-sum _primitive.phase [module-name other-choice-tag] other-choiceC))
- (check-variant module-name tags named-polyT other-choice size)))
- ))))
-
-(context: "Records"
- (<| (times 100)
- (do @
- [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
- tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
- primitives (r.list size _primitive.primitive)
- module-name (r.unicode 5)
- type-name (r.unicode 5)
- choice (|> r.nat (:: @ map (n/% size)))
- #let [varT (#.Parameter 1)
- tagsC (list;map (|>> [module-name] code.tag) tags)
- primitivesT (list;map product.left primitives)
- primitivesC (list;map product.right primitives)
- tupleT (type.tuple primitivesT)
- namedT (#.Named [module-name type-name] tupleT)
- recordC (list.zip2 tagsC primitivesC)
- named-polyT (|> (type.tuple (list.concat (list (list.take choice primitivesT)
- (list varT)
- (list.drop (inc choice) primitivesT))))
- (type.univ-q 1)
- (#.Named [module-name type-name]))]]
- ($_ seq
- (test "Can infer record."
- (|> (typeA.with-inference
- (/.record _primitive.phase recordC))
- (check-record-inference module-name tags namedT size)))
- (test "Records specialize when type-vars get bound."
- (|> (typeA.with-inference
- (/.record _primitive.phase recordC))
- (check-record-inference module-name tags named-polyT size)))
- (test "Can specialize generic records."
- (|> (do phase.monad
- [recordA (typeA.with-type tupleT
- (/.record _primitive.phase recordC))]
- (wrap [tupleT recordA]))
- (check-record-inference module-name tags named-polyT size)))
- ))))
diff --git a/stdlib/source/test/lux/tool.lux b/stdlib/source/test/lux/tool.lux
index 340e24642..91c8d385b 100644
--- a/stdlib/source/test/lux/tool.lux
+++ b/stdlib/source/test/lux/tool.lux
@@ -3,14 +3,6 @@
["_" test (#+ Test)]]
## [compiler
## [phase
- ## [analysis
- ## ["_.A" primitive]
- ## ["_.A" structure]
- ## ["_.A" reference]
- ## ["_.A" case]
- ## ["_.A" function]
- ## [procedure
- ## ["_.A" common]]]
## [synthesis
## ["_.S" primitive]
## ["_.S" structure]
@@ -19,10 +11,13 @@
["." / #_
[compiler
[default
- ["#." syntax]]]])
+ ["#." syntax]]
+ [phase
+ ["#." analysis]]]])
(def: #export test
Test
($_ _.and
/syntax.test
+ /analysis.test
))
diff --git a/stdlib/source/test/lux/tool/compiler/default/syntax.lux b/stdlib/source/test/lux/tool/compiler/default/syntax.lux
index 632e97023..9f36c551f 100644
--- a/stdlib/source/test/lux/tool/compiler/default/syntax.lux
+++ b/stdlib/source/test/lux/tool/compiler/default/syntax.lux
@@ -1,7 +1,9 @@
(.module:
[lux #*
- data/text/format
[abstract/monad (#+ do)]
+ [data
+ text/format
+ ["." name]]
["r" math/random (#+ Random) ("#@." monad)]
["_" test (#+ Test)]
[data
@@ -25,17 +27,8 @@
(def: name-part^
(Random Text)
(do r.monad
- [#let [digits "0123456789"
- delimiters (format "()[]{}#." /.text-delimiter)
- space (format " " text.new-line)
- invalid-range (format digits delimiters space)
- char-gen (|> r.nat
- (:: @ map (|>> (n/% 256) (n/max 1)))
- (r.filter (function (_ sample)
- (not (text.contains? (text.from-code sample)
- invalid-range)))))]
- size (|> r.nat (:: @ map (|>> (n/% 20) (n/max 1))))]
- (r.text char-gen size)))
+ [size (|> r.nat (:: @ map (|>> (n/% 20) (n/max 1))))]
+ (r.ascii/lower-alpha size)))
(def: name^
(Random Name)
@@ -49,12 +42,12 @@
(|> r.nat (r@map code.nat))
(|> r.int (r@map code.int))
(|> r.rev (r@map code.rev))
- (|> r.frac (r@map code.frac))))
+ (|> r.safe-frac (r@map code.frac))))
textual^ (: (Random Code)
($_ r.either
(do r.monad
[size (|> r.nat (r@map (n/% 20)))]
- (|> (r.unicode size) (r@map code.text)))
+ (|> (r.ascii/upper-alpha size) (r@map code.text)))
(|> name^ (r@map code.identifier))
(|> name^ (r@map code.tag))))
simple^ (: (Random Code)
@@ -146,7 +139,8 @@
(def: #export test
Test
- ($_ _.and
- ..code
- ..comments
- ))
+ (<| (_.context (name.module (name-of /._)))
+ ($_ _.and
+ ..code
+ ..comments
+ )))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis.lux
new file mode 100644
index 000000000..d24feb8be
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis.lux
@@ -0,0 +1,24 @@
+(.module:
+ [lux #*
+ ["_" test (#+ Test)]]
+ ["." / #_
+ ["#." primitive]
+ ["#." structure]
+ ["#." reference]
+ ["#." case]
+ ["#." function]
+ ["/#" // #_
+ [extension
+ [analysis
+ ["#." common]]]]])
+
+(def: #export test
+ Test
+ ($_ _.and
+ /primitive.test
+ /structure.test
+ /reference.test
+ /case.test
+ /function.test
+ //common.test
+ ))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis/case.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis/case.lux
new file mode 100644
index 000000000..6f5a324cd
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis/case.lux
@@ -0,0 +1,201 @@
+(.module:
+ [lux #*
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name ("#@." equivalence)]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe]
+ [data
+ ["." product]
+ ["." maybe]
+ ["." text ("#@." equivalence)]
+ [collection
+ ["." list ("#@." monad)]
+ ["." set]]]
+ ["." type
+ ["." check]]
+ [macro
+ ["." code]]]
+ [//
+ ["_." primitive]
+ ["_." structure]]
+ {1
+ ["." /
+ ["/#" //
+ ["#." module]
+ ["#." type]
+ ["/#" //
+ ["/#" //
+ ["#." analysis (#+ Analysis Variant Tag Operation)]]]]]})
+
+(def: (exhaustive-weaving branchings)
+ (-> (List (List Code)) (List (List Code)))
+ (case branchings
+ #.Nil
+ #.Nil
+
+ (#.Cons head+ #.Nil)
+ (list@map (|>> list) head+)
+
+ (#.Cons head+ tail++)
+ (do list.monad
+ [tail+ (exhaustive-weaving tail++)
+ head head+]
+ (wrap (#.Cons head tail+)))))
+
+(def: #export (exhaustive-branches allow-literals? variantTC inputC)
+ (-> Bit (List [Code Code]) Code (Random (List Code)))
+ (case inputC
+ [_ (#.Bit _)]
+ (r@wrap (list (' #0) (' #1)))
+
+ (^template [<tag> <gen> <wrapper>]
+ [_ (<tag> _)]
+ (if allow-literals?
+ (do r.monad
+ [?sample (r.maybe <gen>)]
+ (case ?sample
+ (#.Some sample)
+ (do @
+ [else (exhaustive-branches allow-literals? variantTC inputC)]
+ (wrap (list& (<wrapper> sample) else)))
+
+ #.None
+ (wrap (list (' _)))))
+ (r@wrap (list (' _)))))
+ ([#.Nat r.nat code.nat]
+ [#.Int r.int code.int]
+ [#.Rev r.rev code.rev]
+ [#.Frac r.frac code.frac]
+ [#.Text (r.unicode 5) code.text])
+
+ (^ [_ (#.Tuple (list))])
+ (r@wrap (list (' [])))
+
+ [_ (#.Tuple members)]
+ (do r.monad
+ [member-wise-patterns (monad.map @ (exhaustive-branches allow-literals? variantTC) members)]
+ (wrap (|> member-wise-patterns
+ exhaustive-weaving
+ (list@map code.tuple))))
+
+ (^ [_ (#.Record (list))])
+ (r@wrap (list (' {})))
+
+ [_ (#.Record kvs)]
+ (do r.monad
+ [#let [ks (list@map product.left kvs)
+ vs (list@map product.right kvs)]
+ member-wise-patterns (monad.map @ (exhaustive-branches allow-literals? variantTC) vs)]
+ (wrap (|> member-wise-patterns
+ exhaustive-weaving
+ (list@map (|>> (list.zip2 ks) code.record)))))
+
+ (^ [_ (#.Form (list [_ (#.Tag _)] _))])
+ (do r.monad
+ [bundles (monad.map @
+ (function (_ [_tag _code])
+ (do @
+ [v-branches (exhaustive-branches allow-literals? variantTC _code)]
+ (wrap (list@map (function (_ pattern) (` ((~ _tag) (~ pattern))))
+ v-branches))))
+ variantTC)]
+ (wrap (list@join bundles)))
+
+ _
+ (r@wrap (list))
+ ))
+
+(def: #export (input variant-tags record-tags primitivesC)
+ (-> (List Code) (List Code) (List Code) (Random Code))
+ (r.rec
+ (function (_ input)
+ ($_ r.either
+ (r@map product.right _primitive.primitive)
+ (do r.monad
+ [choice (|> r.nat (:: @ map (n/% (list.size variant-tags))))
+ #let [choiceT (maybe.assume (list.nth choice variant-tags))
+ choiceC (maybe.assume (list.nth choice primitivesC))]]
+ (wrap (` ((~ choiceT) (~ choiceC)))))
+ (do r.monad
+ [size (|> r.nat (:: @ map (n/% 3)))
+ elems (r.list size input)]
+ (wrap (code.tuple elems)))
+ (r@wrap (code.record (list.zip2 record-tags primitivesC)))
+ ))))
+
+(def: (branch body pattern)
+ (-> Code Code [Code Code])
+ [pattern body])
+
+(def: #export test
+ (<| (_.context (name.module (name-of /._)))
+ (do r.monad
+ [module-name (r.unicode 5)
+ variant-name (r.unicode 5)
+ record-name (|> (r.unicode 5) (r.filter (|>> (text@= variant-name) not)))
+ size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ variant-tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
+ record-tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
+ primitivesTC (r.list size _primitive.primitive)
+ #let [primitivesT (list@map product.left primitivesTC)
+ primitivesC (list@map product.right primitivesTC)
+ code-tag (|>> [module-name] code.tag)
+ variant-tags+ (list@map code-tag variant-tags)
+ record-tags+ (list@map code-tag record-tags)
+ variantTC (list.zip2 variant-tags+ primitivesC)]
+ inputC (input variant-tags+ record-tags+ primitivesC)
+ [outputT outputC] (r.filter (|>> product.left (is? Any) not)
+ _primitive.primitive)
+ #let [analyse-pm (|>> (/.case _primitive.phase inputC)
+ (//type.with-type outputT)
+ ////analysis.with-scope
+ (do ///.monad
+ [_ (//module.declare-tags variant-tags false
+ (#.Named [module-name variant-name]
+ (type.variant primitivesT)))
+ _ (//module.declare-tags record-tags false
+ (#.Named [module-name record-name]
+ (type.tuple primitivesT)))])
+ (//module.with-module 0 module-name))]
+ exhaustive-patterns (exhaustive-branches true variantTC inputC)
+ #let [exhaustive-branchesC (list@map (branch outputC)
+ exhaustive-patterns)]]
+ ($_ _.and
+ (_.test "Will reject empty pattern-matching (no branches)."
+ (|> (analyse-pm (list))
+ _structure.check-fails))
+ (_.test "Can analyse exhaustive pattern-matching."
+ (|> (analyse-pm exhaustive-branchesC)
+ _structure.check-succeeds))
+ (let [non-exhaustive-branchesC (list.take (dec (list.size exhaustive-branchesC))
+ exhaustive-branchesC)]
+ (_.test "Will reject non-exhaustive pattern-matching."
+ (|> (analyse-pm non-exhaustive-branchesC)
+ _structure.check-fails)))
+ (do @
+ [redundant-patterns (exhaustive-branches false variantTC inputC)
+ redundancy-idx (|> r.nat (:: @ map (n/% (list.size redundant-patterns))))
+ #let [redundant-branchesC (<| (list@map (branch outputC))
+ list.concat
+ (list (list.take redundancy-idx redundant-patterns)
+ (list (maybe.assume (list.nth redundancy-idx redundant-patterns)))
+ (list.drop redundancy-idx redundant-patterns)))]]
+ (_.test "Will reject redundant pattern-matching."
+ (|> (analyse-pm redundant-branchesC)
+ _structure.check-fails)))
+ (do @
+ [[heterogeneousT heterogeneousC] (r.filter (|>> product.left (check.checks? outputT) not)
+ _primitive.primitive)
+ heterogeneous-idx (|> r.nat (:: @ map (n/% (list.size exhaustive-patterns))))
+ #let [heterogeneous-branchesC (list.concat (list (list.take heterogeneous-idx exhaustive-branchesC)
+ (list (let [[_pattern _body] (maybe.assume (list.nth heterogeneous-idx exhaustive-branchesC))]
+ [_pattern heterogeneousC]))
+ (list.drop (inc heterogeneous-idx) exhaustive-branchesC)))]]
+ (_.test "Will reject pattern-matching if the bodies of the branches do not all have the same type."
+ (|> (analyse-pm heterogeneous-branchesC)
+ _structure.check-fails)))
+ ))))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis/function.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis/function.lux
new file mode 100644
index 000000000..8d345dae2
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis/function.lux
@@ -0,0 +1,125 @@
+(.module:
+ [lux #*
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name ("#@." equivalence)]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe]
+ [data
+ ["." error]
+ ["." maybe]
+ ["." product]
+ ["." text ("#@." equivalence)]
+ [collection
+ ["." list ("#@." functor)]]]
+ ["." type]
+ ["." macro
+ ["." code]]]
+ [//
+ ["_." primitive]
+ ["_." structure]]
+ {1
+ ["." /
+ ["/#" //
+ ["#." module]
+ ["#." type]
+ ["/#" //
+ ["/#" //
+ ["#." reference]
+ ["#." analysis (#+ Analysis Operation)]]]]]})
+
+(def: (check-apply expectedT num-args analysis)
+ (-> Type Nat (Operation Analysis) Bit)
+ (|> analysis
+ (//type.with-type expectedT)
+ (///.run _primitive.state)
+ (case> (#error.Success applyA)
+ (let [[funcA argsA] (////analysis.application applyA)]
+ (n/= num-args (list.size argsA)))
+
+ (#error.Failure error)
+ false)))
+
+(def: abstraction
+ (do r.monad
+ [func-name (r.unicode 5)
+ arg-name (|> (r.unicode 5) (r.filter (|>> (text@= func-name) not)))
+ [outputT outputC] _primitive.primitive
+ [inputT _] _primitive.primitive
+ #let [g!arg (code.local-identifier arg-name)]]
+ (<| (_.context (%name (name-of /.function)))
+ ($_ _.and
+ (_.test "Can analyse function."
+ (and (|> (//type.with-type (All [a] (-> a outputT))
+ (/.function _primitive.phase func-name arg-name outputC))
+ _structure.check-succeeds)
+ (|> (//type.with-type (All [a] (-> a a))
+ (/.function _primitive.phase func-name arg-name g!arg))
+ _structure.check-succeeds)))
+ (_.test "Generic functions can always be specialized."
+ (and (|> (//type.with-type (-> inputT outputT)
+ (/.function _primitive.phase func-name arg-name outputC))
+ _structure.check-succeeds)
+ (|> (//type.with-type (-> inputT inputT)
+ (/.function _primitive.phase func-name arg-name g!arg))
+ _structure.check-succeeds)))
+ (_.test "The function's name is bound to the function's type."
+ (|> (//type.with-type (Rec self (-> inputT self))
+ (/.function _primitive.phase func-name arg-name (code.local-identifier func-name)))
+ _structure.check-succeeds))
+ ))))
+
+(def: apply
+ (do r.monad
+ [full-args (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ partial-args (|> r.nat (:: @ map (n/% full-args)))
+ var-idx (|> r.nat (:: @ map (|>> (n/% full-args) (n/max 1))))
+ inputsTC (r.list full-args _primitive.primitive)
+ #let [inputsT (list@map product.left inputsTC)
+ inputsC (list@map product.right inputsTC)]
+ [outputT outputC] _primitive.primitive
+ #let [funcT (type.function inputsT outputT)
+ partialT (type.function (list.drop partial-args inputsT) outputT)
+ varT (#.Parameter 1)
+ polyT (<| (type.univ-q 1)
+ (type.function (list.concat (list (list.take var-idx inputsT)
+ (list varT)
+ (list.drop (inc var-idx) inputsT))))
+ varT)
+ poly-inputT (maybe.assume (list.nth var-idx inputsT))
+ partial-poly-inputsT (list.drop (inc var-idx) inputsT)
+ partial-polyT1 (<| (type.function partial-poly-inputsT)
+ poly-inputT)
+ partial-polyT2 (<| (type.univ-q 1)
+ (type.function (#.Cons varT partial-poly-inputsT))
+ varT)
+ dummy-function (#////analysis.Function (list) (#////analysis.Reference (////reference.local 1)))]]
+ (<| (_.context (%name (name-of /.apply)))
+ ($_ _.and
+ (_.test "Can analyse monomorphic type application."
+ (|> (/.apply _primitive.phase funcT dummy-function inputsC)
+ (check-apply outputT full-args)))
+ (_.test "Can partially apply functions."
+ (|> (/.apply _primitive.phase funcT dummy-function (list.take partial-args inputsC))
+ (check-apply partialT partial-args)))
+ (_.test "Can apply polymorphic functions."
+ (|> (/.apply _primitive.phase polyT dummy-function inputsC)
+ (check-apply poly-inputT full-args)))
+ (_.test "Polymorphic partial application propagates found type-vars."
+ (|> (/.apply _primitive.phase polyT dummy-function (list.take (inc var-idx) inputsC))
+ (check-apply partial-polyT1 (inc var-idx))))
+ (_.test "Polymorphic partial application preserves quantification for type-vars."
+ (|> (/.apply _primitive.phase polyT dummy-function (list.take var-idx inputsC))
+ (check-apply partial-polyT2 var-idx)))
+ ))))
+
+(def: #export test
+ Test
+ (<| (_.context (name.module (name-of /._)))
+ ($_ _.and
+ ..abstraction
+ ..apply
+ )))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis/primitive.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis/primitive.lux
new file mode 100644
index 000000000..2ed135058
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis/primitive.lux
@@ -0,0 +1,108 @@
+(.module:
+ [lux (#- primitive)
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe
+ ["." exception (#+ exception:)]]
+ [data
+ ["." error (#+ Error)]]
+ ["." type ("#@." equivalence)]
+ [macro
+ ["." code]]]
+ {1
+ ["." /
+ ["/#" //
+ ["#." type]
+ ["/#" //
+ [macro (#+ Expander)]
+ [extension
+ ["#." analysis]]
+ ["/#" //
+ ["#." analysis (#+ Analysis Operation)]
+ [default
+ [evaluation (#+ Eval)]
+ ["." init]]]]]]})
+
+(def: #export (expander macro inputs state)
+ Expander
+ (#error.Failure "NOPE"))
+
+(def: #export (eval count type expression)
+ Eval
+ (function (_ state)
+ (#error.Failure "NO!")))
+
+(def: #export phase
+ ////analysis.Phase
+ (//.phase ..expander))
+
+(def: #export state
+ ////analysis.State+
+ [(///analysis.bundle ..eval) (////analysis.state init.info [])])
+
+(def: #export primitive
+ (Random [Type Code])
+ (`` ($_ r.either
+ (~~ (template [<type> <code-wrapper> <value-gen>]
+ [(r.and (r@wrap <type>) (r@map <code-wrapper> <value-gen>))]
+
+ [Any code.tuple (r.list 0 (r@wrap (' [])))]
+ [Bit code.bit r.bit]
+ [Nat code.nat r.nat]
+ [Int code.int r.int]
+ [Rev code.rev r.rev]
+ [Frac code.frac r.frac]
+ [Text code.text (r.unicode 5)]
+ )))))
+
+(exception: (wrong-inference {expected Type} {inferred Type})
+ (exception.report
+ ["Expected" (%type expected)]
+ ["Inferred" (%type inferred)]))
+
+(def: (infer expected-type analysis)
+ (-> Type (Operation Analysis) (Error Analysis))
+ (|> analysis
+ //type.with-inference
+ (///.run ..state)
+ (case> (#error.Success [inferred-type output])
+ (if (is? expected-type inferred-type)
+ (#error.Success output)
+ (exception.throw wrong-inference [expected-type inferred-type]))
+
+ (#error.Failure error)
+ (#error.Failure error))))
+
+(def: #export test
+ (<| (_.context (name.module (name-of /._)))
+ (`` ($_ _.and
+ (_.test (%name (name-of #////analysis.Unit))
+ (|> (infer Any (..phase (' [])))
+ (case> (^ (#error.Success (#////analysis.Primitive (#////analysis.Unit output))))
+ (is? [] output)
+
+ _
+ false)))
+ (~~ (template [<type> <tag> <random> <constructor>]
+ [(do r.monad
+ [sample <random>]
+ (_.test (%name (name-of <tag>))
+ (|> (infer <type> (..phase (<constructor> sample)))
+ (case> (#error.Success (#////analysis.Primitive (<tag> output)))
+ (is? sample output)
+
+ _
+ false))))]
+
+ [Bit #////analysis.Bit r.bit code.bit]
+ [Nat #////analysis.Nat r.nat code.nat]
+ [Int #////analysis.Int r.int code.int]
+ [Rev #////analysis.Rev r.rev code.rev]
+ [Frac #////analysis.Frac r.frac code.frac]
+ [Text #////analysis.Text (r.unicode 5) code.text]
+ ))))))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis/reference.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis/reference.lux
new file mode 100644
index 000000000..7356b9fad
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis/reference.lux
@@ -0,0 +1,106 @@
+(.module:
+ [lux #*
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name ("#@." equivalence)]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe]
+ [data
+ ["." error (#+ Error)]
+ ["." text ("#@." equivalence)]]
+ ["." type ("#@." equivalence)]
+ [macro
+ ["." code]]]
+ [//
+ ["_." primitive]]
+ {1
+ ["." /
+ ["/#" //
+ ["#." scope]
+ ["#." module]
+ ["#." type]
+ ["/#" //
+ ["/#" //
+ ["#." reference]
+ ["#." analysis (#+ Analysis Variant Tag Operation)]]]]]})
+
+(type: Check (-> (Error Any) Bit))
+
+(template [<name> <on-success> <on-failure>]
+ [(def: <name>
+ Check
+ (|>> (case> (#error.Success _)
+ <on-success>
+
+ (#error.Failure error)
+ <on-failure>)))]
+
+ [success? true false]
+ [failure? false true]
+ )
+
+(def: (reach-test var-name [export? def-module] [import? dependent-module] check!)
+ (-> Text [Bit Text] [Bit Text] Check Bit)
+ (|> (do ///.monad
+ [_ (//module.with-module 0 def-module
+ (//module.define var-name [Any
+ (if export?
+ (' {#.export? #1})
+ (' {}))
+ []]))]
+ (//module.with-module 0 dependent-module
+ (do @
+ [_ (if import?
+ (//module.import def-module)
+ (wrap []))]
+ (//type.with-inference
+ (_primitive.phase (code.identifier [def-module var-name]))))))
+ (///.run _primitive.state)
+ check!))
+
+(def: #export test
+ (<| (_.context (name.module (name-of /._)))
+ (do r.monad
+ [[expectedT _] _primitive.primitive
+ def-module (r.unicode 5)
+ scope-name (r.unicode 5)
+ var-name (r.unicode 5)
+ dependent-module (|> (r.unicode 5)
+ (r.filter (|>> (text@= def-module) not)))]
+ ($_ _.and
+ (_.test "Can analyse variable."
+ (|> (//scope.with-scope scope-name
+ (//scope.with-local [var-name expectedT]
+ (//type.with-inference
+ (_primitive.phase (code.local-identifier var-name)))))
+ (///.run _primitive.state)
+ (case> (^ (#error.Success [inferredT (#////analysis.Reference (////reference.local var))]))
+ (and (type@= expectedT inferredT)
+ (n/= 0 var))
+
+ _
+ false)))
+ (_.test "Can analyse definition (in the same module)."
+ (let [def-name [def-module var-name]]
+ (|> (do ///.monad
+ [_ (//module.define var-name [expectedT (' {}) []])]
+ (//type.with-inference
+ (_primitive.phase (code.identifier def-name))))
+ (//module.with-module 0 def-module)
+ (///.run _primitive.state)
+ (case> (^ (#error.Success [_ inferredT (#////analysis.Reference (////reference.constant constant-name))]))
+ (and (type@= expectedT inferredT)
+ (name@= def-name constant-name))
+
+ _
+ false))))
+ (_.test "Can analyse definition (if exported from imported module)."
+ (reach-test var-name [true def-module] [true dependent-module] success?))
+ (_.test "Cannot analyse definition (if not exported from imported module)."
+ (reach-test var-name [false def-module] [true dependent-module] failure?))
+ (_.test "Cannot analyse definition (if exported from non-imported module)."
+ (reach-test var-name [true def-module] [false dependent-module] failure?))
+ ))))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/analysis/structure.lux b/stdlib/source/test/lux/tool/compiler/phase/analysis/structure.lux
new file mode 100644
index 000000000..7c7e9e52c
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/analysis/structure.lux
@@ -0,0 +1,303 @@
+(.module:
+ [lux #*
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe]
+ [data
+ ["." bit ("#@." equivalence)]
+ ["." error]
+ ["." product]
+ ["." maybe]
+ ["." text]
+ [collection
+ ["." list ("#@." functor)]
+ ["." set]]]
+ ["." type
+ ["." check]]
+ [macro
+ ["." code]]]
+ [//
+ ["_." primitive]]
+ {1
+ ["." /
+ ["/#" //
+ ["#." module]
+ ["#." type]
+ ["/#" //
+ ["/#" //
+ ["#." analysis (#+ Analysis Variant Tag Operation)]]]]]})
+
+(template [<name> <on-success> <on-error>]
+ [(def: #export <name>
+ (All [a] (-> (Operation a) Bit))
+ (|>> (///.run _primitive.state)
+ (case> (#error.Success _)
+ <on-success>
+
+ _
+ <on-error>)))]
+
+ [check-succeeds true false]
+ [check-fails false true]
+ )
+
+(def: (check-sum' tag size variant)
+ (-> Tag Nat (Variant Analysis) Bit)
+ (let [expected//right? (n/= (dec size) tag)
+ expected//lefts (if expected//right?
+ (dec tag)
+ tag)
+ actual//right? (get@ #////analysis.right? variant)
+ actual//lefts (get@ #////analysis.lefts variant)]
+ (and (n/= expected//lefts
+ actual//lefts)
+ (bit@= expected//right?
+ actual//right?))))
+
+(def: (check-sum type tag size analysis)
+ (-> Type Tag Nat (Operation Analysis) Bit)
+ (|> analysis
+ (//type.with-type type)
+ (///.run _primitive.state)
+ (case> (^ (#error.Success (////analysis.variant variant)))
+ (check-sum' tag size variant)
+
+ _
+ false)))
+
+(def: (with-tags module tags type)
+ (All [a] (-> Text (List //module.Tag) Type (Operation a) (Operation [Module a])))
+ (|>> (do ///.monad
+ [_ (//module.declare-tags tags false type)])
+ (//module.with-module 0 module)))
+
+(def: (check-variant module tags expectedT variantT tag analysis)
+ (-> Text (List //module.Tag) Type Type Tag (Operation Analysis) Bit)
+ (|> analysis
+ (with-tags module tags variantT)
+ (//type.with-type expectedT)
+ (///.run _primitive.state)
+ (case> (^ (#error.Success [_ (////analysis.variant variant)]))
+ (check-sum' tag (list.size tags) variant)
+
+ _
+ false)))
+
+(def: (correct-size? size)
+ (-> Nat (-> Analysis Bit))
+ (|>> (case> (^ (////analysis.tuple elems))
+ (|> elems
+ list.size
+ (n/= size))
+
+ _
+ false)))
+
+(def: (check-record module tags expectedT recordT size analysis)
+ (-> Text (List //module.Tag) Type Type Nat (Operation Analysis) Bit)
+ (|> analysis
+ (with-tags module tags recordT)
+ (//type.with-type expectedT)
+ (///.run _primitive.state)
+ (case> (#error.Success [_ productA])
+ (correct-size? size productA)
+
+ _
+ false)))
+
+(def: sum
+ (do r.monad
+ [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ choice (|> r.nat (:: @ map (n/% size)))
+ primitives (r.list size _primitive.primitive)
+ +choice (|> r.nat (:: @ map (n/% (inc size))))
+ [_ +valueC] _primitive.primitive
+ #let [variantT (type.variant (list@map product.left primitives))
+ [valueT valueC] (maybe.assume (list.nth choice primitives))
+ +size (inc size)
+ +primitives (list.concat (list (list.take choice primitives)
+ (list [(#.Parameter 1) +valueC])
+ (list.drop choice primitives)))
+ [+valueT +valueC] (maybe.assume (list.nth +choice +primitives))
+ +variantT (type.variant (list@map product.left +primitives))]]
+ (<| (_.context (%name (name-of /.sum)))
+ ($_ _.and
+ (_.test "Can analyse."
+ (check-sum variantT choice size
+ (/.sum _primitive.phase choice valueC)))
+ (_.test "Can analyse through bound type-vars."
+ (|> (do ///.monad
+ [[_ varT] (//type.with-env check.var)
+ _ (//type.with-env
+ (check.check varT variantT))]
+ (//type.with-type varT
+ (/.sum _primitive.phase choice valueC)))
+ (///.run _primitive.state)
+ (case> (^ (#error.Success (////analysis.variant variant)))
+ (check-sum' choice size variant)
+
+ _
+ false)))
+ (_.test "Cannot analyse through unbound type-vars."
+ (|> (do ///.monad
+ [[_ varT] (//type.with-env check.var)]
+ (//type.with-type varT
+ (/.sum _primitive.phase choice valueC)))
+ check-fails))
+ (_.test "Can analyse through existential quantification."
+ (|> (//type.with-type (type.ex-q 1 +variantT)
+ (/.sum _primitive.phase +choice +valueC))
+ check-succeeds))
+ (_.test "Can analyse through universal quantification."
+ (let [check-outcome (if (not (n/= choice +choice))
+ check-succeeds
+ check-fails)]
+ (|> (//type.with-type (type.univ-q 1 +variantT)
+ (/.sum _primitive.phase +choice +valueC))
+ check-outcome)))
+ ))))
+
+(def: product
+ (do r.monad
+ [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ primitives (r.list size _primitive.primitive)
+ choice (|> r.nat (:: @ map (n/% size)))
+ [_ +valueC] _primitive.primitive
+ #let [tupleT (type.tuple (list@map product.left primitives))
+ [singletonT singletonC] (|> primitives (list.nth choice) maybe.assume)
+ +primitives (list.concat (list (list.take choice primitives)
+ (list [(#.Parameter 1) +valueC])
+ (list.drop choice primitives)))
+ +tupleT (type.tuple (list@map product.left +primitives))]]
+ (<| (_.context (%name (name-of /.product)))
+ ($_ _.and
+ (_.test "Can analyse."
+ (|> (//type.with-type tupleT
+ (/.product _primitive.phase (list@map product.right primitives)))
+ (///.run _primitive.state)
+ (case> (#error.Success tupleA)
+ (correct-size? size tupleA)
+
+ _
+ false)))
+ (_.test "Can infer."
+ (|> (//type.with-inference
+ (/.product _primitive.phase (list@map product.right primitives)))
+ (///.run _primitive.state)
+ (case> (#error.Success [_type tupleA])
+ (and (check.checks? tupleT _type)
+ (correct-size? size tupleA))
+
+ _
+ false)))
+ (_.test "Can analyse singleton."
+ (|> (//type.with-type singletonT
+ (_primitive.phase (` [(~ singletonC)])))
+ check-succeeds))
+ (_.test "Can analyse through bound type-vars."
+ (|> (do ///.monad
+ [[_ varT] (//type.with-env check.var)
+ _ (//type.with-env
+ (check.check varT (type.tuple (list@map product.left primitives))))]
+ (//type.with-type varT
+ (/.product _primitive.phase (list@map product.right primitives))))
+ (///.run _primitive.state)
+ (case> (#error.Success tupleA)
+ (correct-size? size tupleA)
+
+ _
+ false)))
+ (_.test "Can analyse through existential quantification."
+ (|> (//type.with-type (type.ex-q 1 +tupleT)
+ (/.product _primitive.phase (list@map product.right +primitives)))
+ check-succeeds))
+ (_.test "Cannot analyse through universal quantification."
+ (|> (//type.with-type (type.univ-q 1 +tupleT)
+ (/.product _primitive.phase (list@map product.right +primitives)))
+ check-fails))
+ ))))
+
+(def: variant
+ (do r.monad
+ [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
+ choice (|> r.nat (:: @ map (n/% size)))
+ other-choice (|> r.nat (:: @ map (n/% size)) (r.filter (|>> (n/= choice) not)))
+ primitives (r.list size _primitive.primitive)
+ module-name (r.unicode 5)
+ type-name (r.unicode 5)
+ #let [with-name (|>> (#.Named [module-name type-name]))
+ varT (#.Parameter 1)
+ primitivesT (list@map product.left primitives)
+ [choiceT choiceC] (maybe.assume (list.nth choice primitives))
+ [other-choiceT other-choiceC] (maybe.assume (list.nth other-choice primitives))
+ monoT (type.variant primitivesT)
+ polyT (|> (type.variant (list.concat (list (list.take choice primitivesT)
+ (list varT)
+ (list.drop (inc choice) primitivesT))))
+ (type.univ-q 1))
+ choice-tag (maybe.assume (list.nth choice tags))
+ other-choice-tag (maybe.assume (list.nth other-choice tags))]]
+ (<| (_.context (%name (name-of /.tagged-sum)))
+ ($_ _.and
+ (_.test "Can infer."
+ (|> (/.tagged-sum _primitive.phase [module-name choice-tag] choiceC)
+ (check-variant module-name tags
+ monoT (with-name monoT)
+ choice)))
+ (_.test "Inference retains universal quantification when type-vars are not bound."
+ (|> (/.tagged-sum _primitive.phase [module-name other-choice-tag] other-choiceC)
+ (check-variant module-name tags
+ polyT (with-name polyT)
+ other-choice)))
+ (_.test "Can specialize."
+ (|> (//type.with-type monoT
+ (/.tagged-sum _primitive.phase [module-name other-choice-tag] other-choiceC))
+ (check-variant module-name tags
+ monoT (with-name polyT)
+ other-choice)))
+ (_.test "Specialization when type-vars get bound."
+ (|> (/.tagged-sum _primitive.phase [module-name choice-tag] choiceC)
+ (check-variant module-name tags
+ monoT (with-name polyT)
+ choice)))
+ ))))
+
+(def: record
+ (do r.monad
+ [size (|> r.nat (:: @ map (|>> (n/% 10) (n/max 2))))
+ tags (|> (r.set text.hash size (r.unicode 5)) (:: @ map set.to-list))
+ primitives (r.list size _primitive.primitive)
+ module-name (r.unicode 5)
+ type-name (r.unicode 5)
+ choice (|> r.nat (:: @ map (n/% size)))
+ #let [varT (#.Parameter 1)
+ tagsC (list@map (|>> [module-name] code.tag) tags)
+ primitivesT (list@map product.left primitives)
+ primitivesC (list@map product.right primitives)
+ monoT (#.Named [module-name type-name] (type.tuple primitivesT))
+ recordC (list.zip2 tagsC primitivesC)
+ polyT (|> (type.tuple (list.concat (list (list.take choice primitivesT)
+ (list varT)
+ (list.drop (inc choice) primitivesT))))
+ (type.univ-q 1)
+ (#.Named [module-name type-name]))]]
+ (<| (_.context (%name (name-of /.record)))
+ (_.test "Can infer."
+ (|> (/.record _primitive.phase recordC)
+ (check-record module-name tags monoT monoT size))))))
+
+(def: #export test
+ Test
+ (<| (_.context (name.module (name-of /._)))
+ ($_ _.and
+ ..sum
+ ..product
+ ..variant
+ ..record
+ )))
diff --git a/stdlib/source/test/lux/tool/compiler/phase/extension/analysis/common.lux b/stdlib/source/test/lux/tool/compiler/phase/extension/analysis/common.lux
new file mode 100644
index 000000000..9c9d675fd
--- /dev/null
+++ b/stdlib/source/test/lux/tool/compiler/phase/extension/analysis/common.lux
@@ -0,0 +1,202 @@
+(.module:
+ [lux (#- i64 int primitive)
+ [abstract ["." monad (#+ do)]]
+ [data
+ text/format
+ ["." name]]
+ ["r" math/random (#+ Random) ("#@." monad)]
+ ["_" test (#+ Test)]
+ [control
+ pipe
+ [io (#+ IO)]
+ [concurrency
+ ["." atom]]]
+ [data
+ ["." error]
+ ["." product]]
+ ["." type ("#@." equivalence)]
+ [macro
+ ["." code]]]
+ [////
+ [analysis
+ ["_." primitive]]]
+ {1
+ ["." /
+ ["///#" ////
+ [analysis
+ ["#." scope]
+ ["#." type]]]]})
+
+(template [<name> <success> <failure>]
+ [(def: (<name> procedure params output-type)
+ (-> Text (List Code) Type Bit)
+ (|> (////scope.with-scope ""
+ (////type.with-type output-type
+ (_primitive.phase (` ((~ (code.text procedure)) (~+ params))))))
+ (////.run _primitive.state)
+ (case> (#error.Success _)
+ <success>
+
+ (#error.Failure error)
+ <failure>)))]
+
+ [check-success+ true false]
+ [check-failure+ false true]
+ )
+
+(def: primitive
+ (Random [Type Code])
+ (r.filter (|>> product.left (is? Any) not) _primitive.primitive))
+
+(def: lux
+ Test
+ (do r.monad
+ [[primT primC] ..primitive
+ [antiT antiC] (|> ..primitive
+ (r.filter (|>> product.left (type@= primT) not)))]
+ ($_ _.and
+ (_.test "Can test for reference equality."
+ (check-success+ "lux is" (list primC primC) Bit))
+ (_.test "Reference equality must be done with elements of the same type."
+ (check-failure+ "lux is" (list primC antiC) Bit))
+ (_.test "Can 'try' risky IO computations."
+ (check-success+ "lux try"
+ (list (` ("lux coerce" (~ (type.to-code (type (IO primT))))
+ ([(~' _) (~' _)] (~ primC)))))
+ (type (Either Text primT))))
+ )))
+
+(def: i64
+ Test
+ (do r.monad
+ [subjectC (|> r.nat (:: @ map code.nat))
+ signedC (|> r.int (:: @ map code.int))
+ paramC (|> r.nat (:: @ map code.nat))]
+ ($_ _.and
+ (_.test "i64 'and'."
+ (check-success+ "lux i64 and" (list paramC subjectC) Nat))
+ (_.test "i64 'or'."
+ (check-success+ "lux i64 or" (list paramC subjectC) Nat))
+ (_.test "i64 'xor'."
+ (check-success+ "lux i64 xor" (list paramC subjectC) Nat))
+ (_.test "i64 left-shift."
+ (check-success+ "lux i64 left-shift" (list paramC subjectC) Nat))
+ (_.test "i64 logical-right-shift."
+ (check-success+ "lux i64 logical-right-shift" (list paramC subjectC) Nat))
+ (_.test "i64 arithmetic-right-shift."
+ (check-success+ "lux i64 arithmetic-right-shift" (list paramC signedC) Int))
+ (_.test "i64 equivalence."
+ (check-success+ "lux i64 =" (list paramC subjectC) Bit))
+ (_.test "i64 addition."
+ (check-success+ "lux i64 +" (list paramC subjectC) Int))
+ (_.test "i64 subtraction."
+ (check-success+ "lux i64 -" (list paramC subjectC) Int))
+ )))
+
+(def: int
+ Test
+ (do r.monad
+ [subjectC (|> r.int (:: @ map code.int))
+ paramC (|> r.int (:: @ map code.int))]
+ ($_ _.and
+ (_.test "Can multiply integers."
+ (check-success+ "lux int *" (list paramC subjectC) Int))
+ (_.test "Can divide integers."
+ (check-success+ "lux int /" (list paramC subjectC) Int))
+ (_.test "Can calculate remainder of integers."
+ (check-success+ "lux int %" (list paramC subjectC) Int))
+ (_.test "Can compare integers."
+ (check-success+ "lux int <" (list paramC subjectC) Bit))
+ (_.test "Can convert integer to text."
+ (check-success+ "lux int char" (list subjectC) Text))
+ (_.test "Can convert integer to fraction."
+ (check-success+ "lux int frac" (list subjectC) Frac))
+ )))
+
+(def: frac
+ Test
+ (do r.monad
+ [subjectC (|> r.safe-frac (:: @ map code.frac))
+ paramC (|> r.safe-frac (:: @ map code.frac))
+ encodedC (|> r.safe-frac (:: @ map (|>> %f code.text)))]
+ ($_ _.and
+ (_.test "Can add frac numbers."
+ (check-success+ "lux frac +" (list paramC subjectC) Frac))
+ (_.test "Can subtract frac numbers."
+ (check-success+ "lux frac -" (list paramC subjectC) Frac))
+ (_.test "Can multiply frac numbers."
+ (check-success+ "lux frac *" (list paramC subjectC) Frac))
+ (_.test "Can divide frac numbers."
+ (check-success+ "lux frac /" (list paramC subjectC) Frac))
+ (_.test "Can calculate remainder of frac numbers."
+ (check-success+ "lux frac %" (list paramC subjectC) Frac))
+ (_.test "Can test equivalence of frac numbers."
+ (check-success+ "lux frac =" (list paramC subjectC) Bit))
+ (_.test "Can compare frac numbers."
+ (check-success+ "lux frac <" (list paramC subjectC) Bit))
+ (_.test "Can obtain minimum frac number."
+ (check-success+ "lux frac min" (list) Frac))
+ (_.test "Can obtain maximum frac number."
+ (check-success+ "lux frac max" (list) Frac))
+ (_.test "Can obtain smallest frac number."
+ (check-success+ "lux frac smallest" (list) Frac))
+ (_.test "Can convert frac number to integer."
+ (check-success+ "lux frac int" (list subjectC) Int))
+ (_.test "Can convert frac number to text."
+ (check-success+ "lux frac encode" (list subjectC) Text))
+ (_.test "Can convert text to frac number."
+ (check-success+ "lux frac decode" (list encodedC) (type (Maybe Frac))))
+ )))
+
+(def: text
+ Test
+ (do r.monad
+ [subjectC (|> (r.unicode 5) (:: @ map code.text))
+ paramC (|> (r.unicode 5) (:: @ map code.text))
+ replacementC (|> (r.unicode 5) (:: @ map code.text))
+ fromC (|> r.nat (:: @ map code.nat))
+ toC (|> r.nat (:: @ map code.nat))]
+ ($_ _.and
+ (_.test "Can test text equivalence."
+ (check-success+ "lux text =" (list paramC subjectC) Bit))
+ (_.test "Compare texts in lexicographical order."
+ (check-success+ "lux text <" (list paramC subjectC) Bit))
+ (_.test "Can concatenate one text to another."
+ (check-success+ "lux text concat" (list subjectC paramC) Text))
+ (_.test "Can find the index of a piece of text inside a larger one that (may) contain it."
+ (check-success+ "lux text index" (list fromC paramC subjectC) (type (Maybe Nat))))
+ (_.test "Can query the size/length of a text."
+ (check-success+ "lux text size" (list subjectC) Nat))
+ (_.test "Can obtain the character code of a text at a given index."
+ (check-success+ "lux text char" (list fromC subjectC) Nat))
+ (_.test "Can clip a piece of text between 2 indices."
+ (check-success+ "lux text clip" (list fromC toC subjectC) Text))
+ )))
+
+(def: io
+ Test
+ (do r.monad
+ [logC (|> (r.unicode 5) (:: @ map code.text))
+ exitC (|> r.int (:: @ map code.int))]
+ ($_ _.and
+ (_.test "Can log messages to standard output."
+ (check-success+ "lux io log" (list logC) Any))
+ (_.test "Can throw a run-time error."
+ (check-success+ "lux io error" (list logC) Nothing))
+ (_.test "Can exit the program."
+ (check-success+ "lux io exit" (list exitC) Nothing))
+ (_.test "Can query the current time (as milliseconds since epoch)."
+ (check-success+ "lux io current-time" (list) Int))
+ )))
+
+(def: #export test
+ Test
+ (<| (_.context (name.module (name-of /._)))
+ ($_ _.and
+ ..lux
+ ..i64
+ ..int
+ ..frac
+ ..text
+ ..io
+ )))