zeolite-lang 0.23.0.0 → 0.24.0.0
raw patch · 354 files changed
+13154/−4968 lines, 354 filesdep ~basedep ~hashabledep ~megaparsec
Dependency ranges changed: base, hashable, megaparsec, mtl, time, transformers, unix
Files
- ChangeLog.md +201/−0
- base/.zeolite-module +14/−8
- base/boxed.hpp +61/−21
- base/builtin.0rp +36/−8
- base/category-source.hpp +20/−2
- base/cleanup.hpp +56/−0
- base/src/Builtin_Bool.cpp +100/−0
- base/src/Builtin_Char.cpp +115/−0
- base/src/Builtin_CharBuffer.cpp +115/−0
- base/src/Builtin_Float.cpp +107/−0
- base/src/Builtin_Identifier.cpp +98/−0
- base/src/Builtin_Int.cpp +118/−0
- base/src/Builtin_Pointer.cpp +62/−0
- base/src/Builtin_String.cpp +228/−0
- base/src/Extension_Bool.cpp +0/−100
- base/src/Extension_Char.cpp +0/−115
- base/src/Extension_CharBuffer.cpp +0/−115
- base/src/Extension_Float.cpp +0/−107
- base/src/Extension_Int.cpp +0/−118
- base/src/Extension_Pointer.cpp +0/−62
- base/src/Extension_String.cpp +0/−228
- base/src/boxed.cpp +25/−7
- base/src/category-source.cpp +40/−1
- base/src/cleanup.cpp +53/−0
- base/testing.0rp +25/−0
- base/types.hpp +67/−1
- bin/zeolite-setup.hs +7/−4
- example/parser/.zeolite-module +1/−1
- example/parser/parse-text.0rp +4/−4
- example/parser/parse-text.0rx +27/−27
- example/parser/parser-test.0rt +23/−6
- example/parser/parser.0rp +2/−2
- example/parser/parser.0rx +1/−1
- example/parser/test-data.0rp +15/−4
- example/parser/test-data.0rx +30/−11
- example/primes/flag.0rx +1/−1
- example/primes/prime-thread.0rp +1/−1
- example/primes/prime-thread.0rx +2/−2
- example/primes/primes-demo.0rx +2/−2
- example/random/random-demo.0rx +28/−28
- lib/container/.zeolite-module +1/−1
- lib/container/auto-tree.0rp +18/−18
- lib/container/hashed-map.0rp +7/−6
- lib/container/helpers.0rp +10/−10
- lib/container/interfaces.0rp +7/−7
- lib/container/list.0rp +7/−7
- lib/container/sorted-map.0rp +11/−10
- lib/container/sorting.0rp +16/−16
- lib/container/src/auto-tree.0rx +48/−48
- lib/container/src/hashed-map.0rx +57/−53
- lib/container/src/hashed-set.0rx +3/−3
- lib/container/src/helpers.0rx +6/−6
- lib/container/src/list.0rx +4/−4
- lib/container/src/queue.0rx +1/−1
- lib/container/src/sorted-map.0rx +28/−24
- lib/container/src/sorted-set.0rx +3/−3
- lib/container/src/sorting.0rx +36/−36
- lib/container/src/testing.0rx +233/−0
- lib/container/src/type-map.0rx +15/−30
- lib/container/src/util.0rp +32/−0
- lib/container/src/util.0rx +54/−0
- lib/container/src/validated-tree.0rp +2/−2
- lib/container/src/wrappers.0rp +4/−4
- lib/container/src/wrappers.0rx +7/−7
- lib/container/test/hashed-map.0rt +68/−59
- lib/container/test/hashed-set.0rt +18/−18
- lib/container/test/helpers.0rt +41/−41
- lib/container/test/list.0rt +46/−46
- lib/container/test/queue.0rt +9/−9
- lib/container/test/sorted-map.0rt +93/−84
- lib/container/test/sorted-set.0rt +29/−29
- lib/container/test/sorting.0rt +40/−40
- lib/container/test/testing.0rt +257/−0
- lib/container/test/type-map.0rt +38/−37
- lib/container/test/vector.0rt +29/−29
- lib/container/testing.0rp +39/−0
- lib/container/type-map.0rp +2/−2
- lib/file/.zeolite-module +1/−1
- lib/file/test/tests.0rt +12/−12
- lib/math/.zeolite-module +1/−1
- lib/math/categorical-tree.0rp +3/−3
- lib/math/math.0rp +2/−2
- lib/math/random.0rp +9/−9
- lib/math/src/categorical-tree.0rx +23/−23
- lib/math/src/random.0rx +8/−8
- lib/math/src/token.0rx +11/−16
- lib/math/src/validated-tree.0rp +1/−1
- lib/math/test/categorical-tree.0rt +62/−62
- lib/math/test/math.0rt +29/−29
- lib/math/test/random.0rt +75/−75
- lib/math/test/token.0rt +11/−11
- lib/testing/.zeolite-module +13/−1
- lib/testing/check-float.0rp +28/−0
- lib/testing/check-sequence.0rp +33/−0
- lib/testing/check-string.0rp +24/−0
- lib/testing/check-value.0rp +67/−0
- lib/testing/checker.0rp +32/−0
- lib/testing/evaluation.0rp +54/−0
- lib/testing/helpers.0rp +0/−127
- lib/testing/matching.0rp +66/−0
- lib/testing/src/Extension_TestHandler.cpp +59/−0
- lib/testing/src/check-float.0rx +92/−0
- lib/testing/src/check-sequence.0rx +219/−0
- lib/testing/src/check-string.0rx +96/−0
- lib/testing/src/check-value.0rx +269/−0
- lib/testing/src/checker.0rx +110/−0
- lib/testing/src/evaluation.0rx +109/−0
- lib/testing/src/helpers.0rx +0/−135
- lib/testing/src/matching.0rx +241/−0
- lib/testing/src/util.0rp +59/−0
- lib/testing/src/util.0rx +239/−0
- lib/testing/test/check-float.0rt +106/−0
- lib/testing/test/check-sequence.0rt +203/−0
- lib/testing/test/check-string.0rt +162/−0
- lib/testing/test/check-value.0rt +409/−0
- lib/testing/test/checker.0rt +154/−0
- lib/testing/test/evaluation.0rt +184/−0
- lib/testing/test/helpers.0rp +35/−0
- lib/testing/test/helpers.0rx +69/−0
- lib/testing/test/matching.0rt +218/−0
- lib/testing/test/tests.0rt +0/−254
- lib/testing/test/util.0rt +195/−0
- lib/thread/.zeolite-module +6/−0
- lib/thread/barrier.0rp +4/−3
- lib/thread/src/Extension_Enumerated.cpp +24/−1
- lib/thread/src/testing.0rx +4/−4
- lib/thread/test/barrier.0rt +15/−15
- lib/thread/test/condition.0rt +15/−15
- lib/thread/test/thread.0rt +18/−18
- lib/util/.zeolite-module +2/−2
- lib/util/counters.0rp +4/−4
- lib/util/extra.0rp +3/−1
- lib/util/helpers.0rp +25/−25
- lib/util/interfaces.0rp +1/−1
- lib/util/src/counters.0rx +10/−10
- lib/util/src/extra.0rx +8/−4
- lib/util/src/helpers.0rx +31/−31
- lib/util/src/input.0rx +3/−3
- lib/util/src/parse.0rx +2/−2
- lib/util/src/testing.0rx +62/−31
- lib/util/test/counters.0rt +30/−30
- lib/util/test/extra.0rt +37/−35
- lib/util/test/helpers.0rt +99/−99
- lib/util/test/input.0rt +13/−13
- lib/util/test/mutex.0rt +2/−2
- lib/util/test/output.0rt +1/−1
- lib/util/test/parse.0rt +54/−54
- lib/util/test/testing.0rt +44/−34
- lib/util/test/time.0rt +6/−6
- lib/util/testing.0rp +5/−32
- src/Cli/Compiler.hs +21/−17
- src/Cli/ParseCompileOptions.hs +14/−2
- src/Cli/RunCompiler.hs +3/−3
- src/Cli/TestRunner.hs +12/−12
- src/Compilation/CompilerState.hs +12/−1
- src/Compilation/ProcedureContext.hs +35/−7
- src/CompilerCxx/CategoryContext.hs +13/−15
- src/CompilerCxx/Code.hs +151/−133
- src/CompilerCxx/CxxFiles.hs +16/−10
- src/CompilerCxx/LanguageModule.hs +35/−31
- src/CompilerCxx/Procedure.hs +201/−59
- src/Parser/Common.hs +42/−19
- src/Parser/IntegrationTest.hs +13/−6
- src/Parser/Procedure.hs +100/−52
- src/Parser/TypeCategory.hs +53/−10
- src/Parser/TypeInstance.hs +4/−1
- src/Test/ParseMetadata.hs +3/−3
- src/Test/Procedure.hs +66/−8
- src/Test/TypeCategory.hs +239/−218
- src/Test/testfiles/allows_variance_left.0rx +1/−1
- src/Test/testfiles/allows_variance_right.0rx +1/−1
- src/Test/testfiles/ambiguous_merge_inherit.0rx +1/−1
- src/Test/testfiles/bad_type_arg_variance.0rx +1/−1
- src/Test/testfiles/bad_type_return_variance.0rx +1/−1
- src/Test/testfiles/bad_value_arg_variance.0rx +1/−1
- src/Test/testfiles/bad_value_return_variance.0rx +1/−1
- src/Test/testfiles/basic_crash_test.0rt +1/−1
- src/Test/testfiles/concrete.0rx +11/−5
- src/Test/testfiles/concrete_defines_concrete.0rx +1/−1
- src/Test/testfiles/concrete_defines_instance.0rx +1/−1
- src/Test/testfiles/concrete_defines_value.0rx +1/−1
- src/Test/testfiles/concrete_duplicate_param.0rx +1/−1
- src/Test/testfiles/concrete_refines_concrete.0rx +1/−1
- src/Test/testfiles/concrete_refines_instance.0rx +1/−1
- src/Test/testfiles/concrete_refines_value.0rx +1/−1
- src/Test/testfiles/conflict_in_preserved.0rx +1/−1
- src/Test/testfiles/contravariant_defines_covariant.0rx +1/−1
- src/Test/testfiles/contravariant_defines_invariant.0rx +2/−2
- src/Test/testfiles/contravariant_refines_covariant.0rx +1/−1
- src/Test/testfiles/contravariant_refines_invariant.0rx +2/−2
- src/Test/testfiles/covariant_defines_contravariant.0rx +1/−1
- src/Test/testfiles/covariant_defines_invariant.0rx +2/−2
- src/Test/testfiles/covariant_refines_contravariant.0rx +1/−1
- src/Test/testfiles/covariant_refines_invariant.0rx +2/−2
- src/Test/testfiles/defines_variance_left.0rx +1/−1
- src/Test/testfiles/defines_variance_right.0rx +1/−1
- src/Test/testfiles/delayed_merging.0rx +3/−3
- src/Test/testfiles/duplicate_define.0rx +2/−2
- src/Test/testfiles/duplicate_refine.0rx +2/−2
- src/Test/testfiles/failed_merge.0rx +1/−1
- src/Test/testfiles/failed_merge_params.0rx +4/−4
- src/Test/testfiles/filters.0rx +5/−5
- src/Test/testfiles/flatten.0rx +5/−5
- src/Test/testfiles/function_allows_missed.0rx +3/−3
- src/Test/testfiles/function_bad_allows_variance.0rx +1/−1
- src/Test/testfiles/function_bad_defines_variance.0rx +1/−1
- src/Test/testfiles/function_bad_requires_variance.0rx +1/−1
- src/Test/testfiles/function_defines_missed.0rx +3/−3
- src/Test/testfiles/function_duplicate_param.0rx +1/−1
- src/Test/testfiles/function_filter_type_param.0rx +3/−3
- src/Test/testfiles/function_filters_satisfied.0rx +8/−8
- src/Test/testfiles/function_requires_missed.0rx +3/−3
- src/Test/testfiles/infer_meta.0rx +4/−4
- src/Test/testfiles/inference.0rx +4/−4
- src/Test/testfiles/inherit_incompatible.0rx +2/−2
- src/Test/testfiles/internal.0rx +2/−2
- src/Test/testfiles/invariant_self.0rx +1/−1
- src/Test/testfiles/merge_incompatible.0rx +2/−2
- src/Test/testfiles/merged.0rx +5/−5
- src/Test/testfiles/partial_params.0rx +1/−1
- src/Test/testfiles/preserve_merged.0rx +1/−1
- src/Test/testfiles/procedures.0rx +6/−6
- src/Test/testfiles/public.0rp +1/−1
- src/Test/testfiles/refine_wrong_direction.0rx +2/−2
- src/Test/testfiles/requires_variance_left.0rx +1/−1
- src/Test/testfiles/requires_variance_right.0rx +1/−1
- src/Test/testfiles/resolved_in_preserved.0rx +1/−1
- src/Test/testfiles/successful_merge.0rx +1/−1
- src/Test/testfiles/successful_merge_params.0rx +4/−4
- src/Test/testfiles/test.0rt +1/−1
- src/Test/testfiles/type_duplicate_param.0rx +1/−1
- src/Test/testfiles/type_interface.0rx +1/−1
- src/Test/testfiles/valid_filter_variance.0rx +3/−3
- src/Test/testfiles/valid_function_variance.0rx +1/−1
- src/Test/testfiles/valid_self.0rx +3/−3
- src/Test/testfiles/valid_variances.0rx +4/−4
- src/Test/testfiles/value_duplicate_param.0rx +1/−1
- src/Test/testfiles/value_interface.0rx +2/−2
- src/Test/testfiles/value_refines_concrete.0rx +1/−1
- src/Test/testfiles/value_refines_instance.0rx +1/−1
- src/Test/testfiles/value_refines_value.0rx +1/−1
- src/Types/Builtin.hs +30/−8
- src/Types/DefinedCategory.hs +17/−16
- src/Types/IntegrationTest.hs +16/−13
- src/Types/Procedure.hs +43/−17
- src/Types/TypeCategory.hs +242/−124
- src/Types/TypeInstance.hs +20/−12
- tests/.zeolite-module +1/−2
- tests/arg-labels.0rt +308/−0
- tests/bad-path/.zeolite-module +1/−1
- tests/builtin-types.0rt +142/−112
- tests/check-defs/.zeolite-module +1/−1
- tests/check-defs/private1.0rx +1/−1
- tests/check-defs/private2.0rx +1/−1
- tests/check-defs/public.0rp +2/−2
- tests/cli-tests.sh +23/−6
- tests/conditionals.0rt +27/−27
- tests/conversions.0rt +10/−10
- tests/custom-testcase/.zeolite-module +3/−0
- tests/custom-testcase/README.md +14/−0
- tests/custom-testcase/tests.0rt +63/−0
- tests/defer.0rt +33/−5
- tests/delegation.0rt +294/−0
- tests/expr-lookup.0rt +32/−13
- tests/extension.0rt +1/−1
- tests/filters.0rt +54/−54
- tests/freshness/.zeolite-module +1/−1
- tests/freshness/reverse/.zeolite-module +1/−1
- tests/function-calls.0rt +171/−77
- tests/function-merging.0rt +11/−11
- tests/function-visibility.0rt +419/−0
- tests/identify.0rt +275/−0
- tests/immutable.0rt +15/−15
- tests/inference.0rt +66/−66
- tests/infix-functions.0rt +21/−21
- tests/infix-operations.0rt +18/−18
- tests/internal-inheritance.0rt +21/−21
- tests/leak-check/.zeolite-module +1/−1
- tests/leak-check/README.md +5/−5
- tests/leak-check/leak-check.0rx +47/−26
- tests/local-rules.0rt +21/−21
- tests/local.0rp +1/−1
- tests/member-init.0rt +17/−17
- tests/modified-storage.0rt +379/−9
- tests/module-only/.zeolite-module +1/−1
- tests/module-only/internal/.zeolite-module +1/−1
- tests/module-only/internal/private.0rp +1/−1
- tests/module-only/internal/public.0rp +1/−1
- tests/module-only/private.0rx +1/−1
- tests/module-only2/.zeolite-module +1/−1
- tests/module-only2/private1.0rp +1/−1
- tests/module-only3/.zeolite-module +1/−1
- tests/module-only3/internal/.zeolite-module +1/−1
- tests/module-only3/internal/private.0rp +1/−1
- tests/module-only3/internal/public.0rp +1/−1
- tests/module-only4/.zeolite-module +1/−1
- tests/multiple-returns.0rt +47/−15
- tests/named-returns.0rt +20/−20
- tests/pointer/.zeolite-module +1/−4
- tests/pointer/call.0rp +2/−2
- tests/pointer/call.0rt +71/−16
- tests/positional-returns.0rt +9/−9
- tests/program-exit.0rt +3/−3
- tests/reduce.0rt +71/−71
- tests/regressions.0rt +12/−12
- tests/scoped.0rt +41/−41
- tests/self-offset/.zeolite-module +1/−4
- tests/self-offset/offset.0rt +7/−3
- tests/self-type.0rt +25/−25
- tests/simple.0rt +151/−9
- tests/simulate-refs/main.0rx +7/−7
- tests/simulate-refs/ref-state.0rp +0/−10
- tests/simulate-refs/ref-state.0rx +1/−32
- tests/simulate-refs/routines.0rp +4/−4
- tests/simulate-refs/routines.0rx +46/−63
- tests/simulate-refs/state.0rp +34/−2
- tests/simulate-refs/state.0rx +100/−9
- tests/simulate-refs/transitions.0rp +17/−17
- tests/simulate-refs/transitions.0rx +37/−65
- tests/swap.0rt +367/−0
- tests/templates/.zeolite-module +1/−1
- tests/templates/tests.0rt +2/−2
- tests/test-helpers.0rp +113/−0
- tests/test-helpers.0rt +300/−0
- tests/test-helpers.0rx +169/−0
- tests/tests-only/.zeolite-module +1/−1
- tests/tests-only/private.0rx +2/−2
- tests/tests-only/public1.0rp +1/−1
- tests/tests-only/public2.0rp +1/−1
- tests/tests-only2/private.0rx +1/−1
- tests/tests-only3/.zeolite-module +1/−1
- tests/tests-only3/public.0rp +1/−1
- tests/tests-only3/public.0rx +1/−1
- tests/tests-only4/.zeolite-module +1/−1
- tests/tests-only4/normal.0rp +1/−1
- tests/tests-only4/testing.0rp +2/−2
- tests/traces/.zeolite-module +1/−1
- tests/traces/traces.0rx +1/−1
- tests/tracing.0rt +8/−8
- tests/traverse.0rt +18/−18
- tests/typename.0rt +25/−25
- tests/unary-functions.0rt +5/−5
- tests/unreachable.0rt +4/−4
- tests/visibility/.zeolite-module +1/−1
- tests/visibility/internal/.zeolite-module +1/−1
- tests/visibility2/.zeolite-module +1/−1
- tests/visibility2/internal/.zeolite-module +1/−1
- tests/warn-public/.zeolite-module +1/−1
- tests/warn-public/internal/.zeolite-module +1/−1
- tests/warn-public/internal/public.0rp +1/−1
- tests/warn-public/internal2/.zeolite-module +1/−1
- tests/warn-public/internal2/public.0rp +1/−1
- tests/while.0rt +9/−9
- zeolite-lang.cabal +17/−10
ChangeLog.md view
@@ -1,5 +1,206 @@ # Revision history for zeolite-lang +## 0.24.0.0 -- 2023-12-09++### Language++* **[breaking]** In `testcase`, renames `crash` to `failure`.++* **[breaking]** Adds the `visibility` keyword to limit calling of+ `@value`/`@type` functions to specific type contexts. This is breaking because+ `visibility` is now reserved.++ ```text+ concrete Foo {+ visibility Bar, Baz // Functions below here are only visible from Bar or Baz.++ @type call () -> ()+ }+ ```++* **[breaking]** Adds function delegation with `delegate` keyword.++ ```text+ concrete Foo {+ @type new1 (Int) -> (Foo)+ @type new2 (Int) -> (Foo)+ }++ define Foo {+ @value Int value++ new1 (value) {+ // Same as Foo{ value }.+ return delegate -> Foo+ }++ new2 (value) {+ // Same as new1(value).+ return delegate -> `new1`+ }+ }+ ```++ This is a breaking change because `delegate` is now reserved.++* **[breaking]** In `testcase`, you can now optionally include a type name that+ `defines Testcase` after `success`/`failure`. The test will automatically call+ `start()` and `finish()`, which is meant to allow custom checks upon test+ exit. This is breaking because `Testcase` is now reserved.++* **[breaking]** Adds instance identification with the `identify` keyword. This+ is breaking because `identify` is now reserved.++* **[fix]** Fixes parsing of comments that immediately follow operators, e.g.,+ the `/*b+*/` in `a+/*b+*/c`.++* **[fix]** Fixes checking that a `@type` function isn't called on a `@value`.++* **[fix]** Fixes cross-module visibility checks with `$TestsOnly$` in `.0rp`+ without `$ModuleOnly$`. This is primarily to detect if there's usage of a+ `$TestsOnly$` category from a `private_dep` in a `.0rp`.++* **[fix]** Updates parsing of `empty` to allow explicit type conversion, e.g.,+ `empty?String`.++* **[new]** Adds the option to provide _enforced_ labels for function args.++ ```text+ concrete Foo {+ // First arg has the label value:.+ @type bar (Int value:) -> ()+ }++ // ...++ // Callers _must_ use the label value:.+ \ Foo.bar(value: 1)+ ```++ Unlike with languages like C++, where the argument name in the function+ _declaration_ is irrelevant, this is primarily meant to clarify calls to+ functions with arguments whose purposes are ambiguous.++ Note that this _doesn't_ make arguments optional, nor does it allow reordering+ of arguments. Additionally, there's no requirement that the labels match the+ argument names, nor that the labels are even unique.++* **[new]** Adds the `<-|` operator to conditionally overwrite an `optional`+ variable if it's empty.++ ```text+ optional Int value <- empty+ value <-| 123 // Assigned, because value was empty.+ value <-| 456 // Not assigned, because value wasn't empty.+ ```++* **[new]** Adds the `&.` operator to conditionally call a function on an+ `optional` value.++ ```text+ optional Int value <- 123+ optional Formatted formatted <- value&.formatted()+ ```++* **[new]** Updates the return type of inline `<-` to use the type on the right+ side of the expression, rather than the variable's type.++ ```text+ optional Formatted value <- empty+ // Previously, the return type would've been optional Formatted.+ Int value2 <- (value <- 123)+ ```++* **[new]** Updates type inference to arbitrarily choose the lower bound when a+ param is bounded above and below with different types. Previously, the+ compiler would require specifying the param explicitly. This will make param+ inference succeed in more situations than it did previously.++* **[new]** Adds the `<->` operator to swap variable values. This can be used to+ swap the values of writable variables of the same type, i.e., _not_ marked as+ read-only via a pragma and not a function argument.++ ```text+ Int foo <- 123+ Int bar <- 456+ foo <-> bar+ ```++* **[new]** Allows hex, octal, and binary floating-point literals. (Exponents+ not allowed due to ambiguity during hex parsing.)++ ```text+ Float value1 <- \xFED.CBA+ Float value2 <- \o765.432+ Float value3 <- \b101.010+ ```++* **[new]** Adds the `$CallTrace$` macro to get a call trace for testing+ purposes.++### Libraries++* **[breaking]** Removes `Testing` from `lib/testing` entirely. Use the new+ testing approach instead. (More details in items further down.)++ ```text+ // Old way.++ testcase "my tests" {+ success+ }++ unittest test {+ \ Testing.checkEquals("something", "other")+ \ Testing.checkBetween(3, 2, 7)+ }+ ```++ ```text+ // New way.++ testcase "my tests" {+ success TestChecker // <- allows lib/testing to manage test results+ }++ unittest test {+ \ "something" `Matches:with` CheckValue:equals("other")+ \ 3 `Matches:with` CheckValue:betweenEquals(2, 7)+ }+ ```++ Also see the `.0rp` files in `lib/testing`.++* **[breaking]** Removes `UtilTesting` from `lib/util` entirely. Use the new+ testing approach instead.++* **[new]** Adds the `TestChecker` `testcase` checker (see previous section) to+ `lib/testing` to help support custom matchers.++* **[new]** Adds support for custom value matchers in tests to `lib/testing`, as+ well as matchers for value comparisons, substring checks, floating-point+ epsilon, and container comparisons in `lib/testing`, `lib/util`, and+ `lib/container`. User-defined matchers can compose other matchers to+ customize matching of more complex value types.++* **[new]** Implements `SetReader<#k>` for `HashedMap<#k, #v>` and+ `SortedMap<#k, #v>` in `lib/container`.++* **[new]** Adds `tryValue` to `ErrorOr` in `lib/util`.++* **[fix]** Updates `BarrierWait` C++ implementation to compile for MacOS by+ adding runtime failures if the functionality is used. MacOS doesn't support+ thread barriers, so `lib/thread` previously didn't compile for MacOS.++### Compiler CLI++* **[new]** Allows single-`-` CLI options to be clustered, e.g., `-rfj8`, which+ is expanded to `-r`, `-f`, and `-j` `8`.++* **[behavior]** Clearer error messages for categories hidden by `$ModuleOnly$`,+ `$TestsOnly$`, and `private_deps`. Previously, the compiler would just say+ that the category wasn't found.+ ## 0.23.0.0 -- 2022-10-08 ### Language
base/.zeolite-module view
@@ -2,36 +2,41 @@ path: "base" extra_files: [ category_source {- source: "base/src/Extension_Bool.cpp"+ source: "base/src/Builtin_Bool.cpp" categories: [Bool] } category_source {- source: "base/src/Extension_Char.cpp"+ source: "base/src/Builtin_Char.cpp" categories: [Char] } category_source {- source: "base/src/Extension_CharBuffer.cpp"+ source: "base/src/Builtin_CharBuffer.cpp" categories: [CharBuffer] } category_source {- source: "base/src/Extension_Float.cpp"+ source: "base/src/Builtin_Float.cpp" categories: [Float] } category_source {- source: "base/src/Extension_Int.cpp"+ source: "base/src/Builtin_Identifier.cpp"+ categories: [Identifier]+ }+ category_source {+ source: "base/src/Builtin_Int.cpp" categories: [Int] } category_source {- source: "base/src/Extension_String.cpp"+ source: "base/src/Builtin_String.cpp" categories: [String] } category_source {- source: "base/src/Extension_Pointer.cpp"+ source: "base/src/Builtin_Pointer.cpp" categories: [Pointer] } "base/boxed.hpp" "base/category-header.hpp" "base/category-source.hpp"+ "base/cleanup.hpp" "base/cycle-check.hpp" "base/function.hpp" "base/logging.hpp"@@ -42,8 +47,9 @@ "base/types.hpp" "base/src/boxed.cpp" "base/src/category-source.cpp"+ "base/src/cleanup.cpp" "base/src/logging.cpp" "base/src/returns.cpp" "base/src/thread-crosser.cc" ]-mode: incremental {}+mode: incremental { }
base/boxed.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021-2022 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -30,7 +30,15 @@ class ValueFunction; namespace zeolite_internal {+class WeakValue;+class BoxedValue;+} // namespace zeolite_internal +void SwapValues(zeolite_internal::WeakValue&, zeolite_internal::WeakValue&);+void SwapValues(zeolite_internal::BoxedValue&, zeolite_internal::BoxedValue&);++namespace zeolite_internal {+ struct UnionValue { enum class Type : char { EMPTY,@@ -39,6 +47,7 @@ INT, FLOAT, POINTER,+ IDENTIFIER, BOXED, }; @@ -46,6 +55,8 @@ std::atomic_flag lock_; std::atomic_int strong_; std::atomic_int weak_;+ // NOTE: This can't be optimized out because it might differ from the+ // pointer to the underlying object, e.g., if TypeValue is a virtual base. TypeValue* object_; }; @@ -55,16 +66,16 @@ union { unsigned char* as_bytes_;- Pointer* as_boxed_;- PrimBool as_bool_;- PrimChar as_char_;- PrimInt as_int_;- PrimFloat as_float_;- PrimPointer as_pointer_;+ Pointer* as_boxed_;+ PrimBool as_bool_;+ PrimChar as_char_;+ PrimInt as_int_;+ PrimFloat as_float_;+ PrimPointer as_pointer_;+ PrimIdentifier as_identifier_; } __attribute__((packed)) value_; } __attribute__((packed)); - class BoxedValue { public: constexpr BoxedValue()@@ -116,27 +127,28 @@ return *this; } - inline BoxedValue(PrimBool value)+ inline explicit BoxedValue(PrimBool value) : union_{ .type_ = UnionValue::Type::BOOL, .value_ = { .as_bool_ = value } } {} - inline BoxedValue(PrimChar value)+ inline explicit BoxedValue(PrimChar value) : union_{ .type_ = UnionValue::Type::CHAR, .value_ = { .as_char_ = value } } {} - inline BoxedValue(PrimInt value)+ inline explicit BoxedValue(PrimInt value) : union_{ .type_ = UnionValue::Type::INT, .value_ = { .as_int_ = value } } {} - inline BoxedValue(PrimFloat value)+ inline explicit BoxedValue(PrimFloat value) : union_{ .type_ = UnionValue::Type::FLOAT, .value_ = { .as_float_ = value } } {} - inline BoxedValue(PrimPointer value)+ inline explicit BoxedValue(PrimPointer value) : union_{ .type_ = UnionValue::Type::POINTER, .value_ = { .as_pointer_ = value } } {} + inline explicit BoxedValue(PrimIdentifier value)+ : union_{ .type_ = UnionValue::Type::IDENTIFIER, .value_ = { .as_identifier_ = value } } {}+ template<class T, class... As> static inline BoxedValue New(const As&... args) { using Pointer = UnionValue::Pointer;- BoxedValue new_value;- new_value.union_.type_ = UnionValue::Type::BOXED;- new_value.union_.value_.as_bytes_ = (unsigned char*) malloc(sizeof(Pointer) + sizeof(T));+ BoxedValue new_value(reinterpret_cast<unsigned char*>(malloc(sizeof(Pointer) + sizeof(T)))); new (new_value.union_.value_.as_bytes_) Pointer{ ATOMIC_FLAG_INIT, {1}, {1}, {new (new_value.union_.value_.as_bytes_ + sizeof(Pointer)) T(args...)} };@@ -197,7 +209,7 @@ inline T* AsPointer() const { switch (union_.type_) { case UnionValue::Type::POINTER:- return reinterpret_cast<T*>(union_.value_.as_boxed_);+ return reinterpret_cast<T*>(union_.value_.as_pointer_); default: FAIL() << union_.CategoryName() << " is not a Pointer value"; __builtin_unreachable();@@ -205,6 +217,17 @@ } } + inline PrimIdentifier AsIdentifier() const {+ switch (union_.type_) {+ case UnionValue::Type::IDENTIFIER:+ return union_.value_.as_identifier_;+ default:+ FAIL() << union_.CategoryName() << " is not an Identifier value";+ __builtin_unreachable();+ break;+ }+ }+ inline static bool Present(const BoxedValue& target) { return target.union_.type_ != UnionValue::Type::EMPTY; }@@ -224,6 +247,8 @@ return BoxedValue(target); } + static PrimIdentifier Identify(const BoxedValue& target);+ void Validate(const std::string& name) const; const PrimString& AsString() const;@@ -232,7 +257,11 @@ private: friend class ::TypeValue; friend class WeakValue;+ friend void ::SwapValues(BoxedValue&, BoxedValue&); + inline explicit BoxedValue(unsigned char* value)+ : union_{ .type_ = UnionValue::Type::BOXED, .value_ = { .as_bytes_ = value } } {}+ // Intentionally break old calls that used new. inline explicit constexpr BoxedValue(void*) : BoxedValue() {} @@ -242,10 +271,7 @@ template<class T> static inline BoxedValue FromPointer(const T* pointer) {- BoxedValue value;- value.union_.type_ = UnionValue::Type::BOXED;- value.union_.value_.as_bytes_ =- reinterpret_cast<unsigned char*>(const_cast<T*>(pointer))-sizeof(UnionValue::Pointer);+ BoxedValue value(reinterpret_cast<unsigned char*>(const_cast<T*>(pointer))-sizeof(UnionValue::Pointer)); if (value.union_.value_.as_boxed_->object_ != pointer || ++value.union_.value_.as_boxed_->strong_ == 1) { FAIL() << "Bad VAR_SELF pointer " << pointer << " in " << pointer->CategoryName();@@ -279,6 +305,7 @@ private: friend class BoxedValue;+ friend void ::SwapValues(WeakValue&, WeakValue&); void Cleanup(); @@ -286,6 +313,19 @@ } __attribute__((packed)); } // namespace zeolite_internal+++inline void SwapValues(BoxedValue& left, BoxedValue& right) {+ zeolite_internal::UnionValue temp = right.union_;+ right.union_ = left.union_;+ left.union_ = temp;+}++inline void SwapValues(WeakValue& left, WeakValue& right) {+ zeolite_internal::UnionValue temp = right.union_;+ right.union_ = left.union_;+ left.union_ = temp;+} using zeolite_internal::BoxedValue; using zeolite_internal::WeakValue;
base/builtin.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -23,6 +23,7 @@ // Notes: // - You do not need () to make a function call on a literal; something like // true.asInt() is totally fine.+// - Values are unboxed when storing in variables. concrete Bool { immutable @@ -51,6 +52,7 @@ // 'a'.asInt() is totally fine. // - When converting to Int with asInt(), the value will always be unsigned, // i.e., beween 0-255. ASCII characters will be in the 0-127 range.+// - Values are unboxed when storing in variables. concrete Char { immutable @@ -73,9 +75,13 @@ // Literals: // - . required, with at least one digit on either side, e.g., 0.1 // - Scientific notation: 0.1E-10, etc.+// - Hex: \xABC.DEF, etc.+// - Octal: \o777.266, etc.+// - Binary: \b011.011, etc. // // Notes: // - You must use () to make a function call on a literal, e.g, (1.1).asInt().+// - Values are unboxed when storing in variables. concrete Float { immutable @@ -103,11 +109,10 @@ // - Overflow will cause a compilation error. // - Hex, oct, and binary escapes can go up to 2^64-1 to allow use of all 64 // bits, but they will still be used as signed values.-//-// Notes: // - You must use () to make a function call on a literal, e.g, (100).asFloat(). // - When converting to Char with asChar(), the value will always be treated as // unsigned, i.e., beween 0-255 mod 256.+// - Values are unboxed when storing in variables. concrete Int { immutable @@ -160,7 +165,7 @@ // Example: // // String.builder().append("foo").append("bar").build()- @type builder () -> ([Append<Formatted>&Build<String>])+ @type builder () -> ([Append<Formatted> & Build<String>]) } // Built-in fixed-size buffer of byte data.@@ -194,10 +199,33 @@ // values with incompatible types. // - This is category is only meant for passing C++ data between extensions when // it would otherwise require marshaling, which is why it has no functions.+// - Values are unboxed when storing in variables. concrete Pointer<#x> { immutable } +// An identifier for a value instance.+//+// Literals: None.+//+// Notes:+// - Get an Identifier<#x> from optional #x value with instance(value).+// - Also supports comparisons, e.g., <, ==.+// - Values are unboxed when storing in variables.+// - Identifiers will be unique for different concrete values if:+// - Both underlying concrete types are unboxed, which is the case with all+// custom concrete types.+// - Both values existed at the same time at some point.+concrete Identifier<|#x> {+ immutable++ refines Formatted+ refines Hashed++ defines Equals<Identifier<any>>+ defines LessThan<Identifier<any>>+}+ // Convertible to Bool. @value interface AsBool { // Convert the value to Bool.@@ -330,7 +358,7 @@ refines Container // Write the value at the given index and return self.- writeAt (Int,#x) -> (#self)+ writeAt (Int, #x) -> (#self) } // Sequence that can be subsequenced.@@ -338,7 +366,7 @@ refines Container // Return a copy of a subsequence.- subSequence (Int,Int) -> (#self)+ subSequence (Int, Int) -> (#self) } // The type has a default value.@@ -365,7 +393,7 @@ // - #x: The value type to be compared. @type interface Equals<#x|> { // Returns true iff the two values are equal. Must be symmetric.- equals (#x,#x) -> (Bool)+ equals (#x, #x) -> (Bool) } // The type can compare values for less-than.@@ -374,5 +402,5 @@ // - #x: The value type to be compared. @type interface LessThan<#x|> { // Returns true iff the first value is less than the second.- lessThan (#x,#x) -> (Bool)+ lessThan (#x, #x) -> (Bool) }
base/category-source.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -26,6 +26,7 @@ #include <vector> #include "boxed.hpp"+#include "cleanup.hpp" #include "cycle-check.hpp" #include "function.hpp" #include "returns.hpp"@@ -39,7 +40,9 @@ } #define BUILTIN_EXIT(e) { \- std::exit(e); \+ int code = e; \+ GlobalCleanup::Finish(code); \+ std::exit(code); \ __builtin_unreachable(); \ } @@ -73,6 +76,10 @@ return BoxedValue(reinterpret_cast<PrimPointer>(static_cast<T1*>(value))); } +inline BoxedValue Box_Identifier(PrimIdentifier value) {+ return BoxedValue(value);+}+ BoxedValue Box_String(const PrimString& value); S<const TypeInstance> Merge_Intersect(const L<S<const TypeInstance>>& params);@@ -178,6 +185,13 @@ } }; +#define TYPE_VALUE_CALL_UNLESS_EMPTY(expr, func, args, count) ({ \+ const BoxedValue result = expr; \+ BoxedValue::Present(result) \+ ? TypeValue::Call(result, func, args) \+ : ReturnTuple(count); \+ })+ class TypeValue { public: inline static ReturnTuple Call(const BoxedValue& target, const ValueFunction& label,@@ -254,5 +268,9 @@ std::atomic_flag lock_ = ATOMIC_FLAG_INIT; std::map<typename ParamsKey<P>::Type, W<T>> cache_; };++#ifdef ZEOLITE_TESTS_ONLY__YOUR_MODULE_IS_BROKEN_IF_YOU_USE_THIS_IN_HAND_WRITTEN_CODE+BoxedValue GetCallTrace(const ValueFunction& get_func, const ValueFunction& next_func);+#endif #endif // CATEGORY_SOURCE_HPP_
+ base/cleanup.hpp view
@@ -0,0 +1,56 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#ifndef CLEANUP_HPP_+#define CLEANUP_HPP_++#include "thread-capture.h"+#include "category-header.hpp"+++class GlobalCleanup : public capture_thread::ThreadCapture<GlobalCleanup> {+ public:+ // Executes cleanup routines in reverse order.+ static void Finish(int code);++ protected:+ // NOTE: Each destructor should call Cleanup().+ virtual ~GlobalCleanup() = default;+ virtual GlobalCleanup* GetNext() const = 0;+ virtual void Cleanup(int code) = 0;+};++// Executes type functions upon construction and destruction.+class WrapTypeCall : public GlobalCleanup {+ public:+ // Both start and finish take no args. finish is only called once, whether+ // it's via Finish() or the destructor.+ WrapTypeCall(S<const TypeInstance> type, const TypeFunction* start, const TypeFunction* finish);+ ~WrapTypeCall();++ protected:+ GlobalCleanup* GetNext() const override;+ void Cleanup(int code) override;++ private:+ const S<const TypeInstance> type_;+ const TypeFunction* finish_;+ const AutoThreadCrosser cross_and_capture_to_;+};++#endif // CLEANUP_HPP_
+ base/src/Builtin_Bool.cpp view
@@ -0,0 +1,100 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Bool.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Default.hpp"+#include "Category_Duplicate.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_Int.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Bool : public Category_Bool {+};++struct ExtType_Bool : public Type_Bool {+ inline ExtType_Bool(Category_Bool& p, Params<0>::Type params) : Type_Bool(p, params) {}++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Bool.default")+ return ReturnTuple(Box_Bool(false));+ }++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Bool.equals")+ const PrimBool Var_arg1 = (params_args.GetArg(0)).AsBool();+ const PrimBool Var_arg2 = (params_args.GetArg(1)).AsBool();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Bool.lessThan")+ const PrimBool Var_arg1 = (params_args.GetArg(0)).AsBool();+ const PrimBool Var_arg2 = (params_args.GetArg(1)).AsBool();+ return ReturnTuple(Box_Bool(!Var_arg1 && Var_arg2));+ }+};++ReturnTuple DispatchBool(PrimBool value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ case CategoryId_AsBool:+ return ReturnTuple(Box_Bool(value));+ case CategoryId_AsFloat:+ return ReturnTuple(Box_Float(value ? 1.0 : 0.0));+ case CategoryId_AsInt:+ return ReturnTuple(Box_Int(value? 1 : 0));+ case CategoryId_Duplicate:+ return ReturnTuple(Box_Bool(value));+ case CategoryId_Formatted:+ return ReturnTuple(Box_String(value? "true" : "false"));+ case CategoryId_Hashed:+ return ReturnTuple(Box_Int(value ? 1000000009ULL : 1000000007ULL));+ default:+ FAIL() << "Bool does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Bool& CreateCategory_Bool() {+ static auto& category = *new ExtCategory_Bool();+ return category;+}++S<const Type_Bool> CreateType_Bool(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Bool(CreateCategory_Bool(), Params<0>::Type()));+ return cached;+}++void RemoveType_Bool(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_Char.cpp view
@@ -0,0 +1,115 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Char.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsChar.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Char.hpp"+#include "Category_Default.hpp"+#include "Category_Duplicate.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Char : public Category_Char {+};++struct ExtType_Char : public Type_Char {+ inline ExtType_Char(Category_Char& p, Params<0>::Type params) : Type_Char(p, params) {}++ ReturnTuple Call_maxBound(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Char.maxBound")+ return ReturnTuple(Box_Char('\xff'));+ }++ ReturnTuple Call_minBound(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Char.minBound")+ return ReturnTuple(Box_Char('\0'));+ }++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Char.default")+ return ReturnTuple(Box_Char('\0'));+ }++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Char.equals")+ const PrimChar Var_arg1 = (params_args.GetArg(0)).AsChar();+ const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Char.lessThan")+ const PrimChar Var_arg1 = (params_args.GetArg(0)).AsChar();+ const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++ReturnTuple DispatchChar(PrimChar value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ case CategoryId_AsBool:+ return ReturnTuple(Box_Bool(value != '\0'));+ case CategoryId_AsChar:+ return ReturnTuple(Box_Char(value));+ case CategoryId_AsFloat:+ return ReturnTuple(Box_Float(((int) value + 256) % 256));+ case CategoryId_AsInt:+ return ReturnTuple(Box_Int(((int) value + 256) % 256));+ case CategoryId_Duplicate:+ return ReturnTuple(Box_Char(value));+ case CategoryId_Formatted:+ return ReturnTuple(Box_String(PrimString(1, value)));+ case CategoryId_Hashed:+ return ReturnTuple(Box_Int(1000000009ULL * ((unsigned long long) value + 1000000007ULL)));+ default:+ FAIL() << "Char does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Char& CreateCategory_Char() {+ static auto& category = *new ExtCategory_Char();+ return category;+}++S<const Type_Char> CreateType_Char(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Char(CreateCategory_Char(), Params<0>::Type()));+ return cached;+}++void RemoveType_Char(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_CharBuffer.cpp view
@@ -0,0 +1,115 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_CharBuffer.hpp"+#include "Category_Char.hpp"+#include "Category_CharBuffer.hpp"+#include "Category_Container.hpp"+#include "Category_Int.hpp"+#include "Category_ReadAt.hpp"+#include "Category_WriteAt.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++BoxedValue CreateValue_CharBuffer(S<const Type_CharBuffer> parent, PrimCharBuffer buffer);++struct ExtCategory_CharBuffer : public Category_CharBuffer {+};++struct ExtType_CharBuffer : public Type_CharBuffer {+ inline ExtType_CharBuffer(Category_CharBuffer& p, Params<0>::Type params) : Type_CharBuffer(p, params) {}++ ReturnTuple Call_new(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("CharBuffer.new")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ if (Var_arg1 < 0) {+ FAIL() << "Buffer size " << Var_arg1 << " is invalid";+ }+ return ReturnTuple(CreateValue_CharBuffer(CreateType_CharBuffer(Params<0>::Type()), PrimCharBuffer(Var_arg1,'\0')));+ }+};++struct ExtValue_CharBuffer : public Value_CharBuffer {+ inline ExtValue_CharBuffer(S<const Type_CharBuffer> p, PrimCharBuffer value)+ : Value_CharBuffer(std::move(p)), value_(std::move(value)) {}++ ReturnTuple Call_readAt(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("CharBuffer.readAt")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ if (Var_arg1 < 0 || Var_arg1 >= AsCharBuffer().size()) {+ FAIL() << "Read position " << Var_arg1 << " is out of bounds";+ }+ return ReturnTuple(Box_Char(AsCharBuffer()[Var_arg1]));+ }++ ReturnTuple Call_resize(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("CharBuffer.resize")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ if (Var_arg1 < 0) {+ FAIL() << "Buffer size " << Var_arg1 << " is invalid";+ } else {+ value_.resize(Var_arg1);+ }+ return ReturnTuple(VAR_SELF);+ }++ ReturnTuple Call_size(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("CharBuffer.size")+ return ReturnTuple(Box_Int(value_.size()));+ }++ ReturnTuple Call_writeAt(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("CharBuffer.writeAt")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();+ if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {+ FAIL() << "Write position " << Var_arg1 << " is out of bounds";+ } else {+ value_[Var_arg1] = Var_arg2;+ }+ return ReturnTuple(VAR_SELF);+ }++ PrimCharBuffer& AsCharBuffer() final { return value_; }++ PrimCharBuffer value_;+};++Category_CharBuffer& CreateCategory_CharBuffer() {+ static auto& category = *new ExtCategory_CharBuffer();+ return category;+}++S<const Type_CharBuffer> CreateType_CharBuffer(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_CharBuffer(CreateCategory_CharBuffer(), Params<0>::Type()));+ return cached;+}++void RemoveType_CharBuffer(const Params<0>::Type& params) {}++BoxedValue CreateValue_CharBuffer(S<const Type_CharBuffer> parent, PrimCharBuffer value) {+ return BoxedValue::New<ExtValue_CharBuffer>(std::move(parent), std::move(value));+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_Float.cpp view
@@ -0,0 +1,107 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <sstream>++#include "category-source.hpp"+#include "Streamlined_Float.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Default.hpp"+#include "Category_Duplicate.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Float : public Category_Float {+};++struct ExtType_Float : public Type_Float {+ inline ExtType_Float(Category_Float& p, Params<0>::Type params) : Type_Float(p, params) {}++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Float.default")+ return ReturnTuple(Box_Float(0.0));+ }++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Float.equals")+ const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();+ const PrimFloat Var_arg2 = (params_args.GetArg(1)).AsFloat();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Float.lessThan")+ const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();+ const PrimFloat Var_arg2 = (params_args.GetArg(1)).AsFloat();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++ReturnTuple DispatchFloat(PrimFloat value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ case CategoryId_AsBool:+ return ReturnTuple(Box_Bool(value != 0.0));+ case CategoryId_AsFloat:+ return ReturnTuple(Box_Float(value));+ case CategoryId_AsInt:+ return ReturnTuple(Box_Int(value));+ case CategoryId_Duplicate:+ return ReturnTuple(Box_Float(value));+ case CategoryId_Formatted: {+ // NOTE: std::to_string does weird things with significant digits.+ std::ostringstream output;+ output << value;+ return ReturnTuple(Box_String(output.str()));+ }+ case CategoryId_Hashed:+ return ReturnTuple(Box_Int(1000000009ULL * reinterpret_cast<uint64_t&>(value)));+ default:+ FAIL() << "Float does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Float& CreateCategory_Float() {+ static auto& category = *new ExtCategory_Float();+ return category;+}++S<const Type_Float> CreateType_Float(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Float(CreateCategory_Float(), Params<0>::Type()));+ return cached;+}++void RemoveType_Float(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_Identifier.cpp view
@@ -0,0 +1,98 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <iomanip>+#include <sstream>++#include "category-source.hpp"+#include "Streamlined_Identifier.hpp"+#include "Category_Equals.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_LessThan.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Identifier : public Category_Identifier {+};++struct ExtType_Identifier : public Type_Identifier {+ inline ExtType_Identifier(Category_Identifier& p, Params<1>::Type params) : Type_Identifier(p, params) {}++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Identifier.equals")+ const PrimIdentifier Var_arg1 = (params_args.GetArg(0)).AsIdentifier();+ const PrimIdentifier Var_arg2 = (params_args.GetArg(1)).AsIdentifier();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Identifier.lessThan")+ const PrimIdentifier Var_arg1 = (params_args.GetArg(0)).AsIdentifier();+ const PrimIdentifier Var_arg2 = (params_args.GetArg(1)).AsIdentifier();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++PrimIdentifier RandomizeIdentifier(PrimIdentifier identifier) {+ // This is random enough. It only needs to be odd.+ const static auto MULTIPLIER =+ ((unsigned long long) &CreateCategory_Identifier())+ + 1 - (1 & (unsigned long long) &CreateCategory_Identifier());+ return reinterpret_cast<PrimIdentifier>(MULTIPLIER * MULTIPLIER * ((unsigned long long) identifier));+}++ReturnTuple DispatchIdentifier(PrimIdentifier value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ case CategoryId_Formatted: {+ std::ostringstream output;+ output << std::hex << std::setfill('0') << std::setw(16) << (unsigned long long) value;+ return ReturnTuple(Box_String(output.str()));+ }+ case CategoryId_Hashed:+ return ReturnTuple(Box_Int(1000000009ULL * ((unsigned long long) value + 1000000007ULL)));+ default:+ FAIL() << "Identifier does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Identifier& CreateCategory_Identifier() {+ static auto& category = *new ExtCategory_Identifier();+ return category;+}++static auto& Identifier_instance_cache = *new InstanceCache<1, Type_Identifier>([](const Params<1>::Type& params) {+ return S_get(new ExtType_Identifier(CreateCategory_Identifier(), params));+ });++S<const Type_Identifier> CreateType_Identifier(const Params<1>::Type& params) {+ return Identifier_instance_cache.GetOrCreate(params);+}++void RemoveType_Identifier(const Params<1>::Type& params) {+ Identifier_instance_cache.Remove(params);+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_Int.cpp view
@@ -0,0 +1,118 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <climits>+#include <string>++#include "category-source.hpp"+#include "Streamlined_Int.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsChar.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Char.hpp"+#include "Category_Default.hpp"+#include "Category_Duplicate.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Int : public Category_Int {+};++struct ExtType_Int : public Type_Int {+ inline ExtType_Int(Category_Int& p, Params<0>::Type params) : Type_Int(p, params) {}++ ReturnTuple Call_maxBound(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Int.maxBound")+ return ReturnTuple(Box_Int(9223372036854775807LL));+ }++ ReturnTuple Call_minBound(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Int.minBound")+ return ReturnTuple(Box_Int(-9223372036854775807LL - 1LL));+ }++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Int.default")+ return ReturnTuple(Box_Int(0));+ }++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Int.equals")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Int.lessThan")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++ReturnTuple DispatchInt(PrimInt value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ case CategoryId_AsBool:+ return ReturnTuple(Box_Bool(value != 0));+ case CategoryId_AsChar:+ return ReturnTuple(Box_Char(PrimChar(((value % 256) + 256) % 256)));+ case CategoryId_AsFloat:+ return ReturnTuple(Box_Float(value));+ case CategoryId_AsInt:+ return ReturnTuple(Box_Int(value));+ case CategoryId_Duplicate:+ return ReturnTuple(Box_Int(value));+ case CategoryId_Formatted:+ return ReturnTuple(Box_String(std::to_string(value)));+ case CategoryId_Hashed:+ return ReturnTuple(Box_Int(1000000007ULL * value));+ default:+ FAIL() << "Int does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Int& CreateCategory_Int() {+ static auto& category = *new ExtCategory_Int();+ return category;+}++S<const Type_Int> CreateType_Int(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Int(CreateCategory_Int(), Params<0>::Type()));+ return cached;+}++void RemoveType_Int(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_Pointer.cpp view
@@ -0,0 +1,62 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Pointer.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Pointer : public Category_Pointer {+};++struct ExtType_Pointer : public Type_Pointer {+ inline ExtType_Pointer(Category_Pointer& p, Params<1>::Type params) : Type_Pointer(p, params) {}+};++ReturnTuple DispatchPointer(PrimPointer value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ default:+ FAIL() << "Pointer does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Pointer& CreateCategory_Pointer() {+ static auto& category = *new ExtCategory_Pointer();+ return category;+}++static auto& Pointer_instance_cache = *new InstanceCache<1, Type_Pointer>([](const Params<1>::Type& params) {+ return S_get(new ExtType_Pointer(CreateCategory_Pointer(), params));+ });++S<const Type_Pointer> CreateType_Pointer(const Params<1>::Type& params) {+ return Pointer_instance_cache.GetOrCreate(params);+}++void RemoveType_Pointer(const Params<1>::Type& params) {+ Pointer_instance_cache.Remove(params);+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Builtin_String.cpp view
@@ -0,0 +1,228 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_String.hpp"+#include "Category_Append.hpp"+#include "Category_AsBool.hpp"+#include "Category_Bool.hpp"+#include "Category_Build.hpp"+#include "Category_Char.hpp"+#include "Category_CharBuffer.hpp"+#include "Category_Container.hpp"+#include "Category_Default.hpp"+#include "Category_DefaultOrder.hpp"+#include "Category_Duplicate.hpp"+#include "Category_Equals.hpp"+#include "Category_Formatted.hpp"+#include "Category_Hashed.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_Order.hpp"+#include "Category_ReadAt.hpp"+#include "Category_String.hpp"+#include "Category_SubSequence.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_String : public Category_String {+};++class Value_StringBuilder : public TypeValue {+ public:+ std::string CategoryName() const final { return "StringBuilder"; }++ ReturnTuple Dispatch(const ValueFunction& label,+ const ParamsArgs& params_args) final {+ if (&label == &Function_Append_append) {+ TRACE_FUNCTION("StringBuilder.append")+ std::lock_guard<std::mutex> lock(mutex);+ output_ << TypeValue::Call(params_args.GetArg(0), Function_Formatted_formatted, PassParamsArgs()).At(0).AsString();+ return ReturnTuple(VAR_SELF);+ }+ if (&label == &Function_Build_build) {+ TRACE_FUNCTION("StringBuilder.build")+ std::lock_guard<std::mutex> lock(mutex);+ return ReturnTuple(Box_String(output_.str()));+ }+ return TypeValue::Dispatch(label, params_args);+ }++ private:+ std::mutex mutex;+ std::ostringstream output_;+};++struct ExtType_String : public Type_String {+ inline ExtType_String(Category_String& p, Params<0>::Type params) : Type_String(p, params) {}++ ReturnTuple Call_builder(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.builder")+ return ReturnTuple(BoxedValue::New<Value_StringBuilder>());+ }++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.default")+ return ReturnTuple(Box_String(""));+ }++ ReturnTuple Call_equals(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.equals")+ const BoxedValue& Var_arg1 = (params_args.GetArg(0));+ const BoxedValue& Var_arg2 = (params_args.GetArg(1));+ return ReturnTuple(Box_Bool(Var_arg1.AsString()==Var_arg2.AsString()));+ }++ ReturnTuple Call_fromCharBuffer(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.fromCharBuffer")+ const BoxedValue& Var_arg1 = (params_args.GetArg(0));+ return ReturnTuple(Box_String(PrimString(Var_arg1.AsCharBuffer())));+ }++ ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.lessThan")+ const BoxedValue& Var_arg1 = (params_args.GetArg(0));+ const BoxedValue& Var_arg2 = (params_args.GetArg(1));+ return ReturnTuple(Box_Bool(Var_arg1.AsString()<Var_arg2.AsString()));+ }+};++class StringOrder : public TypeValue {+ public:+ StringOrder(BoxedValue container, const std::string& s)+ : container_(container), value_(s) {}++ std::string CategoryName() const final { return "StringOrder"; }++ ReturnTuple Dispatch(const ValueFunction& label, const ParamsArgs& params_args) final {+ if (&label == &Function_Order_next) {+ TRACE_FUNCTION("StringOrder.next")+ if (index_+1 >= value_.size()) {+ return ReturnTuple(Var_empty);+ } else {+ ++index_;+ return ReturnTuple(VAR_SELF);+ }+ }+ if (&label == &Function_Order_get) {+ TRACE_FUNCTION("StringOrder.get")+ if (index_ >= value_.size()) {+ FAIL() << "Iterated past end of String";+ }+ return ReturnTuple(Box_Char(value_[index_]));+ }+ return TypeValue::Dispatch(label, params_args);+ }++ private:+ const BoxedValue container_;+ const std::string& value_;+ int index_ = 0;+};++struct ExtValue_String : public Value_String {+ inline ExtValue_String(S<const Type_String> p, const PrimString& value)+ : Value_String(std::move(p)), value_(value) {}++ ReturnTuple Call_asBool(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.asBool")+ return ReturnTuple(Box_Bool(value_.size() != 0));+ }++ ReturnTuple Call_defaultOrder(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.defaultOrder")+ if (value_.empty()) {+ return ReturnTuple(Var_empty);+ } else {+ return ReturnTuple(BoxedValue::New<StringOrder>(VAR_SELF, value_));+ }+ }++ ReturnTuple Call_duplicate(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.duplicate")+ return ReturnTuple(VAR_SELF);+ }++ ReturnTuple Call_formatted(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.formatted")+ return ReturnTuple(VAR_SELF);+ }++ ReturnTuple Call_hashed(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.hashed")+ PrimInt hash = 1000000009ULL;+ for (char c : value_) {+ hash = hash * 1000000009ULL + (unsigned long long) c * 1000000007ULL;+ }+ return ReturnTuple(Box_Int(hash));+ }++ ReturnTuple Call_readAt(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.readAt")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {+ FAIL() << "Read position " << Var_arg1 << " is out of bounds";+ }+ return ReturnTuple(Box_Char(value_[Var_arg1]));+ }++ ReturnTuple Call_size(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.size")+ return ReturnTuple(Box_Int(value_.size()));+ }++ ReturnTuple Call_subSequence(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("String.subSequence")+ const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();+ const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();+ if (Var_arg1 < 0 || Var_arg1 > value_.size()) {+ FAIL() << "Subsequence position " << Var_arg1 << " is out of bounds";+ }+ if (Var_arg2 < 0 || Var_arg1 + Var_arg2 > value_.size()) {+ FAIL() << "Subsequence size " << Var_arg2 << " is invalid";+ }+ return ReturnTuple(Box_String(value_.substr(Var_arg1,Var_arg2)));+ }++ const PrimString& AsString() const final { return value_; }++ const PrimString value_;+};++Category_String& CreateCategory_String() {+ static auto& category = *new ExtCategory_String();+ return category;+}++S<const Type_String> CreateType_String(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_String(CreateCategory_String(), Params<0>::Type()));+ return cached;+}++void RemoveType_String(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++BoxedValue Box_String(const PrimString& value) {+ return BoxedValue::New<ExtValue_String>(CreateType_String(Params<0>::Type()), value);+}
− base/src/Extension_Bool.cpp
@@ -1,100 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"-#include "Streamlined_Bool.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsFloat.hpp"-#include "Category_AsInt.hpp"-#include "Category_Bool.hpp"-#include "Category_Default.hpp"-#include "Category_Duplicate.hpp"-#include "Category_Equals.hpp"-#include "Category_Float.hpp"-#include "Category_Formatted.hpp"-#include "Category_Hashed.hpp"-#include "Category_Int.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Bool : public Category_Bool {-};--struct ExtType_Bool : public Type_Bool {- inline ExtType_Bool(Category_Bool& p, Params<0>::Type params) : Type_Bool(p, params) {}-- ReturnTuple Call_default(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Bool.default")- return ReturnTuple(Box_Bool(false));- }-- ReturnTuple Call_equals(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Bool.equals")- const PrimBool Var_arg1 = (params_args.GetArg(0)).AsBool();- const PrimBool Var_arg2 = (params_args.GetArg(1)).AsBool();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));- }-- ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Bool.lessThan")- const PrimBool Var_arg1 = (params_args.GetArg(0)).AsBool();- const PrimBool Var_arg2 = (params_args.GetArg(1)).AsBool();- return ReturnTuple(Box_Bool(!Var_arg1 && Var_arg2));- }-};--ReturnTuple DispatchBool(PrimBool value, const ValueFunction& label,- const ParamsArgs& params_args) {- switch (label.collection) {- case CategoryId_AsBool:- return ReturnTuple(Box_Bool(value));- case CategoryId_AsFloat:- return ReturnTuple(Box_Float(value ? 1.0 : 0.0));- case CategoryId_AsInt:- return ReturnTuple(Box_Int(value? 1 : 0));- case CategoryId_Duplicate:- return ReturnTuple(Box_Bool(value));- case CategoryId_Formatted:- return ReturnTuple(Box_String(value? "true" : "false"));- case CategoryId_Hashed:- return ReturnTuple(Box_Int(value ? 1000000009ULL : 1000000007ULL));- default:- FAIL() << "Bool does not implement " << label;- __builtin_unreachable();- }-}--Category_Bool& CreateCategory_Bool() {- static auto& category = *new ExtCategory_Bool();- return category;-}--S<const Type_Bool> CreateType_Bool(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_Bool(CreateCategory_Bool(), Params<0>::Type()));- return cached;-}--void RemoveType_Bool(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_Char.cpp
@@ -1,115 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"-#include "Streamlined_Char.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsChar.hpp"-#include "Category_AsFloat.hpp"-#include "Category_AsInt.hpp"-#include "Category_Bool.hpp"-#include "Category_Char.hpp"-#include "Category_Default.hpp"-#include "Category_Duplicate.hpp"-#include "Category_Equals.hpp"-#include "Category_Float.hpp"-#include "Category_Formatted.hpp"-#include "Category_Hashed.hpp"-#include "Category_Int.hpp"-#include "Category_LessThan.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Char : public Category_Char {-};--struct ExtType_Char : public Type_Char {- inline ExtType_Char(Category_Char& p, Params<0>::Type params) : Type_Char(p, params) {}-- ReturnTuple Call_maxBound(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Char.maxBound")- return ReturnTuple(Box_Char('\xff'));- }-- ReturnTuple Call_minBound(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Char.minBound")- return ReturnTuple(Box_Char('\0'));- }-- ReturnTuple Call_default(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Char.default")- return ReturnTuple(Box_Char('\0'));- }-- ReturnTuple Call_equals(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Char.equals")- const PrimChar Var_arg1 = (params_args.GetArg(0)).AsChar();- const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));- }-- ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Char.lessThan")- const PrimChar Var_arg1 = (params_args.GetArg(0)).AsChar();- const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));- }-};--ReturnTuple DispatchChar(PrimChar value, const ValueFunction& label,- const ParamsArgs& params_args) {- switch (label.collection) {- case CategoryId_AsBool:- return ReturnTuple(Box_Bool(value != '\0'));- case CategoryId_AsChar:- return ReturnTuple(Box_Char(value));- case CategoryId_AsFloat:- return ReturnTuple(Box_Float(((int) value + 256) % 256));- case CategoryId_AsInt:- return ReturnTuple(Box_Int(((int) value + 256) % 256));- case CategoryId_Duplicate:- return ReturnTuple(Box_Char(value));- case CategoryId_Formatted:- return ReturnTuple(Box_String(PrimString(1, value)));- case CategoryId_Hashed:- return ReturnTuple(Box_Int(1000000009ULL * ((unsigned long long) value + 1000000007ULL)));- default:- FAIL() << "Char does not implement " << label;- __builtin_unreachable();- }-}--Category_Char& CreateCategory_Char() {- static auto& category = *new ExtCategory_Char();- return category;-}--S<const Type_Char> CreateType_Char(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_Char(CreateCategory_Char(), Params<0>::Type()));- return cached;-}--void RemoveType_Char(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_CharBuffer.cpp
@@ -1,115 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"-#include "Streamlined_CharBuffer.hpp"-#include "Category_Char.hpp"-#include "Category_CharBuffer.hpp"-#include "Category_Container.hpp"-#include "Category_Int.hpp"-#include "Category_ReadAt.hpp"-#include "Category_WriteAt.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue CreateValue_CharBuffer(S<const Type_CharBuffer> parent, PrimCharBuffer buffer);--struct ExtCategory_CharBuffer : public Category_CharBuffer {-};--struct ExtType_CharBuffer : public Type_CharBuffer {- inline ExtType_CharBuffer(Category_CharBuffer& p, Params<0>::Type params) : Type_CharBuffer(p, params) {}-- ReturnTuple Call_new(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("CharBuffer.new")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- if (Var_arg1 < 0) {- FAIL() << "Buffer size " << Var_arg1 << " is invalid";- }- return ReturnTuple(CreateValue_CharBuffer(CreateType_CharBuffer(Params<0>::Type()), PrimCharBuffer(Var_arg1,'\0')));- }-};--struct ExtValue_CharBuffer : public Value_CharBuffer {- inline ExtValue_CharBuffer(S<const Type_CharBuffer> p, PrimCharBuffer value)- : Value_CharBuffer(std::move(p)), value_(std::move(value)) {}-- ReturnTuple Call_readAt(const ParamsArgs& params_args) final {- TRACE_FUNCTION("CharBuffer.readAt")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- if (Var_arg1 < 0 || Var_arg1 >= AsCharBuffer().size()) {- FAIL() << "Read position " << Var_arg1 << " is out of bounds";- }- return ReturnTuple(Box_Char(AsCharBuffer()[Var_arg1]));- }-- ReturnTuple Call_resize(const ParamsArgs& params_args) final {- TRACE_FUNCTION("CharBuffer.resize")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- if (Var_arg1 < 0) {- FAIL() << "Buffer size " << Var_arg1 << " is invalid";- } else {- value_.resize(Var_arg1);- }- return ReturnTuple(VAR_SELF);- }-- ReturnTuple Call_size(const ParamsArgs& params_args) final {- TRACE_FUNCTION("CharBuffer.size")- return ReturnTuple(Box_Int(value_.size()));- }-- ReturnTuple Call_writeAt(const ParamsArgs& params_args) final {- TRACE_FUNCTION("CharBuffer.writeAt")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- const PrimChar Var_arg2 = (params_args.GetArg(1)).AsChar();- if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {- FAIL() << "Write position " << Var_arg1 << " is out of bounds";- } else {- value_[Var_arg1] = Var_arg2;- }- return ReturnTuple(VAR_SELF);- }-- PrimCharBuffer& AsCharBuffer() final { return value_; }-- PrimCharBuffer value_;-};--Category_CharBuffer& CreateCategory_CharBuffer() {- static auto& category = *new ExtCategory_CharBuffer();- return category;-}--S<const Type_CharBuffer> CreateType_CharBuffer(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_CharBuffer(CreateCategory_CharBuffer(), Params<0>::Type()));- return cached;-}--void RemoveType_CharBuffer(const Params<0>::Type& params) {}--BoxedValue CreateValue_CharBuffer(S<const Type_CharBuffer> parent, PrimCharBuffer value) {- return BoxedValue::New<ExtValue_CharBuffer>(std::move(parent), std::move(value));-}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_Float.cpp
@@ -1,107 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include <sstream>--#include "category-source.hpp"-#include "Streamlined_Float.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsFloat.hpp"-#include "Category_AsInt.hpp"-#include "Category_Bool.hpp"-#include "Category_Default.hpp"-#include "Category_Duplicate.hpp"-#include "Category_Equals.hpp"-#include "Category_Float.hpp"-#include "Category_Formatted.hpp"-#include "Category_Hashed.hpp"-#include "Category_Int.hpp"-#include "Category_LessThan.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Float : public Category_Float {-};--struct ExtType_Float : public Type_Float {- inline ExtType_Float(Category_Float& p, Params<0>::Type params) : Type_Float(p, params) {}-- ReturnTuple Call_default(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Float.default")- return ReturnTuple(Box_Float(0.0));- }-- ReturnTuple Call_equals(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Float.equals")- const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();- const PrimFloat Var_arg2 = (params_args.GetArg(1)).AsFloat();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));- }-- ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Float.lessThan")- const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();- const PrimFloat Var_arg2 = (params_args.GetArg(1)).AsFloat();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));- }-};--ReturnTuple DispatchFloat(PrimFloat value, const ValueFunction& label,- const ParamsArgs& params_args) {- switch (label.collection) {- case CategoryId_AsBool:- return ReturnTuple(Box_Bool(value != 0.0));- case CategoryId_AsFloat:- return ReturnTuple(Box_Float(value));- case CategoryId_AsInt:- return ReturnTuple(Box_Int(value));- case CategoryId_Duplicate:- return ReturnTuple(Box_Float(value));- case CategoryId_Formatted: {- // NOTE: std::to_string does weird things with significant digits.- std::ostringstream output;- output << value;- return ReturnTuple(Box_String(output.str()));- }- case CategoryId_Hashed:- return ReturnTuple(Box_Int(1000000009ULL * reinterpret_cast<uint64_t&>(value)));- default:- FAIL() << "Float does not implement " << label;- __builtin_unreachable();- }-}--Category_Float& CreateCategory_Float() {- static auto& category = *new ExtCategory_Float();- return category;-}--S<const Type_Float> CreateType_Float(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_Float(CreateCategory_Float(), Params<0>::Type()));- return cached;-}--void RemoveType_Float(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_Int.cpp
@@ -1,118 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include <climits>-#include <string>--#include "category-source.hpp"-#include "Streamlined_Int.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsChar.hpp"-#include "Category_AsFloat.hpp"-#include "Category_AsInt.hpp"-#include "Category_Bool.hpp"-#include "Category_Char.hpp"-#include "Category_Default.hpp"-#include "Category_Duplicate.hpp"-#include "Category_Equals.hpp"-#include "Category_Float.hpp"-#include "Category_Formatted.hpp"-#include "Category_Hashed.hpp"-#include "Category_Int.hpp"-#include "Category_LessThan.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Int : public Category_Int {-};--struct ExtType_Int : public Type_Int {- inline ExtType_Int(Category_Int& p, Params<0>::Type params) : Type_Int(p, params) {}-- ReturnTuple Call_maxBound(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Int.maxBound")- return ReturnTuple(Box_Int(9223372036854775807LL));- }-- ReturnTuple Call_minBound(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Int.minBound")- return ReturnTuple(Box_Int(-9223372036854775807LL - 1LL));- }-- ReturnTuple Call_default(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Int.default")- return ReturnTuple(Box_Int(0));- }-- ReturnTuple Call_equals(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Int.equals")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));- }-- ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Int.lessThan")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));- }-};--ReturnTuple DispatchInt(PrimInt value, const ValueFunction& label,- const ParamsArgs& params_args) {- switch (label.collection) {- case CategoryId_AsBool:- return ReturnTuple(Box_Bool(value != 0));- case CategoryId_AsChar:- return ReturnTuple(Box_Char(PrimChar(((value % 256) + 256) % 256)));- case CategoryId_AsFloat:- return ReturnTuple(Box_Float(value));- case CategoryId_AsInt:- return ReturnTuple(Box_Int(value));- case CategoryId_Duplicate:- return ReturnTuple(Box_Int(value));- case CategoryId_Formatted:- return ReturnTuple(Box_String(std::to_string(value)));- case CategoryId_Hashed:- return ReturnTuple(Box_Int(1000000007ULL * value));- default:- FAIL() << "Int does not implement " << label;- __builtin_unreachable();- }-}--Category_Int& CreateCategory_Int() {- static auto& category = *new ExtCategory_Int();- return category;-}--S<const Type_Int> CreateType_Int(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_Int(CreateCategory_Int(), Params<0>::Type()));- return cached;-}--void RemoveType_Int(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_Pointer.cpp
@@ -1,62 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2022 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"-#include "Streamlined_Pointer.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Pointer : public Category_Pointer {-};--struct ExtType_Pointer : public Type_Pointer {- inline ExtType_Pointer(Category_Pointer& p, Params<1>::Type params) : Type_Pointer(p, params) {}-};--ReturnTuple DispatchPointer(PrimPointer value, const ValueFunction& label,- const ParamsArgs& params_args) {- switch (label.collection) {- default:- FAIL() << "Pointer does not implement " << label;- __builtin_unreachable();- }-}--Category_Pointer& CreateCategory_Pointer() {- static auto& category = *new ExtCategory_Pointer();- return category;-}--static auto& Pointer_instance_cache = *new InstanceCache<1, Type_Pointer>([](const Params<1>::Type& params) {- return S_get(new ExtType_Pointer(CreateCategory_Pointer(), params));- });--S<const Type_Pointer> CreateType_Pointer(const Params<1>::Type& params) {- return Pointer_instance_cache.GetOrCreate(params);-}--void RemoveType_Pointer(const Params<1>::Type& params) {- Pointer_instance_cache.Remove(params);-}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− base/src/Extension_String.cpp
@@ -1,228 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"-#include "Streamlined_String.hpp"-#include "Category_Append.hpp"-#include "Category_AsBool.hpp"-#include "Category_Bool.hpp"-#include "Category_Build.hpp"-#include "Category_Char.hpp"-#include "Category_CharBuffer.hpp"-#include "Category_Container.hpp"-#include "Category_Default.hpp"-#include "Category_DefaultOrder.hpp"-#include "Category_Duplicate.hpp"-#include "Category_Equals.hpp"-#include "Category_Formatted.hpp"-#include "Category_Hashed.hpp"-#include "Category_Int.hpp"-#include "Category_LessThan.hpp"-#include "Category_Order.hpp"-#include "Category_ReadAt.hpp"-#include "Category_String.hpp"-#include "Category_SubSequence.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_String : public Category_String {-};--class Value_StringBuilder : public TypeValue {- public:- std::string CategoryName() const final { return "StringBuilder"; }-- ReturnTuple Dispatch(const ValueFunction& label,- const ParamsArgs& params_args) final {- if (&label == &Function_Append_append) {- TRACE_FUNCTION("StringBuilder.append")- std::lock_guard<std::mutex> lock(mutex);- output_ << TypeValue::Call(params_args.GetArg(0), Function_Formatted_formatted, PassParamsArgs()).At(0).AsString();- return ReturnTuple(VAR_SELF);- }- if (&label == &Function_Build_build) {- TRACE_FUNCTION("StringBuilder.build")- std::lock_guard<std::mutex> lock(mutex);- return ReturnTuple(Box_String(output_.str()));- }- return TypeValue::Dispatch(label, params_args);- }-- private:- std::mutex mutex;- std::ostringstream output_;-};--struct ExtType_String : public Type_String {- inline ExtType_String(Category_String& p, Params<0>::Type params) : Type_String(p, params) {}-- ReturnTuple Call_builder(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.builder")- return ReturnTuple(BoxedValue::New<Value_StringBuilder>());- }-- ReturnTuple Call_default(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.default")- return ReturnTuple(Box_String(""));- }-- ReturnTuple Call_equals(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.equals")- const BoxedValue& Var_arg1 = (params_args.GetArg(0));- const BoxedValue& Var_arg2 = (params_args.GetArg(1));- return ReturnTuple(Box_Bool(Var_arg1.AsString()==Var_arg2.AsString()));- }-- ReturnTuple Call_fromCharBuffer(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.fromCharBuffer")- const BoxedValue& Var_arg1 = (params_args.GetArg(0));- return ReturnTuple(Box_String(PrimString(Var_arg1.AsCharBuffer())));- }-- ReturnTuple Call_lessThan(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.lessThan")- const BoxedValue& Var_arg1 = (params_args.GetArg(0));- const BoxedValue& Var_arg2 = (params_args.GetArg(1));- return ReturnTuple(Box_Bool(Var_arg1.AsString()<Var_arg2.AsString()));- }-};--class StringOrder : public TypeValue {- public:- StringOrder(BoxedValue container, const std::string& s)- : container_(container), value_(s) {}-- std::string CategoryName() const final { return "StringOrder"; }-- ReturnTuple Dispatch(const ValueFunction& label, const ParamsArgs& params_args) final {- if (&label == &Function_Order_next) {- TRACE_FUNCTION("StringOrder.next")- if (index_+1 >= value_.size()) {- return ReturnTuple(Var_empty);- } else {- ++index_;- return ReturnTuple(VAR_SELF);- }- }- if (&label == &Function_Order_get) {- TRACE_FUNCTION("StringOrder.get")- if (index_ >= value_.size()) {- FAIL() << "Iterated past end of String";- }- return ReturnTuple(Box_Char(value_[index_]));- }- return TypeValue::Dispatch(label, params_args);- }-- private:- const BoxedValue container_;- const std::string& value_;- int index_ = 0;-};--struct ExtValue_String : public Value_String {- inline ExtValue_String(S<const Type_String> p, const PrimString& value)- : Value_String(std::move(p)), value_(value) {}-- ReturnTuple Call_asBool(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.asBool")- return ReturnTuple(Box_Bool(value_.size() != 0));- }-- ReturnTuple Call_defaultOrder(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.defaultOrder")- if (value_.empty()) {- return ReturnTuple(Var_empty);- } else {- return ReturnTuple(BoxedValue::New<StringOrder>(VAR_SELF, value_));- }- }-- ReturnTuple Call_duplicate(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.duplicate")- return ReturnTuple(VAR_SELF);- }-- ReturnTuple Call_formatted(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.formatted")- return ReturnTuple(VAR_SELF);- }-- ReturnTuple Call_hashed(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.hashed")- PrimInt hash = 1000000009ULL;- for (char c : value_) {- hash = hash * 1000000009ULL + (unsigned long long) c * 1000000007ULL;- }- return ReturnTuple(Box_Int(hash));- }-- ReturnTuple Call_readAt(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.readAt")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {- FAIL() << "Read position " << Var_arg1 << " is out of bounds";- }- return ReturnTuple(Box_Char(value_[Var_arg1]));- }-- ReturnTuple Call_size(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.size")- return ReturnTuple(Box_Int(value_.size()));- }-- ReturnTuple Call_subSequence(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("String.subSequence")- const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- const PrimInt Var_arg2 = (params_args.GetArg(1)).AsInt();- if (Var_arg1 < 0 || Var_arg1 > value_.size()) {- FAIL() << "Subsequence position " << Var_arg1 << " is out of bounds";- }- if (Var_arg2 < 0 || Var_arg1 + Var_arg2 > value_.size()) {- FAIL() << "Subsequence size " << Var_arg2 << " is invalid";- }- return ReturnTuple(Box_String(value_.substr(Var_arg1,Var_arg2)));- }-- const PrimString& AsString() const final { return value_; }-- const PrimString value_;-};--Category_String& CreateCategory_String() {- static auto& category = *new ExtCategory_String();- return category;-}--S<const Type_String> CreateType_String(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_String(CreateCategory_String(), Params<0>::Type()));- return cached;-}--void RemoveType_String(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue Box_String(const PrimString& value) {- return BoxedValue::New<ExtValue_String>(CreateType_String(Params<0>::Type()), value);-}
base/src/boxed.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021-2022 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -42,6 +42,11 @@ ReturnTuple DispatchPointer(PrimPointer value, const ValueFunction& label, const ParamsArgs& params_args) __attribute__((weak)); +ReturnTuple DispatchIdentifier(PrimIdentifier value, const ValueFunction& label,+ const ParamsArgs& params_args) __attribute__((weak));++PrimIdentifier RandomizeIdentifier(PrimIdentifier identifier) __attribute__((weak));+ #ifdef ZEOLITE_PUBLIC_NAMESPACE } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE;@@ -83,12 +88,13 @@ std::string UnionValue::CategoryName() const { switch (type_) {- case UnionValue::Type::EMPTY: return "empty";- case UnionValue::Type::BOOL: return "Bool";- case UnionValue::Type::CHAR: return "Char";- case UnionValue::Type::INT: return "Int";- case UnionValue::Type::FLOAT: return "Float";- case UnionValue::Type::POINTER: return "Pointer";+ case UnionValue::Type::EMPTY: return "empty";+ case UnionValue::Type::BOOL: return "Bool";+ case UnionValue::Type::CHAR: return "Char";+ case UnionValue::Type::INT: return "Int";+ case UnionValue::Type::FLOAT: return "Float";+ case UnionValue::Type::POINTER: return "Pointer";+ case UnionValue::Type::IDENTIFIER: return "Identifier"; case UnionValue::Type::BOXED: if (!value_.as_boxed_ || !value_.as_boxed_->object_) { FAIL() << "Function called on null pointer";@@ -120,6 +126,16 @@ zeolite_internal::Validate(name, union_); } +// static+PrimIdentifier BoxedValue::Identify(const BoxedValue& target) {+ switch (target.union_.type_) {+ case UnionValue::Type::IDENTIFIER:+ return target.union_.value_.as_identifier_;+ default:+ return RandomizeIdentifier(target.union_.value_.as_identifier_);+ }+}+ const PrimString& BoxedValue::AsString() const { switch (union_.type_) { case UnionValue::Type::BOXED:@@ -165,6 +181,8 @@ return DispatchFloat(union_.value_.as_float_, label, params_args); case UnionValue::Type::POINTER: return DispatchPointer(union_.value_.as_pointer_, label, params_args);+ case UnionValue::Type::IDENTIFIER:+ return DispatchIdentifier(union_.value_.as_identifier_, label, params_args); case UnionValue::Type::BOXED: if (!union_.value_.as_boxed_ || !union_.value_.as_boxed_->object_) { FAIL() << "Function called on null pointer";
base/src/category-source.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -269,4 +269,43 @@ PrimCharBuffer& TypeValue::AsCharBuffer() { FAIL() << CategoryName() << " is not a CharBuffer value"; __builtin_unreachable();+}++namespace {++class CallTrace : public TypeValue {+ public:+ CallTrace(BoxedValue next, std::string trace, const ValueFunction& get_func, const ValueFunction& next_func)+ : next_(std::move(next)), trace_(std::move(trace)), next_func_(next_func), get_func_(get_func) {}++ std::string CategoryName() const override {+ return "CallTrace";+ }++ ReturnTuple Dispatch(const ValueFunction& label, const ParamsArgs& params_args) override {+ if (&label == &next_func_) {+ return ReturnTuple(next_);+ }+ if (&label == &get_func_) {+ return ReturnTuple(Box_String(trace_));+ }+ return TypeValue::Dispatch(label, params_args);+ }++ private:+ const BoxedValue next_;+ const std::string trace_;+ const ValueFunction& get_func_;+ const ValueFunction& next_func_;+};++} // namespace++BoxedValue GetCallTrace(const ValueFunction& get_func, const ValueFunction& next_func) {+ const TraceList trace = TraceContext::GetTrace();+ BoxedValue head;+ for (auto current = trace.rbegin(), end = trace.rend(); current != end; ++current) {+ head = BoxedValue::New<CallTrace>(head, (*current)(), get_func, next_func);+ }+ return head; }
+ base/src/cleanup.cpp view
@@ -0,0 +1,53 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "cleanup.hpp"++#include "category-source.hpp"+++// static+void GlobalCleanup::Finish(int code) {+ GlobalCleanup* current = GetCurrent();+ while (current) {+ current->Cleanup(code);+ current = current->GetNext();+ }+}++WrapTypeCall::WrapTypeCall(S<const TypeInstance> type, const TypeFunction* start, const TypeFunction* finish)+ : type_(std::move(type)), finish_(finish), cross_and_capture_to_(this) {+ if (start) {+ (void) TypeInstance::Call(type_, *start, PassParamsArgs());+ }+}++WrapTypeCall::~WrapTypeCall() {+ Cleanup(0);+}++GlobalCleanup* WrapTypeCall::GetNext() const {+ return cross_and_capture_to_.Previous();+}++void WrapTypeCall::Cleanup(int code) {+ if (finish_) {+ (void) TypeInstance::Call(type_, *finish_, PassParamsArgs());+ finish_ = nullptr;+ }+}
+ base/testing.0rp view
@@ -0,0 +1,25 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++// Used for automating checks for a testcase.+@type interface Testcase {+ start () -> ()+ finish () -> ()+}
base/types.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -47,6 +47,45 @@ class OpaqueObject { ~OpaqueObject() = default; }; using PrimPointer = OpaqueObject*; +class OpaqueInstance { ~OpaqueInstance() = default; };+using PrimIdentifier = OpaqueInstance*;++inline void SwapValues(PrimBool& left, PrimBool& right) {+ PrimBool temp = right;+ right = left;+ left = temp;+}++inline void SwapValues(PrimInt& left, PrimInt& right) {+ PrimInt temp = right;+ right = left;+ left = temp;+}++inline void SwapValues(PrimChar& left, PrimChar& right) {+ PrimChar temp = right;+ right = left;+ left = temp;+}++inline void SwapValues(PrimFloat& left, PrimFloat& right) {+ PrimFloat temp = right;+ right = left;+ left = temp;+}++inline void SwapValues(PrimPointer& left, PrimPointer& right) {+ PrimPointer temp = right;+ right = left;+ left = temp;+}++inline void SwapValues(PrimIdentifier& left, PrimIdentifier& right) {+ PrimIdentifier temp = right;+ right = left;+ left = temp;+}+ template<int S> inline PrimString PrimString_FromLiteral(const char(&literal)[S]) { return PrimString(literal, literal + (S - 1));@@ -96,6 +135,12 @@ return *this; } + LazyInit& operator = (T&& value) {+ InitValue();+ value_ = value;+ return *this;+ }+ private: LazyInit(const LazyInit&) = delete; LazyInit(LazyInit&&) = delete;@@ -118,6 +163,27 @@ T value_; const std::function<T()> create_; };++template<class T>+inline void SwapValues(LazyInit<T>& left, LazyInit<T>& right) {+ T temp = right.Get();+ right = left.Get();+ left = std::move(temp);+}++template<class T>+inline void SwapValues(T& left, LazyInit<T>& right) {+ T temp = right.Get();+ right = std::move(left);+ left = std::move(temp);+}++template<class T>+inline void SwapValues(LazyInit<T>& left, T& right) {+ T temp = std::move(right);+ right = left.Get();+ left = std::move(temp);+} class TypeCategory;
bin/zeolite-setup.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -40,6 +40,7 @@ then handle pn os else compilerErrorM "Parallel processes (-j) must be > 0." _ -> compilerErrorM "Parallel processes (-j) must be > 0."+ handle pn (('-':'j':n@(_:_)):os) = handle pn ("-j":n:os) handle pn ("--reuse":_) = do config <- loadConfig runWith pn config@@ -68,13 +69,13 @@ libraries :: [String] libraries = [ "base",+ "tests", "lib/testing", "lib/util", "lib/container", "lib/file", "lib/math",- "lib/thread",- "tests"+ "lib/thread" ] optionalLibraries :: [String]@@ -173,6 +174,8 @@ _coForce = ForceAll, _coParallel = pn }- runCompiler resolver backend options+ -- The 2 lines below suppress warnings if there were no errors.+ result <- lift $ toTrackedErrors $ runCompiler resolver backend options+ when (isCompilerError result) (fromTrackedErrors result) mapM_ optionalWarning optionalLibraries where optionalWarning library = compilerWarningM $ "Optional library " ++ library ++ " must be built manually if needed"
example/parser/.zeolite-module view
@@ -7,4 +7,4 @@ "lib/file" "lib/testing" ]-mode: incremental {}+mode: incremental { }
example/parser/parse-text.0rp view
@@ -5,7 +5,7 @@ // Parses a string containing a limited set of characters. concrete SequenceOfParser {- @type create (String, Int /*min*/, Int /*max*/) -> (Parser<String>)+ @type create (String, Int min:, Int max:) -> (Parser<String>) } // Parses a fixed character.@@ -21,7 +21,7 @@ @type error (Formatted) -> (Parser<all>) @type try<#x> (Parser<#x>) -> (Parser<#x>)- @type or<#x> (Parser<#x>,Parser<#x>) -> (Parser<#x>)- @type left<#x> (Parser<#x>,Parser<any>) -> (Parser<#x>)- @type right<#x> (Parser<any>,Parser<#x>) -> (Parser<#x>)+ @type or<#x> (Parser<#x>, Parser<#x>) -> (Parser<#x>)+ @type left<#x> (Parser<#x>, Parser<any>) -> (Parser<#x>)+ @type right<#x> (Parser<any>, Parser<#x>) -> (Parser<#x>) }
example/parser/parse-text.0rx view
@@ -25,7 +25,7 @@ } create (match) {- return StringParser{ match }+ return delegate -> #self } } @@ -44,7 +44,7 @@ min.formatted() + "," + max.formatted() + "} at " + contextOld.getPosition() ParseContext<any> context <- contextOld- [Append<Formatted>&Build<String>] builder <- String.builder()+ [Append<Formatted> & Build<String>] builder <- String.builder() optional Order<Int> counter <- defer if (max == 0) {@@ -55,13 +55,13 @@ Int count <- 0 traverse (counter -> count) {- $Hidden[count,counter]$+ $Hidden[count, counter]$ if (context.atEof()) { break } Bool found <- false traverse (Counter.zeroIndexed(matches.size()) -> Int index) {- $ReadOnly[context,index]$+ $ReadOnly[context, index]$ if (context.current() == matches.readAt(index)) { \ builder.append(matches.readAt(index)) found <- true@@ -83,8 +83,8 @@ } } - create (matches,min,max) {- return SequenceOfParser{ matches, min, max }+ create (matches, min, max) {+ return delegate -> #self } } @@ -106,7 +106,7 @@ } create (match) {- return CharParser{ match }+ return delegate -> #self } } @@ -126,7 +126,7 @@ } create (value) {- return #self{ value }+ return delegate -> #self } } @@ -170,12 +170,12 @@ } create (parser) {- return #self{ parser }+ return delegate -> #self } } concrete OrParser<#x> {- @type create (Parser<#x>,Parser<#x>) -> (Parser<#x>)+ @type create (Parser<#x>, Parser<#x>) -> (Parser<#x>) } define OrParser {@@ -196,14 +196,14 @@ } } - create (parser1,parser2) {- return #self{ parser1, parser2 }+ create (parser1, parser2) {+ return delegate -> #self } } concrete LeftParser<#x> { - @type create (Parser<#x>,Parser<any>) -> (Parser<#x>)+ @type create (Parser<#x>, Parser<any>) -> (Parser<#x>) } define LeftParser {@@ -229,13 +229,13 @@ } } - create (parser1,parser2) {- return #self{ parser1, parser2 }+ create (parser1, parser2) {+ return delegate -> #self } } concrete RightParser<#x> {- @type create (Parser<any>,Parser<#x>) -> (Parser<#x>)+ @type create (Parser<any>, Parser<#x>) -> (Parser<#x>) } define RightParser {@@ -256,33 +256,33 @@ } } - create (parser1,parser2) {- return #self{ parser1, parser2 }+ create (parser1, parser2) {+ return delegate -> #self } } define Parse { error (message) {- return ErrorParser.create(message)+ return delegate -> `ErrorParser.create` } const (value) {- return ConstParser<#x>.create(value)+ return delegate -> `ConstParser<#x>.create` } try (parser) {- return TryParser<#x>.create(parser)+ return delegate -> `TryParser<#x>.create` } - or (parser1,parser2) {- return OrParser<#x>.create(parser1,parser2)+ or (parser1, parser2) {+ return delegate -> `OrParser<#x>.create` } - left (parser1,parser2) {- return LeftParser<#x>.create(parser1,parser2)+ left (parser1, parser2) {+ return delegate -> `LeftParser<#x>.create` } - right (parser1,parser2) {- return RightParser<#x>.create(parser1,parser2)+ right (parser1, parser2) {+ return delegate -> `RightParser<#x>.create` } }
example/parser/parser-test.0rt view
@@ -1,13 +1,30 @@ testcase "parse data from a file" {- success+ // We need to specify TestChecker here in order to use lib/testing.+ success TestChecker } unittest test { String raw <- FileTesting.forceReadFile($ExprLookup[MODULE_PATH]$ + "/test-data.txt")- ErrorOr<TestData> errorOrData <- TestDataParser.create() `ParseState:consumeAll` raw- TestData data <- errorOrData.getValue()+ ErrorOr<TestData> actual <- TestDataParser.create() `ParseState:consumeAll` raw - \ Testing.checkEquals(data.getName(),"example data")- \ Testing.checkEquals(data.getDescription(),"THIS_IS_A_TOKEN")- \ Testing.checkFalse(data.getBoolean())+ // Since TestData.create specifies labels, we _must_ use them here.+ TestData expected <- TestData.create(+ name: "example data",+ description: "THIS_IS_A_TOKEN",+ boolean: false)++ // Since TestData refines TestCompare<TestData>, we can use Matches:value.+ \ actual.tryValue() `Matches:value` expected++ // If we want to check the ErrorOr<TestData> itself, we need a+ // ValueMatcher<TestData> to pass to CheckErrorOr:value. We can do this with+ // CheckValue:using to create one from TestCompare<TestData>.+ \ actual `Matches:with` CheckErrorOr:value(CheckValue:using(expected))++ // Matches:with uses more general matchers such as CheckValue:equals. &. below+ // will call the function iff the value isn't empty. This is needed in order+ // to call functions on optional values.+ \ actual.tryValue()&.name() `Matches:with` CheckValue:equals("example data")+ \ actual.tryValue()&.description() `Matches:with` CheckValue:equals("THIS_IS_A_TOKEN")+ \ actual.tryValue()&.boolean() `Matches:with` CheckValue:equals(false) }
example/parser/parser.0rp view
@@ -6,7 +6,7 @@ // ParseState<all> can convert to all other ParseState. concrete ParseState<|#x> { // Consumes all input and returns the result.- @category consumeAll<#y> (Parser<#y>,String) -> (ErrorOr<#y>)+ @category consumeAll<#y> (Parser<#y>, String) -> (ErrorOr<#y>) } // A self-contained parser operation.@@ -26,7 +26,7 @@ @value interface ParseContext<|#x> { // Continue computation. run<#y> (Parser<#y>) -> (ParseContext<#y>)- runAndGet<#y> (Parser<#y>) -> (ParseContext<any>,ErrorOr<#y>)+ runAndGet<#y> (Parser<#y>) -> (ParseContext<any>, ErrorOr<#y>) getValue () -> (ErrorOr<#x>) // End computation and pass on the next state.
example/parser/parser.0rx view
@@ -8,7 +8,7 @@ @value ErrorOr<#x> value @value optional Formatted error - consumeAll (parser,data) {+ consumeAll (parser, data) { ParseContext<#y> context <- parser.run(new(data)) if (context.hasAnyError()) { return context.getValue()
example/parser/test-data.0rp view
@@ -1,12 +1,23 @@+// $TestsOnly$ means that categories in this file are only available in .0rt and+// in other files that use $TestsOnly$. $TestsOnly$ // A contrived object for test data. concrete TestData {- @type create (String,String,Bool) -> (TestData)+ // This is used in tests. This allows fine-grained error information, vs. just+ // comparing the entire object for equality. (Also see parser-test.0rt.)+ refines TestCompare<TestData> - @value getName () -> (String)- @value getDescription () -> (String)- @value getBoolean () -> (Bool)+ @value name () -> (String)+ @value description () -> (String)+ @value boolean () -> (Bool)++ // This limits visibility of everything below. In this case, we don't want+ // anyone besides TestDataParser (and unittest) to construct TestData.+ visibility TestDataParser++ // We can give arguments labels to require calls to be clearer.+ @type create (String name:, String description:, Bool boolean:) -> (TestData) }
example/parser/test-data.0rx view
@@ -5,21 +5,38 @@ @value String description @value Bool boolean - create (name,description,boolean) {+ create (name, description, boolean) { return TestData{ name, description, boolean } } - getName () {+ name () { return name } - getDescription () {+ description () { return description } - getBoolean () {+ boolean () { return boolean }++ // From TestCompare<TestData>.+ testCompare (actual, report) {+ \ MultiChecker.new(report)+ .tryCheck(+ title: "name",+ actual.name(),+ CheckValue:equals(name))+ .tryCheck(+ title: "description",+ actual.description(),+ CheckValue:equals(description))+ .tryCheck(+ title: "boolean",+ actual.boolean(),+ CheckValue:equals(boolean))+ } } define TestDataParser {@@ -38,16 +55,16 @@ refines Parser<TestData> - @category Parser<any> whitespace <- SequenceOfParser.create(" \n\t",1,0) `Parse.or` Parse.error("Expected whitespace")+ @category Parser<any> whitespace <- SequenceOfParser.create(" \n\t", min: 1, max: 0) `Parse.or` Parse.error("Expected whitespace") @category String sentenceChars <- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "., !?-"- @category Parser<String> sentence <- SequenceOfParser.create(sentenceChars,0,0)+ @category Parser<String> sentence <- SequenceOfParser.create(sentenceChars, min: 0, max: 0) @category Parser<any> quote <- CharParser.create('"') @category Parser<String> quotedSentence <- quote `Parse.right` sentence `Parse.left` quote- @category Parser<String> token <- SequenceOfParser.create("ABCDEFGHIJKLMNOPQRSTUVWXYZ_",1,0)+ @category Parser<String> token <- SequenceOfParser.create("ABCDEFGHIJKLMNOPQRSTUVWXYZ_", min: 1, max: 0) @category Parser<String> sentenceOrToken <- quotedSentence `Parse.or` token `Parse.left` whitespace @category Parser<Bool> acronym <- StringParser.create("acronym") `Parse.right` Parse.const(true)@@ -75,13 +92,15 @@ return context.convertError() } else { return context.setValue(- ErrorOr:value(TestData.create(name.getValue(),- description.getValue(),- boolean.getValue())))+ // Since TestData.create specifies labels, we _must_ use them here.+ ErrorOr:value(TestData.create(+ name: name.getValue(),+ description: description.getValue(),+ boolean: boolean.getValue()))) } } create () {- return TestDataParser{ }+ return delegate -> #self } }
example/primes/flag.0rx view
@@ -1,5 +1,5 @@ define ThreadFlag {- @value [ConditionWait&ConditionResume] cond+ @value [ConditionWait & ConditionResume] cond @value Bool enabled @value Bool canceled
example/primes/prime-thread.0rp view
@@ -4,5 +4,5 @@ concrete PrimeThread { refines Routine - @type create (ThreadContinue,PrimeTracker) -> (PrimeThread)+ @type create (ThreadContinue, PrimeTracker) -> (PrimeThread) }
example/primes/prime-thread.0rx view
@@ -2,8 +2,8 @@ @value ThreadContinue flag @value PrimeTracker tracker - create (flag,tracker) {- return PrimeThread{ flag, tracker }+ create (flag, tracker) {+ return delegate -> #self } run () {
example/primes/primes-demo.0rx view
@@ -6,14 +6,14 @@ run () { PrimeTracker tracker <- PrimeTracker.create() ThreadFlag flag <- ThreadFlag.new()- Thread thread <- ProcessThread.from(PrimeThread.create(flag,tracker)).start()+ Thread thread <- ProcessThread.from(PrimeThread.create(flag, tracker)).start() // Interactive input loop. scoped { TextReader reader <- TextReader.fromBlockReader(BasicInput.stdin()) } in while (!reader.pastEnd()) {- $Hidden[tracker,thread]$+ $Hidden[tracker, thread]$ \ BasicOutput.stderr() .writeNow("Press [Enter] to toggle start/stop computation thread. Type \"exit\" to exit.\n")
example/random/random-demo.0rx view
@@ -15,35 +15,35 @@ // NOTE: The overall scale here doesn't matter; it just matters what the // relative weights are. CategoricalTree only supports positive Int weights. CategoricalTree<Char> weights <- CategoricalTree<Char>.new()- .setWeight('a',8167)- .setWeight('b',1492)- .setWeight('c',2782)- .setWeight('d',4253)- .setWeight('e',12702)- .setWeight('f',2228)- .setWeight('g',2015)- .setWeight('h',6094)- .setWeight('i',6966)- .setWeight('j',153)- .setWeight('k',772)- .setWeight('l',4025)- .setWeight('m',2406)- .setWeight('n',6749)- .setWeight('o',7507)- .setWeight('p',1929)- .setWeight('q',95)- .setWeight('r',5987)- .setWeight('s',6327)- .setWeight('t',9056)- .setWeight('u',2758)- .setWeight('v',978)- .setWeight('w',2361)- .setWeight('x',150)- .setWeight('y',1974)- .setWeight('z',74)+ .setWeight('a', 8167)+ .setWeight('b', 1492)+ .setWeight('c', 2782)+ .setWeight('d', 4253)+ .setWeight('e', 12702)+ .setWeight('f', 2228)+ .setWeight('g', 2015)+ .setWeight('h', 6094)+ .setWeight('i', 6966)+ .setWeight('j', 153)+ .setWeight('k', 772)+ .setWeight('l', 4025)+ .setWeight('m', 2406)+ .setWeight('n', 6749)+ .setWeight('o', 7507)+ .setWeight('p', 1929)+ .setWeight('q', 95)+ .setWeight('r', 5987)+ .setWeight('s', 6327)+ .setWeight('t', 9056)+ .setWeight('u', 2758)+ .setWeight('v', 978)+ .setWeight('w', 2361)+ .setWeight('x', 150)+ .setWeight('y', 1974)+ .setWeight('z', 74) Generator<Char> letter <- weights `RandomCategorical:sampleWith` RandomUniform.probability()- Generator<Float> length <- RandomGaussian.new(5.0,3.0)+ Generator<Float> length <- RandomGaussian.new(5.0, 3.0) Generator<Float> timing <- RandomExponential.new(4.0) while (timeLimit <= 0.0 || Realtime.monoSeconds() < startTime+timeLimit) {@@ -56,7 +56,7 @@ // Populate the letters using their relative frequencies. traverse (Counter.zeroIndexed(buffer.size()) -> Int pos) {- \ buffer.writeAt(pos,letter.generate())+ \ buffer.writeAt(pos, letter.generate()) } // Print the word.
lib/container/.zeolite-module view
@@ -34,4 +34,4 @@ categories: [Vector] } ]-mode: incremental {}+mode: incremental { }
lib/container/auto-tree.0rp view
@@ -33,12 +33,12 @@ // of the tree. It is provided as a filter for the return of getRoot() so that // a container can implement custom functionality using the tree's structure // without risking modification of the tree.-concrete AutoBinaryTree<|#n,#k,#v|#r> {+concrete AutoBinaryTree<|#n, #k, #v|#r> { refines Container refines Duplicate #k immutable- #n defines KVFactory<#k,#v>- #n requires BalancedTreeNode<#n,#k,#v>+ #n defines KVFactory<#k, #v>+ #n requires BalancedTreeNode<#n, #k, #v> #n requires Duplicate #k defines LessThan<#k> #r allows #n@@ -57,21 +57,21 @@ // Notes: // - updateNode() will be called on every affected node, starting with the // deepest node. It might be called an arbitrary number of times per node.- @value weakSet (#k,#v) -> (#v)+ @value weakSet (#k, #v) -> (#v) // Swap the value associated with the key if it is not present. // // Notes: // - updateNode() will be called on every affected node, starting with the // deepest node. It might be called an arbitrary number of times per node.- @value swap (#k,optional #v) -> (optional #v)+ @value swap (#k, optional #v) -> (optional #v) } // An interface for reading the state of a BST node. // // Notes: // - This is intended for internal use in BST-based categories.-@value interface BinaryTreeNode<|#k,#v> {+@value interface BinaryTreeNode<|#k, #v> { getLower () -> (optional #self) getHigher () -> (optional #self) getKey () -> (#k)@@ -83,8 +83,8 @@ // // Notes: // - This is intended for internal use in BST-based categories.-@value interface BalancedTreeNode<#n|#k,#v|> {- refines BinaryTreeNode<#k,#v>+@value interface BalancedTreeNode<#n|#k, #v|> {+ refines BinaryTreeNode<#k, #v> // Set the lower child of the node. //@@ -119,26 +119,26 @@ // // Notes: // - This is intended for internal use in BST-based categories.-concrete ForwardTreeOrder<|#k,#v> {- refines Order<KeyValue<#k,#v>>+concrete ForwardTreeOrder<|#k, #v> {+ refines Order<KeyValue<#k, #v>> - @category create<#k,#v> (optional BinaryTreeNode<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)+ @category create<#k, #v> (optional BinaryTreeNode<#k, #v>) -> (optional ForwardTreeOrder<#k, #v>) - @category seek<#k,#v>+ @category seek<#k, #v> #k defines LessThan<#k>- (#k,optional BinaryTreeNode<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)+ (#k, optional BinaryTreeNode<#k, #v>) -> (optional ForwardTreeOrder<#k, #v>) } // Provides reverse iteration of the nodes in a BST. // // Notes: // - This is intended for internal use in BST-based categories.-concrete ReverseTreeOrder<|#k,#v> {- refines Order<KeyValue<#k,#v>>+concrete ReverseTreeOrder<|#k, #v> {+ refines Order<KeyValue<#k, #v>> - @category create<#k,#v> (optional BinaryTreeNode<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)+ @category create<#k, #v> (optional BinaryTreeNode<#k, #v>) -> (optional ReverseTreeOrder<#k, #v>) - @category seek<#k,#v>+ @category seek<#k, #v> #k defines LessThan<#k>- (#k,optional BinaryTreeNode<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)+ (#k, optional BinaryTreeNode<#k, #v>) -> (optional ReverseTreeOrder<#k, #v>) }
lib/container/hashed-map.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,16 +21,17 @@ // Params: // - #k: The key type. // - #v: The value type.-concrete HashedMap<#k,#v> {+concrete HashedMap<#k, #v> { defines Default refines Container- refines DefaultOrder<KeyValue<#k,#v>>+ refines DefaultOrder<KeyValue<#k, #v>> refines Duplicate refines KeyOrder<#k>- refines KVExchange<#k,#v>- refines KVWriter<#k,#v>- refines KVReader<#k,#v>+ refines KVExchange<#k, #v>+ refines KVWriter<#k, #v>+ refines KVReader<#k, #v> refines ValueOrder<#v>+ refines SetReader<#k> #k immutable #k defines Equals<#k> #k requires Hashed
lib/container/helpers.0rp view
@@ -30,10 +30,10 @@ // Example: // // Bool lt <- x `KeyValueH:lessThan` y- @category lessThan<#k,#v>+ @category lessThan<#k, #v> #k defines LessThan<#k> #v defines LessThan<#v>- (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)+ (KeyValue<#k, #v>, KeyValue<#k, #v>) -> (Bool) // The same as lessThan, but with custom comparators. //@@ -49,11 +49,11 @@ // Example: // // // Ignore the value and compare Int keys.- // Bool lt <- x `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` y- @category lessThanWith<#k,#v,#kk,#vv>+ // Bool lt <- x `KeyValueH:lessThanWith<?, ?, Int, AlwaysEqual>` y+ @category lessThanWith<#k, #v, #kk, #vv> #kk defines LessThan<#k> #vv defines LessThan<#v>- (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)+ (KeyValue<#k, #v>, KeyValue<#k, #v>) -> (Bool) // Compare for equals. //@@ -64,10 +64,10 @@ // Example: // // Bool eq <- x `KeyValueH:equals` y- @category equals<#k,#v>+ @category equals<#k, #v> #k defines Equals<#k> #v defines Equals<#v>- (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)+ (KeyValue<#k, #v>, KeyValue<#k, #v>) -> (Bool) // The same as equals, but with custom comparators. //@@ -80,9 +80,9 @@ // Example: // // // Ignore the key and compare Int values.- // Bool eq <- x `KeyValueH:equalsWith<?,?,AlwaysEqual,Int>` y- @category equalsWith<#k,#v,#kk,#vv>+ // Bool eq <- x `KeyValueH:equalsWith<?, ?, AlwaysEqual, Int>` y+ @category equalsWith<#k, #v, #kk, #vv> #kk defines Equals<#k> #vv defines Equals<#v>- (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)+ (KeyValue<#k, #v>, KeyValue<#k, #v>) -> (Bool) }
lib/container/interfaces.0rp view
@@ -48,9 +48,9 @@ // Params: // - #k: The key type. // - #v: The value type.-@value interface KVWriter<#k,#v|> {+@value interface KVWriter<#k, #v|> { // Sets or replaces the value associated with the key and returns self.- set (#k,#v) -> (#self)+ set (#k, #v) -> (#self) // Removes the value associated with the key if present and returns self. remove (#k) -> (#self) }@@ -84,7 +84,7 @@ // - #v: The value type. @value interface KVExchange<#k|#v|> { // Replaces the value if it does not exist and returns the final value.- weakSet (#k,#v) -> (#v)+ weakSet (#k, #v) -> (#v) // Swap the value associated with the key. //@@ -94,7 +94,7 @@ // // Returns: // - optional #v: Previous value, or empty if none existed.- swap (#k,optional #v) -> (optional #v)+ swap (#k, optional #v) -> (optional #v) } // Writing to a set of values.@@ -118,13 +118,13 @@ } // Factory for creating a new key-value pair.-@type interface KVFactory<#k,#v|> {+@type interface KVFactory<#k, #v|> { // Create a new pair from the provided key and value.- newNode (#k,#v) -> (#self)+ newNode (#k, #v) -> (#self) } // A single key-value pair from a KVReader.-@value interface KeyValue<|#k,#v> {+@value interface KeyValue<|#k, #v> { // Get the key. // // Notes:
lib/container/list.0rp view
@@ -38,7 +38,7 @@ // List element that supports reverse iteration. @value interface DoubleNode<|#n|#x> {- refines ListNode<#n,#x>+ refines ListNode<#n, #x> // Return the previous element. prev () -> (optional #self)@@ -63,10 +63,10 @@ defines NewNode<#x> // Duplication happens only in the forward direction. refines Duplicate- refines DoubleNode<LinkedNode<#x>,#x>+ refines DoubleNode<LinkedNode<#x>, #x> // Create a new builder.- @type builder () -> (ListBuilder<#x,#self>)+ @type builder () -> (ListBuilder<#x, #self>) // Set the value held by the node. @value set (#x) -> (#self)@@ -80,10 +80,10 @@ concrete ForwardNode<#x> { defines NewNode<#x> refines Duplicate- refines ListNode<ForwardNode<#x>,#x>+ refines ListNode<ForwardNode<#x>, #x> // Create a new builder.- @type builder () -> (ListBuilder<#x,#self>)+ @type builder () -> (ListBuilder<#x, #self>) // Set the value held by the node. @value set (#x) -> (#self)@@ -93,7 +93,7 @@ concrete ListBuilder<#x|#n> { refines Append<#x> #n defines NewNode<#x>- #n requires ListNode<#n,#x>+ #n requires ListNode<#n, #x> // Create a new builder. @type new () -> (#self)@@ -112,5 +112,5 @@ // head/tail, but that tail will no longer be the end. // - Calling mutating functions (e.g., setNext, setPrev) on any of the // elements between the returned head/tail will invalidate the builder.- @value build () -> (optional #n,optional #n)+ @value build () -> (optional #n, optional #n) }
lib/container/sorted-map.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,15 +21,16 @@ // Params: // - #k: The key type. // - #v: The value type.-concrete SortedMap<#k,#v> {+concrete SortedMap<#k, #v> { defines Default refines Container- refines DefaultOrder<KeyValue<#k,#v>>+ refines DefaultOrder<KeyValue<#k, #v>> refines Duplicate refines KeyOrder<#k>- refines KVExchange<#k,#v>- refines KVWriter<#k,#v>- refines KVReader<#k,#v>+ refines KVExchange<#k, #v>+ refines KVWriter<#k, #v>+ refines KVReader<#k, #v>+ refines SetReader<#k> refines ValueOrder<#v> #k immutable #k defines LessThan<#k>@@ -44,7 +45,7 @@ // - Traversal of the entire map is amortized O(n); however, the cost of any // particular iteration could be up to O(log n). // - The overall memory cost is O(log n).- @value defaultOrder () -> (optional Order<KeyValue<#k,#v>>)+ @value defaultOrder () -> (optional Order<KeyValue<#k, #v>>) // Traverse the map in the reverse order of defaultOrder(). //@@ -52,19 +53,19 @@ // - Traversal of the entire map is amortized O(n); however, the cost of any // particular iteration could be up to O(log n). // - The overall memory cost is O(log n).- @value reverseOrder () -> (optional Order<KeyValue<#k,#v>>)+ @value reverseOrder () -> (optional Order<KeyValue<#k, #v>>) // Start forward traversal (same as defaultOrder()) from the specified key. // // Notes: // - If the key does not exist in the SortedMap, the position right after // where it would be (in the forward direction) is returned.- @value getForward (#k) -> (optional Order<KeyValue<#k,#v>>)+ @value getForward (#k) -> (optional Order<KeyValue<#k, #v>>) // Start reverse traversal (same as reverseOrder()) from the specified key. // // Notes: // - If the key does not exist in the SortedMap, the position right after // where it would be (in the reverse direction) is returned.- @value getReverse (#k) -> (optional Order<KeyValue<#k,#v>>)+ @value getReverse (#k) -> (optional Order<KeyValue<#k, #v>>) }
lib/container/sorting.0rp view
@@ -28,7 +28,7 @@ // - Worst-case storage is O(1). @category sort<#x> #x defines LessThan<#x>- ([ReadAt<#x>&WriteAt<#x>]) -> ()+ ([ReadAt<#x> & WriteAt<#x>]) -> () // In-place unstable sorting of a random-access container. //@@ -43,17 +43,17 @@ // Example: // // // Sort myIntContainer in reverse order. (Reversed is from lib/util.)- // \ Sorting:sortWith<?,Reversed<Int>>(myIntContainer)- @category sortWith<#x,#xx>+ // \ Sorting:sortWith<?, Reversed<Int>>(myIntContainer)+ @category sortWith<#x, #xx> #xx defines LessThan<#x>- ([ReadAt<#x>&WriteAt<#x>]) -> ()+ ([ReadAt<#x> & WriteAt<#x>]) -> () // The same as sortWith, but with LessThan2 instead of LessThan. @category sortWith2<#x>- ([ReadAt<#x>&WriteAt<#x>],LessThan2<#x>) -> ()+ ([ReadAt<#x> & WriteAt<#x>], LessThan2<#x>) -> () // In-place order reversal of a random-access container.- @category reverse<#x> ([ReadAt<#x>&WriteAt<#x>]) -> ()+ @category reverse<#x> ([ReadAt<#x> & WriteAt<#x>]) -> () // In-place stable sorting of an iterable list. //@@ -69,9 +69,9 @@ // - Worst-case storage is O(1). // - If the node is not the actual head, the part of the list being sorted // might become detached from the earlier part of the list.- @category sortList<#n,#x>+ @category sortList<#n, #x> #x defines LessThan<#x>- #n requires ListNode<#n,#x>+ #n requires ListNode<#n, #x> (optional #n) -> (optional #n) // In-place stable sorting of an iterable list.@@ -93,16 +93,16 @@ // Example: // // // Sort myIntContainer in reverse order. (Reversed is from lib/util.)- // optional ListNode<#n,#x> newHead <- Sorting:sortListWith<?,?,Reversed<Int>>(oldHead)- @category sortListWith<#n,#x,#xx>+ // optional ListNode<#n, #x> newHead <- Sorting:sortListWith<?, ?, Reversed<Int>>(oldHead)+ @category sortListWith<#n, #x, #xx> #xx defines LessThan<#x>- #n requires ListNode<#n,#x>+ #n requires ListNode<#n, #x> (optional #n) -> (optional #n) // The same as sortListWith, but with LessThan2 instead of LessThan.- @category sortListWith2<#n,#x>- #n requires ListNode<#n,#x>- (optional #n,LessThan2<#x>) -> (optional #n)+ @category sortListWith2<#n, #x>+ #n requires ListNode<#n, #x>+ (optional #n, LessThan2<#x>) -> (optional #n) // Reverses the list in place and returns the new head. //@@ -112,7 +112,7 @@ // Notes: // - If the node is not the actual head, the part of the list being reversed // might become detached from the earlier part of the list.- @category reverseList<#n,#x>- #n requires ListNode<#n,#x>+ @category reverseList<#n, #x>+ #n requires ListNode<#n, #x> (optional #n) -> (optional #n) }
lib/container/src/auto-tree.0rx view
@@ -41,11 +41,11 @@ } get (k) {- return find(root,k)+ return find(root, k) } - weakSet (k,v) {- root, optional #v v2 <- insertWeak(root,k,v)+ weakSet (k, v) {+ root, optional #v v2 <- insertWeak(root, k, v) if (`present` v2) { return `require` v2 } else {@@ -54,8 +54,8 @@ } } - swap (k,v) (old) {- root, old <- exchange(root,k,v)+ swap (k, v) (old) {+ root, old <- exchange(root, k, v) if (!present(v) && present(old)) { treeSize <- treeSize-1 } elif (present(v) && !present(old)) {@@ -63,22 +63,22 @@ } } - @type exchange (optional #n,#k,optional #v) -> (optional #n,optional #v)- exchange (node,k,v) (newRoot,old) {+ @type exchange (optional #n, #k, optional #v) -> (optional #n, optional #v)+ exchange (node, k, v) (newRoot, old) { if (!present(node)) { if (present(v)) {- return #n.newNode(k,require(v)), empty+ return #n.newNode(k, require(v)), empty } else { return empty, empty } } #n node2 <- require(node) if (k `#k.lessThan` node2.getKey()) {- newRoot, old <- exchange(node2.getLower(),k,v)+ newRoot, old <- exchange(node2.getLower(), k, v) \ node2.setLower(newRoot) newRoot <- rebalance(node2) } elif (node2.getKey() `#k.lessThan` k) {- newRoot, old <- exchange(node2.getHigher(),k,v)+ newRoot, old <- exchange(node2.getHigher(), k, v) \ node2.setHigher(newRoot) newRoot <- rebalance(node2) } elif (present(v)) {@@ -93,18 +93,18 @@ } - @type insertWeak (optional #n,#k,#v) -> (optional #n,optional #v)- insertWeak (node,k,v) (newRoot,value) {+ @type insertWeak (optional #n, #k, #v) -> (optional #n, optional #v)+ insertWeak (node, k, v) (newRoot, value) { if (!present(node)) {- return #n.newNode(k,v), empty+ return #n.newNode(k, v), empty } #n node2 <- require(node) if (k `#k.lessThan` node2.getKey()) {- newRoot, value <- insertWeak(node2.getLower(),k,v)+ newRoot, value <- insertWeak(node2.getLower(), k, v) \ node2.setLower(newRoot) newRoot <- rebalance(node2) } elif (node2.getKey() `#k.lessThan` k) {- newRoot, value <- insertWeak(node2.getHigher(),k,v)+ newRoot, value <- insertWeak(node2.getHigher(), k, v) \ node2.setHigher(newRoot) newRoot <- rebalance(node2) } else {@@ -112,15 +112,15 @@ } } - @type find (optional #n,#k) -> (optional #v)- find (node,k) {+ @type find (optional #n, #k) -> (optional #v)+ find (node, k) { if (present(node)) { scoped { #n node2 <- require(node) } in if (k `#k.lessThan` node2.getKey()) {- return find(node2.getLower(),k)+ return find(node2.getLower(), k) } elif (node2.getKey() `#k.lessThan` k) {- return find(node2.getHigher(),k)+ return find(node2.getHigher(), k) } else { return node2.getValue() }@@ -195,13 +195,13 @@ \ node.setHigher(temp) } if (present(newNode)) {- \ swapChildren(node,require(newNode))+ \ swapChildren(node, require(newNode)) \ require(newNode).updateNode() } } - @type removeHighest (optional #n) -> (optional #n,optional #n)- removeHighest (node) (newNode,removed) {+ @type removeHighest (optional #n) -> (optional #n, optional #n)+ removeHighest (node) (newNode, removed) { if (!present(node)) { return empty, empty }@@ -217,8 +217,8 @@ } } - @type removeLowest (optional #n) -> (optional #n,optional #n)- removeLowest (node) (newNode,removed) {+ @type removeLowest (optional #n) -> (optional #n, optional #n)+ removeLowest (node) (newNode, removed) { if (!present(node)) { return empty, empty }@@ -234,8 +234,8 @@ } } - @type swapChildren (#n,#n) -> ()- swapChildren (l,r) {+ @type swapChildren (#n, #n) -> ()+ swapChildren (l, r) { scoped { optional #n temp <- l.getLower() \ l.setLower(r.getLower())@@ -250,30 +250,30 @@ define ForwardTreeOrder { $ReadOnlyExcept[]$ - @value BinaryTreeNode<#k,#v> node- @value optional ForwardTreeOrder<#k,#v> prev+ @value BinaryTreeNode<#k, #v> node+ @value optional ForwardTreeOrder<#k, #v> prev create (node) (current) {- optional BinaryTreeNode<#k,#v> node2 <- node+ optional BinaryTreeNode<#k, #v> node2 <- node current <- empty while (present(node2)) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ current <- ForwardTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getLower() } } - seek (key,node) (current) {- optional BinaryTreeNode<#k,#v> node2 <- node+ seek (key, node) (current) {+ optional BinaryTreeNode<#k, #v> node2 <- node current <- empty while (present(node2)) { if (require(node2).getKey() `#k.lessThan` key) { // Skip node2 in the traversal, since it's before key. node2 <- require(node2).getHigher() } elif (key `#k.lessThan` require(node2).getKey()) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ current <- ForwardTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getLower() } else {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ current <- ForwardTreeOrder<#k, #v>{ require(node2), current } break } }@@ -283,46 +283,46 @@ // Algorithm: // 1. Pop self from the stack. // 2. Traverse lower to the bottom starting from the higher child of self.- optional BinaryTreeNode<#k,#v> node2 <- node.getHigher()+ optional BinaryTreeNode<#k, #v> node2 <- node.getHigher() current <- prev while (present(node2)) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ current <- ForwardTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getLower() } } get () {- return SimpleKeyValue:new(node.getKey(),node.getValue())+ return SimpleKeyValue:new(node.getKey(), node.getValue()) } } define ReverseTreeOrder { $ReadOnlyExcept[]$ - @value BinaryTreeNode<#k,#v> node- @value optional ReverseTreeOrder<#k,#v> prev+ @value BinaryTreeNode<#k, #v> node+ @value optional ReverseTreeOrder<#k, #v> prev create (node) (current) {- optional BinaryTreeNode<#k,#v> node2 <- node+ optional BinaryTreeNode<#k, #v> node2 <- node current <- empty while (present(node2)) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ current <- ReverseTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getHigher() } } - seek (key,node) (current) {- optional BinaryTreeNode<#k,#v> node2 <- node+ seek (key, node) (current) {+ optional BinaryTreeNode<#k, #v> node2 <- node current <- empty while (present(node2)) { if (require(node2).getKey() `#k.lessThan` key) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ current <- ReverseTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getHigher() } elif (key `#k.lessThan` require(node2).getKey()) { // Skip node2 in the traversal, since it's after key. node2 <- require(node2).getLower() } else {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ current <- ReverseTreeOrder<#k, #v>{ require(node2), current } break } }@@ -332,15 +332,15 @@ // Algorithm: // 1. Pop self from the stack. // 2. Traverse higher to the bottom starting from the lower child of self.- optional BinaryTreeNode<#k,#v> node2 <- node.getLower()+ optional BinaryTreeNode<#k, #v> node2 <- node.getLower() current <- prev while (present(node2)) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ current <- ReverseTreeOrder<#k, #v>{ require(node2), current } node2 <- require(node2).getHigher() } } get () {- return SimpleKeyValue:new(node.getKey(),node.getValue())+ return SimpleKeyValue:new(node.getKey(), node.getValue()) } }
lib/container/src/hashed-map.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -18,10 +18,10 @@ define HashedMap { @value Int itemCount- @value [DefaultOrder<HashRoot<#k,#v>>&ReadAt<HashRoot<#k,#v>>] table+ @value [DefaultOrder<HashRoot<#k, #v>> & ReadAt<HashRoot<#k, #v>>] table new () {- return #self{ 0, Vector:createSize<HashRoot<#k,#v>>($ExprLookup[HASH_TABLE_MIN_SIZE]$) }+ return #self{ 0, Vector:createSize<HashRoot<#k, #v>>($ExprLookup[HASH_TABLE_MIN_SIZE]$) } } default () {@@ -29,29 +29,33 @@ } duplicate () {- return #self{ itemCount, table.defaultOrder() `OrderH:duplicateTo` Vector<HashRoot<#k,#v>>.new() }+ return #self{ itemCount, table.defaultOrder() `OrderH:duplicateTo` Vector<HashRoot<#k, #v>>.new() } } size () { return itemCount } + member (k) {+ return `present` delegate -> `get`+ }+ get (k) { return table.readAt(getBin(k.hashed())).find(k) } - set (k,v) {- \ swap(k,v)+ set (k, v) {+ \ swap(k, v) return self } remove (k) {- \ swap(k,empty)+ \ swap(k, empty) return self } - weakSet (k,v) {- optional #v value <- table.readAt(getBin(k.hashed())).weakReplace(k,v)+ weakSet (k, v) {+ optional #v value <- table.readAt(getBin(k.hashed())).weakReplace(k, v) if (`present` value) { return `require` value } else {@@ -61,8 +65,8 @@ } } - swap (k,v) (old) {- old <- table.readAt(getBin(k.hashed())).exchange(k,v)+ swap (k, v) (old) {+ old <- table.readAt(getBin(k.hashed())).exchange(k, v) if (!present(v) && present(old)) { itemCount <- itemCount-1 \ maybeResize()@@ -73,7 +77,7 @@ } defaultOrder () {- return HashedMapOrder<#k,#v>.new(itemCount,table)+ return HashedMapOrder<#k, #v>.new(itemCount, table) } keyOrder () {@@ -95,34 +99,34 @@ @value maybeResize () -> () maybeResize () {- optional [DefaultOrder<HashRoot<#k,#v>>&ReadAt<HashRoot<#k,#v>>] newTable <- empty+ optional [DefaultOrder<HashRoot<#k, #v>> & ReadAt<HashRoot<#k, #v>>] newTable <- empty if (itemCount >= $ExprLookup[HASH_TABLE_EXPAND_RATIO]$*table.size()) {- newTable <- Vector:createSize<HashRoot<#k,#v>>(2*table.size())+ newTable <- Vector:createSize<HashRoot<#k, #v>>(2*table.size()) } elif ($ExprLookup[HASH_TABLE_CONTRACT_RATIO]$*itemCount < table.size() && table.size() > $ExprLookup[HASH_TABLE_MIN_SIZE]$) {- newTable <- Vector:createSize<HashRoot<#k,#v>>(table.size()/2)+ newTable <- Vector:createSize<HashRoot<#k, #v>>(table.size()/2) } if (`present` newTable) {- [DefaultOrder<HashRoot<#k,#v>>&ReadAt<HashRoot<#k,#v>>] oldTable <- table+ [DefaultOrder<HashRoot<#k, #v>> & ReadAt<HashRoot<#k, #v>>] oldTable <- table table <- `require` newTable $Hidden[newTable]$- traverse (oldTable.defaultOrder() -> HashRoot<#k,#v> root) {- traverse (root.defaultOrder() -> HashNode<#k,#v> node) {- \ table.readAt(getBin(node.getKey().hashed())).exchange(node.getKey(),node.getValue())+ traverse (oldTable.defaultOrder() -> HashRoot<#k, #v> root) {+ traverse (root.defaultOrder() -> HashNode<#k, #v> node) {+ \ table.readAt(getBin(node.getKey().hashed())).exchange(node.getKey(), node.getValue()) } } } } } -concrete HashNode<#k,#v> {+concrete HashNode<#k, #v> { refines Duplicate refines Order<#self> - @type new (#k,#v,optional HashNode<#k,#v>) -> (#self)+ @type new (#k, #v, optional HashNode<#k, #v>) -> (#self) @value getKey () -> (#k) @value getValue () -> (#v) @value setValue (#v) -> ()- @value setNext (optional HashNode<#k,#v>) -> (optional #self)+ @value setNext (optional HashNode<#k, #v>) -> (optional #self) } define HashNode {@@ -130,14 +134,14 @@ @value #k key @value #v value- @value optional HashNode<#k,#v> next+ @value optional HashNode<#k, #v> next - new (key,value,next) {- return #self{ key, value, next }+ new (key, value, next) {+ return delegate -> #self } duplicate () {- optional HashNode<#k,#v> next2 <- empty+ optional HashNode<#k, #v> next2 <- empty if (`present` next) { next2 <- require(next).duplicate() }@@ -156,21 +160,21 @@ } } -concrete HashRoot<#k,#v> {+concrete HashRoot<#k, #v> { defines Default- refines DefaultOrder<HashNode<#k,#v>>+ refines DefaultOrder<HashNode<#k, #v>> refines Duplicate #k defines Equals<#k> - @value exchange (#k,optional #v) -> (optional #v)- @value weakReplace (#k,#v) -> (optional #v)+ @value exchange (#k, optional #v) -> (optional #v)+ @value weakReplace (#k, #v) -> (optional #v) @value find (#k) -> (optional #v) // Override to allow returning HashNode directly.- @value defaultOrder () -> (optional HashNode<#k,#v>)+ @value defaultOrder () -> (optional HashNode<#k, #v>) } define HashRoot {- @value optional HashNode<#k,#v> root+ @value optional HashNode<#k, #v> root default () { return #self{ empty }@@ -188,17 +192,17 @@ } } - exchange (k,v) (old) {+ exchange (k, v) (old) { old <- empty scoped {- optional HashNode<#k,#v> prev <- empty- } in traverse (root -> HashNode<#k,#v> node) {+ optional HashNode<#k, #v> prev <- empty+ } in traverse (root -> HashNode<#k, #v> node) { if (node.getKey() `#k.equals` k) { old <- node.getValue() if (`present` v) { \ node.setValue(`require` v) } else {- optional HashNode<#k,#v> next <- node.setNext(empty)+ optional HashNode<#k, #v> next <- node.setNext(empty) if (`present` prev) { \ require(prev).setNext(next) } else {@@ -211,23 +215,23 @@ prev <- node } if (`present` v) {- root <- HashNode<#k,#v>.new(k,`require` v,root)+ root <- HashNode<#k, #v>.new(k, `require` v, root) } } - weakReplace (k,v) {- traverse (root -> HashNode<#k,#v> node) {+ weakReplace (k, v) {+ traverse (root -> HashNode<#k, #v> node) { if (node.getKey() `#k.equals` k) { return node.getValue() } }- root <- HashNode<#k,#v>.new(k,v,root)+ root <- HashNode<#k, #v>.new(k, v, root) return empty } find (k) (v) { v <- empty- traverse (root -> HashNode<#k,#v> node) {+ traverse (root -> HashNode<#k, #v> node) { if (node.getKey() `#k.equals` k) { return node.getValue() }@@ -235,22 +239,22 @@ } } -concrete HashedMapOrder<#k,#v> {- refines Order<KeyValue<#k,#v>>+concrete HashedMapOrder<#k, #v> {+ refines Order<KeyValue<#k, #v>> - @type new (Int,DefaultOrder<HashRoot<#k,#v>>) -> (optional #self)+ @type new (Int, DefaultOrder<HashRoot<#k, #v>>) -> (optional #self) } define HashedMapOrder { @value Int count- @value optional Order<HashRoot<#k,#v>> root- @value HashNode<#k,#v> node+ @value optional Order<HashRoot<#k, #v>> root+ @value HashNode<#k, #v> node - new (count,table) (next) {+ new (count, table) (next) { next <- empty if (count > 0) { scoped {- optional Order<HashRoot<#k,#v>> root, optional HashNode<#k,#v> node <- seekNext(table.defaultOrder())+ optional Order<HashRoot<#k, #v>> root, optional HashNode<#k, #v> node <- seekNext(table.defaultOrder()) } in if (`present` node) { next <- #self{ count, root, `require` node } }@@ -258,20 +262,20 @@ } get () {- return SimpleKeyValue:new(node.getKey(),node.getValue())+ return SimpleKeyValue:new(node.getKey(), node.getValue()) } next () (next) { next <- empty if ((count <- count-1) > 0) { scoped {- optional HashNode<#k,#v> newNode <- node.next()+ optional HashNode<#k, #v> newNode <- node.next() } in if (`present` newNode) { node <- `require` newNode return self } scoped {- root, optional HashNode<#k,#v> newNode <- seekNext(root)+ root, optional HashNode<#k, #v> newNode <- seekNext(root) } in if (`present` newNode) { node <- `require` newNode return self@@ -279,8 +283,8 @@ } } - @type seekNext (optional Order<HashRoot<#k,#v>>) -> (optional Order<HashRoot<#k,#v>>,optional HashNode<#k,#v>)- seekNext (start) (root,node) {+ @type seekNext (optional Order<HashRoot<#k, #v>>) -> (optional Order<HashRoot<#k, #v>>, optional HashNode<#k, #v>)+ seekNext (start) (root, node) { root <- start node <- empty $Hidden[start]$
lib/container/src/hashed-set.0rx view
@@ -17,14 +17,14 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define HashedSet {- @value HashedMap<#k,any> map+ @value HashedMap<#k, any> map default () { return new() } new () {- return #self{ HashedMap<#k,any>.new() }+ return #self{ HashedMap<#k, any>.new() } } size () {@@ -36,7 +36,7 @@ } add (k) {- \ map.set(k,Void.default())+ \ map.set(k, Void.default()) return self }
lib/container/src/helpers.0rx view
@@ -17,11 +17,11 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define KeyValueH {- lessThan (x,y) {- return lessThanWith<#k,#v,#k,#v>(x,y)+ lessThan (x, y) {+ return lessThanWith<#k, #v, #k, #v>(x, y) } - lessThanWith (x,y) {+ lessThanWith (x, y) { if (x.getKey() `#kk.lessThan` y.getKey()) { return true } elif (y.getKey() `#kk.lessThan` x.getKey()) {@@ -31,11 +31,11 @@ } } - equals (x,y) {- return equalsWith<#k,#v,#k,#v>(x,y)+ equals (x, y) {+ return equalsWith<#k, #v, #k, #v>(x, y) } - equalsWith (x,y) {+ equalsWith (x, y) { if (!(x.getKey() `#kk.equals` y.getKey())) { return false } else {
lib/container/src/list.0rx view
@@ -35,7 +35,7 @@ } builder () {- return ListBuilder<#x,#self>.new()+ return ListBuilder<#x, #self>.new() } next () {@@ -47,7 +47,7 @@ } duplicate () {- $Hidden[prev,next,value]$+ $Hidden[prev, next, value]$ return require(builder().appendAll(self).build(){0}) } @@ -104,7 +104,7 @@ } builder () {- return ListBuilder<#x,#self>.new()+ return ListBuilder<#x, #self>.new() } next () {@@ -112,7 +112,7 @@ } duplicate () {- $Hidden[next,value]$+ $Hidden[next, value]$ return require(builder().appendAll(self).build(){0}) }
lib/container/src/queue.0rx view
@@ -30,7 +30,7 @@ } duplicate () {- $ReadOnly[size,head]$+ $ReadOnly[size, head]$ $Hidden[tail]$ scoped { optional ForwardNode<#x> head2, optional ForwardNode<#x> tail2 <-
lib/container/src/sorted-map.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,20 +17,24 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define SortedMap {- @value AutoBinaryTree<SortedMapNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> map+ @value AutoBinaryTree<SortedMapNode<#k, #v>, #k, #v, BinaryTreeNode<#k, #v>> map default () { return new() } new () {- return #self{ AutoBinaryTree<SortedMapNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() }+ return #self{ AutoBinaryTree<SortedMapNode<#k, #v>, #k, #v, BinaryTreeNode<#k, #v>>.new() } } size () { return map.size() } + member (k) {+ return `present` delegate -> `get`+ }+ duplicate () { return #self{ map.duplicate() } }@@ -39,22 +43,22 @@ return map.get(k) } - set (k,v) {- \ swap(k,v)+ set (k, v) {+ \ swap(k, v) return self } remove (k) {- \ swap(k,empty)+ \ swap(k, empty) return self } - weakSet (k,v) {- return map.weakSet(k,v)+ weakSet (k, v) {+ return map.weakSet(k, v) } - swap (k,v) {- return map.swap(k,v)+ swap (k, v) {+ return map.swap(k, v) } defaultOrder () {@@ -66,11 +70,11 @@ } getForward (k) {- return ForwardTreeOrder:seek(k,map.getRoot())+ return ForwardTreeOrder:seek(k, map.getRoot()) } getReverse (k) {- return ReverseTreeOrder:seek(k,map.getRoot())+ return ReverseTreeOrder:seek(k, map.getRoot()) } keyOrder () {@@ -83,24 +87,24 @@ } define ValidatedTree {- @value AutoBinaryTree<SortedMapNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> map+ @value AutoBinaryTree<SortedMapNode<#k, #v>, #k, #v, BinaryTreeNode<#k, #v>> map new () { $NoTrace$- return #self{ AutoBinaryTree<SortedMapNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() }+ return #self{ AutoBinaryTree<SortedMapNode<#k, #v>, #k, #v, BinaryTreeNode<#k, #v>>.new() } } size () { $NoTrace$ return map.size() } - set (k,v) { $NoTrace$- \ map.swap(k,v)+ set (k, v) { $NoTrace$+ \ map.swap(k, v) \ validate(map.getRoot()) return self } remove (k) { $NoTrace$- \ map.swap(k,empty)+ \ map.swap(k, empty) \ validate(map.getRoot()) return self }@@ -109,7 +113,7 @@ return map.get(k) } - @type validate (optional BinaryTreeNode<#k,#v>) -> ()+ @type validate (optional BinaryTreeNode<#k, #v>) -> () validate (node) { $NoTrace$ if (present(node)) { \ validateOrder(require(node))@@ -117,7 +121,7 @@ } } - @type validateOrder (BinaryTreeNode<#k,#v>) -> ()+ @type validateOrder (BinaryTreeNode<#k, #v>) -> () validateOrder (node) { $NoTrace$ if (present(node.getLower())) { if (!(require(node.getLower()).getKey() `#k.lessThan` node.getKey())) {@@ -133,7 +137,7 @@ } } - @type validateBalance (BinaryTreeNode<#k,#v>) -> ()+ @type validateBalance (BinaryTreeNode<#k, #v>) -> () validateBalance (node) { $NoTrace$ scoped { Int balance <- 0@@ -156,9 +160,9 @@ } } -concrete SortedMapNode<#k,#v> {- defines KVFactory<#k,#v>- refines BalancedTreeNode<SortedMapNode<#k,#v>,#k,#v>+concrete SortedMapNode<#k, #v> {+ defines KVFactory<#k, #v>+ refines BalancedTreeNode<SortedMapNode<#k, #v>, #k, #v> refines Duplicate } @@ -171,7 +175,7 @@ @value optional #self lower @value optional #self higher - newNode (k,v) {+ newNode (k, v) { return #self{ 1, k, v, empty, empty } }
lib/container/src/sorted-set.0rx view
@@ -17,14 +17,14 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define SortedSet {- @value SortedMap<#k,any> map+ @value SortedMap<#k, any> map default () { return new() } new () {- return #self{ SortedMap<#k,any>.new() }+ return #self{ SortedMap<#k, any>.new() } } size () {@@ -36,7 +36,7 @@ } add (k) {- \ map.set(k,Void.default())+ \ map.set(k, Void.default()) return self }
lib/container/src/sorting.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -18,15 +18,15 @@ define Sorting { sort (seq) {- \ sortWith<#x,#x>(seq)+ \ sortWith<#x, #x>(seq) } sortWith (seq) {- \ seq `sortWith2` AsLessThan2<#x,#xx>.new()+ \ seq `sortWith2` AsLessThan2<#x, #xx>.new() } - sortWith2 (seq,compare) {- \ HeapSort<#x>.inPlace(seq,compare)+ sortWith2 (seq, compare) {+ \ HeapSort<#x>.inPlace(seq, compare) } reverse (seq) {@@ -36,23 +36,23 @@ $ReadOnly[i]$ Int j <- seq.size()-i-1 #x temp <- seq.readAt(i)- \ seq.writeAt(i,seq.readAt(j))- \ seq.writeAt(j,temp)+ \ seq.writeAt(i, seq.readAt(j))+ \ seq.writeAt(j, temp) } update { i <- i-1 } } sortList (head) {- return sortListWith<#n,#x,#x>(head)+ return sortListWith<#n, #x, #x>(head) } sortListWith (head) {- return head `sortListWith2` AsLessThan2<#x,#xx>.new()+ return head `sortListWith2` AsLessThan2<#x, #xx>.new() } - sortListWith2 (head,compare) {- return MergeSort<#n,#x>.sort(head,compare)+ sortListWith2 (head, compare) {+ return MergeSort<#n, #x>.sort(head, compare) } reverseList (head) (head2) {@@ -80,17 +80,17 @@ // Putting the params at the top level allows helpers to be called without // needing to pass the params every time. concrete HeapSort<#x> {- @type inPlace ([ReadAt<#x>&WriteAt<#x>],LessThan2<#x>) -> ()+ @type inPlace ([ReadAt<#x> & WriteAt<#x>], LessThan2<#x>) -> () } define HeapSort { $ReadOnlyExcept[]$ - @value [ReadAt<#x>&WriteAt<#x>] seq+ @value [ReadAt<#x> & WriteAt<#x>] seq @value LessThan2<#x> compare - inPlace (seq,compare) {- \ #self{ seq, compare }.execute()+ inPlace (seq, compare) {+ \ (delegate -> #self).execute() } @value execute () -> ()@@ -100,7 +100,7 @@ Int i <- seq.size()/2-1 } in while (i >= 0) { $ReadOnly[i]$- \ sift(i,seq.size())+ \ sift(i, seq.size()) } update { i <- i-1 }@@ -110,15 +110,15 @@ Int i <- seq.size()-1 } in while (i >= 0) { $ReadOnly[i]$- \ swap(0,i)- \ sift(0,i)+ \ swap(0, i)+ \ sift(0, i) } update { i <- i-1 } } - @value sift (Int,Int) -> ()- sift (start,size) { $NoTrace$+ @value sift (Int, Int) -> ()+ sift (start, size) { $NoTrace$ scoped { Int last <- start Int indexLargest <- last@@ -127,7 +127,7 @@ $ReadOnly[last]$ Int left <- 2*last+1 Int right <- 2*last+2- $ReadOnly[left,right]$+ $ReadOnly[left, right]$ if (seq.readAt(indexLargest) `compare.lessThan2` seq.readAt(left)) { indexLargest <- left }@@ -138,33 +138,33 @@ break } } update {- \ swap(last,indexLargest)+ \ swap(last, indexLargest) last <- indexLargest } } - @value swap (Int,Int) -> ()- swap (i,j) { $NoTrace$+ @value swap (Int, Int) -> ()+ swap (i, j) { $NoTrace$ if (i != j) { #x temp <- seq.readAt(i)- \ seq.writeAt(i,seq.readAt(j))- \ seq.writeAt(j,temp)+ \ seq.writeAt(i, seq.readAt(j))+ \ seq.writeAt(j, temp) } } } // Putting the params at the top level allows helpers to be called without // needing to pass the params every time.-concrete MergeSort<#n,#x> {- #n requires ListNode<#n,#x>+concrete MergeSort<#n, #x> {+ #n requires ListNode<#n, #x> - @type sort (optional #n,LessThan2<#x>) -> (optional #n)+ @type sort (optional #n, LessThan2<#x>) -> (optional #n) } define MergeSort { @value LessThan2<#x> compare - sort (head,compare) {+ sort (head, compare) { return #self{ compare }.iterated(head) } @@ -188,7 +188,7 @@ optional #n right <- left `splitAt` chunk next <- right `splitAt` chunk $Hidden[next]$- $ReadOnly[left,right]$+ $ReadOnly[left, right]$ dirty <- dirty || present(right) optional #n newHead, optional #n newTail <- left `merge` right if (!present(head2)) {@@ -203,8 +203,8 @@ } } - @value splitAt (optional #n,Int) -> (optional #n)- splitAt (head,n) {+ @value splitAt (optional #n, Int) -> (optional #n)+ splitAt (head, n) { optional #n head2 <- head $Hidden[head]$ @@ -223,14 +223,14 @@ return empty } - @value merge (optional #n,optional #n) -> (optional #n,optional #n)- merge (left,right) (head,tail) {+ @value merge (optional #n, optional #n) -> (optional #n, optional #n)+ merge (left, right) (head, tail) { head <- empty tail <- empty optional #n left2 <- left optional #n right2 <- right- $Hidden[left,right]$+ $Hidden[left, right]$ while (present(left2) && present(right2)) { #n append <- defer
+ lib/container/src/testing.0rx view
@@ -0,0 +1,233 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CheckSet {+ equals (expected) {+ return SetEquals<#k>.new(expected)+ }+}++define CheckMap {+ using (expected) {+ return MapAdapter<#k, #v>.new(expected)+ }++ equals (expected) {+ return MapEquals<#k, #v>.new(expected)+ }++ matches (expected) {+ return MapMatches<#k, #v>.new(expected)+ }+}++concrete MapAdapter<#k, #v> {+ #v requires TestCompare<#v>++ @type new ([SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>]) -> ([SetReader<#k> & DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>])+}++define MapAdapter {+ $ReadOnlyExcept[current]$++ refines SetReader<#k>+ refines DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>+ refines Order<KeyValue<#k, ValueMatcher<#v>>>++ @value [SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>] original+ @value optional Order<KeyValue<#k, #v>> current++ new (original) {+ return #self{ original, empty }+ }++ defaultOrder () {+ return #self{ original, original.defaultOrder() }+ }++ get () {+ scoped {+ KeyValue<#k, #v> keyValue <- `require` current&.get()+ } in return SimpleKeyValue:new(keyValue.getKey(), CheckValue:using(keyValue.getValue()))+ }++ next () {+ if (`present` (current <- current&.next())) {+ return self+ } else {+ return empty+ }+ }++ member (k) {+ return delegate -> `original.member`+ }+}++concrete SetEquals<#k> {+ #k requires Formatted++ @type new ([SetReader<#k> & DefaultOrder<#k>]) -> (ValueMatcher<[SetReader<#k> & DefaultOrder<#k>]>)+}++define SetEquals {+ $ReadOnlyExcept[]$++ refines ValueMatcher<[SetReader<#k> & DefaultOrder<#k>]>++ @value [SetReader<#k> & DefaultOrder<#k>] expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ traverse (expected.defaultOrder() -> #k currentExpected) {+ if (`present` actual && ! `require(actual).member` currentExpected) {+ \ report.addError(message: String.builder()+ .append("\"")+ .append(currentExpected)+ .append("\" is missing")+ .build())+ }+ }+ traverse (actual&.defaultOrder() -> #k currentActual) {+ if (! `expected.member` currentActual) {+ \ report.addError(message: String.builder()+ .append("\"")+ .append(currentActual)+ .append("\" is unexpected")+ .build())+ }+ }+ }++ summary () {+ return "set equals"+ }+}++concrete MapEquals<#k, #v> {+ #k requires Formatted+ #v requires Formatted+ #v defines Equals<#v>++ @type new ([SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>]) -> (ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>)+}++define MapEquals {+ $ReadOnlyExcept[]$++ refines ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>++ @value [SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>] expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ traverse (expected.defaultOrder() -> KeyValue<#k, #v> current) {+ optional #v value <- actual&.get(current.getKey())+ $Hidden[actual, expected]$+ if (! `present` value) {+ \ report.addError(message: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current.getKey())+ .append(" is missing")+ .build())+ } elif (!(require(value) `#v.equals` current.getValue())) {+ TestReport newReport <- report.newSection(title: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current.getKey())+ .build())+ $Hidden[report]$+ \ newReport.addError(message: String.builder()+ .append(`Format:autoFormat` value)+ .append(" does not equal ")+ .append(`Format:autoFormat` current.getValue())+ .build())+ }+ }+ traverse (actual&.keyOrder() -> #k current) {+ if (! `expected.member` current) {+ \ report.addError(message: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current)+ .append(" is unexpected")+ .build())+ }+ }+ }++ summary () {+ return "map equals"+ }+}++concrete MapMatches<#k, #v> {+ #k requires Formatted++ @type new ([SetReader<#k> & DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>]) -> (ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>)+}++define MapMatches {+ $ReadOnlyExcept[]$++ refines ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>++ @value [SetReader<#k> & DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>] expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ traverse (expected.defaultOrder() -> KeyValue<#k, ValueMatcher<#v>> current) {+ optional #v value <- actual&.get(current.getKey())+ $Hidden[actual, expected]$+ if (! `present` value) {+ \ report.addError(message: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current.getKey())+ .append(" is missing")+ .build())+ } else {+ TestReport newReport <- report.newSection(title: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current.getKey())+ .build())+ $Hidden[report]$+ \ require(value) `current.getValue().check` newReport+ }+ }+ traverse (actual&.keyOrder() -> #k current) {+ if (! `expected.member` current) {+ \ report.addError(message: String.builder()+ .append("Key ")+ .append(`Format:autoFormat` current)+ .append(" is unexpected")+ .build())+ }+ }+ }++ summary () {+ return "map matches"+ }+}
lib/container/src/type-map.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,22 +17,22 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define TypeMap {- @value SortedMap<TypeKey<any>,GenericValue<any>> map+ @value SortedMap<TypeKey<any>, GenericValue<any>> map default () { return new() } new () {- return TypeMap{ SortedMap<TypeKey<any>,GenericValue<any>>.new() }+ return TypeMap{ SortedMap<TypeKey<any>, GenericValue<any>>.new() } } duplicate () { return #self{ map.duplicate() } } - set (k,v) {- \ map.set(k,GenericValue:create(v))+ set (k, v) {+ \ map.set(k, GenericValue:create(v)) return self } @@ -52,7 +52,7 @@ } getAll (output) {- traverse (map.defaultOrder() -> KeyValue<any,GenericValue<any>> pair) {+ traverse (map.defaultOrder() -> KeyValue<any, GenericValue<any>> pair) { scoped { optional #x value <- pair.getValue().check<#x>() } in if (present(value)) {@@ -64,44 +64,29 @@ } define TypeKey {- $ReadOnlyExcept[counter]$-- @category Mutex counterMutex <- SpinlockMutex.new()- @category Int counter <- 0- @value Int index- new () {- scoped {- \ counterMutex.lock()- } cleanup {- \ counterMutex.unlock()- } in return TypeKey<#x>{ (counter <- counter+1) }+ return #self{ } } formatted () { return String.builder() .append(typename<#self>()) .append("{")- .append(index)+ .append( `identify` self) .append("}") .build() } hashed () {- return index.hashed()- }-- lessThan (l,r) {- return l.get() < r.get()+ return identify(self).hashed() } - equals (l,r) {- return l.get() == r.get()+ lessThan (l, r) {+ return identify(l) < identify(r) } - @value get () -> (Int)- get () {- return index+ equals (l, r) {+ return identify(l) == identify(r) } } @@ -116,10 +101,10 @@ @value #x value create (v) {- return GenericValue<#x>{ v }+ return delegate -> GenericValue<#x> } check () {- return reduce<#x,#y>(value)+ return reduce<#x, #y>(value) } }
+ lib/container/src/util.0rp view
@@ -0,0 +1,32 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$++concrete Format {+ @category autoFormat<#x>+ #x requires Formatted+ (optional #x) -> (Formatted)+}++concrete TestValue {+ immutable+ refines TestCompare<TestValue>++ @type new (String) -> (TestValue)+}
+ lib/container/src/util.0rx view
@@ -0,0 +1,54 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define Format {+ autoFormat (value) {+ if (`present` value) {+ return String.builder()+ .append("\"")+ .append(`require` value)+ .append("\"")+ .build()+ } else {+ return "empty"+ }+ }+}++define TestValue {+ @value String message++ new (message) {+ return delegate -> #self+ }++ testCompare (actual, report) {+ if (actual.message() != message) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual.message())+ .append(" does not equal ")+ .append(`Format:autoFormat` message)+ .build())+ }+ }++ @value message () -> (String)+ message () {+ return message+ }+}
lib/container/src/validated-tree.0rp view
@@ -26,8 +26,8 @@ // therefore only be used in tests. concrete ValidatedTree<#k|#v|> { refines Container- refines KVWriter<#k,#v>- refines KVReader<#k,#v>+ refines KVWriter<#k, #v>+ refines KVReader<#k, #v> #k immutable #k defines LessThan<#k>
lib/container/src/wrappers.0rp view
@@ -18,14 +18,14 @@ $ModuleOnly$ -concrete SimpleKeyValue<|#k,#v> {- @category new<#k,#v> (#k,#v) -> (KeyValue<#k,#v>)+concrete SimpleKeyValue<|#k, #v> {+ @category new<#k, #v> (#k, #v) -> (KeyValue<#k, #v>) } concrete MapKeyOrder<#k> {- @category new<#k> (optional Order<KeyValue<#k,any>>) -> (optional Order<#k>)+ @category new<#k> (optional Order<KeyValue<#k, any>>) -> (optional Order<#k>) } concrete MapValueOrder<#v> {- @category new<#v> (optional Order<KeyValue<any,#v>>) -> (optional Order<#v>)+ @category new<#v> (optional Order<KeyValue<any, #v>>) -> (optional Order<#v>) }
lib/container/src/wrappers.0rx view
@@ -19,13 +19,13 @@ define SimpleKeyValue { $ReadOnlyExcept[]$ - refines KeyValue<#k,#v>+ refines KeyValue<#k, #v> @value #k key @value #v value - new (key,value) {- return SimpleKeyValue<#k,#v>{ key, value }+ new (key, value) {+ return delegate -> SimpleKeyValue<#k, #v> } getKey () {@@ -40,7 +40,7 @@ define MapKeyOrder { refines Order<#k> - @value Order<KeyValue<#k,any>> order+ @value Order<KeyValue<#k, any>> order new (order) { if (!present(order)) {@@ -52,7 +52,7 @@ next () { scoped {- optional Order<KeyValue<#k,any>> order2 <- order.next()+ optional Order<KeyValue<#k, any>> order2 <- order.next() } in if (present(order2)) { order <- require(order2) return self@@ -69,7 +69,7 @@ define MapValueOrder { refines Order<#v> - @value Order<KeyValue<any,#v>> order+ @value Order<KeyValue<any, #v>> order new (order) { if (!present(order)) {@@ -81,7 +81,7 @@ next () { scoped {- optional Order<KeyValue<any,#v>> order2 <- order.next()+ optional Order<KeyValue<any, #v>> order2 <- order.next() } in if (present(order2)) { order <- require(order2) return self
lib/container/test/hashed-map.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,19 +17,19 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "HashedMap tests" {- success+ success TestChecker } unittest integrationTest {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.default()+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.default() Int count <- 33 $ReadOnly[count]$ // Insert values. traverse (Counter.zeroIndexed(count) -> Int i) { Int new <- ((i + 13) * 3547) % count- \ map.set(new,i)- \ Testing.checkEquals(map.size(),i+1)+ \ map.set(new, i)+ \ map.size() `Matches:with` CheckValue:equals(i+1) } // Check and remove values.@@ -55,21 +55,21 @@ .flush() } \ map.remove(new)- \ Testing.checkEquals(map.size(),count-i-1)+ \ map.size() `Matches:with` CheckValue:equals(count-i-1) } } unittest removeNotPresent {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.new().set(1,1).set(2,2).set(4,4)+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.new().set(1, 1).set(2, 2).set(4, 4) \ map.remove(3)- \ Testing.checkEquals(map.size(),3)+ \ map.size() `Matches:with` CheckValue:equals(3) } unittest defaultOrder {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -80,27 +80,27 @@ // Validate traversal coverage. Int index <- 0- traverse (map.defaultOrder() -> KeyValue<Int,Int> entry) {- \ Testing.checkFalse(visited.readAt(entry.getKey()))- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())- \ visited.writeAt(entry.getKey(),true)+ traverse (map.defaultOrder() -> KeyValue<Int, Int> entry) {+ \ visited.readAt(entry.getKey()) `Matches:with` CheckValue:equals(false)+ \ (entry.getValue()*hash)%max `Matches:with` CheckValue:equals(entry.getKey())+ \ visited.writeAt(entry.getKey(), true) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest defaultOrderEmpty {- traverse (HashedMap<Int,Int>.new().defaultOrder() -> _) {+ traverse (HashedMap<Int, Int>.new().defaultOrder() -> _) { fail("not empty") } } unittest keyOrder {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -112,19 +112,19 @@ // Validate traversal coverage. Int index <- 0 traverse (map.keyOrder() -> Int key) {- \ Testing.checkFalse(visited.readAt(key))- \ visited.writeAt(key,true)+ \ visited.readAt(key) `Matches:with` CheckValue:equals(false)+ \ visited.writeAt(key, true) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest valueOrder {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -136,83 +136,92 @@ // Validate traversal coverage. Int index <- 0 traverse (map.valueOrder() -> Int value) {- \ Testing.checkFalse(visited.readAt(value))- \ visited.writeAt(value,true)+ \ visited.readAt(value) `Matches:with` CheckValue:equals(false)+ \ visited.writeAt(value, true) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest duplicate {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.default()+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.default() Int max <- 31 $ReadOnly[max]$ traverse (Counter.zeroIndexed(max) -> Int i) {- \ map.set(i,i)+ \ map.set(i, i) } - HashedMap<Int,Int> copy <- map.duplicate()- \ Testing.checkEquals(copy.size(),map.size())+ HashedMap<Int, Int> copy <- map.duplicate()+ \ copy.size() `Matches:with` CheckValue:equals(map.size()) traverse (Counter.zeroIndexed(max) -> Int i) { $Hidden[map]$- \ Testing.checkOptional(copy.get(i),i)+ \ copy.get(i) `Matches:with` CheckValue:equals(i) } - \ copy.set(2,5)+ \ copy.set(2, 5) \ copy.remove(7) $Hidden[copy]$ - \ Testing.checkEquals(map.size(),max)+ \ map.size() `Matches:with` CheckValue:equals(max) traverse (Counter.zeroIndexed(max) -> Int i) {- \ Testing.checkOptional(map.get(i),i)+ \ map.get(i) `Matches:with` CheckValue:equals(i) } } unittest duplicateEmpty {- HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()- HashedMap<Int,Int> copy <- map.duplicate()- \ map.set(1,1)- \ Testing.checkEquals(copy.size(),0)+ HashedMap<Int, Int> map <- HashedMap<Int, Int>.new()+ HashedMap<Int, Int> copy <- map.duplicate()+ \ map.set(1, 1)+ \ copy.size() `Matches:with` CheckValue:equals(0) } unittest weakSetExists {- HashedMap<Int,Value> map <- HashedMap<Int,Value>.default()- .set(1,Value.new(1))- .set(2,Value.new(2))- .set(3,Value.new(3))+ HashedMap<Int, Value> map <- HashedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3)) Value value0 <- Value.new(5)- Value value1 <- map.weakSet(1,value0)- \ Testing.checkEquals(map.size(),3)+ Value value1 <- map.weakSet(1, value0)+ \ map.size() `Matches:with` CheckValue:equals(3) - \ Testing.checkEquals(value0.get(),5)- \ Testing.checkEquals(value1.get(),1)+ \ value0.get() `Matches:with` CheckValue:equals(5)+ \ value1.get() `Matches:with` CheckValue:equals(1) \ value0.set(10)- \ Testing.checkEquals(value1.get(),1)- \ Testing.checkOptional(map.get(1),Value.new(1))+ \ value1.get() `Matches:with` CheckValue:equals(1)+ \ map.get(1) `Matches:with` CheckValue:equals(Value.new(1)) } unittest weakSetMissing {- HashedMap<Int,Value> map <- HashedMap<Int,Value>.default()- .set(1,Value.new(1))- .set(2,Value.new(2))- .set(3,Value.new(3))+ HashedMap<Int, Value> map <- HashedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3)) Value value0 <- Value.new(5)- Value value1 <- map.weakSet(7,value0)- \ Testing.checkEquals(map.size(),4)+ Value value1 <- map.weakSet(7, value0)+ \ map.size() `Matches:with` CheckValue:equals(4) - \ Testing.checkEquals(value0.get(),5)- \ Testing.checkEquals(value1.get(),5)+ \ value0.get() `Matches:with` CheckValue:equals(5)+ \ value1.get() `Matches:with` CheckValue:equals(5) \ value0.set(10)- \ Testing.checkEquals(value1.get(),10)- \ Testing.checkOptional(map.get(7),Value.new(10))+ \ value1.get() `Matches:with` CheckValue:equals(10)+ \ map.get(7) `Matches:with` CheckValue:equals(Value.new(10)) } +unittest setMember {+ HashedMap<Int, Value> map <- HashedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3))+ \ map.member(1) `Matches:with` CheckValue:equals(true)+ \ map.member(5) `Matches:with` CheckValue:equals(false)+}+ concrete Value { defines Equals<Value> refines Formatted@@ -233,7 +242,7 @@ return value.formatted() } - equals (x,y) {+ equals (x, y) { return x.get() == y.get() } }
lib/container/test/hashed-set.0rt view
@@ -17,19 +17,19 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "HashedSet tests" {- success+ success TestChecker } unittest addAndRemove { HashedSet<Int> set <- HashedSet<Int>.default() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) { \ set.add((i*hash)%max)- \ Testing.checkEquals(set.size(),i+1)+ \ set.size() `Matches:with` CheckValue:equals(i+1) } // Remove only the odd elements.@@ -38,33 +38,33 @@ // Remove it twice to ensure idempotence. \ set.remove(i).remove(i) }- \ Testing.checkEquals(set.size(),max-(i+1)/2)+ \ set.size() `Matches:with` CheckValue:equals(max-(i+1)/2) } // Validate set membership. traverse (Counter.zeroIndexed(max) -> Int i) {- \ Testing.checkEquals(set.member(i),i%2 == 0)+ \ set.member(i) `Matches:with` CheckValue:equals(i%2 == 0) } } unittest append { HashedSet<Int> set <- HashedSet<Int>.new() \ set.append(3)- \ Testing.checkEquals(set.size(),1)- \ Testing.checkTrue(set.member(3))+ \ set.size() `Matches:with` CheckValue:equals(1)+ \ set.member(3) `Matches:with` CheckValue:equals(true) } unittest removeNotPresent { HashedSet<Int> set <- HashedSet<Int>.new().add(1).add(2).add(4) \ set.remove(3)- \ Testing.checkEquals(set.size(),3)+ \ set.size() `Matches:with` CheckValue:equals(3) } unittest defaultOrder { HashedSet<Int> set <- HashedSet<Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -76,12 +76,12 @@ // Validate traversal coverage. Int index <- 0 traverse (set.defaultOrder() -> Int entry) {- \ Testing.checkFalse(visited.readAt(entry))- \ visited.writeAt(entry,true)+ \ visited.readAt(entry) `Matches:with` CheckValue:equals(false)+ \ visited.writeAt(entry, true) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest defaultOrderEmpty {@@ -94,12 +94,12 @@ HashedSet<Int> set <- HashedSet<Int>.new().add(1).add(2) HashedSet<Int> copy <- set.duplicate()- \ Testing.checkEquals(copy.size(),2)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(copy.member(1))+ \ copy.size() `Matches:with` CheckValue:equals(2)+ \ copy.member(1) `Matches:with` CheckValue:equals(true)+ \ copy.member(1) `Matches:with` CheckValue:equals(true) \ copy.remove(2)- \ Testing.checkEquals(copy.size(),1)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(set.member(2))+ \ copy.size() `Matches:with` CheckValue:equals(1)+ \ copy.member(1) `Matches:with` CheckValue:equals(true)+ \ set.member(2) `Matches:with` CheckValue:equals(true) }
lib/container/test/helpers.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,83 +17,83 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "comparator helper tests" {- success+ success TestChecker } unittest keyValueHLessThan {- \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:lessThan` KV.new(1,"a"))- \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:lessThan` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(2,"a") `KeyValueH:lessThan` KV.new(1,"b"))- \ Testing.checkTrue(KV.new(1,"b") `KeyValueH:lessThan` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:lessThan` KV.new(1, "a")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "a") `KeyValueH:lessThan` KV.new(1, "b")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(2, "a") `KeyValueH:lessThan` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "b") `KeyValueH:lessThan` KV.new(2, "a")) `Matches:with` CheckValue:equals(true) } unittest keyValueHLessThanWith {- \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"a"))- \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(2,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"))- \ Testing.checkTrue(KV.new(1,"b") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:lessThanWith<?, ?, Int, AlwaysEqual>` KV.new(1, "a")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "a") `KeyValueH:lessThanWith<?, ?, Int, AlwaysEqual>` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(2, "a") `KeyValueH:lessThanWith<?, ?, Int, AlwaysEqual>` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "b") `KeyValueH:lessThanWith<?, ?, Int, AlwaysEqual>` KV.new(2, "a")) `Matches:with` CheckValue:equals(true) - \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"a"))- \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"b"))- \ Testing.checkTrue(KV.new(2,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(1,"b") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:lessThanWith<?, ?, AlwaysEqual, String>` KV.new(1, "a")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "a") `KeyValueH:lessThanWith<?, ?, AlwaysEqual, String>` KV.new(1, "b")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(2, "a") `KeyValueH:lessThanWith<?, ?, AlwaysEqual, String>` KV.new(1, "b")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(1, "b") `KeyValueH:lessThanWith<?, ?, AlwaysEqual, String>` KV.new(2, "a")) `Matches:with` CheckValue:equals(false) } unittest keyValueHEquals {- \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:equals` KV.new(1,"a"))- \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:equals` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(2,"a") `KeyValueH:equals` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(1,"b") `KeyValueH:equals` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:equals` KV.new(1, "a")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(1, "a") `KeyValueH:equals` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(2, "a") `KeyValueH:equals` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "b") `KeyValueH:equals` KV.new(2, "a")) `Matches:with` CheckValue:equals(false) } unittest keyValueHEqualsWith {- \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"a"))- \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(2,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(1,"b") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:equalsWith<?, ?, Int, AlwaysEqual>` KV.new(1, "a")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(1, "a") `KeyValueH:equalsWith<?, ?, Int, AlwaysEqual>` KV.new(1, "b")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(2, "a") `KeyValueH:equalsWith<?, ?, Int, AlwaysEqual>` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "b") `KeyValueH:equalsWith<?, ?, Int, AlwaysEqual>` KV.new(2, "a")) `Matches:with` CheckValue:equals(false) - \ Testing.checkTrue(KV.new(1,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"a"))- \ Testing.checkFalse(KV.new(1,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(2,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"b"))- \ Testing.checkFalse(KV.new(1,"b") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(2,"a"))+ \ (KV.new(1, "a") `KeyValueH:equalsWith<?, ?, AlwaysEqual, String>` KV.new(1, "a")) `Matches:with` CheckValue:equals(true)+ \ (KV.new(1, "a") `KeyValueH:equalsWith<?, ?, AlwaysEqual, String>` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(2, "a") `KeyValueH:equalsWith<?, ?, AlwaysEqual, String>` KV.new(1, "b")) `Matches:with` CheckValue:equals(false)+ \ (KV.new(1, "b") `KeyValueH:equalsWith<?, ?, AlwaysEqual, String>` KV.new(2, "a")) `Matches:with` CheckValue:equals(false) } unittest integrationTest {- SortedMap<Int,String> map1 <- SortedMap<Int,String>.new()- .set(1,"d").set(2,"c").set(3,"b").set(4,"a")- SortedMap<Int,String> map2 <- SortedMap<Int,String>.new()- .set(1,"a").set(2,"b").set(3,"c").set(4,"d")+ SortedMap<Int, String> map1 <- SortedMap<Int, String>.new()+ .set(1, "d").set(2, "c").set(3, "b").set(4, "a")+ SortedMap<Int, String> map2 <- SortedMap<Int, String>.new()+ .set(1, "a").set(2, "b").set(3, "c").set(4, "d") - \ Testing.checkTrue(map1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,AlwaysEqual>>` map2.defaultOrder())- \ Testing.checkFalse(map1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,String>>` map2.defaultOrder())- \ Testing.checkFalse(map1.defaultOrder() `OrderH:equalsWith<?,KVEquals<AlwaysEqual,String>>` map2.defaultOrder())+ \ (map1.defaultOrder() `OrderH:equalsWith<?, KVEquals<Int, AlwaysEqual>>` map2.defaultOrder()) `Matches:with` CheckValue:equals(true)+ \ (map1.defaultOrder() `OrderH:equalsWith<?, KVEquals<Int, String>>` map2.defaultOrder()) `Matches:with` CheckValue:equals(false)+ \ (map1.defaultOrder() `OrderH:equalsWith<?, KVEquals<AlwaysEqual, String>>` map2.defaultOrder()) `Matches:with` CheckValue:equals(false) } -concrete KVEquals<#k,#v> {- defines Equals<KeyValue<Int,String>>+concrete KVEquals<#k, #v> {+ defines Equals<KeyValue<Int, String>> #k defines Equals<Int> #v defines Equals<String> } define KVEquals {- equals (x,y) {- return x `KeyValueH:equalsWith<?,?,#k,#v>` y+ equals (x, y) {+ return x `KeyValueH:equalsWith<?, ?, #k, #v>` y } } concrete KV {- refines KeyValue<Int,String>+ refines KeyValue<Int, String> - @type new (Int,String) -> (KV)+ @type new (Int, String) -> (KV) } define KV {- $ReadOnly[key,value]$+ $ReadOnly[key, value]$ @value Int key @value String value - new (k,v) {+ new (k, v) { return KV{ k, v } }
lib/container/test/list.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "basic list tests" {- success+ success TestChecker timeout 5 } @@ -40,11 +40,11 @@ .append(4) traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(head).get(),value)+ \ require(head).get() `Matches:with` CheckValue:equals(value) } update { head <- require(head).next() }- \ Testing.checkFalse(present(head))+ \ present(head) `Matches:with` CheckValue:equals(false) } unittest reverseTraverse {@@ -67,11 +67,11 @@ .append(3) traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(tail).get(),value)+ \ require(tail).get() `Matches:with` CheckValue:equals(value) } update { tail <- require(tail).prev() }- \ Testing.checkFalse(present(tail))+ \ present(tail) `Matches:with` CheckValue:equals(false) } unittest setNext {@@ -84,7 +84,7 @@ .append(4) .build() - optional LinkedNode<Int> after1 <- Helper.jumpBy(3,head1)+ optional LinkedNode<Int> after1 <- Helper.jumpBy(3, head1) optional LinkedNode<Int> before1 <- require(after1).prev() optional LinkedNode<Int> head2, _ <- LinkedNode<Int>.builder()@@ -96,15 +96,15 @@ .append(14) .build() - optional LinkedNode<Int> after2 <- Helper.jumpBy(3,head2)+ optional LinkedNode<Int> after2 <- Helper.jumpBy(3, head2) optional LinkedNode<Int> before2 <- require(after2).prev() - \ Testing.checkEquals(require(require(before1).setNext(after2)).get(),1)+ \ require(require(before1).setNext(after2)).get() `Matches:with` CheckValue:equals(1) - \ Testing.checkFalse(present(require(after1).prev()))- \ Testing.checkEquals(require(require(before1).next()).get(),11)- \ Testing.checkEquals(require(require(after2).prev()).get(),5)- \ Testing.checkFalse(present(require(before2).next()))+ \ present(require(after1).prev()) `Matches:with` CheckValue:equals(false)+ \ require(require(before1).next()).get() `Matches:with` CheckValue:equals(11)+ \ require(require(after2).prev()).get() `Matches:with` CheckValue:equals(5)+ \ present(require(before2).next()) `Matches:with` CheckValue:equals(false) } unittest setPrev {@@ -117,7 +117,7 @@ .append(4) .build() - optional LinkedNode<Int> after1 <- Helper.jumpBy(3,head1)+ optional LinkedNode<Int> after1 <- Helper.jumpBy(3, head1) optional LinkedNode<Int> before1 <- require(after1).prev() optional LinkedNode<Int> head2, _ <- LinkedNode<Int>.builder()@@ -129,15 +129,15 @@ .append(14) .build() - optional LinkedNode<Int> after2 <- Helper.jumpBy(3,head2)+ optional LinkedNode<Int> after2 <- Helper.jumpBy(3, head2) optional LinkedNode<Int> before2 <- require(after2).prev() - \ Testing.checkEquals(require(require(after1).setPrev(before2)).get(),5)+ \ require(require(after1).setPrev(before2)).get() `Matches:with` CheckValue:equals(5) - \ Testing.checkEquals(require(require(after1).prev()).get(),15)- \ Testing.checkFalse(present(require(before1).next()))- \ Testing.checkFalse(present(require(after2).prev()))- \ Testing.checkEquals(require(require(before2).next()).get(),1)+ \ require(require(after1).prev()).get() `Matches:with` CheckValue:equals(15)+ \ present(require(before1).next()) `Matches:with` CheckValue:equals(false)+ \ present(require(after2).prev()) `Matches:with` CheckValue:equals(false)+ \ require(require(before2).next()).get() `Matches:with` CheckValue:equals(1) } unittest setNextSame {@@ -150,13 +150,13 @@ .append(4) .build() - optional LinkedNode<Int> after <- Helper.jumpBy(3,head)+ optional LinkedNode<Int> after <- Helper.jumpBy(3, head) optional LinkedNode<Int> before <- require(after).prev() \ require(before).setNext(after) - \ Testing.checkEquals(require(require(after).prev()).get(),5)- \ Testing.checkEquals(require(require(before).next()).get(),1)+ \ require(require(after).prev()).get() `Matches:with` CheckValue:equals(5)+ \ require(require(before).next()).get() `Matches:with` CheckValue:equals(1) } unittest setPrevSame {@@ -169,13 +169,13 @@ .append(4) .build() - optional LinkedNode<Int> after <- Helper.jumpBy(3,head)+ optional LinkedNode<Int> after <- Helper.jumpBy(3, head) optional LinkedNode<Int> before <- require(after).prev() \ require(after).setPrev(before) - \ Testing.checkEquals(require(require(after).prev()).get(),5)- \ Testing.checkEquals(require(require(before).next()).get(),1)+ \ require(require(after).prev()).get() `Matches:with` CheckValue:equals(5)+ \ require(require(before).next()).get() `Matches:with` CheckValue:equals(1) } unittest setNextSelf {@@ -188,14 +188,14 @@ .append(4) .build() - optional LinkedNode<Int> after <- Helper.jumpBy(3,head)+ optional LinkedNode<Int> after <- Helper.jumpBy(3, head) optional LinkedNode<Int> before <- require(after).prev() \ require(before).setNext(before) - \ Testing.checkFalse(present(require(after).prev()))- \ Testing.checkEquals(require(require(before).prev()).get(),5)- \ Testing.checkEquals(require(require(before).next()).get(),5)+ \ present(require(after).prev()) `Matches:with` CheckValue:equals(false)+ \ require(require(before).prev()).get() `Matches:with` CheckValue:equals(5)+ \ require(require(before).next()).get() `Matches:with` CheckValue:equals(5) } unittest setPrevSelf {@@ -208,14 +208,14 @@ .append(4) .build() - optional LinkedNode<Int> after <- Helper.jumpBy(3,head)+ optional LinkedNode<Int> after <- Helper.jumpBy(3, head) optional LinkedNode<Int> before <- require(after).prev() \ require(after).setPrev(after) - \ Testing.checkFalse(present(require(before).next()))- \ Testing.checkEquals(require(require(after).prev()).get(),1)- \ Testing.checkEquals(require(require(after).next()).get(),1)+ \ present(require(before).next()) `Matches:with` CheckValue:equals(false)+ \ require(require(after).prev()).get() `Matches:with` CheckValue:equals(1)+ \ require(require(after).next()).get() `Matches:with` CheckValue:equals(1) } unittest duplicate {@@ -237,20 +237,20 @@ .append(4) optional LinkedNode<Int> head2 <- require(head).duplicate()- \ require(Helper.jumpBy(3,head)).set(7).setNext(empty)+ \ require(Helper.jumpBy(3, head)).set(7).setNext(empty) $Hidden[head]$ traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(head2).get(),value)+ \ require(head2).get() `Matches:with` CheckValue:equals(value) } update { head2 <- require(head2).next() }- \ Testing.checkFalse(present(head2))+ \ present(head2) `Matches:with` CheckValue:equals(false) } unittest hugeCleanup { $DisableCoverage$ scoped {- ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()+ ListBuilder<Int, LinkedNode<Int>> builder <- LinkedNode<Int>.builder() } in traverse (Counter.zeroIndexed(1000000) -> _) { \ builder.append(0) }@@ -275,11 +275,11 @@ .append(4) traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(head).get(),value)+ \ require(head).get() `Matches:with` CheckValue:equals(value) } update { head <- require(head).next() }- \ Testing.checkFalse(present(head))+ \ present(head) `Matches:with` CheckValue:equals(false) } unittest duplicateSingle {@@ -301,20 +301,20 @@ .append(4) optional ForwardNode<Int> head2 <- require(head).duplicate()- \ require(Helper.jumpBy(3,head)).set(7).setNext(empty)+ \ require(Helper.jumpBy(3, head)).set(7).setNext(empty) $Hidden[head]$ traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(head2).get(),value)+ \ require(head2).get() `Matches:with` CheckValue:equals(value) } update { head2 <- require(head2).next() }- \ Testing.checkFalse(present(head2))+ \ present(head2) `Matches:with` CheckValue:equals(false) } unittest hugeCleanupSingle { $DisableCoverage$ scoped {- ListBuilder<Int,ForwardNode<Int>> builder <- ForwardNode<Int>.builder()+ ListBuilder<Int, ForwardNode<Int>> builder <- ForwardNode<Int>.builder() } in traverse (Counter.zeroIndexed(1000000) -> _) { \ builder.append(0) }@@ -323,11 +323,11 @@ concrete Helper { @type jumpBy<#x> #x requires Order<any>- (Int,optional #x) -> (optional #x)+ (Int, optional #x) -> (optional #x) } define Helper {- jumpBy (n,x) (y) {+ jumpBy (n, x) (y) { y <- x traverse (Counter.zeroIndexed(n) -> _) { y <- require(y).next()
lib/container/test/queue.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "SimpleQueue tests" {- success+ success TestChecker } unittest integrationTest {@@ -25,14 +25,14 @@ $ReadOnly[max]$ SimpleQueue<Int> queue <- SimpleQueue<Int>.default() traverse (`Counter.zeroIndexed` max -> Int value) {- \ Testing.checkEquals(queue.size(),value)+ \ queue.size() `Matches:with` CheckValue:equals(value) \ queue.append(value) } traverse (`Counter.zeroIndexed` max -> Int value) {- \ Testing.checkEquals(queue.size(),max-value)- \ Testing.checkEquals(queue.pop(),value)+ \ queue.size() `Matches:with` CheckValue:equals(max-value)+ \ queue.pop() `Matches:with` CheckValue:equals(value) }- \ Testing.checkEquals(queue.size(),0)+ \ queue.size() `Matches:with` CheckValue:equals(0) } unittest duplicate {@@ -45,8 +45,8 @@ \ queue.pop() $Hidden[queue]$ traverse (`Counter.zeroIndexed` max -> Int value) {- \ Testing.checkEquals(copy.size(),max-value)- \ Testing.checkEquals(copy.pop(),value)+ \ copy.size() `Matches:with` CheckValue:equals(max-value)+ \ copy.pop() `Matches:with` CheckValue:equals(value) }- \ Testing.checkEquals(copy.size(),0)+ \ copy.size() `Matches:with` CheckValue:equals(0) }
lib/container/test/sorted-map.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,19 +17,19 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "SortedMap tests" {- success+ success TestChecker } unittest integrationTest {- ValidatedTree<Int,Int> map <- ValidatedTree<Int,Int>.new()+ ValidatedTree<Int, Int> map <- ValidatedTree<Int, Int>.new() Int count <- 33 $ReadOnly[count]$ // Insert values. traverse (Counter.zeroIndexed(count) -> Int i) { Int new <- ((i + 13) * 3547) % count- \ map.set(new,i)- \ Testing.checkEquals(map.size(),i+1)+ \ map.set(new, i)+ \ map.size() `Matches:with` CheckValue:equals(i+1) } // Check and remove values.@@ -55,21 +55,21 @@ .flush() } \ map.remove(new)- \ Testing.checkEquals(map.size(),count-i-1)+ \ map.size() `Matches:with` CheckValue:equals(count-i-1) } } unittest removeNotPresent {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new().set(1,1).set(2,2).set(4,4)+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new().set(1, 1).set(2, 2).set(4, 4) \ map.remove(3)- \ Testing.checkEquals(map.size(),3)+ \ map.size() `Matches:with` CheckValue:equals(3) } unittest defaultOrder {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -78,26 +78,26 @@ // Validate the traversal order. Int index <- 0- traverse (map.defaultOrder() -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())+ traverse (map.defaultOrder() -> KeyValue<Int, Int> entry) {+ \ entry.getKey() `Matches:with` CheckValue:equals(index)+ \ (entry.getValue()*hash)%max `Matches:with` CheckValue:equals(entry.getKey()) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest defaultOrderEmpty {- traverse (SortedMap<Int,Int>.new().defaultOrder() -> _) {+ traverse (SortedMap<Int, Int>.new().defaultOrder() -> _) { fail("not empty") } } unittest keyOrder {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -107,18 +107,18 @@ // Validate the traversal order. Int index <- 0 traverse (map.keyOrder() -> Int key) {- \ Testing.checkEquals(key,index)+ \ key `Matches:with` CheckValue:equals(index) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest valueOrder {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -128,18 +128,18 @@ // Validate the traversal order. Int index <- 0 traverse (map.valueOrder() -> Int value) {- \ Testing.checkEquals((value*hash)%max,index)+ \ (value*hash)%max `Matches:with` CheckValue:equals(index) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest reverseOrder {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -148,20 +148,20 @@ // Validate the traversal order. Int index <- max- traverse (map.reverseOrder() -> KeyValue<Int,Int> entry) {+ traverse (map.reverseOrder() -> KeyValue<Int, Int> entry) { index <- index-1- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())+ \ entry.getKey() `Matches:with` CheckValue:equals(index)+ \ (entry.getValue()*hash)%max `Matches:with` CheckValue:equals(entry.getKey()) } - \ Testing.checkEquals(index,0)+ \ index `Matches:with` CheckValue:equals(0) } unittest getForward {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -171,39 +171,39 @@ // Validate the traversal order from every starting point. traverse (Counter.zeroIndexed(max) -> Int i) { Int index <- i- traverse (map.getForward(index) -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())+ traverse (map.getForward(index) -> KeyValue<Int, Int> entry) {+ \ entry.getKey() `Matches:with` CheckValue:equals(index)+ \ (entry.getValue()*hash)%max `Matches:with` CheckValue:equals(entry.getKey()) index <- index+1 }- \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } } unittest getForwardNotFound {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()- \ map.set(1,1).set(3,3).set(5,5)+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new()+ \ map.set(1, 1).set(3, 3).set(5, 5) scoped {- optional Order<KeyValue<Int,Int>> start <- map.getForward(4)+ optional Order<KeyValue<Int, Int>> start <- map.getForward(4) } in if (!present(start)) { fail("Failed") } else {- \ Testing.checkEquals(require(start).get().getKey(),5)+ \ require(start).get().getKey() `Matches:with` CheckValue:equals(5) } scoped {- optional Order<KeyValue<Int,Int>> start <- map.getForward(6)+ optional Order<KeyValue<Int, Int>> start <- map.getForward(6) } in if (present(start)) { fail("Failed") } } unittest getReverse {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the map in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -213,103 +213,112 @@ // Validate the traversal order from every starting point. traverse (Counter.zeroIndexed(max) -> Int i) { Int index <- i- traverse (map.getReverse(index) -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())+ traverse (map.getReverse(index) -> KeyValue<Int, Int> entry) {+ \ entry.getKey() `Matches:with` CheckValue:equals(index)+ \ (entry.getValue()*hash)%max `Matches:with` CheckValue:equals(entry.getKey()) index <- index-1 }- \ Testing.checkEquals(index,-1)+ \ index `Matches:with` CheckValue:equals(-1) } } unittest getReverseNotFound {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()- \ map.set(1,1).set(3,3).set(5,5)+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new()+ \ map.set(1, 1).set(3, 3).set(5, 5) scoped {- optional Order<KeyValue<Int,Int>> start <- map.getReverse(2)+ optional Order<KeyValue<Int, Int>> start <- map.getReverse(2) } in if (!present(start)) { fail("Failed") } else {- \ Testing.checkEquals(require(start).get().getKey(),1)+ \ require(start).get().getKey() `Matches:with` CheckValue:equals(1) } scoped {- optional Order<KeyValue<Int,Int>> start <- map.getReverse(0)+ optional Order<KeyValue<Int, Int>> start <- map.getReverse(0) } in if (present(start)) { fail("Failed") } } unittest duplicate {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.default()+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.default() Int max <- 31 $ReadOnly[max]$ traverse (Counter.zeroIndexed(max) -> Int i) {- \ map.set(i,i)+ \ map.set(i, i) } - SortedMap<Int,Int> copy <- map.duplicate()- \ Testing.checkEquals(copy.size(),map.size())+ SortedMap<Int, Int> copy <- map.duplicate()+ \ copy.size() `Matches:with` CheckValue:equals(map.size()) traverse (Counter.zeroIndexed(max) -> Int i) { $Hidden[map]$- \ Testing.checkOptional(copy.get(i),i)+ \ copy.get(i) `Matches:with` CheckValue:equals(i) } - \ copy.set(2,5)+ \ copy.set(2, 5) \ copy.remove(7) $Hidden[copy]$ - \ Testing.checkEquals(map.size(),max)+ \ map.size() `Matches:with` CheckValue:equals(max) traverse (Counter.zeroIndexed(max) -> Int i) {- \ Testing.checkOptional(map.get(i),i)+ \ map.get(i) `Matches:with` CheckValue:equals(i) } } unittest duplicateEmpty {- SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()- SortedMap<Int,Int> copy <- map.duplicate()- \ map.set(1,1)- \ Testing.checkEquals(copy.size(),0)+ SortedMap<Int, Int> map <- SortedMap<Int, Int>.new()+ SortedMap<Int, Int> copy <- map.duplicate()+ \ map.set(1, 1)+ \ copy.size() `Matches:with` CheckValue:equals(0) } unittest weakSetExists {- SortedMap<Int,Value> map <- SortedMap<Int,Value>.default()- .set(1,Value.new(1))- .set(2,Value.new(2))- .set(3,Value.new(3))+ SortedMap<Int, Value> map <- SortedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3)) Value value0 <- Value.new(5)- Value value1 <- map.weakSet(1,value0)- \ Testing.checkEquals(map.size(),3)+ Value value1 <- map.weakSet(1, value0)+ \ map.size() `Matches:with` CheckValue:equals(3) - \ Testing.checkEquals(value0.get(),5)- \ Testing.checkEquals(value1.get(),1)+ \ value0.get() `Matches:with` CheckValue:equals(5)+ \ value1.get() `Matches:with` CheckValue:equals(1) \ value0.set(10)- \ Testing.checkEquals(value1.get(),1)- \ Testing.checkOptional(map.get(1),Value.new(1))+ \ value1.get() `Matches:with` CheckValue:equals(1)+ \ map.get(1) `Matches:with` CheckValue:equals(Value.new(1)) } unittest weakSetMissing {- SortedMap<Int,Value> map <- SortedMap<Int,Value>.default()- .set(1,Value.new(1))- .set(2,Value.new(2))- .set(3,Value.new(3))+ SortedMap<Int, Value> map <- SortedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3)) Value value0 <- Value.new(5)- Value value1 <- map.weakSet(7,value0)- \ Testing.checkEquals(map.size(),4)+ Value value1 <- map.weakSet(7, value0)+ \ map.size() `Matches:with` CheckValue:equals(4) - \ Testing.checkEquals(value0.get(),5)- \ Testing.checkEquals(value1.get(),5)+ \ value0.get() `Matches:with` CheckValue:equals(5)+ \ value1.get() `Matches:with` CheckValue:equals(5) \ value0.set(10)- \ Testing.checkEquals(value1.get(),10)- \ Testing.checkOptional(map.get(7),Value.new(10))+ \ value1.get() `Matches:with` CheckValue:equals(10)+ \ map.get(7) `Matches:with` CheckValue:equals(Value.new(10)) } +unittest setMember {+ SortedMap<Int, Value> map <- SortedMap<Int, Value>.default()+ .set(1, Value.new(1))+ .set(2, Value.new(2))+ .set(3, Value.new(3))+ \ map.member(1) `Matches:with` CheckValue:equals(true)+ \ map.member(5) `Matches:with` CheckValue:equals(false)+}+ concrete Value { defines Equals<Value> refines Formatted@@ -330,7 +339,7 @@ return value.formatted() } - equals (x,y) {+ equals (x, y) { return x.get() == y.get() } }
lib/container/test/sorted-set.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,19 +17,19 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "SortedSet tests" {- success+ success TestChecker } unittest addAndRemove { SortedSet<Int> set <- SortedSet<Int>.default() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) { \ set.add((i*hash)%max)- \ Testing.checkEquals(set.size(),i+1)+ \ set.size() `Matches:with` CheckValue:equals(i+1) } // Remove only the odd elements.@@ -38,33 +38,33 @@ // Remove it twice to ensure idempotence. \ set.remove(i).remove(i) }- \ Testing.checkEquals(set.size(),max-(i+1)/2)+ \ set.size() `Matches:with` CheckValue:equals(max-(i+1)/2) } // Validate set membership. traverse (Counter.zeroIndexed(max) -> Int i) {- \ Testing.checkEquals(set.member(i),i%2 == 0)+ \ set.member(i) `Matches:with` CheckValue:equals(i%2 == 0) } } unittest append { SortedSet<Int> set <- SortedSet<Int>.new() \ set.append(3)- \ Testing.checkEquals(set.size(),1)- \ Testing.checkTrue(set.member(3))+ \ set.size() `Matches:with` CheckValue:equals(1)+ \ set.member(3) `Matches:with` CheckValue:equals(true) } unittest removeNotPresent { SortedSet<Int> set <- SortedSet<Int>.new().add(1).add(2).add(4) \ set.remove(3)- \ Testing.checkEquals(set.size(),3)+ \ set.size() `Matches:with` CheckValue:equals(3) } unittest defaultOrder { SortedSet<Int> set <- SortedSet<Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -74,11 +74,11 @@ // Validate the traversal order. Int index <- 0 traverse (set.defaultOrder() -> Int entry) {- \ Testing.checkEquals(entry,index)+ \ entry `Matches:with` CheckValue:equals(index) index <- index+1 } - \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } unittest defaultOrderEmpty {@@ -91,7 +91,7 @@ SortedSet<Int> set <- SortedSet<Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -102,17 +102,17 @@ Int index <- max traverse (set.reverseOrder() -> Int entry) { index <- index-1- \ Testing.checkEquals(entry,index)+ \ entry `Matches:with` CheckValue:equals(index) } - \ Testing.checkEquals(index,0)+ \ index `Matches:with` CheckValue:equals(0) } unittest getForward { SortedSet<Int> set <- SortedSet<Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -123,10 +123,10 @@ traverse (Counter.zeroIndexed(max) -> Int i) { Int index <- i traverse (set.getForward(index) -> Int entry) {- \ Testing.checkEquals(entry,index)+ \ entry `Matches:with` CheckValue:equals(index) index <- index+1 }- \ Testing.checkEquals(index,max)+ \ index `Matches:with` CheckValue:equals(max) } } @@ -139,7 +139,7 @@ } in if (!present(start)) { fail("Failed") } else {- \ Testing.checkEquals(require(start).get(),5)+ \ require(start).get() `Matches:with` CheckValue:equals(5) } scoped {@@ -153,7 +153,7 @@ SortedSet<Int> set <- SortedSet<Int>.new() Int hash <- 13 Int max <- 20- $ReadOnly[hash,max]$+ $ReadOnly[hash, max]$ // Populate the set in a pseudo-random order. traverse (Counter.zeroIndexed(max) -> Int i) {@@ -164,10 +164,10 @@ traverse (Counter.zeroIndexed(max) -> Int i) { Int index <- i traverse (set.getReverse(index) -> Int entry) {- \ Testing.checkEquals(entry,index)+ \ entry `Matches:with` CheckValue:equals(index) index <- index-1 }- \ Testing.checkEquals(index,-1)+ \ index `Matches:with` CheckValue:equals(-1) } } @@ -180,7 +180,7 @@ } in if (!present(start)) { fail("Failed") } else {- \ Testing.checkEquals(require(start).get(),1)+ \ require(start).get() `Matches:with` CheckValue:equals(1) } scoped {@@ -194,12 +194,12 @@ SortedSet<Int> set <- SortedSet<Int>.new().add(1).add(2) SortedSet<Int> copy <- set.duplicate()- \ Testing.checkEquals(copy.size(),2)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(copy.member(1))+ \ copy.size() `Matches:with` CheckValue:equals(2)+ \ copy.member(1) `Matches:with` CheckValue:equals(true)+ \ copy.member(1) `Matches:with` CheckValue:equals(true) \ copy.remove(2)- \ Testing.checkEquals(copy.size(),1)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(set.member(2))+ \ copy.size() `Matches:with` CheckValue:equals(1)+ \ copy.member(1) `Matches:with` CheckValue:equals(true)+ \ set.member(2) `Matches:with` CheckValue:equals(true) }
lib/container/test/sorting.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "Sorting tests" {- success+ success TestChecker timeout 5 } @@ -26,7 +26,7 @@ TestSequence expected <- TestSequence.create() Int hash <- 269 Int size <- 137- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.zeroIndexed(size) -> Int i) { \ original.append((i*hash)%size/3)@@ -34,7 +34,7 @@ } \ Sorting:sort(original)- \ Testing.checkEquals(original,expected)+ \ original `Matches:with` CheckValue:equals(expected) } unittest sortWith { $DisableCoverage$@@ -42,15 +42,15 @@ TestSequence expected <- TestSequence.create() Int hash <- 313 Int size <- 197- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.revZeroIndexed(size) -> Int i) { \ original.append((i*hash)%size/3) \ expected.append(i/3) } - \ Sorting:sortWith<?,Reversed<Int>>(original)- \ Testing.checkEquals(original,expected)+ \ Sorting:sortWith<?, Reversed<Int>>(original)+ \ original `Matches:with` CheckValue:equals(expected) } unittest sortEmpty {@@ -58,7 +58,7 @@ TestSequence expected <- TestSequence.create() \ Sorting:sort(original)- \ Testing.checkEquals(original,expected)+ \ original `Matches:with` CheckValue:equals(expected) } unittest reverseEvenSize {@@ -76,7 +76,7 @@ } \ Sorting:reverse(original)- \ Testing.checkEquals(original,expected)+ \ original `Matches:with` CheckValue:equals(expected) } unittest reverseOddSize { $DisableCoverage$@@ -94,7 +94,7 @@ } \ Sorting:reverse(original)- \ Testing.checkEquals(original,expected)+ \ original `Matches:with` CheckValue:equals(expected) } unittest reverseEmpty {@@ -102,15 +102,15 @@ TestSequence expected <- TestSequence.create() \ Sorting:reverse(original)- \ Testing.checkEquals(original,expected)+ \ original `Matches:with` CheckValue:equals(expected) } unittest sortList {- ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()+ ListBuilder<Int, LinkedNode<Int>> builder <- LinkedNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.zeroIndexed(size) -> Int i) { \ builder.append((i*hash)%size/3)@@ -120,19 +120,19 @@ optional LinkedNode<Int> actual <- Sorting:sortList(builder.build(){0}) traverse (expected.defaultOrder() -> Int n) {- \ Testing.checkEquals(require(actual).get(),n)+ \ require(actual).get() `Matches:with` CheckValue:equals(n) } update { actual <- require(actual).next() }- \ Testing.checkFalse(present(actual))+ \ present(actual) `Matches:with` CheckValue:equals(false) } unittest sortListSingle { $DisableCoverage$- ListBuilder<Int,ForwardNode<Int>> builder <- ForwardNode<Int>.builder()+ ListBuilder<Int, ForwardNode<Int>> builder <- ForwardNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.zeroIndexed(size) -> Int i) { \ builder.append((i*hash)%size/3)@@ -142,23 +142,23 @@ optional ForwardNode<Int> actual <- Sorting:sortList(builder.build(){0}) traverse (expected.defaultOrder() -> Int n) {- \ Testing.checkEquals(require(actual).get(),n)+ \ require(actual).get() `Matches:with` CheckValue:equals(n) } update { actual <- require(actual).next() }- \ Testing.checkFalse(present(actual))+ \ present(actual) `Matches:with` CheckValue:equals(false) } unittest sortListEmpty {- \ Sorting:sortList<LinkedNode<Int>,Int>(empty)+ \ Sorting:sortList<LinkedNode<Int>, Int>(empty) } unittest sortListPow2 { $DisableCoverage$- ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()+ ListBuilder<Int, LinkedNode<Int>> builder <- LinkedNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 256- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.zeroIndexed(size) -> Int i) { \ builder.append((i*hash)%size/3)@@ -168,37 +168,37 @@ optional LinkedNode<Int> actual <- Sorting:sortList(builder.build(){0}) traverse (expected.defaultOrder() -> Int n) {- \ Testing.checkEquals(require(actual).get(),n)+ \ require(actual).get() `Matches:with` CheckValue:equals(n) } update { actual <- require(actual).next() }- \ Testing.checkFalse(present(actual))+ \ present(actual) `Matches:with` CheckValue:equals(false) } unittest sortListWith { $DisableCoverage$- ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()+ ListBuilder<Int, LinkedNode<Int>> builder <- LinkedNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137- $ReadOnly[hash,size]$+ $ReadOnly[hash, size]$ traverse (Counter.revZeroIndexed(size) -> Int i) { \ builder.append((i*hash)%size/3) \ expected.append(i/3) } - optional LinkedNode<Int> actual <- Sorting:sortListWith<?,?,Reversed<Int>>(builder.build(){0})+ optional LinkedNode<Int> actual <- Sorting:sortListWith<?, ?, Reversed<Int>>(builder.build(){0}) traverse (expected.defaultOrder() -> Int n) {- \ Testing.checkEquals(require(actual).get(),n)+ \ require(actual).get() `Matches:with` CheckValue:equals(n) } update { actual <- require(actual).next() }- \ Testing.checkFalse(present(actual))+ \ present(actual) `Matches:with` CheckValue:equals(false) } unittest reverseList {- ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()+ ListBuilder<Int, LinkedNode<Int>> builder <- LinkedNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int size <- 101 $ReadOnly[size]$@@ -214,15 +214,15 @@ optional LinkedNode<Int> reversed <- Sorting:reverseList(builder.build(){0}) traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(reversed).get(),value)+ \ require(reversed).get() `Matches:with` CheckValue:equals(value) } update { reversed <- require(reversed).next() }- \ Testing.checkFalse(present(reversed))+ \ present(reversed) `Matches:with` CheckValue:equals(false) } unittest reverseListSingle { $DisableCoverage$- ListBuilder<Int,ForwardNode<Int>> builder <- ForwardNode<Int>.builder()+ ListBuilder<Int, ForwardNode<Int>> builder <- ForwardNode<Int>.builder() Vector<Int> expected <- Vector<Int>.new() Int size <- 101 $ReadOnly[size]$@@ -238,15 +238,15 @@ optional ForwardNode<Int> reversed <- Sorting:reverseList(builder.build(){0}) traverse (expected.defaultOrder() -> Int value) {- \ Testing.checkEquals(require(reversed).get(),value)+ \ require(reversed).get() `Matches:with` CheckValue:equals(value) } update { reversed <- require(reversed).next() }- \ Testing.checkFalse(present(reversed))+ \ present(reversed) `Matches:with` CheckValue:equals(false) } unittest reverseListEmpty {- \ Sorting:reverseList<LinkedNode<Int>,Int>(empty)+ \ Sorting:reverseList<LinkedNode<Int>, Int>(empty) } concrete TestSequence {@@ -267,7 +267,7 @@ } formatted () {- [Append<Formatted>&Build<String>] builder <- String.builder()+ [Append<Formatted> & Build<String>] builder <- String.builder() \ builder.append("{") traverse (seq.defaultOrder() -> Formatted x) { \ builder.append(" ").append(x)@@ -283,8 +283,8 @@ return seq.readAt(i) } - writeAt (i,x) {- \ seq.writeAt(i,x)+ writeAt (i, x) {+ \ seq.writeAt(i, x) return self } @@ -293,7 +293,7 @@ return self } - equals (x,y) {+ equals (x, y) { return x `ReadAtH:equals` y } }
+ lib/container/test/testing.0rt view
@@ -0,0 +1,257 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CheckSet equality success" {+ success TestChecker+}++unittest equals {+ SortedSet<Int> actual <- SortedSet<Int>.new().append(1).append(2).append(3)+ SortedSet<Int> expected <- SortedSet<Int>.new().append(1).append(2).append(3)+ \ actual `Matches:with` CheckSet:equals(expected)+}+++testcase "CheckSet:equals different" {+ failure TestChecker+ require "\"10\""+ require "\"20\""+ require "\"30\""+ require "\"40\""+ require "\"50\""+ require "\"60\""+}++unittest test {+ SortedSet<Int> actual <- SortedSet<Int>.new().append(10).append(20).append(30)+ SortedSet<Int> expected <- SortedSet<Int>.new().append(40).append(50).append(60)+ \ actual `Matches:with` CheckSet:equals(expected)+}+++testcase "CheckSet:equals extra" {+ failure TestChecker+ require "\"40\""+ exclude "\"10\""+ exclude "\"20\""+ exclude "\"30\""+}++unittest test {+ SortedSet<Int> actual <- SortedSet<Int>.new().append(10).append(20).append(30).append(40)+ SortedSet<Int> expected <- SortedSet<Int>.new().append(10).append(20).append(30)+ \ actual `Matches:with` CheckSet:equals(expected)+}+++testcase "CheckSet:equals missing" {+ failure TestChecker+ require "\"40\""+ exclude "\"10\""+ exclude "\"20\""+ exclude "\"30\""+}++unittest test {+ SortedSet<Int> actual <- SortedSet<Int>.new().append(10).append(20).append(30)+ SortedSet<Int> expected <- SortedSet<Int>.new().append(10).append(20).append(30).append(40)+ \ actual `Matches:with` CheckSet:equals(expected)+}+++testcase "CheckMap equality success" {+ success TestChecker+}++unittest equals {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ HashedMap<String, Int> expected <- HashedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ \ actual `Matches:with` CheckMap:equals(expected)+}+++testcase "CheckMap:equals different" {+ failure TestChecker+ require "two"+ require "2900.+2"+ require "three"+ require "3.+3900"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2900)+ .set("three", 3)+ HashedMap<String, Int> expected <- HashedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3900)+ \ actual `Matches:with` CheckMap:equals(expected)+}+++testcase "CheckMap:equals extra" {+ failure TestChecker+ require "zero"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ HashedMap<String, Int> expected <- HashedMap<String, Int>.new()+ .set("zero", 0)+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ \ actual `Matches:with` CheckMap:equals(expected)+}+++testcase "CheckMap:equals missing" {+ failure TestChecker+ require "four"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ .set("four", 4)+ HashedMap<String, Int> expected <- HashedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ \ actual `Matches:with` CheckMap:equals(expected)+}+++testcase "CheckMap equality success" {+ success TestChecker+}++unittest matches {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ HashedMap<String, ValueMatcher<Int>> expected <- HashedMap<String, ValueMatcher<Int>>.new()+ .set("one", CheckValue:equals(1))+ .set("two", CheckValue:equals(2))+ .set("three", CheckValue:equals(3))+ \ actual `Matches:with` CheckMap:matches(expected)+}+++testcase "CheckMap:matches different" {+ failure TestChecker+ require "two"+ require "2900.+2"+ require "three"+ require "3.+3900"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2900)+ .set("three", 3)+ HashedMap<String, ValueMatcher<Int>> expected <- HashedMap<String, ValueMatcher<Int>>.new()+ .set("one", CheckValue:equals(1))+ .set("two", CheckValue:equals(2))+ .set("three", CheckValue:equals(3900))+ \ actual `Matches:with` CheckMap:matches(expected)+}+++testcase "CheckMap:matches extra" {+ failure TestChecker+ require "zero"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ HashedMap<String, ValueMatcher<Int>> expected <- HashedMap<String, ValueMatcher<Int>>.new()+ .set("zero", CheckValue:equals(0))+ .set("one", CheckValue:equals(1))+ .set("two", CheckValue:equals(2))+ .set("three", CheckValue:equals(3))+ \ actual `Matches:with` CheckMap:matches(expected)+}+++testcase "CheckMap:matches missing" {+ failure TestChecker+ require "four"+}++unittest test {+ SortedMap<String, Int> actual <- SortedMap<String, Int>.new()+ .set("one", 1)+ .set("two", 2)+ .set("three", 3)+ .set("four", 4)+ HashedMap<String, ValueMatcher<Int>> expected <- HashedMap<String, ValueMatcher<Int>>.new()+ .set("one", CheckValue:equals(1))+ .set("two", CheckValue:equals(2))+ .set("three", CheckValue:equals(3))+ \ actual `Matches:with` CheckMap:matches(expected)+}+++testcase "CheckMap:using success" {+ success TestChecker+}++unittest test {+ SortedMap<String, TestValue> actual <- SortedMap<String, TestValue>.new()+ .set("one", TestValue.new("one"))+ .set("two", TestValue.new("two"))+ SortedMap<String, TestValue> expected <- SortedMap<String, TestValue>.new()+ .set("one", TestValue.new("one"))+ .set("two", TestValue.new("two"))+ \ actual `Matches:with` CheckMap:matches(CheckMap:using(expected))+}+++testcase "CheckMap:using failure" {+ failure TestChecker+ require "TWO.+two"+}++unittest test {+ SortedMap<String, TestValue> actual <- SortedMap<String, TestValue>.new()+ .set("one", TestValue.new("one"))+ .set("two", TestValue.new("TWO"))+ SortedMap<String, TestValue> expected <- SortedMap<String, TestValue>.new()+ .set("one", TestValue.new("one"))+ .set("two", TestValue.new("two"))+ \ actual `Matches:with` CheckMap:matches(CheckMap:using(expected))+}
lib/container/test/type-map.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "TypeMap tests" {- success+ success TestChecker } unittest basicOperations {@@ -27,21 +27,21 @@ TypeKey<String> keyString <- TypeKey<String>.new() TypeKey<Value> keyValue <- TypeKey<Value>.new() - \ Testing.checkOptional(map.get(keyInt), empty)- \ Testing.checkOptional(map.get(keyString),empty)- \ Testing.checkOptional(map.get(keyValue), empty)+ \ map.get(keyInt) `Matches:with` CheckValue:equals(empty?Int)+ \ map.get(keyString) `Matches:with` CheckValue:equals(empty?String)+ \ map.get(keyValue) `Matches:with` CheckValue:equals(empty?Value) - \ map.set(keyInt,1)- \ map.set(keyString,"a")- \ map.set(keyValue,Value.new())+ \ map.set(keyInt, 1)+ \ map.set(keyString, "a")+ \ map.set(keyValue, Value.new()) - \ Testing.checkOptional(map.get(keyInt), 1)- \ Testing.checkOptional(map.get(keyString),"a")- \ Testing.checkOptional(map.get(keyValue), Value.new())+ \ map.get(keyInt) `Matches:with` CheckValue:equals( 1)+ \ map.get(keyString) `Matches:with` CheckValue:equals("a")+ \ map.get(keyValue) `Matches:with` CheckValue:equals( Value.new()) \ map.remove(keyString) - \ Testing.checkOptional(map.get(keyString),empty)+ \ map.get(keyString) `Matches:with` CheckValue:equals(empty?String) } unittest wrongReturnType {@@ -50,56 +50,57 @@ TypeKey<String> keyString <- TypeKey<String>.new() // Added as Formatted, which means it cannot be retrieved as String later.- \ map.set<Formatted>(keyString,"a")- \ Testing.checkOptional(map.get<String>(keyString),empty)+ \ map.set<Formatted>(keyString, "a")+ \ map.get<String>(keyString) `Matches:with` CheckValue:equals(empty?String) - \ map.set<String>(keyString,"a")- \ Testing.checkOptional(map.get<String>(keyString),"a")+ \ map.set<String>(keyString, "a")+ \ map.get<String>(keyString) `Matches:with` CheckValue:equals("a") } unittest duplicate { TypeKey<Int> keyInt <- TypeKey<Int>.new() TypeKey<String> keyString <- TypeKey<String>.new() - TypeMap map <- TypeMap.new().set(keyInt,1).set(keyString,"a")+ TypeMap map <- TypeMap.new().set(keyInt, 1).set(keyString, "a") TypeMap copy <- map.duplicate()- \ Testing.checkOptional(copy.get(keyInt),1)- \ Testing.checkOptional(copy.get(keyString),"a")+ \ copy.get(keyInt) `Matches:with` CheckValue:equals(1)+ \ copy.get(keyString) `Matches:with` CheckValue:equals("a") \ copy.remove(keyString)- \ Testing.checkOptional(copy.get(keyInt),1)- \ Testing.checkOptional(copy.get(keyString),empty)- \ Testing.checkOptional(map.get(keyString),"a")+ \ copy.get(keyInt) `Matches:with` CheckValue:equals(1)+ \ copy.get(keyString) `Matches:with` CheckValue:equals(empty?String)+ \ map.get(keyString) `Matches:with` CheckValue:equals("a") } unittest getValues { TypeMap map <- TypeMap.new()- .set(TypeKey<String>.new(),"one")- .set(TypeKey<Int>.new(),2)- .set(TypeKey<String>.new(),"two")- .set(TypeKey<Int>.new(),1)+ .set(TypeKey<String>.new(), "one")+ .set(TypeKey<Int>.new(), 2)+ .set(TypeKey<String>.new(), "two")+ .set(TypeKey<Int>.new(), 1) - [Container&SetReader<String>] actual <- map.getAll(SortedSet<String>.new())+ [Container & SetReader<String>] actual <- map.getAll(SortedSet<String>.new()) - \ Testing.checkEquals(actual.size(),2)- \ Testing.checkTrue(actual.member("one"))- \ Testing.checkTrue(actual.member("two"))+ \ actual.size() `Matches:with` CheckValue:equals(2)+ \ actual.member("one") `Matches:with` CheckValue:equals(true)+ \ actual.member("two") `Matches:with` CheckValue:equals(true) } unittest keyEquals { TypeKey<Int> key1 <- TypeKey<Int>.new() TypeKey<Int> key2 <- TypeKey<Int>.new() TypeKey<String> key3 <- TypeKey<String>.new()- \ Testing.checkEquals<TypeKey<Int>>(key1,key1)- \ Testing.checkFalse(key1 `TypeKey<any>.equals` key2)- \ Testing.checkFalse(key1 `TypeKey<any>.equals` key3)+ \ key1 `Matches:with` CheckValue:equals(key1)+ \ (key1 `TypeKey<any>.equals` key2) `Matches:with` CheckValue:equals(false)+ \ (key1 `TypeKey<any>.equals` key2) `Matches:with` CheckValue:equals(false)+ \ (key1 `TypeKey<any>.equals` key3) `Matches:with` CheckValue:equals(false) } unittest keyHashed { TypeKey<Int> key1 <- TypeKey<Int>.new() TypeKey<Int> key2 <- TypeKey<Int>.new()- \ Testing.checkNotEquals(key1.hashed(),key2.hashed())+ \ key1.hashed() `Matches:with` CheckValue:notEquals(key2.hashed()) } concrete Value {@@ -118,15 +119,15 @@ return "Value" } - equals (_,_) {+ equals (_, _) { return true } } testcase "TypeKey formatted" {- crash- require "TypeKey<Int>\{[0-9]+\}"+ failure+ require "TypeKey<Int>\{[0-9a-fA-F]+\}" } unittest test {
lib/container/test/vector.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,17 +17,17 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "Vector tests" {- success+ success TestChecker } unittest createSize { Vector<Int> values <- Vector:createSize<Int>(10)- \ Testing.checkEquals(values.size(),10)+ \ values.size() `Matches:with` CheckValue:equals(10) scoped { Int i <- 0 } in while (i < values.size()) {- \ Testing.checkEquals(values.readAt(i),Int.default())+ \ values.readAt(i) `Matches:with` CheckValue:equals(Int.default()) } update { i <- i+1 }@@ -40,16 +40,16 @@ Int i <- 0 } in while (i < 10) { \ values.append(i)- \ Testing.checkEquals(values.size(),i+1)+ \ values.size() `Matches:with` CheckValue:equals(i+1) } update { i <- i+1 }- \ Testing.checkEquals(values.size(),10)+ \ values.size() `Matches:with` CheckValue:equals(10) scoped { Int i <- 0 } in while (i < values.size()) {- \ Testing.checkEquals(values.readAt(i),i)+ \ values.readAt(i) `Matches:with` CheckValue:equals(i) } update { i <- i+1 }@@ -62,21 +62,21 @@ Int i <- 0 } in while (i < 10) { \ values.push(i)- \ Testing.checkEquals(values.size(),i+1)+ \ values.size() `Matches:with` CheckValue:equals(i+1) } update { i <- i+1 }- \ Testing.checkEquals(values.size(),10)+ \ values.size() `Matches:with` CheckValue:equals(10) scoped { Int i <- 0 } in while (i < 10) {- \ Testing.checkEquals(values.pop(),10-i-1)- \ Testing.checkEquals(values.size(),10-i-1)+ \ values.pop() `Matches:with` CheckValue:equals(10-i-1)+ \ values.size() `Matches:with` CheckValue:equals(10-i-1) } update { i <- i+1 }- \ Testing.checkEquals(values.size(),0)+ \ values.size() `Matches:with` CheckValue:equals(0) } unittest writeAt {@@ -85,7 +85,7 @@ scoped { Int i <- 0 } in while (i < values.size()) {- \ values.writeAt(i,2*i)+ \ values.writeAt(i, 2*i) } update { i <- i+1 }@@ -93,7 +93,7 @@ scoped { Int i <- 0 } in while (i < values.size()) {- \ Testing.checkEquals(values.readAt(i),2*i)+ \ values.readAt(i) `Matches:with` CheckValue:equals(2*i) } update { i <- i+1 }@@ -110,26 +110,26 @@ \ vector.push(1) traverse (vector.defaultOrder() -> Int i) {- \ Testing.checkEquals(i,vector.readAt(index))+ \ i `Matches:with` CheckValue:equals(vector.readAt(index)) index <- index+1 } - \ Testing.checkEquals(index,6)+ \ index `Matches:with` CheckValue:equals(6) } unittest duplicate { Vector<Int> vector <- Vector<Int>.default().push(1).push(2) Vector<Int> copy <- vector.duplicate()- \ Testing.checkEquals(copy.size(),2)- \ Testing.checkEquals(copy.readAt(0),1)- \ Testing.checkEquals(copy.readAt(1),2)+ \ copy.size() `Matches:with` CheckValue:equals(2)+ \ copy.readAt(0) `Matches:with` CheckValue:equals(1)+ \ copy.readAt(1) `Matches:with` CheckValue:equals(2) - \ copy.writeAt(1,3)+ \ copy.writeAt(1, 3) \ copy.pop()- \ Testing.checkEquals(copy.size(),1)- \ Testing.checkEquals(copy.readAt(0),1)- \ Testing.checkEquals(vector.readAt(1),2)+ \ copy.size() `Matches:with` CheckValue:equals(1)+ \ copy.readAt(0) `Matches:with` CheckValue:equals(1)+ \ vector.readAt(1) `Matches:with` CheckValue:equals(2) } concrete Value {@@ -151,20 +151,20 @@ testcase "distinct default values in pre-sized Vector" {- success+ success TestChecker } unittest test { Vector<Type> values <- Vector:createSize<Type>(10) \ values.readAt(3).set(7) - \ Testing.checkEquals(values.readAt(3),Type.create(7))+ \ values.readAt(3) `Matches:with` CheckValue:equals(Type.create(7)) scoped { Int i <- 0 } in while (i < values.size()) { if (i != 3) {- \ Testing.checkEquals(values.readAt(i),Type.create(0))+ \ values.readAt(i) `Matches:with` CheckValue:equals(Type.create(0)) } } update { i <- i+1@@ -195,7 +195,7 @@ return value.formatted() } - equals (x,y) {+ equals (x, y) { return x.get() == y.get() } @@ -211,7 +211,7 @@ testcase "negative Vector index" {- crash+ failure } unittest test {@@ -221,7 +221,7 @@ testcase "Vector index out of bounds" {- crash+ failure } unittest test {
+ lib/container/testing.0rp view
@@ -0,0 +1,39 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++concrete CheckSet {+ @category equals<#k>+ #k requires Formatted+ ([SetReader<#k> & DefaultOrder<#k>]) -> (ValueMatcher<[SetReader<#k> & DefaultOrder<#k>]>)+}++concrete CheckMap {+ @category using<#k, #v>+ #v requires TestCompare<#v>+ ([SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>]) -> ([SetReader<#k> & DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>])++ @category equals<#k, #v>+ #k requires Formatted+ #v requires Formatted+ #v defines Equals<#v>+ ([SetReader<#k> & DefaultOrder<KeyValue<#k, #v>>]) -> (ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>)++ @category matches<#k, #v>+ #k requires Formatted+ ([SetReader<#k> & DefaultOrder<KeyValue<#k, ValueMatcher<#v>>>]) -> (ValueMatcher<[KVReader<#k, #v> & KeyOrder<#k>]>)+}
lib/container/type-map.0rp view
@@ -28,7 +28,7 @@ // // Params: // - #x: The value type being stored.- @value set<#x> (TypeKey<#x>,#x) -> (TypeMap)+ @value set<#x> (TypeKey<#x>, #x) -> (TypeMap) // Remove the value associated with the key if present and return self. @value remove (TypeKey<any>) -> (TypeMap)@@ -47,7 +47,7 @@ @value get<#x> (TypeKey<#x>) -> (optional #x) // Get all values of type #x.- @value getAll<#c,#x>+ @value getAll<#c, #x> #c requires Append<#x> (#c) -> (#c) }
lib/file/.zeolite-module view
@@ -20,4 +20,4 @@ categories: [RawFileWriter] } ]-mode: incremental {}+mode: incremental { }
lib/file/test/tests.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "read and write" {- success+ success TestChecker } unittest readWrite {@@ -28,12 +28,12 @@ } cleanup { \ writer.freeResource() } in {- \ Testing.checkEmpty(writer.getFileError())+ \ present(writer.getFileError()) `Matches:with` CheckValue:equals(false) Int writeSize <- writer.writeBlock(data) if (writeSize != data.size()) { fail(writeSize) }- \ Testing.checkEmpty(writer.getFileError())+ \ present(writer.getFileError()) `Matches:with` CheckValue:equals(false) } scoped {@@ -41,7 +41,7 @@ } cleanup { \ reader.freeResource() } in {- \ Testing.checkEmpty(reader.getFileError())+ \ present(reader.getFileError()) `Matches:with` CheckValue:equals(false) scoped { String data2 <- reader.readBlock(8)@@ -53,7 +53,7 @@ } in if (data2 != "some\x00data") { fail("\"" + data2 + "\"") }- \ Testing.checkEmpty(reader.getFileError())+ \ present(reader.getFileError()) `Matches:with` CheckValue:equals(false) if (!reader.pastEnd()) { fail("more data in file")@@ -70,7 +70,7 @@ \ writer.freeResource() } in \ writer.writeBlock(data) - \ Testing.checkEquals(FileTesting.forceReadFile("testfile"),data)+ \ FileTesting.forceReadFile("testfile") `Matches:with` CheckValue:equals(data) } unittest readEmpty {@@ -81,7 +81,7 @@ if (data != "") { fail("\"" + data + "\"") }- \ Testing.checkEmpty(reader.getFileError())+ \ present(reader.getFileError()) `Matches:with` CheckValue:equals(false) if (!reader.pastEnd()) { fail("more data in file") }@@ -89,18 +89,18 @@ unittest readMissing { RawFileReader reader <- RawFileReader.open("do-not-create-this-file")- \ Testing.checkPresent(reader.getFileError())+ \ present(reader.getFileError()) `Matches:with` CheckValue:equals(true) } unittest unwritable { RawFileWriter writer <- RawFileWriter.open("testfile") \ writer.freeResource()- \ Testing.checkPresent(writer.getFileError())+ \ present(writer.getFileError()) `Matches:with` CheckValue:equals(true) } testcase "read missing file crash" {- crash+ failure require "do-not-create-this-file" require "RawFileReader .*creation" }@@ -112,7 +112,7 @@ testcase "unwritable file crash" {- crash+ failure require "testfile" require "RawFileWriter .*creation" }
lib/math/.zeolite-module view
@@ -29,4 +29,4 @@ categories: [RandomUniform] } ]-mode: incremental {}+mode: incremental { }
lib/math/categorical-tree.0rp view
@@ -33,11 +33,11 @@ // Return the value at the given offset. // // Notes:- // - The offset must be within [0,getTotal()). A uniform selection in that+ // - The offset must be within [0, getTotal()). A uniform selection in that // range will provide samples that follow the categorical distribution // corresponding to the relative weights of the respective #c. // - The return value is deterministic. If you were to iterate over- // [0,getTotal()), you'd get an increasing sequence of all #c in the+ // [0, getTotal()), you'd get an increasing sequence of all #c in the // CategoricalReader, each repeated the number of times indicated by its // respective weight. // - Also see RandomCategorical in random.0rp.@@ -74,7 +74,7 @@ // Notes: // - The weight must not be negative. // - The sum of all weights (see getTotal()) must not exceed Int.maxBound().- @value setWeight (#c,Int) -> (#self)+ @value setWeight (#c, Int) -> (#self) // Increments the weight of the value by 1. @value incrWeight (#c) -> (#self)
lib/math/math.0rp view
@@ -36,12 +36,12 @@ @type log (Float) -> (Float) @type log10 (Float) -> (Float) @type log2 (Float) -> (Float)- @type pow (Float,Float) -> (Float)+ @type pow (Float, Float) -> (Float) @type sqrt (Float) -> (Float) @type ceil (Float) -> (Float) @type floor (Float) -> (Float)- @type fmod (Float,Float) -> (Float)+ @type fmod (Float, Float) -> (Float) @type trunc (Float) -> (Float) @type round (Float) -> (Float) @type fabs (Float) -> (Float)
lib/math/random.0rp view
@@ -37,7 +37,7 @@ refines Generator<Float> // Creates a new generator with the specified mean and standard deviation.- @type new (Float,Float) -> (#self)+ @type new (Float, Float) -> (#self) // Resets the seed for RNG. @value setSeed (Int) -> (#self)@@ -48,9 +48,9 @@ refines Generator<Float> // Creates a new generator with the specified min and max values.- @type new (Float,Float) -> (#self)+ @type new (Float, Float) -> (#self) - // Creates a new generator for the range [0.0,1.0).+ // Creates a new generator for the range [0.0, 1.0). @type probability () -> (#self) // Resets the seed for RNG.@@ -72,10 +72,10 @@ // Creates a generator for the provided distribution. // // Notes:- // - The Generator<Float> *must* return values in the range [0,1).+ // - The Generator<Float> *must* return values in the range [0, 1). // - The distribution is not copied; therefore, changes to the distribution // will affect the returned generator.- @category sampleWith<#c> (CategoricalReader<#c>,Generator<Float>) -> (RandomCategorical<#c>)+ @category sampleWith<#c> (CategoricalReader<#c>, Generator<Float>) -> (RandomCategorical<#c>) // Returns true if the distribution is empty. //@@ -93,9 +93,9 @@ // 2. Samples from the copy *without* replacement until the tree is empty. // // Notes:- // - The Generator must only return values in [0,1).+ // - The Generator must only return values in [0, 1). // - If category c has a weight of n, it will occur n times in the output.- @category permuteFrom<#c> (CategoricalTree<#c>,Generator<Float>,Append<#c>) -> ()+ @category permuteFrom<#c> (CategoricalTree<#c>, Generator<Float>, Append<#c>) -> () // Creates a permutation from the CategoricalTree. //@@ -103,8 +103,8 @@ // 2. Samples from the copy *without* replacement until the tree is empty. // // Notes:- // - The Generator must only return values in [0,1).+ // - The Generator must only return values in [0, 1). // - If category c has a weight of n, it will occur *once* in the output, but // it will have a relative chance of n to be chosen ahead of others.- @category permuteFromWeight<#c> (CategoricalTree<#c>,Generator<Float>,Append<#c>) -> ()+ @category permuteFromWeight<#c> (CategoricalTree<#c>, Generator<Float>, Append<#c>) -> () }
lib/math/src/categorical-tree.0rx view
@@ -17,14 +17,14 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define CategoricalTree {- @value AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>> tree+ @value AutoBinaryTree<CategoricalTreeNode<#c>, #c, Int, CategoricalSearch<#c>> tree default () { return new() } new () {- return #self{ AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>>.new() }+ return #self{ AutoBinaryTree<CategoricalTreeNode<#c>, #c, Int, CategoricalSearch<#c>>.new() } } duplicate () {@@ -35,13 +35,13 @@ return CategoricalTreeNode<#c>.tryTotal(tree.getRoot()) } - setWeight (cat,size) {+ setWeight (cat, size) { if (size < 0) { fail("size must not be negative") } elif (size > 0) {- \ tree.swap(cat,size)+ \ tree.swap(cat, size) } else {- \ tree.swap(cat,empty)+ \ tree.swap(cat, empty) } return self }@@ -57,12 +57,12 @@ } incrWeight (cat) {- \ setWeight(cat,getWeight(cat)+1)+ \ setWeight(cat, getWeight(cat)+1) return self } decrWeight (cat) {- \ setWeight(cat,getWeight(cat)-1)+ \ setWeight(cat, getWeight(cat)-1) return self } @@ -72,7 +72,7 @@ } elif (pos >= getTotal()) { fail("position must be strictly less than the total") } else {- return require(CategoricalTreeNode<#c>.findPosition(pos,tree.getRoot()))+ return require(CategoricalTreeNode<#c>.findPosition(pos, tree.getRoot())) } } @@ -86,23 +86,23 @@ } define ValidatedTree {- @value AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>> tree+ @value AutoBinaryTree<CategoricalTreeNode<#c>, #c, Int, CategoricalSearch<#c>> tree new () { $NoTrace$- return #self{ AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>>.new() }+ return #self{ AutoBinaryTree<CategoricalTreeNode<#c>, #c, Int, CategoricalSearch<#c>>.new() } } getTotal () { $NoTrace$ return CategoricalTreeNode<#c>.tryTotal(tree.getRoot()) } - setWeight (cat,size) { $NoTrace$+ setWeight (cat, size) { $NoTrace$ if (size < 0) { fail("size must not be negative") } elif (size > 0) {- \ tree.swap(cat,size)+ \ tree.swap(cat, size) } else {- \ tree.swap(cat,empty)+ \ tree.swap(cat, empty) } \ validateTotal(tree.getRoot()) return self@@ -124,7 +124,7 @@ } elif (pos >= getTotal()) { fail("position must be strictly less than the total") } else {- return require(CategoricalTreeNode<#c>.findPosition(pos,tree.getRoot()))+ return require(CategoricalTreeNode<#c>.findPosition(pos, tree.getRoot())) } } @@ -154,18 +154,18 @@ } @value interface CategoricalSearch<|#c> {- refines BinaryTreeNode<#c,Int>+ refines BinaryTreeNode<#c, Int> getTotal () -> (Int) } concrete CategoricalTreeNode<#c> {- defines KVFactory<#c,Int>+ defines KVFactory<#c, Int> refines CategoricalSearch<#c>- refines BalancedTreeNode<CategoricalTreeNode<#c>,#c,Int>+ refines BalancedTreeNode<CategoricalTreeNode<#c>, #c, Int> refines Duplicate - @type findPosition (Int,optional CategoricalSearch<#c>) -> (optional #c)+ @type findPosition (Int, optional CategoricalSearch<#c>) -> (optional #c) @type tryTotal (optional CategoricalSearch<#c>) -> (Int) @value getTotal () -> (Int)@@ -193,7 +193,7 @@ return #self{ height, key, size, total, lower2, higher2 } } - findPosition (pos,node) (cat) {+ findPosition (pos, node) (cat) { cat <- empty if (present(node)) { scoped {@@ -202,11 +202,11 @@ CategoricalSearch<#c> node2 <- require(node) Int lower <- tryTotal(node2.getLower()) Int size <- node2.getValue()- $ReadOnly[node2,lower,size]$+ $ReadOnly[node2, lower, size]$ } in if (pos2 < node2.getTotal()) { if (pos2 < lower) { // pos2 is in the 1st (lower) of the 3 sections.- return findPosition(pos2,node2.getLower())+ return findPosition(pos2, node2.getLower()) } pos2 <- pos2-lower if (pos2 < size) {@@ -215,7 +215,7 @@ } pos2 <- pos2-size // pos2 is in the 3rd (higher) of the 3 sections.- return findPosition(pos2,node2.getHigher())+ return findPosition(pos2, node2.getHigher()) } } }@@ -228,7 +228,7 @@ } } - newNode (k,v) {+ newNode (k, v) { return #self{ 1, k, v, v, empty, empty } }
lib/math/src/random.0rx view
@@ -17,10 +17,10 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define Randomize {- permuteFrom (tree,random,output) {+ permuteFrom (tree, random, output) { CategoricalTree<#c> copy <- tree.duplicate() Generator<#c> generator <- copy `RandomCategorical:sampleWith` random- $Hidden[tree,random]$+ $Hidden[tree, random]$ while (copy.getTotal() > 0) { #c cat <- generator.generate() \ output.append(cat)@@ -28,14 +28,14 @@ } } - permuteFromWeight (tree,random,output) {+ permuteFromWeight (tree, random, output) { CategoricalTree<#c> copy <- tree.duplicate() Generator<#c> generator <- copy `RandomCategorical:sampleWith` random- $Hidden[tree,random]$+ $Hidden[tree, random]$ while (copy.getTotal() > 0) { #c cat <- generator.generate() \ output.append(cat)- \ copy.setWeight(cat,0)+ \ copy.setWeight(cat, 0) } } }@@ -46,7 +46,7 @@ @value Float constant new (constant) {- return GenerateConstant{ constant }+ return delegate -> #self } generate () {@@ -60,8 +60,8 @@ @value CategoricalReader<#c> categorical @value Generator<Float> random - sampleWith (categorical,random) {- return RandomCategorical<#c>{ categorical, random }+ sampleWith (categorical, random) {+ return delegate -> RandomCategorical<#c> } generate () {
lib/math/src/token.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,14 +17,12 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define Token {- $ReadOnlyExcept[counter]$+ $ReadOnlyExcept[]$ @category Mutex mutex <- SpinlockMutex.new()- @category HashedMap<String,Token> toToken <- HashedMap<String,Token>.new()- @category Int counter <- 0+ @category HashedMap<String, Token> toToken <- HashedMap<String, Token>.new() @value String string- @value Int value from (string) (token) { scoped {@@ -32,10 +30,10 @@ optional Token existing <- toToken.get(string) } cleanup { \ mutex.unlock()- } in if (present(existing)) {- return require(existing)+ } in if (`present` existing) {+ token <- `require` existing } else {- \ toToken.set(string,(token <- Token{ string, (counter <- counter+1) }))+ \ string `toToken.set` (token <- Token{ string }) } } @@ -44,17 +42,14 @@ } hashed () {- return value.hashed()+ return identify(self).hashed() } - equals (x,y) {- return x.get() == y.get()+ equals (x, y) {+ return identify(x) == identify(y) } - lessThan (x,y) {- return x.get() < y.get()+ lessThan (x, y) {+ return identify(x) < identify(y) }-- @value get () -> (Int)- get () { return value } }
lib/math/src/validated-tree.0rp view
@@ -31,7 +31,7 @@ @type new () -> (#self) @value getTotal () -> (Int)- @value setWeight (#c,Int) -> (#self)+ @value setWeight (#c, Int) -> (#self) @value getWeight (#c) -> (Int) @value locate (Int) -> (#c) }
lib/math/test/categorical-tree.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,17 +17,17 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "CategoricalTree tests" {- success+ success TestChecker } unittest simpleInsertion { CategoricalTree<Int> tree <- CategoricalTree<Int>.default()- .setWeight(1,3)- .setWeight(6,2)- .setWeight(3,1)- .setWeight(5,4)- .setWeight(4,3)- .setWeight(2,7)+ .setWeight(1, 3)+ .setWeight(6, 2)+ .setWeight(3, 1)+ .setWeight(5, 4)+ .setWeight(4, 3)+ .setWeight(2, 7) Vector<Int> expected <- Vector<Int>.new() .push(1).push(1).push(1)@@ -37,31 +37,31 @@ .push(5).push(5).push(5).push(5) .push(6).push(6) - \ Testing.checkEquals(tree.getTotal(),expected.size())- \ Testing.checkEquals(tree.getWeight(1),3)- \ Testing.checkEquals(tree.getWeight(2),7)- \ Testing.checkEquals(tree.getWeight(3),1)- \ Testing.checkEquals(tree.getWeight(4),3)- \ Testing.checkEquals(tree.getWeight(5),4)- \ Testing.checkEquals(tree.getWeight(6),2)+ \ tree.getTotal() `Matches:with` CheckValue:equals(expected.size())+ \ tree.getWeight(1) `Matches:with` CheckValue:equals(3)+ \ tree.getWeight(2) `Matches:with` CheckValue:equals(7)+ \ tree.getWeight(3) `Matches:with` CheckValue:equals(1)+ \ tree.getWeight(4) `Matches:with` CheckValue:equals(3)+ \ tree.getWeight(5) `Matches:with` CheckValue:equals(4)+ \ tree.getWeight(6) `Matches:with` CheckValue:equals(2) traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {- \ Testing.checkEquals(tree.locate(pos),expected.readAt(pos))+ \ tree.locate(pos) `Matches:with` CheckValue:equals(expected.readAt(pos)) } } unittest modifySizes { CategoricalTree<Int> tree <- CategoricalTree<Int>.new()- .setWeight(1,3)- .setWeight(6,2)- .setWeight(3,1)- .setWeight(5,4)- .setWeight(4,3)- .setWeight(2,7)- .setWeight(7,3)+ .setWeight(1, 3)+ .setWeight(6, 2)+ .setWeight(3, 1)+ .setWeight(5, 4)+ .setWeight(4, 3)+ .setWeight(2, 7)+ .setWeight(7, 3) // modifications start here- .setWeight(5,1)- .setWeight(3,0)+ .setWeight(5, 1)+ .setWeight(3, 0) Vector<Int> expected <- Vector<Int>.new() .push(1).push(1).push(1)@@ -71,22 +71,22 @@ .push(6).push(6) .push(7).push(7).push(7) - \ Testing.checkEquals(tree.getTotal(),expected.size())- \ Testing.checkEquals(tree.getWeight(1),3)- \ Testing.checkEquals(tree.getWeight(2),7)- \ Testing.checkEquals(tree.getWeight(3),0)- \ Testing.checkEquals(tree.getWeight(4),3)- \ Testing.checkEquals(tree.getWeight(5),1)- \ Testing.checkEquals(tree.getWeight(6),2)- \ Testing.checkEquals(tree.getWeight(7),3)+ \ tree.getTotal() `Matches:with` CheckValue:equals(expected.size())+ \ tree.getWeight(1) `Matches:with` CheckValue:equals(3)+ \ tree.getWeight(2) `Matches:with` CheckValue:equals(7)+ \ tree.getWeight(3) `Matches:with` CheckValue:equals(0)+ \ tree.getWeight(4) `Matches:with` CheckValue:equals(3)+ \ tree.getWeight(5) `Matches:with` CheckValue:equals(1)+ \ tree.getWeight(6) `Matches:with` CheckValue:equals(2)+ \ tree.getWeight(7) `Matches:with` CheckValue:equals(3) traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {- \ Testing.checkEquals(tree.locate(pos),expected.readAt(pos))+ \ tree.locate(pos) `Matches:with` CheckValue:equals(expected.readAt(pos)) } // Use ReadAt aliases for the same functionality. traverse (Counter.zeroIndexed(tree.size()) -> Int pos) {- \ Testing.checkEquals(tree.readAt(pos),expected.readAt(pos))+ \ tree.readAt(pos) `Matches:with` CheckValue:equals(expected.readAt(pos)) } } @@ -96,59 +96,59 @@ .incrWeight(1) .incrWeight(1) - \ Testing.checkEquals(tree.getTotal(),3)- \ Testing.checkEquals(tree.getWeight(1),3)+ \ tree.getTotal() `Matches:with` CheckValue:equals(3)+ \ tree.getWeight(1) `Matches:with` CheckValue:equals(3) } unittest decrement { CategoricalTree<Int> tree <- CategoricalTree<Int>.new()- .setWeight(1,10)+ .setWeight(1, 10) .decrWeight(1) .decrWeight(1) .decrWeight(1) - \ Testing.checkEquals(tree.getTotal(),7)- \ Testing.checkEquals(tree.getWeight(1),7)+ \ tree.getTotal() `Matches:with` CheckValue:equals(7)+ \ tree.getWeight(1) `Matches:with` CheckValue:equals(7) } unittest duplicate {- CategoricalTree<Int> tree <- CategoricalTree<Int>.new().setWeight(1,1).setWeight(2,2)+ CategoricalTree<Int> tree <- CategoricalTree<Int>.new().setWeight(1, 1).setWeight(2, 2) CategoricalTree<Int> copy <- tree.duplicate()- \ Testing.checkEquals(copy.size(),3)- \ Testing.checkEquals(copy.getWeight(1),1)- \ Testing.checkEquals(copy.getWeight(2),2)+ \ copy.size() `Matches:with` CheckValue:equals(3)+ \ copy.getWeight(1) `Matches:with` CheckValue:equals(1)+ \ copy.getWeight(2) `Matches:with` CheckValue:equals(2) - \ copy.setWeight(2,0)- \ Testing.checkEquals(copy.size(),1)- \ Testing.checkEquals(copy.getWeight(1),1)- \ Testing.checkEquals(tree.getWeight(2),2)+ \ copy.setWeight(2, 0)+ \ copy.size() `Matches:with` CheckValue:equals(1)+ \ copy.getWeight(1) `Matches:with` CheckValue:equals(1)+ \ tree.getWeight(2) `Matches:with` CheckValue:equals(2) } unittest integrationTest { $DisableCoverage$ ValidatedTree<Int> tree <- ValidatedTree<Int>.new()- SortedMap<Int,Int> expected <- SortedMap<Int,Int>.new()+ SortedMap<Int, Int> expected <- SortedMap<Int, Int>.new() Int count <- 137 Int maxSize <- 15 Int hash1 <- 379 Int hash2 <- 457- $ReadOnly[count,maxSize,hash1,hash2]$+ $ReadOnly[count, maxSize, hash1, hash2]$ // Populate the tree with arbitrary data. traverse (Counter.zeroIndexed(count) -> Int i) {- \ tree.setWeight((i*hash1)%count,(i*hash2)%maxSize)+ \ tree.setWeight((i*hash1)%count, (i*hash2)%maxSize) } // Overwrite the tree with real data. traverse (Counter.zeroIndexed(count) -> Int i) { Int key <- (i*hash2)%count Int size <- (i*hash1)%maxSize- \ tree.setWeight(key,size)- \ expected.set(key,size)+ \ tree.setWeight(key, size)+ \ expected.set(key, size) } - optional Order<KeyValue<Int,Int>> node <- expected.defaultOrder()+ optional Order<KeyValue<Int, Int>> node <- expected.defaultOrder() Int key <- 0 Int remaining <- 0 traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {@@ -159,27 +159,27 @@ } $ReadOnly[key]$ $Hidden[node]$- \ Testing.checkEquals(tree.locate(pos),key)+ \ tree.locate(pos) `Matches:with` CheckValue:equals(key) remaining <- remaining-1 } - \ Testing.checkEmpty(node)- \ Testing.checkEquals(remaining,0)+ \ present(node) `Matches:with` CheckValue:equals(false)+ \ remaining `Matches:with` CheckValue:equals(0) } testcase "negative size crashes" {- crash+ failure require "size.+negative" } unittest test {- \ CategoricalTree<Int>.new().setWeight(0,-10)+ \ CategoricalTree<Int>.new().setWeight(0, -10) } testcase "negative position crashes" {- crash+ failure require "position.+negative" } @@ -189,10 +189,10 @@ testcase "position past end crashes" {- crash+ failure require "position.+total" } unittest test {- \ CategoricalTree<Int>.new().setWeight(0,1).locate(1)+ \ CategoricalTree<Int>.new().setWeight(0, 1).locate(1) }
lib/math/test/math.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,103 +17,103 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "sanity check all functions" {- success+ success TestChecker } unittest cos {- \ Testing.checkBetween(Math.cos(2.0),-0.42,-0.41)+ \ Math.cos(2.0) `Matches:with` CheckValue:betweenEquals(-0.42, -0.41) } unittest sin {- \ Testing.checkBetween(Math.sin(2.0),0.90,0.91)+ \ Math.sin(2.0) `Matches:with` CheckValue:betweenEquals(0.90, 0.91) } unittest tan {- \ Testing.checkBetween(Math.tan(2.0),-2.19,-2.18)+ \ Math.tan(2.0) `Matches:with` CheckValue:betweenEquals(-2.19, -2.18) } unittest acos {- \ Testing.checkBetween(Math.acos(0.5),1.04,1.05)+ \ Math.acos(0.5) `Matches:with` CheckValue:betweenEquals(1.04, 1.05) } unittest asin {- \ Testing.checkBetween(Math.asin(0.5),0.52,0.53)+ \ Math.asin(0.5) `Matches:with` CheckValue:betweenEquals(0.52, 0.53) } unittest atan {- \ Testing.checkBetween(Math.atan(0.5),0.46,0.47)+ \ Math.atan(0.5) `Matches:with` CheckValue:betweenEquals(0.46, 0.47) } unittest cosh {- \ Testing.checkBetween(Math.cosh(2.0),3.76,3.77)+ \ Math.cosh(2.0) `Matches:with` CheckValue:betweenEquals(3.76, 3.77) } unittest sinh {- \ Testing.checkBetween(Math.sinh(2.0),3.62,3.63)+ \ Math.sinh(2.0) `Matches:with` CheckValue:betweenEquals(3.62, 3.63) } unittest tanh {- \ Testing.checkBetween(Math.tanh(2.0),0.96,0.97)+ \ Math.tanh(2.0) `Matches:with` CheckValue:betweenEquals(0.96, 0.97) } unittest acosh {- \ Testing.checkBetween(Math.acosh(2.0),1.31,1.32)+ \ Math.acosh(2.0) `Matches:with` CheckValue:betweenEquals(1.31, 1.32) } unittest asinh {- \ Testing.checkBetween(Math.asinh(2.0),1.44,1.45)+ \ Math.asinh(2.0) `Matches:with` CheckValue:betweenEquals(1.44, 1.45) } unittest atanh {- \ Testing.checkBetween(Math.atanh(0.5),0.54,0.55)+ \ Math.atanh(0.5) `Matches:with` CheckValue:betweenEquals(0.54, 0.55) } unittest exp {- \ Testing.checkBetween(Math.exp(1.0),2.71,2.72)+ \ Math.exp(1.0) `Matches:with` CheckValue:betweenEquals(2.71, 2.72) } unittest log {- \ Testing.checkBetween(Math.log(9.0),2.19,2.20)+ \ Math.log(9.0) `Matches:with` CheckValue:betweenEquals(2.19, 2.20) } unittest log10 {- \ Testing.checkBetween(Math.log10(100.0),1.99,2.01)+ \ Math.log10(100.0) `Matches:with` CheckValue:betweenEquals(1.99, 2.01) } unittest log2 {- \ Testing.checkBetween(Math.log2(8.0),2.99,3.01)+ \ Math.log2(8.0) `Matches:with` CheckValue:betweenEquals(2.99, 3.01) } unittest pow {- \ Testing.checkBetween(Math.pow(2.0,3.0),7.99,8.01)+ \ Math.pow(2.0, 3.0) `Matches:with` CheckValue:betweenEquals(7.99, 8.01) } unittest sqrt {- \ Testing.checkBetween(Math.sqrt(4.0),1.99,2.01)+ \ Math.sqrt(4.0) `Matches:with` CheckValue:betweenEquals(1.99, 2.01) } unittest ceil {- \ Testing.checkBetween(Math.ceil(2.2),2.99,3.01)+ \ Math.ceil(2.2) `Matches:with` CheckValue:betweenEquals(2.99, 3.01) } unittest floor {- \ Testing.checkBetween(Math.floor(2.2),1.99,2.01)+ \ Math.floor(2.2) `Matches:with` CheckValue:betweenEquals(1.99, 2.01) } unittest fmod {- \ Testing.checkBetween(Math.fmod(7.0,4.0),2.99,3.01)+ \ Math.fmod(7.0, 4.0) `Matches:with` CheckValue:betweenEquals(2.99, 3.01) } unittest trunc {- \ Testing.checkBetween(Math.trunc(2.2),1.99,2.01)+ \ Math.trunc(2.2) `Matches:with` CheckValue:betweenEquals(1.99, 2.01) } unittest round {- \ Testing.checkBetween(Math.round(2.7),2.99,3.01)+ \ Math.round(2.7) `Matches:with` CheckValue:betweenEquals(2.99, 3.01) } unittest fabs {- \ Testing.checkBetween(Math.fabs(-10.0),9.99,10.01)+ \ Math.fabs(-10.0) `Matches:with` CheckValue:betweenEquals(9.99, 10.01) } unittest isinf {@@ -129,7 +129,7 @@ } unittest abs {- \ Testing.checkEquals(Math.abs(-10),10)- \ Testing.checkEquals(Math.abs(10),10)- \ Testing.checkEquals(Math.abs(0),0)+ \ Math.abs(-10) `Matches:with` CheckValue:equals(10)+ \ Math.abs(10) `Matches:with` CheckValue:equals(10)+ \ Math.abs(0) `Matches:with` CheckValue:equals(0) }
lib/math/test/random.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "valid instantiations" {- success+ success TestChecker } unittest exponential {@@ -26,12 +26,12 @@ } unittest gaussian {- Generator<Float> random <- RandomGaussian.new(0.0,1.0)+ Generator<Float> random <- RandomGaussian.new(0.0, 1.0) Float value <- random.generate() } unittest uniform {- Generator<Float> random <- RandomUniform.new(0.0,1.0)+ Generator<Float> random <- RandomUniform.new(0.0, 1.0) Float value <- random.generate() } @@ -47,19 +47,19 @@ unittest categorical { CategoricalTree<Float> tree <- CategoricalTree<Float>.new()- .setWeight(0.0,1)- .setWeight(1.0,1)- .setWeight(2.0,1)- .setWeight(3.0,1)- .setWeight(4.0,1)+ .setWeight(0.0, 1)+ .setWeight(1.0, 1)+ .setWeight(2.0, 1)+ .setWeight(3.0, 1)+ .setWeight(4.0, 1) RandomCategorical<Float> random <- tree `RandomCategorical:sampleWith` RandomUniform.probability()- \ Testing.checkFalse(random.isEmpty())+ \ random.isEmpty() `Matches:with` CheckValue:equals(false) Float value <- random.generate() } testcase "negative lambda in exponential" {- crash+ failure require "lambda" require "-1" }@@ -70,93 +70,93 @@ testcase "negative standard deviation in gaussian" {- crash+ failure require "standard deviation" require "-1" } unittest test {- Generator<Float> random <- RandomGaussian.new(0.0,-1.0)+ Generator<Float> random <- RandomGaussian.new(0.0, -1.0) } testcase "empty range in uniform" {- crash+ failure require "range" require "0,-1" } unittest test {- Generator<Float> random <- RandomUniform.new(0.0,-1.0)+ Generator<Float> random <- RandomUniform.new(0.0, -1.0) } testcase "sampling with empty CategoricalTree" {- crash+ failure TestChecker require "less than the total" } unittest categorical { CategoricalTree<Float> tree <- CategoricalTree<Float>.new() RandomCategorical<Float> random <- tree `RandomCategorical:sampleWith` RandomUniform.probability()- \ Testing.checkTrue(random.isEmpty())+ \ random.isEmpty() `Matches:with` CheckValue:equals(true) Float value <- random.generate() } testcase "distribution sanity checks" {- success+ success TestChecker } unittest exponential { $DisableCoverage$ Int count <- 10000 Float lambda <- 10.0- $ReadOnly[count,lambda]$+ $ReadOnly[count, lambda]$ Generator<Float> random <- RandomExponential.new(lambda) Float sum <- 0.0 traverse (Counter.zeroIndexed(count) -> _) { Float value <- random.generate()- \ Testing.checkGreaterThan(value,0.0)+ \ value `Matches:with` CheckValue:greaterThanNotEquals(0.0) sum <- sum+value } - \ Testing.checkBetween(sum/count.asFloat(),0.9/lambda,1.1/lambda)+ \ sum/count.asFloat() `Matches:with` CheckValue:betweenEquals(0.9/lambda, 1.1/lambda) } unittest gaussian { $DisableCoverage$ Int count <- 10000 Float mean <- 100.0 Float sd <- 1.0- $ReadOnly[count,mean,sd]$+ $ReadOnly[count, mean, sd]$ - Generator<Float> random <- RandomGaussian.new(mean,sd)+ Generator<Float> random <- RandomGaussian.new(mean, sd) Float sum <- 0.0 traverse (Counter.zeroIndexed(count) -> _) { sum <- sum+random.generate() } - \ Testing.checkBetween(sum/count.asFloat(),mean-0.1*sd,mean+0.1*sd)+ \ sum/count.asFloat() `Matches:with` CheckValue:betweenEquals(mean-0.1*sd, mean+0.1*sd) } unittest uniform { $DisableCoverage$ Int count <- 10000 Float min <- -11.0 Float max <- 5.0- $ReadOnly[count,min,max]$+ $ReadOnly[count, min, max]$ - Generator<Float> random <- RandomUniform.new(min,max)+ Generator<Float> random <- RandomUniform.new(min, max) Float sum <- 0.0 traverse (Counter.zeroIndexed(count) -> _) { Float value <- random.generate()- \ Testing.checkBetween(value,min,max)+ \ value `Matches:with` CheckValue:betweenEquals(min, max) sum <- sum+value } - \ Testing.checkBetween(sum/count.asFloat(),(min+max)/2.0-0.1*(max-min),(min+max)/2.0+0.1*(max-min))+ \ sum/count.asFloat() `Matches:with` CheckValue:betweenEquals((min+max)/2.0-0.1*(max-min), (min+max)/2.0+0.1*(max-min)) } unittest probability { $DisableCoverage$@@ -168,51 +168,51 @@ Float sum <- 0.0 traverse (Counter.zeroIndexed(count) -> _) { Float value <- random.generate()- \ Testing.checkBetween(value,0.0,1.0)+ \ value `Matches:with` CheckValue:betweenEquals(0.0, 1.0) sum <- sum+value } - \ Testing.checkBetween(sum/count.asFloat(),0.4,0.6)+ \ sum/count.asFloat() `Matches:with` CheckValue:betweenEquals(0.4, 0.6) } unittest constant { $DisableCoverage$ Int count <- 10000 Float constant <- 12345.0- $ReadOnly[count,constant]$+ $ReadOnly[count, constant]$ Generator<Float> random <- GenerateConstant.new(constant) traverse (Counter.zeroIndexed(count) -> _) { Float value <- random.generate()- \ Testing.checkEquals(constant,value)+ \ constant `Matches:with` CheckValue:equals(value) } } unittest categorical { $DisableCoverage$ Int count <- 10000 CategoricalTree<Float> tree <- CategoricalTree<Float>.new()- .setWeight(0.0,1)- .setWeight(1.0,1)- .setWeight(2.0,1)- .setWeight(3.0,1)- .setWeight(4.0,1)- $ReadOnly[count,tree]$+ .setWeight(0.0, 1)+ .setWeight(1.0, 1)+ .setWeight(2.0, 1)+ .setWeight(3.0, 1)+ .setWeight(4.0, 1)+ $ReadOnly[count, tree]$ Generator<Float> random <- tree `RandomCategorical:sampleWith` RandomUniform.probability() Float sum <- 0.0 traverse (Counter.zeroIndexed(count) -> _) { Float value <- random.generate()- \ Testing.checkBetween(value,0.0,4.0)+ \ value `Matches:with` CheckValue:betweenEquals(0.0, 4.0) sum <- sum+value } - \ Testing.checkBetween(sum/count.asFloat(),1.9,2.1)+ \ sum/count.asFloat() `Matches:with` CheckValue:betweenEquals(1.9, 2.1) } testcase "distribution seed checks" {- success+ success TestChecker } unittest exponential {@@ -229,18 +229,18 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkNotEquals(v1,v2)- \ Testing.checkNotEquals(v1,v3)- \ Testing.checkEquals(v3,v4)+ \ v1 `Matches:with` CheckValue:notEquals(v2)+ \ v1 `Matches:with` CheckValue:notEquals(v3)+ \ v3 `Matches:with` CheckValue:equals(v4) } unittest gaussian { Float mean <- 100.0 Float sd <- 1.0- $ReadOnly[mean,sd]$+ $ReadOnly[mean, sd]$ - RandomGaussian random1 <- RandomGaussian.new(mean,sd)- RandomGaussian random2 <- RandomGaussian.new(mean,sd)+ RandomGaussian random1 <- RandomGaussian.new(mean, sd)+ RandomGaussian random2 <- RandomGaussian.new(mean, sd) Float v1 <- random1.generate() Float v2 <- random2.generate()@@ -249,18 +249,18 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkNotEquals(v1,v2)- \ Testing.checkNotEquals(v1,v3)- \ Testing.checkEquals(v3,v4)+ \ v1 `Matches:with` CheckValue:notEquals(v2)+ \ v1 `Matches:with` CheckValue:notEquals(v3)+ \ v3 `Matches:with` CheckValue:equals(v4) } unittest uniform { Float min <- -11.0 Float max <- 5.0- $ReadOnly[min,max]$+ $ReadOnly[min, max]$ - RandomUniform random1 <- RandomUniform.new(min,max)- RandomUniform random2 <- RandomUniform.new(min,max)+ RandomUniform random1 <- RandomUniform.new(min, max)+ RandomUniform random2 <- RandomUniform.new(min, max) Float v1 <- random1.generate() Float v2 <- random2.generate()@@ -269,21 +269,21 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkNotEquals(v1,v2)- \ Testing.checkNotEquals(v1,v3)- \ Testing.checkEquals(v3,v4)+ \ v1 `Matches:with` CheckValue:notEquals(v2)+ \ v1 `Matches:with` CheckValue:notEquals(v3)+ \ v3 `Matches:with` CheckValue:equals(v4) } testcase "Randomize tests" {- success+ success TestChecker } unittest permuteFrom { CategoricalTree<String> tree <- CategoricalTree<String>.new()- .setWeight("a",2)- .setWeight("b",3)- .setWeight("c",1)+ .setWeight("a", 2)+ .setWeight("b", 3)+ .setWeight("c", 1) Vector<String> expected <- Vector<String>.new() .append("a")@@ -294,24 +294,24 @@ .append("c") Vector<String> output <- Vector<String>.new()- \ Randomize:permuteFrom(tree,RandomUniform.new(0.0,1.0),output)+ \ Randomize:permuteFrom(tree, RandomUniform.new(0.0, 1.0), output) \ Sorting:sort(output) - \ Testing.checkEquals(output.size(),expected.size())+ \ output.size() `Matches:with` CheckValue:equals(expected.size()) traverse (Counter.zeroIndexed(output.size()) -> Int pos) {- \ Testing.checkEquals(output.readAt(pos),expected.readAt(pos))+ \ output.readAt(pos) `Matches:with` CheckValue:equals(expected.readAt(pos)) } - \ Testing.checkEquals(tree.getWeight("a"),2)- \ Testing.checkEquals(tree.getWeight("b"),3)- \ Testing.checkEquals(tree.getWeight("c"),1)+ \ tree.getWeight("a") `Matches:with` CheckValue:equals(2)+ \ tree.getWeight("b") `Matches:with` CheckValue:equals(3)+ \ tree.getWeight("c") `Matches:with` CheckValue:equals(1) } unittest permuteFromWeight { CategoricalTree<String> tree <- CategoricalTree<String>.new()- .setWeight("a",2)- .setWeight("b",3)- .setWeight("c",1)+ .setWeight("a", 2)+ .setWeight("b", 3)+ .setWeight("c", 1) Vector<String> expected <- Vector<String>.new() .append("a")@@ -319,15 +319,15 @@ .append("c") Vector<String> output <- Vector<String>.new()- \ Randomize:permuteFromWeight(tree,RandomUniform.new(0.0,1.0),output)+ \ Randomize:permuteFromWeight(tree, RandomUniform.new(0.0, 1.0), output) \ Sorting:sort(output) - \ Testing.checkEquals(output.size(),expected.size())+ \ output.size() `Matches:with` CheckValue:equals(expected.size()) traverse (Counter.zeroIndexed(output.size()) -> Int pos) {- \ Testing.checkEquals(output.readAt(pos),expected.readAt(pos))+ \ output.readAt(pos) `Matches:with` CheckValue:equals(expected.readAt(pos)) } - \ Testing.checkEquals(tree.getWeight("a"),2)- \ Testing.checkEquals(tree.getWeight("b"),3)- \ Testing.checkEquals(tree.getWeight("c"),1)+ \ tree.getWeight("a") `Matches:with` CheckValue:equals(2)+ \ tree.getWeight("b") `Matches:with` CheckValue:equals(3)+ \ tree.getWeight("c") `Matches:with` CheckValue:equals(1) }
lib/math/test/token.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,26 +17,26 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "basic Token tests" {- success+ success TestChecker } unittest equals {- \ Testing.checkEquals(Token.from("message"),Token.from("message"))- \ Testing.checkFalse(Token.from("message") `Token.equals` Token.from("other"))+ \ Token.from("message") `Matches:with` CheckValue:equals(Token.from("message"))+ \ Token.from("message") `Token.equals` Token.from("other") `Matches:with` CheckValue:equals(false) } unittest lessThan {- \ Testing.checkFalse(Token.from("message") `Token.lessThan` Token.from("message"))- \ Testing.checkTrue((Token.from("message") `Token.lessThan` Token.from("other")) ||- (Token.from("other") `Token.lessThan` Token.from("message")))+ \ Token.from("message") `Token.lessThan` Token.from("message") `Matches:with` CheckValue:equals(false)+ \ ((Token.from("message") `Token.lessThan` Token.from("other")) ^+ (Token.from("other") `Token.lessThan` Token.from("message"))) `Matches:with` CheckValue:equals(true) } unittest formatted {- \ Testing.checkEquals(Token.from("message").formatted(),"message")+ \ Token.from("message").formatted() `Matches:with` CheckValue:equals("message") } unittest hashed {- \ Testing.checkNotEquals(Token.from("message").hashed(),Token.from("other").hashed())- \ Testing.checkNotEquals(Token.from("message").hashed(),"message".hashed())- \ Testing.checkEquals(Token.from("message").hashed(),Token.from("message").hashed())+ \ Token.from("message").hashed() `Matches:with` CheckValue:notEquals(Token.from("other").hashed())+ \ Token.from("message").hashed() `Matches:with` CheckValue:notEquals("message".hashed())+ \ Token.from("message").hashed() `Matches:with` CheckValue:equals(Token.from("message").hashed()) }
lib/testing/.zeolite-module view
@@ -1,7 +1,19 @@ root: "../.." path: "lib/testing"+expression_map: [+ expression_macro {+ name: FLOAT_RELATIVE_THRESHOLD+ expression: 1.0E-7+ }+] extra_paths: [ "lib/testing/src" "lib/testing/test" ]-mode: incremental {}+extra_files: [+ category_source {+ source: "lib/testing/src/Extension_TestHandler.cpp"+ categories: [TestHandler]+ }+]+mode: incremental { }
+ lib/testing/check-float.0rp view
@@ -0,0 +1,28 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Simple Float checks.+concrete CheckFloat {+ // Uses relative threshold of $ExprLookup[FLOAT_RELATIVE_THRESHOLD]$ times the+ // max absolute value of the values being compared.+ // NOTE: This will never match 0 unless exactly 0 is expected.+ @category almostEquals (AsFloat) -> (ValueMatcher<[AsFloat & Formatted]>)++ // Uses absolute threshold.+ @category closeTo (AsFloat, Float epsilon:) -> (ValueMatcher<[AsFloat & Formatted]>)+}
+ lib/testing/check-sequence.0rp view
@@ -0,0 +1,33 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Checks sequences of values.+concrete CheckSequence {+ @category using<#x>+ #x requires TestCompare<#x>+ (DefaultOrder<#x>) -> (DefaultOrder<ValueMatcher<#x>>)++ @category equals<#x>+ #x requires Formatted+ #x defines Equals<#x>+ (DefaultOrder<#x>) -> (ValueMatcher<DefaultOrder<#x>>)++ @category matches<#x> (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<DefaultOrder<#x>>)++ @category allMatch<#x> (ValueMatcher<#x>) -> (ValueMatcher<DefaultOrder<#x>>)+}
+ lib/testing/check-string.0rp view
@@ -0,0 +1,24 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Simple sub-string checks.+concrete CheckString {+ @category contains (Formatted) -> (ValueMatcher<Formatted>)+ @category startsWith (Formatted) -> (ValueMatcher<Formatted>)+ @category endsWith (Formatted) -> (ValueMatcher<Formatted>)+}
+ lib/testing/check-value.0rp view
@@ -0,0 +1,67 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Simple equality-based value checks.+concrete CheckValue<#x|> {+ @category using<#x>+ #x requires TestCompare<#x>+ (#x) -> (ValueMatcher<#x>)++ @category equals<#x>+ #x requires Formatted+ #x defines Equals<#x>+ (optional #x) -> (ValueMatcher<#x>)++ @category notEquals<#x>+ #x requires Formatted+ #x defines Equals<#x>+ (optional #x) -> (ValueMatcher<#x>)++ // Value has the same Identifier.+ @category is<#x> (optional #x) -> (ValueMatcher<#x>)++ @category lessThanNotEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x) -> (ValueMatcher<#x>)++ @category greaterThanNotEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x) -> (ValueMatcher<#x>)++ @category betweenNotEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x, #x) -> (ValueMatcher<#x>)++ @category lessThanEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x) -> (ValueMatcher<#x>)++ @category greaterThanEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x) -> (ValueMatcher<#x>)++ @category betweenEquals<#x>+ #x requires Formatted+ #x defines LessThan<#x>+ (#x, #x) -> (ValueMatcher<#x>)+}
+ lib/testing/checker.0rp view
@@ -0,0 +1,32 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++// NOTE: You must set the testcase checker in order to use this.+//+// testcase "my testcase" {+// success TestChecker+// }+concrete TestChecker {+ defines Testcase++ @type isFailing () -> (Bool)+ @type checkNow () -> ()+ @type newReport (Formatted title:, optional Order<Formatted> context:) -> (TestReport)+}
+ lib/testing/evaluation.0rp view
@@ -0,0 +1,54 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++// NOTE: You must specify TestChecker in order to use this.+//+// testcase "my testcase" {+// success TestChecker+// }+concrete Matches {+ // Fails immediately if match fails.+ @category with<#x> (optional #x, ValueMatcher<#x>) -> ()++ // Fails later if match fails.+ @category tryWith<#x> (optional #x, ValueMatcher<#x>) -> ()++ // Fails immediately if match fails.+ @category value<#x>+ #x requires TestCompare<#x>+ (optional #x, #x) -> ()++ // Fails later if match fails.+ @category tryValue<#x>+ #x requires TestCompare<#x>+ (optional #x, #x) -> ()+}++// Unconditional outcomes regardless of the actual value.+concrete CheckAlways {+ // Unconditionally match.+ @category match () -> (ValueMatcher<any>)++ // Unconditional error.+ @category error (Formatted) -> (ValueMatcher<any>)++ // Immediate crash if the matcher is used to check a value.+ @category die (Formatted) -> (ValueMatcher<any>)+}
− lib/testing/helpers.0rp
@@ -1,127 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--$TestsOnly$--// General helpers for use in unit tests.-concrete Testing {- // Check the values for equality. Crashes if they are not equal.- //- // Args:- // - #x: Actual value.- // - #x: Expected value.- @type checkEquals<#x>- #x requires Formatted- #x defines Equals<#x>- (#x,#x) -> ()-- // Check the values for inequality. Crashes if they are equal.- //- // Args:- // - #x: Actual value.- // - #x: Expected value.- @type checkNotEquals<#x>- #x requires Formatted- #x defines Equals<#x>- (#x,#x) -> ()-- // Check the value for empty. Crashes if present.- //- // Args:- // - #x: Actual value.- @type checkEmpty<#x> (optional #x) -> ()-- // Check the value for present. Crashes if empty.- //- // Args:- // - optional any: Actual value.- @type checkPresent (optional any) -> ()-- // Check the optional values for equality. Crashes if they are not equal.- //- // Args:- // - optional #x: Actual value.- // - optional #x: Expected value.- @type checkOptional<#x>- #x requires Formatted- #x defines Equals<#x>- (optional #x,optional #x) -> ()-- // Check the value for true. Crashes if false.- //- // Args:- // - AsBool: Actual value.- @type checkTrue (AsBool) -> ()-- // Check the value for false. Crashes if true.- //- // Args:- // - AsBool: Actual value.- @type checkFalse (AsBool) -> ()-- // Check that the value is within a range. Crashes if it is not in the range.- //- // Args:- // - #x: Actual value.- // - #x: Lower bound.- // - #x: Upper bound.- //- // Notes:- // - This could be done without Equals, except that some types have- // "undefined" values (e.g., NaN, for Float) that prevent inferring equality- // from less-than comparisons.- @type checkBetween<#x>- #x requires Formatted- #x defines Equals<#x>- #x defines LessThan<#x>- (#x,#x,#x) -> ()-- // Check that the value is above the limit. Crashes if it is not in the range.- //- // Args:- // - #x: Actual value.- // - #x: Lower bound.- //- // Notes:- // - This could be done without Equals, except that some types have- // "undefined" values (e.g., NaN, for Float) that prevent inferring equality- // from less-than comparisons.- // - This comparison doesn't allow the value to equal the bound.- @type checkGreaterThan<#x>- #x requires Formatted- #x defines Equals<#x>- #x defines LessThan<#x>- (#x,#x) -> ()-- // Check that the value is below the limit. Crashes if it is not in the range.- //- // Args:- // - #x: Actual value.- // - #x: Upper bound.- //- // Notes:- // - This could be done without Equals, except that some types have- // "undefined" values (e.g., NaN, for Float) that prevent inferring equality- // from less-than comparisons.- // - This comparison doesn't allow the value to equal the bound.- @type checkLessThan<#x>- #x requires Formatted- #x defines Equals<#x>- #x defines LessThan<#x>- (#x,#x) -> ()-}
+ lib/testing/matching.0rp view
@@ -0,0 +1,66 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Supports test comparisons.+// NOTE: This should be refined in #x.+@value interface TestCompare<#x|> {+ testCompare (#x actual:, TestReport) -> ()+}++// Base interface for custom value matchers.+@value interface ValueMatcher<#x|> {+ check<#y>+ #y requires #x+ (optional #y, TestReport) -> ()++ summary () -> (Formatted)+}++// Interface used by predicate testers and matchers to report errors.+@value interface TestReport {+ // Adds a new error message.+ addError (Formatted message:) -> (#self)++ // Adds a child section without changing the error status.+ newSection (Formatted title:) -> (#self)++ // Discards error messages and child sections.+ discardReport () -> (#self)++ // Returns true if there are error messages, or if a child has an error.+ hasError () -> (Bool)+}++// Helper to check multiple members of a single object.+concrete MultiChecker {+ @value check<#x> (Formatted title:, optional #x, ValueMatcher<#x>) -> (optional #self)+ @value tryCheck<#x> (Formatted title:, optional #x, ValueMatcher<#x>) -> (#self)++ // Can only be constructed by value checkers.+ visibility ValueMatcher<all>, TestCompare<all>++ @type new (TestReport) -> (#self)+}++concrete MatcherCompose {+ @category not<#x> (ValueMatcher<#x>) -> (ValueMatcher<#x>)+ @category or<#x> (ValueMatcher<#x>, ValueMatcher<#x>) -> (ValueMatcher<#x>)+ @category and<#x> (ValueMatcher<#x>, ValueMatcher<#x>) -> (ValueMatcher<#x>)+ @category anyOf<#x> (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<#x>)+ @category allOf<#x> (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<#x>)+}
+ lib/testing/src/Extension_TestHandler.cpp view
@@ -0,0 +1,59 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <cstdlib>+#include <iostream>++#include "category-source.hpp"+#include "Streamlined_TestHandler.hpp"+#include "Category_String.hpp"+#include "Category_TestHandler.hpp"++#ifdef ZEOLITE_PRIVATE_NAMESPACE+namespace ZEOLITE_PRIVATE_NAMESPACE {+#endif // ZEOLITE_PRIVATE_NAMESPACE++struct ExtCategory_TestHandler : public Category_TestHandler {+ ReturnTuple Call_failAndExit(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("TestHandler:failAndExit")+ const BoxedValue& Var_arg1 = params_args.GetArg(0);+ std::cerr << Var_arg1.AsString();+ std::exit(1);+ }+};++struct ExtType_TestHandler : public Type_TestHandler {+ inline ExtType_TestHandler(Category_TestHandler& p, Params<0>::Type params) : Type_TestHandler(p, params) {}+};++Category_TestHandler& CreateCategory_TestHandler() {+ static auto& category = *new ExtCategory_TestHandler();+ return category;+}++S<const Type_TestHandler> CreateType_TestHandler(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_TestHandler(CreateCategory_TestHandler(), Params<0>::Type()));+ return cached;+}++void RemoveType_TestHandler(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PRIVATE_NAMESPACE+} // namespace ZEOLITE_PRIVATE_NAMESPACE+using namespace ZEOLITE_PRIVATE_NAMESPACE;+#endif // ZEOLITE_PRIVATE_NAMESPACE
+ lib/testing/src/check-float.0rx view
@@ -0,0 +1,92 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CheckFloat {+ $ReadOnlyExcept[]$++ refines ValueMatcher<[AsFloat & Formatted]>++ @value optional Float epsilon+ @value Float expected++ almostEquals (expected) {+ return CheckFloat{ empty, expected.asFloat() }+ }++ closeTo (expected, epsilon) {+ return CheckFloat{ epsilon, expected.asFloat() }+ }++ check (actual, report) {+ optional Float threshold <- epsilon+ if (`present` actual) {+ Float value <- require(actual).asFloat()+ $Hidden[actual]$+ if (`present` epsilon) {+ threshold <- `require` epsilon+ } else {+ threshold <- $ExprLookup[FLOAT_RELATIVE_THRESHOLD]$ * getMaxAbs(value, expected)+ }+ $Hidden[epsilon]$+ if (abs(value - expected) <= `require` threshold) {+ return _+ }+ }+ $Hidden[epsilon]$+ if (`present` threshold) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" is not within ")+ .append(`require` threshold)+ .append(" of ")+ .append(expected)+ .build())+ } else {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" is not close to ")+ .append(expected)+ .build())+ }+ }++ summary () {+ if (`present` epsilon) {+ return "value is close to"+ } else {+ return "value is almost equal to"+ }+ }++ @type abs (Float) -> (Float)+ abs (x) {+ if (x < 0.0) {+ return -x+ } else {+ return x+ }+ }++ @type getMaxAbs (Float, Float) -> (Float)+ getMaxAbs (x, y) (max) {+ max <- abs(x)+ if (abs(y) > max) {+ max <- abs(y)+ }+ }+}
+ lib/testing/src/check-sequence.0rx view
@@ -0,0 +1,219 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CheckSequence {+ using (expected) {+ return SequenceAdapter<#x>.new(expected)+ }++ equals (expected) {+ return SequenceEquals<#x>.new(expected)+ }++ matches (expected) {+ return SequenceMatches<#x>.new(expected)+ }++ allMatch (expected) {+ return SequenceAllMatch<#x>.new(expected)+ }+}++concrete SequenceAdapter<#x> {+ #x requires TestCompare<#x>++ @type new (DefaultOrder<#x>) -> (DefaultOrder<ValueMatcher<#x>>)+}++define SequenceAdapter {+ $ReadOnlyExcept[current]$++ refines DefaultOrder<ValueMatcher<#x>>+ refines Order<ValueMatcher<#x>>++ @value DefaultOrder<#x> original+ @value optional Order<#x> current++ new (original) {+ return #self{ original, empty }+ }++ defaultOrder () {+ return #self{ original, original.defaultOrder() }+ }++ get () {+ return CheckValue:using(`require` current&.get())+ }++ next () {+ if (`present` (current <- current&.next())) {+ return self+ } else {+ return empty+ }+ }+}++concrete SequenceEquals<#x> {+ #x requires Formatted+ #x defines Equals<#x>++ @type new (DefaultOrder<#x>) -> (ValueMatcher<DefaultOrder<#x>>)+}++define SequenceEquals {+ $ReadOnlyExcept[]$++ refines ValueMatcher<DefaultOrder<#x>>++ @value DefaultOrder<#x> expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ optional Order<#x> currentActual <- actual&.defaultOrder()+ optional Order<#x> currentExpected <- expected.defaultOrder()+ Int index <- 0+ $Hidden[actual, expected]$+ while (`present` currentActual || `present` currentExpected) {+ optional #x valueActual <- currentActual&.get()+ optional #x valueExpected <- currentExpected&.get()+ TestReport newReport <- report.newSection(title: String.builder()+ .append("Item #")+ .append(index)+ .build())+ $Hidden[report]$+ if (! `present` valueActual) {+ \ newReport.addError(message: String.builder()+ .append(`Format:autoFormat` valueExpected)+ .append(" is missing")+ .build())+ } elif (! `present` valueExpected) {+ \ newReport.addError(message: String.builder()+ .append(`Format:autoFormat` valueActual)+ .append(" is unexpected")+ .build())+ } elif (!(require(valueActual) `#x.equals` require(valueExpected))) {+ \ newReport.addError(message: String.builder()+ .append(`Format:autoFormat` valueActual)+ .append(" does not equal ")+ .append(`Format:autoFormat` valueExpected)+ .build())+ }+ } update {+ currentActual <- currentActual&.next()+ currentExpected <- currentExpected&.next()+ index <- index+1+ }+ }++ summary () {+ return "sequence has equal values"+ }+}++concrete SequenceMatches<#x> {+ @type new (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<DefaultOrder<#x>>)+}++define SequenceMatches {+ $ReadOnlyExcept[]$++ refines ValueMatcher<DefaultOrder<#x>>++ @value DefaultOrder<ValueMatcher<#x>> expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ optional Order<#x> currentActual <- actual&.defaultOrder()+ optional Order<ValueMatcher<#x>> currentExpected <- expected.defaultOrder()+ Int index <- 0+ $Hidden[actual, expected]$+ while (`present` currentActual || `present` currentExpected) {+ optional #x valueActual <- currentActual&.get()+ optional ValueMatcher<#x> valueExpected <- currentExpected&.get()+ TestReport newReport <- report.newSection(title: String.builder()+ .append("Item #")+ .append(index)+ .build())+ $Hidden[report]$+ if (! `present` valueActual) {+ \ newReport.addError(message: String.builder()+ .append("Item #")+ .append(index)+ .append(" is missing")+ .build())+ } elif (! `present` valueExpected) {+ \ newReport.addError(message: String.builder()+ .append("Item #")+ .append(index)+ .append(" is unexpected")+ .build())+ } else {+ \ valueActual `require(valueExpected).check` newReport+ }+ } update {+ currentActual <- currentActual&.next()+ currentExpected <- currentExpected&.next()+ index <- index+1+ }+ }++ summary () {+ return "sequence values separately match"+ }+}++concrete SequenceAllMatch<#x> {+ @type new (ValueMatcher<#x>) -> (ValueMatcher<DefaultOrder<#x>>)+}++define SequenceAllMatch {+ $ReadOnlyExcept[]$++ refines ValueMatcher<DefaultOrder<#x>>++ @value ValueMatcher<#x> expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ scoped {+ Int index <- 0+ } in traverse (actual&.defaultOrder() -> #x value) {+ TestReport newReport <- report.newSection(title: String.builder()+ .append("Item #")+ .append(index)+ .build())+ $Hidden[report]$+ \ value `expected.check` newReport+ }+ }++ summary () {+ return "sequence values all match"+ }+}
+ lib/testing/src/check-string.0rx view
@@ -0,0 +1,96 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CheckString {+ $ReadOnlyExcept[]$++ refines ValueMatcher<Formatted>++ @value String expected+ @value Bool fromStart+ @value Bool toEnd++ contains (expected) {+ return CheckString{ expected.formatted(), false, false }+ }++ startsWith (expected) {+ return CheckString{ expected.formatted(), true, false }+ }++ endsWith (expected) {+ return CheckString{ expected.formatted(), false, true }+ }++ check (actual, report) {+ if (! `present` actual) {+ \ report.addError(message: appendErrorAndBuild(String.builder().append("empty")))+ return _+ }+ String value <- require(actual).formatted()+ $Hidden[actual]$+ Int startIndex <- 0+ if (toEnd) {+ startIndex <- value.size()-expected.size()+ }+ while (startIndex >= 0 && startIndex+expected.size() <= value.size()) {+ Bool matches <- true+ scoped {+ Int index <- startIndex+ $Hidden[startIndex]$+ } in traverse (expected.defaultOrder() -> Char char) {+ $Hidden[expected]$+ if (value.readAt(index) != char) {+ matches <- false+ break+ }+ } update {+ index <- index+1+ }+ if (matches) {+ return _+ } elif (fromStart || toEnd) {+ break+ }+ } update {+ startIndex <- startIndex+1+ }+ \ report.addError(message: appendErrorAndBuild(String.builder().append(`Format:autoFormat` value)))+ }++ summary () {+ if (fromStart) {+ return "String starts with"+ } elif (toEnd) {+ return "String ends with"+ } else {+ return "String contains"+ }+ }++ @value appendErrorAndBuild ([Append<Formatted> & Build<String>]) -> (String)+ appendErrorAndBuild (output) {+ if (fromStart) {+ return output.append(" does not start with ").append(`Format:autoFormat` expected).build()+ } elif (toEnd) {+ return output.append(" does not end with ").append(`Format:autoFormat` expected).build()+ } else {+ return output.append(" does not contain ").append(`Format:autoFormat` expected).build()+ }+ }+}
+ lib/testing/src/check-value.0rx view
@@ -0,0 +1,269 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CheckValue {+ using (expected) {+ return ValueTester<#x>.new(expected)+ }++ equals (expected) {+ return ValueEquals<#x>.new(false, expected)+ }++ notEquals (expected) {+ return ValueEquals<#x>.new(true, expected)+ }++ is (expected) {+ return ValueIdentifier<#x>.new(expected)+ }++ lessThanNotEquals (upper) {+ return ValueBounds<#x>.new(false, empty, upper)+ }++ greaterThanNotEquals (lower) {+ return ValueBounds<#x>.new(false, lower, empty)+ }++ betweenNotEquals (lower, upper) {+ return ValueBounds<#x>.new(false, lower, upper)+ }++ lessThanEquals (upper) {+ return ValueBounds<#x>.new(true, empty, upper)+ }++ greaterThanEquals (lower) {+ return ValueBounds<#x>.new(true, lower, empty)+ }++ betweenEquals (lower, upper) {+ return ValueBounds<#x>.new(true, lower, upper)+ }+}++concrete ValueTester<#x> {+ #x requires TestCompare<#x>++ @type new (#x) -> (ValueMatcher<#x>)+}++define ValueTester {+ $ReadOnlyExcept[]$++ refines ValueMatcher<#x>++ @value #x expected++ new (expected) {+ return delegate -> #self+ }++ check (actual, report) {+ if (! `present` actual) {+ \ report.addError(message: "expected value but got empty")+ } else {+ \ expected.testCompare(actual: require(actual), report)+ }+ }++ summary () {+ return String.builder()+ .append("matches ")+ .append(typename<#x>())+ .build()+ }+}++concrete ValueEquals<#x> {+ #x requires Formatted+ #x defines Equals<#x>++ @type new (Bool, optional #x) -> (ValueMatcher<#x>)+}++define ValueEquals {+ $ReadOnlyExcept[]$++ refines ValueMatcher<#x>++ @value Bool invert+ @value optional #x expected++ new (invert, expected) {+ return delegate -> #self+ }++ check (actual, report) {+ Bool match <- defer+ if (`present` actual && `present` expected) {+ match <- require(actual) `#x.equals` require(expected)+ } else {+ match <- ! `present` actual && ! `present` expected+ }+ if (invert && match) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" equals ")+ .append(`Format:autoFormat` expected)+ .build())+ } elif (!invert && !match) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" does not equal ")+ .append(`Format:autoFormat` expected)+ .build())+ }+ }++ summary () {+ if (invert) {+ return "value not equals"+ } else {+ return "value equals"+ }+ }+}++concrete ValueIdentifier<#x> {+ @type new (optional #x) -> (ValueMatcher<#x>)+}++define ValueIdentifier {+ $ReadOnlyExcept[]$++ refines ValueMatcher<#x>++ // NOTE: Don't use #x here so that it doesn't create a reference.+ @value Identifier<#x> expected++ new (expected) {+ return #self{ `identify` expected }+ }++ check (actual, report) {+ if (`identify` actual != expected) {+ \ report.addError(message: String.builder()+ .append(`format` `identify` actual)+ .append(" does not equal ")+ .append(`format` expected)+ .build())+ }+ }++ summary () {+ return "value is same instance as"+ }++ @type format (Identifier<#x>) -> (Formatted)+ format (id) {+ return String.builder()+ .append(typename<#x>())+ .append("@")+ .append(id)+ .build()+ }+}++concrete ValueBounds<#x> {+ #x requires Formatted+ #x defines LessThan<#x>++ @type new (Bool, optional #x, optional #x) -> (ValueMatcher<#x>)+}++define ValueBounds {+ $ReadOnlyExcept[]$++ refines ValueMatcher<#x>++ @value Bool inclusive+ @value optional #x lower+ @value optional #x upper++ new (inclusive, lower, upper) {+ return delegate -> #self+ }++ check (actual, report) {+ Bool match <- `present` actual+ if (match && `present` lower) {+ match <- require(lower) `compare` require(actual)+ }+ if (match && `present` upper) {+ match <- require(actual) `compare` require(upper)+ }+ if (!match) {+ if (`present` lower && `present` upper) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" is not between ")+ .append(`Format:autoFormat` lower)+ .append(" and ")+ .append(`Format:autoFormat` upper)+ .build())+ } elif (`present` lower) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" is not greater than ")+ .append(`Format:autoFormat` lower)+ .build())+ } elif (`present` upper) {+ \ report.addError(message: String.builder()+ .append(`Format:autoFormat` actual)+ .append(" is not less than ")+ .append(`Format:autoFormat` upper)+ .build())+ }+ }+ }++ summary () {+ if (inclusive) {+ if (`present` lower && `present` upper) {+ return "value is between or equal"+ } elif (`present` lower) {+ return "value is greater than or equal"+ } elif (`present` upper) {+ return "value is less than or equal"+ } else {+ return "value is present"+ }+ } else {+ if (`present` lower && `present` upper) {+ return "value is between but not equal"+ } elif (`present` lower) {+ return "value is greater than but not equal"+ } elif (`present` upper) {+ return "value is less than but not equal"+ } else {+ return "value is present"+ }+ }+ }++ @value compare (#x, #x) -> (Bool)+ compare (x, y) {+ if (inclusive) {+ return !(y `#x.lessThan` x)+ } else {+ return x `#x.lessThan` y+ }+ }+}
+ lib/testing/src/checker.0rx view
@@ -0,0 +1,110 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++define TestChecker {+ @category Bool started <- false+ @category Bool inProgress <- false+ @category Int testCount <- 0+ @category ValueList<TestReportTree> reports <- ValueList<TestReportTree>.new()++ start () { $NoTrace$+ if (started) {+ fail("Testcase already started.")+ }+ started <- true+ inProgress <- true+ }++ finish () { $NoTrace$+ \ checkTestingStarted()+ if (inProgress) {+ inProgress <- false+ \ checkNow()+ }+ }++ isFailing () { $NoTrace$+ \ checkTestingStarted()+ traverse (reports.defaultOrder() -> TestReportTree report) {+ if (report.hasError()) {+ return true+ }+ }+ return false+ }++ checkNow () { $NoTrace$+ \ checkTestingStarted()+ if (isFailing()) {+ \ TestHandler:failAndExit(formatErrors().formatted())+ }+ }++ newReport (title, context) { $NoTrace$+ \ checkTestingAllowed()+ ValueList<Formatted> contextList <- ValueList<Formatted>.new()+ traverse (context -> Formatted item) {+ String stringItem <- item.formatted()+ // TODO: Get rid of this hard coding.+ if (stringItem == "From testcase") {+ break+ } else {+ \ contextList.append(stringItem)+ }+ }+ String numberedTitle <- String.builder()+ .append("Check #")+ .append((testCount <- testCount+1))+ .append(": ")+ .append(title)+ .build()+ TestReportTree report <- TestReportTree.new(numberedTitle, contextList)+ \ reports.append(report)+ return report+ }++ @category formatErrors () -> (Formatted)+ formatErrors () {+ IndentAppend output <- IndentAppend.new(String.builder())+ \ output.append("TestChecker failures:")+ scoped {+ \ output.pushIndent()+ } cleanup {+ \ output.popIndent()+ } in traverse (reports.defaultOrder() -> TestReportTree report) {+ \ report.prune()&.writeTo(output)&.addNewline()+ }+ return output.build()+ }++ @category checkTestingStarted () -> ()+ checkTestingStarted () {+ if (!started) {+ fail("Testcase was not started.")+ }+ }++ @category checkTestingAllowed () -> ()+ checkTestingAllowed () {+ if (!started || !inProgress) {+ fail("Testcase not started or no longer in progress.")+ }+ }+}
+ lib/testing/src/evaluation.0rx view
@@ -0,0 +1,109 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++define Matches {+ with (value, matcher) { $NoTrace$+ if (delegate -> `executeMatch`) {+ \ TestChecker.checkNow()+ }+ }++ tryWith (value, matcher) { $NoTrace$+ \ delegate -> `executeMatch`+ }++ value (actual, expected) { $NoTrace$+ if (delegate -> `executeValue`) {+ \ TestChecker.checkNow()+ }+ }++ tryValue (actual, expected) { $NoTrace$+ \ delegate -> `executeValue`+ }++ @category executeMatch<#x> (optional #x, ValueMatcher<#x>) -> (Bool)+ executeMatch (value, matcher) { $NoTrace$+ String title <- String.builder()+ .append("Matches with ")+ .append(matcher.summary())+ .build()+ TestReport report <- TestChecker.newReport(title: title, context: $CallTrace$)+ \ value `matcher.check` report+ return report.hasError()+ }++ @category executeValue<#x>+ #x requires TestCompare<#x>+ (optional #x, #x) -> (Bool)+ executeValue (actual, expected) { $NoTrace$+ String title <- String.builder()+ .append("Matches ")+ .append(typename<#x>())+ .build()+ TestReport report <- TestChecker.newReport(title: title, context: $CallTrace$)+ if (! `present` actual) {+ \ report.addError(message: "expected value but got empty")+ } else {+ \ expected.testCompare(actual: require(actual), report)+ }+ return report.hasError()+ }+}++define CheckAlways {+ $ReadOnlyExcept[]$++ refines ValueMatcher<any>++ @value Bool die+ @value optional Formatted message++ match () {+ return CheckAlways{ false, empty }+ }++ error (message) {+ return CheckAlways{ false, message }+ }++ die (message) {+ return CheckAlways{ true, message }+ }++ check (_, report) {+ if (! `present` message) {+ } elif (die) {+ fail(`require` message)+ } else {+ \ report.addError(message: `require` message)+ }+ }++ summary () {+ if (die) {+ return "always die"+ } elif (`present` message) {+ return "always error"+ } else {+ return "always pass"+ }+ }+}
− lib/testing/src/helpers.0rx
@@ -1,135 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--$TestsOnly$--define Testing {- checkEquals (x,y) { $NoTrace$- if (!#x.equals(x,y)) {- fail(String.builder()- .append(x)- .append(" is not equal to ")- .append(y)- .build())- }- }-- checkNotEquals (x,y) { $NoTrace$- if (#x.equals(x,y)) {- fail(String.builder()- .append(x)- .append(" is equal to ")- .append(y)- .build())- }- }-- checkEmpty (x) { $NoTrace$- if (present(x)) {- scoped {- optional Formatted formatted <- reduce<#x,Formatted>(require(x))- } in if (present(formatted)) {- fail(String.builder()- .append(require(formatted))- .append(" is not empty")- .build())- } else {- fail("(unformatted value) is not empty")- }- }- }-- checkPresent (x) { $NoTrace$- if (!present(x)) {- fail(String.builder()- .append("expected non-empty value")- .build())- }- }-- checkOptional (x,y) { $NoTrace$- if (present(x) && present(y)) {- \ checkEquals(require(x),require(y))- } elif (!present(x) && present(y)) {- fail("empty is not equal to " + require(y).formatted())- } elif (present(x) && !present(y)) {- fail(require(x).formatted() + " is not equal to empty")- }- }-- checkTrue (x) { $NoTrace$- if (!x.asBool()) {- fail("expected true")- }- }-- checkFalse (x) { $NoTrace$- if (x.asBool()) {- fail("expected false")- }- }-- checkBetween (x,l,h) { $NoTrace$- if (!lessEquals(l,h)) {- fail(String.builder()- .append("Upper limit ")- .append(l)- .append(" is not at or above lower limit ")- .append(h)- .build())- }- if (!lessEquals(l,x) || !lessEquals(x,h)) {- fail(String.builder()- .append(x)- .append(" is not between ")- .append(l)- .append(" and ")- .append(h)- .build())- }- }-- checkGreaterThan (x,l) { $NoTrace$- if (lessEquals(x,l)) {- fail(String.builder()- .append(x)- .append(" is not greater than ")- .append(l)- .build())- }- }-- checkLessThan (x,h) { $NoTrace$- if (lessEquals(h,x)) {- fail(String.builder()- .append(x)- .append(" is not less than ")- .append(h)- .build())- }- }-- @type lessEquals<#x>- #x defines Equals<#x>- #x defines LessThan<#x>- (#x,#x) -> (Bool)- lessEquals (x,y) { $NoTrace$- // Using !#x.lessThan(y,x) wouldn't account for NaNs.- return #x.lessThan(x,y) || #x.equals(x,y)- }-}
+ lib/testing/src/matching.0rx view
@@ -0,0 +1,241 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define MultiChecker {+ $ReadOnlyExcept[]$++ @value TestReport report++ new (report) {+ return delegate -> #self+ }++ check (title, value, matcher) {+ if (delegate -> `executeMatch`) {+ return empty+ } else {+ return self+ }+ }++ tryCheck (title, value, matcher) {+ \ delegate -> `executeMatch`+ return self+ }++ @value executeMatch<#x> (Formatted title:, optional #x, ValueMatcher<#x>) -> (Bool)+ executeMatch (title, value, matcher) {+ String fullTitle <- String.builder()+ .append(title)+ .append(": ")+ .append(matcher.summary())+ .build()+ TestReport newReport <- report.newSection(title: fullTitle)+ $Hidden[report]$+ \ value `matcher.check` newReport+ return newReport.hasError()+ }+}++define MatcherCompose {+ or (left, right) {+ return delegate -> `OrMatcher:new`+ }++ not (matcher) {+ return delegate -> `NotMatcher:new`+ }++ and (left, right) {+ return delegate -> `AndMatcher:new`+ }++ anyOf (matchers) {+ return delegate -> `AnyOfMatcher:new`+ }++ allOf (matchers) {+ return delegate -> `AllOfMatcher:new`+ }+}++concrete OrMatcher<#x|> {+ refines ValueMatcher<#x>++ @category new<#x> (ValueMatcher<#x>, ValueMatcher<#x>) -> (ValueMatcher<#x>)+}++define OrMatcher {+ @value ValueMatcher<#x> left+ @value ValueMatcher<#x> right++ new (left, right) {+ return delegate -> OrMatcher<#x>+ }++ check (actual, report) {+ TestReport leftReport <- report.newSection(title: left.summary())+ TestReport rightReport <- report.newSection(title: right.summary())+ \ actual `left.check` leftReport+ if (!leftReport.hasError()) {+ return _+ }+ $Hidden[left]$+ \ actual `right.check` rightReport+ if (!rightReport.hasError()) {+ \ leftReport.discardReport()+ }+ }++ summary () {+ return String.builder()+ .append("either (")+ .append(left.summary())+ .append(") or (")+ .append(right.summary())+ .append(")")+ .build()+ }+}++concrete NotMatcher<#x|> {+ refines ValueMatcher<#x>++ @category new<#x> (ValueMatcher<#x>) -> (ValueMatcher<#x>)+}++define NotMatcher {+ @value ValueMatcher<#x> matcher++ new (matcher) {+ return delegate -> NotMatcher<#x>+ }++ check (actual, report) {+ \ delegate -> `matcher.check`+ if (report.hasError()) {+ \ report.discardReport()+ } else {+ \ report.addError(message: String.builder()+ .append("expected failure to match with ")+ .append(matcher.summary())+ .build())+ }+ }++ summary () {+ return String.builder()+ .append("not (")+ .append(matcher.summary())+ .append(")")+ .build()+ }+}++concrete AndMatcher<#x|> {+ refines ValueMatcher<#x>++ @category new<#x> (ValueMatcher<#x>, ValueMatcher<#x>) -> (ValueMatcher<#x>)+}++define AndMatcher {+ @value ValueMatcher<#x> left+ @value ValueMatcher<#x> right++ new (left, right) {+ return delegate -> AndMatcher<#x>+ }++ check (actual, report) {+ TestReport leftReport <- report.newSection(title: left.summary())+ TestReport rightReport <- report.newSection(title: right.summary())+ \ actual `left.check` leftReport+ \ actual `right.check` rightReport+ }++ summary () {+ return String.builder()+ .append("both (")+ .append(left.summary())+ .append(") and (")+ .append(right.summary())+ .append(")")+ .build()+ }+}++concrete AnyOfMatcher<#x|> {+ refines ValueMatcher<#x>++ @category new<#x> (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<#x>)+}++define AnyOfMatcher {+ @value DefaultOrder<ValueMatcher<#x>> matchers++ new (matchers) {+ return delegate -> AnyOfMatcher<#x>+ }++ check (actual, report) {+ ValueList<TestReport> reports <- ValueList<TestReport>.new()+ traverse (matchers.defaultOrder() -> ValueMatcher<#x> matcher) {+ TestReport subReport <- report.newSection(title: matcher.summary())+ $Hidden[report]$+ \ actual `matcher.check` subReport+ if (subReport.hasError()) {+ \ reports.append(subReport)+ } else {+ traverse (reports.defaultOrder() -> TestReport failed) {+ \ failed.discardReport()+ }+ break+ }+ }+ }++ summary () {+ return "match any of"+ }+}++concrete AllOfMatcher<#x|> {+ refines ValueMatcher<#x>++ @category new<#x> (DefaultOrder<ValueMatcher<#x>>) -> (ValueMatcher<#x>)+}++define AllOfMatcher {+ @value DefaultOrder<ValueMatcher<#x>> matchers++ new (matchers) {+ return delegate -> AllOfMatcher<#x>+ }++ check (actual, report) {+ traverse (matchers.defaultOrder() -> ValueMatcher<#x> matcher) {+ TestReport subReport <- report.newSection(title: matcher.summary())+ $Hidden[report]$+ \ actual `matcher.check` subReport+ }+ }++ summary () {+ return "match all of"+ }+}
+ lib/testing/src/util.0rp view
@@ -0,0 +1,59 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$++concrete IndentAppend {+ refines Append<Formatted>+ refines Build<Formatted>++ @type new ([Append<Formatted> & Build<Formatted>]) -> (#self)++ @value pushIndent () -> (#self)+ @value popIndent () -> (#self)+ @value addNewline () -> (#self)+}++concrete ValueList<#x> {+ refines Append<#x>+ refines DefaultOrder<#x>++ @type new () -> (#self)+ @value isEmpty () -> (Bool)+}++// See Extension_TestHandler.cpp.+concrete TestHandler {+ @category failAndExit (String) -> ()+}++concrete TestReportTree {+ refines TestReport++ @type new (Formatted, ValueList<Formatted>) -> (#self)++ // NOTE: This will write passing sections unless you prune() first.+ @value writeTo (IndentAppend) -> (IndentAppend)+ @value prune () -> (optional #self)+}++concrete Format {+ @category autoFormat<#x>+ #x requires Formatted+ (optional #x) -> (Formatted)+}
+ lib/testing/src/util.0rx view
@@ -0,0 +1,239 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define IndentAppend {+ $ReadOnlyExcept[indentCount]$++ @value [Append<Formatted> & Build<Formatted>] output+ @value Int indentCount++ new (output) {+ return #self{ output, 0 }+ }++ pushIndent () {+ indentCount <- indentCount+1+ return self+ }++ popIndent () {+ indentCount <- indentCount-1+ return self+ }++ addNewline () {+ \ output.append("\n")+ return self+ }++ append (value) {+ scoped {+ Int count <- 0+ } in while (count < indentCount) {+ \ output.append(" ")+ } update {+ count <- count+1+ }+ \ output.append(value).append("\n")+ return self+ }++ build () {+ return output.build()+ }+}++concrete ListNode<#x> {+ refines Order<#x>++ @type new (#x) -> (#self)+ @value setNext (optional ListNode<#x>) -> (#self)+}++define ListNode {+ $FlatCleanup[next]$+ $ReadOnly[value]$++ @value #x value+ @value optional #self next++ new (value) {+ return #self{ value, empty }+ }++ setNext (newNext) {+ next <- newNext+ return self+ }++ next () {+ return next+ }++ get () {+ return value+ }+}++define ValueList {+ @value optional ListNode<#x> head+ @value optional ListNode<#x> tail++ new () {+ return #self{ empty, empty }+ }++ isEmpty () {+ return ! `present` head+ }++ append (value) {+ scoped {+ ListNode<#x> node <- ListNode<#x>.new(value)+ } in {+ head <-| node+ \ tail&.setNext(node)+ tail <- node+ }+ return self+ }++ defaultOrder () {+ return head+ }+}++define TestReportTree {+ $ReadOnlyExcept[messages, children]$++ @value Formatted title+ @value ValueList<Formatted> context+ @value ValueList<Formatted> messages+ @value ValueList<TestReportTree> children++ new (title, context) {+ return #self{ title, context, ValueList<Formatted>.new(), ValueList<TestReportTree>.new() }+ }++ writeTo (output) {+ \ output.append(title)+ scoped {+ \ output.pushIndent()+ } cleanup {+ \ output.popIndent()+ } in {+ \ writeMessagesTo(output)+ \ writeContextTo(output)+ \ writeChildrenTo(output)+ }+ return output+ }++ addError (message) {+ \ messages.append(message)+ return self+ }++ newSection (newTitle) {+ #self new <- new(newTitle, ValueList<Formatted>.new())+ \ children.append(new)+ return new+ }++ discardReport () {+ messages <- ValueList<Formatted>.new()+ children <- ValueList<TestReportTree>.new()+ return self+ }++ hasError () {+ if (!messages.isEmpty()) {+ return true+ }+ traverse (children.defaultOrder() -> TestReportTree child) {+ if (child.hasError()) {+ return true+ }+ }+ return false+ }++ prune () {+ optional ValueList<TestReportTree> newChildren <- empty+ traverse (children.defaultOrder() -> TestReportTree child) {+ $Hidden[children]$+ optional TestReportTree newChild <- child.prune()+ $Hidden[child]$+ if (`present` newChild) {+ \ (newChildren <-| ValueList<TestReportTree>.new()).append(`require` newChild)+ }+ }+ if (! `present` newChildren && messages.isEmpty()) {+ children <- ValueList<TestReportTree>.new()+ return empty+ } else {+ children <- (newChildren <-| ValueList<TestReportTree>.new())+ return self+ }+ }++ @value writeContextTo (IndentAppend) -> ()+ writeContextTo (output) {+ $Hidden[messages, children]$+ scoped {+ \ output.pushIndent()+ } cleanup {+ \ output.popIndent()+ } in traverse (context.defaultOrder() -> Formatted line) {+ \ output.append(line)+ }+ }++ @value writeMessagesTo (IndentAppend) -> ()+ writeMessagesTo (output) {+ $Hidden[context, children]$+ if (!messages.isEmpty()) {+ traverse (messages.defaultOrder() -> Formatted line) {+ \ output.append(line)+ }+ }+ }++ @value writeChildrenTo (IndentAppend) -> ()+ writeChildrenTo (output) {+ $Hidden[messages, context]$+ traverse (children.defaultOrder() -> TestReportTree child) {+ \ output.append("---")+ \ child.writeTo(output)+ }+ }+}++define Format {+ autoFormat (value) {+ if (`present` value) {+ return String.builder()+ .append("\"")+ .append(`require` value)+ .append("\"")+ .build()+ } else {+ return "empty"+ }+ }+}
+ lib/testing/test/check-float.0rt view
@@ -0,0 +1,106 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CheckFloat success" {+ success TestChecker+}++unittest almostEquals {+ \ 1.230000000001 `Matches:with` CheckFloat:almostEquals(1.23)+ \ 1.229999999999 `Matches:with` CheckFloat:almostEquals(1.23)+ \ -1.230000000001 `Matches:with` CheckFloat:almostEquals(-1.23)+ \ -1.229999999999 `Matches:with` CheckFloat:almostEquals(-1.23)+ \ 1000000001.0 `Matches:with` CheckFloat:almostEquals(1000000002.0)+}++unittest closeTo {+ \ 1.24 `Matches:with` CheckFloat:closeTo(1.23, epsilon: 0.011)+ \ 1.22 `Matches:with` CheckFloat:closeTo(1.23, epsilon: 0.011)+ \ -1.24 `Matches:with` CheckFloat:closeTo(-1.23, epsilon: 0.011)+ \ -1.22 `Matches:with` CheckFloat:closeTo(-1.23, epsilon: 0.011)+}+++testcase "CheckFloat:almostEquals failure empty" {+ failure TestChecker+ require "empty .+1.23"+}++unittest test {+ \ empty `Matches:with` CheckFloat:almostEquals(1.23)+}+++testcase "CheckFloat:almostEquals failure above" {+ failure TestChecker+ require "1.24.+ 1.23"+}++unittest test {+ \ 1.24 `Matches:with` CheckFloat:almostEquals(1.23)+}+++testcase "CheckFloat:almostEquals failure expect 0" {+ failure TestChecker+ require "not within"+}++unittest test {+ \ 0.000000001 `Matches:with` CheckFloat:almostEquals(0.0)+}+++testcase "CheckFloat:almostEquals failure below" {+ failure TestChecker+ require "1.22.+ 1.23"+}++unittest test {+ \ 1.22 `Matches:with` CheckFloat:almostEquals(1.23)+}+++testcase "CheckFloat:closeTo failure empty" {+ failure TestChecker+ require "empty .+0.001 .+1.23"+}++unittest test {+ \ empty `Matches:with` CheckFloat:closeTo(1.23, epsilon: 0.001)+}+++testcase "CheckFloat:closeTo failure above" {+ failure TestChecker+ require "1.24.+ 0.001.+ 1.23"+}++unittest test {+ \ 1.24 `Matches:with` CheckFloat:closeTo(1.23, epsilon: 0.001)+}+++testcase "CheckFloat:closeTo failure below" {+ failure TestChecker+ require "1.22.+ 0.001.+ 1.23"+}++unittest test {+ \ 1.22 `Matches:with` CheckFloat:closeTo(1.23, epsilon: 0.001)+}
+ lib/testing/test/check-sequence.0rt view
@@ -0,0 +1,203 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CheckSequence:equals success" {+ success TestChecker+}++unittest equals {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ ValueList<Int> expected <- ValueList<Int>.new().append(10).append(20).append(30)+ \ actual `Matches:with` CheckSequence:equals(expected)+}++unittest equalsWithEmpty {+ ValueList<Int> expected <- ValueList<Int>.new()+ \ empty `Matches:with` CheckSequence:equals(expected)+}+++testcase "CheckSequence:equals different" {+ failure TestChecker+ require "10.+40"+ require "20.+50"+ require "30.+60"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ ValueList<Int> expected <- ValueList<Int>.new().append(40).append(50).append(60)+ \ actual `Matches:with` CheckSequence:equals(expected)+}+++testcase "CheckSequence:equals extra" {+ failure TestChecker+ require "40.+unexpected"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30).append(40)+ ValueList<Int> expected <- ValueList<Int>.new().append(10).append(20).append(30)+ \ actual `Matches:with` CheckSequence:equals(expected)+}+++testcase "CheckSequence:equals missing" {+ failure TestChecker+ require "40.+missing"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ ValueList<Int> expected <- ValueList<Int>.new().append(10).append(20).append(30).append(40)+ \ actual `Matches:with` CheckSequence:equals(expected)+}+++testcase "CheckSequence:matches success" {+ success TestChecker+}++unittest matches {+ ValueList<Int> actual <- ValueList<Int>.new().append(1).append(2).append(3)+ ValueList<ValueMatcher<Int>> expected <- ValueList<ValueMatcher<Int>>.new()+ .append(`CheckValue:equals` 1)+ .append(`CheckValue:equals` 2)+ .append(`CheckValue:equals` 3)+ \ actual `Matches:with` CheckSequence:matches(expected)+}++unittest matchesWithEmpty {+ ValueList<ValueMatcher<Int>> expected <- ValueList<ValueMatcher<Int>>.new()+ \ empty `Matches:with` CheckSequence:matches(expected)+}+++testcase "CheckSequence:matches different" {+ failure TestChecker+ require "10.+40"+ require "20.+50"+ require "30.+60"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ ValueList<ValueMatcher<Int>> expected <- ValueList<ValueMatcher<Int>>.new()+ .append(`CheckValue:equals` 40)+ .append(`CheckValue:equals` 50)+ .append(`CheckValue:equals` 60)+ \ actual `Matches:with` CheckSequence:matches(expected)+}+++testcase "CheckSequence:matches extra" {+ failure TestChecker+ require "unexpected"+ require "[Ii]tem #3"+ exclude "[Ii]tem #0"+ exclude "[Ii]tem #1"+ exclude "[Ii]tem #2"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30).append(40)+ ValueList<ValueMatcher<Int>> expected <- ValueList<ValueMatcher<Int>>.new()+ .append(`CheckValue:equals` 10)+ .append(`CheckValue:equals` 20)+ .append(`CheckValue:equals` 30)+ \ actual `Matches:with` CheckSequence:matches(expected)+}+++testcase "CheckSequence:matches missing" {+ failure TestChecker+ require "missing"+ require "[Ii]tem #3"+ exclude "[Ii]tem #0"+ exclude "[Ii]tem #1"+ exclude "[Ii]tem #2"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ ValueList<ValueMatcher<Int>> expected <- ValueList<ValueMatcher<Int>>.new()+ .append(`CheckValue:equals` 10)+ .append(`CheckValue:equals` 20)+ .append(`CheckValue:equals` 30)+ .append(`CheckValue:equals` 40)+ \ actual `Matches:with` CheckSequence:matches(expected)+}+++testcase "CheckSequence:allMatch success" {+ success TestChecker+}++unittest allMatch {+ ValueList<Int> actual <- ValueList<Int>.new().append(1).append(2).append(3)+ \ actual `Matches:with` CheckSequence:allMatch(CheckValue:greaterThanEquals(0))+}++unittest allMatchWithEmpty {+ \ empty `Matches:with` CheckSequence:allMatch(CheckValue:greaterThanEquals(0))+}+++testcase "CheckSequence:allMatch failure" {+ failure TestChecker+ require "10.+25"+ require "20.+25"+ exclude "30.+25"+}++unittest test {+ ValueList<Int> actual <- ValueList<Int>.new().append(10).append(20).append(30)+ \ actual `Matches:with` CheckSequence:allMatch(CheckValue:greaterThanEquals(25))+}+++testcase "CheckSequence:using success" {+ success TestChecker+}++unittest test {+ ValueList<TestValue> actual <- ValueList<TestValue>.new()+ .append(TestValue.default())+ .append(TestValue.new(456, "something", empty))+ ValueList<TestValue> expected <- ValueList<TestValue>.new()+ .append(TestValue.default())+ .append(TestValue.new(456, "something", empty))+ \ actual `Matches:with` CheckSequence:matches(CheckSequence:using(expected))+}+++testcase "CheckSequence:using failure" {+ failure TestChecker+ require "456.+321"+}++unittest test {+ ValueList<TestValue> actual <- ValueList<TestValue>.new()+ .append(TestValue.default())+ .append(TestValue.new(456, "something", empty))+ ValueList<TestValue> expected <- ValueList<TestValue>.new()+ .append(TestValue.default())+ .append(TestValue.new(321, "something", empty))+ \ actual `Matches:with` CheckSequence:matches(CheckSequence:using(expected))+}
+ lib/testing/test/check-string.0rt view
@@ -0,0 +1,162 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CheckString:contains success" {+ success TestChecker+}++unittest entireString {+ \ "1234567890" `Matches:with` CheckString:contains("1234567890")+}++unittest beginning {+ \ "1234567890" `Matches:with` CheckString:contains("12345")+}++unittest end {+ \ "1234567890" `Matches:with` CheckString:contains("67890")+}++unittest middle {+ \ "1234567890" `Matches:with` CheckString:contains("4567")+}+++testcase "CheckString:contains failure empty" {+ failure TestChecker+ require "does not contain"+ require "empty"+}++unittest test {+ \ empty `Matches:with` CheckString:contains("567890")+}+++testcase "CheckString:contains failure partial" {+ failure TestChecker+ require "does not contain"+ require "567890"+}++unittest test {+ \ "123456789" `Matches:with` CheckString:contains("567890")+}+++testcase "CheckString:contains failure too long" {+ failure TestChecker+ require "does not contain"+ require "123"+}++unittest test {+ \ "123" `Matches:with` CheckString:contains("12345")+}+++testcase "CheckString:startsWith success" {+ success TestChecker+}++unittest entireString {+ \ "1234567890" `Matches:with` CheckString:startsWith("1234567890")+}++unittest beginning {+ \ "1234567890" `Matches:with` CheckString:startsWith("12345")+}+++testcase "CheckString:startsWith failure empty" {+ failure TestChecker+ require "does not start with"+ require "empty"+}++unittest test {+ \ empty `Matches:with` CheckString:startsWith("567890")+}+++testcase "CheckString:startsWith failure not at start" {+ failure TestChecker+ require "does not start with"+ require "567890"+}++unittest test {+ \ "1234567890" `Matches:with` CheckString:startsWith("567890")+}+++testcase "CheckString:startsWith failure too long" {+ failure TestChecker+ require "does not start with"+ require "123"+}++unittest test {+ \ "123" `Matches:with` CheckString:startsWith("12345")+}+++testcase "CheckString:endsWith success" {+ success TestChecker+}++unittest entireString {+ \ "1234567890" `Matches:with` CheckString:endsWith("1234567890")+}++unittest end {+ \ "1234567890" `Matches:with` CheckString:endsWith("567890")+}+++testcase "CheckString:endsWith failure empty" {+ failure TestChecker+ require "does not end with"+ require "empty"+}++unittest test {+ \ empty `Matches:with` CheckString:endsWith("567890")+}+++testcase "CheckString:endsWith failure not at end" {+ failure TestChecker+ require "does not end with"+ require "123456"+}++unittest test {+ \ "1234567890" `Matches:with` CheckString:endsWith("123456")+}+++testcase "CheckString:endsWith failure too long" {+ failure TestChecker+ require "does not end with"+ require "345"+}++unittest test {+ \ "345" `Matches:with` CheckString:endsWith("12345")+}
+ lib/testing/test/check-value.0rt view
@@ -0,0 +1,409 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CheckValue:equals success" {+ success TestChecker+}++unittest nonEmpty {+ \ "foo" `Matches:with` CheckValue:equals("foo")+}++unittest bothEmpty {+ \ empty?String `Matches:with` CheckValue:equals(empty?String)+}+++testcase "CheckValue:equals failure not equal" {+ failure TestChecker+ require "foo"+ require "bar"+}++unittest test {+ \ "foo" `Matches:with` CheckValue:equals("bar")+}+++testcase "CheckValue:equals failure left empty" {+ failure TestChecker+ require "empty"+ require "bar"+}++unittest test {+ \ empty?String `Matches:with` CheckValue:equals("bar")+}+++testcase "CheckValue:equals failure right empty" {+ failure TestChecker+ require "foo"+ require "empty"+}++unittest test {+ \ "foo" `Matches:with` CheckValue:equals(empty?String)+}+++testcase "CheckValue:notEquals success" {+ success TestChecker+}++unittest nonEmpty {+ \ "foo" `Matches:with` CheckValue:notEquals("bar")+}++unittest leftEmpty {+ \ empty?String `Matches:with` CheckValue:notEquals("bar")+}++unittest rightEmpty {+ \ "foo" `Matches:with` CheckValue:notEquals(empty?String)+}+++testcase "CheckValue:notEquals failure non-empty" {+ failure TestChecker+ require "foo"+}++unittest test {+ \ "foo" `Matches:with` CheckValue:notEquals("foo")+}+++testcase "CheckValue:notEquals failure empty" {+ failure TestChecker+ require "empty"+}++unittest test {+ \ empty?String `Matches:with` CheckValue:notEquals(empty?String)+}+++testcase "CheckValue:is success" {+ success TestChecker+}++unittest test {+ String value <- "foo"+ \ value `Matches:with` CheckValue:is(value)+}+++testcase "CheckValue:is failure same value" {+ failure TestChecker+ require "String@[a-f0-9]+"+ exclude "foo"+}++unittest test {+ \ "foo" `Matches:with` CheckValue:is("foo")+}+++testcase "CheckValue:using success" {+ success TestChecker+}++unittest test {+ \ TestValue.default() `Matches:with` `CheckValue:using` TestValue.default()+}+++testcase "CheckValue:using failure not equal" {+ failure TestChecker+ require "message1"+}++unittest test {+ \ TestValue.default() `Matches:with` `CheckValue:using` TestValue.new(123, "message1", empty)+}+++testcase "CheckValue:using failure left empty" {+ failure TestChecker+ require "empty"+}++unittest test {+ \ empty?TestValue `Matches:with` `CheckValue:using` TestValue.new(123, "message1", empty)+}+++testcase "CheckValue:lessThanNotEqual success" {+ success TestChecker+}++unittest test {+ \ 0 `Matches:with` CheckValue:lessThanNotEquals(1)+}+++testcase "CheckValue:lessThanNotEqual failure non-empty" {+ failure TestChecker+ require "100"+ require "20"+}++unittest test {+ \ 100 `Matches:with` CheckValue:lessThanNotEquals(20)+}+++testcase "CheckValue:lessThanNotEqual failure endpoint" {+ failure TestChecker+ require "100"+}++unittest test {+ \ 100 `Matches:with` CheckValue:lessThanNotEquals(100)+}+++testcase "CheckValue:lessThanNotEqual failure empty" {+ failure TestChecker+ require "empty"+ require "20"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:lessThanNotEquals(20)+}+++testcase "CheckValue:greaterThanNotEqual success" {+ success TestChecker+}++unittest test {+ \ 1 `Matches:with` CheckValue:greaterThanNotEquals(0)+}+++testcase "CheckValue:greaterThanNotEqual failure non-empty" {+ failure TestChecker+ require "10"+ require "200"+}++unittest test {+ \ 10 `Matches:with` CheckValue:greaterThanNotEquals(200)+}+++testcase "CheckValue:greaterThanNotEqual failure endpoint" {+ failure TestChecker+ require "10"+}++unittest test {+ \ 10 `Matches:with` CheckValue:greaterThanNotEquals(10)+}+++testcase "CheckValue:greaterThanNotEqual failure empty" {+ failure TestChecker+ require "empty"+ require "20"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:greaterThanNotEquals(20)+}+++testcase "CheckValue:betweenNotEqual success" {+ success TestChecker+}++unittest test {+ \ 1 `Matches:with` CheckValue:betweenNotEquals(0, 3)+}+++testcase "CheckValue:betweenNotEqual failure below" {+ failure TestChecker+ require "3"+ require "5"+ require "200"+}++unittest test {+ \ 3 `Matches:with` CheckValue:betweenNotEquals(5, 200)+}+++testcase "CheckValue:betweenNotEqual failure above" {+ failure TestChecker+ require "300"+ require "5"+ require "200"+}++unittest test {+ \ 300 `Matches:with` CheckValue:betweenNotEquals(5, 200)+}+++testcase "CheckValue:betweenNotEqual failure endpoint low" {+ failure TestChecker+ require "5"+ require "200"+}++unittest test {+ \ 5 `Matches:with` CheckValue:betweenNotEquals(5, 200)+}+++testcase "CheckValue:betweenNotEqual failure endpoint high" {+ failure TestChecker+ require "5"+ require "200"+}++unittest test {+ \ 200 `Matches:with` CheckValue:betweenNotEquals(5, 200)+}+++testcase "CheckValue:betweenNotEqual failure empty" {+ failure TestChecker+ require "empty"+ require "5"+ require "200"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:betweenNotEquals(5, 200)+}+++testcase "CheckValue:lessThanEqual success" {+ success TestChecker+}++unittest test {+ \ 0 `Matches:with` CheckValue:lessThanEquals(1)+ \ 0 `Matches:with` CheckValue:lessThanEquals(0)+}+++testcase "CheckValue:lessThanEqual failure non-empty" {+ failure TestChecker+ require "100"+ require "20"+}++unittest test {+ \ 100 `Matches:with` CheckValue:lessThanEquals(20)+}+++testcase "CheckValue:lessThanEqual failure empty" {+ failure TestChecker+ require "empty"+ require "20"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:lessThanEquals(20)+}+++testcase "CheckValue:greaterThanEqual success" {+ success TestChecker+}++unittest test {+ \ 1 `Matches:with` CheckValue:greaterThanEquals(0)+ \ 1 `Matches:with` CheckValue:greaterThanEquals(1)+}+++testcase "CheckValue:greaterThanEqual failure non-empty" {+ failure TestChecker+ require "10"+ require "200"+}++unittest test {+ \ 10 `Matches:with` CheckValue:greaterThanEquals(200)+}+++testcase "CheckValue:greaterThanEqual failure empty" {+ failure TestChecker+ require "empty"+ require "20"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:greaterThanEquals(20)+}+++testcase "CheckValue:betweenEqual success" {+ success TestChecker+}++unittest test {+ \ 1 `Matches:with` CheckValue:betweenEquals(0, 3)+ \ 0 `Matches:with` CheckValue:betweenEquals(0, 3)+ \ 3 `Matches:with` CheckValue:betweenEquals(0, 3)+}+++testcase "CheckValue:betweenEqual failure below" {+ failure TestChecker+ require "3"+ require "5"+ require "200"+}++unittest test {+ \ 3 `Matches:with` CheckValue:betweenEquals(5, 200)+}+++testcase "CheckValue:betweenEqual failure above" {+ failure TestChecker+ require "300"+ require "5"+ require "200"+}++unittest test {+ \ 300 `Matches:with` CheckValue:betweenEquals(5, 200)+}+++testcase "CheckValue:betweenEqual failure empty" {+ failure TestChecker+ require "empty"+ require "5"+ require "200"+}++unittest test {+ \ empty?Int `Matches:with` CheckValue:betweenEquals(5, 200)+}
+ lib/testing/test/checker.0rt view
@@ -0,0 +1,154 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "TestChecker.isFailing fails if not started" {+ failure+ require "not started"+}++unittest test {+ \ TestChecker.isFailing()+}+++testcase "TestChecker.finish fails if not started" {+ failure+ require "not started"+}++unittest test {+ \ TestChecker.finish()+}+++testcase "TestChecker.checkNow fails if not started" {+ failure+ require "not started"+}++unittest test {+ \ TestChecker.checkNow()+}+++testcase "TestChecker.start fails if already started" {+ failure+ require "already started"+}++unittest test {+ \ TestChecker.start()+ \ TestChecker.start()+}+++testcase "TestChecker.newReport fails if not started" {+ failure+ require "not started"+}++unittest test {+ \ TestChecker.newReport(title: "title", context: empty)+}+++testcase "TestChecker explicit start and finish" {+ success+}++unittest test {+ \ TestChecker.start()+ \ TestChecker.newReport(title: "title", context: empty)+ \ TestChecker.newReport(title: "title", context: empty).newSection(title: "subtitle")+ \ Testing.checkEquals(TestChecker.isFailing(), false)+ \ TestChecker.checkNow()+ \ TestChecker.finish()+}+++testcase "TestChecker succeeds by default" {+ success TestChecker+}++unittest test { }+++testcase "TestChecker fails when error added to report" {+ failure TestChecker+ require "context1"+ require "context2"+ require "title1"+ require "message1"+ require "title2"+ require "message2"+ exclude "testError"+}++unittest testError {+ ValueList<String> context <- ValueList<String>.new()+ .append("context1")+ .append("context2")+ \ TestChecker.newReport(title: "title1", context: context.defaultOrder()).addError(message: "message1")+ \ TestChecker.newReport(title: "title2", context: empty).addError(message: "message2")+}+++testcase "TestChecker fails when error added to child" {+ failure TestChecker+ require "title"+ require "child"+ require "message"+ exclude "testError"+}++unittest testError {+ TestReport report <- TestChecker.newReport(title: "title", context: empty)+ TestReport child <- report.newSection(title: "child")+ \ child.addError(message: "message")+}+++testcase "TestChecker ignores discarded errors" {+ success TestChecker+}++unittest topLevel {+ TestReport report <- TestChecker.newReport(title: "title", context: empty)+ \ Testing.checkEquals(report.hasError(), false)++ \ report.addError(message: "message")+ \ Testing.checkEquals(report.hasError(), true)++ \ report.discardReport()+ \ Testing.checkEquals(report.hasError(), false)+}++unittest recursive {+ TestReport report <- TestChecker.newReport(title: "title", context: empty)+ TestReport child <- report.newSection(title: "child")+ \ Testing.checkEquals(report.hasError(), false)+ \ Testing.checkEquals(child.hasError(), false)++ \ child.addError(message: "message")+ \ Testing.checkEquals(report.hasError(), true)+ \ Testing.checkEquals(child.hasError(), true)++ \ report.discardReport()+ \ Testing.checkEquals(report.hasError(), false)+ \ Testing.checkEquals(child.hasError(), true)+}
+ lib/testing/test/evaluation.0rt view
@@ -0,0 +1,184 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "Matches no errors" {+ success TestChecker+}++unittest withOnce {+ \ "foo" `Matches:with` CheckAlways:match()+}++unittest withMulti {+ \ "foo" `Matches:with` CheckAlways:match()+ \ "foo" `Matches:with` CheckAlways:match()+}++unittest tryWithOnce {+ \ "foo" `Matches:tryWith` CheckAlways:match()+}++unittest tryWithMulti {+ \ "foo" `Matches:tryWith` CheckAlways:match()+ \ "foo" `Matches:tryWith` CheckAlways:match()+}++unittest valueOnce {+ \ TestValue.default() `Matches:value` TestValue.default()+}++unittest valueMulti {+ \ TestValue.default() `Matches:value` TestValue.default()+ \ TestValue.default() `Matches:value` TestValue.default()+}++unittest tryValueOnce {+ \ TestValue.default() `Matches:tryValue` TestValue.default()+}++unittest tryValueMulti {+ \ TestValue.default() `Matches:tryValue` TestValue.default()+ \ TestValue.default() `Matches:tryValue` TestValue.default()+}+++testcase "Matches:with fails immediately" {+ failure TestChecker+ require "message1"+ exclude "message2"+}++unittest test {+ \ "foo" `Matches:with` CheckAlways:error("message1")+ \ "foo" `Matches:with` CheckAlways:error("message2")+}+++testcase "Matches:tryWith fails later" {+ failure TestChecker+ require "message1"+ require "message2"+}++unittest test {+ \ "foo" `Matches:tryWith` CheckAlways:error("message1")+ \ "foo" `Matches:tryWith` CheckAlways:error("message2")+}+++testcase "Matches:value fails immediately" {+ failure TestChecker+ require "message1"+ exclude "321"+ exclude "message2"+ exclude "999"+}++unittest test {+ \ TestValue.default() `Matches:value` TestValue.new(123, "message1", empty)+ \ TestValue.default() `Matches:value` TestValue.new(321, "message2", 999)+}+++testcase "Matches:value failure with empty" {+ failure TestChecker+ require "empty"+}++unittest test {+ \ empty?TestValue `Matches:value` TestValue.new(123, "message1", empty)+}+++testcase "Matches:tryValue fails later" {+ failure TestChecker+ require "message1"+ require "321"+ require "message2"+ require "999"+}++unittest test {+ \ TestValue.default() `Matches:tryValue` TestValue.new(123, "message1", empty)+ \ TestValue.default() `Matches:tryValue` TestValue.new(321, "message2", 999)+}+++testcase "Matches:tryValue failure with empty" {+ failure TestChecker+ require "empty"+}++unittest test {+ \ empty?TestValue `Matches:tryValue` TestValue.new(123, "message1", empty)+}+++testcase "Matches:with doesn't evaluate pending errors" {+ failure TestChecker+ require "message2"+ exclude "message1"+}++unittest test {+ \ "foo" `Matches:tryWith` CheckAlways:error("message1")+ \ "foo" `Matches:with` CheckAlways:match()+ fail("message2")+}+++testcase "Matches:value doesn't evaluate pending errors" {+ failure TestChecker+ require "message2"+ exclude "message1"+}++unittest test {+ \ TestValue.default() `Matches:tryValue` TestValue.new(123, "message1", empty)+ \ TestValue.default() `Matches:value` TestValue.default()+ fail("message2")+}+++testcase "CheckAlways" {+ success+}++unittest match {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ CheckAlways:match().check(123, report)+ \ Testing.checkEquals(report.hasError(), false)+}++unittest fromWithoutError {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ CheckAlways:error("message").check(123, report)+ \ Testing.checkEquals(report.hasError(), true)+}+++testcase "CheckAlways:die" {+ failure+ require "something"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ report.addError(message: "message")+ \ CheckAlways:die("something").check(123, report)+}
+ lib/testing/test/helpers.0rp view
@@ -0,0 +1,35 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$+$TestsOnly$++concrete TestValue {+ refines TestCompare<TestValue>+ // TestValue.new(123, "message", empty)+ defines Default++ @type new (Int, String, optional Int) -> (#self)+}++concrete Testing {+ @type checkEquals<#x>+ #x requires Formatted+ #x defines Equals<#x>+ (optional #x, optional #x) -> ()+}
+ lib/testing/test/helpers.0rx view
@@ -0,0 +1,69 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++define TestValue {+ $ReadOnlyExcept[]$++ @value Int number+ @value String message+ @value optional Int error++ new (number, message, error) {+ return delegate -> #self+ }++ default () {+ return new(123, "message", empty)+ }++ testCompare (actual, report) {+ \ MultiChecker.new(report)+ .tryCheck(title: "number", actual.number(), CheckValue:equals(number))+ .tryCheck(title: "message", actual.message(), CheckValue:equals(message))+ .tryCheck(title: "error", actual.error(), CheckValue:equals(error))+ }++ @value number () -> (Int)+ number () { return number }++ @value message () -> (String)+ message () { return message }++ @value error () -> (optional Int)+ error () { return error }+}++define Testing {+ checkEquals (x, y) { $NoTrace$+ Bool failed <- false+ if (`present` x && `present` y && !#x.equals(`require` x, `require` y)) {+ failed <- true+ } elif (`present` x != `present` y) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(`Format:autoFormat` x)+ .append(" is not equal to ")+ .append(`Format:autoFormat` y)+ .build())+ }+ }+}
+ lib/testing/test/matching.0rt view
@@ -0,0 +1,218 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "MultiChecker.check short cicuits" {+ failure+ require "title0"+ require "title2"+ require "message2"+ exclude "title1"+ exclude "title3"+ exclude "message3"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title0", ValueList<Formatted>.new())++ \ MultiChecker.new(report)+ .check(title: "title1", "foo", CheckAlways:match())+ &.check(title: "title2", "foo", CheckAlways:error("message2"))+ &.check(title: "title3", "foo", CheckAlways:error("message3"))++ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.prune()&.writeTo(output)+ \ TestHandler:failAndExit(output.build().formatted())+}+++testcase "MultiChecker.tryCheck continues" {+ failure+ require "title0"+ require "title2"+ require "message2"+ require "title3"+ require "message3"+ exclude "title1"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title0", ValueList<Formatted>.new())++ \ MultiChecker.new(report)+ .tryCheck<String>(title: "title1", "foo", CheckAlways:match())+ .tryCheck<String>(title: "title2", "foo", CheckAlways:error("message2"))+ .tryCheck<String>(title: "title3", "foo", CheckAlways:error("message3"))++ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.prune()&.writeTo(output)+ \ TestHandler:failAndExit(output.build().formatted())+}+++testcase "MultiChecker.check doesn't force pending errors" {+ failure+ require "title0"+ require "title1"+ require "message1"+ require "title3"+ require "message3"+ exclude "title2"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title0", ValueList<Formatted>.new())++ \ MultiChecker.new(report)+ .tryCheck<String>(title: "title1", "foo", CheckAlways:error("message1"))+ .check(title: "title2", "foo", CheckAlways:match())+ &.tryCheck<String>(title: "title3", "foo", CheckAlways:error("message3"))++ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.prune()&.writeTo(output)+ \ TestHandler:failAndExit(output.build().formatted())+}+++testcase "MatcherCompose:not success" {+ success TestChecker+}++unittest test {+ \ "foo" `Matches:with` `MatcherCompose:not` CheckAlways:error("message")+}+++testcase "MatcherCompose:not failure" {+ failure TestChecker+ require "expected failure"+}++unittest test {+ \ "foo" `Matches:with` `MatcherCompose:not` CheckAlways:match()+}+++testcase "MatcherCompose:or success" {+ success TestChecker+}++unittest test {+ \ "foo" `Matches:with` (CheckAlways:match() `MatcherCompose:or` CheckAlways:match())+ \ "foo" `Matches:with` (CheckAlways:match() `MatcherCompose:or` CheckAlways:error("message"))+ \ "foo" `Matches:with` (CheckAlways:error("message") `MatcherCompose:or` CheckAlways:match())+}+++testcase "MatcherCompose:or failure" {+ failure TestChecker+ require "message1"+ require "message2"+}++unittest test {+ \ "foo" `Matches:with` (CheckAlways:error("message1") `MatcherCompose:or` CheckAlways:error("message2"))+}+++testcase "MatcherCompose:and success" {+ success TestChecker+}++unittest test {+ \ "foo" `Matches:with` (CheckAlways:match() `MatcherCompose:and` CheckAlways:match())+}+++testcase "MatcherCompose:and failure both" {+ failure TestChecker+ require "message1"+ require "message2"+}++unittest test {+ \ "foo" `Matches:with` (CheckAlways:error("message1") `MatcherCompose:and` CheckAlways:error("message2"))+}+++testcase "MatcherCompose:and failure one" {+ failure TestChecker+ require "message"+}++unittest test {+ \ "foo" `Matches:with` (CheckAlways:match() `MatcherCompose:and` CheckAlways:error("message"))+}+++testcase "MatcherCompose:anyOf success" {+ success TestChecker+}++unittest someMatching {+ \ "foo" `Matches:with` MatcherCompose:anyOf(ValueList<ValueMatcher<any>>.new()+ .append(CheckAlways:error("message"))+ .append(CheckAlways:match())+ .append(CheckAlways:die("message")))+}++unittest emptyList {+ \ "foo" `Matches:with` MatcherCompose:anyOf(ValueList<ValueMatcher<any>>.new())+}+++testcase "MatcherCompose:anyOf failure" {+ failure TestChecker+ require "message1"+ require "message2"+}++unittest test {+ \ "foo" `Matches:with` MatcherCompose:anyOf(ValueList<ValueMatcher<any>>.new()+ .append(CheckAlways:error("message1"))+ .append(CheckAlways:error("message2")))+}+++testcase "MatcherCompose:allOf success" {+ success TestChecker+}++unittest allMatching {+ \ "foo" `Matches:with` MatcherCompose:allOf(ValueList<ValueMatcher<any>>.new()+ .append(CheckAlways:match())+ .append(CheckAlways:match()))+}++unittest emptyList {+ \ "foo" `Matches:with` MatcherCompose:allOf(ValueList<ValueMatcher<any>>.new())+}+++testcase "MatcherCompose:allOf failure" {+ failure TestChecker+ require "message1"+ require "message2"+}++unittest test {+ \ "foo" `Matches:with` MatcherCompose:allOf(ValueList<ValueMatcher<any>>.new()+ .append(CheckAlways:match())+ .append(CheckAlways:error("message1"))+ .append(CheckAlways:match())+ .append(CheckAlways:error("message2")))+}
− lib/testing/test/tests.0rt
@@ -1,254 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at-- http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--testcase "checkEquals success" {- success-}--unittest test {- \ Testing.checkEquals(13,13)-}---testcase "checkEquals fail" {- crash- require stderr "13"- require stderr "15"-}--unittest test {- \ Testing.checkEquals(13,15)-}---testcase "checkNotEquals success" {- success-}--unittest test {- \ Testing.checkNotEquals(12,13)-}---testcase "checkNotEquals fail" {- crash- require stderr "13.*13"-}--unittest test {- \ Testing.checkNotEquals(13,13)-}---testcase "checkEmpty success" {- success-}--unittest formatted {- \ Testing.checkEmpty(empty)-}--unittest notFormatted {- optional CharBuffer value <- empty- \ Testing.checkEmpty(value)-}---testcase "checkEmpty fail formatted" {- crash- require stderr "13"- require stderr "empty"-}--unittest test {- \ Testing.checkEmpty(13)-}---testcase "checkEmpty fail unformatted" {- crash- require stderr "unformatted"- require stderr "empty"-}--unittest test {- CharBuffer value <- CharBuffer.new(10)- \ Testing.checkEmpty(value)-}---testcase "checkPresent success" {- success-}--unittest test {- \ Testing.checkPresent(13)-}---testcase "checkPresent fail" {- crash- require stderr "empty"-}--unittest test {- \ Testing.checkPresent(empty)-}---testcase "checkOptional success" {- success-}--unittest test {- \ Testing.checkOptional<Int>(empty,empty)- \ Testing.checkOptional(13,13)-}---testcase "checkOptional fail empty" {- crash- require stderr "13"- require stderr "empty"-}--unittest test {- \ Testing.checkOptional(13,empty)-}---testcase "checkOptional fail present" {- crash- require stderr "13"- require stderr "empty"-}--unittest test {- \ Testing.checkOptional(empty,13)-}---testcase "checkBetween success" {- success-}--unittest test {- \ Testing.checkBetween(13,13,15)-}---testcase "checkBetween fail" {- crash- require stderr "13"- require stderr "14"- require stderr "15"-}--unittest test {- \ Testing.checkBetween(13,14,15)-}---testcase "checkBetween bad range" {- crash- exclude stderr "14"- require stderr "13"- require stderr "15"-}--unittest test {- \ Testing.checkBetween(14,15,13)-}---testcase "checkGreaterThan success" {- success-}--unittest test {- \ Testing.checkGreaterThan(13,11)-}---testcase "checkGreaterThan fail" {- crash- require stderr "13"- require stderr "14"-}--unittest test {- \ Testing.checkGreaterThan(13,14)-}---testcase "checkLessThan success" {- success-}--unittest test {- \ Testing.checkLessThan(13,14)-}---testcase "checkLessThan fail" {- crash- require stderr "13"- require stderr "11"-}--unittest test {- \ Testing.checkLessThan(13,11)-}---testcase "checkTrue success" {- success-}--unittest test {- \ Testing.checkTrue(1)-}---testcase "checkTrue fail" {- crash- require stderr "true"-}--unittest test {- \ Testing.checkTrue(0)-}---testcase "checkFalse success" {- success-}--unittest test {- \ Testing.checkFalse(0)-}---testcase "checkFalse fail" {- crash- require stderr "false"-}--unittest test {- \ Testing.checkFalse(1)-}
+ lib/testing/test/util.0rt view
@@ -0,0 +1,195 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "IndentAppend" {+ success+}++unittest nothingAppended {+ String result <- IndentAppend.new(String.builder())+ .build()+ .formatted()+ \ Testing.checkEquals(result, "")+}++unittest addNewline {+ String result <- IndentAppend.new(String.builder())+ .addNewline()+ .build()+ .formatted()+ \ Testing.checkEquals(result, "\n")+}++unittest usesNewlines {+ String result <- IndentAppend.new(String.builder())+ .append("message1")+ .append("message2")+ .build()+ .formatted()+ \ Testing.checkEquals(result, "message1\nmessage2\n")+}++unittest indents {+ String result <- IndentAppend.new(String.builder())+ .pushIndent()+ .append("message1")+ .pushIndent()+ .append("message2")+ .popIndent()+ .popIndent()+ .append("message3")+ .build()+ .formatted()+ \ Testing.checkEquals(result, " message1\n message2\nmessage3\n")+}+++testcase "ValueList" {+ success+}++concrete Helper {+ @type new (ValueList<Int>) -> (Helper)++ @value checkNext (Int) -> (Helper)+ @value checkFinished () -> ()+}++define Helper {+ @value optional Order<Int> current++ new (list) {+ return Helper{ list.defaultOrder() }+ }++ checkNext (value) {+ \ Testing.checkEquals(current&.get(), value)+ current <- current&.next()+ return self+ }++ checkFinished () {+ if (`present` current) {+ fail("list not empty")+ }+ }+}++unittest nothingAdded {+ ValueList<Int> list <- ValueList<Int>.new()+ \ Testing.checkEquals(list.isEmpty(), true)+ \ Helper.new(list)+ .checkFinished()+}++unittest withItems {+ ValueList<Int> list <- ValueList<Int>.new()+ .append(1)+ .append(2)+ .append(3)+ \ Testing.checkEquals(list.isEmpty(), false)+ \ Helper.new(list)+ .checkNext(1)+ .checkNext(2)+ .checkNext(3)+ .checkFinished()+}+++testcase "TestHandler skips tracing" {+ failure+ require "message"+ exclude "exitTest"+}++unittest exitTest {+ \ TestHandler:failAndExit("message")+}+++testcase "TestReportTree success" {+ success+}++unittest nothingAdded {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ IndentAppend output <- IndentAppend.new(String.builder())+ \ Testing.checkEquals(report.hasError(), false)+ \ report.prune()&.writeTo(output)+ \ Testing.checkEquals(output.build().formatted(), "")+}++unittest nonFailingSections {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ report.newSection(title: "child1")+ \ report.newSection(title: "child2")+ \ Testing.checkEquals(report.hasError(), false)+ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.prune()&.writeTo(output)+ \ Testing.checkEquals(output.build().formatted(), "")+}+++testcase "TestReportTree prune doesn't include non-failing sections" {+ failure+ require "title"+ require "child2"+ require "message2"+ require "child4"+ require "message4"+ exclude "child1"+ exclude "child5"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ report.newSection(title: "child1")+ \ report.newSection(title: "child2").addError(message: "message2")+ \ report.newSection(title: "child3").addError(message: "message3").discardReport()+ \ report.newSection(title: "child4").addError(message: "message4")+ \ report.newSection(title: "child5")+ \ Testing.checkEquals(report.hasError(), true)+ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.prune()&.writeTo(output)+ \ TestHandler:failAndExit(output.build().formatted())+}+++testcase "TestReportTree unpruned preserves non-failing sections" {+ failure+ require "title"+ require "child1"+ require "child2"+ require "message2"+ require "child4"+ require "message4"+ require "child5"+}++unittest test {+ TestReportTree report <- TestReportTree.new("title", ValueList<Formatted>.new())+ \ report.newSection(title: "child1")+ \ report.newSection(title: "child2").addError(message: "message2")+ \ report.newSection(title: "child3").addError(message: "message3").discardReport()+ \ report.newSection(title: "child4").addError(message: "message4")+ \ report.newSection(title: "child5")+ \ Testing.checkEquals(report.hasError(), true)+ IndentAppend output <- IndentAppend.new(String.builder())+ \ report.writeTo(output)+ \ TestHandler:failAndExit(output.build().formatted())+}
lib/thread/.zeolite-module view
@@ -24,6 +24,12 @@ categories: [EnumeratedBarrier EnumeratedWait] } ]+extension_specs: [+ category {+ name: EnumeratedBarrier+ refines: [ReadAt<BarrierWait>]+ }+] mode: incremental { link_flags: ["-lpthread"] }
lib/thread/barrier.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,6 +16,9 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] +// NOTE: This functionality isn't available on MacOS because MacOS doesn't+// support thread barriers.+ // Waits for a thread barrier. @value interface BarrierWait { // Block until the barrier condition is satisfied.@@ -24,8 +27,6 @@ // A thread barrier validated using thread enumeration. concrete EnumeratedBarrier {- refines ReadAt<BarrierWait>- // Create a new barrier for a fixed number of threads. // // Args:
lib/thread/src/Extension_Enumerated.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -19,7 +19,10 @@ #include <atomic> #include <vector> +#ifndef __APPLE__ #include <pthread.h>+#endif+ #include <string.h> #include "category-source.hpp"@@ -29,6 +32,8 @@ #include "Category_EnumeratedBarrier.hpp" #include "Category_Int.hpp" +#ifndef __APPLE__+ namespace { class Barrier {@@ -97,13 +102,19 @@ } // namespace +#endif+ #ifdef ZEOLITE_PRIVATE_NAMESPACE namespace ZEOLITE_PRIVATE_NAMESPACE { #endif // ZEOLITE_PRIVATE_NAMESPACE +#ifndef __APPLE__+ BoxedValue CreateValue_EnumeratedWait( S<const Type_EnumeratedWait> parent, S<Barrier> b, int i); +#endif+ struct ExtCategory_EnumeratedWait : public Category_EnumeratedWait { }; @@ -111,6 +122,8 @@ inline ExtType_EnumeratedWait(Category_EnumeratedWait& p, Params<0>::Type params) : Type_EnumeratedWait(p, params) {} }; +#ifndef __APPLE__+ struct ExtValue_EnumeratedWait : public Value_EnumeratedWait { inline ExtValue_EnumeratedWait(S<const Type_EnumeratedWait> p, S<Barrier> b, int i) : Value_EnumeratedWait(std::move(p)), barrier(b), index(i) {}@@ -129,6 +142,8 @@ int index; }; +#endif+ Category_EnumeratedWait& CreateCategory_EnumeratedWait() { static auto& category = *new ExtCategory_EnumeratedWait(); return category;@@ -141,11 +156,15 @@ void RemoveType_EnumeratedWait(const Params<0>::Type& params) {} +#ifndef __APPLE__+ BoxedValue CreateValue_EnumeratedWait( S<const Type_EnumeratedWait> parent, S<Barrier> b, int i) { return BoxedValue::New<ExtValue_EnumeratedWait>(std::move(parent), std::move(b), i); } +#endif+ #ifdef ZEOLITE_PRIVATE_NAMESPACE } // namespace ZEOLITE_PRIVATE_NAMESPACE using namespace ZEOLITE_PRIVATE_NAMESPACE;@@ -167,6 +186,9 @@ ReturnTuple Call_new(const ParamsArgs& params_args) const final { TRACE_FUNCTION("EnumeratedBarrier.new")+#ifdef __APPLE__+ FAIL() << "Error creating barriers: BarrierWait not supported on MacOS";+#else const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt(); if (Var_arg1 < 0) { FAIL() << "Invalid barrier thread count " << Var_arg1;@@ -179,6 +201,7 @@ waits.push_back(wait); } return ReturnTuple(CreateValue_EnumeratedBarrier(PARAM_SELF, std::move(waits)));+#endif } };
lib/thread/src/testing.0rx view
@@ -20,15 +20,15 @@ define NoOpRoutine { create () {- return NoOpRoutine{ }+ return delegate -> #self } - run () {}+ run () { } } define CrashRoutine { create () {- return CrashRoutine{ }+ return delegate -> #self } run () {@@ -38,7 +38,7 @@ define InfiniteRoutine { create () {- return InfiniteRoutine{ }+ return delegate -> #self } run () { $NoTrace$
lib/thread/test/barrier.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,12 +17,12 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "EnumeratedBarrier tests" {- success+ success TestChecker } unittest correctCount { ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(13)- \ Testing.checkEquals(barriers.size(),13)+ \ barriers.size() `Matches:with` CheckValue:equals(13) } unittest waitForOneThread {@@ -32,7 +32,7 @@ unittest zeroAllowed { ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(0)- \ Testing.checkEquals(barriers.size(),0)+ \ barriers.size() `Matches:with` CheckValue:equals(0) } unittest waitForMultipleThreads {@@ -40,14 +40,14 @@ Mutex mutex <- SimpleMutex.new() ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(3) - Thread thread1 <- ProcessThread.from(WaitAndIncrement.create(2,value,mutex,barriers.readAt(1))).start()- Thread thread2 <- ProcessThread.from(WaitAndIncrement.create(2,value,mutex,barriers.readAt(2))).start()+ Thread thread1 <- ProcessThread.from(WaitAndIncrement.create(2, value, mutex, barriers.readAt(1))).start()+ Thread thread2 <- ProcessThread.from(WaitAndIncrement.create(2, value, mutex, barriers.readAt(2))).start() \ barriers.readAt(0).wait()- \ Testing.checkEquals(value.get(),2)+ \ value.get() `Matches:with` CheckValue:equals(2) \ barriers.readAt(0).wait()- \ Testing.checkEquals(value.get(),4)+ \ value.get() `Matches:with` CheckValue:equals(4) \ thread1.join() \ thread2.join()@@ -56,7 +56,7 @@ concrete WaitAndIncrement { refines Routine - @type create (Int,Value,Mutex,BarrierWait) -> (WaitAndIncrement)+ @type create (Int, Value, Mutex, BarrierWait) -> (WaitAndIncrement) } define WaitAndIncrement {@@ -65,7 +65,7 @@ @value Mutex mutex @value BarrierWait barrier - create (count,value,mutex,barrier) {+ create (count, value, mutex, barrier) { return WaitAndIncrement{ count, value, mutex, barrier } } @@ -73,7 +73,7 @@ scoped { Int i <- 0 } in while (i < count) {- $Hidden[i,count]$+ $Hidden[i, count]$ scoped { MutexLock lock <- MutexLock.lock(mutex) } cleanup {@@ -92,7 +92,7 @@ testcase "EnumeratedBarrier crashes with negative count" {- crash+ failure require "-4" } @@ -102,7 +102,7 @@ testcase "wait() crashes when references are lost" {- crash+ failure require "BarrierWait.*destroyed" } @@ -115,7 +115,7 @@ testcase "references lost during wait() causes crash" {- crash+ failure require "BarrierWait.*waiting" } @@ -149,7 +149,7 @@ testcase "wait() crashes when two threads use same BarrierWait" {- crash+ failure require "BarrierWait.*in use" }
lib/thread/test/condition.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,15 +17,15 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "ThreadCondition tests" {- success+ success TestChecker } unittest resumeAll { Value value <- Value.create() ThreadCondition cond <- ThreadCondition.new() - Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()- Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()+ Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value, cond)).start()+ Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value, cond)).start() // Wait for both threads to increment Value once, to indicate readiness. while (true) {@@ -42,15 +42,15 @@ \ thread1.join() \ thread2.join() - \ Testing.checkEquals(value.get(),4)+ \ value.get() `Matches:with` CheckValue:equals(4) } unittest resumeOne { Value value <- Value.create() ThreadCondition cond <- ThreadCondition.new() - Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()- Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()+ Thread thread1 <- ProcessThread.from(WaitAndUpdate.create(value, cond)).start()+ Thread thread2 <- ProcessThread.from(WaitAndUpdate.create(value, cond)).start() \ Realtime.sleepSeconds(0.01) @@ -69,20 +69,20 @@ \ thread1.join() \ thread2.join() - \ Testing.checkEquals(value.get(),3)+ \ value.get() `Matches:with` CheckValue:equals(3) } unittest forceWaitTimeout { Value value <- Value.create() ThreadCondition cond <- ThreadCondition.new() - Thread thread <- ProcessThread.from(WaitAndUpdate.create(value,cond)).start()+ Thread thread <- ProcessThread.from(WaitAndUpdate.create(value, cond)).start() \ Realtime.sleepSeconds(0.2) \ cond.resumeOne() \ thread.join() - \ Testing.checkEquals(value.get(),1)+ \ value.get() `Matches:with` CheckValue:equals(1) } unittest waitNoTimeout {@@ -121,14 +121,14 @@ concrete WaitAndUpdate { refines Routine - @type create (Value,ConditionWait) -> (WaitAndUpdate)+ @type create (Value, ConditionWait) -> (WaitAndUpdate) } define WaitAndUpdate { @value Value value @value ConditionWait cond - create (value,cond) {+ create (value, cond) { return WaitAndUpdate{ value, cond } } @@ -150,7 +150,7 @@ testcase "wait() crashes if not locked first" {- crash+ failure require "waiting for condition" } @@ -160,7 +160,7 @@ testcase "timedWait() crashes if not locked first" {- crash+ failure require "waiting for condition" } @@ -170,7 +170,7 @@ testcase "timedWait() crashes with negative wait" {- crash+ failure require "-0\.1" }
lib/thread/test/thread.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021-2022 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,16 +17,16 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "simple Thread test" {- success+ success TestChecker } unittest test { CountLoop counter <- CountLoop.create(10000)- \ Testing.checkEquals(counter.get(),0)+ \ counter.get() `Matches:with` CheckValue:equals(0) \ counter.start()- \ Testing.checkEquals(counter.get(),10000)+ \ counter.get() `Matches:with` CheckValue:equals(10000) \ counter.start()- \ Testing.checkEquals(counter.get(),20000)+ \ counter.get() `Matches:with` CheckValue:equals(20000) } concrete CountLoop {@@ -79,17 +79,17 @@ testcase "ProcessThread mutex integration test" {- success+ success TestChecker } unittest test { Mutex mutex <- SimpleMutex.new() Value value <- Value.create()- Thread evenThread <- ProcessThread.from(EvenOrOdd.create(mutex,true, 10,value)).start()- Thread oddThread <- ProcessThread.from(EvenOrOdd.create(mutex,false,10,value)).start()+ Thread evenThread <- ProcessThread.from(EvenOrOdd.create(mutex, true, 10, value)).start()+ Thread oddThread <- ProcessThread.from(EvenOrOdd.create(mutex, false, 10, value)).start() \ evenThread.join() \ oddThread.join()- \ Testing.checkEquals(value.get(),20)+ \ value.get() `Matches:with` CheckValue:equals(20) } concrete EvenOrOdd {@@ -100,7 +100,7 @@ // - Bool: Increment only on even if true, or on odd if false. // - Int: Number of increment operations. // - Value: Value to increment.- @type create (Mutex,Bool,Int,Value) -> (Routine)+ @type create (Mutex, Bool, Int, Value) -> (Routine) } define EvenOrOdd {@@ -109,7 +109,7 @@ @value Int count @value Value value - create (m,e,c,v) {+ create (m, e, c, v) { return EvenOrOdd{ m, e, c, v } } @@ -143,7 +143,7 @@ testcase "Argv available in Thread" {- success+ success TestChecker args "arg1" } @@ -163,13 +163,13 @@ } run () {- \ Testing.checkEquals(Argv.global().readAt(1),"arg1")+ \ Argv.global().readAt(1) `Matches:with` CheckValue:equals("arg1") } } testcase "join() crashes if Thread not started yet" {- crash+ failure require "thread.*started" } @@ -188,7 +188,7 @@ testcase "join() twice crashes" {- crash+ failure require "thread.*started" } @@ -198,7 +198,7 @@ testcase "detach() crashes if Thread not started yet" {- crash+ failure require "thread.*started" } @@ -217,7 +217,7 @@ testcase "detach() twice crashes" {- crash+ failure require "thread.*started" } @@ -246,7 +246,7 @@ testcase "creation tracing in Thread" {- crash+ failure // Thread creation. require "CrashThread\.new" // Inherited trace from start call.
lib/util/.zeolite-module view
@@ -10,7 +10,7 @@ expression: \x1000 } ]-private_deps: [+public_deps: [ "lib/testing" ] extra_files: [@@ -43,4 +43,4 @@ categories: [SpinlockMutex] } ]-mode: incremental {}+mode: incremental { }
lib/util/counters.0rp view
@@ -31,7 +31,7 @@ // Creates an Order<#x> that repeats a single value, for use with traverse. concrete Repeat<#x> { // Repeat the value the specified number of times.- @category times<#y> (#y,Int) -> (optional Order<#y>)+ @category times<#y> (#y, Int) -> (optional Order<#y>) // Repeat the value an unlimited number of times. @category unlimited<#y> (#y) -> (optional Order<#y>) }@@ -41,17 +41,17 @@ // Get the lower value. (Defaults to the first value.) @category min<#x> #x defines LessThan<#x>- (#x,#x) -> (#x)+ (#x, #x) -> (#x) // Get the higher value. (Defaults to the second value.) @category max<#x> #x defines LessThan<#x>- (#x,#x) -> (#x)+ (#x, #x) -> (#x) // Determine the lower and higher values. (Defaults to the same order.) @category minMax<#x> #x defines LessThan<#x>- (#x,#x) -> (#x,#x)+ (#x, #x) -> (#x, #x) } // Builds a sequence of values.
lib/util/extra.0rp view
@@ -63,6 +63,8 @@ // Get the contained value. Crashes if there is no value. @value getValue () -> (#x)+ // Get the contained value. Returns empty if there is no value.+ @value tryValue () -> (optional #x) // Get the error message. Crashes if there is no error. @value getError () -> (Formatted) // Convert the error to any other ErrorOr type. Crashes if there is no error.@@ -81,7 +83,7 @@ // Notes: // - When used in unit tests, arg 0 is "testcase" and the remaining args are // set from args in the testcase. (See extra.0rt.)- @type global () -> ([ReadAt<String>&SubSequence])+ @type global () -> ([ReadAt<String> & SubSequence]) } // A resource that requires explicit cleanup.
lib/util/helpers.0rp view
@@ -29,7 +29,7 @@ // Bool lt <- x.defaultOrder() `OrderH:lessThan` y.defaultOrder() @category lessThan<#x> #x defines LessThan<#x>- (optional Order<#x>,optional Order<#x>) -> (Bool)+ (optional Order<#x>, optional Order<#x>) -> (Bool) // The same as lessThan, but with a custom comparator. //@@ -39,10 +39,10 @@ // // Example: //- // Bool lt <- x.defaultOrder() `OrderH:lessThanWith<?,Reversed<Int>>` y.defaultOrder()- @category lessThanWith<#x,#xx>+ // Bool lt <- x.defaultOrder() `OrderH:lessThanWith<?, Reversed<Int>>` y.defaultOrder()+ @category lessThanWith<#x, #xx> #xx defines LessThan<#x>- (optional Order<#x>,optional Order<#x>) -> (Bool)+ (optional Order<#x>, optional Order<#x>) -> (Bool) // Extend equals, based on position-wise comparisons. //@@ -51,7 +51,7 @@ // Bool eq <- x.defaultOrder() `OrderH:equals` y.defaultOrder() @category equals<#x> #x defines Equals<#x>- (optional Order<#x>,optional Order<#x>) -> (Bool)+ (optional Order<#x>, optional Order<#x>) -> (Bool) // The same as equals, but with a custom comparator. //@@ -61,10 +61,10 @@ // // Example: //- // Bool eq <- x.defaultOrder() `OrderH:equalsWith<?,BySize>` y.defaultOrder()- @category equalsWith<#x,#xx>+ // Bool eq <- x.defaultOrder() `OrderH:equalsWith<?, BySize>` y.defaultOrder()+ @category equalsWith<#x, #xx> #xx defines Equals<#x>- (optional Order<#x>,optional Order<#x>) -> (Bool)+ (optional Order<#x>, optional Order<#x>) -> (Bool) // Copies references to all elements to the destination. //@@ -78,9 +78,9 @@ // // Returns: // - #c: The container originally passed.- @category copyTo<#x,#c>+ @category copyTo<#x, #c> #c requires Append<#x>- (optional Order<#x>,#c) -> (#c)+ (optional Order<#x>, #c) -> (#c) // Duplicates all elements to the destination. //@@ -94,10 +94,10 @@ // // Returns: // - #c: The container originally passed.- @category duplicateTo<#x,#c>+ @category duplicateTo<#x, #c> #x requires Duplicate #c requires Append<#x>- (optional Order<#x>,#c) -> (#c)+ (optional Order<#x>, #c) -> (#c) } // Helpers to extend functionality to the ReadAt<#x> built-in.@@ -113,7 +113,7 @@ // Bool lt <- x `ReadAtH:lessThan` y @category lessThan<#x> #x defines LessThan<#x>- (ReadAt<#x>,ReadAt<#x>) -> (Bool)+ (ReadAt<#x>, ReadAt<#x>) -> (Bool) // The same as lessThan, but with a custom comparator. //@@ -123,10 +123,10 @@ // // Example: //- // Bool lt <- x `ReadAtH:lessThanWith<?,Reversed<Int>>` y- @category lessThanWith<#x,#xx>+ // Bool lt <- x `ReadAtH:lessThanWith<?, Reversed<Int>>` y+ @category lessThanWith<#x, #xx> #xx defines LessThan<#x>- (ReadAt<#x>,ReadAt<#x>) -> (Bool)+ (ReadAt<#x>, ReadAt<#x>) -> (Bool) // Extend equals, based on position-wise comparisons. //@@ -135,7 +135,7 @@ // Bool eq <- x `ReadAtH:equals` y @category equals<#x> #x defines Equals<#x>- (ReadAt<#x>,ReadAt<#x>) -> (Bool)+ (ReadAt<#x>, ReadAt<#x>) -> (Bool) // The same as equals, but with a custom comparator. //@@ -145,10 +145,10 @@ // // Example: //- // Bool eq <- x `ReadAtH:equalsWith<?,BySize>` y- @category equalsWith<#x,#xx>+ // Bool eq <- x `ReadAtH:equalsWith<?, BySize>` y+ @category equalsWith<#x, #xx> #xx defines Equals<#x>- (ReadAt<#x>,ReadAt<#x>) -> (Bool)+ (ReadAt<#x>, ReadAt<#x>) -> (Bool) // Copies references to all elements to the destination. //@@ -162,9 +162,9 @@ // // Returns: // - #c: The container originally passed.- @category copyTo<#x,#c>+ @category copyTo<#x, #c> #c requires Append<#x>- (ReadAt<#x>,#c) -> (#c)+ (ReadAt<#x>, #c) -> (#c) // Duplicates all elements to the destination. //@@ -178,10 +178,10 @@ // // Returns: // - #c: The container originally passed.- @category duplicateTo<#x,#c>+ @category duplicateTo<#x, #c> #x requires Duplicate #c requires Append<#x>- (ReadAt<#x>,#c) -> (#c)+ (ReadAt<#x>, #c) -> (#c) // Iterates over the container from 0 to the end. @category forwardOrder<#x> (ReadAt<#x>) -> (optional Order<#x>)@@ -190,7 +190,7 @@ @category reverseOrder<#x> (ReadAt<#x>) -> (optional Order<#x>) // Iterates over the container using the provided index order.- @category iterateWith<#x> (ReadAt<#x>,optional Order<Int>) -> (optional Order<#x>)+ @category iterateWith<#x> (ReadAt<#x>, optional Order<Int>) -> (optional Order<#x>) } // Helpers to extend functionality to the Formatted built-in.
lib/util/interfaces.0rp view
@@ -18,5 +18,5 @@ // A @value version of the LessThan @type interface. @value interface LessThan2<#x|> {- lessThan2 (#x,#x) -> (Bool)+ lessThan2 (#x, #x) -> (Bool) }
lib/util/src/counters.0rx view
@@ -64,7 +64,7 @@ actualStart <- start + increment*(require(actualCount)-1) actualIncrement <- -increment }- return IntCounter.new(actualStart,actualIncrement,actualCount)+ return IntCounter.new(actualStart, actualIncrement, actualCount) } start (x) {@@ -96,7 +96,7 @@ } concrete IntCounter {- @type new (Int,Int,optional Int) -> (optional Order<Int>)+ @type new (Int, Int, optional Int) -> (optional Order<Int>) } define IntCounter {@@ -108,11 +108,11 @@ @value Int increment @value optional Int remaining - new (start,increment,count) {+ new (start, increment, count) { if (`present` count && `require` count <= 0) { return empty } else {- return #self{ start, increment, count }+ return delegate -> #self } } @@ -141,7 +141,7 @@ @value #x value @value Order<any> counter - times (value,max) {+ times (value, max) { optional Order<any> counter <- Counter.builder().count(max).done() if (! `present` counter) { return empty@@ -170,15 +170,15 @@ } define Ranges {- min (x,y) {- return minMax(x,y){0}+ min (x, y) {+ return minMax(x, y){0} } - max (x,y) (z) {- return minMax(x,y){1}+ max (x, y) (z) {+ return minMax(x, y){1} } - minMax (x,y) {+ minMax (x, y) { // NOTE: Using y < x makes the default x, y when they are equal. if (y `#x.lessThan` x) { return y, x
lib/util/src/extra.0rx view
@@ -31,11 +31,11 @@ return "Void" } - equals (_,_) {+ equals (_, _) { return true } - lessThan (_,_) {+ lessThan (_, _) { return false } @@ -67,7 +67,7 @@ fail("container is always empty") } - writeAt (_,_) {+ writeAt (_, _) { fail("container is always empty") } }@@ -96,13 +96,17 @@ } } + tryValue () {+ return maybeValue+ }+ getError () { return require(maybeError) } convertError () { scoped {- optional ErrorOr<all> error <- reduce<#self,ErrorOr<all>>(self)+ optional ErrorOr<all> error <- reduce<#self, ErrorOr<all>>(self) } in if (present(error)) { return require(error) } else {
lib/util/src/helpers.0rx view
@@ -17,16 +17,16 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define OrderH {- lessThan (x,y) {- return lessThanWith<#x,#x>(x,y)+ lessThan (x, y) {+ return lessThanWith<#x, #x>(x, y) } - lessThanWith (x,y) {+ lessThanWith (x, y) { optional Order<#x> xx <- x optional Order<#x> yy <- y- $Hidden[x,y]$+ $Hidden[x, y]$ while (present(xx) && present(yy)) {- $ReadOnly[xx,yy]$+ $ReadOnly[xx, yy]$ if (require(xx).get() `#xx.lessThan` require(yy).get()) { return true } elif (require(yy).get() `#xx.lessThan` require(xx).get()) {@@ -39,16 +39,16 @@ return present(yy) } - equals (x,y) {- return equalsWith<#x,#x>(x,y)+ equals (x, y) {+ return equalsWith<#x, #x>(x, y) } - equalsWith (x,y) {+ equalsWith (x, y) { optional Order<#x> xx <- x optional Order<#x> yy <- y- $Hidden[x,y]$+ $Hidden[x, y]$ while (present(xx) && present(yy)) {- $ReadOnly[xx,yy]$+ $ReadOnly[xx, yy]$ if (!(require(xx).get() `#xx.equals` require(yy).get())) { return false }@@ -59,7 +59,7 @@ return !present(xx) && !present(yy) } - copyTo (input,output) (original) {+ copyTo (input, output) (original) { original <- output $Hidden[original]$ traverse (input -> #x value) {@@ -67,7 +67,7 @@ } } - duplicateTo (input,output) (original) {+ duplicateTo (input, output) (original) { original <- output $Hidden[original]$ traverse (input -> #x value) {@@ -77,11 +77,11 @@ } define ReadAtH {- lessThan (x,y) {- return lessThanWith<#x,#x>(x,y)+ lessThan (x, y) {+ return lessThanWith<#x, #x>(x, y) } - lessThanWith (x,y) {+ lessThanWith (x, y) { traverse (`Counter.zeroIndexed` (x.size() `Ranges:min` y.size()) -> Int i) { $ReadOnly[i]$ if (x.readAt(i) `#xx.lessThan` y.readAt(i)) {@@ -93,11 +93,11 @@ return x.size() < y.size() } - equals (x,y) {- return equalsWith<#x,#x>(x,y)+ equals (x, y) {+ return equalsWith<#x, #x>(x, y) } - equalsWith (x,y) {+ equalsWith (x, y) { if (x.size() != y.size()) { return false }@@ -110,7 +110,7 @@ return true } - copyTo (input,output) (original) {+ copyTo (input, output) (original) { original <- output $Hidden[original]$ traverse (`Counter.zeroIndexed` input.size() -> Int i) {@@ -118,7 +118,7 @@ } } - duplicateTo (input,output) (original) {+ duplicateTo (input, output) (original) { original <- output $Hidden[original]$ traverse (`Counter.zeroIndexed` input.size() -> Int i) {@@ -134,7 +134,7 @@ return input `iterateWith` `Counter.revZeroIndexed` input.size() } - iterateWith (input,order) {+ iterateWith (input, order) { return input `IndexOrder:iterateWith` order } }@@ -143,7 +143,7 @@ try (x) { if (present(x)) { scoped {- optional Formatted formatted <- reduce<#x,Formatted>(x)+ optional Formatted formatted <- reduce<#x, Formatted>(x) } in if (present(formatted)) { return require(formatted) } else {@@ -164,7 +164,7 @@ concrete IndexOrder<#x> { refines Order<#x> - @category iterateWith<#x> (ReadAt<#x>,optional Order<Int>) -> (optional Order<#x>)+ @category iterateWith<#x> (ReadAt<#x>, optional Order<Int>) -> (optional Order<#x>) } define IndexOrder {@@ -173,7 +173,7 @@ @value ReadAt<#x> container @value Order<Int> index - iterateWith (container,index) {+ iterateWith (container, index) { if (`present` index) { return IndexOrder<#x>{ container, `require` index } } else {@@ -198,27 +198,27 @@ } define Reversed {- lessThan (x,y) {+ lessThan (x, y) { return y `#x.lessThan` x } } define BySize {- equals (x,y) {+ equals (x, y) { return x.size() == y.size() } - lessThan (x,y) {+ lessThan (x, y) { return x.size() < y.size() } } define AlwaysEqual {- equals (_,_) {+ equals (_, _) { return true } - lessThan (_,_) {+ lessThan (_, _) { return false } }@@ -227,10 +227,10 @@ refines LessThan2<#x> new () {- return #self{ }+ return delegate -> #self } - lessThan2 (x,y) {+ lessThan2 (x, y) { return x `#xx.lessThan` y } }
lib/util/src/input.0rx view
@@ -25,7 +25,7 @@ } readAll (reader) {- [Append<Formatted>&Build<String>] builder <- String.builder()+ [Append<Formatted> & Build<String>] builder <- String.builder() while (!reader.pastEnd()) { \ builder.append(reader.readBlock($ExprLookup[BLOCK_READ_SIZE]$)) }@@ -69,8 +69,8 @@ @value takeLine (Int) -> (String) takeLine (position) {- String data <- buffer.subSequence(0,position)- buffer <- buffer.subSequence(position+1,buffer.size()-position-1)+ String data <- buffer.subSequence(0, position)+ buffer <- buffer.subSequence(position+1, buffer.size()-position-1) return data } }
lib/util/src/parse.0rx view
@@ -95,7 +95,7 @@ } total <- sign*total- $Hidden[sign,hasDigit]$+ $Hidden[sign, hasDigit]$ Int expSign <- 0 Int exp <- 0@@ -107,7 +107,7 @@ Char c <- require(curr).get() curr <- require(curr).next() $ReadOnly[c]$- $Hidden[curr,total]$+ $Hidden[curr, total]$ if (expSign == 0) { if (c == '-') { expSign <- -1
lib/util/src/testing.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,43 +16,74 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -$TestsOnly$+define CheckErrorOr {+ $ReadOnlyExcept[]$ -define UtilTesting {- checkError (x) {- if (!x.isError()) {- fail(String.builder()- .append("expected an error but got value ")- .append(x.getValue())- .build())- }+ refines ValueMatcher<ErrorOr<#x>>++ @value optional ValueMatcher<#x> valueMatcher+ @value optional ValueMatcher<String> errorMatcher++ value (valueMatcher) {+ return CheckErrorOr<#x>{ valueMatcher, empty } } - checkSuccess (x,y) {- if (x.isError()) {- fail(String.builder()- .append("expected ")- .append(y)- .append(" but got error ")- .append(x.getError())- .build())- } else {- \ Testing.checkEquals(x.getValue(),y)+ error (errorMatcher) {+ return CheckErrorOr<any>{ empty, errorMatcher }+ }++ check (actual, report) {+ optional #x value <- empty+ if (`present` actual && !require(actual).isError()) {+ value <- require(actual).getValue() }+ optional String error <- empty+ if (`present` actual && require(actual).isError()) {+ error <- require(actual).getError().formatted()+ }+ MultiChecker checker <- MultiChecker.new(report)+ if (`present` valueMatcher) {+ \ checker.tryCheck(title: "value", value, require(valueMatcher))+ } elif (`present` value) {+ optional Formatted formattedValue <- reduce<#y, ErrorOr<Formatted>>(actual)&.getValue()+ if (`present` formattedValue) {+ \ report.newSection(title: "value")+ .addError(message: String.builder()+ .append("expected empty but got \"")+ .append(`require` formattedValue)+ .append("\"")+ .build())+ } else {+ \ report.newSection(title: "value")+ .addError(message: String.builder()+ .append("expected empty but got ")+ .append(typename<#y>())+ .build())+ }+ }+ if (`present` errorMatcher) {+ \ checker.tryCheck(title: "error", error, require(errorMatcher))+ } elif (`present` error) {+ \ report.newSection(title: "error")+ .addError(message: String.builder()+ .append("expected empty but got \"")+ .append(require(error).formatted())+ .append("\"")+ .build())+ } } - checkSuccessBetween (x,l,h) {- if (x.isError()) {- fail(String.builder()- .append("expected value between ")- .append(l)- .append(" and ")- .append(h)- .append(" but got error ")- .append(x.getError())- .build())+ summary () {+ if (present(valueMatcher)) {+ return String.builder()+ .append(typename<ErrorOr<#x>>())+ .append(" has matching value")+ .build() } else {- \ Testing.checkBetween(x.getValue(),l,h)+ return String.builder()+ .append(typename<ErrorOr<#x>>())+ .append(" has error")+ .build() } } }
lib/util/test/counters.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021-2022 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,18 +17,18 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "counter tests" {- success+ success TestChecker } unittest zeroIndexed { Int index <- 0 traverse (Counter.zeroIndexed(10) -> Int i) {- \ Testing.checkEquals(i,index)+ \ i `Matches:with` CheckValue:equals(index) index <- index+1 } - \ Testing.checkEquals(index,10)+ \ index `Matches:with` CheckValue:equals(10) } unittest zeroIndexedEmpty {@@ -41,11 +41,11 @@ Int index <- 9 traverse (Counter.revZeroIndexed(10) -> Int i) {- \ Testing.checkEquals(i,index)+ \ i `Matches:with` CheckValue:equals(index) index <- index-1 } - \ Testing.checkEquals(index,-1)+ \ index `Matches:with` CheckValue:equals(-1) } unittest revZeroIndexedEmpty {@@ -58,13 +58,13 @@ Int index <- 0 traverse (Counter.unlimited() -> Int i) {- \ Testing.checkEquals(i,index)+ \ i `Matches:with` CheckValue:equals(index) if ((index <- index+1) >= 10) { break } } - \ Testing.checkEquals(index,10)+ \ index `Matches:with` CheckValue:equals(10) } unittest builderReversePositive {@@ -77,11 +77,11 @@ .limit(17) .reverse() .done() -> Int i) {- \ Testing.checkEquals(i,index)+ \ i `Matches:with` CheckValue:equals(index) index <- index-5 } - \ Testing.checkEquals(index,-2)+ \ index `Matches:with` CheckValue:equals(-2) } unittest builderReverseNegative {@@ -94,22 +94,22 @@ .limit(3) .reverse() .done() -> Int i) {- \ Testing.checkEquals(i,index)+ \ i `Matches:with` CheckValue:equals(index) index <- index+5 } - \ Testing.checkEquals(index,22)+ \ index `Matches:with` CheckValue:equals(22) } unittest times { Int index <- 0 traverse ("message" `Repeat:times` 10 -> String m) {- \ Testing.checkEquals(m,"message")+ \ m `Matches:with` CheckValue:equals("message") index <- index+1 } - \ Testing.checkEquals(index,10)+ \ index `Matches:with` CheckValue:equals(10) } unittest timesEmpty {@@ -122,47 +122,47 @@ Int index <- 0 traverse (Repeat:unlimited("message") -> String m) {- \ Testing.checkEquals(m,"message")+ \ m `Matches:with` CheckValue:equals("message") if ((index <- index+1) >= 10) { break } } - \ Testing.checkEquals(index,10)+ \ index `Matches:with` CheckValue:equals(10) } unittest minMax { scoped {- Int x, Int y <- Ranges:minMax(10,3)+ Int x, Int y <- Ranges:minMax(10, 3) } in {- \ Testing.checkEquals(x,3)- \ Testing.checkEquals(y,10)+ \ x `Matches:with` CheckValue:equals(3)+ \ y `Matches:with` CheckValue:equals(10) } scoped {- Int x, Int y <- Ranges:minMax(3,10)+ Int x, Int y <- Ranges:minMax(3, 10) } in {- \ Testing.checkEquals(x,3)- \ Testing.checkEquals(y,10)+ \ x `Matches:with` CheckValue:equals(3)+ \ y `Matches:with` CheckValue:equals(10) } } unittest min { scoped {- Int x <- Ranges:min(10,3)- } in \ Testing.checkEquals(x,3)+ Int x <- Ranges:min(10, 3)+ } in \ x `Matches:with` CheckValue:equals(3) scoped {- Int x <- Ranges:min(3,10)- } in \ Testing.checkEquals(x,3)+ Int x <- Ranges:min(3, 10)+ } in \ x `Matches:with` CheckValue:equals(3) } unittest max { scoped {- Int x <- Ranges:max(10,3)- } in \ Testing.checkEquals(x,10)+ Int x <- Ranges:max(10, 3)+ } in \ x `Matches:with` CheckValue:equals(10) scoped {- Int x <- Ranges:max(3,10)- } in \ Testing.checkEquals(x,10)+ Int x <- Ranges:max(3, 10)+ } in \ x `Matches:with` CheckValue:equals(10) }
lib/util/test/extra.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,31 +17,31 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "Argv checks" {- success+ success TestChecker args "arg1" "arg2" "arg3" "arg4" } unittest global { Int count <- Argv.global().size()- \ Testing.checkEquals(count,5)- \ Testing.checkEquals(Argv.global().readAt(0),"testcase")- \ Testing.checkEquals(Argv.global().readAt(1),"arg1")- \ Testing.checkEquals(Argv.global().readAt(2),"arg2")- \ Testing.checkEquals(Argv.global().readAt(3),"arg3")- \ Testing.checkEquals(Argv.global().readAt(4),"arg4")+ \ count `Matches:with` CheckValue:equals(5)+ \ Argv.global().readAt(0) `Matches:with` CheckValue:equals("testcase")+ \ Argv.global().readAt(1) `Matches:with` CheckValue:equals("arg1")+ \ Argv.global().readAt(2) `Matches:with` CheckValue:equals("arg2")+ \ Argv.global().readAt(3) `Matches:with` CheckValue:equals("arg3")+ \ Argv.global().readAt(4) `Matches:with` CheckValue:equals("arg4") } unittest subSequence {- ReadAt<String> argv <- Argv.global().subSequence(2,2)+ ReadAt<String> argv <- Argv.global().subSequence(2, 2) Int count <- argv.size()- \ Testing.checkEquals(count,2)- \ Testing.checkEquals(argv.readAt(0),"arg2")- \ Testing.checkEquals(argv.readAt(1),"arg3")+ \ count `Matches:with` CheckValue:equals(2)+ \ argv.readAt(0) `Matches:with` CheckValue:equals("arg2")+ \ argv.readAt(1) `Matches:with` CheckValue:equals("arg3") } testcase "Argv readAt out of bounds" {- crash+ failure require "index 5" } @@ -51,41 +51,43 @@ testcase "Argv subSequence out of bounds" {- crash+ failure require "index 5" } unittest test {- \ Argv.global().subSequence(5,1)+ \ Argv.global().subSequence(5, 1) } testcase "ErrorOr checks" {- success+ success TestChecker } unittest withValue { ErrorOr<Int> value <- ErrorOr:value<Int>(10)- \ Testing.checkFalse(value.isError())- \ Testing.checkEquals(value.getValue(),10)+ \ value.isError() `Matches:with` CheckValue:equals(false)+ \ value.getValue() `Matches:with` CheckValue:equals(10)+ \ value.tryValue() `Matches:with` CheckValue:equals(10) } unittest withError { ErrorOr<String> value <- ErrorOr:error("error message")- \ Testing.checkTrue(value.isError())- \ Testing.checkEquals(value.getError().formatted(),"error message")+ \ value.isError() `Matches:with` CheckValue:equals(true)+ \ value.tryValue() `Matches:with` CheckValue:equals(empty?String)+ \ value.getError().formatted() `Matches:with` CheckValue:equals("error message") } unittest convertError { scoped { ErrorOr<String> error <- ErrorOr:error("error message") } in ErrorOr<Int> value <- error.convertError()- \ Testing.checkEquals(value.getError().formatted(),"error message")+ \ value.getError().formatted() `Matches:with` CheckValue:equals("error message") } testcase "ErrorOr getError() crashes with value" {- crash+ failure require "empty" } @@ -96,7 +98,7 @@ testcase "ErrorOr getValue() crashes with error" {- crash+ failure require "error message" } @@ -107,7 +109,7 @@ testcase "ErrorOr convertError() crashes with no error" {- crash+ failure require "no error" } @@ -118,28 +120,28 @@ testcase "Void tests" {- success+ success TestChecker } unittest formatted {- \ Testing.checkEquals(Void.default().formatted(),"Void")+ \ Void.default().formatted() `Matches:with` CheckValue:equals("Void") } unittest lessThan {- \ Testing.checkFalse(Void.default() `Void.lessThan` Void.default())+ \ Void.default() `Void.lessThan` Void.default() `Matches:with` CheckValue:equals(false) } unittest equals {- \ Testing.checkTrue(Void.default() `Void.equals` Void.default())+ \ Void.default() `Void.equals` Void.default() `Matches:with` CheckValue:equals(true) } unittest hashed {- \ Testing.checkEquals(Void.default().duplicate().hashed(),Void.default().hashed())+ \ Void.default().duplicate().hashed() `Matches:with` CheckValue:equals(Void.default().hashed()) } testcase "AlwaysEmpty tests" {- success+ success TestChecker } unittest conversions {@@ -148,11 +150,11 @@ } unittest size {- \ Testing.checkEquals(AlwaysEmpty.default().size(),0)+ \ AlwaysEmpty.default().size() `Matches:with` CheckValue:equals(0) } unittest duplicate {- \ Testing.checkEquals(AlwaysEmpty.default().duplicate().size(),0)+ \ AlwaysEmpty.default().duplicate().size() `Matches:with` CheckValue:equals(0) } unittest defaultOrder {@@ -163,7 +165,7 @@ testcase "AlwaysEmpty.readAt fails" {- crash+ failure require "empty" } @@ -173,10 +175,10 @@ testcase "AlwaysEmpty.writeAt fails" {- crash+ failure require "empty" } unittest readAt {- \ AlwaysEmpty.default().writeAt(0,123)+ \ AlwaysEmpty.default().writeAt(0, 123) }
lib/util/test/helpers.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,73 +17,73 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "comparator helper tests" {- success+ success TestChecker } unittest orderHLessThan {- \ Testing.checkFalse("".defaultOrder() `OrderH:lessThan` "".defaultOrder())- \ Testing.checkTrue("a".defaultOrder() `OrderH:lessThan` "abc".defaultOrder())- \ Testing.checkFalse("b".defaultOrder() `OrderH:lessThan` "abc".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:lessThan` "abc".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:lessThan` "a".defaultOrder())- \ Testing.checkTrue("abc".defaultOrder() `OrderH:lessThan` "b".defaultOrder())+ \ "".defaultOrder() `OrderH:lessThan` "".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "a".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "b".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:lessThan` "abc".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:lessThan` "a".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:lessThan` "b".defaultOrder() `Matches:with` CheckValue:equals(true) } unittest orderHLessThanWith {- \ Testing.checkFalse("".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "".defaultOrder())- \ Testing.checkTrue("a".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "abc".defaultOrder())- \ Testing.checkTrue("b".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "abc".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "abc".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "a".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` "b".defaultOrder())+ \ "".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "a".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "abc".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "b".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "abc".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "abc".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "abc".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "a".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:lessThanWith<?, Reversed<Char>>` "b".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest orderHEquals {- \ Testing.checkTrue("".defaultOrder() `OrderH:equals` "".defaultOrder())- \ Testing.checkFalse("a".defaultOrder() `OrderH:equals` "abc".defaultOrder())- \ Testing.checkTrue("abc".defaultOrder() `OrderH:equals` "abc".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:equals` "a".defaultOrder())+ \ "".defaultOrder() `OrderH:equals` "".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "a".defaultOrder() `OrderH:equals` "abc".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:equals` "abc".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "abc".defaultOrder() `OrderH:equals` "a".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest orderHEqualsWith {- \ Testing.checkTrue("".defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` "".defaultOrder())- \ Testing.checkFalse("a".defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` "ABC".defaultOrder())- \ Testing.checkTrue("abc".defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` "ABC".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` "DEF".defaultOrder())- \ Testing.checkFalse("abc".defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` "A".defaultOrder())+ \ "".defaultOrder() `OrderH:equalsWith<?, IgnoreCase>` "".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "a".defaultOrder() `OrderH:equalsWith<?, IgnoreCase>` "ABC".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:equalsWith<?, IgnoreCase>` "ABC".defaultOrder() `Matches:with` CheckValue:equals(true)+ \ "abc".defaultOrder() `OrderH:equalsWith<?, IgnoreCase>` "DEF".defaultOrder() `Matches:with` CheckValue:equals(false)+ \ "abc".defaultOrder() `OrderH:equalsWith<?, IgnoreCase>` "A".defaultOrder() `Matches:with` CheckValue:equals(false) } unittest readAtHLessThan {- \ Testing.checkFalse("" `ReadAtH:lessThan` "")- \ Testing.checkTrue("a" `ReadAtH:lessThan` "abc")- \ Testing.checkFalse("b" `ReadAtH:lessThan` "abc")- \ Testing.checkFalse("abc" `ReadAtH:lessThan` "abc")- \ Testing.checkFalse("abc" `ReadAtH:lessThan` "a")- \ Testing.checkTrue("abc" `ReadAtH:lessThan` "b")+ \ "" `ReadAtH:lessThan` "" `Matches:with` CheckValue:equals(false)+ \ "a" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(true)+ \ "b" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:lessThan` "abc" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:lessThan` "a" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:lessThan` "b" `Matches:with` CheckValue:equals(true) } unittest readAtHLessThanWith {- \ Testing.checkFalse("" `ReadAtH:lessThanWith<?,Reversed<Char>>` "")- \ Testing.checkTrue("a" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc")- \ Testing.checkTrue("b" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc")- \ Testing.checkFalse("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc")- \ Testing.checkFalse("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "a")- \ Testing.checkFalse("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "b")+ \ "" `ReadAtH:lessThanWith<?, Reversed<Char>>` "" `Matches:with` CheckValue:equals(false)+ \ "a" `ReadAtH:lessThanWith<?, Reversed<Char>>` "abc" `Matches:with` CheckValue:equals(true)+ \ "b" `ReadAtH:lessThanWith<?, Reversed<Char>>` "abc" `Matches:with` CheckValue:equals(true)+ \ "abc" `ReadAtH:lessThanWith<?, Reversed<Char>>` "abc" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:lessThanWith<?, Reversed<Char>>` "a" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:lessThanWith<?, Reversed<Char>>` "b" `Matches:with` CheckValue:equals(false) } unittest readAtHEquals {- \ Testing.checkTrue("" `ReadAtH:equals` "")- \ Testing.checkFalse("a" `ReadAtH:equals` "abc")- \ Testing.checkTrue("abc" `ReadAtH:equals` "abc")- \ Testing.checkFalse("abc" `ReadAtH:equals` "a")+ \ "" `ReadAtH:equals` "" `Matches:with` CheckValue:equals(true)+ \ "a" `ReadAtH:equals` "abc" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:equals` "abc" `Matches:with` CheckValue:equals(true)+ \ "abc" `ReadAtH:equals` "a" `Matches:with` CheckValue:equals(false) } unittest readAtHEqualsWith {- \ Testing.checkTrue("" `ReadAtH:equalsWith<?,IgnoreCase>` "")- \ Testing.checkFalse("a" `ReadAtH:equalsWith<?,IgnoreCase>` "ABC")- \ Testing.checkTrue("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "ABC")- \ Testing.checkFalse("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "DEF")- \ Testing.checkFalse("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "a")+ \ "" `ReadAtH:equalsWith<?, IgnoreCase>` "" `Matches:with` CheckValue:equals(true)+ \ "a" `ReadAtH:equalsWith<?, IgnoreCase>` "ABC" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:equalsWith<?, IgnoreCase>` "ABC" `Matches:with` CheckValue:equals(true)+ \ "abc" `ReadAtH:equalsWith<?, IgnoreCase>` "DEF" `Matches:with` CheckValue:equals(false)+ \ "abc" `ReadAtH:equalsWith<?, IgnoreCase>` "a" `Matches:with` CheckValue:equals(false) } concrete IgnoreCase {@@ -91,7 +91,7 @@ } define IgnoreCase {- equals (x,y) {+ equals (x, y) { return toLower(x) == toLower(y) } @@ -106,118 +106,118 @@ } unittest reversed {- \ Testing.checkFalse(0 `Reversed<Int>.lessThan` 0)- \ Testing.checkFalse(0 `Reversed<Int>.lessThan` 1)- \ Testing.checkTrue(1 `Reversed<Int>.lessThan` 0)+ \ 0 `Reversed<Int>.lessThan` 0 `Matches:with` CheckValue:equals(false)+ \ 0 `Reversed<Int>.lessThan` 1 `Matches:with` CheckValue:equals(false)+ \ 1 `Reversed<Int>.lessThan` 0 `Matches:with` CheckValue:equals(true) } unittest bySizeLessThan {- \ Testing.checkFalse("" `BySize.lessThan` "")- \ Testing.checkTrue("b" `BySize.lessThan` "ac")- \ Testing.checkFalse("ac" `BySize.lessThan` "b")- \ Testing.checkFalse("a" `BySize.lessThan` "b")+ \ "" `BySize.lessThan` "" `Matches:with` CheckValue:equals(false)+ \ "b" `BySize.lessThan` "ac" `Matches:with` CheckValue:equals(true)+ \ "ac" `BySize.lessThan` "b" `Matches:with` CheckValue:equals(false)+ \ "a" `BySize.lessThan` "b" `Matches:with` CheckValue:equals(false) } unittest bySizeEquals {- \ Testing.checkTrue("" `BySize.equals` "")- \ Testing.checkFalse("b" `BySize.equals` "ac")- \ Testing.checkFalse("ac" `BySize.equals` "b")- \ Testing.checkTrue("a" `BySize.equals` "b")+ \ "" `BySize.equals` "" `Matches:with` CheckValue:equals(true)+ \ "b" `BySize.equals` "ac" `Matches:with` CheckValue:equals(false)+ \ "ac" `BySize.equals` "b" `Matches:with` CheckValue:equals(false)+ \ "a" `BySize.equals` "b" `Matches:with` CheckValue:equals(true) } unittest alwaysEqualLessThan {- \ Testing.checkFalse("" `AlwaysEqual.lessThan` "")- \ Testing.checkFalse("b" `AlwaysEqual.lessThan` "ac")- \ Testing.checkFalse("ac" `AlwaysEqual.lessThan` "b")+ \ "" `AlwaysEqual.lessThan` "" `Matches:with` CheckValue:equals(false)+ \ "b" `AlwaysEqual.lessThan` "ac" `Matches:with` CheckValue:equals(false)+ \ "ac" `AlwaysEqual.lessThan` "b" `Matches:with` CheckValue:equals(false) } unittest alwaysEqualEquals {- \ Testing.checkTrue("" `AlwaysEqual.equals` "")- \ Testing.checkTrue("b" `AlwaysEqual.equals` "ac")- \ Testing.checkTrue("ac" `AlwaysEqual.equals` "b")- \ Testing.checkTrue("a" `AlwaysEqual.equals` "b")+ \ "" `AlwaysEqual.equals` "" `Matches:with` CheckValue:equals(true)+ \ "b" `AlwaysEqual.equals` "ac" `Matches:with` CheckValue:equals(true)+ \ "ac" `AlwaysEqual.equals` "b" `Matches:with` CheckValue:equals(true)+ \ "a" `AlwaysEqual.equals` "b" `Matches:with` CheckValue:equals(true) } testcase "iteration tests" {- success+ success TestChecker } unittest orderHCopyTo { ValueCheck output <- ValueCheck.new(10)- \ ValueOrder.wrap(false,Counter.zeroIndexed(10)) `OrderH:copyTo` output+ \ ValueOrder.wrap(false, Counter.zeroIndexed(10)) `OrderH:copyTo` output \ output.checkEnd() } unittest orderHDuplicateTo { ValueCheck output <- ValueCheck.new(10)- \ ValueOrder.wrap(true,Counter.zeroIndexed(10)) `OrderH:duplicateTo` output+ \ ValueOrder.wrap(true, Counter.zeroIndexed(10)) `OrderH:duplicateTo` output \ output.checkEnd() } unittest readAtHCopyTo { ValueCheck output <- ValueCheck.new(10)- \ ValueSource.new(false,10) `ReadAtH:copyTo` output+ \ ValueSource.new(false, 10) `ReadAtH:copyTo` output \ output.checkEnd() } unittest readAtHDuplicateTo { ValueCheck output <- ValueCheck.new(10)- \ ValueSource.new(true,10) `ReadAtH:duplicateTo` output+ \ ValueSource.new(true, 10) `ReadAtH:duplicateTo` output \ output.checkEnd() } unittest readAtHForwardOrder {- ValueSource source <- ValueSource.new(false,10)+ ValueSource source <- ValueSource.new(false, 10) Int expected <- 0 traverse (`ReadAtH:forwardOrder` source -> Value actual) {- \ Testing.checkEquals(actual.get(),expected)+ \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected+1 }- \ Testing.checkEquals(expected,10)+ \ expected `Matches:with` CheckValue:equals(10) } unittest readAtHForwardOrderEmpty {- ValueSource source <- ValueSource.new(false,0)+ ValueSource source <- ValueSource.new(false, 0) traverse (`ReadAtH:forwardOrder` source -> _) { fail("not empty") } } unittest readAtHReverseOrder {- ValueSource source <- ValueSource.new(false,10)+ ValueSource source <- ValueSource.new(false, 10) Int expected <- 9 traverse (`ReadAtH:reverseOrder` source -> Value actual) {- \ Testing.checkEquals(actual.get(),expected)+ \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected-1 }- \ Testing.checkEquals(expected,-1)+ \ expected `Matches:with` CheckValue:equals(-1) } unittest readAtHReverseOrderEmpty {- ValueSource source <- ValueSource.new(false,0)+ ValueSource source <- ValueSource.new(false, 0) traverse (`ReadAtH:reverseOrder` source -> _) { fail("not empty") } } unittest readAtHIterateWith {- ValueSource source <- ValueSource.new(false,10)+ ValueSource source <- ValueSource.new(false, 10) Int expected <- 0 traverse (source `ReadAtH:iterateWith` `Counter.zeroIndexed` 5 -> Value actual) {- \ Testing.checkEquals(actual.get(),expected)+ \ actual.get() `Matches:with` CheckValue:equals(expected) } update { expected <- expected+1 }- \ Testing.checkEquals(expected,5)+ \ expected `Matches:with` CheckValue:equals(5) } concrete ValueOrder { refines Order<Value> - @type wrap (Bool,optional Order<Int>) -> (optional Order<Value>)+ @type wrap (Bool, optional Order<Int>) -> (optional Order<Value>) } define ValueOrder {@@ -226,7 +226,7 @@ @value Bool original @value Order<Int> order - wrap (original,order) {+ wrap (original, order) { if (!present(order)) { return empty } else {@@ -245,12 +245,12 @@ } get () {- return Value.new(original,order.get())+ return Value.new(original, order.get()) } } concrete ValueCheck {- // Must append the next value in the sequence [0,size).+ // Must append the next value in the sequence [0, size). refines Append<Value> @type new (Int) -> (ValueCheck)@@ -268,11 +268,11 @@ } checkEnd () {- \ Testing.checkEquals(current,target)+ \ current `Matches:with` CheckValue:equals(target) } append (x) {- \ Testing.checkEquals(x.get(),current)+ \ x.get() `Matches:with` CheckValue:equals(current) current <- current+1 return self }@@ -285,19 +285,19 @@ // Args: // - Bool: Whether or not the value is "original". // - Int: Value to return from get().- @type new (Bool,Int) -> (Value)+ @type new (Bool, Int) -> (Value) // Crashes if "original" is true. @value get () -> (Int) } define Value {- $ReadOnly[original,value]$+ $ReadOnly[original, value]$ @value Bool original @value Int value - new (original,value) {+ new (original, value) { return Value{ original, value } } @@ -317,22 +317,22 @@ } concrete ValueSource {- // readAt(i) returns Value.new(original,i).+ // readAt(i) returns Value.new(original, i). refines ReadAt<Value> // Args: // - Bool: Whether or not to mark new values as "original". // - Int: Total size.- @type new (Bool,Int) -> (ValueSource)+ @type new (Bool, Int) -> (ValueSource) } define ValueSource {- $ReadOnly[original,size]$+ $ReadOnly[original, size]$ @value Bool original @value Int size - new (original,size) {+ new (original, size) { return ValueSource{ original, size } } @@ -341,25 +341,25 @@ } readAt (i) {- \ Testing.checkBetween(i,0,size-1)- return Value.new(original,i)+ \ i `Matches:with` CheckValue:betweenEquals(0, size-1)+ return Value.new(original, i) } } testcase "formatting tests" {- success+ success TestChecker } unittest emptyValue {- \ Testing.checkEquals(FormattedH:try<Char>(empty).formatted(),"Char{empty}")- \ Testing.checkEquals(FormattedH:try(empty).formatted(),"all{empty}")+ \ FormattedH:try<Char>(empty).formatted() `Matches:with` CheckValue:equals("Char{empty}")+ \ FormattedH:try(empty).formatted() `Matches:with` CheckValue:equals("all{empty}") } unittest formattedValue {- \ Testing.checkEquals(FormattedH:try(123).formatted(),"123")+ \ FormattedH:try(123).formatted() `Matches:with` CheckValue:equals("123") } unittest nonFormattedValue {- \ Testing.checkEquals(FormattedH:try(String.builder()).formatted(),"[Append<Formatted>&Build<String>]{?}")+ \ FormattedH:try(String.builder()).formatted() `Matches:with` CheckValue:equals("[Append<Formatted>&Build<String>]{?}") }
lib/util/test/input.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,20 +17,20 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "TextReader checks" {- success+ success TestChecker } concrete Helper {- @type checkNext (TextReader,String) -> ()+ @type checkNext (TextReader, String) -> () } define Helper {- checkNext (reader,line) {+ checkNext (reader, line) { if (reader.pastEnd()) { fail("past end") } String value <- reader.readNextLine()- \ Testing.checkEquals(value,line)+ \ value `Matches:with` CheckValue:equals(line) } } @@ -70,11 +70,11 @@ unittest correctSplit { TextReader reader <- TextReader.fromBlockReader(FakeFile.create())- \ Helper.checkNext(reader,"this is a partial line")- \ Helper.checkNext(reader,"with some more data")- \ Helper.checkNext(reader,"and")- \ Helper.checkNext(reader,"more lines")- \ Helper.checkNext(reader,"unfinished")+ \ Helper.checkNext(reader, "this is a partial line")+ \ Helper.checkNext(reader, "with some more data")+ \ Helper.checkNext(reader, "and")+ \ Helper.checkNext(reader, "more lines")+ \ Helper.checkNext(reader, "unfinished") if (!reader.pastEnd()) { fail("not past end") }@@ -85,15 +85,15 @@ unittest readAll { String allContents <- TextReader.readAll(FakeFile.create())- \ Testing.checkEquals(allContents,"this is a partial line\nwith some more data\nand\nmore lines\nunfinished")+ \ allContents `Matches:with` CheckValue:equals("this is a partial line\nwith some more data\nand\nmore lines\nunfinished") } testcase "stdin is empty in tests" {- success+ success TestChecker timeout 1 } unittest test {- \ Testing.checkEquals(TextReader.readAll(BasicInput.stdin()),"")+ \ TextReader.readAll(BasicInput.stdin()) `Matches:with` CheckValue:equals("") }
lib/util/test/mutex.0rt view
@@ -32,7 +32,7 @@ testcase "MutexLock crashes if not freed" {- crash+ failure require "not freed" } @@ -43,7 +43,7 @@ testcase "MutexLock crashes if freed twice" {- crash+ failure require "freed multiple times" }
lib/util/test/output.0rt view
@@ -47,7 +47,7 @@ testcase "error writer" {- crash+ failure require "message1" require "message2" require "message3"
lib/util/test/parse.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,213 +17,213 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "ParseChars tests" {- success+ success TestChecker } unittest floatNoDecimal {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123"),122.9,123.1)+ \ ParseChars.float("123") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0)) } unittest floatDecimalLeft {- \ UtilTesting.checkSuccessBetween(ParseChars.float(".123"),0.1229,0.1231)+ \ ParseChars.float(".123") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(0.123)) } unittest floatDecimalRight {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123."),122.9,123.1)+ \ ParseChars.float("123.") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0)) } unittest floatDecimalMiddle {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123.456"),123.4559,123.4561)+ \ ParseChars.float("123.456") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.456)) } unittest floatLeadingTrailingZeros {- \ UtilTesting.checkSuccessBetween(ParseChars.float("000123.456000"),123.4559,123.4561)+ \ ParseChars.float("000123.456000") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.456)) } unittest floatNegative {- \ UtilTesting.checkSuccessBetween(ParseChars.float("-123.456"),-123.4561,-123.4559)+ \ ParseChars.float("-123.456") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(-123.456)) } unittest floatPositive {- \ UtilTesting.checkSuccessBetween(ParseChars.float("+123.456"),123.4559,123.4561)+ \ ParseChars.float("+123.456") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.456)) } unittest floatNegativeDecimalLeft {- \ UtilTesting.checkSuccessBetween(ParseChars.float("-.456"),-0.4561,-0.4559)+ \ ParseChars.float("-.456") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(-0.456)) } unittest floatExponentNoDecimal {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123E5"),122.9E5,123.1E5)+ \ ParseChars.float("123E5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0E5)) } unittest floatNegativeExponent {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123E-5"),122.9E-5,123.1E-5)+ \ ParseChars.float("123E-5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0E-5)) } unittest floatPositiveExponent {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123E+5"),122.9E5,123.1E5)+ \ ParseChars.float("123E+5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0E5)) } unittest floatExponentDecimalRight {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123.E5"),122.9E5,123.1E5)+ \ ParseChars.float("123.E5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0E5)) } unittest floatExponentDecimalLeft {- \ UtilTesting.checkSuccessBetween(ParseChars.float(".123E5"),122.9E2,123.1E2)+ \ ParseChars.float(".123E5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.0E2)) } unittest floatExponentDecimalMiddle {- \ UtilTesting.checkSuccessBetween(ParseChars.float("123.456E5"),123.4559E5,123.4561E5)+ \ ParseChars.float("123.456E5") `Matches:with` CheckErrorOr:value(CheckFloat:almostEquals(123.456E5)) } unittest floatEmpty {- \ UtilTesting.checkError(ParseChars.float(""))+ \ ParseChars.float("") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest floatNoDigits {- \ UtilTesting.checkError(ParseChars.float("."))+ \ ParseChars.float(".") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest floatTwoDecimals {- \ UtilTesting.checkError(ParseChars.float("1.1."))+ \ ParseChars.float("1.1.") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest floatExponentNoDigitsNoDecimal {- \ UtilTesting.checkError(ParseChars.float("E5"))+ \ ParseChars.float("E5") `Matches:with` CheckErrorOr:error(CheckString:contains("E")) } unittest floatExponentNoDigitsDecimal {- \ UtilTesting.checkError(ParseChars.float(".E5"))+ \ ParseChars.float(".E5") `Matches:with` CheckErrorOr:error(CheckString:contains("E")) } unittest floatExponentNoDigitsSign {- \ UtilTesting.checkError(ParseChars.float("-E5"))+ \ ParseChars.float("-E5") `Matches:with` CheckErrorOr:error(CheckString:contains("E")) } unittest floatDecimalAfterExponent {- \ UtilTesting.checkError(ParseChars.float("1E.5"))+ \ ParseChars.float("1E.5") `Matches:with` CheckErrorOr:error(CheckString:contains(".")) } unittest floatExponentExcessData {- \ UtilTesting.checkError(ParseChars.float("123E5Q"))+ \ ParseChars.float("123E5Q") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest floatBadCharAfterDigit {- \ UtilTesting.checkError(ParseChars.float("123X"))+ \ ParseChars.float("123X") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest floatMissingExponentDigits {- \ UtilTesting.checkError(ParseChars.float("123E"))+ \ ParseChars.float("123E") `Matches:with` CheckErrorOr:error(CheckString:contains("exponent")) } unittest int {- \ UtilTesting.checkSuccess(ParseChars.int("1234"),1234)+ \ ParseChars.int("1234") `Matches:with` CheckErrorOr:value(CheckValue:equals(1234)) } unittest intNegative {- \ UtilTesting.checkSuccess(ParseChars.int("-1234"),-1234)+ \ ParseChars.int("-1234") `Matches:with` CheckErrorOr:value(CheckValue:equals(-1234)) } unittest intPositive {- \ UtilTesting.checkSuccess(ParseChars.int("+1234"),1234)+ \ ParseChars.int("+1234") `Matches:with` CheckErrorOr:value(CheckValue:equals(1234)) } unittest intLeadingZeros {- \ UtilTesting.checkSuccess(ParseChars.int("001234"),1234)+ \ ParseChars.int("001234") `Matches:with` CheckErrorOr:value(CheckValue:equals(1234)) } unittest intEmpty {- \ UtilTesting.checkError(ParseChars.int(""))+ \ ParseChars.int("") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest intJustSign {- \ UtilTesting.checkError(ParseChars.int("-"))+ \ ParseChars.int("-") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest intBadDigit {- \ UtilTesting.checkError(ParseChars.int("12A"))+ \ ParseChars.int("12A") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest hexInt {- \ UtilTesting.checkSuccess(ParseChars.hexInt("12AbCdEf"),\x12ABCDEF)+ \ ParseChars.hexInt("12AbCdEf") `Matches:with` CheckErrorOr:value(CheckValue:equals(\x12ABCDEF)) } unittest hexIntNegative {- \ UtilTesting.checkSuccess(ParseChars.hexInt("-12AbCdEf"),-\x12ABCDEF)+ \ ParseChars.hexInt("-12AbCdEf") `Matches:with` CheckErrorOr:value(CheckValue:equals(-\x12ABCDEF)) } unittest hexIntPositive {- \ UtilTesting.checkSuccess(ParseChars.hexInt("+12AbCdEf"),\x12ABCDEF)+ \ ParseChars.hexInt("+12AbCdEf") `Matches:with` CheckErrorOr:value(CheckValue:equals(\x12ABCDEF)) } unittest hexIntLeadingZeros {- \ UtilTesting.checkSuccess(ParseChars.hexInt("0012AbCdEf"),\x12ABCDEF)+ \ ParseChars.hexInt("0012AbCdEf") `Matches:with` CheckErrorOr:value(CheckValue:equals(\x12ABCDEF)) } unittest hexIntEmpty {- \ UtilTesting.checkError(ParseChars.hexInt(""))+ \ ParseChars.hexInt("") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest hexIntJustSign {- \ UtilTesting.checkError(ParseChars.hexInt("-"))+ \ ParseChars.hexInt("-") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest hexIntBadDigit {- \ UtilTesting.checkError(ParseChars.hexInt("12Q"))+ \ ParseChars.hexInt("12Q") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest octInt {- \ UtilTesting.checkSuccess(ParseChars.octInt("127"),\o127)+ \ ParseChars.octInt("127") `Matches:with` CheckErrorOr:value(CheckValue:equals(\o127)) } unittest octIntNegative {- \ UtilTesting.checkSuccess(ParseChars.octInt("-127"),-\o127)+ \ ParseChars.octInt("-127") `Matches:with` CheckErrorOr:value(CheckValue:equals(-\o127)) } unittest octIntPositive {- \ UtilTesting.checkSuccess(ParseChars.octInt("+127"),\o127)+ \ ParseChars.octInt("+127") `Matches:with` CheckErrorOr:value(CheckValue:equals(\o127)) } unittest octIntLeadingZeros {- \ UtilTesting.checkSuccess(ParseChars.octInt("00127"),\o127)+ \ ParseChars.octInt("00127") `Matches:with` CheckErrorOr:value(CheckValue:equals(\o127)) } unittest octIntEmpty {- \ UtilTesting.checkError(ParseChars.octInt(""))+ \ ParseChars.octInt("") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest octIntJustSign {- \ UtilTesting.checkError(ParseChars.octInt("-"))+ \ ParseChars.octInt("-") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest octIntBadDigit {- \ UtilTesting.checkError(ParseChars.octInt("19"))+ \ ParseChars.octInt("19") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) } unittest binInt {- \ UtilTesting.checkSuccess(ParseChars.binInt("100101"),\b100101)+ \ ParseChars.binInt("100101") `Matches:with` CheckErrorOr:value(CheckValue:equals(\b100101)) } unittest binIntNegative {- \ UtilTesting.checkSuccess(ParseChars.binInt("-100101"),-\b100101)+ \ ParseChars.binInt("-100101") `Matches:with` CheckErrorOr:value(CheckValue:equals(-\b100101)) } unittest binIntPositive {- \ UtilTesting.checkSuccess(ParseChars.binInt("+100101"),\b100101)+ \ ParseChars.binInt("+100101") `Matches:with` CheckErrorOr:value(CheckValue:equals(\b100101)) } unittest binIntLeadingZeros {- \ UtilTesting.checkSuccess(ParseChars.binInt("00100101"),\b100101)+ \ ParseChars.binInt("00100101") `Matches:with` CheckErrorOr:value(CheckValue:equals(\b100101)) } unittest binIntEmpty {- \ UtilTesting.checkError(ParseChars.binInt(""))+ \ ParseChars.binInt("") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest binIntJustSign {- \ UtilTesting.checkError(ParseChars.binInt("-"))+ \ ParseChars.binInt("-") `Matches:with` CheckErrorOr:error(CheckString:contains("missing digits")) } unittest binIntBadDigit {- \ UtilTesting.checkError(ParseChars.binInt("12"))+ \ ParseChars.binInt("12") `Matches:with` CheckErrorOr:error(CheckString:contains("failed")) }
lib/util/test/testing.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,81 +16,91 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -testcase "UtilTesting.checkError with error" {- success+testcase "CheckErrorOr success" {+ success TestChecker } -unittest test {- \ UtilTesting.checkError(ErrorOr:error("failure"))+unittest value {+ \ ErrorOr:value(123) `Matches:with` CheckErrorOr:value(CheckValue:equals(123)) } +unittest error {+ \ ErrorOr:error("something") `Matches:with` CheckErrorOr:error(CheckValue:equals("something"))+} -testcase "UtilTesting.checkError with value" {- crash- require "message"++testcase "CheckErrorOr:value failure with value" {+ failure TestChecker+ require "456"+ require "123" } unittest test {- \ UtilTesting.checkError(ErrorOr:value("message"))+ \ ErrorOr:value(456) `Matches:with` CheckErrorOr:value(CheckValue:equals(123)) } -testcase "UtilTesting.checkSuccess success" {- success+testcase "CheckErrorOr:value failure with error" {+ failure TestChecker+ require "something"+ require "123" } unittest test {- \ UtilTesting.checkSuccess(ErrorOr:value("message"),"message")+ \ ErrorOr:error("something") `Matches:with` CheckErrorOr:value(CheckValue:equals(123)) } -testcase "UtilTesting.checkSuccess bad value" {- crash- require "message"- require "foo"+testcase "CheckErrorOr:value failure with empty" {+ failure TestChecker+ require "empty"+ require "123" } unittest test {- \ UtilTesting.checkSuccess(ErrorOr:value("foo"),"message")+ \ empty `Matches:with` CheckErrorOr:value(CheckValue:equals(123)) } -testcase "UtilTesting.checkSuccess with error" {- crash- require "message"- require "failure"+testcase "CheckErrorOr:error failure with value" {+ failure TestChecker+ require "456"+ require "something" } unittest test {- \ UtilTesting.checkSuccess(ErrorOr:error("failure"),"message")+ \ ErrorOr:value(456) `Matches:with` CheckErrorOr:error(CheckValue:equals("something")) } -testcase "UtilTesting.checkSuccessBetween success" {- success+testcase "CheckErrorOr:error failure with error" {+ failure TestChecker+ require "message"+ require "something" } unittest test {- \ UtilTesting.checkSuccessBetween(ErrorOr:value(1),0,2)+ \ ErrorOr:error("message") `Matches:with` CheckErrorOr:error(CheckValue:equals("something")) } -testcase "UtilTesting.checkSuccess bad value" {- crash- require "7.+0.*2"+testcase "CheckErrorOr:error failure with empty" {+ failure TestChecker+ require "empty"+ require "something" } unittest test {- \ UtilTesting.checkSuccessBetween(ErrorOr:value(7),0,2)+ \ empty `Matches:with` CheckErrorOr:error(CheckValue:equals("something")) } -testcase "UtilTesting.checkSuccess with error" {- crash- require "0.*2"- require "failure"+testcase "CheckErrorOr:error failure with non-Formatted" {+ failure TestChecker+ require "CharBuffer"+ require "something" } unittest test {- \ UtilTesting.checkSuccessBetween(ErrorOr:error("failure"),0,2)+ \ ErrorOr:value(CharBuffer.new(0)) `Matches:with` CheckErrorOr:error(CheckValue:equals("something")) }
lib/util/test/time.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -38,7 +38,7 @@ testcase "sleepSeconds() does not interfere with test timeout" {- crash+ failure require "signal 14" timeout 1 }@@ -49,7 +49,7 @@ testcase "sleepSecondsPrecise() does not interfere with test timeout" {- crash+ failure require "signal 14" timeout 1 }@@ -60,7 +60,7 @@ testcase "monoSeconds() diff is somewhat accurate" {- success+ success TestChecker timeout 2 } @@ -68,12 +68,12 @@ Float start <- Realtime.monoSeconds() \ Realtime.sleepSeconds(0.5) Float stop <- Realtime.monoSeconds()- \ Testing.checkBetween(stop-start,0.5,0.6)+ \ (stop-start) `Matches:with` CheckValue:betweenEquals(0.5, 0.6) } unittest testPrecise { Float start <- Realtime.monoSeconds() \ Realtime.sleepSecondsPrecise(0.5) Float stop <- Realtime.monoSeconds()- \ Testing.checkBetween(stop-start,0.5,0.51)+ \ (stop-start) `Matches:with` CheckValue:betweenEquals(0.5, 0.51) }
lib/util/testing.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,35 +16,8 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -$TestsOnly$--// General lib/util helpers for use in unit tests.-concrete UtilTesting {- // Check the value for an ErrorOr error. Crashes if it is not an error.- //- // Args:- // - ErrorOr<Formatted>: Actual value.- @type checkError (ErrorOr<Formatted>) -> ()-- // Check the values for equality. Crashes if they are not equal.- //- // Args:- // - ErrorOr<#x>: Actual value.- // - #x: Expected value.- @type checkSuccess<#x>- #x requires Formatted- #x defines Equals<#x>- (ErrorOr<#x>,#x) -> ()-- // Check that the value is within a range. Crashes if it is not in the range.- //- // Args:- // - ErrorOr<#x>: Actual value.- // - #x: Lower bound.- // - #x: Upper bound.- @type checkSuccessBetween<#x>- #x requires Formatted- #x defines Equals<#x>- #x defines LessThan<#x>- (ErrorOr<#x>,#x,#x) -> ()+// Checks the contents of an ErrorOr.+concrete CheckErrorOr<#x> {+ @category value<#x> (ValueMatcher<#x>) -> (ValueMatcher<ErrorOr<#x>>)+ @category error (ValueMatcher<String>) -> (ValueMatcher<ErrorOr<any>>) }
src/Cli/Compiler.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2022 Kevin P. Barry+Copyright 2020-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -49,7 +49,7 @@ import Module.ProcessMetadata import Parser.SourceFile import Parser.TextParser (SourceContext)-import Types.Builtin+import Types.Builtin (requiredStaticTypes) import Types.DefinedCategory import Types.TypeCategory import Types.TypeInstance@@ -288,7 +288,7 @@ let lf' = lf ++ getLinkFlagsForDeps deps2 let os = getObjectFilesForDeps deps2 let ofr = getObjectFileResolver os- let objects = ofr ns2 req+ let objects = ofr ns2 (req `Set.union` requiredStaticTypes) return $ CompileToBinary mainAbs objects [] f0 paths2 lf' getCommand LinkDynamic mainAbs f0 deps2 paths2 = do let objects = getLibrariesForDeps deps2@@ -316,16 +316,16 @@ createModuleTemplates resolver p d ds cm deps1 deps2 = do time <- errorFromIO getCurrentTime (ps,xs,_) <- findSourceFiles p (d:ds)- (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _) <-+ (LanguageModule _ _ _ cs0 ps0 tc0 tp0 cs1 ps1 tc1 tp1 _ _ cm0) <- fmap (createLanguageModule [] Map.empty . fst) $ loadModuleGlobals resolver p (PublicNamespace,PrivateNamespace) ps Nothing deps1 deps2 xs' <- zipWithContents resolver p xs ds2 <- mapCompilerM parseInternalSource xs' let ds3 = concat $ map (\(_,_,d2) -> d2) ds2- tm <- foldM includeNewTypes defaultCategories [cs0,cs1,ps0,ps1,ts0,ts1]- let cs = filter isValueConcrete $ cs1++ps1++ts1+ tm <- foldM includeNewTypes cm0 [cs0,cs1,ps0,ps1,tc0,tp0,tc1,tp1]+ let cs = filter isValueConcrete $ cs1++ps1++tc1++tp1 let ca = Set.fromList $ map getCategoryName $ filter isValueConcrete cs let ca' = foldr Set.delete ca $ map dcName ds3- let testingCats = Set.fromList $ map getCategoryName ts1+ let testingCats = Set.fromList $ (map getCategoryName tc1) ++ (map getCategoryName tp1) ts <- fmap concat $ mapCompilerM (\n -> generate (n `Set.member` testingCats) tm n) $ Set.toList ca' mapCompilerM_ (writeTemplate time) ts where generate testing tm n = do@@ -376,18 +376,22 @@ [WithVisibility (AnyCategory c)] -> LanguageModule c createLanguageModule ss em cs = lm where lm = LanguageModule {- lmPublicNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,without ModuleOnly],- lmPrivateNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,with ModuleOnly],- lmLocalNamespaces = Set.fromList $ map wvData $ apply ns [without FromDependency],- lmPublicDeps = map wvData $ apply cs [with FromDependency,without ModuleOnly,without TestsOnly],- lmPrivateDeps = map wvData $ apply cs [with FromDependency,with ModuleOnly,without TestsOnly],- lmTestingDeps = map wvData $ apply cs [with FromDependency,with TestsOnly],- lmPublicLocal = map wvData $ apply cs [without FromDependency,without ModuleOnly,without TestsOnly],- lmPrivateLocal = map wvData $ apply cs [without FromDependency,with ModuleOnly,without TestsOnly],- lmTestingLocal = map wvData $ apply cs [without FromDependency,with TestsOnly],+ lmPublicNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,without ModuleOnly],+ lmPrivateNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,with ModuleOnly],+ lmLocalNamespaces = Set.fromList $ map wvData $ apply ns [without FromDependency],+ lmPublicDeps = map wvData $ apply cs [with FromDependency,without ModuleOnly,without TestsOnly],+ lmPrivateDeps = map wvData $ apply cs [with FromDependency,with ModuleOnly,without TestsOnly],+ lmPublicTestingDeps = map wvData $ apply cs [with FromDependency,without ModuleOnly,with TestsOnly],+ lmPrivateTestingDeps = map wvData $ apply cs [with FromDependency,with ModuleOnly,with TestsOnly],+ lmPublicLocal = map wvData $ apply cs [without FromDependency,without ModuleOnly,without TestsOnly],+ lmPrivateLocal = map wvData $ apply cs [without FromDependency,with ModuleOnly,without TestsOnly],+ lmPublicTestingLocal = map wvData $ apply cs [without FromDependency,without ModuleOnly,with TestsOnly],+ lmPrivateTestingLocal = map wvData $ apply cs [without FromDependency,with ModuleOnly,with TestsOnly], lmStreamlined = ss,- lmExprMap = em+ lmExprMap = em,+ lmEmptyCategories = CategoryMap km Map.empty }+ km = Map.fromList $ map (\(WithVisibility _ t) -> (getCategoryName t,getCategoryContext t)) cs ns = map (mapCodeVisibility getCategoryNamespace) cs with v = hasCodeVisibility v without v = not . hasCodeVisibility v
src/Cli/ParseCompileOptions.hs view
@@ -25,6 +25,7 @@ import Control.Monad (when) import Lens.Micro import Text.Regex.TDFA+import qualified Data.Set as Set import Base.CompilerError import Cli.CompileOptions@@ -85,9 +86,9 @@ "", "Options:", " -f: Force an operation that zeolite would otherwise reject.",- " -j [# parallel]: Parallel execution of compilation subprocesses.", " -i [module]: A single source module to include as a public dependency.", " -I [module]: A single source module to include as a private dependency.",+ " -j [# parallel]: Parallel execution of compilation subprocesses.", " -o [binary]: The name of the binary file to create with -m.", " -p [path]: Set a path prefix for finding modules or files.", " --log-traces [filename]: Log call traces to a file when running tests.",@@ -124,8 +125,19 @@ defaultMainFunc :: String defaultMainFunc = "run" +optionsWithArgs :: Set.Set Char+optionsWithArgs = Set.fromList "iIjmop"++splitOptionClusters :: [String] -> [String]+splitOptionClusters (o@('-':c:rest):os)+ | c == '-' || null rest = o : splitOptionClusters os+ | c `Set.member` optionsWithArgs = ('-':c:[]) : rest : splitOptionClusters os+ | otherwise = ('-':c:[]) : splitOptionClusters (('-':rest):os)+splitOptionClusters (o:os) = o : splitOptionClusters os+splitOptionClusters [] = []+ parseCompileOptions :: CollectErrorsM m => [String] -> m CompileOptions-parseCompileOptions = parseAll emptyCompileOptions . zip ([1..] :: [Int]) where+parseCompileOptions = parseAll emptyCompileOptions . zip ([1..] :: [Int]) . splitOptionClusters where parseAll co [] = return co parseAll co os = do (os',co') <- parseSingle co os
src/Cli/RunCompiler.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -203,9 +203,9 @@ sequence_ $ intercalate [string_ ","] $ map ((:[]) . parseColTitle) tracesLogHeader some (char '\n' <|> char '\r') >> return () parseSingle = do- ms <- parseDec+ ms <- fmap snd parseDec string_ ","- pid <- parseDec+ pid <- fmap snd parseDec string_ "," func <- quotedString string_ ","
src/Cli/TestRunner.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -108,7 +108,7 @@ Just t -> compilerWarningM $ "Explicit timeouts are ignored in " ++ ex2 ++ " tests: " ++ show t run (ExpectCompilerError _ rs es) _ _ cs ds ts = do- result <- toTrackedErrors $ compileAll [] cs ds ts+ result <- toTrackedErrors $ compileAll Nothing [] cs ds ts if not $ isCompilerError result then compilerErrorM "Expected compilation failure" else fmap (:[]) $ return $ do@@ -117,22 +117,22 @@ checkContent rs es (lines warnings ++ lines errors) [] [] run (ExpectCompiles _ rs es) _ _ cs ds ts = do- result <- toTrackedErrors $ compileAll [] cs ds ts+ result <- toTrackedErrors $ compileAll Nothing [] cs ds ts if isCompilerError result then fromTrackedErrors result >> return [] else fmap (:[]) $ return $ do let warnings = show $ getCompilerWarnings result checkContent rs es (lines warnings) [] [] - run (ExpectRuntimeError _ rs es) args timeout cs ds ts = do- when (length ts /= 1) $ compilerErrorM "Exactly one unittest is required when crash is expected"+ run (ExpectRuntimeError _ t rs es) args timeout cs ds ts = do+ when (length ts /= 1) $ compilerErrorM "Exactly one unittest is required when failure is expected" uniqueTestNames ts- execute False rs es args timeout cs ds ts+ execute False t rs es args timeout cs ds ts - run (ExpectRuntimeSuccess _ rs es) args timeout cs ds ts = do+ run (ExpectRuntimeSuccess _ t rs es) args timeout cs ds ts = do when (null ts) $ compilerErrorM "At least one unittest is required when success is expected" uniqueTestNames ts- execute True rs es args timeout cs ds ts+ execute True t rs es args timeout cs ds ts checkContent rs es comp err out = do let cr = checkRequired rs comp err out@@ -157,8 +157,8 @@ testClash (n,ts) = "unittest " ++ show n ++ " is defined multiple times" !!> (mapCompilerM_ (compilerErrorM . ("Defined at " ++) . formatFullContext) $ sort $ map tpContext ts) - execute s2 rs es args timeout cs ds ts = do- result <- toTrackedErrors $ compileAll args cs ds ts+ execute s2 t rs es args timeout cs ds ts = do+ result <- toTrackedErrors $ compileAll t args cs ds ts if isCompilerError result then return [result >> return ()] else do@@ -185,10 +185,10 @@ (hPutStrLn stderr $ "--- unittest " ++ show f2 ++ " passed ---") (hPutStrLn stderr $ "--- unittest " ++ show f2 ++ " failed ---") - compileAll args cs ds ts = do+ compileAll t args cs ds ts = do let ns1 = StaticNamespace $ privateNamespace s let cs' = map (setCategoryNamespace ns1) cs- fromTrackedErrors $ compileTestsModule cm ns1 args cs' ds ts+ fromTrackedErrors $ compileTestsModule cm ns1 args t cs' ds ts checkRequired rs comp err out = mapCompilerM_ (checkSubsetForRegex True comp err out) rs checkExcluded es comp err out = mapCompilerM_ (checkSubsetForRegex False comp err out) es
src/Compilation/CompilerState.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -48,6 +48,7 @@ csCheckVariableInit, csClearOutput, csCurrentScope,+ csDelegateArgs, csExprLookup, csGetCategoryFunction, csGetCleanup,@@ -55,6 +56,7 @@ csGetNoTrace, csGetOutput, csGetParamScope,+ csGetTestsOnly, csGetTypeFunction, csGetVariable, csInheritDeferred,@@ -101,6 +103,7 @@ import Base.CompilerError import Base.GeneralType+import Base.Positional import Types.DefinedCategory import Types.Procedure import Types.TypeCategory@@ -150,9 +153,11 @@ ccReleaseExprMacro :: a -> [c] -> MacroName -> m a ccSetNoTrace :: a -> Bool -> m a ccGetNoTrace :: a -> m Bool+ ccGetTestsOnly :: a -> m Bool ccAddTrace :: a -> String -> m a ccGetTraces :: a -> m [String] ccCanForward :: a -> [ParamName] -> [VariableName] -> m Bool+ ccDelegateArgs :: a -> m (Positional (Maybe (CallArgLabel c), VariableName)) data MemberValue c = MemberValue {@@ -359,11 +364,17 @@ csGetNoTrace :: CompilerContext c m s a => CompilerState a m Bool csGetNoTrace = fmap ccGetNoTrace get >>= lift +csGetTestsOnly :: CompilerContext c m s a => CompilerState a m Bool+csGetTestsOnly = fmap ccGetTestsOnly get >>= lift+ csAddTrace :: CompilerContext c m s a => String -> CompilerState a m () csAddTrace t = fmap (\x -> ccAddTrace x t) get >>= lift >>= put csCanForward :: CompilerContext c m s a => [ParamName] -> [VariableName] -> CompilerState a m Bool csCanForward ps as = fmap (\x -> ccCanForward x ps as) get >>= lift++csDelegateArgs :: CompilerContext c m s a => CompilerState a m (Positional (Maybe (CallArgLabel c), VariableName))+csDelegateArgs = fmap ccDelegateArgs get >>= lift data CompiledData s = CompiledData {
src/Compilation/ProcedureContext.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -89,8 +89,9 @@ _pcExprMap :: ExprMap c, _pcReservedMacros :: [(MacroName,[c])], _pcNoTrace :: Bool,+ _pcTestsOnly :: Bool, _pcTraces :: [String],- _pcParentCall :: Maybe (Positional ParamName,Positional VariableName)+ _pcParentCall :: Maybe (Positional ParamName,Positional (Maybe (CallArgLabel c), InputValue c)) } $(makeLenses ''ProcedureContext)@@ -146,7 +147,17 @@ case t of Just t0 -> replaceSelfInstance self t0 Nothing -> return self- getFunction t' t' where+ f <- getFunction t' t'+ when (ctx ^. pcType /= sfType f && ctx ^. pcType /= CategoryNone) $+ "In call to " ++ show (sfName f) ++ formatFullContextBrace c ??> checkVisibility (ctx ^. pcScope) (sfVisibility f) f+ return f where+ checkVisibility _ FunctionVisibilityDefault _ = return ()+ checkVisibility CategoryScope v _ = "Function restricted to @type and @value contexts" ??> compilerErrorM (show v)+ checkVisibility _ _ f = do+ r <- ccResolver ctx+ allFilters <- ccAllFilters ctx+ self <- fmap (singleType . JustTypeInstance) $ ccSelfType ctx+ checkFunctionCallVisibility r allFilters f self multipleMatchError t2 fs = do "Multiple matches for function " ++ show n ++ " called on " ++ show t2 ++ formatFullContextBrace c !!> mapErrorsM (map show fs)@@ -409,19 +420,28 @@ ccReleaseExprMacro ctx _ n = return $ ctx & pcReservedMacros %~ (filter ((/= n) . fst)) ccSetNoTrace ctx t = return $ ctx & pcNoTrace .~ t ccGetNoTrace = return . (^. pcNoTrace)+ ccGetTestsOnly = return . (^. pcTestsOnly) ccAddTrace ctx "" = return ctx ccAddTrace ctx t = return $ ctx & pcTraces <>~ [t] ccGetTraces = return . (^. pcTraces) ccCanForward ctx ps as = handle (ctx ^. pcParentCall) where+ nameOrError (InputValue _ n) = return n+ nameOrError _ = emptyErrorM handle Nothing = return False handle (Just (ps0,as0)) = collectFirstM [checkMatch ps0 as0,return False] checkMatch ps0 as0 = do+ as0' <- fmap Positional $ mapCompilerM (nameOrError . snd) $ pValues as0 processPairs_ equalOrError ps0 (Positional ps)- processPairs_ equalOrError as0 (Positional as)+ processPairs_ equalOrError as0' (Positional as) return True equalOrError x y | x == y = return () | otherwise = emptyErrorM+ ccDelegateArgs ctx = handle (ctx ^. pcParentCall) where+ nameOrError (l,InputValue _ n) = return (l,n)+ nameOrError (_,DiscardInput c) = compilerErrorM $ "Delegation is not allowed with ignored args" ++ formatFullContextBrace c+ handle Nothing = compilerErrorM "Delegation is only allowed within function calls"+ handle (Just (_,as0)) = fmap Positional $ mapCompilerM nameOrError $ pValues as0 updateReturnVariables :: (Show c, CollectErrorsM m) => (Map.Map VariableName (VariableValue c)) ->@@ -444,17 +464,25 @@ updateArgVariables :: (Show c, CollectErrorsM m) => (Map.Map VariableName (VariableValue c)) ->- Positional (PassedValue c) -> ArgValues c ->+ Positional (PassedValue c, Maybe (CallArgLabel c)) -> ArgValues c -> m (Map.Map VariableName (VariableValue c)) updateArgVariables ma as1 as2 = do as <- processPairs alwaysPair as1 (avNames as2) let as' = filter (not . isDiscardedInput . snd) as foldM update ma as' where- update va (PassedValue _ t,a) = do+ checkName (Just l) (InputValue c (VariableName n))+ | l `matchesCallArgLabel` n = return ()+ | otherwise = compilerWarningM $ "Variable " ++ n +++ formatFullContextBrace c +++ " has a different name than arg label " ++ show l+ checkName _ _ = return ()+ update va ((PassedValue _ t,n),a) = do let c = ivContext a case ivName a `Map.lookup` va of- Nothing -> return $ Map.insert (ivName a) (VariableValue c LocalScope t (VariableReadOnly c)) va+ Nothing -> return () (Just v) -> compilerErrorM $ "Variable " ++ show (ivName a) ++ formatFullContextBrace c ++ " is already defined" ++ formatFullContextBrace (vvContext v)+ checkName n a+ return $ Map.insert (ivName a) (VariableValue c LocalScope t (VariableReadOnly c)) va
src/CompilerCxx/CategoryContext.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -42,9 +42,9 @@ getContextForInit :: (Show c, CollectErrorsM m) =>- CategoryMap c -> ExprMap c -> AnyCategory c -> DefinedCategory c ->+ Bool -> CategoryMap c -> ExprMap c -> AnyCategory c -> DefinedCategory c -> SymbolScope -> m (ProcedureContext c)-getContextForInit tm em t d s = do+getContextForInit to tm em t d s = do let ps = Positional $ getCategoryParams t -- NOTE: This is always ValueScope for initializer checks. let ms = filter ((== ValueScope) . dmScope) $ dcMembers d@@ -85,14 +85,15 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,+ _pcTestsOnly = to, _pcTraces = [], _pcParentCall = Nothing } getProcedureContext :: (Show c, CollectErrorsM m) =>- ScopeContext c -> ScopedFunction c -> ExecutableProcedure c -> m (ProcedureContext c)-getProcedureContext (ScopeContext tm t ps ms pa fa va em)- ff@(ScopedFunction _ _ _ s as1 rs1 ps1 fs _)+ Bool -> ScopeContext c -> ScopedFunction c -> ExecutableProcedure c -> m (ProcedureContext c)+getProcedureContext to (ScopeContext tm t ps ms pa fa va em)+ ff@(ScopedFunction _ _ _ s _ as1 rs1 ps1 fs _) (ExecutableProcedure _ _ _ _ as2 rs2 _) = do rs' <- if isUnnamedReturns rs2 then return $ ValidatePositions rs1@@ -146,21 +147,17 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,+ _pcTestsOnly = to, _pcTraces = [], _pcParentCall = parentCall } where pairOutput (PassedValue c1 t2) (OutputValue c2 n2) = return $ (n2,PassedValue (c2++c1) t2)- psList = map vpParam $ pValues ps1- asList = sequence $ map maybeArgName $ pValues $ avNames as2- maybeArgName (InputValue _ n) = Just n- maybeArgName _ = Nothing- parentCall = case asList of- Just as3 -> Just (Positional psList,Positional as3)- Nothing -> Nothing+ args = Positional $ zip (map snd $ pValues as1) (pValues $ avNames as2)+ parentCall = Just (fmap vpParam ps1,args) -getMainContext :: CollectErrorsM m => CategoryMap c -> ExprMap c -> m (ProcedureContext c)-getMainContext tm em = return $ ProcedureContext {+getMainContext :: CollectErrorsM m => Bool -> CategoryMap c -> ExprMap c -> m (ProcedureContext c)+getMainContext to tm em = return $ ProcedureContext { _pcScope = LocalScope, _pcType = CategoryNone, _pcExtParams = Positional [],@@ -186,6 +183,7 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,+ _pcTestsOnly = to, _pcTraces = [], _pcParentCall = Nothing }
src/CompilerCxx/Code.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -125,21 +125,23 @@ showCreationTrace = "TRACE_CREATION" hasPrimitiveValue :: CategoryName -> Bool-hasPrimitiveValue BuiltinBool = True-hasPrimitiveValue BuiltinInt = True-hasPrimitiveValue BuiltinFloat = True-hasPrimitiveValue BuiltinChar = True-hasPrimitiveValue BuiltinPointer = True-hasPrimitiveValue _ = False+hasPrimitiveValue BuiltinBool = True+hasPrimitiveValue BuiltinInt = True+hasPrimitiveValue BuiltinFloat = True+hasPrimitiveValue BuiltinChar = True+hasPrimitiveValue BuiltinPointer = True+hasPrimitiveValue BuiltinIdentifier = True+hasPrimitiveValue _ = False isStoredUnboxed :: ValueType -> Bool isStoredUnboxed t- | t == boolRequiredValue = True- | t == intRequiredValue = True- | t == floatRequiredValue = True- | t == charRequiredValue = True- | isPointerRequiredValue t = True- | otherwise = False+ | t == boolRequiredValue = True+ | t == intRequiredValue = True+ | t == floatRequiredValue = True+ | t == charRequiredValue = True+ | isPointerRequiredValue t = True+ | isIdentifierRequiredValue t = True+ | otherwise = False expressionFromLiteral :: PrimitiveType -> String -> (ExpressionType,ExpressionValue) expressionFromLiteral PrimString e =@@ -153,13 +155,14 @@ expressionFromLiteral PrimBool e = (Positional [boolRequiredValue],UnboxedPrimitive PrimBool e) expressionFromLiteral PrimPointer _ = undefined+expressionFromLiteral PrimIdentifier _ = undefined getFromLazy :: ExpressionValue -> ExpressionValue-getFromLazy (OpaqueMulti e) = OpaqueMulti $ e ++ ".Get()"-getFromLazy (WrappedSingle e) = WrappedSingle $ e ++ ".Get()"-getFromLazy (UnwrappedSingle e) = UnwrappedSingle $ e ++ ".Get()"-getFromLazy (BoxedPrimitive t e) = BoxedPrimitive t $ e ++ ".Get()"-getFromLazy (UnboxedPrimitive t e) = UnboxedPrimitive t $ e ++ ".Get()"+getFromLazy (OpaqueMulti e) = OpaqueMulti $ "(" ++ e ++ ").Get()"+getFromLazy (WrappedSingle e) = WrappedSingle $ "(" ++ e ++ ").Get()"+getFromLazy (UnwrappedSingle e) = UnwrappedSingle $ "(" ++ e ++ ").Get()"+getFromLazy (BoxedPrimitive t e) = BoxedPrimitive t $ "(" ++ e ++ ").Get()"+getFromLazy (UnboxedPrimitive t e) = UnboxedPrimitive t $ "(" ++ e ++ ").Get()" getFromLazy (LazySingle e) = LazySingle $ getFromLazy e useAsWhatever :: ExpressionValue -> String@@ -171,147 +174,162 @@ useAsWhatever (LazySingle e) = useAsWhatever $ getFromLazy e useAsReturns :: ExpressionValue -> String-useAsReturns (OpaqueMulti e) = e-useAsReturns (WrappedSingle e) = "ReturnTuple(" ++ e ++ ")"-useAsReturns (UnwrappedSingle e) = "ReturnTuple(" ++ e ++ ")"-useAsReturns (BoxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"-useAsReturns (LazySingle e) = useAsReturns $ getFromLazy e+useAsReturns (OpaqueMulti e) = e+useAsReturns (WrappedSingle e) = "ReturnTuple(" ++ e ++ ")"+useAsReturns (UnwrappedSingle e) = "ReturnTuple(" ++ e ++ ")"+useAsReturns (BoxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimIdentifier e) = "ReturnTuple(Box_Identifier(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimIdentifier e) = "ReturnTuple(Box_Identifier(" ++ e ++ "))"+useAsReturns (LazySingle e) = useAsReturns $ getFromLazy e useAsArgs :: ExpressionValue -> String-useAsArgs (OpaqueMulti e) = e-useAsArgs (WrappedSingle e) = e-useAsArgs (UnwrappedSingle e) = e-useAsArgs (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"-useAsArgs (LazySingle e) = useAsArgs $ getFromLazy e+useAsArgs (OpaqueMulti e) = e+useAsArgs (WrappedSingle e) = e+useAsArgs (UnwrappedSingle e) = e+useAsArgs (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimIdentifier e) = "Box_Identifier(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimIdentifier e) = "Box_Identifier(" ++ e ++ ")"+useAsArgs (LazySingle e) = useAsArgs $ getFromLazy e useAsUnwrapped :: ExpressionValue -> String-useAsUnwrapped (OpaqueMulti e) = "(" ++ e ++ ").At(0)"-useAsUnwrapped (WrappedSingle e) = e-useAsUnwrapped (UnwrappedSingle e) = e-useAsUnwrapped (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"-useAsUnwrapped (LazySingle e) = useAsUnwrapped $ getFromLazy e+useAsUnwrapped (OpaqueMulti e) = "(" ++ e ++ ").At(0)"+useAsUnwrapped (WrappedSingle e) = e+useAsUnwrapped (UnwrappedSingle e) = e+useAsUnwrapped (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimIdentifier e) = "Box_Identifier(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimIdentifier e) = "Box_Identifier(" ++ e ++ ")"+useAsUnwrapped (LazySingle e) = useAsUnwrapped $ getFromLazy e useAsUnboxed :: PrimitiveType -> ExpressionValue -> String-useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsBool()"-useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsString()"-useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsChar()"-useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsInt()"-useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsFloat()"-useAsUnboxed PrimPointer (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsPointer<OpaqueObject>()"-useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ").AsBool()"-useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ").AsString()"-useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ").AsChar()"-useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ").AsInt()"-useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ").AsFloat()"-useAsUnboxed PrimPointer (WrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()"-useAsUnboxed PrimBool (UnwrappedSingle e) = "(" ++ e ++ ").AsBool()"-useAsUnboxed PrimString (UnwrappedSingle e) = "(" ++ e ++ ").AsString()"-useAsUnboxed PrimChar (UnwrappedSingle e) = "(" ++ e ++ ").AsChar()"-useAsUnboxed PrimInt (UnwrappedSingle e) = "(" ++ e ++ ").AsInt()"-useAsUnboxed PrimFloat (UnwrappedSingle e) = "(" ++ e ++ ").AsFloat()"-useAsUnboxed PrimPointer (UnwrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()"-useAsUnboxed _ (BoxedPrimitive _ e) = e-useAsUnboxed _ (UnboxedPrimitive _ e) = e-useAsUnboxed t (LazySingle e) = useAsUnboxed t $ getFromLazy e+useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsBool()"+useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsString()"+useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsChar()"+useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsInt()"+useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsFloat()"+useAsUnboxed PrimPointer (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsPointer<OpaqueObject>()"+useAsUnboxed PrimIdentifier (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsIdentifier()"+useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ").AsBool()"+useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ").AsString()"+useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ").AsChar()"+useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ").AsInt()"+useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ").AsFloat()"+useAsUnboxed PrimPointer (WrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()"+useAsUnboxed PrimIdentifier (WrappedSingle e) = "(" ++ e ++ ").AsIdentifier()"+useAsUnboxed PrimBool (UnwrappedSingle e) = "(" ++ e ++ ").AsBool()"+useAsUnboxed PrimString (UnwrappedSingle e) = "(" ++ e ++ ").AsString()"+useAsUnboxed PrimChar (UnwrappedSingle e) = "(" ++ e ++ ").AsChar()"+useAsUnboxed PrimInt (UnwrappedSingle e) = "(" ++ e ++ ").AsInt()"+useAsUnboxed PrimFloat (UnwrappedSingle e) = "(" ++ e ++ ").AsFloat()"+useAsUnboxed PrimPointer (UnwrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()"+useAsUnboxed PrimIdentifier (UnwrappedSingle e) = "(" ++ e ++ ").AsIdentifier()"+useAsUnboxed _ (BoxedPrimitive _ e) = e+useAsUnboxed _ (UnboxedPrimitive _ e) = e+useAsUnboxed t (LazySingle e) = useAsUnboxed t $ getFromLazy e valueAsWrapped :: ExpressionValue -> ExpressionValue-valueAsWrapped (UnwrappedSingle e) = WrappedSingle e-valueAsWrapped (BoxedPrimitive _ e) = WrappedSingle e-valueAsWrapped (UnboxedPrimitive PrimBool e) = WrappedSingle $ "Box_Bool(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimString e) = WrappedSingle $ "Box_String(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimChar e) = WrappedSingle $ "Box_Char(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimInt e) = WrappedSingle $ "Box_Int(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimFloat e) = WrappedSingle $ "Box_Float(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimPointer e) = WrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"-valueAsWrapped (LazySingle e) = valueAsWrapped $ getFromLazy e-valueAsWrapped v = v+valueAsWrapped (UnwrappedSingle e) = WrappedSingle e+valueAsWrapped (BoxedPrimitive _ e) = WrappedSingle e+valueAsWrapped (UnboxedPrimitive PrimBool e) = WrappedSingle $ "Box_Bool(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimString e) = WrappedSingle $ "Box_String(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimChar e) = WrappedSingle $ "Box_Char(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimInt e) = WrappedSingle $ "Box_Int(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimFloat e) = WrappedSingle $ "Box_Float(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimPointer e) = WrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimIdentifier e) = WrappedSingle $ "Box_Identifier(" ++ e ++ ")"+valueAsWrapped (LazySingle e) = valueAsWrapped $ getFromLazy e+valueAsWrapped v = v valueAsUnwrapped :: ExpressionValue -> ExpressionValue-valueAsUnwrapped (OpaqueMulti e) = UnwrappedSingle $ "(" ++ e ++ ").At(0)"-valueAsUnwrapped (WrappedSingle e) = UnwrappedSingle e-valueAsUnwrapped (UnboxedPrimitive PrimBool e) = UnwrappedSingle $ "Box_Bool(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimString e) = UnwrappedSingle $ "Box_String(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimChar e) = UnwrappedSingle $ "Box_Char(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimInt e) = UnwrappedSingle $ "Box_Int(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimFloat e) = UnwrappedSingle $ "Box_Float(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimPointer e) = UnwrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"-valueAsUnwrapped (LazySingle e) = valueAsUnwrapped $ getFromLazy e-valueAsUnwrapped v = v+valueAsUnwrapped (OpaqueMulti e) = UnwrappedSingle $ "(" ++ e ++ ").At(0)"+valueAsUnwrapped (WrappedSingle e) = UnwrappedSingle e+valueAsUnwrapped (UnboxedPrimitive PrimBool e) = UnwrappedSingle $ "Box_Bool(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimString e) = UnwrappedSingle $ "Box_String(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimChar e) = UnwrappedSingle $ "Box_Char(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimInt e) = UnwrappedSingle $ "Box_Int(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimFloat e) = UnwrappedSingle $ "Box_Float(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimPointer e) = UnwrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimIdentifier e) = UnwrappedSingle $ "Box_Identifier(" ++ e ++ ")"+valueAsUnwrapped (LazySingle e) = valueAsUnwrapped $ getFromLazy e+valueAsUnwrapped v = v variableStoredType :: ValueType -> String variableStoredType t- | t == boolRequiredValue = "PrimBool"- | t == intRequiredValue = "PrimInt"- | t == floatRequiredValue = "PrimFloat"- | t == charRequiredValue = "PrimChar"- | isPointerRequiredValue t = "PrimPointer"- | isWeakValue t = "WeakValue"- | otherwise = "BoxedValue"+ | t == boolRequiredValue = "PrimBool"+ | t == intRequiredValue = "PrimInt"+ | t == floatRequiredValue = "PrimFloat"+ | t == charRequiredValue = "PrimChar"+ | isPointerRequiredValue t = "PrimPointer"+ | isIdentifierRequiredValue t = "PrimIdentifier"+ | isWeakValue t = "WeakValue"+ | otherwise = "BoxedValue" variableLazyType :: ValueType -> String variableLazyType t = "LazyInit<" ++ variableStoredType t ++ ">" variableProxyType :: ValueType -> String variableProxyType t- | t == boolRequiredValue = "PrimBool"- | t == intRequiredValue = "PrimInt"- | t == floatRequiredValue = "PrimFloat"- | t == charRequiredValue = "PrimChar"- | isPointerRequiredValue t = "PrimPointer"- | isWeakValue t = "WeakValue&"- | otherwise = "BoxedValue&"+ | t == boolRequiredValue = "PrimBool"+ | t == intRequiredValue = "PrimInt"+ | t == floatRequiredValue = "PrimFloat"+ | t == charRequiredValue = "PrimChar"+ | isPointerRequiredValue t = "PrimPointer"+ | isIdentifierRequiredValue t = "PrimIdentifier"+ | isWeakValue t = "WeakValue&"+ | otherwise = "BoxedValue&" readStoredVariable :: Bool -> ValueType -> String -> ExpressionValue readStoredVariable True t s = LazySingle $ readStoredVariable False t s readStoredVariable False t s- | t == boolRequiredValue = UnboxedPrimitive PrimBool s- | t == intRequiredValue = UnboxedPrimitive PrimInt s- | t == floatRequiredValue = UnboxedPrimitive PrimFloat s- | t == charRequiredValue = UnboxedPrimitive PrimChar s- | isPointerRequiredValue t = UnboxedPrimitive PrimPointer s- | otherwise = UnwrappedSingle s+ | t == boolRequiredValue = UnboxedPrimitive PrimBool s+ | t == intRequiredValue = UnboxedPrimitive PrimInt s+ | t == floatRequiredValue = UnboxedPrimitive PrimFloat s+ | t == charRequiredValue = UnboxedPrimitive PrimChar s+ | isPointerRequiredValue t = UnboxedPrimitive PrimPointer s+ | isIdentifierRequiredValue t = UnboxedPrimitive PrimIdentifier s+ | otherwise = UnwrappedSingle s writeStoredVariable :: ValueType -> ExpressionValue -> String writeStoredVariable t e- | t == boolRequiredValue = useAsUnboxed PrimBool e- | t == intRequiredValue = useAsUnboxed PrimInt e- | t == floatRequiredValue = useAsUnboxed PrimFloat e- | t == charRequiredValue = useAsUnboxed PrimChar e- | isPointerRequiredValue t = useAsUnboxed PrimPointer e- | otherwise = useAsUnwrapped e+ | t == boolRequiredValue = useAsUnboxed PrimBool e+ | t == intRequiredValue = useAsUnboxed PrimInt e+ | t == floatRequiredValue = useAsUnboxed PrimFloat e+ | t == charRequiredValue = useAsUnboxed PrimChar e+ | isPointerRequiredValue t = useAsUnboxed PrimPointer e+ | isIdentifierRequiredValue t = useAsUnboxed PrimIdentifier e+ | otherwise = useAsUnwrapped e functionLabelType :: ScopedFunction c -> String functionLabelType = getType . sfScope where
src/CompilerCxx/CxxFiles.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -592,7 +592,7 @@ createParam p = onlyCode $ paramType ++ " " ++ paramName (vpParam p) ++ ";" inlineCategoryConstructor t d tm em = do- ctx <- getContextForInit tm em t d CategoryScope+ ctx <- getContextForInit testing tm em t d CategoryScope initMembers <- runDataCompiler (sequence $ map compileLazyInit members) ctx let initMembersStr = intercalate ", " $ cdOutput initMembers let initColon = if null initMembersStr then "" else " : "@@ -709,20 +709,22 @@ "CycleCheck<" ++ n2 ++ "> marker(*this);" ] - defineProcedure t = compileExecutableProcedure (isImmutable t)+ defineProcedure t = compileExecutableProcedure testing (isImmutable t) declareProcedure t = procedureDeclaration (isImmutable t) isImmutable :: AnyCategory c -> Bool isImmutable = any isCategoryImmutable . getCategoryPragmas formatFunctionTypes :: Show c => ScopedFunction c -> [String]-formatFunctionTypes (ScopedFunction c _ _ s as rs ps fa _) = [location,args,returns,params] ++ filters where+formatFunctionTypes (ScopedFunction c _ _ s _ as rs ps fa _) = [location,args,returns,params] ++ filters where location = show s ++ " function declared at " ++ formatFullContext c- args = "Arg Types: (" ++ intercalate ", " (map (show . pvType) $ pValues as) ++ ")"+ args = "Arg Types: (" ++ intercalate ", " (map singleArg $ pValues as) ++ ")" returns = "Return Types: (" ++ intercalate ", " (map (show . pvType) $ pValues rs) ++ ")" params = "Type Params: <" ++ intercalate ", " (map (show . vpParam) $ pValues ps) ++ ">" filters = map singleFilter fa singleFilter (ParamFilter _ n2 f) = " " ++ show n2 ++ " " ++ show f+ singleArg (a,Just n) = show (pvType a) ++ " " ++ (calName n)+ singleArg (a,_) = show (pvType a) createMainCommon :: String -> CompiledData [String] -> CompiledData [String] -> [String] createMainCommon n (CompiledData req0 _ out0) (CompiledData req1 _ out1) =@@ -747,13 +749,17 @@ argv = onlyCode "ProgramArgv program_argv(argc, argv);" generateTestFile :: (Ord c, Show c, CollectErrorsM m) =>- CategoryMap c -> ExprMap c -> [String] -> [TestProcedure c] -> m (CompiledData [String])-generateTestFile tm em args ts = "In the creation of the test binary procedure" ??> do+ CategoryMap c -> ExprMap c -> [String] -> Maybe ([c],TypeInstance) -> [TestProcedure c] ->+ m (CompiledData [String])+generateTestFile tm em args t ts = "In the creation of the test binary procedure" ??> do+ wrap <- case t of+ Just t2 -> compileWrapTestcase tm t2+ Nothing -> return emptyCode ts' <- fmap mconcat $ mapCompilerM (compileTestProcedure tm em) ts (include,sel) <- selectTestFromArgv1 $ map tpName ts let (CompiledData req traces _) = ts' <> sel let contentTop = mconcat [timeoutInclude,onlyCodes include,ts']- let contentMain = mconcat [setTimeout,argv,callLog,sel]+ let contentMain = mconcat [setTimeout,argv,callLog,wrap,sel] let file = testsOnlySourceGuard ++ createMainCommon "testcase" contentTop contentMain return $ CompiledData req traces file where args' = map escapeChars args@@ -1032,8 +1038,8 @@ fromDefines ds = Set.toList $ Set.unions $ map (categoriesFromDefine . vdType) ds fromDefine (DefinesInstance d ps) = d:(fromGenerals $ pValues ps) fromFunctions fs = concat $ map fromFunction fs- fromFunction (ScopedFunction _ _ t2 _ as rs _ fs _) =- [t2] ++ (fromGenerals $ map (vtType . pvType) (pValues as ++ pValues rs)) ++ fromFilters fs+ fromFunction (ScopedFunction _ _ t2 _ _ as rs _ fs _) =+ [t2] ++ (fromGenerals $ map (vtType . pvType) (map fst (pValues as) ++ pValues rs)) ++ fromFilters fs fromFilters fs = concat $ map (fromFilter . pfFilter) fs fromFilter (TypeFilter _ t2) = Set.toList $ categoriesFromTypes t2 fromFilter (DefinesFilter t2) = fromDefine t2
src/CompilerCxx/LanguageModule.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -35,7 +35,6 @@ import CompilerCxx.CxxFiles import CompilerCxx.Naming import Module.CompileMetadata (CategorySpec(..))-import Types.Builtin import Types.DefinedCategory import Types.Procedure import Types.TypeCategory@@ -49,12 +48,15 @@ lmLocalNamespaces :: Set.Set Namespace, lmPublicDeps :: [AnyCategory c], lmPrivateDeps :: [AnyCategory c],- lmTestingDeps :: [AnyCategory c],+ lmPublicTestingDeps :: [AnyCategory c],+ lmPrivateTestingDeps :: [AnyCategory c], lmPublicLocal :: [AnyCategory c], lmPrivateLocal :: [AnyCategory c],- lmTestingLocal :: [AnyCategory c],+ lmPublicTestingLocal :: [AnyCategory c],+ lmPrivateTestingLocal :: [AnyCategory c], lmStreamlined :: [CategoryName],- lmExprMap :: ExprMap c+ lmExprMap :: ExprMap c,+ lmEmptyCategories :: CategoryMap c } data PrivateSource c =@@ -68,47 +70,49 @@ compileLanguageModule :: (Ord c, Show c, CollectErrorsM m) => LanguageModule c -> Map.Map CategoryName (CategorySpec c) -> [PrivateSource c] -> m [CxxOutput]-compileLanguageModule (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 ss em) cm xa = do+compileLanguageModule (LanguageModule ns0 ns1 ns2 cs0 ps0 tc0 tp0 cs1 ps1 tc1 tp1 ss em cm0) sm xa = do let dm = mapDefByName $ concat $ map psDefine xa- checkDefined dm extensions allExternal $ filter isValueConcrete (cs1 ++ ps1 ++ ts1)+ checkDefined dm extensions allExternal $ filter isValueConcrete (cs1 ++ ps1 ++ tc1 ++ tp1) checkSupefluous $ Set.toList $ extensions `Set.difference` ca- tmPublic <- foldM includeNewTypes defaultCategories [cs0,cs1]- tmPrivate <- foldM includeNewTypes tmPublic [ps0,ps1]- tmTesting <- foldM includeNewTypes tmPrivate [ts0,ts1]+ tmPublic <- foldM includeNewTypes cm0 [cs0,cs1]+ tmPrivate <- foldM includeNewTypes tmPublic [ps0,ps1]+ tmPublicTesting <- foldM includeNewTypes tmPublic [tc0,tc1]+ tmPrivateTesting <- foldM includeNewTypes tmPublicTesting [ps0,tp0,ps1,tp1] xxInterfaces <- fmap concat $ collectAllM $ map (generateNativeInterface False nsPublic) (onlyNativeInterfaces cs1) ++ map (generateNativeInterface False nsPrivate) (onlyNativeInterfaces ps1) ++- map (generateNativeInterface True nsPrivate) (onlyNativeInterfaces ts1)- xxPrivate <- fmap concat $ mapCompilerM (compilePrivate tmPrivate tmTesting) xa- xxStreamlined <- fmap concat $ mapCompilerM (streamlined tmPrivate tmTesting) $ nub ss+ map (generateNativeInterface True nsPublic) (onlyNativeInterfaces tc1) +++ map (generateNativeInterface True nsPrivate) (onlyNativeInterfaces tp1)+ xxPrivate <- fmap concat $ mapCompilerM (compilePrivate tmPrivate tmPrivateTesting) xa+ xxStreamlined <- fmap concat $ mapCompilerM (streamlined tmPrivate tmPrivateTesting) $ nub ss let allFiles = xxInterfaces ++ xxPrivate ++ xxStreamlined noDuplicateFiles $ map (\f -> (coFilename f,coNamespace f)) allFiles return allFiles where nsPublic = ns0 `Set.union` ns2 nsPrivate = ns1 `Set.union` nsPublic extensions = Set.fromList ss- allExternal = Set.unions [extensions,Map.keysSet cm]- testingCats = Set.fromList $ map getCategoryName ts1+ allExternal = Set.unions [extensions,Map.keysSet sm]+ testingCats = Set.fromList $ (map getCategoryName tc1) ++ (map getCategoryName tp1) onlyNativeInterfaces = filter (not . (`Set.member` extensions) . getCategoryName) . filter (not . isValueConcrete)- localCats = Set.fromList $ map getCategoryName $ cs1 ++ ps1 ++ ts1+ localCats = Set.fromList $ map getCategoryName $ cs1 ++ ps1 ++ tc1 ++ tp1 streamlined tm0 tm2 n = do checkLocal localCats ([] :: [String]) n let testing = n `Set.member` testingCats let tm = if testing then tm2 else tm0 (_,t) <- getConcreteCategory tm ([],n) let ctx = FileContext testing tm nsPrivate Map.empty- let spec = Map.findWithDefault (CategorySpec [] [] []) (getCategoryName t) cm+ let spec = Map.findWithDefault (CategorySpec [] [] []) (getCategoryName t) sm generateStreamlinedExtension ctx t spec compilePrivate tmPrivate tmTesting (PrivateSource ns3 testing cs2 ds) = do let tm = if testing then tmTesting else tmPrivate let cs = Set.fromList $ map getCategoryName $ if testing- then cs2 ++ cs1 ++ ps1 ++ ts1+ then cs2 ++ cs1 ++ ps1 ++ tc1 ++ tp1 else cs2 ++ cs1 ++ ps1 tm' <- includeNewTypes tm cs2 let ctx = FileContext testing tm' (ns3 `Set.insert` nsPrivate) em- checkLocals ds $ Map.keysSet tm'+ checkLocals ds $ Map.keysSet $ cmAvailable tm' when testing $ checkTests ds (cs1 ++ ps1) let dm = mapDefByName ds checkDefined dm Set.empty Set.empty $ filter isValueConcrete cs2@@ -123,7 +127,7 @@ checkLocal cs (dcContext d) (dcName d) fmap snd $ getConcreteCategory tm (dcContext d,dcName d) mapDefByName = Map.fromListWith (++) . map (\d -> (dcName d,[d]))- ca = Set.fromList $ map getCategoryName $ filter isValueConcrete (cs1 ++ ps1 ++ ts1)+ ca = Set.fromList $ map getCategoryName $ filter isValueConcrete (cs1 ++ ps1 ++ tc1 ++ tp1) checkLocals ds tm = mapCompilerM_ (\d -> checkLocal tm (dcContext d) (dcName d)) ds checkLocal cs2 c n = when (not $ n `Set.member` cs2) $@@ -170,9 +174,9 @@ return $ (f,ns3) `Set.insert` used compileTestsModule :: (Ord c, Show c, CollectErrorsM m) =>- LanguageModule c -> Namespace -> [String] -> [AnyCategory c] -> [DefinedCategory c] ->- [TestProcedure c] -> m ([CxxOutput],CxxOutput,[(FunctionName,[c])])-compileTestsModule cm ns args cs ds ts = do+ LanguageModule c -> Namespace -> [String] -> Maybe ([c],TypeInstance) -> [AnyCategory c] ->+ [DefinedCategory c] -> [TestProcedure c] -> m ([CxxOutput],CxxOutput,[(FunctionName,[c])])+compileTestsModule cm ns args t cs ds ts = do let xs = PrivateSource { psNamespace = ns, psTesting = True,@@ -180,23 +184,23 @@ psDefine = ds } xx <- compileLanguageModule cm Map.empty [xs]- (main,fs) <- compileTestMain cm args xs ts+ (main,fs) <- compileTestMain cm args t xs ts return (xx,main,fs) compileTestMain :: (Ord c, Show c, CollectErrorsM m) =>- LanguageModule c -> [String] -> PrivateSource c -> [TestProcedure c] ->+ LanguageModule c -> [String] -> Maybe ([c],TypeInstance) -> PrivateSource c -> [TestProcedure c] -> m (CxxOutput,[(FunctionName,[c])])-compileTestMain (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 _ em) args ts2 tests = do+compileTestMain (LanguageModule ns0 ns1 ns2 cs0 ps0 tc0 tp0 cs1 ps1 tc1 tp1 _ em cm0) args t ts2 tests = do tm' <- tm- (CompiledData req traces main) <- generateTestFile tm' em args tests+ (CompiledData req traces main) <- generateTestFile tm' em args t tests let output = CxxOutput Nothing testFilename NoNamespace (psNamespace ts2 `Set.insert` Set.unions [ns0,ns1,ns2]) req traces main- let tests' = map (\t -> (tpName t,tpContext t)) tests+ let tests' = map (\t2 -> (tpName t2,tpContext t2)) tests return (output,tests') where- tm = foldM includeNewTypes defaultCategories [cs0,cs1,ps0,ps1,ts0,ts1,psCategory ts2]+ tm = foldM includeNewTypes cm0 [cs0,cs1,ps0,ps1,tc0,tp0,tc1,tp1,psCategory ts2] compileModuleMain :: (Ord c, Show c, CollectErrorsM m) => LanguageModule c -> [PrivateSource c] -> CategoryName -> FunctionName -> m CxxOutput-compileModuleMain (LanguageModule ns0 ns1 ns2 cs0 ps0 _ cs1 ps1 _ _ em) xa n f = do+compileModuleMain (LanguageModule ns0 ns1 ns2 cs0 ps0 _ _ cs1 ps1 _ _ _ em cm0) xa n f = do let resolved = filter (\d -> dcName d == n) $ concat $ map psDefine $ filter (not . psTesting) xa reconcile resolved tm' <- tm@@ -204,7 +208,7 @@ tm'' <- includeNewTypes tm' cs (ns,main) <- generateMainFile tm'' em n f return $ CxxOutput Nothing mainFilename NoNamespace (ns `Set.insert` Set.unions [ns0,ns1,ns2]) (Set.fromList [n]) Set.empty main where- tm = foldM includeNewTypes defaultCategories [cs0,cs1,ps0,ps1]+ tm = foldM includeNewTypes cm0 [cs0,cs1,ps0,ps1] reconcile [_] = return () reconcile [] = compilerErrorM $ "No matches for main category " ++ show n ++ " ($TestsOnly$ sources excluded)" reconcile ds =
src/CompilerCxx/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -31,6 +31,7 @@ compileLazyInit, compileRegularInit, compileTestProcedure,+ compileWrapTestcase, procedureDeclaration, selectTestFromArgv1, ) where@@ -87,12 +88,12 @@ deriving Show compileExecutableProcedure :: (Ord c, Show c, CollectErrorsM m) =>- Bool -> CxxFunctionType -> ScopeContext c -> ScopedFunction c ->+ Bool -> Bool -> CxxFunctionType -> ScopeContext c -> ScopedFunction c -> ExecutableProcedure c -> m (CompiledData [String])-compileExecutableProcedure immutable cxxType ctx- ff@(ScopedFunction _ _ _ s as1 rs1 ps1 _ _)+compileExecutableProcedure to immutable cxxType ctx+ ff@(ScopedFunction _ _ _ s _ as1 rs1 ps1 _ _) pp@(ExecutableProcedure c pragmas c2 n as2 rs2 p) = do- ctx' <- getProcedureContext ctx ff pp+ ctx' <- getProcedureContext to ctx ff pp output <- runDataCompiler compileWithReturn ctx' procedureTrace <- setProcedureTrace creationTrace <- setCreationTrace@@ -152,7 +153,7 @@ | otherwise = ["ReturnTuple returns(" ++ show (length $ pValues rs1) ++ ");"] nameParams = flip map (zip ([0..] :: [Int]) $ pValues ps1) $ (\(i,p2) -> paramType ++ " " ++ paramName (vpParam p2) ++ " = params_args.GetParam(" ++ show i ++ ");")- nameArgs = map nameSingleArg (zip ([0..] :: [Int]) $ zip (pValues as1) (pValues $ avNames as2))+ nameArgs = map nameSingleArg (zip ([0..] :: [Int]) $ zip (map fst $ pValues as1) (pValues $ avNames as2)) nameSingleArg (i,(t2,n2)) | isDiscardedInput n2 = "// Arg " ++ show i ++ " (" ++ show (pvType t2) ++ ") is discarded" | otherwise = "const " ++ variableProxyType (pvType t2) ++ " " ++ variableName (ivName n2) ++@@ -307,6 +308,19 @@ csSetDeferred (UsedVariable c2 n) createVariable (ExistingVariable (DiscardInput c2)) = compilerErrorM $ "Cannot defer discarded value" ++ formatFullContextBrace c2+compileStatement (VariableSwap c vl vr) = message ??> handle vl vr where+ message = "In variable swap at " ++ formatFullContext c+ handle (OutputValue cl nl) (OutputValue cr nr) = do+ r <- csResolver+ fa <- csAllFilters+ (VariableValue _ sl tl _) <- getWritableVariable cl nl+ (VariableValue _ sr tr _) <- getWritableVariable cr nr+ lift $ checkValueAssignment r fa tl tr+ lift $ checkValueAssignment r fa tr tl+ csCheckVariableInit [UsedVariable cl nl, UsedVariable cr nr]+ scopedL <- autoScope sl+ scopedR <- autoScope sr+ csWrite ["SwapValues(" ++ scopedL ++ variableName nl ++ ", " ++ scopedR ++ variableName nr ++ ");"] compileStatement (Assignment c as e) = message ??> do (ts,e') <- compileExpression e r <- csResolver@@ -362,6 +376,9 @@ csWrite [scoped ++ variableName n ++ " = " ++ writeStoredVariable t (UnwrappedSingle $ "r.At(" ++ show i ++ ")") ++ ";"] assignMulti _ = return ()+compileStatement (AssignmentEmpty c n e) = do+ (_,e') <- compileExpressionStart (InlineAssignment c n AssignIfEmpty e)+ csWrite ["(void) (" ++ useAsWhatever e' ++ ");"] compileStatement (NoValueExpression _ v) = compileVoidExpression v compileStatement (MarkReadOnly c vs) = mapM_ (\v -> csSetReadOnly (UsedVariable c v)) vs compileStatement (MarkHidden c vs) = mapM_ (\v -> csSetHidden (UsedVariable c v)) vs@@ -486,10 +503,10 @@ (Positional [t]) let currVar = hiddenVariableName $ VariableName "traverse" let currType = orderOptionalValue $ fixTypeParams t2- let currExpr = BuiltinCall [] $ FunctionCall [] BuiltinRequire (Positional []) (Positional [RawExpression (Positional [currType]) (UnwrappedSingle currVar)])- let currPresent = BuiltinCall [] $ FunctionCall [] BuiltinPresent (Positional []) (Positional [RawExpression (Positional [currType]) (UnwrappedSingle currVar)])- let callNext = Expression c1 currExpr [ValueCall c1 $ FunctionCall c1 (FunctionName "next") (Positional []) (Positional [])]- let callGet = Expression c2 currExpr [ValueCall c2 $ FunctionCall c2 (FunctionName "get") (Positional []) (Positional [])]+ let currExpr = BuiltinCall [] $ FunctionCall [] BuiltinRequire (Positional []) (Positional [(Nothing,RawExpression (Positional [currType]) (UnwrappedSingle currVar))])+ let currPresent = BuiltinCall [] $ FunctionCall [] BuiltinPresent (Positional []) (Positional [(Nothing,RawExpression (Positional [currType]) (UnwrappedSingle currVar))])+ let callNext = Expression c1 currExpr [ValueCall c1 AlwaysCall $ FunctionCall c1 (FunctionName "next") (Positional []) (Positional [])]+ let callGet = Expression c2 currExpr [ValueCall c2 AlwaysCall $ FunctionCall c2 (FunctionName "get") (Positional []) (Positional [])] (Positional [typeGet],exprNext) <- compileExpression callNext when (typeGet /= currType) $ compilerErrorM $ "Unexpected return type from next(): " ++ show typeGet ++ " (expected) " ++ show currType ++ " (actual)" let assnGet = if isAssignableDiscard a then [] else [Assignment c2 (Positional [a]) callGet]@@ -601,21 +618,31 @@ CompilerContext c m [String] a) => Expression c -> CompilerState a m (ExpressionType,ExpressionValue) compileExpression = compile where+ callFunctionSpec c as (FunctionSpec _ (CategoryFunction c2 cn) fn ps) =+ compile (Expression c (CategoryCall c2 cn (FunctionCall c fn ps as)) [])+ callFunctionSpec c as (FunctionSpec _ (TypeFunction c2 tn) fn ps) =+ compile (Expression c (TypeCall c2 tn (FunctionCall c fn ps as)) [])+ callFunctionSpec c as (FunctionSpec _ (ValueFunction c2 e0) fn ps) =+ compile (Expression c (ParensExpression c2 e0) [ValueCall c AlwaysCall (FunctionCall c fn ps as)])+ callFunctionSpec c as (FunctionSpec c2 UnqualifiedFunction fn ps) =+ compile (Expression c (UnqualifiedCall c2 (FunctionCall c fn ps as)) []) compile (Literal l) = compileValueLiteral l compile (Expression _ s os) = do foldl transform (compileExpressionStart s) os- compile (UnaryExpression c (FunctionOperator _ (FunctionSpec _ (CategoryFunction c2 cn) fn ps)) e) =- compile (Expression c (CategoryCall c2 cn (FunctionCall c fn ps (Positional [e]))) [])- compile (UnaryExpression c (FunctionOperator _ (FunctionSpec _ (TypeFunction c2 tn) fn ps)) e) =- compile (Expression c (TypeCall c2 tn (FunctionCall c fn ps (Positional [e]))) [])- compile (UnaryExpression c (FunctionOperator _ (FunctionSpec _ (ValueFunction c2 e0) fn ps)) e) =- compile (Expression c (ParensExpression c2 e0) [ValueCall c (FunctionCall c fn ps (Positional [e]))])- compile (UnaryExpression c (FunctionOperator _ (FunctionSpec c2 UnqualifiedFunction fn ps)) e) =- compile (Expression c (UnqualifiedCall c2 (FunctionCall c fn ps (Positional [e]))) [])+ compile (DelegatedFunctionCall c f) = "In function delegation at " ++ formatFullContext c ??> do+ args <- csDelegateArgs+ let vars = fmap (\(l,v) -> (l,Expression c (NamedVariable (OutputValue c v)) [])) args+ callFunctionSpec c vars f+ compile (DelegatedInitializeValue c t) = "In initialization delegation at " ++ formatFullContext c ??> do+ args <- csDelegateArgs+ let vars = fmap (\(_,v) -> Expression c (NamedVariable (OutputValue c v)) []) args+ compile (Expression c (InitializeValue c t vars) [])+ compile (UnaryExpression c (FunctionOperator _ fa@(FunctionSpec _ _ _ _)) e) =+ callFunctionSpec c (Positional [(Nothing,e)]) fa compile (UnaryExpression _ (NamedOperator c "-") (Literal (IntegerLiteral _ _ l))) = compile (Literal (IntegerLiteral c False (-l)))- compile (UnaryExpression _ (NamedOperator c "-") (Literal (DecimalLiteral _ l e))) =- compile (Literal (DecimalLiteral c (-l) e))+ compile (UnaryExpression _ (NamedOperator c "-") (Literal (DecimalLiteral _ l e b))) =+ compile (Literal (DecimalLiteral c (-l) e b)) compile (UnaryExpression _ (NamedOperator c o) e) = do (Positional ts,e') <- compileExpression e t' <- requireSingle c ts@@ -645,13 +672,13 @@ | otherwise = compilerErrorM $ "Cannot use " ++ show t ++ " with unary ~ operator" ++ formatFullContextBrace c compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec _ (CategoryFunction c2 cn) fn ps)) e2) =- compile (Expression c (CategoryCall c2 cn (FunctionCall c fn ps (Positional [e1,e2]))) [])+ compile (Expression c (CategoryCall c2 cn (FunctionCall c fn ps (Positional [(Nothing,e1),(Nothing,e2)]))) []) compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec _ (TypeFunction c2 tn) fn ps)) e2) =- compile (Expression c (TypeCall c2 tn (FunctionCall c fn ps (Positional [e1,e2]))) [])+ compile (Expression c (TypeCall c2 tn (FunctionCall c fn ps (Positional [(Nothing,e1),(Nothing,e2)]))) []) compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec _ (ValueFunction c2 e0) fn ps)) e2) =- compile (Expression c (ParensExpression c2 e0) [ValueCall c (FunctionCall c fn ps (Positional [e1,e2]))])+ compile (Expression c (ParensExpression c2 e0) [ValueCall c AlwaysCall (FunctionCall c fn ps (Positional [(Nothing,e1),(Nothing,e2)]))]) compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec c2 UnqualifiedFunction fn ps)) e2) =- compile (Expression c (UnqualifiedCall c2 (FunctionCall c fn ps (Positional [e1,e2]))) [])+ compile (Expression c (UnqualifiedCall c2 (FunctionCall c fn ps (Positional [(Nothing,e1),(Nothing,e2)]))) []) compile (InfixExpression _ e1 (NamedOperator c o) e2) = do e1' <- compileExpression e1 e2' <- if o `Set.member` logical@@ -679,6 +706,8 @@ bind t1' t2' where bind t1 t2+ | o `Set.member` comparison && isIdentifierRequiredValue t1 && isIdentifierRequiredValue t2 = do+ return (Positional [boolRequiredValue],glueInfix PrimIdentifier PrimBool e1 o e2) | t1 /= t2 = compilerErrorM $ "Cannot " ++ show o ++ " " ++ show t1 ++ " and " ++ show t2 ++ formatFullContextBrace c@@ -726,11 +755,11 @@ (lift $ checkValueAssignment r fa t' vt) <?? "In explicit type conversion at " ++ formatFullContext c return (Positional [vt],e')- transform e (ValueCall c f) = do+ transform e (ValueCall c o f) = do (Positional ts,e') <- e t' <- requireSingle c ts- f' <- lookupValueFunction t' f- compileFunctionCall (Just $ useAsUnwrapped e') f' f+ f' <- lookupValueFunction t' o f+ compileFunctionCall (o == CallUnlessEmpty) (Just $ useAsUnwrapped e') f' f transform e (SelectReturn c pos) = do (Positional ts,e') <- e when (not $ isOpaqueMulti e') $@@ -740,20 +769,37 @@ return (Positional [ts !! pos],WrappedSingle $ useAsReturns e' ++ ".At(" ++ show pos ++ ")") requireSingle _ [t] = return t requireSingle c2 ts =- compilerErrorM $ "Function call requires 1 return but found but found {" ++- intercalate "," (map show ts) ++ "}" ++ formatFullContextBrace c2+ compilerErrorM $ "Function call requires one return but got " ++ formatTypes ts ++ formatFullContextBrace c2+ formatTypes [] = "none"+ formatTypes ts = intercalate ", " (map show ts) +forceOptionalReturns :: [c] -> ScopedFunction c -> ScopedFunction c+forceOptionalReturns c0 (ScopedFunction c n t s v as rs ps fs ms) =+ ScopedFunction c n t s v as rs' ps fs ms where+ rs' = fmap forceOptional rs+ forceOptional (PassedValue c2 (ValueType RequiredValue t2)) = (PassedValue (c0 ++ c2) (ValueType OptionalValue t2))+ forceOptional t2 = t2+ lookupValueFunction :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>- ValueType -> FunctionCall c -> CompilerState a m (ScopedFunction c)-lookupValueFunction (ValueType WeakValue t) (FunctionCall c _ _ _) =+ ValueType -> ValueCallType -> FunctionCall c -> CompilerState a m (ScopedFunction c)+lookupValueFunction (ValueType OptionalValue t) CallUnlessEmpty f@(FunctionCall c _ _ _) = do+ f' <- lookupValueFunction (ValueType RequiredValue t) AlwaysCall f+ return $ forceOptionalReturns c f'+lookupValueFunction t CallUnlessEmpty (FunctionCall c _ _ _) =+ compilerErrorM $ "Optional type required for &. but got " ++ show t ++ formatFullContextBrace c+lookupValueFunction (ValueType WeakValue t) _ (FunctionCall c _ _ _) = compilerErrorM $ "Use strong to convert weak " ++ show t ++ " to optional first" ++ formatFullContextBrace c-lookupValueFunction (ValueType OptionalValue t) (FunctionCall c _ _ _) =+lookupValueFunction (ValueType OptionalValue t) _ (FunctionCall c _ _ _) = compilerErrorM $ "Use require to convert optional " ++ show t ++ " to required first" ++ formatFullContextBrace c-lookupValueFunction (ValueType RequiredValue t) (FunctionCall c n _ _) =- csGetTypeFunction c (Just t) n+lookupValueFunction (ValueType RequiredValue t) _ (FunctionCall c n _ _) = do+ f' <- csGetTypeFunction c (Just t) n+ when (sfScope f' /= ValueScope) $ compilerErrorM $ "Function " ++ show n +++ " cannot be used as a value function" +++ formatFullContextBrace c+ return f' compileExpressionStart :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>@@ -773,11 +819,21 @@ -- NOTE: This will be skipped if expression compilation fails. csReleaseExprMacro c n return e'+compileExpressionStart (ExpressionMacro c MacroCallTrace) = do+ to <- csGetTestsOnly+ when (not to) $ compilerErrorM $ "$CallTrace$ is a $TestsOnly$ macro" ++ formatFullContextBrace c+ csAddRequired $ Set.fromList [BuiltinOrder,BuiltinFormatted]+ let formatted = singleType $ JustTypeInstance (TypeInstance BuiltinFormatted (Positional []))+ let order = singleType $ JustTypeInstance (TypeInstance BuiltinOrder (Positional [formatted]))+ nextFunc <- csGetTypeFunction c (Just order) (FunctionName "next")+ getFunc <- csGetTypeFunction c (Just order) (FunctionName "get")+ let getTrace = "GetCallTrace(" ++ functionName getFunc ++ ", " ++ functionName nextFunc ++ ")"+ return (Positional [orderOptionalValue formatted],UnwrappedSingle getTrace) compileExpressionStart (CategoryCall c t f@(FunctionCall _ n _ _)) = do f' <- csGetCategoryFunction c (Just t) n csAddRequired $ Set.fromList [t,sfType f'] t' <- expandCategory t- compileFunctionCall (Just t') f' f+ compileFunctionCall False (Just t') f' f compileExpressionStart (TypeCall c t f@(FunctionCall _ n _ _)) = do self <- autoSelfType t' <- lift $ replaceSelfInstance self (singleType t)@@ -794,7 +850,7 @@ t2 <- if same then return Nothing else fmap Just $ expandGeneralInstance t'- compileFunctionCall t2 f' f+ compileFunctionCall False t2 f' f where maybeSingleType = lift . tryCompilerM . matchOnlyLeaf checkSame (Just (JustTypeInstance t2)) = csSameType t2@@ -803,7 +859,7 @@ ctx <- get f' <- lift $ collectFirstM [tryCategory ctx,tryNonCategory ctx] <?? "In function call at " ++ formatFullContext c csAddRequired $ Set.fromList [sfType f']- compileFunctionCall Nothing f' f+ compileFunctionCall False Nothing f' f where tryCategory ctx = ccGetCategoryFunction ctx c Nothing n tryNonCategory ctx = do@@ -819,7 +875,7 @@ compilerErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c when (length (pValues es) /= 1) $ compilerErrorM $ "Expected 1 argument" ++ formatFullContextBrace c- es' <- sequence $ map compileExpression $ pValues es+ es' <- sequence $ map (compileExpression . snd) $ pValues es when (length (pValues $ fst $ head es') /= 1) $ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c let (Positional [t0],e) = head es'@@ -827,12 +883,26 @@ compilerErrorM $ "Weak values not allowed here" ++ formatFullContextBrace c return $ (Positional [boolRequiredValue], UnboxedPrimitive PrimBool $ "BoxedValue::Present(" ++ useAsUnwrapped e ++ ")")+compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinIdentify ps es)) = do+ when (length (pValues ps) /= 0) $+ compilerErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c+ when (length (pValues es) /= 1) $+ compilerErrorM $ "Expected 1 argument" ++ formatFullContextBrace c+ es' <- sequence $ map (compileExpression . snd) $ pValues es+ when (length (pValues $ fst $ head es') /= 1) $+ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c+ let (Positional [t0],e) = head es'+ when (isWeakValue t0) $+ compilerErrorM $ "Weak values not allowed here" ++ formatFullContextBrace c+ csAddRequired $ Set.fromList [BuiltinIdentifier]+ return $ (Positional [ValueType RequiredValue (singleType $ JustTypeInstance (TypeInstance BuiltinIdentifier (Positional [(vtType t0)])))],+ UnboxedPrimitive PrimIdentifier $ "BoxedValue::Identify(" ++ useAsUnwrapped e ++ ")") compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinReduce ps es)) = do when (length (pValues ps) /= 2) $ compilerErrorM $ "Expected 2 type parameters" ++ formatFullContextBrace c when (length (pValues es) /= 1) $ compilerErrorM $ "Expected 1 argument" ++ formatFullContextBrace c- es' <- sequence $ map compileExpression $ pValues es+ es' <- sequence $ map (compileExpression . snd) $ pValues es when (length (pValues $ fst $ head es') /= 1) $ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c let (Positional [t0],e) = head es'@@ -857,7 +927,7 @@ compilerErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c when (length (pValues es) /= 1) $ compilerErrorM $ "Expected 1 argument" ++ formatFullContextBrace c- es' <- sequence $ map compileExpression $ pValues es+ es' <- sequence $ map (compileExpression . snd) $ pValues es when (length (pValues $ fst $ head es') /= 1) $ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c let (Positional [t0],e) = head es'@@ -870,7 +940,7 @@ compilerErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c when (length (pValues es) /= 1) $ compilerErrorM $ "Expected 1 argument" ++ formatFullContextBrace c- es' <- sequence $ map compileExpression $ pValues es+ es' <- sequence $ map (compileExpression . snd) $ pValues es when (length (pValues $ fst $ head es') /= 1) $ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c let (Positional [t0],e) = head es'@@ -896,9 +966,15 @@ valueAsWrapped $ UnboxedPrimitive PrimString $ typeBase ++ "::TypeName(" ++ t' ++ ")") compileExpressionStart (BuiltinCall _ _) = undefined compileExpressionStart (ParensExpression _ e) = compileExpression e-compileExpressionStart (InlineAssignment c n e) = do+compileExpressionStart (InlineAssignment c n o e) = do (VariableValue _ s t0 _) <- getWritableVariable c n- (Positional [t],e') <- compileExpression e -- TODO: Get rid of the Positional matching here.+ e2 <- compileExpression e+ when (length (pValues $ fst $ e2) /= 1) $+ compilerErrorM $ "Expected single return" ++ formatFullContextBrace c+ let (Positional [t],e') = e2+ when (o == AssignIfEmpty && not (isOptionalValue t0)) $+ compilerErrorM $ "Variable must have an optional type" ++ formatFullContextBrace c+ when (o == AssignIfEmpty) $ csCheckVariableInit [UsedVariable c n] r <- csResolver fa <- csAllFilters lift $ (checkValueAssignment r fa t t0) <??@@ -906,8 +982,19 @@ csUpdateAssigned n scoped <- autoScope s let lazy = s == CategoryScope- return (Positional [t0],readStoredVariable lazy t0 $ "(" ++ scoped ++ variableName n ++- " = " ++ writeStoredVariable t0 e' ++ ")")+ let variable = scoped ++ variableName n+ let assign = variable ++ " = " ++ writeStoredVariable t0 e'+ let check = "BoxedValue::Present(" ++ useAsUnwrapped (readStoredVariable lazy t0 variable) ++ ")"+ let assignAndGet = readStoredVariable lazy t0 assign+ let alwaysAssign = if isWeakValue t0 && not (isWeakValue t)+ then UnwrappedSingle $ "BoxedValue::Strong(" ++ useAsUnwrapped assignAndGet ++ ")"+ else assignAndGet+ let maybeAssign = readStoredVariable lazy t0 $ check ++ " ? " ++ variable ++ " : (" ++ assign ++ ")"+ case o of+ AlwaysAssign -> return (Positional [t],alwaysAssign)+ AssignIfEmpty -> return (Positional [combineTypes t0 t],maybeAssign)+ where+ combineTypes (ValueType _ t1) (ValueType s _) = ValueType s t1 compileExpressionStart (InitializeValue c t es) = do scope <- csCurrentScope t' <- case scope of@@ -978,10 +1065,17 @@ -- written out as a literal looks like an unsigned overflow. Using ULL here -- silences that warning. return $ expressionFromLiteral PrimInt (show l ++ "ULL")-compileValueLiteral (DecimalLiteral _ l e) = do+compileValueLiteral (DecimalLiteral _ l e 10) = do csAddRequired (Set.fromList [BuiltinFloat]) -- TODO: Check bounds. return $ expressionFromLiteral PrimFloat (show l ++ "E" ++ show e)+compileValueLiteral (DecimalLiteral _ l e b) = do+ csAddRequired (Set.fromList [BuiltinFloat])+ let scale = if e < 0+ then "/" ++ show (b^(-e))+ else "*" ++ show (b^e)+ -- TODO: Check bounds.+ return $ expressionFromLiteral PrimFloat ("(" ++ show l ++ "E0" ++ scale ++ ")") compileValueLiteral (BoolLiteral _ True) = do csAddRequired (Set.fromList [BuiltinBool]) return $ expressionFromLiteral PrimBool "true"@@ -999,12 +1093,12 @@ compileFunctionCall :: (Ord c, Show c, CollectErrorsM m, CompilerContext c m [String] a) =>- Maybe String -> ScopedFunction c -> FunctionCall c ->+ Bool -> Maybe String -> ScopedFunction c -> FunctionCall c -> CompilerState a m (ExpressionType,ExpressionValue)-compileFunctionCall e f (FunctionCall c _ ps es) = message ??> do+compileFunctionCall optionalValue e f (FunctionCall c _ ps es) = message ??> do r <- csResolver fa <- csAllFilters- es' <- sequence $ map compileExpression $ pValues es+ es' <- sequence $ map (compileExpression . snd) $ pValues es (ts,es'') <- lift $ getValues es' f' <- lift $ parsedToFunctionType f let psActual = case ps of@@ -1017,6 +1111,11 @@ lift $ mapCompilerM_ backgroundMessage $ zip3 (map vpParam $ pValues $ sfParams f) (pValues ps') (pValues ps2) -- Called an extra time so arg count mismatches have reasonable errors. lift $ processPairs_ (\_ _ -> return ()) (ftArgs f'') (Positional ts)+ lift $ if (length ts /= length (pValues es))+ then do+ mapCompilerM_ (labelNotAllowedError . fst) $ pValues es+ mapCompilerM_ (labelNotSetError . snd) $ pValues $ sfArgs f+ else processPairs_ checkArgLabel (fmap snd $ sfArgs f) (Positional $ zip ([0..] :: [Int]) $ map fst $ pValues es) lift $ processPairs_ (checkArg r fa) (ftArgs f'') (Positional $ zip ([0..] :: [Int]) ts) csAddRequired $ Set.unions $ map categoriesFromTypes $ pValues ps2 csAddRequired (Set.fromList [sfType f])@@ -1027,18 +1126,23 @@ call <- assemble e scoped scope (sfScope f) paramsArgs return $ (ftReturns f'',OpaqueMulti call) where+ labelNotAllowedError (Just l) = compilerErrorM $ "Arg label " ++ show l ++ " not allowed when forwarding multiple returns"+ labelNotAllowedError _ = return ()+ labelNotSetError (Just l) = compilerErrorM $ "Arg label " ++ show l ++ " cannot be set when forwarding multiple returns"+ labelNotSetError _ = return () replaceSelfParam self (AssignedInstance c2 t) = do t' <- replaceSelfInstance self t return $ AssignedInstance c2 t' replaceSelfParam _ t = return t message = "In call to " ++ show (sfName f) ++ " at " ++ formatFullContext c- backgroundMessage (n,(InferredInstance c2),t) =- compilerBackgroundM $ "Parameter " ++ show n ++ " (from " ++ show (sfType f) ++ "." ++- show (sfName f) ++ ") inferred as " ++ show t ++ " at " ++ formatFullContext c2+ backgroundMessage (n,(InferredInstance c2),t) = do+ let funcName = functionDebugName (sfType f) f+ compilerBackgroundM $ "Parameter " ++ show n ++ " (from " ++ funcName +++ ") inferred as " ++ show t ++ " at " ++ formatFullContext c2 backgroundMessage _ = return () getParamsArgs ps2 paramEs argEs = do psNames <- lift $ collectParamNames ps2- asNames <- lift $ collectArgNames $ pValues es+ asNames <- lift $ collectArgNames $ map snd $ pValues es canForward <- case (psNames,asNames) of (Just pn,Just an) -> csCanForward pn an _ -> return False@@ -1054,11 +1158,14 @@ assemble Nothing scoped _ _ paramsArgs = return $ scoped ++ callName (sfName f) ++ "(" ++ paramsArgs ++ ")" assemble (Just e2) _ _ ValueScope paramsArgs =- return $ valueBase ++ "::Call(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ paramsArgs ++ ")"+ if optionalValue+ then return $ "TYPE_VALUE_CALL_UNLESS_EMPTY(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ paramsArgs ++ ", " ++ show returnCount ++ ")"+ else return $ valueBase ++ "::Call(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ paramsArgs ++ ")" assemble (Just e2) _ _ TypeScope paramsArgs = return $ typeBase ++ "::Call(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ paramsArgs ++ ")" assemble (Just e2) _ _ _ paramsArgs = return $ e2 ++ ".Call(" ++ functionName f ++ ", " ++ paramsArgs ++ ")"+ returnCount = length $ pValues $ sfReturns f -- TODO: Lots of duplication with assignments and initialization. -- Single expression, but possibly multi-return. getValues [(Positional ts,e2)] = return (ts,[useAsArgs e2])@@ -1072,6 +1179,16 @@ compilerErrorM $ "Return position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1" checkArg r fa t0 (i,t1) = do checkValueAssignment r fa t1 t0 <?? "In argument " ++ show i ++ " to " ++ show (sfName f)+ checkArgLabel (Just (CallArgLabel _ n1)) (_,Just (CallArgLabel _ n2))+ | n1 == n2 = return ()+ checkArgLabel l1 (i,l2) = "In argument " ++ show i ++ " to " ++ show (sfName f) ??> labelError l1 l2+ labelError (Just l1) (Just l2) =+ compilerErrorM $ "Expected arg label " ++ show l1 ++ " but got " ++ show l2+ labelError (Just l1) _ =+ compilerErrorM $ "Expected arg label " ++ show l1 ++ " but label is missing"+ labelError _ (Just l2) =+ compilerErrorM $ "Expected no arg label but got " ++ show l2+ labelError _ _ = return () collectParamNames = fmap sequence . mapCompilerM collectParamName collectParamName = fmap getParamName . tryCompilerM . matchOnlyLeaf getParamName (Just (JustParamName _ n)) = Just n@@ -1087,8 +1204,8 @@ Positional ValueType -> m (Positional GeneralInstance) guessParamsFromArgs r fa f ps ts = do fm <- getFunctionFilterMap f- args <- processPairs (\t1 t2 -> return $ TypePattern Covariant t1 t2) ts (fmap pvType $ sfArgs f)- filts <- fmap concat $ processPairs (guessesFromFilters fm) ts (fmap pvType $ sfArgs f)+ args <- processPairs (\t1 t2 -> return $ TypePattern Covariant t1 t2) ts (fmap (pvType . fst) $ sfArgs f)+ filts <- fmap concat $ processPairs (guessesFromFilters fm) ts (fmap (pvType . fst) $ sfArgs f) pa <- fmap Map.fromList $ processPairs toInstance (fmap vpParam $ sfParams f) ps gs <- inferParamTypes r fa pa (args ++ filts) gs' <- mergeInferredTypes r fa fm pa gs@@ -1096,7 +1213,10 @@ fmap Positional $ mapCompilerM (subPosition pa3) (pValues $ sfParams f) where subPosition pa2 p = case (vpParam p) `Map.lookup` pa2 of- Just t -> return t+ Just t -> if not (hasInferredParams t)+ then return t+ else compilerErrorM $ "Could not infer param " +++ show (vpParam p) ++ formatFullContextBrace (vpContext p) Nothing -> compilerErrorM $ "Something went wrong inferring " ++ show (vpParam p) ++ formatFullContextBrace (vpContext p) toInstance p1 (AssignedInstance _ t) = return (p1,t)@@ -1122,17 +1242,39 @@ compileMainProcedure :: (Ord c, Show c, CollectErrorsM m) => CategoryMap c -> ExprMap c -> Expression c -> m (CompiledData [String]) compileMainProcedure tm em e = do- ctx <- getMainContext tm em+ ctx <- getMainContext False tm em runDataCompiler compiler ctx where procedure = Procedure [] [IgnoreValues [] e] compiler = do ctx0 <- getCleanContext compileProcedure ctx0 procedure >>= put +compileWrapTestcase :: (Ord c, Show c, CollectErrorsM m) =>+ CategoryMap c -> ([c],TypeInstance) -> m (CompiledData [String])+compileWrapTestcase tm (c,t) = do+ ctx <- getMainContext False tm Map.empty+ runDataCompiler compiler ctx <??+ "In custom testcase checker at " ++ formatFullContext c+ where+ compiler = do+ ctx0 <- getCleanContext+ lift (execStateT testcase ctx0) >>= put+ testcase = do+ let t2 = singleType $ JustTypeInstance t+ r <- csResolver+ lift $ validateGeneralInstanceForCall r Map.empty t2+ lift $ validateAssignment r Map.empty t2 [DefinesFilter (DefinesInstance BuiltinTestcase (Positional []))]+ start <- csGetTypeFunction c (Just t2) (FunctionName "start")+ finish <- csGetTypeFunction c (Just t2) (FunctionName "finish")+ csAddRequired $ Set.fromList [sfType start,sfType finish]+ csAddRequired $ categoriesFromTypes t2+ t2' <- expandGeneralInstance t2+ csWrite ["WrapTypeCall check_test(" ++ t2' ++ ", &" ++ functionName start ++ ", &" ++ functionName finish ++ ");"]+ compileTestProcedure :: (Ord c, Show c, CollectErrorsM m) => CategoryMap c -> ExprMap c -> TestProcedure c -> m (CompiledData [String]) compileTestProcedure tm em (TestProcedure c n cov p) = do- ctx <- getMainContext tm em+ ctx <- getMainContext True tm em p' <- runDataCompiler compiler ctx <?? "In unittest " ++ show n ++ formatFullContextBrace c return $ mconcat [
src/Parser/Common.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,6 +21,7 @@ module Parser.Common ( ParseFromSource(..), anyComment,+ assignEmptyOperator, assignOperator, blockComment, builtinValues,@@ -43,6 +44,7 @@ kwDefer, kwDefine, kwDefines,+ kwDelegate, kwElif, kwElse, kwEmpty,@@ -51,8 +53,9 @@ kwFalse, kwIf, kwIgnore,- kwIn, kwImmutable,+ kwIn,+ kwIdentify, kwInterface, kwOptional, kwPresent,@@ -72,6 +75,7 @@ kwUnittest, kwUpdate, kwValue,+ kwVisibility, kwWeak, kwWhile, labeled,@@ -92,7 +96,6 @@ parseDec, parseHex, parseOct,- parseSubOne, pragmaArgsEnd, pragmaArgsStart, pragmaEnd,@@ -110,8 +113,10 @@ statementStart, stringChar, string_,+ swapOperator, typeSymbolGet, valueSymbolGet,+ valueSymbolMaybeGet, ) where import Data.Char@@ -145,6 +150,9 @@ valueSymbolGet :: TextParser () valueSymbolGet = sepAfter (string_ ".") +valueSymbolMaybeGet :: TextParser ()+valueSymbolMaybeGet = sepAfter (string_ "&.")+ categorySymbolGet :: TextParser () categorySymbolGet = labeled ":" $ useNewOperators <|> sepAfter (string_ ":") @@ -164,6 +172,12 @@ assignOperator :: TextParser () assignOperator = operator "<-" >> return () +assignEmptyOperator :: TextParser ()+assignEmptyOperator = operator "<-|" >> return ()++swapOperator :: TextParser ()+swapOperator = operator "<->" >> return ()+ infixFuncStart :: TextParser () infixFuncStart = sepAfter (string_ "`") @@ -209,6 +223,9 @@ kwDefines :: TextParser () kwDefines = keyword "defines" +kwDelegate :: TextParser ()+kwDelegate = keyword "delegate"+ kwElif :: TextParser () kwElif = keyword "elif" @@ -230,15 +247,18 @@ kwIf :: TextParser () kwIf = keyword "if" -kwIn :: TextParser ()-kwIn = keyword "in"- kwIgnore :: TextParser () kwIgnore = keyword "_" kwImmutable :: TextParser () kwImmutable = keyword "immutable" +kwIn :: TextParser ()+kwIn = keyword "in"++kwIdentify :: TextParser ()+kwIdentify = keyword "identify"+ kwInterface :: TextParser () kwInterface = keyword "interface" @@ -296,6 +316,9 @@ kwValue :: TextParser () kwValue = keyword "@value" +kwVisibility :: TextParser ()+kwVisibility = keyword "visibility"+ kwWeak :: TextParser () kwWeak = keyword "weak" @@ -330,6 +353,7 @@ kwDefer, kwDefine, kwDefines,+ kwDelegate, kwElif, kwElse, kwEmpty,@@ -337,9 +361,10 @@ kwFail, kwFalse, kwIf,- kwIn, kwIgnore, kwImmutable,+ kwIn,+ kwIdentify, kwInterface, kwOptional, kwPresent,@@ -359,6 +384,7 @@ kwUnittest, kwUpdate, kwValue,+ kwVisibility, kwWeak, kwWhile ]@@ -433,7 +459,7 @@ operator :: String -> TextParser String operator o = labeled o $ do string_ o- notFollowedBy operatorSymbol+ try anyComment <|> notFollowedBy operatorSymbol optionalSpace return o @@ -481,20 +507,17 @@ | c >= 'a' && c <= 'f' = 10 + ord(c) - ord('a') | otherwise = undefined -parseDec :: TextParser Integer-parseDec = labeled "base-10" $ fmap snd $ parseIntCommon 10 digitChar--parseHex :: TextParser Integer-parseHex = labeled "base-16" $ fmap snd $ parseIntCommon 16 hexDigitChar+parseDec :: TextParser (Integer,Integer)+parseDec = labeled "base-10" $ parseIntCommon 10 digitChar -parseOct :: TextParser Integer-parseOct = labeled "base-8" $ fmap snd $ parseIntCommon 8 octDigitChar+parseHex :: TextParser (Integer,Integer)+parseHex = labeled "base-16" $ parseIntCommon 16 hexDigitChar -parseBin :: TextParser Integer-parseBin = labeled "base-2" $ fmap snd $ parseIntCommon 2 (oneOf "01")+parseOct :: TextParser (Integer,Integer)+parseOct = labeled "base-8" $ parseIntCommon 8 octDigitChar -parseSubOne :: TextParser (Integer,Integer)-parseSubOne = parseIntCommon 10 digitChar+parseBin :: TextParser (Integer,Integer)+parseBin = labeled "base-2" $ parseIntCommon 2 (oneOf "01") parseIntCommon :: Integer -> TextParser Char -> TextParser (Integer,Integer) parseIntCommon b p = do
src/Parser/IntegrationTest.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -28,6 +28,7 @@ import Parser.Procedure () import Parser.TextParser import Parser.TypeCategory ()+import Parser.TypeInstance () import Types.IntegrationTest @@ -56,20 +57,26 @@ c <- getSourceContext keyword "error" return $ ExpectCompilerError [c]- resultCrash = labeled "crash expectation" $ do+ resultCrash = labeled "failure expectation" $ do c <- getSourceContext- keyword "crash"- return $ ExpectRuntimeError [c]+ keyword "failure"+ t <- fmap Just parseTestcaseType <|> return Nothing+ return $ ExpectRuntimeError [c] t resultSuccess = labeled "success expectation" $ do c <- getSourceContext keyword "success"- return $ ExpectRuntimeSuccess [c]+ t <- fmap Just parseTestcaseType <|> return Nothing+ return $ ExpectRuntimeSuccess [c] t+ parseTestcaseType = do+ c <- getSourceContext+ t <- sourceParser+ return ([c],t) parseArgs = labeled "testcase args" $ do keyword "args" many (sepAfter quotedString) parseTimeout = labeled "testcase timeout" $ do keyword "timeout"- fmap Just (sepAfter parseDec)+ fmap (Just . snd) (sepAfter parseDec) requireOrExclude = parseAny2 require exclude where require = do keyword "require"
src/Parser/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -133,14 +133,32 @@ parseFailCall <|> parseExitCall <|> parseVoid <|>+ parseSwap <|> parseAssign <|> parsePragma <|> parseIgnore where parseAssign = labeled "assignment" $ do c <- getSourceContext as <- sepBy sourceParser (sepAfter $ string_ ",")+ case as of+ [ExistingVariable (InputValue _ n)] -> parseAssignEmpty c n <|> parseAlwaysAssign c as+ _ -> parseAlwaysAssign c as+ parseAssignEmpty c n = do+ assignEmptyOperator+ e <- sourceParser+ statementEnd+ return $ AssignmentEmpty [c] n e+ parseAlwaysAssign c as = do assignOperator assignExpr c as <|> assignDefer c as+ parseSwap = labeled "swap" $ do+ c <- getSourceContext+ l <- try $ do+ var <- sourceParser+ swapOperator+ return var+ r <- sourceParser+ return $ VariableSwap [c] l r assignExpr c as = do e <- sourceParser statementEnd@@ -411,7 +429,7 @@ asInfix [e] [] <|> return e where -- NOTE: InitializeValue is parsed as ExpressionStart.- notInfix = literal <|> try unaryBuiltin <|> unary <|> expression+ notInfix = literal <|> try unaryBuiltin <|> unary <|> delegatedCall <|> expression asInfix es os = do c <- getSourceContext o <- infixOperator <|> functionOperator@@ -443,16 +461,30 @@ (sepBy sourceParser (sepAfter $ string_ ",")) <|> return [] infixFuncEnd e <- notInfix- return $ Expression [c] (BuiltinCall [c] $ FunctionCall [c] n (Positional ps) (Positional [e])) []+ return $ Expression [c] (BuiltinCall [c] $ FunctionCall [c] n (Positional ps) (Positional [(Nothing,e)])) [] unary = do c <- getSourceContext o <- unaryOperator <|> functionOperator e <- notInfix return $ UnaryExpression [c] o e+ delegatedCall = do+ kwDelegate+ sepAfter_ $ string "->"+ try delegateCall <|> delegateInit+ delegateInit = do+ c <- getSourceContext+ t <- (paramSelf >> return Nothing) <|> fmap Just sourceParser+ return $ DelegatedInitializeValue [c] t+ delegateCall = do+ c <- getSourceContext+ infixFuncStart+ f <- sourceParser+ infixFuncEnd+ return $ DelegatedFunctionCall [c] f expression = labeled "expression" $ do c <- getSourceContext s <- sourceParser- vs <- many sourceParser+ vs <- many (try sourceParser) return $ Expression [c] s vs instance ParseFromSource (FunctionQualifier SourceContext) where@@ -514,24 +546,30 @@ (sepBy sourceParser (sepAfter $ string_ ",")) <|> return [] es <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")")- (sepBy sourceParser (sepAfter $ string_ ","))- return $ FunctionCall [c] n (Positional ps) (Positional es)+ (sepBy parseArg (sepAfter $ string_ ","))+ return $ FunctionCall [c] n (Positional ps) (Positional es) where+ parseArg = do+ l <- try (fmap Just sourceParser) <|> return Nothing+ e <- sourceParser+ return (l,e) builtinFunction :: TextParser FunctionName builtinFunction = foldr (<|>) empty $ map try [- kwPresent >> return BuiltinPresent,- kwReduce >> return BuiltinReduce,- kwRequire >> return BuiltinRequire,- kwStrong >> return BuiltinStrong,+ kwPresent >> return BuiltinPresent,+ kwReduce >> return BuiltinReduce,+ kwRequire >> return BuiltinRequire,+ kwStrong >> return BuiltinStrong,+ kwIdentify >> return BuiltinIdentify, kwTypename >> return BuiltinTypename ] builtinUnary :: TextParser FunctionName builtinUnary = foldr (<|>) empty $ map try [- kwPresent >> return BuiltinPresent,- kwReduce >> return BuiltinReduce,- kwRequire >> return BuiltinRequire,- kwStrong >> return BuiltinStrong+ kwPresent >> return BuiltinPresent,+ kwReduce >> return BuiltinReduce,+ kwRequire >> return BuiltinRequire,+ kwStrong >> return BuiltinStrong,+ kwIdentify >> return BuiltinIdentify ] instance ParseFromSource (ExpressionStart SourceContext) where@@ -542,13 +580,15 @@ builtinValue <|> sourceContext <|> exprLookup <|>+ exprMacro <|> categoryCall <|> -- Keep this before typeCall, since it does a look-ahead for {. initalize <|> typeCall <|> stringLiteral <|> charLiteral <|>- boolLiteral where+ boolLiteral <|>+ emptyLiteral where parens = do c <- getSourceContext sepAfter (string_ "(")@@ -558,9 +598,9 @@ assign :: SourceContext -> TextParser (ExpressionStart SourceContext) assign c = do n <- sourceParser- assignOperator+ o <- (assignEmptyOperator >> return AssignIfEmpty) <|> (assignOperator >> return AlwaysAssign) e <- sourceParser- return $ InlineAssignment [c] n e+ return $ InlineAssignment [c] n o e expr :: SourceContext -> TextParser (ExpressionStart SourceContext) expr c = do e <- sourceParser@@ -584,6 +624,9 @@ case pragma of (PragmaExprLookup c name) -> return $ NamedMacro c name _ -> undefined -- Should be caught above.+ exprMacro = do+ (c,macro) <- macroExpression+ return $ ExpressionMacro [c] macro variableOrUnqualified = do c <- getSourceContext n <- sourceParser :: TextParser VariableName@@ -634,61 +677,62 @@ c <- getSourceContext b <- try $ (kwTrue >> return True) <|> (kwFalse >> return False) return $ UnambiguousLiteral $ BoolLiteral [c] b+ emptyLiteral = do+ c <- getSourceContext+ kwEmpty+ return $ UnambiguousLiteral $ EmptyLiteral [c] instance ParseFromSource (ValueLiteral SourceContext) where sourceParser = labeled "literal" $- -- NOTE: StringLiteral, CharLiteral, and BoolLiteral are parsed- -- as ExpressionStart.- escapedInteger <|>- integerOrDecimal <|>- emptyLiteral where- escapedInteger = do+ -- NOTE: StringLiteral, CharLiteral, BoolLiteral , and+ -- EmptyLiteral are parsed as ExpressionStart.+ escapedIntegerOrDecimal <|>+ integerOrDecimal where+ escapedIntegerOrDecimal = do c <- getSourceContext escapeStart b <- oneOf "bBoOdDxX"- d <- case b of- 'b' -> parseBin- 'B' -> parseBin- 'o' -> parseOct- 'O' -> parseOct- 'd' -> parseDec- 'D' -> parseDec- 'x' -> parseHex- 'X' -> parseHex- _ -> undefined- optionalSpace- return $ IntegerLiteral [c] True d+ let (digitParser,base) = case b of+ 'b' -> (parseBin,2)+ 'B' -> (parseBin,2)+ 'o' -> (parseOct,8)+ 'O' -> (parseOct,8)+ 'd' -> (parseDec,10)+ 'D' -> (parseDec,10)+ 'x' -> (parseHex,16)+ 'X' -> (parseHex,16)+ _ -> undefined+ d <- fmap snd digitParser+ decimal c d False base digitParser <|> integer c d True integerOrDecimal = do c <- getSourceContext- d <- parseDec- decimal c d <|> integer c d- decimal c d = do+ d <- fmap snd parseDec+ decimal c d True 10 parseDec <|> integer c d False+ decimal c d allowExp base digitParser = do char_ '.'- (n,d2) <- parseSubOne- e <- decExponent <|> return 0+ (n,d2) <- digitParser+ e <- if allowExp+ then decExponent <|> return 0+ else return 0 optionalSpace- return $ DecimalLiteral [c] (d*10^n + d2) (e - n)+ return $ DecimalLiteral [c] (d*base^n + d2) (e - n) base decExponent = do string_ "e" <|> string_ "E" s <- (string_ "+" >> return 1) <|> (string_ "-" >> return (-1)) <|> return 1- e <- parseDec+ e <- fmap snd parseDec return (s*e)- integer c d = do+ integer c d unsigned = do optionalSpace- return $ IntegerLiteral [c] False d- emptyLiteral = do- c <- getSourceContext- kwEmpty- return $ EmptyLiteral [c]+ return $ IntegerLiteral [c] unsigned d instance ParseFromSource (ValueOperation SourceContext) where- sourceParser = try valueCall <|> try conversion <|> selectReturn where+ sourceParser = valueCall <|> conversion <|> selectReturn where valueCall = labeled "function call" $ do c <- getSourceContext- valueSymbolGet+ o <- (valueSymbolGet >> return AlwaysCall) <|> (valueSymbolMaybeGet >> return CallUnlessEmpty) n <- sourceParser f <- parseFunctionCall c n- return $ ValueCall [c] f+ return $ ValueCall [c] o f conversion = labeled "type conversion" $ do c <- getSourceContext inferredParam@@ -697,7 +741,7 @@ selectReturn = labeled "return selection" $ do c <- getSourceContext sepAfter_ (string_ "{")- pos <- labeled "return position" parseDec+ pos <- labeled "return position" $ fmap snd parseDec sepAfter_ (string_ "}") return $ SelectReturn [c] (fromIntegral pos) @@ -735,6 +779,10 @@ pragmaSourceContext :: TextParser (PragmaExpr SourceContext) pragmaSourceContext = autoPragma "SourceContext" $ Left parseAt where parseAt c = PragmaSourceContext c++macroExpression :: TextParser (SourceContext,MacroExpression)+macroExpression = callTrace where+ callTrace = autoPragma "CallTrace" $ Left (flip (,) MacroCallTrace) data MarkType = ReadOnly | Hidden deriving (Show)
src/Parser/TypeCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019,2021 Kevin P. Barry+Copyright 2019,2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -69,9 +69,9 @@ open pg <- pragmas (rs,ds,vs) <- parseRefinesDefinesFilters- fs <- flip sepBy optionalSpace $ parseScopedFunction parseScope (return n)+ (fs,fv) <- parseFunctionsWithVisibility $ parseScopedFunction parseScope (return n) close- return $ ValueConcrete [c] NoNamespace n pg ps rs ds vs fs+ return $ ValueConcrete [c] NoNamespace n pg fv ps rs ds vs fs pragmas = fmap (:[]) immutable <|> return [] immutable = do c <- getSourceContext@@ -161,6 +161,43 @@ e <- sepAfter $ many alphaNumChar return $ FunctionName (b:e) +instance ParseFromSource (CallArgLabel SourceContext) where+ sourceParser = labeled "arg label" $ do+ c <- getSourceContext+ b <- lowerChar+ e <- many alphaNumChar+ sepAfter $ char_ ':'+ return $ CallArgLabel [c] (b:e ++ ":")++instance ParseFromSource (FunctionVisibility SourceContext) where+ sourceParser = labeled "visibility" $ do+ c <- getSourceContext+ kwVisibility+ visDefault <|> visTypes c where+ visDefault = do+ kwIgnore+ return $ FunctionVisibilityDefault+ visTypes c = do+ ts <- sepBy1 singleType (sepAfter $ string ",")+ return $ FunctionVisibility [c] ts+ singleType = do+ c <- getSourceContext+ t <- sourceParser+ return ([c],t)++parseFunctionsWithVisibility :: TextParser (ScopedFunction SourceContext) ->+ TextParser ([ScopedFunction SourceContext],[FunctionVisibility SourceContext])+parseFunctionsWithVisibility func = labeled "visibility" $ sepBy anyType optionalSpace >>= merge FunctionVisibilityDefault where+ anyType = fmap Left func <|> fmap Right sourceParser+ merge v0 (Left f:ps) = do+ (fs,vs) <- merge v0 ps+ return (setVis v0 f:fs,vs)+ merge _ (Right v:ps) = do+ (fs,vs) <- merge v ps+ return (fs,v:vs)+ merge _ _ = return ([],[])+ setVis v (ScopedFunction c n t s _ as rs ps fs ms) = (ScopedFunction c n t s v as rs ps fs ms)+ parseScopedFunction :: TextParser SymbolScope -> TextParser CategoryName -> TextParser (ScopedFunction SourceContext) parseScopedFunction sp tp = labeled "function" $ do@@ -168,10 +205,10 @@ (s,t,n) <- try parseName ps <- fmap Positional $ noParams <|> someParams fa <- parseFilters- as <- fmap Positional $ typeList "argument type"+ as <- fmap Positional $ typeList "arg label" singleArg sepAfter_ (string "->")- rs <- fmap Positional $ typeList "return type"- return $ ScopedFunction [c] n t s as rs ps fa []+ rs <- fmap Positional $ typeList "return type" singleReturn+ return $ ScopedFunction [c] n t s FunctionVisibilityDefault as rs ps fa [] where parseName = do s <- sp -- Could be a constant, i.e., nothing consumed.@@ -187,10 +224,16 @@ c <- getSourceContext n <- sourceParser return $ ValueParam [c] n Invariant- typeList l = between (sepAfter $ string_ "(")- (sepAfter $ string_ ")")- (sepBy (labeled l $ singleType) (sepAfter $ string ","))- singleType = do+ typeList l parseVal = between (sepAfter $ string_ "(")+ (sepAfter $ string_ ")")+ (sepBy (labeled l $ parseVal) (sepAfter $ string ","))+ singleArg = do+ c <- getSourceContext+ t <- sourceParser+ optionalSpace+ n <- fmap Just sourceParser <|> return Nothing+ return $ (PassedValue [c] t,n)+ singleReturn = do c <- getSourceContext t <- sourceParser return $ PassedValue [c] t
src/Parser/TypeInstance.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2020,2022 Kevin P. Barry+Copyright 2019-2020,2022-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -82,7 +82,10 @@ | n == "Float" = BuiltinFloat | n == "String" = BuiltinString | n == "Pointer" = BuiltinPointer+ | n == "Identifier" = BuiltinIdentifier | n == "Formatted" = BuiltinFormatted+ | n == "Order" = BuiltinOrder+ | n == "Testcase" = BuiltinTestcase | otherwise = CategoryName n instance ParseFromSource ParamName where
src/Test/ParseMetadata.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -427,12 +427,12 @@ [(MacroName "MY_MACRO", Expression _ (BuiltinCall _ (FunctionCall _ BuiltinRequire (Positional [])- (Positional [Literal (EmptyLiteral _)]))) []),+ (Positional [(Nothing,Expression _ (UnambiguousLiteral (EmptyLiteral _)) [])]))) []), (MacroName "MY_OTHER_MACRO", Expression _ (TypeCall _ _ (FunctionCall _ (FunctionName "execute") (Positional [])- (Positional [Expression _ (UnambiguousLiteral (StringLiteral _ "this is a string\n")) []]))) [])+ (Positional [(Nothing,Expression _ (UnambiguousLiteral (StringLiteral _ "this is a string\n")) [])]))) []) ] -> True _ -> False),
src/Test/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -83,8 +83,11 @@ checkShortParseSuccess "\\ (false).call()", checkShortParseSuccess "\\ false.call()", checkShortParseFail "\\ 1.call()",- checkShortParseFail "\\ empty.call()",+ checkShortParseSuccess "\\ empty.call()", + checkShortParseSuccess "\\ foo(arg1: 123)",+ checkShortParseFail "\\ foo(arg1 : 123)",+ checkShortParseSuccess "x <- var.func()", checkShortParseFail "x <- var.func() var.func()", checkShortParseFail "x <- y <- var.func()",@@ -113,6 +116,19 @@ checkShortParseSuccess "_, weak T<#x> x <- var.func()", checkShortParseFail "_, weak T<#x> x <- T<#x> x", + checkShortParseSuccess "a <-> b",+ checkShortParseFail "self <-> b",+ checkShortParseFail "a <-> self",+ checkShortParseFail "_ <-> b",+ checkShortParseFail "a <-> _",+ checkShortParseFail "\\ a <-> b",+ checkShortParseFail "a, b <-> c",+ checkShortParseFail "a <-> b, c",+ checkShortParseFail "#a <-> b",+ checkShortParseFail "a <-> #b",+ checkShortParseFail "a.foo() <-> b",+ checkShortParseFail "a <-> b.foo()",+ checkShortParseSuccess "if (var.func()) { \\ val.call() }", checkShortParseSuccess "if (present(var)) { \\ val.call() }", checkShortParseFail "if (T<#x> x) { \\ val.call() }",@@ -190,6 +206,15 @@ checkShortParseSuccess "\\ ~x | ~y", checkShortParseSuccess "\\ ~x ^ ~y", + checkShortParseSuccess "\\ a+b",+ checkShortParseFail "\\ a++b",+ checkShortParseFail "\\ a+/b",+ checkShortParseFail "\\ a/=b",+ checkShortParseSuccess "\\ a+/*c*//*c*/d",+ checkShortParseSuccess "\\ a+//c\nd",+ checkShortParseSuccess "\\ a/*c*//*c*/+d",+ checkShortParseSuccess "\\ a//c\n+d",+ checkShortParseSuccess "x <- y + z", checkShortParseSuccess "x <- !y == !z", checkShortParseSuccess "x <- (x + y) / z",@@ -207,7 +232,6 @@ checkShortParseSuccess "x <- \\x123aBc + \\x123aBc", checkShortParseFail "x <- \\x123aQc", checkShortParseFail "x <- \\x",- checkShortParseFail "x <- \\x1.2", checkShortParseSuccess "x <- \" return \\\"\\\" \" + \"1fds\"", checkShortParseFail "x <- \"fsdfd", checkShortParseFail "x <- \"\"fsdfd",@@ -242,6 +266,28 @@ checkShortParseSuccess "x <- `reduce<#x,#y>` y", checkShortParseFail "x <- `typename<#y>` y", + checkShortParseSuccess "x <- 123.456",+ checkShortParseSuccess "x <- \\d123.456",+ checkShortParseFail "x <- 123.",+ checkShortParseFail "x <- \\d123.",+ checkShortParseSuccess "x <- 123.456E1",+ checkShortParseFail "x <- \\d123.456E1",++ checkShortParseSuccess "x <- \\b101.101",+ checkShortParseFail "x <- \\b101.",+ checkShortParseFail "x <- \\b101.101E1",++ checkShortParseSuccess "x <- \\xABC.DEF",+ checkShortParseFail "x <- \\xABC.",++ checkShortParseSuccess "x <- \\o123.456",+ checkShortParseFail "x <- \\o123.",+ checkShortParseFail "x <- \\o123.456E1",++ checkShortParseFail "Int x <-| 123",+ checkShortParseFail "_ <-| 123",+ checkShortParseFail "x, y <-| 123",+ checkParsesAs "'\"'" (\e -> case e of (Expression _ (UnambiguousLiteral (CharLiteral _ '"')) []) -> True@@ -322,7 +368,7 @@ (FunctionSpec _ (ValueFunction _ (Expression _ (BuiltinCall _ (FunctionCall _ BuiltinRequire (Positional [])- (Positional [Expression _ (NamedVariable (OutputValue _ (VariableName "x"))) []]))) []))+ (Positional [(Nothing,Expression _ (NamedVariable (OutputValue _ (VariableName "x"))) [])]))) [])) (FunctionName "foo") (Positional []))) (Literal (IntegerLiteral _ False 2)) -> True _ -> False),@@ -374,7 +420,7 @@ (FunctionSpec _ (ValueFunction _ (Expression _ (BuiltinCall _ (FunctionCall _ BuiltinRequire (Positional [])- (Positional [Expression _ (NamedVariable (OutputValue _ (VariableName "x"))) []]))) []))+ (Positional [(Nothing,Expression _ (NamedVariable (OutputValue _ (VariableName "x"))) [])]))) [])) (FunctionName "not") (Positional []))) (Literal (IntegerLiteral _ False 2)) -> True _ -> False),@@ -424,15 +470,27 @@ _ -> False), checkParsesAs "1.2345" (\e -> case e of- (Literal (DecimalLiteral _ 12345 (-4))) -> True+ (Literal (DecimalLiteral _ 12345 (-4) 10)) -> True _ -> False), checkParsesAs "1.2345E+4" (\e -> case e of- (Literal (DecimalLiteral _ 12345 0)) -> True+ (Literal (DecimalLiteral _ 12345 0 10)) -> True _ -> False), checkParsesAs "1.2345E-4" (\e -> case e of- (Literal (DecimalLiteral _ 12345 (-8))) -> True+ (Literal (DecimalLiteral _ 12345 (-8) 10)) -> True+ _ -> False),++ checkParsesAs "\\xF.F" (\e -> case e of+ (Literal (DecimalLiteral _ 255 (-1) 16)) -> True+ _ -> False),++ checkParsesAs "\\o7.7" (\e -> case e of+ (Literal (DecimalLiteral _ 63 (-1) 8)) -> True+ _ -> False),++ checkParsesAs "\\b1.1" (\e -> case e of+ (Literal (DecimalLiteral _ 3 (-1) 2)) -> True _ -> False), checkParseMatch "$NoTrace$" pragmaNoTrace
src/Test/TypeCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -20,8 +20,9 @@ module Test.TypeCategory (tests) where import Control.Arrow-import Control.Monad ((>=>))+import Control.Monad ((>=>),when) import System.FilePath+import Text.Regex.TDFA import qualified Data.Map as Map import qualified Data.Set as Set @@ -32,7 +33,6 @@ import Parser.TextParser (SourceContext) import Parser.TypeCategory () import Test.Common-import Types.Builtin import Types.TypeCategory import Types.TypeInstance import Types.Variance@@ -84,67 +84,73 @@ checkShortParseFail "concrete Type<#x> { #x defines #self }", checkShortParseFail "@value interface Type { call<#self> () -> () }", - checkOperationSuccess ("testfiles" </> "value_refines_value.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "value_refines_instance.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "value_refines_concrete.0rx") (checkConnectedTypes defaultCategories),+ checkOperationSuccess ("testfiles" </> "value_refines_value.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "value_refines_instance.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "value_refines_concrete.0rx") (checkConnectedTypes emptyCategoryMap), - checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "concrete_refines_instance.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "concrete_refines_concrete.0rx") (checkConnectedTypes defaultCategories),- checkOperationSuccess ("testfiles" </> "concrete_defines_instance.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "concrete_defines_value.0rx") (checkConnectedTypes defaultCategories),- checkOperationFail ("testfiles" </> "concrete_defines_concrete.0rx") (checkConnectedTypes defaultCategories),+ checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "concrete_refines_instance.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "concrete_refines_concrete.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationSuccess ("testfiles" </> "concrete_defines_instance.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "concrete_defines_value.0rx") (checkConnectedTypes emptyCategoryMap),+ checkOperationFail ("testfiles" </> "concrete_defines_concrete.0rx") (checkConnectedTypes emptyCategoryMap), checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx")- (checkConnectedTypes $ Map.fromList [+ (checkConnectedTypes $ toCategoryMap [ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] []) ]), checkOperationFail ("testfiles" </> "concrete_refines_value.0rx")- (checkConnectedTypes $ Map.fromList [+ (checkConnectedTypes $ toCategoryMap [ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] []) ]), checkOperationSuccess ("testfiles" </> "partial.0rx")- (checkConnectedTypes $ Map.fromList [+ (checkConnectedTypes $ toCategoryMap [ (CategoryName "Parent",ValueInterface [] NoNamespace (CategoryName "Parent") [] [] [] []) ]), checkOperationFail ("testfiles" </> "partial.0rx")- (checkConnectedTypes $ Map.fromList [+ (checkConnectedTypes $ toCategoryMap [ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] []) ]), checkOperationFail ("testfiles" </> "partial.0rx")- (checkConnectedTypes $ Map.fromList [- (CategoryName "Parent",ValueConcrete [] NoNamespace (CategoryName "Parent") [] [] [] [] [] [])+ (checkConnectedTypes $ toCategoryMap [+ (CategoryName "Parent",ValueConcrete [] NoNamespace (CategoryName "Parent") [] [] [] [] [] [] []) ]),+ checkOperationFailWith "Parent.+not found"+ ("testfiles" </> "partial.0rx")+ (checkConnectedTypes emptyCategoryMap),+ checkOperationFailWith "Parent.+not visible"+ ("testfiles" </> "partial.0rx")+ (checkConnectedTypes $ CategoryMap (Map.fromList [(CategoryName "Parent",[])]) Map.empty), - checkOperationSuccess ("testfiles" </> "value_refines_value.0rx") (checkConnectionCycles Map.empty),- checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkConnectionCycles Map.empty),- checkOperationSuccess ("testfiles" </> "concrete_defines_instance.0rx") (checkConnectionCycles Map.empty),- checkOperationFail ("testfiles" </> "value_cycle.0rx") (checkConnectionCycles Map.empty),+ checkOperationSuccess ("testfiles" </> "value_refines_value.0rx") (checkConnectionCycles emptyCategoryMap),+ checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx") (checkConnectionCycles emptyCategoryMap),+ checkOperationSuccess ("testfiles" </> "concrete_defines_instance.0rx") (checkConnectionCycles emptyCategoryMap),+ checkOperationFail ("testfiles" </> "value_cycle.0rx") (checkConnectionCycles emptyCategoryMap), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts+ ts2 <- topoSortCategories emptyCategoryMap ts map (show . getCategoryName) ts2 `containsPaired` [ "Object2","Object3","Object1","Type","Parent","Child" ]), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 scrapeAllRefines ts3 `containsExactly` [ ("Object1","Object3<#y>"), ("Object1","Object2"),@@ -164,7 +170,7 @@ checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- existing <- return $ Map.fromList [+ existing <- return $ toCategoryMap [ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] []) ] ts2 <- topoSortCategories existing ts@@ -172,7 +178,7 @@ checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- existing <- return $ Map.fromList [+ existing <- return $ toCategoryMap [ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] []) ] topoSortCategories existing ts),@@ -180,7 +186,7 @@ checkOperationSuccess ("testfiles" </> "partial.0rx") (\ts -> do- existing <- return $ Map.fromList [+ existing <- return $ toCategoryMap [ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [] [] [ValueRefine [] $ TypeInstance (CategoryName "Object1") (Positional []),@@ -198,33 +204,33 @@ ("Child","Object2") ]), - checkOperationSuccess ("testfiles" </> "valid_variances.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "contravariant_refines_covariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "contravariant_refines_invariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "covariant_refines_contravariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "covariant_refines_invariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "contravariant_defines_covariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "contravariant_defines_invariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "covariant_defines_contravariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "covariant_defines_invariant.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "concrete_duplicate_param.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "type_duplicate_param.0rx") (checkParamVariances defaultCategories),- checkOperationFail ("testfiles" </> "value_duplicate_param.0rx") (checkParamVariances defaultCategories),+ checkOperationSuccess ("testfiles" </> "valid_variances.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "contravariant_refines_covariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "contravariant_refines_invariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "covariant_refines_contravariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "covariant_refines_invariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "contravariant_defines_covariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "contravariant_defines_invariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "covariant_defines_contravariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "covariant_defines_invariant.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "concrete_duplicate_param.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "type_duplicate_param.0rx") (checkParamVariances emptyCategoryMap),+ checkOperationFail ("testfiles" </> "value_duplicate_param.0rx") (checkParamVariances emptyCategoryMap), checkOperationSuccess ("testfiles" </> "concrete_refines_value.0rx")- (checkParamVariances $ Map.fromList [+ (checkParamVariances $ toCategoryMap [ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] []) ]), checkOperationFail ("testfiles" </> "concrete_refines_value.0rx")- (checkParamVariances $ Map.fromList [+ (checkParamVariances $ toCategoryMap [ (CategoryName "Parent",InstanceInterface [] NoNamespace (CategoryName "Parent") [] [] []) ]), checkOperationSuccess ("testfiles" </> "partial_params.0rx")- (checkParamVariances $ Map.fromList [+ (checkParamVariances $ toCategoryMap [ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [] [ValueParam [] (ParamName "#w") Contravariant,@@ -232,7 +238,7 @@ ]), checkOperationFail ("testfiles" </> "partial_params.0rx")- (checkParamVariances $ Map.fromList [+ (checkParamVariances $ toCategoryMap [ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [] [ValueParam [] (ParamName "#w") Invariant,@@ -240,7 +246,7 @@ ]), checkOperationFail ("testfiles" </> "partial_params.0rx")- (checkParamVariances $ Map.fromList [+ (checkParamVariances $ toCategoryMap [ (CategoryName "Parent", ValueInterface [] NoNamespace (CategoryName "Parent") [] [ValueParam [] (ParamName "#w") Contravariant,@@ -256,55 +262,55 @@ checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 rs <- getTypeRefines ts3 "Object1<#a,#b>" "Object1" rs `containsPaired` ["#a","#b"]), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 rs <- getTypeRefines ts3 "Object1<#a,#b>" "Object3" rs `containsPaired` ["#b"]), checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 rs <- getTypeRefines ts3 "Undefined<#a,#b>" "Undefined" rs `containsPaired` ["#a","#b"]), checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 rs <- getTypeRefines ts3 "Object1<#a>" "Object1" rs `containsPaired` ["#a"]), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 rs <- getTypeRefines ts3 "Parent<#t>" "Object1" rs `containsPaired` ["#t","Object3<Object2>"]), checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 getTypeRefines ts3 "Parent<#t>" "Child"), checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 getTypeRefines ts3 "Child" "Type"), checkOperationFail ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2 getTypeRefines ts3 "Child" "Missing"), checkOperationSuccess@@ -362,64 +368,64 @@ checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "Child"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "[Child|Child]"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "[Child&Child]"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "Object2"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "[Object2|Object2]"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "[Object2&Object2]"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeFail r [] "Type<Child>"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeFail r [] "[Type<Child>|Type<Child>]"), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ta <- flattenAllConnections defaultCategories ts2 >>= declareAllTypes defaultCategories+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeFail r [] "[Type<Child>&Type<Child>]"), @@ -427,29 +433,29 @@ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "Value0<Value1,Value2>"), checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "Value0<Value1,Value1>"), checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r [] "Value0<Value3,Value2>"), checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r ["#x","#y"]@@ -457,8 +463,8 @@ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r ["#x","#y"]@@ -466,8 +472,8 @@ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r ["#x","#y"]@@ -475,8 +481,8 @@ checkOperationSuccess ("testfiles" </> "filters.0rx") (\ts -> do- ts2 <- topoSortCategories Map.empty ts- ta <- flattenAllConnections Map.empty ts2 >>= declareAllTypes Map.empty+ ts2 <- topoSortCategories emptyCategoryMap ts+ ta <- flattenAllConnections emptyCategoryMap ts2 >>= declareAllTypes emptyCategoryMap let r = CategoryResolver ta checkTypeSuccess r ["#x","#y"]@@ -485,222 +491,222 @@ checkOperationSuccess ("testfiles" </> "requires_concrete.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- checkCategoryInstances defaultCategories ts3),+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2+ checkCategoryInstances emptyCategoryMap ts3), -- TODO: Clean these tests up. checkOperationSuccess ("testfiles" </> "merged.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- ts3 <- flattenAllConnections defaultCategories ts2- tm <- declareAllTypes defaultCategories ts3- rs <- getRefines tm "Test"+ ts2 <- topoSortCategories emptyCategoryMap ts+ ts3 <- flattenAllConnections emptyCategoryMap ts2+ tm <- declareAllTypes emptyCategoryMap ts3+ rs <- getRefines (cmAvailable tm) "Test" rs `containsExactly` ["Value0","Value1","Value2","Value3", "Value4<Value1,Value1>","Inherit1","Inherit2"]), checkOperationSuccess ("testfiles" </> "merged.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "duplicate_refine.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "duplicate_define.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "refine_wrong_direction.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "inherit_incompatible.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "merge_incompatible.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "flatten.0rx") (\ts -> do- let tm0 = Map.fromList [+ let tm0 = toCategoryMap [ (CategoryName "Parent2",InstanceInterface [] NoNamespace (CategoryName "Parent2") [] [] []) ] tm <- includeNewTypes tm0 ts- rs <- getRefines tm "Child"+ rs <- getRefines (cmAvailable tm) "Child" rs `containsExactly` ["Parent<Child>","Object2", "Object1<Child,Object3<Object2>>", "Object3<Object3<Object2>>"]), checkOperationSuccess ("testfiles" </> "category_function_param_match.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_param_clash.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_duplicate_param.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_bad_filter_param.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_bad_allows_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_bad_requires_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "function_bad_defines_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "weak_arg.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "weak_return.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "function_filters_satisfied.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "function_requires_missed.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "function_allows_missed.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "function_defines_missed.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "valid_function_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "bad_value_arg_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "bad_value_return_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "bad_type_arg_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "bad_type_return_variance.0rx")- (\ts -> checkCategoryInstances defaultCategories ts),+ (\ts -> checkCategoryInstances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "valid_filter_variance.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "allows_variance_right.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "defines_variance_right.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "requires_variance_right.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "allows_variance_left.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "defines_variance_left.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationSuccess ("testfiles" </> "requires_variance_left.0rx")- (\ts -> checkParamVariances defaultCategories ts),+ (\ts -> checkParamVariances emptyCategoryMap ts), checkOperationFail ("testfiles" </> "conflicting_declaration.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "conflicting_inherited.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "successful_merge.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "merge_with_refine.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "failed_merge.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "ambiguous_merge_inherit.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "merge_different_scopes.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "successful_merge_params.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "failed_merge_params.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "preserve_merged.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationFail ("testfiles" </> "conflict_in_preserved.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "resolved_in_preserved.0rx") (\ts -> do- ts2 <- topoSortCategories defaultCategories ts- flattenAllConnections defaultCategories ts2 >> return ()),+ ts2 <- topoSortCategories emptyCategoryMap ts+ flattenAllConnections emptyCategoryMap ts2 >> return ()), checkOperationSuccess ("testfiles" </> "valid_self.0rx")- (includeNewTypes defaultCategories >=> const (return ())),+ (includeNewTypes emptyCategoryMap >=> const (return ())), checkOperationFail ("testfiles" </> "bad_merge_self.0rx")- (includeNewTypes defaultCategories >=> const (return ())),+ (includeNewTypes emptyCategoryMap >=> const (return ())), checkOperationFail ("testfiles" </> "contravariant_self.0rx")- (includeNewTypes defaultCategories >=> const (return ())),+ (includeNewTypes emptyCategoryMap >=> const (return ())), checkOperationFail ("testfiles" </> "invariant_self.0rx")- (includeNewTypes defaultCategories >=> const (return ())),+ (includeNewTypes emptyCategoryMap >=> const (return ())), checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Type1","#x")]@@ -708,7 +714,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Type2","#x"),("Type1","#x")]@@ -716,7 +722,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] []@@ -725,7 +731,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface1<Type2>","#x"),("Interface1<Type1>","#x")]@@ -734,7 +740,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<Type2>","#x"),("Interface2<Type1>","#x")]@@ -742,7 +748,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<Type2>","Interface2<#x>"),@@ -752,7 +758,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface3<Type1>","#x"),("Interface3<Type1>","#x")]@@ -760,7 +766,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface3<Type1>","#x"),("Interface3<Type2>","#x")]@@ -768,7 +774,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface3<Type1>","Interface3<#x>"),@@ -777,7 +783,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceFail tm [("#x",[])] ["#x"] [("Interface3<Type1>","Interface3<#x>"),@@ -786,16 +792,17 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts- checkInferenceFail tm+ tm <- includeNewTypes emptyCategoryMap ts+ checkInferenceSuccess tm [("#x",[])] ["#x"] [("Type1","#x"), ("Interface1<Type2>","Interface1<#x>"),- ("Interface2<Type0>","Interface2<#x>")]),+ ("Interface2<Type0>","Interface2<#x>")]+ [("#x","Type1")]), checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface3<Type2>","Interface3<#x>"),@@ -806,7 +813,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface1<Type1>","Interface1<[#x|Interface2<#x>]>")]@@ -814,7 +821,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface1<Type2>","Interface1<[#x&Type1]>")]@@ -822,7 +829,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<Type1>","Interface2<[#x&Interface2<#x>]>")]@@ -830,7 +837,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<Type0>","Interface2<[#x|Type1]>")]@@ -839,7 +846,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] -- Guesses are both Type0 and Type1, and Type0 is more general.@@ -849,7 +856,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] -- An unrelated union shouldn't cause problems.@@ -859,7 +866,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[]),("#y",[])] ["#x","#y"] [("Interface3<Type0>","[Interface1<#x>&Interface3<#x>]"),@@ -869,7 +876,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface1<any>","Interface1<#x>")]@@ -877,7 +884,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<all>","Interface2<#x>")]@@ -886,7 +893,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface1<all>","Interface1<#x>")]@@ -894,7 +901,7 @@ checkOperationSuccess ("testfiles" </> "inference.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("Interface2<any>","Interface2<#x>")]@@ -903,7 +910,7 @@ checkOperationSuccess ("testfiles" </> "delayed_merging.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceFail tm [("#x",[])] ["#x"] -- Guesses are either Type1 or Type2.@@ -911,7 +918,7 @@ checkOperationSuccess ("testfiles" </> "delayed_merging.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] -- Failure to merge Type1 and Type2 is resolved by Base.@@ -922,7 +929,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type1>|Interface3<Type2>]","Interface0<#x>")]@@ -931,7 +938,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type0>|Interface3<Type4>]","Interface0<#x>")]@@ -940,7 +947,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type1>&Interface3<Type2>]","Interface0<#x>")]@@ -949,7 +956,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceFail tm [("#x",[])] ["#x"] -- Guesses are Type0 or Type4, which can't be merged.@@ -957,7 +964,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type1>|Interface3<Type2>]","Interface1<#x>")]@@ -966,7 +973,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type0>|Interface3<Type4>]","Interface1<#x>")]@@ -975,7 +982,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",[])] ["#x"] [("[Interface2<Type1>&Interface3<Type2>]","Interface1<#x>")]@@ -984,7 +991,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceFail tm [("#x",[])] ["#x"] -- Guesses are Type0 or Type4, which can't be merged.@@ -993,7 +1000,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",["requires Type0"])] ["#x"] -- Guesses are Type1 or Type4, which can't be merged, but the filter@@ -1003,7 +1010,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",["allows Type2"])] ["#x"] -- Guesses are Type1 or Type4, which can't be merged, but the filter@@ -1013,7 +1020,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",["defines Defined<#x>"])] ["#x"] -- Guesses are Type1 or Type4, which can't be merged, but the filter@@ -1024,7 +1031,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",["requires Type0"])] ["#x"] [("[Type1|Type2]","#x")]@@ -1032,7 +1039,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceSuccess tm [("#x",["requires #x"])] ["#x"] [("[Type1|Type2]","#x")]@@ -1040,7 +1047,7 @@ checkOperationSuccess ("testfiles" </> "infer_meta.0rx") (\ts -> do- tm <- includeNewTypes defaultCategories ts+ tm <- includeNewTypes emptyCategoryMap ts checkInferenceFail tm [("#x",["requires Type0"])] ["#x"] [("[Type1|Type4]","#x")])@@ -1060,7 +1067,7 @@ getTypeRefines :: Show c => [AnyCategory c] -> String -> String -> TrackedErrors [String] getTypeRefines ts s n = do- ta <- declareAllTypes defaultCategories ts+ ta <- declareAllTypes emptyCategoryMap ts let r = CategoryResolver ta t <- readSingle "(string)" s Positional rs <- trRefines r t (CategoryName n)@@ -1068,7 +1075,7 @@ getTypeDefines :: Show c => [AnyCategory c] -> String -> String -> TrackedErrors [String] getTypeDefines ts s n = do- ta <- declareAllTypes defaultCategories ts+ ta <- declareAllTypes emptyCategoryMap ts let r = CategoryResolver ta t <- readSingle "(string)" s Positional ds <- trDefines r t (CategoryName n)@@ -1076,14 +1083,14 @@ getTypeVariance :: Show c => [AnyCategory c] -> String -> TrackedErrors [Variance] getTypeVariance ts n = do- ta <- declareAllTypes defaultCategories ts+ ta <- declareAllTypes emptyCategoryMap ts let r = CategoryResolver ta (Positional vs) <- trVariance r (CategoryName n) return vs getTypeFilters :: Show c => [AnyCategory c] -> String -> TrackedErrors [[String]] getTypeFilters ts s = do- ta <- declareAllTypes defaultCategories ts+ ta <- declareAllTypes emptyCategoryMap ts let r = CategoryResolver ta t <- readSingle "(string)" s Positional vs <- trTypeFilters r t@@ -1091,7 +1098,7 @@ getTypeDefinesFilters :: Show c => [AnyCategory c] -> String -> TrackedErrors [[String]] getTypeDefinesFilters ts s = do- ta <- declareAllTypes defaultCategories ts+ ta <- declareAllTypes emptyCategoryMap ts let r = CategoryResolver ta t <- readSingle "(string)" s Positional vs <- trDefinesFilters r t@@ -1099,13 +1106,13 @@ scrapeAllRefines :: [AnyCategory c] -> [(String, String)] scrapeAllRefines = map (show *** show) . concat . map scrapeSingle where- scrapeSingle (ValueInterface _ _ n _ _ rs _) = map ((,) n . vrType) rs- scrapeSingle (ValueConcrete _ _ n _ _ rs _ _ _) = map ((,) n . vrType) rs+ scrapeSingle (ValueInterface _ _ n _ _ rs _) = map ((,) n . vrType) rs+ scrapeSingle (ValueConcrete _ _ n _ _ _ rs _ _ _) = map ((,) n . vrType) rs scrapeSingle _ = [] scrapeAllDefines :: [AnyCategory c] -> [(String, String)] scrapeAllDefines = map (show *** show) . concat . map scrapeSingle where- scrapeSingle (ValueConcrete _ _ n _ _ _ ds _ _) = map ((,) n . vdType) ds+ scrapeSingle (ValueConcrete _ _ n _ _ _ _ ds _ _) = map ((,) n . vdType) ds scrapeSingle _ = [] checkPaired :: Show a => (a -> a -> TrackedErrors ()) -> [a] -> [a] -> TrackedErrors ()@@ -1129,6 +1136,20 @@ return $ check (parsed >>= o >> return ()) where check x = x <!! "Check " ++ f ++ ":"++checkOperationFailWith :: String -> String -> ([AnyCategory SourceContext] -> TrackedErrors a) -> IO (TrackedErrors ())+checkOperationFailWith m f o = do+ contents <- loadFile f+ let parsed = readMulti f contents :: TrackedErrors [AnyCategory SourceContext]+ return $ check (parsed >>= o >> return ())+ where+ check c+ | isCompilerError c = do+ let text = show (getCompilerError c)+ when (not $ text =~ m) $+ compilerErrorM $ "Expected pattern " ++ show m ++ " in error output but got\n" ++ text+ | otherwise = compilerErrorM $ "Check " ++ f ++ ": Expected failure but got\n" +++ show (getCompilerSuccess c) ++ "\n" checkOperationFail :: String -> ([AnyCategory SourceContext] -> TrackedErrors a) -> IO (TrackedErrors ()) checkOperationFail f o = do
src/Test/testfiles/allows_variance_left.0rx view
@@ -1,4 +1,4 @@-@value interface Interface {}+@value interface Interface { } concrete Type<|#x> { #x allows Interface
src/Test/testfiles/allows_variance_right.0rx view
@@ -1,4 +1,4 @@-@value interface Interface<|#x> {}+@value interface Interface<|#x> { } concrete Type<#x|> { #x allows Interface<#x>
src/Test/testfiles/ambiguous_merge_inherit.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/bad_type_arg_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#x|> {}+@value interface Type1<#x|> { } @type interface Type2<#x|> { // contravariant * contravariant = covariant
src/Test/testfiles/bad_type_return_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#x|> {}+@value interface Type1<#x|> { } @type interface Type2<|#x> { something () -> (Type1<#x>)
src/Test/testfiles/bad_value_arg_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#x|> {}+@value interface Type1<#x|> { } @value interface Type2<#x|> { // contravariant * contravariant = covariant
src/Test/testfiles/bad_value_return_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#x|> {}+@value interface Type1<#x|> { } @value interface Type2<|#x> { something () -> (Type1<#x>)
src/Test/testfiles/basic_crash_test.0rt view
@@ -1,5 +1,5 @@ testcase "basic crash test" {- crash+ failure require "pattern in output 1" exclude "pattern not in output 1" require "pattern in output 2"
src/Test/testfiles/concrete.0rx view
@@ -1,23 +1,29 @@-concrete/*!!!*/Type<#a,#b // <- contravariant params- |#c,#d // <- invariant params- |#e,#f /* <- covariant params*/> {+concrete/*!!!*/Type<#a, #b // <- contravariant params+ |#c, #d // <- invariant params+ |#e, #f /* <- covariant params*/> { refines /* <- used with value interfaces */ Parent- refines Other<Type2<#a>,#f>- defines /* <- used with type interfaces */ Equals<Type<#a,#b,#c,#d,#e,#f>>+ refines Other<Type2<#a>, #f>+ defines /* <- used with type interfaces */ Equals<Type<#a, #b, #c, #d, #e, #f>> #a allows /* <- used with value-interface filters */ Parent #b requires Type2<#a> #c defines // <- used with type-interface filters Equals<#c /* <- a type arg */> + visibility _+ @category create<#x> #x requires Type1<Type3> () -> (optional Type1<Type3>) + visibility #self+ @type create2<#y> #y requires #x #y allows T2 #y defines T3 () -> (optional #x)++ visibility Append<String> @value get () -> (Type1<Type3>) @value set (Type1<Type3>) -> ()
src/Test/testfiles/concrete_defines_concrete.0rx view
@@ -1,4 +1,4 @@-concrete Parent {}+concrete Parent { } concrete Child { defines Parent
src/Test/testfiles/concrete_defines_instance.0rx view
@@ -1,4 +1,4 @@-@type interface Parent {}+@type interface Parent { } concrete Child { defines Parent
src/Test/testfiles/concrete_defines_value.0rx view
@@ -1,4 +1,4 @@-@value interface Parent {}+@value interface Parent { } concrete Child { defines Parent
src/Test/testfiles/concrete_duplicate_param.0rx view
@@ -1,1 +1,1 @@-concrete Type<#x|#y|#x> {}+concrete Type<#x|#y|#x> { }
src/Test/testfiles/concrete_refines_concrete.0rx view
@@ -1,4 +1,4 @@-concrete Parent {}+concrete Parent { } concrete Child { refines Parent
src/Test/testfiles/concrete_refines_instance.0rx view
@@ -1,4 +1,4 @@-@type interface Parent {}+@type interface Parent { } concrete Child { refines Parent
src/Test/testfiles/concrete_refines_value.0rx view
@@ -1,4 +1,4 @@-@value interface Parent {}+@value interface Parent { } concrete Child { refines Parent
src/Test/testfiles/conflict_in_preserved.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/contravariant_defines_covariant.0rx view
@@ -1,4 +1,4 @@-@type interface Object1<|#x> {}+@type interface Object1<|#x> { } concrete Object2<#y|> { defines Object1<#y>
src/Test/testfiles/contravariant_defines_invariant.0rx view
@@ -1,6 +1,6 @@-@value interface Object1<#x|> {}+@value interface Object1<#x|> { } -@type interface Object2<#z> {}+@type interface Object2<#z> { } concrete Object3<#y|> { // Despite matching variance with Object1, Object2 turns it into invariant.
src/Test/testfiles/contravariant_refines_covariant.0rx view
@@ -1,4 +1,4 @@-@value interface Object1<|#x> {}+@value interface Object1<|#x> { } @value interface Object2<#y|> { refines Object1<#y>
src/Test/testfiles/contravariant_refines_invariant.0rx view
@@ -1,6 +1,6 @@-@value interface Object1<#x|> {}+@value interface Object1<#x|> { } -@value interface Object2<#z> {}+@value interface Object2<#z> { } @value interface Object3<#y|> { // Despite matching variance with Object1, Object2 turns it into invariant.
src/Test/testfiles/covariant_defines_contravariant.0rx view
@@ -1,4 +1,4 @@-@type interface Object1<#x|> {}+@type interface Object1<#x|> { } concrete Object2<|#y> { defines Object1<#y>
src/Test/testfiles/covariant_defines_invariant.0rx view
@@ -1,6 +1,6 @@-@value interface Object1<|#x> {}+@value interface Object1<|#x> { } -@type interface Object2<#z> {}+@type interface Object2<#z> { } concrete Object3<|#y> { // Despite matching variance with Object1, Object2 turns it into invariant.
src/Test/testfiles/covariant_refines_contravariant.0rx view
@@ -1,4 +1,4 @@-@value interface Object1<#x|> {}+@value interface Object1<#x|> { } @value interface Object2<|#y> { refines Object1<#y>
src/Test/testfiles/covariant_refines_invariant.0rx view
@@ -1,6 +1,6 @@-@value interface Object1<|#x> {}+@value interface Object1<|#x> { } -@value interface Object2<#z> {}+@value interface Object2<#z> { } @value interface Object3<|#y> { // Despite matching variance with Object1, Object2 turns it into invariant.
src/Test/testfiles/defines_variance_left.0rx view
@@ -1,4 +1,4 @@-@type interface Interface {}+@type interface Interface { } concrete Type<#x|> { #x defines Interface
src/Test/testfiles/defines_variance_right.0rx view
@@ -1,4 +1,4 @@-@type interface Interface<|#x> {}+@type interface Interface<|#x> { } concrete Type<|#x> { #x defines Interface<#x>
src/Test/testfiles/delayed_merging.0rx view
@@ -1,4 +1,4 @@-@value interface Base {}+@value interface Base { } concrete Type1 { refines Base@@ -8,9 +8,9 @@ refines Base } -@value interface Interface1<|#x> {}+@value interface Interface1<|#x> { } -@value interface Interface2<|#x> {}+@value interface Interface2<|#x> { } concrete Type { refines Interface1<Type1>
src/Test/testfiles/duplicate_define.0rx view
@@ -1,10 +1,10 @@-@value interface Value0 {}+@value interface Value0 { } @value interface Value1 { refines Value0 } -@type interface Type0<|#x> {}+@type interface Type0<|#x> { } concrete Object { defines Type0<Value0>
src/Test/testfiles/duplicate_refine.0rx view
@@ -1,10 +1,10 @@-@value interface Value0 {}+@value interface Value0 { } @value interface Value1 { refines Value0 } -@value interface Value2<|#x> {}+@value interface Value2<|#x> { } concrete Object { refines Value2<Value0>
src/Test/testfiles/failed_merge.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/failed_merge_params.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#a> {}+@value interface Type1<#a> { } @value interface Type2<#b> { refines Type1<#b>@@ -9,14 +9,14 @@ } @value interface Interface1<#j> {- something<#x,#y>+ something<#x, #y> #x requires Type2<#j> #y allows Type1<#j> (#x) -> (#y) } @value interface Interface2<#k> {- something<#w,#z>+ something<#w, #z> #w requires Type3<#k> #z allows Type3<#k> (#w) -> (#z)@@ -26,7 +26,7 @@ refines Interface1<#q> refines Interface2<#q> - @value something<#r,#s>+ @value something<#r, #s> #r requires Type2<#q> #s allows Type2<#q> (#r) -> (#s)
src/Test/testfiles/filters.0rx view
@@ -1,16 +1,16 @@-@type interface Equals<#x|> {}+@type interface Equals<#x|> { } -@value interface Function<#y|#z> {}+@value interface Function<#y|#z> { } -concrete Value0<#t,#w> {+concrete Value0<#t, #w> { #t allows #w- #t requires Function<#t,#w>+ #t requires Function<#t, #w> #w requires #t #w defines Equals<#w> } @value interface Value1 {- refines Function<Value1,Value2>+ refines Function<Value1, Value2> } concrete Value2 {
src/Test/testfiles/flatten.0rx view
@@ -1,15 +1,15 @@-@value interface Object1<#x,#y> {+@value interface Object1<#x, #y> { refines Object3<#y> // -> refines Object2 } -@value interface Object2 {}+@value interface Object2 { } -@type interface Type<#x> {}+@type interface Type<#x> { } concrete Child { refines Parent<Child>- // -> refines Object1<Child,Object3<Object2>>+ // -> refines Object1<Child, Object3<Object2>> // -> refines Object3<Object3<Object2>> // -> refines Object2 @@ -17,7 +17,7 @@ } @value interface Parent<#x> {- refines Object1<#x,Object3<Object2>>+ refines Object1<#x, Object3<Object2>> // -> refines Object3<Object3<Object2>> // -> refines Object2 }
src/Test/testfiles/function_allows_missed.0rx view
@@ -1,8 +1,8 @@-@type interface Type1 {}+@type interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } -@value interface Type3 {}+@value interface Type3 { } concrete Type4<#x> { #x requires Type2
src/Test/testfiles/function_bad_allows_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Interface<#x|> {}+@value interface Interface<#x|> { } concrete Type<|#x> { @value something<#y>
src/Test/testfiles/function_bad_defines_variance.0rx view
@@ -1,4 +1,4 @@-@type interface Interface<|#x> {}+@type interface Interface<|#x> { } concrete Type<|#x> { @value something<#y>
src/Test/testfiles/function_bad_requires_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Interface<|#x> {}+@value interface Interface<|#x> { } concrete Type<|#x> { @value something<#y>
src/Test/testfiles/function_defines_missed.0rx view
@@ -1,8 +1,8 @@-@type interface Type1 {}+@type interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } -@value interface Type3 {}+@value interface Type3 { } concrete Type4<#x> { #x requires Type2
src/Test/testfiles/function_duplicate_param.0rx view
@@ -1,4 +1,4 @@ concrete Type {- @value something<#x,#x>+ @value something<#x, #x> () -> () }
src/Test/testfiles/function_filter_type_param.0rx view
@@ -1,11 +1,11 @@-@value interface Base1 {}+@value interface Base1 { } -@type interface Base2 {}+@type interface Base2 { } concrete Type<#x|#y|#z> { @type call #x allows Base1 #y requires Base1 #z defines Base2- (#x,#y) -> (#y,#z)+ (#x, #y) -> (#y, #z) }
src/Test/testfiles/function_filters_satisfied.0rx view
@@ -1,23 +1,23 @@-@type interface Type1<#x> {}+@type interface Type1<#x> { } -@value interface Type2<#x|> {}+@value interface Type2<#x|> { } -@value interface Type3<#x|> {}+@value interface Type3<#x|> { } -concrete Type4<#w,#x> {+concrete Type4<#w, #x> { #w requires Type2<#w> #x allows Type3<#x> #w defines Type1<#w> - @type something<#y,#z>+ @type something<#y, #z> #y requires Type2<#y> #z allows Type3<#z> #y defines Type1<#y>- () -> (Type4<#y,#z>)+ () -> (Type4<#y, #z>) - @type something2<#y,#z>+ @type something2<#y, #z> #y requires #w #z allows #x #y defines Type1<#y>- () -> (Type4<#y,#z>)+ () -> (Type4<#y, #z>) }
src/Test/testfiles/function_requires_missed.0rx view
@@ -1,8 +1,8 @@-@type interface Type1 {}+@type interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } -@value interface Type3 {}+@value interface Type3 { } concrete Type4<#x> { #x requires Type2
src/Test/testfiles/infer_meta.0rx view
@@ -1,4 +1,4 @@-@value interface Type0 {}+@value interface Type0 { } @value interface Type1 { refines Type0@@ -12,11 +12,11 @@ defines Defined<Type4> } -@type interface Defined<#x> {}+@type interface Defined<#x> { } -@value interface Interface0<|#x> {}+@value interface Interface0<|#x> { } -@value interface Interface1<#y|> {}+@value interface Interface1<#y|> { } @value interface Interface2<#y> { refines Interface0<#y>
src/Test/testfiles/inference.0rx view
@@ -1,14 +1,14 @@-@value interface Interface1<|#x> {}+@value interface Interface1<|#x> { } -@value interface Interface2<#y|> {}+@value interface Interface2<#y|> { } @value interface Interface3<#z> { refines Interface1<Type1> } -@value interface Interface4<#x|#y|#z> {}+@value interface Interface4<#x|#y|#z> { } -@value interface Type0 {}+@value interface Type0 { } @value interface Type1 { refines Type0
src/Test/testfiles/inherit_incompatible.0rx view
@@ -1,4 +1,4 @@-@value interface Base {}+@value interface Base { } @value interface Child1 { refines Base@@ -8,7 +8,7 @@ refines Base } -@value interface Inherit<#x|> {}+@value interface Inherit<#x|> { } @value interface Parent1 { refines Inherit<Child1>
src/Test/testfiles/internal.0rx view
@@ -1,5 +1,5 @@ $TestsOnly$ -concrete Type {}+concrete Type { } -define Type {}+define Type { }
src/Test/testfiles/invariant_self.0rx view
@@ -1,4 +1,4 @@-@value interface Base<#x> {}+@value interface Base<#x> { } @value interface Value<#x|#y|#z> { refines Base<#self>
src/Test/testfiles/merge_incompatible.0rx view
@@ -1,4 +1,4 @@-@value interface Base {}+@value interface Base { } @value interface Child1 { refines Base@@ -8,7 +8,7 @@ refines Base } -@value interface Inherit<#x|> {}+@value interface Inherit<#x|> { } @value interface Parent1 { refines Inherit<Child1>
src/Test/testfiles/merged.0rx view
@@ -1,4 +1,4 @@-@value interface Value0 {}+@value interface Value0 { } @value interface Value1 { refines Value0@@ -12,16 +12,16 @@ refines Value0 } -@value interface Value4<#x|#y> {}+@value interface Value4<#x|#y> { } -@type interface Type0<#x|#y> {}+@type interface Type0<#x|#y> { } @value interface Inherit1 {- refines Value4<Value1,Value1>+ refines Value4<Value1, Value1> } @value interface Inherit2 {- refines Value4<Value2,Value0>+ refines Value4<Value2, Value0> } concrete Test {
src/Test/testfiles/partial_params.0rx view
@@ -1,3 +1,3 @@ concrete Child<#x|#y> {- refines Parent<#x,#y>+ refines Parent<#x, #y> }
src/Test/testfiles/preserve_merged.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/procedures.0rx view
@@ -1,4 +1,4 @@-testFunction1 (a,b,c) (d,e,f) {+testFunction1 (a, b, c) (d, e, f) { if (T.f()) { // do nothing } elif (#q.r().f()) {@@ -7,12 +7,12 @@ // sleep } - x <- Type<#z,T<#m>>{ r, Type.new() }+ x <- Type<#z, T<#m>>{ r, Type.new() } x <- empty scoped {- optional T myvar <- reduce<#x,#y>(q)+ optional T myvar <- reduce<#x, #y>(q) } in if (present(myvar)) { \ unqualified() } else {@@ -20,7 +20,7 @@ } scoped {- optional T myvar <- reduce<#x,#y>(q)+ optional T myvar <- reduce<#x, #y>(q) } in v, _ <- x.process(myvar) scoped {@@ -30,7 +30,7 @@ } in \ x.process() \ z.call().call()- x, weak [#k|Type] y, _ <- z.call()+ x, weak [#k | Type] y, _ <- z.call() x <- z?T<#z>.call().call() return _ return a@@ -44,4 +44,4 @@ } } -testFunction2 (a,b,c) {}+testFunction2 (a, b, c) { }
src/Test/testfiles/public.0rp view
@@ -1,4 +1,4 @@ $ModuleOnly$ $TestsOnly$ -concrete Type {}+concrete Type { }
src/Test/testfiles/refine_wrong_direction.0rx view
@@ -1,10 +1,10 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1 } -@value interface Inherited<|#x> {}+@value interface Inherited<|#x> { } @value interface Parent { refines Inherited<Type2>
src/Test/testfiles/requires_variance_left.0rx view
@@ -1,4 +1,4 @@-@value interface Interface {}+@value interface Interface { } concrete Type<#x|> { #x requires Interface
src/Test/testfiles/requires_variance_right.0rx view
@@ -1,4 +1,4 @@-@value interface Interface<|#x> {}+@value interface Interface<|#x> { } concrete Type<|#x> { #x requires Interface<#x>
src/Test/testfiles/resolved_in_preserved.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/successful_merge.0rx view
@@ -1,4 +1,4 @@-@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1
src/Test/testfiles/successful_merge_params.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#a> {}+@value interface Type1<#a> { } @value interface Type2<#b> { refines Type1<#b>@@ -9,14 +9,14 @@ } @value interface Interface1<#j> {- something<#x,#y>+ something<#x, #y> #x requires Type2<#j> #y allows Type1<#j> (#x) -> (#y) } @value interface Interface2<#k> {- something<#w,#z>+ something<#w, #z> #w requires Type3<#k> #z allows Type1<#k> (#w) -> (#z)@@ -26,7 +26,7 @@ refines Interface1<#q> refines Interface2<#q> - @value something<#r,#s>+ @value something<#r, #s> #r requires Type2<#q> #s allows Type2<#q> (#r) -> (#s)
src/Test/testfiles/test.0rt view
@@ -11,5 +11,5 @@ } define Test {- run () {}+ run () { } }
src/Test/testfiles/type_duplicate_param.0rx view
@@ -1,1 +1,1 @@-@type interface Type<#x|#y|#x> {}+@type interface Type<#x|#y|#x> { }
src/Test/testfiles/type_interface.0rx view
@@ -1,4 +1,4 @@-@type interface Type<#a,#b|#c,#d|#e,#f> {+@type interface Type<#a, #b|#c, #d|#e, #f> { create () -> (optional #x) create2<#y>
src/Test/testfiles/valid_filter_variance.0rx view
@@ -1,16 +1,16 @@-@value interface Interface1<#x|> {}+@value interface Interface1<#x|> { } concrete Type1<#x|> { #x allows Interface1<#x> } -@type interface Interface2<#x|> {}+@type interface Interface2<#x|> { } concrete Type2<|#x> { #x defines Interface2<#x> } -@value interface Interface3<#x|> {}+@value interface Interface3<#x|> { } concrete Type3<|#x> { #x requires Interface3<#x>
src/Test/testfiles/valid_function_variance.0rx view
@@ -1,4 +1,4 @@-@value interface Type1<#x|> {}+@value interface Type1<#x|> { } @value interface Type2<#x|> { // arg: contravariant * contravariant * contravariant = contravariant
src/Test/testfiles/valid_self.0rx view
@@ -1,4 +1,4 @@-@value interface Base<|#x> {}+@value interface Base<|#x> { } @value interface Value<#x|#y|#z> { refines Base<#self>@@ -6,11 +6,11 @@ } concrete Child1 {- refines Value<all,all,all>+ refines Value<all, all, all> @value call () -> (#self) } concrete Child2 {- refines Value<all,all,all>+ refines Value<all, all, all> @value call () -> (all) }
src/Test/testfiles/valid_variances.0rx view
@@ -1,6 +1,6 @@-@value interface Object1<#x|> {}+@value interface Object1<#x|> { } -@value interface Object2<|#y> {}+@value interface Object2<|#y> { } @value interface Object3<#w|#z> { refines Object1<#w>@@ -8,7 +8,7 @@ } @value interface Object4<#t> {- refines Object3<#t,#t>+ refines Object3<#t, #t> } @value interface Object5<|#q> {@@ -16,7 +16,7 @@ refines Object1<Object1<#q>> } -@type interface Object6<|#x> {}+@type interface Object6<|#x> { } concrete Object7<|#s> { // Variance reversed twice by Object1.
src/Test/testfiles/value_duplicate_param.0rx view
@@ -1,1 +1,1 @@-@value interface Type<#x|#y|#x> {}+@value interface Type<#x|#y|#x> { }
src/Test/testfiles/value_interface.0rx view
@@ -1,6 +1,6 @@-@value interface Type<#a,#b|#c,#d|#e,#f> {+@value interface Type<#a, #b|#c, #d|#e, #f> { refines Parent- refines Other<Type2<#a>,#f>+ refines Other<Type2<#a>, #f> get () -> (#x) set (#x) -> ()
src/Test/testfiles/value_refines_concrete.0rx view
@@ -1,4 +1,4 @@-concrete Parent {}+concrete Parent { } @value interface Child { refines Parent
src/Test/testfiles/value_refines_instance.0rx view
@@ -1,4 +1,4 @@-@type interface Parent {}+@type interface Parent { } @value interface Child { refines Parent
src/Test/testfiles/value_refines_value.0rx view
@@ -1,4 +1,4 @@-@value interface Parent {}+@value interface Parent { } @value interface Child { refines Parent
src/Types/Builtin.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,6 +16,7 @@ -- Author: Kevin P. Barry [ta0kira@gmail.com] +{-# LANGUAGE CPP #-} {-# LANGUAGE Safe #-} module Types.Builtin (@@ -23,29 +24,26 @@ PrimitiveType(..), boolRequiredValue, charRequiredValue,- defaultCategories, emptyType, floatRequiredValue, formattedRequiredValue, intRequiredValue,+ isIdentifierRequiredValue, isPointerRequiredValue, isOpaqueMulti, orderOptionalValue,+ requiredStaticTypes, stringRequiredValue, ) where -import qualified Data.Map as Map+import qualified Data.Set as Set import Base.GeneralType import Base.MergeTree (reduceMergeTree) import Base.Positional-import Types.TypeCategory import Types.TypeInstance -defaultCategories :: CategoryMap c-defaultCategories = Map.empty- boolRequiredValue :: ValueType boolRequiredValue = requiredSingleton BuiltinBool stringRequiredValue :: ValueType@@ -68,6 +66,13 @@ extractSingle = reduceMergeTree (const Nothing) (const Nothing) Just isPointerRequiredValue _ = False +isIdentifierRequiredValue :: ValueType -> Bool+isIdentifierRequiredValue (ValueType RequiredValue t) = check $ extractSingle t where+ check (Just (JustTypeInstance (TypeInstance BuiltinIdentifier (Positional [_])))) = True+ check _ = False+ extractSingle = reduceMergeTree (const Nothing) (const Nothing) Just+isIdentifierRequiredValue _ = False+ emptyType :: ValueType emptyType = ValueType OptionalValue minBound @@ -77,7 +82,8 @@ PrimInt | PrimFloat | PrimString |- PrimPointer+ PrimPointer |+ PrimIdentifier deriving (Eq,Show) data ExpressionValue =@@ -98,3 +104,19 @@ isOpaqueMulti :: ExpressionValue -> Bool isOpaqueMulti (OpaqueMulti _) = True isOpaqueMulti _ = False++requiredStaticTypes :: Set.Set CategoryName+#ifdef darwin_HOST_OS+-- Weak linking doesn't work on MacOS, so we need these in order to link against+-- boxed.cpp without linker errors.+requiredStaticTypes = Set.fromList [+ BuiltinBool,+ BuiltinChar,+ BuiltinInt,+ BuiltinFloat,+ BuiltinPointer,+ BuiltinIdentifier+ ]+#else+requiredStaticTypes = Set.empty+#endif
src/Types/DefinedCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -143,12 +143,12 @@ foldr (update fm) (return start) fs where start = Map.fromList $ map (\f -> (sfName f,f)) $ getCategoryFunctions t pm = getCategoryParamMap t- update fm f@(ScopedFunction c n t2 s as rs ps fs2 ms) fa = do+ update fm f@(ScopedFunction c n t2 s v as rs ps fs2 ms) fa = do validateCategoryFunction r t f fa' <- fa case n `Map.lookup` fa' of Nothing -> return $ Map.insert n f fa'- (Just f0@(ScopedFunction c2 _ _ _ _ _ _ _ ms2)) -> do+ (Just f0@(ScopedFunction c2 _ _ _ _ _ _ _ _ ms2)) -> do ("In function merge:\n---\n" ++ show f0 ++ "\n ->\n" ++ show f ++ "\n---\n") ??> do f0' <- parsedToFunctionType f0@@ -156,7 +156,7 @@ case s of CategoryScope -> checkFunctionConvert r Map.empty Map.empty f0' f' _ -> checkFunctionConvert r fm pm f0' f'- return $ Map.insert n (ScopedFunction (c++c2) n t2 s as rs ps fs2 ([f0]++ms++ms2)) fa'+ return $ Map.insert n (ScopedFunction (c++c2) n t2 s v as rs ps fs2 ([f0]++ms++ms2)) fa' pairProceduresToFunctions :: (Show c, CollectErrorsM m) => Map.Map FunctionName (ScopedFunction c) -> [ExecutableProcedure c] ->@@ -189,7 +189,7 @@ formatFullContextBrace (epContext p) ++ " does not correspond to a function" getPair (Just f) (Just p) = do- processPairs_ alwaysPair (fmap pvType $ sfArgs f) (fmap inputValueName $ avNames $ epArgs p) <!!+ processPairs_ alwaysPair (fmap (pvType . fst) $ sfArgs f) (fmap inputValueName $ avNames $ epArgs p) <!! ("Procedure for " ++ show (sfName f) ++ formatFullContextBrace (avContext $ epArgs p) ++ " has the wrong number of arguments" ++@@ -229,13 +229,13 @@ -- TODO: Most of this duplicates parts of flattenAllConnections. mergeInternalInheritance :: (Show c, CollectErrorsM m) => CategoryMap c -> DefinedCategory c -> m (CategoryMap c)-mergeInternalInheritance tm d = "In definition of " ++ show (dcName d) ++ formatFullContextBrace (dcContext d) ??> do+mergeInternalInheritance cm@(CategoryMap km tm) d = "In definition of " ++ show (dcName d) ++ formatFullContextBrace (dcContext d) ??> do let rs2 = dcRefines d let ds2 = dcDefines d- (_,t@(ValueConcrete c ns n pg ps rs ds vs fs)) <- getConcreteCategory tm (dcContext d,dcName d)- let c2 = ValueConcrete c ns n pg ps (rs++rs2) (ds++ds2) vs fs+ (_,t@(ValueConcrete c ns n pg fv ps rs ds vs fs)) <- getConcreteCategory cm (dcContext d,dcName d)+ let c2 = ValueConcrete c ns n pg fv ps (rs++rs2) (ds++ds2) vs fs let tm' = Map.insert (dcName d) c2 tm- let r = CategoryResolver tm'+ let r = CategoryResolver (CategoryMap km tm') fm <- getCategoryFilterMap t let pm = getCategoryParamMap t rs2' <- fmap concat $ mapCompilerM (flattenRefine r) rs2@@ -249,17 +249,17 @@ pg2 <- fmap concat $ mapCompilerM getRefinesPragmas rs2 pg3 <- fmap concat $ mapCompilerM getDefinesPragmas ds2 let fs2 = mergeInternalFunctions fs (dcFunctions d)- fs' <- mergeFunctions r tm' pm fm rs' ds' fs2- let c2' = ValueConcrete c ns n (pg++pg2++pg3) ps rs' ds' vs fs'+ fs' <- mergeFunctions r (CategoryMap km tm') pm fm rs' ds' fs2+ let c2' = ValueConcrete c ns n (pg++pg2++pg3) fv ps rs' ds' vs fs' let tm0 = (dcName d) `Map.delete` tm- checkCategoryInstances tm0 [c2']- return $ Map.insert (dcName d) c2' tm+ checkCategoryInstances (CategoryMap km tm0) [c2']+ return $ CategoryMap km $ Map.insert (dcName d) c2' tm where getRefinesPragmas rf = do- (_,t) <- getCategory tm (vrContext rf,tiName $ vrType rf)+ (_,t) <- getCategory cm (vrContext rf,tiName $ vrType rf) return $ map (prependCategoryPragmaContext $ vrContext rf) $ getCategoryPragmas t getDefinesPragmas df = do- (_,t) <- getCategory tm (vdContext df,diName $ vdType df)+ (_,t) <- getCategory cm (vdContext df,diName $ vdType df) return $ map (prependCategoryPragmaContext $ vdContext df) $ getCategoryPragmas t mergeInternalFunctions fs1 = Map.elems . foldr single (funcMap fs1) funcMap = Map.fromList . map (\f -> (sfName f,f))@@ -271,6 +271,7 @@ sfName = sfName f, sfType = sfType f, sfScope = sfScope f,+ sfVisibility = sfVisibility f, sfArgs = sfArgs f, sfReturns = sfReturns f, sfParams = sfParams f,@@ -284,7 +285,7 @@ validateDefinesVariance r vm Covariant t <?? "In " ++ show t ++ formatFullContextBrace c flattenRefine r ra@(ValueRefine c t) = do- (_,t2) <- getValueCategory tm (c,tiName t)+ (_,t2) <- getValueCategory cm (c,tiName t) rs <- mapCompilerM (singleRefine r ra) (getCategoryRefines t2) return (ra:rs) singleRefine r (ValueRefine c t) (ValueRefine c2 t2) = do
src/Types/IntegrationTest.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -33,6 +33,7 @@ ) where import Types.TypeCategory+import Types.TypeInstance import Types.DefinedCategory import Types.Procedure @@ -67,11 +68,13 @@ } | ExpectRuntimeError { ereContext :: [c],+ ereCategory :: Maybe ([c],TypeInstance), ereRequirePattern :: [OutputPattern], ereExcludePattern :: [OutputPattern] } | ExpectRuntimeSuccess { ersContext :: [c],+ ersCategory :: Maybe ([c],TypeInstance), ersRequirePattern :: [OutputPattern], ersExcludePattern :: [OutputPattern] }@@ -94,21 +97,21 @@ isExpectCompilerError _ = False isExpectRuntimeError :: ExpectedResult c -> Bool-isExpectRuntimeError (ExpectRuntimeError _ _ _) = True-isExpectRuntimeError _ = False+isExpectRuntimeError (ExpectRuntimeError _ _ _ _) = True+isExpectRuntimeError _ = False isExpectRuntimeSuccess :: ExpectedResult c -> Bool-isExpectRuntimeSuccess (ExpectRuntimeSuccess _ _ _) = True-isExpectRuntimeSuccess _ = False+isExpectRuntimeSuccess (ExpectRuntimeSuccess _ _ _ _) = True+isExpectRuntimeSuccess _ = False getRequirePattern :: ExpectedResult c -> [OutputPattern]-getRequirePattern (ExpectCompiles _ rs _) = rs-getRequirePattern (ExpectCompilerError _ rs _) = rs-getRequirePattern (ExpectRuntimeError _ rs _) = rs-getRequirePattern (ExpectRuntimeSuccess _ rs _) = rs+getRequirePattern (ExpectCompiles _ rs _) = rs+getRequirePattern (ExpectCompilerError _ rs _) = rs+getRequirePattern (ExpectRuntimeError _ _ rs _) = rs+getRequirePattern (ExpectRuntimeSuccess _ _ rs _) = rs getExcludePattern :: ExpectedResult c -> [OutputPattern]-getExcludePattern (ExpectCompiles _ _ es) = es-getExcludePattern (ExpectCompilerError _ _ es) = es-getExcludePattern (ExpectRuntimeError _ _ es) = es-getExcludePattern (ExpectRuntimeSuccess _ _ es) = es+getExcludePattern (ExpectCompiles _ _ es) = es+getExcludePattern (ExpectCompilerError _ _ es) = es+getExcludePattern (ExpectRuntimeError _ _ _ es) = es+getExcludePattern (ExpectRuntimeSuccess _ _ _ es) = es
src/Types/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,6 +21,7 @@ module Types.Procedure ( ArgValues(..), Assignable(..),+ AssignmentType(..), ExecutableProcedure(..), Expression(..), ExpressionStart(..),@@ -32,6 +33,7 @@ InputValue(..), InstanceOrInferred(..), IteratedLoop(..),+ MacroExpression(..), MacroName(..), Operator(..), OutputValue(..),@@ -42,6 +44,7 @@ Statement(..), TestProcedure(..), TraceType(..),+ ValueCallType(..), ValueLiteral(..), ValueOperation(..), VariableName(..),@@ -180,6 +183,8 @@ RawFailCall String | IgnoreValues [c] (Expression c) | Assignment [c] (Positional (Assignable c)) (Expression c) |+ AssignmentEmpty [c] VariableName (Expression c) |+ VariableSwap [c] (OutputValue c) (OutputValue c) | DeferredVariables [c] [Assignable c] | NoValueExpression [c] (VoidExpression c) | MarkReadOnly [c] [VariableName] |@@ -203,6 +208,8 @@ getStatementContext (RawFailCall _) = [] getStatementContext (IgnoreValues c _) = c getStatementContext (Assignment c _ _) = c+getStatementContext (AssignmentEmpty c _ _) = c+getStatementContext (VariableSwap c _ _) = c getStatementContext (DeferredVariables c _) = c getStatementContext (NoValueExpression c _) = c getStatementContext (MarkReadOnly c _) = c@@ -253,7 +260,9 @@ Literal (ValueLiteral c) | UnaryExpression [c] (Operator c) (Expression c) | InfixExpression [c] (Expression c) (Operator c) (Expression c) |- RawExpression ExpressionType ExpressionValue+ RawExpression ExpressionType ExpressionValue |+ DelegatedFunctionCall [c] (FunctionSpec c) |+ DelegatedInitializeValue [c] (Maybe TypeInstance) deriving (Show) type ExpressionType = Positional ValueType@@ -296,25 +305,33 @@ getOperatorName (FunctionOperator _ (FunctionSpec _ _ n _)) = n getExpressionContext :: Expression c -> [c]-getExpressionContext (Expression c _ _) = c-getExpressionContext (Literal l) = getValueLiteralContext l-getExpressionContext (UnaryExpression c _ _) = c-getExpressionContext (InfixExpression c _ _ _) = c-getExpressionContext (RawExpression _ _) = []+getExpressionContext (Expression c _ _) = c+getExpressionContext (Literal l) = getValueLiteralContext l+getExpressionContext (UnaryExpression c _ _) = c+getExpressionContext (InfixExpression c _ _ _) = c+getExpressionContext (RawExpression _ _) = []+getExpressionContext (DelegatedFunctionCall c _) = c+getExpressionContext (DelegatedInitializeValue c _) = c data FunctionCall c =- FunctionCall [c] FunctionName (Positional (InstanceOrInferred c)) (Positional (Expression c))+ FunctionCall [c] FunctionName (Positional (InstanceOrInferred c)) (Positional (Maybe (CallArgLabel c), Expression c)) deriving (Show) +data AssignmentType =+ AlwaysAssign |+ AssignIfEmpty+ deriving (Eq,Show)+ data ExpressionStart c = NamedVariable (OutputValue c) | NamedMacro [c] MacroName |+ ExpressionMacro [c] MacroExpression | CategoryCall [c] CategoryName (FunctionCall c) | TypeCall [c] TypeInstanceOrParam (FunctionCall c) | UnqualifiedCall [c] (FunctionCall c) | BuiltinCall [c] (FunctionCall c) | ParensExpression [c] (Expression c) |- InlineAssignment [c] VariableName (Expression c) |+ InlineAssignment [c] VariableName AssignmentType (Expression c) | InitializeValue [c] (Maybe TypeInstance) (Positional (Expression c)) | UnambiguousLiteral (ValueLiteral c) deriving (Show)@@ -323,22 +340,27 @@ StringLiteral [c] String | CharLiteral [c] Char | IntegerLiteral [c] Bool Integer |- DecimalLiteral [c] Integer Integer |+ DecimalLiteral [c] Integer Integer Integer | BoolLiteral [c] Bool | EmptyLiteral [c] deriving (Show) getValueLiteralContext :: ValueLiteral c -> [c]-getValueLiteralContext (StringLiteral c _) = c-getValueLiteralContext (CharLiteral c _) = c-getValueLiteralContext (IntegerLiteral c _ _) = c-getValueLiteralContext (DecimalLiteral c _ _) = c-getValueLiteralContext (BoolLiteral c _) = c-getValueLiteralContext (EmptyLiteral c) = c+getValueLiteralContext (StringLiteral c _) = c+getValueLiteralContext (CharLiteral c _) = c+getValueLiteralContext (IntegerLiteral c _ _) = c+getValueLiteralContext (DecimalLiteral c _ _ _) = c+getValueLiteralContext (BoolLiteral c _) = c+getValueLiteralContext (EmptyLiteral c) = c +data ValueCallType =+ AlwaysCall |+ CallUnlessEmpty+ deriving (Eq,Show)+ data ValueOperation c = TypeConversion [c] GeneralInstance |- ValueCall [c] (FunctionCall c) |+ ValueCall [c] ValueCallType (FunctionCall c) | SelectReturn [c] Int deriving (Show) @@ -352,6 +374,10 @@ show = mnName data TraceType = NoTrace | TraceCreation deriving (Show)++data MacroExpression =+ MacroCallTrace+ deriving (Show) data PragmaProcedure c = PragmaTracing {
src/Types/TypeCategory.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,9 +21,11 @@ module Types.TypeCategory ( AnyCategory(..),- CategoryMap,+ CallArgLabel(..),+ CategoryMap(..), CategoryResolver(..), FunctionName(..),+ FunctionVisibility(..), Namespace(..), ParamFilter(..), PassedValue(..),@@ -37,8 +39,10 @@ checkCategoryInstances, checkConnectedTypes, checkConnectionCycles,+ checkFunctionCallVisibility, checkParamVariances, declareAllTypes, -- TODO: Remove?+ emptyCategoryMap, flattenAllConnections, formatFullContext, formatFullContextBrace,@@ -73,6 +77,7 @@ isStaticNamespace, isValueConcrete, isValueInterface,+ matchesCallArgLabel, mergeDefines, mergeFunctions, mergeInferredTypes,@@ -85,6 +90,7 @@ replaceSelfFunction, setCategoryNamespace, singleFromCategory,+ toCategoryMap, topoSortCategories, uncheckedSubFunction, validateCategoryFunction,@@ -129,6 +135,7 @@ vcNamespace :: Namespace, vcName :: CategoryName, vcPragmas :: [PragmaCategory c],+ vcVisibility :: [FunctionVisibility c], vcParams :: [ValueParam c], vcRefines :: [ValueRefine c], vcDefines :: [ValueDefine c],@@ -172,7 +179,7 @@ map (\p -> " " ++ show p) pg ++ map (\f -> formatInterfaceFunc f) fs) ++ "\n}\n"- format (ValueConcrete cs ns n pg ps rs ds vs fs) =+ format (ValueConcrete cs ns n pg _ ps rs ds vs fs) = "concrete " ++ show n ++ formatParams ps ++ namespace ns ++ " { " ++ formatContext cs ++ "\n" ++ (intercalate "\n\n" $ map (\p -> " " ++ show p) pg ++@@ -200,54 +207,59 @@ formatConcreteFunc f = showFunctionInContext (show (sfScope f) ++ " ") " " f getCategoryName :: AnyCategory c -> CategoryName-getCategoryName (ValueInterface _ _ n _ _ _ _) = n-getCategoryName (InstanceInterface _ _ n _ _ _) = n-getCategoryName (ValueConcrete _ _ n _ _ _ _ _ _) = n+getCategoryName (ValueInterface _ _ n _ _ _ _) = n+getCategoryName (InstanceInterface _ _ n _ _ _) = n+getCategoryName (ValueConcrete _ _ n _ _ _ _ _ _ _) = n getCategoryContext :: AnyCategory c -> [c]-getCategoryContext (ValueInterface c _ _ _ _ _ _) = c-getCategoryContext (InstanceInterface c _ _ _ _ _) = c-getCategoryContext (ValueConcrete c _ _ _ _ _ _ _ _) = c+getCategoryContext (ValueInterface c _ _ _ _ _ _) = c+getCategoryContext (InstanceInterface c _ _ _ _ _) = c+getCategoryContext (ValueConcrete c _ _ _ _ _ _ _ _ _) = c getCategoryNamespace :: AnyCategory c -> Namespace-getCategoryNamespace (ValueInterface _ ns _ _ _ _ _) = ns-getCategoryNamespace (InstanceInterface _ ns _ _ _ _) = ns-getCategoryNamespace (ValueConcrete _ ns _ _ _ _ _ _ _) = ns+getCategoryNamespace (ValueInterface _ ns _ _ _ _ _) = ns+getCategoryNamespace (InstanceInterface _ ns _ _ _ _) = ns+getCategoryNamespace (ValueConcrete _ ns _ _ _ _ _ _ _ _) = ns getCategoryPragmas :: AnyCategory c -> [PragmaCategory c]-getCategoryPragmas (ValueInterface _ _ _ pg _ _ _) = pg-getCategoryPragmas (InstanceInterface _ _ _ pg _ _) = pg-getCategoryPragmas (ValueConcrete _ _ _ pg _ _ _ _ _) = pg+getCategoryPragmas (ValueInterface _ _ _ pg _ _ _) = pg+getCategoryPragmas (InstanceInterface _ _ _ pg _ _) = pg+getCategoryPragmas (ValueConcrete _ _ _ pg _ _ _ _ _ _) = pg setCategoryNamespace :: Namespace -> AnyCategory c -> AnyCategory c-setCategoryNamespace ns (ValueInterface c _ n pg ps rs fs) = (ValueInterface c ns n pg ps rs fs)-setCategoryNamespace ns (InstanceInterface c _ n pg ps fs) = (InstanceInterface c ns n pg ps fs)-setCategoryNamespace ns (ValueConcrete c _ n pg ps rs ds vs fs) = (ValueConcrete c ns n pg ps rs ds vs fs)+setCategoryNamespace ns (ValueInterface c _ n pg ps rs fs) = (ValueInterface c ns n pg ps rs fs)+setCategoryNamespace ns (InstanceInterface c _ n pg ps fs) = (InstanceInterface c ns n pg ps fs)+setCategoryNamespace ns (ValueConcrete c _ n pg fv ps rs ds vs fs) = (ValueConcrete c ns n pg fv ps rs ds vs fs) +getCategoryVisibilities :: AnyCategory c -> [FunctionVisibility c]+getCategoryVisibilities (ValueInterface _ _ _ _ _ _ _) = []+getCategoryVisibilities (InstanceInterface _ _ _ _ _ _) = []+getCategoryVisibilities (ValueConcrete _ _ _ _ fv _ _ _ _ _) = fv+ getCategoryParams :: AnyCategory c -> [ValueParam c]-getCategoryParams (ValueInterface _ _ _ _ ps _ _) = ps-getCategoryParams (InstanceInterface _ _ _ _ ps _) = ps-getCategoryParams (ValueConcrete _ _ _ _ ps _ _ _ _) = ps+getCategoryParams (ValueInterface _ _ _ _ ps _ _) = ps+getCategoryParams (InstanceInterface _ _ _ _ ps _) = ps+getCategoryParams (ValueConcrete _ _ _ _ _ ps _ _ _ _) = ps getCategoryRefines :: AnyCategory c -> [ValueRefine c]-getCategoryRefines (ValueInterface _ _ _ _ _ rs _) = rs-getCategoryRefines (InstanceInterface _ _ _ _ _ _) = []-getCategoryRefines (ValueConcrete _ _ _ _ _ rs _ _ _) = rs+getCategoryRefines (ValueInterface _ _ _ _ _ rs _) = rs+getCategoryRefines (InstanceInterface _ _ _ _ _ _) = []+getCategoryRefines (ValueConcrete _ _ _ _ _ _ rs _ _ _) = rs getCategoryDefines :: AnyCategory c -> [ValueDefine c]-getCategoryDefines (ValueInterface _ _ _ _ _ _ _) = []-getCategoryDefines (InstanceInterface _ _ _ _ _ _) = []-getCategoryDefines (ValueConcrete _ _ _ _ _ _ ds _ _) = ds+getCategoryDefines (ValueInterface _ _ _ _ _ _ _) = []+getCategoryDefines (InstanceInterface _ _ _ _ _ _) = []+getCategoryDefines (ValueConcrete _ _ _ _ _ _ _ ds _ _) = ds getCategoryFilters :: AnyCategory c -> [ParamFilter c]-getCategoryFilters (ValueInterface _ _ _ _ _ _ _) = []-getCategoryFilters (InstanceInterface _ _ _ _ _ _) = []-getCategoryFilters (ValueConcrete _ _ _ _ _ _ _ vs _) = vs+getCategoryFilters (ValueInterface _ _ _ _ _ _ _) = []+getCategoryFilters (InstanceInterface _ _ _ _ _ _) = []+getCategoryFilters (ValueConcrete _ _ _ _ _ _ _ _ vs _) = vs getCategoryFunctions :: AnyCategory c -> [ScopedFunction c]-getCategoryFunctions (ValueInterface _ _ _ _ _ _ fs) = fs-getCategoryFunctions (InstanceInterface _ _ _ _ _ fs) = fs-getCategoryFunctions (ValueConcrete _ _ _ _ _ _ _ _ fs) = fs+getCategoryFunctions (ValueInterface _ _ _ _ _ _ fs) = fs+getCategoryFunctions (InstanceInterface _ _ _ _ _ fs) = fs+getCategoryFunctions (ValueConcrete _ _ _ _ _ _ _ _ _ fs) = fs singleFromCategory :: AnyCategory c -> TypeInstance singleFromCategory t = TypeInstance n (Positional ps) where@@ -272,7 +284,7 @@ fromFilter ImmutableFilter = [] fromType (ValueType _ t2) = fromInstance t2 fromFunction f = args ++ returns ++ filters2 where- args = concat $ map (fromType . pvType) $ pValues $ sfArgs f+ args = concat $ map (fromType . pvType . fst) $ pValues $ sfArgs f returns = concat $ map (fromType . pvType) $ pValues $ sfReturns f filters2 = concat $ map (fromFilter . pfFilter) $ sfFilters f @@ -285,7 +297,7 @@ isInstanceInterface _ = False isValueConcrete :: AnyCategory c -> Bool-isValueConcrete (ValueConcrete _ _ _ _ _ _ _ _ _) = True+isValueConcrete (ValueConcrete _ _ _ _ _ _ _ _ _ _) = True isValueConcrete _ = False data Namespace =@@ -463,18 +475,25 @@ ParamValues -> GeneralInstance -> m GeneralInstance subAllParams pa = uncheckedSubInstance (getValueForParam pa) -type CategoryMap c = Map.Map CategoryName (AnyCategory c)+data CategoryMap c =+ CategoryMap {+ cmKnown :: Map.Map CategoryName [c],+ cmAvailable :: Map.Map CategoryName (AnyCategory c)+ } +emptyCategoryMap :: CategoryMap c+emptyCategoryMap = toCategoryMap []++toCategoryMap :: [(CategoryName,AnyCategory c)] -> CategoryMap c+toCategoryMap = CategoryMap Map.empty . Map.fromList+ getCategory :: (Show c, CollectErrorsM m) => CategoryMap c -> ([c],CategoryName) -> m ([c],AnyCategory c)-getCategory tm (c,n) =- case n `Map.lookup` tm of- (Just t) -> return (c,t)- _ -> compilerErrorM $ "Type " ++ show n ++ context ++ " not found"- where- context- | null c = ""- | otherwise = formatFullContextBrace c+getCategory (CategoryMap km tm) (c,n) = handle (n `Map.lookup` tm) (n `Map.lookup` km) where+ handle (Just t) _ = return (c,t)+ handle _ (Just c2) = compilerErrorM $ "Type " ++ show n ++ formatFullContextBrace c2 +++ " not visible here" ++ formatFullContextBrace c+ handle _ _ = compilerErrorM $ "Type " ++ show n ++ " not found" ++ formatFullContextBrace c getValueCategory :: (Show c, CollectErrorsM m) => CategoryMap c -> ([c],CategoryName) -> m ([c],AnyCategory c)@@ -520,13 +539,13 @@ declareAllTypes :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m (CategoryMap c) declareAllTypes tm0 = foldr (\t tm -> tm >>= update t) (return tm0) where- update t tm =+ update t (CategoryMap km tm) = case getCategoryName t `Map.lookup` tm of (Just t2) -> compilerErrorM $ "Type " ++ show (getCategoryName t) ++ formatFullContextBrace (getCategoryContext t) ++ " has already been declared" ++ formatFullContextBrace (getCategoryContext t2)- _ -> return $ Map.insert (getCategoryName t) t tm+ _ -> return $ CategoryMap km $ Map.insert (getCategoryName t) t tm getFilterMap :: CollectErrorsM m => [ValueParam c] -> [ParamFilter c] -> m ParamFilters getFilterMap ps fs = do@@ -577,20 +596,20 @@ checkConnectedTypes :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m ()-checkConnectedTypes tm0 ts = do- tm <- declareAllTypes tm0 ts- collectAllM_ (map (checkSingle tm) ts)+checkConnectedTypes cm0 ts = do+ cm <- declareAllTypes cm0 ts+ collectAllM_ (map (checkSingle cm) ts) where- checkSingle tm (ValueInterface c _ n _ _ rs _) = do+ checkSingle cm (ValueInterface c _ n _ _ rs _) = do let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs- is <- mapCompilerM (getCategory tm) ts2+ is <- mapCompilerM (getCategory cm) ts2 collectAllM_ (map (valueRefinesInstanceError c n) is) collectAllM_ (map (valueRefinesConcreteError c n) is)- checkSingle tm (ValueConcrete c _ n _ _ rs ds _ _) = do+ checkSingle cm (ValueConcrete c _ n _ _ _ rs ds _ _) = do let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs let ts3 = map (\d -> (vdContext d,diName $ vdType d)) ds- is1 <- mapCompilerM (getCategory tm) ts2- is2 <- mapCompilerM (getCategory tm) ts3+ is1 <- mapCompilerM (getCategory cm) ts2+ is2 <- mapCompilerM (getCategory cm) ts3 collectAllM_ (map (concreteRefinesInstanceError c n) is1) collectAllM_ (map (concreteDefinesValueError c n) is2) collectAllM_ (map (concreteRefinesConcreteError c n) is1)@@ -637,17 +656,18 @@ checkConnectionCycles :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m ()-checkConnectionCycles tm0 ts = collectAllM_ (map (checker []) ts) where+checkConnectionCycles (CategoryMap km tm0) ts = collectAllM_ (map (checker []) ts) where tm = Map.union tm0 $ Map.fromList $ zip (map getCategoryName ts) ts+ cm = CategoryMap km tm checker us (ValueInterface c _ n _ _ rs _) = do failIfCycle n c us let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs- is <- mapCompilerM (getValueCategory tm) ts2+ is <- mapCompilerM (getValueCategory cm) ts2 collectAllM_ (map (checker (us ++ [n]) . snd) is)- checker us (ValueConcrete c _ n _ _ rs _ _ _) = do+ checker us (ValueConcrete c _ n _ _ _ rs _ _ _) = do failIfCycle n c us let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs- is <- mapCompilerM (getValueCategory tm) ts2+ is <- mapCompilerM (getValueCategory cm) ts2 collectAllM_ (map (checker (us ++ [n]) . snd) is) checker _ _ = return () failIfCycle n c us =@@ -658,9 +678,9 @@ checkParamVariances :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m ()-checkParamVariances tm0 ts = do- tm <- declareAllTypes tm0 ts- let r = CategoryResolver tm+checkParamVariances cm0 ts = do+ cm <- declareAllTypes cm0 ts+ let r = CategoryResolver cm mapCompilerM_ (checkCategory r) ts mapCompilerM_ checkBounds ts where@@ -671,11 +691,12 @@ noDuplicates c n ps let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) ps collectAllM_ (map (checkRefine r vm) rs)- checkCategory r t@(ValueConcrete c _ n _ ps rs ds _ _) = categoryContext t ??> do+ checkCategory r t@(ValueConcrete c _ n _ fv ps rs ds _ _) = categoryContext t ??> do noDuplicates c n ps let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) ps collectAllM_ (map (checkRefine r vm) rs) collectAllM_ (map (checkDefine r vm) ds)+ collectAllM_ (map (checkVisibility r vm) fv) checkCategory _ t@(InstanceInterface c _ n _ ps _) = categoryContext t ??> do noDuplicates c n ps noDuplicates c n ps = collectAllM_ (map checkCount $ group $ sort $ map vpParam ps) where@@ -689,21 +710,35 @@ checkDefine r vm (ValueDefine c t) = validateDefinesVariance r vm Covariant t <?? "In " ++ show t ++ formatFullContextBrace c+ checkVisibility _ _ FunctionVisibilityDefault = return ()+ checkVisibility r vm (FunctionVisibility _ ts2) =+ collectAllM_ (map (checkVisibilitySingle r vm) ts2)+ checkVisibilitySingle r vm (c,t) =+ validateInstanceVariance r vm Covariant t <??+ "In visibility " ++ show t ++ formatFullContextBrace c checkCategoryInstances :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m ()-checkCategoryInstances tm0 ts = do- tm <- declareAllTypes tm0 ts- let r = CategoryResolver tm+checkCategoryInstances cm0 ts = do+ cm <- declareAllTypes cm0 ts+ let r = CategoryResolver cm mapCompilerM_ (checkSingle r) ts where checkSingle r t = do pa <- getCategoryParamSet t- mapCompilerM_ (checkFilterParam pa) (getCategoryFilters t)- mapCompilerM_ (checkRefine r pa) (getCategoryRefines t)- mapCompilerM_ (checkDefine r pa) (getCategoryDefines t)- mapCompilerM_ (checkFilter r pa) (getCategoryFilters t)+ mapCompilerM_ (checkFilterParam pa) (getCategoryFilters t)+ mapCompilerM_ (checkRefine r pa) (getCategoryRefines t)+ mapCompilerM_ (checkDefine r pa) (getCategoryDefines t)+ mapCompilerM_ (checkFilter r pa) (getCategoryFilters t)+ mapCompilerM_ (checkVisibility r pa) (getCategoryVisibilities t) mapCompilerM_ (validateCategoryFunction r t) (getCategoryFunctions t)+ checkVisibility r fm (FunctionVisibility c ts2) =+ mapCompilerM_ (checkVisibilitySingle r fm) ts2 <??+ "In visibility at " ++ formatFullContext c+ checkVisibility _ _ _ = return ()+ checkVisibilitySingle r fm (c,t) =+ validateGeneralInstance r fm t <??+ "In " ++ show t ++ formatFullContextBrace c checkFilterParam pa (ParamFilter c n _) = when (not $ n `Set.member` pa) $ compilerErrorM $ "Param " ++ show n ++ formatFullContextBrace c ++ " not found"@@ -729,7 +764,11 @@ TypeScope -> validatateFunctionType r pa vm funcType ValueScope -> validatateFunctionType r pa vm funcType _ -> return ()- getFunctionFilterMap f >>= disallowBoundedParams where+ getFunctionFilterMap f >>= disallowBoundedParams+ checkVis (sfScope f) (sfVisibility f) where+ checkVis CategoryScope va@(FunctionVisibility _ _) =+ compilerErrorM $ "Category functions must not have restricted visibility: " ++ show va+ checkVis _ _ = return () message | getCategoryName t == sfType f = "In function:\n---\n" ++ show f ++ "\n---\n" | otherwise = "In function inherited from " ++ show (sfType f) ++@@ -737,18 +776,18 @@ topoSortCategories :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m [AnyCategory c]-topoSortCategories tm0 ts = do- tm <- declareAllTypes tm0 ts- fmap fst $ update tm (Map.keysSet tm0) ts+topoSortCategories cm0 ts = do+ cm <- declareAllTypes cm0 ts+ fmap fst $ update cm (Map.keysSet $ cmAvailable cm0) ts where- update tm ta (t:ts2) = do+ update cm ta (t:ts2) = do if getCategoryName t `Set.member` ta- then update tm ta ts2+ then update cm ta ts2 else do- refines <- mapCompilerM (\r -> getCategory tm (vrContext r,tiName $ vrType r)) $ getCategoryRefines t- defines <- mapCompilerM (\d -> getCategory tm (vdContext d,diName $ vdType d)) $ getCategoryDefines t- (ts3,ta2) <- update tm (getCategoryName t `Set.insert` ta) (map snd $ refines ++ defines)- (ts4,ta3) <- update tm ta2 ts2+ refines <- mapCompilerM (\r -> getCategory cm (vrContext r,tiName $ vrType r)) $ getCategoryRefines t+ defines <- mapCompilerM (\d -> getCategory cm (vdContext d,diName $ vdType d)) $ getCategoryDefines t+ (ts3,ta2) <- update cm (getCategoryName t `Set.insert` ta) (map snd $ refines ++ defines)+ (ts4,ta3) <- update cm ta2 ts2 return (ts3 ++ [t] ++ ts4,ta3) update _ ta _ = return ([],ta) @@ -794,10 +833,10 @@ flattenAllConnections :: (Show c, CollectErrorsM m) => CategoryMap c -> [AnyCategory c] -> m [AnyCategory c]-flattenAllConnections tm0 ts = do+flattenAllConnections (CategoryMap km tm0) ts = do -- We need to process all refines before type-checking can be done. tm1 <- foldr preMerge (return tm0) (reverse ts)- let r = CategoryResolver tm1+ let r = CategoryResolver (CategoryMap km tm1) (ts',_) <- foldr (update r) (return ([],tm0)) (reverse ts) return ts' where@@ -808,9 +847,9 @@ preMergeSingle tm (ValueInterface c ns n pg ps rs fs) = do rs' <- fmap concat $ mapCompilerM (getRefines tm) rs return $ ValueInterface c ns n pg ps rs' fs- preMergeSingle tm (ValueConcrete c ns n pg ps rs ds vs fs) = do+ preMergeSingle tm (ValueConcrete c ns n pg fv ps rs ds vs fs) = do rs' <- fmap concat $ mapCompilerM (getRefines tm) rs- return $ ValueConcrete c ns n pg ps rs' ds vs fs+ return $ ValueConcrete c ns n pg fv ps rs' ds vs fs preMergeSingle _ t = return t update r t u = do (ts2,tm) <- u@@ -827,10 +866,10 @@ checkMerged r fm rs rs'' pg2 <- fmap concat $ mapCompilerM (getRefinesPragmas tm) rs -- Only merge from direct parents.- fs' <- mergeFunctions r tm pm fm rs [] fs+ fs' <- mergeFunctions r (CategoryMap km tm) pm fm rs [] fs return $ ValueInterface c ns n (pg++pg2) ps rs'' fs' -- TODO: Remove duplication below and/or have separate tests.- updateSingle r tm t@(ValueConcrete c ns n pg ps rs ds vs fs) = do+ updateSingle r tm t@(ValueConcrete c ns n pg fv ps rs ds vs fs) = do fm <- getCategoryFilterMap t let pm = getCategoryParamMap t rs' <- fmap concat $ mapCompilerM (getRefines tm) rs@@ -842,11 +881,11 @@ pg2 <- fmap concat $ mapCompilerM (getRefinesPragmas tm) rs pg3 <- fmap concat $ mapCompilerM (getDefinesPragmas tm) ds -- Only merge from direct parents.- fs' <- mergeFunctions r tm pm fm rs ds fs- return $ ValueConcrete c ns n (pg++pg2++pg3) ps rs'' ds' vs fs'+ fs' <- mergeFunctions r (CategoryMap km tm) pm fm rs ds fs+ return $ ValueConcrete c ns n (pg++pg2++pg3) fv ps rs'' ds' vs fs' updateSingle _ _ t = return t getRefines tm ra@(ValueRefine c t@(TypeInstance n _)) = do- (_,v) <- getValueCategory tm (c,n)+ (_,v) <- getValueCategory (CategoryMap km tm) (c,n) let refines = getCategoryRefines v pa <- assignParams tm c t fmap (ra:) $ mapCompilerM (subAll c pa) refines@@ -854,7 +893,7 @@ t2 <- uncheckedSubSingle (getValueForParam pa) t1 return $ ValueRefine (c ++ c1) t2 assignParams tm c (TypeInstance n ps) = do- (_,v) <- getValueCategory tm (c,n)+ (_,v) <- getValueCategory (CategoryMap km tm) (c,n) let ns = map vpParam $ getCategoryParams v paired <- processPairs alwaysPair (Positional ns) ps return $ Map.insert ParamSelf selfType $ Map.fromList paired@@ -869,31 +908,31 @@ return () checkConvert _ _ _ _ = return () getRefinesPragmas tm rf = do- (_,t) <- getCategory tm (vrContext rf,tiName $ vrType rf)+ (_,t) <- getCategory (CategoryMap km tm) (vrContext rf,tiName $ vrType rf) return $ map (prependCategoryPragmaContext $ vrContext rf) $ getCategoryPragmas t getDefinesPragmas tm df = do- (_,t) <- getCategory tm (vdContext df,diName $ vdType df)+ (_,t) <- getCategory (CategoryMap km tm) (vdContext df,diName $ vdType df) return $ map (prependCategoryPragmaContext $ vdContext df) $ getCategoryPragmas t mergeFunctions :: (Show c, CollectErrorsM m, TypeResolver r) => r -> CategoryMap c -> ParamValues -> ParamFilters -> [ValueRefine c] -> [ValueDefine c] -> [ScopedFunction c] -> m [ScopedFunction c]-mergeFunctions r tm pm fm rs ds fs = do- inheritValue <- fmap concat $ mapCompilerM (getRefinesFuncs tm) rs- inheritType <- fmap concat $ mapCompilerM (getDefinesFuncs tm) ds+mergeFunctions r cm pm fm rs ds fs = do+ inheritValue <- fmap concat $ mapCompilerM getRefinesFuncs rs+ inheritType <- fmap concat $ mapCompilerM getDefinesFuncs ds let inheritByName = fmap (nubBy sameFunction) $ Map.fromListWith (++) $ map (\f -> (sfName f,[f])) $ inheritValue ++ inheritType let explicitByName = Map.fromListWith (++) $ map (\f -> (sfName f,[f])) fs let allNames = Set.toList $ Set.union (Map.keysSet inheritByName) (Map.keysSet explicitByName) mapCompilerM (mergeByName inheritByName explicitByName) allNames where- getRefinesFuncs tm2 (ValueRefine c (TypeInstance n ts2)) = do- (_,t) <- getValueCategory tm2 (c,n)+ getRefinesFuncs (ValueRefine c (TypeInstance n ts2)) = do+ (_,t) <- getValueCategory cm (c,n) let ps = map vpParam $ getCategoryParams t let fs2 = getCategoryFunctions t paired <- processPairs alwaysPair (Positional ps) ts2 let assigned = Map.fromList $ (ParamSelf,selfType):paired mapCompilerM (unfixedSubFunction assigned) fs2- getDefinesFuncs tm2 (ValueDefine c (DefinesInstance n ts2)) = do- (_,t) <- getInstanceCategory tm2 (c,n)+ getDefinesFuncs (ValueDefine c (DefinesInstance n ts2)) = do+ (_,t) <- getInstanceCategory cm (c,n) let ps = map vpParam $ getCategoryParams t let fs2 = getCategoryFunctions t paired <- processPairs alwaysPair (Positional ps) ts2@@ -915,9 +954,9 @@ show (length es) ++ " times:\n---\n" ++ intercalate "\n---\n" (map show es) | otherwise = do- let ff@(ScopedFunction c n2 t s as rs2 ps fa ms) = head es+ let ff@(ScopedFunction c n2 t s v as rs2 ps fa ms) = head es mapCompilerM_ (checkMerge ff) is- return $ ScopedFunction c n2 t s as rs2 ps fa (ms ++ is)+ return $ ScopedFunction c n2 t s v as rs2 ps fa (ms ++ is) where checkMerge f1 f2 | sfScope f1 /= sfScope f2 =@@ -926,11 +965,23 @@ show f2 ++ "\n ->\n" ++ show f1 | otherwise = "In function merge:\n---\n" ++ show f2 ++ "\n ->\n" ++ show f1 ++ "\n---\n" ??> do+ checkMergeVis (sfVisibility f1) (sfVisibility f2) f1' <- parsedToFunctionType f1 f2' <- parsedToFunctionType f2 case sfScope f1 of CategoryScope -> checkFunctionConvert r Map.empty Map.empty f2' f1' _ -> checkFunctionConvert r fm pm f2' f1'+ processPairs_ checkArgNames (sfArgs f1) (sfArgs f2)+ checkMergeVis FunctionVisibilityDefault _ = return ()+ checkMergeVis v1 v2 =+ compilerErrorM $ "Cannot supersede " ++ show v2 ++ " with " ++ show v1+ checkArgNames (_,n1) (_,n2)+ | fmap calName n1 == fmap calName n2 = return ()+ checkArgNames t1 t2 =+ compilerErrorM $ "Expected arg label from " ++ showArgName t2 +++ " to match " ++ showArgName t1+ showArgName (t',Nothing) = show t'+ showArgName (t',Just n') = show (pvType t') ++ " " ++ show n' data FunctionName = FunctionName {@@ -940,24 +991,52 @@ BuiltinReduce | BuiltinRequire | BuiltinStrong |+ BuiltinIdentify | BuiltinTypename deriving (Eq,Ord) instance Show FunctionName where show (FunctionName n) = n- show BuiltinPresent = "present"- show BuiltinReduce = "reduce"- show BuiltinRequire = "require"- show BuiltinStrong = "strong"+ show BuiltinPresent = "present"+ show BuiltinReduce = "reduce"+ show BuiltinRequire = "require"+ show BuiltinStrong = "strong"+ show BuiltinIdentify = "identify" show BuiltinTypename = "typename" +data CallArgLabel c =+ CallArgLabel {+ calContext :: [c],+ calName ::String+ }+ deriving (Eq,Ord)++instance Show c => Show (CallArgLabel c) where+ show (CallArgLabel c n) = n ++ formatFullContextBrace c++matchesCallArgLabel :: CallArgLabel c -> String -> Bool+matchesCallArgLabel (CallArgLabel _ n1) n2 = init n1 == n2++data FunctionVisibility c =+ FunctionVisibility {+ fvContext :: [c],+ fvTypes :: [([c],GeneralInstance)]+ } |+ FunctionVisibilityDefault+ deriving (Eq)++instance Show c => Show (FunctionVisibility c) where+ show FunctionVisibilityDefault = "visibility _"+ show (FunctionVisibility c ts) = "visibility " ++ intercalate ", " (map (show . snd) ts) ++ formatFullContextBrace c+ data ScopedFunction c = ScopedFunction { sfContext :: [c], sfName :: FunctionName, sfType :: CategoryName, sfScope :: SymbolScope,- sfArgs :: Positional (PassedValue c),+ sfVisibility :: FunctionVisibility c,+ sfArgs :: Positional (PassedValue c, Maybe (CallArgLabel c)), sfReturns :: Positional (PassedValue c), sfParams :: Positional (ValueParam c), sfFilters :: [ParamFilter c],@@ -968,17 +1047,19 @@ show f = showFunctionInContext (show (sfScope f) ++ " ") "" f sameFunction :: ScopedFunction c -> ScopedFunction c -> Bool-sameFunction (ScopedFunction _ n1 t1 s1 _ _ _ _ _) (ScopedFunction _ n2 t2 s2 _ _ _ _ _) =+sameFunction (ScopedFunction _ n1 t1 s1 _ _ _ _ _ _) (ScopedFunction _ n2 t2 s2 _ _ _ _ _ _) = all id [n1 == n2, t1 == t2, s1 == s2] showFunctionInContext :: Show c => String -> String -> ScopedFunction c -> String-showFunctionInContext s indent (ScopedFunction cs n t _ as rs ps fa ms) =+showFunctionInContext s indent (ScopedFunction cs n t _ _ as rs ps fa ms) = indent ++ s ++ "/*" ++ show t ++ "*/ " ++ show n ++ showParams (pValues ps) ++ " " ++ formatContext cs ++ "\n" ++ concat (map (\v -> indent ++ formatValue v ++ "\n") fa) ++- indent ++ "(" ++ intercalate "," (map (show . pvType) $ pValues as) ++ ") -> " +++ indent ++ "(" ++ intercalate "," (map showArg $ pValues as) ++ ") -> " ++ "(" ++ intercalate "," (map (show . pvType) $ pValues rs) ++ ")" ++ showMerges (flatten ms) where+ showArg (a,Nothing) = show (pvType a)+ showArg (a,Just n2) = show (pvType a) ++ " " ++ show (calName n2) showParams [] = "" showParams ps2 = "<" ++ intercalate "," (map (show . vpParam) ps2) ++ ">" formatContext cs2 = "/*" ++ formatFullContext cs2 ++ "*/"@@ -1001,8 +1082,8 @@ parsedToFunctionType :: (Show c, CollectErrorsM m) => ScopedFunction c -> m FunctionType-parsedToFunctionType (ScopedFunction c n _ _ as rs ps fa _) = do- let as' = Positional $ map pvType $ pValues as+parsedToFunctionType (ScopedFunction c n _ _ _ as rs ps fa _) = do+ let as' = Positional $ map (pvType . fst) $ pValues as let rs' = Positional $ map pvType $ pValues rs let ps' = Positional $ map vpParam $ pValues ps mapCompilerM_ checkFilter fa@@ -1027,40 +1108,71 @@ unfixedSubFunction :: (Show c, CollectErrorsM m) => ParamValues -> ScopedFunction c -> m (ScopedFunction c)-unfixedSubFunction pa ff@(ScopedFunction c n t s as rs ps fa ms) =+unfixedSubFunction pa ff@(ScopedFunction c n t s v as rs ps fa ms) = "In function:\n---\n" ++ show ff ++ "\n---\n" ??> do let unresolved = Map.fromList $ map (\n2 -> (n2,singleType $ JustParamName False n2)) $ map vpParam $ pValues ps let pa' = pa `Map.union` unresolved- as' <- fmap Positional $ mapCompilerM (subPassed pa') $ pValues as+ as' <- fmap Positional $ mapCompilerM (subPassedNamed pa') $ pValues as rs' <- fmap Positional $ mapCompilerM (subPassed pa') $ pValues rs fa' <- mapCompilerM (subFilter pa') fa ms' <- mapCompilerM (uncheckedSubFunction pa) ms- return $ (ScopedFunction c n t s as' rs' ps fa' ms')+ v' <- subVisibility pa' v+ return $ (ScopedFunction c n t s v' as' rs' ps fa' ms') where+ subPassedNamed pa2 (a,n2) = do+ a2 <- subPassed pa2 a+ return (a2,n2) subPassed pa2 (PassedValue c2 t2) = do t' <- uncheckedSubValueType (getValueForParam pa2) t2 return $ PassedValue c2 t' subFilter pa2 (ParamFilter c2 n2 f) = do f' <- uncheckedSubFilter (getValueForParam pa2) f return $ ParamFilter c2 n2 f'+ subVisibility _ FunctionVisibilityDefault = return FunctionVisibilityDefault+ subVisibility pa2 (FunctionVisibility c2 ts) = do+ ts' <- mapCompilerM (subVisibilitySingle pa2) ts+ return $ FunctionVisibility c2 ts'+ subVisibilitySingle pa2 (c2,t2) = do+ t2' <- uncheckedSubInstance (getValueForParam pa2) t2+ return (c2,t2') replaceSelfFunction :: (Show c, CollectErrorsM m) => GeneralInstance -> ScopedFunction c -> m (ScopedFunction c)-replaceSelfFunction self ff@(ScopedFunction c n t s as rs ps fa ms) =+replaceSelfFunction self ff@(ScopedFunction c n t s v as rs ps fa ms) = "In function:\n---\n" ++ show ff ++ "\n---\n" ??> do- as' <- fmap Positional $ mapCompilerM subPassed $ pValues as+ as' <- fmap Positional $ mapCompilerM subPassedNamed $ pValues as rs' <- fmap Positional $ mapCompilerM subPassed $ pValues rs fa' <- mapCompilerM subFilter fa ms' <- mapCompilerM (replaceSelfFunction self) ms- return $ (ScopedFunction c n t s as' rs' ps fa' ms')+ v' <- subVisibility v+ return $ (ScopedFunction c n t s v' as' rs' ps fa' ms') where+ subPassedNamed (a,n2) = do+ a2 <- subPassed a+ return (a2,n2) subPassed (PassedValue c2 t2) = do t' <- replaceSelfValueType self t2 return $ PassedValue c2 t' subFilter (ParamFilter c2 n2 f) = do f' <- replaceSelfFilter self f return $ ParamFilter c2 n2 f'+ subVisibility FunctionVisibilityDefault = return FunctionVisibilityDefault+ subVisibility (FunctionVisibility c2 ts) = do+ ts' <- mapCompilerM subVisibilitySingle ts+ return $ FunctionVisibility c2 ts'+ subVisibilitySingle (c2,t2) = do+ t2' <- replaceSelfInstance self t2+ return (c2,t2') +checkFunctionCallVisibility :: (Show c, CollectErrorsM m, TypeResolver r) =>+ r -> ParamFilters -> ScopedFunction c -> GeneralInstance -> m ()+checkFunctionCallVisibility r fs f = check (sfVisibility f) where+ check FunctionVisibilityDefault _ = return ()+ check (FunctionVisibility _ ts) t0 = "Cannot call " ++ show (sfName f) ++ " in context of " ++ show t0 !!>+ collectFirstM_ (map (checkSingle t0) ts)+ checkSingle t0 (c,t) = "In visibility " ++ show t ++ formatFullContextBrace c ??>+ checkGeneralMatch r fs Covariant t0 t+ data PatternMatch = TypePattern { tpVariance :: Variance,@@ -1098,10 +1210,10 @@ deriving (Eq,Ord) instance Show a => Show (GuessRange a) where- show (GuessRange Nothing Nothing) = "Literally anything is possible"- show (GuessRange Nothing (Just hi)) = "Something at or below " ++ show hi- show (GuessRange (Just lo) Nothing) = "Something at or above " ++ show lo- show (GuessRange (Just lo) (Just hi)) = "Something between " ++ show lo ++ " and " ++ show hi+ show (GuessRange Nothing Nothing) = "literally anything is possible"+ show (GuessRange Nothing (Just hi)) = "something at or below " ++ show hi+ show (GuessRange (Just lo) Nothing) = "something at or above " ++ show lo+ show (GuessRange (Just lo) (Just hi)) = "something between " ++ show lo ++ " and " ++ show hi data GuessUnion = GuessUnion {@@ -1130,6 +1242,7 @@ mergeInferredTypes :: (CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> ParamFilters -> ParamValues -> MergeTree InferredTypeGuess -> m ParamValues+mergeInferredTypes _ _ ff _ _ | null (Map.toList ff) = return Map.empty mergeInferredTypes r f ff ps gs0 = do let gs0' = mapTypeGuesses gs0 gs1 <- mapCompilerM (\(i,is) -> fmap ((,) i) $ (reduce >=> simplifyUnion) is) $ Map.toList gs0'@@ -1199,7 +1312,7 @@ _ -> tryRangeUnion (ms ++ [g2]) g1 gs tryRangeUnion _ _ _ = return Nothing takeBest [gs] = return $ Map.fromList gs- takeBest [] = compilerErrorM "No feasible param guesses found"+ takeBest [] = compilerErrorM genericError takeBest gs = "Unable to merge alternative param guesses" !!> do mapCompilerM_ showAmbiguous (zip ([1..] :: [Int]) gs) emptyErrorM@@ -1209,12 +1322,14 @@ gs' <- mapCompilerM extractGuesses gs let mult = foldM (\xs ys -> [xs++[y] | y <- ys]) [] gs' let gs2 = map filterGuess mult- collectFirstM_ gs2 <!! "No feasible param guesses found"+ collectFirstM_ gs2 <!! genericError collectAnyM gs2+ genericError = "No guesses available for params " ++ intercalate ", " (map show $ Map.keys ff) filterGuess gs = checkSubFilters gs >> return gs extractGuesses (i,is) = do let is2 = map (extractSingle i) is- collectFirstM_ is2 <!! "No feasible guesses for param " ++ show i+ -- resetBackgroundM prevents duplicate messages.+ resetBackgroundM $ collectFirstM_ is2 <!! "No feasible guesses for param " ++ show i fmap nub $ collectAnyM is2 extractSingle i (GuessRange (Just lo) Nothing) = return (i,lo) extractSingle i (GuessRange Nothing (Just hi)) = return (i,hi)@@ -1222,7 +1337,10 @@ p <- (Just hi) `convertsTo` (Just lo) if p then return (i,lo)- else compilerErrorM $ "Ambiguous guess for param " ++ show i ++ ": " ++ show g+ else do+ compilerBackgroundM $ "Arbitrarily using lower bound " ++ show lo +++ " for " ++ show i ++ " (" ++ show g ++ ")"+ return (i,lo) extractSingle i g@(GuessRange Nothing Nothing) = compilerErrorM $ "Ambiguous guess for param " ++ show i ++ ": " ++ show g checkSubFilters gs = "In validation of inference guess: " ++ describeGuess gs ??> do
src/Types/TypeInstance.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2022 Kevin P. Barry+Copyright 2019-2022,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -52,6 +52,7 @@ getValueForParam, hasInferredParams, isDefinesFilter,+ isOptionalValue, isRequiresFilter, isWeakValue, mapTypeGuesses,@@ -124,6 +125,9 @@ isWeakValue :: ValueType -> Bool isWeakValue = (== WeakValue) . vtRequired +isOptionalValue :: ValueType -> Bool+isOptionalValue = (== OptionalValue) . vtRequired+ requiredSingleton :: CategoryName -> ValueType requiredSingleton n = ValueType RequiredValue $ singleType $ JustTypeInstance $ TypeInstance n (Positional []) @@ -141,22 +145,26 @@ BuiltinFloat | BuiltinString | BuiltinPointer |+ BuiltinIdentifier | BuiltinFormatted | BuiltinOrder |+ BuiltinTestcase | CategoryNone instance Show CategoryName where- show (CategoryName n) = n- show BuiltinBool = "Bool"- show BuiltinChar = "Char"- show BuiltinCharBuffer = "CharBuffer"- show BuiltinInt = "Int"- show BuiltinFloat = "Float"- show BuiltinString = "String"- show BuiltinPointer = "Pointer"- show BuiltinFormatted = "Formatted"- show BuiltinOrder = "Order"- show CategoryNone = "(none)"+ show (CategoryName n) = n+ show BuiltinBool = "Bool"+ show BuiltinChar = "Char"+ show BuiltinCharBuffer = "CharBuffer"+ show BuiltinInt = "Int"+ show BuiltinFloat = "Float"+ show BuiltinString = "String"+ show BuiltinPointer = "Pointer"+ show BuiltinIdentifier = "Identifier"+ show BuiltinFormatted = "Formatted"+ show BuiltinOrder = "Order"+ show BuiltinTestcase = "Testcase"+ show CategoryNone = "(none)" instance Eq CategoryName where c1 == c2 = show c1 == show c2
tests/.zeolite-module view
@@ -32,7 +32,6 @@ } ] private_deps: [- "lib/testing" "visibility" "visibility2" ]@@ -51,4 +50,4 @@ defines: [Default] } ]-mode: incremental {}+mode: incremental { }
+ tests/arg-labels.0rt view
@@ -0,0 +1,308 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "call with arg labels" {+ success+ exclude compiler "value:"+}++unittest categoryCall {+ \ Testing.checkEquals(Value:call(value: 1), 1)+}++unittest typeValueCall {+ \ Testing.checkEquals(Value.new(value: 1).add(value: 10), 11)+}++concrete Value {+ @category call (Int value:) -> (Int)+ @type new (Int value:) -> (#self)+ @value add (Int value:) -> (Int)+}++define Value {+ @value Int storedValue++ call (value) { return value }+ new (value) { return Value{ value } }+ add (value) { return storedValue+value }+}+++testcase "call with missing required label" {+ error+ require compiler "value:"+}++unittest test {+ \ Value:call(1)+}++concrete Value {+ @category call (Int value:) -> (Int)+}++define Value {+ call (value) { return value }+}+++testcase "call with unexpected label" {+ error+ require compiler "value:"+}++unittest test {+ \ Value:call(value: 1)+}++concrete Value {+ @category call (Int) -> (Int)+}++define Value {+ call (value) { return value }+}+++testcase "call with mismatched label" {+ error+ require compiler "value:"+ require compiler "number:"+}++unittest test {+ \ Value:call(number: 1)+}++concrete Value {+ @category call (Int value:) -> (Int)+}++define Value {+ call (value) { return value }+}+++testcase "merge with matched label" {+ success+}++unittest test {+ \ Testing.checkEquals(Value.call(value: 1), 1)+}++@type interface Base {+ call (Int value:) -> (Int)+}++concrete Value {+ defines Base++ @type call (Int value:) -> (Int)+}++define Value {+ call (value) { return value }+}+++testcase "failed merge with mismatched label" {+ error+ require compiler "value:"+ require compiler "number:"+}++@type interface Base {+ call (Int value:) -> (Int)+}++concrete Value {+ defines Base++ @type call (Int number:) -> (Int)+}++define Value {+ call (number) { return number }+}+++testcase "failed merge with added label" {+ error+ require compiler "number:"+}++@type interface Base {+ call (Int) -> (Int)+}++concrete Value {+ defines Base++ @type call (Int number:) -> (Int)+}++define Value {+ call (number) { return number }+}+++testcase "failed merge with removed label" {+ error+ require compiler "number:"+}++@type interface Base {+ call (Int number:) -> (Int)+}++concrete Value {+ defines Base++ @type call (Int) -> (Int)+}++define Value {+ call (number) { return number }+}+++testcase "warning when arg name differs from arg label" {+ compiles+ require compiler "value:"+ require compiler "number"+}++concrete Value {+ @type call (Int value:) -> (Int)+}++define Value {+ call (number) { return number }+}+++testcase "no warning when arg with label is ignored" {+ compiles+ exclude compiler "value:"+}++concrete Value {+ @type call (Int value:) -> (Int)+}++define Value {+ call (_) { return 1 }+}+++testcase "prefix not allowed with required labels" {+ error+ require compiler "value:"+}++unittest test {+ \ `Value.call` 123+}++concrete Value {+ @type call (Int value:) -> (Int)+}++define Value {+ call (_) { return 1 }+}+++testcase "infix not allowed with required labels" {+ error+ require compiler "value1:"+ require compiler "value2:"+}++unittest test {+ \ 987 `Value.call` 123+}++concrete Value {+ @type call (Int value1:, Int value2:) -> (Int)+}++define Value {+ call (_, _) { return 1 }+}+++testcase "arg labels disallowed when forwarding multiple args" {+ error+ require compiler "value1:"+ exclude compiler "value2:"+}++unittest test {+ \ Value.call2(value1: Value.call1())+}++concrete Value {+ @type call1 () -> (Int, Int)+ @type call2 (Int value1:, Int value2:) -> ()+}++define Value {+ call1 () { return 1, 2 }+ call2 (_, _) { }+}+++testcase "arg labels still checked when passing multiple returns" {+ error+ require compiler "value1:"+ require compiler "value2:"+}++unittest test {+ \ Value.call2(Value.call1())+}++concrete Value {+ @type call1 () -> (Int, Int)+ @type call2 (Int value1:, Int value2:) -> ()+}++define Value {+ call1 () { return 1, 2 }+ call2 (_, _) { }+}+++testcase "reusing label is allowed" {+ success+}++unittest test {+ \ Testing.checkEquals(Value.call(positive: 1, positive: 2), 3)+}++concrete Value {+ @type call (Int positive:, Int positive:) -> (Int)+}++define Value {+ call (value1, value2) { return value1+value2 }+}
tests/bad-path/.zeolite-module view
@@ -1,2 +1,2 @@ path: "/dev/null"-mode: incremental {}+mode: incremental { }
tests/builtin-types.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -32,37 +32,37 @@ } unittest bool {- if (!present(reduce<Bool,Bool>(true))) {+ if (!present(reduce<Bool, Bool>(true))) { fail("Failed") } } unittest asBool {- if (!present(reduce<Bool,AsBool>(true))) {+ if (!present(reduce<Bool, AsBool>(true))) { fail("Failed") } } unittest asChar {- if (present(reduce<Bool,AsChar>(true))) {+ if (present(reduce<Bool, AsChar>(true))) { fail("Failed") } } unittest asInt {- if (!present(reduce<Bool,AsInt>(true))) {+ if (!present(reduce<Bool, AsInt>(true))) { fail("Failed") } } unittest asFloat {- if (!present(reduce<Bool,AsFloat>(true))) {+ if (!present(reduce<Bool, AsFloat>(true))) { fail("Failed") } } unittest formatted {- if (!present(reduce<Bool,Formatted>(true))) {+ if (!present(reduce<Bool, Formatted>(true))) { fail("Failed") } }@@ -73,37 +73,37 @@ } unittest char {- if (!present(reduce<Char,Char>('a'))) {+ if (!present(reduce<Char, Char>('a'))) { fail("Failed") } } unittest asBool {- if (!present(reduce<Char,AsBool>('a'))) {+ if (!present(reduce<Char, AsBool>('a'))) { fail("Failed") } } unittest asChar {- if (!present(reduce<Char,AsChar>('a'))) {+ if (!present(reduce<Char, AsChar>('a'))) { fail("Failed") } } unittest asInt {- if (!present(reduce<Char,AsInt>('a'))) {+ if (!present(reduce<Char, AsInt>('a'))) { fail("Failed") } } unittest asFloat {- if (!present(reduce<Char,AsFloat>('a'))) {+ if (!present(reduce<Char, AsFloat>('a'))) { fail("Failed") } } unittest formatted {- if (!present(reduce<Char,Formatted>('a'))) {+ if (!present(reduce<Char, Formatted>('a'))) { fail("Failed") } }@@ -114,37 +114,37 @@ } unittest int {- if (!present(reduce<Int,Int>(1))) {+ if (!present(reduce<Int, Int>(1))) { fail("Failed") } } unittest asBool {- if (!present(reduce<Int,AsBool>(1))) {+ if (!present(reduce<Int, AsBool>(1))) { fail("Failed") } } unittest asChar {- if (!present(reduce<Int,AsChar>(1))) {+ if (!present(reduce<Int, AsChar>(1))) { fail("Failed") } } unittest asInt {- if (!present(reduce<Int,AsInt>(1))) {+ if (!present(reduce<Int, AsInt>(1))) { fail("Failed") } } unittest asFloat {- if (!present(reduce<Int,AsFloat>(1))) {+ if (!present(reduce<Int, AsFloat>(1))) { fail("Failed") } } unittest formatted {- if (!present(reduce<Int,Formatted>(1))) {+ if (!present(reduce<Int, Formatted>(1))) { fail("Failed") } }@@ -155,37 +155,37 @@ } unittest float {- if (!present(reduce<Float,Float>(1.0))) {+ if (!present(reduce<Float, Float>(1.0))) { fail("Failed") } } unittest asBool {- if (!present(reduce<Float,AsBool>(1.0))) {+ if (!present(reduce<Float, AsBool>(1.0))) { fail("Failed") } } unittest asChar {- if (present(reduce<Float,AsChar>(1.0))) {+ if (present(reduce<Float, AsChar>(1.0))) { fail("Failed") } } unittest asInt {- if (!present(reduce<Float,AsInt>(1.0))) {+ if (!present(reduce<Float, AsInt>(1.0))) { fail("Failed") } } unittest asFloat {- if (!present(reduce<Float,AsFloat>(1.0))) {+ if (!present(reduce<Float, AsFloat>(1.0))) { fail("Failed") } } unittest formatted {- if (!present(reduce<Float,Formatted>(1.0))) {+ if (!present(reduce<Float, Formatted>(1.0))) { fail("Failed") } }@@ -196,31 +196,31 @@ } unittest charBuffer {- if (!present(reduce<CharBuffer,CharBuffer>(CharBuffer.new(0)))) {+ if (!present(reduce<CharBuffer, CharBuffer>(CharBuffer.new(0)))) { fail("Failed") } } unittest readAt {- if (!present(reduce<CharBuffer,ReadAt<Char>>(CharBuffer.new(0)))) {+ if (!present(reduce<CharBuffer, ReadAt<Char>>(CharBuffer.new(0)))) { fail("Failed") }- if (present(reduce<CharBuffer,ReadAt<Int>>(CharBuffer.new(0)))) {+ if (present(reduce<CharBuffer, ReadAt<Int>>(CharBuffer.new(0)))) { fail("Failed") } } unittest writeAt {- if (!present(reduce<CharBuffer,WriteAt<Char>>(CharBuffer.new(0)))) {+ if (!present(reduce<CharBuffer, WriteAt<Char>>(CharBuffer.new(0)))) { fail("Failed") }- if (present(reduce<CharBuffer,WriteAt<Int>>(CharBuffer.new(0)))) {+ if (present(reduce<CharBuffer, WriteAt<Int>>(CharBuffer.new(0)))) { fail("Failed") } } unittest container {- if (!present(reduce<CharBuffer,Container>(CharBuffer.new(0)))) {+ if (!present(reduce<CharBuffer, Container>(CharBuffer.new(0)))) { fail("Failed") } }@@ -231,67 +231,67 @@ } unittest string {- if (!present(reduce<String,String>("a"))) {+ if (!present(reduce<String, String>("a"))) { fail("Failed") } } unittest asBool {- if (!present(reduce<String,AsBool>("a"))) {+ if (!present(reduce<String, AsBool>("a"))) { fail("Failed") } } unittest asChar {- if (present(reduce<String,AsChar>("a"))) {+ if (present(reduce<String, AsChar>("a"))) { fail("Failed") } } unittest asInt {- if (present(reduce<String,AsInt>("a"))) {+ if (present(reduce<String, AsInt>("a"))) { fail("Failed") } } unittest asFloat {- if (present(reduce<String,AsFloat>("a"))) {+ if (present(reduce<String, AsFloat>("a"))) { fail("Failed") } } unittest formatted {- if (!present(reduce<String,Formatted>("a"))) {+ if (!present(reduce<String, Formatted>("a"))) { fail("Failed") } } unittest defaultOrder {- if (!present(reduce<String,DefaultOrder<Char>>("a"))) {+ if (!present(reduce<String, DefaultOrder<Char>>("a"))) { fail("Failed") }- if (present(reduce<String,DefaultOrder<Int>>("a"))) {+ if (present(reduce<String, DefaultOrder<Int>>("a"))) { fail("Failed") } } unittest subSequence {- if (!present(reduce<String,SubSequence>("a"))) {+ if (!present(reduce<String, SubSequence>("a"))) { fail("Failed") } } unittest readAt {- if (!present(reduce<String,ReadAt<Char>>("a"))) {+ if (!present(reduce<String, ReadAt<Char>>("a"))) { fail("Failed") }- if (present(reduce<String,ReadAt<Int>>("a"))) {+ if (present(reduce<String, ReadAt<Int>>("a"))) { fail("Failed") } } unittest container {- if (!present(reduce<String,Container>("a"))) {+ if (!present(reduce<String, Container>("a"))) { fail("Failed") } }@@ -306,19 +306,19 @@ } unittest charDefault {- \ Testing.checkEquals(Char.default(),'\000')+ \ Testing.checkEquals(Char.default(), '\000') } unittest floatDefault {- \ Testing.checkEquals(Float.default(),0.0)+ \ Testing.checkEquals(Float.default(), 0.0) } unittest intDefault {- \ Testing.checkEquals(Int.default(),0)+ \ Testing.checkEquals(Int.default(), 0) } unittest stringDefault {- \ Testing.checkEquals(String.default(),"")+ \ Testing.checkEquals(String.default(), "") } unittest boolDuplicate {@@ -326,39 +326,39 @@ } unittest charDuplicate {- \ Testing.checkEquals('a'.duplicate(),'a')+ \ Testing.checkEquals('a'.duplicate(), 'a') } unittest floatDuplicate {- \ Testing.checkEquals((1.1).duplicate(),1.1)+ \ Testing.checkEquals((1.1).duplicate(), 1.1) } unittest intDuplicate {- \ Testing.checkEquals((123).duplicate(),123)+ \ Testing.checkEquals((123).duplicate(), 123) } unittest stringDuplicate {- \ Testing.checkEquals("string".duplicate(),"string")+ \ Testing.checkEquals("string".duplicate(), "string") } unittest boolHashed {- \ Testing.checkNotEquals(true.hashed(),false.hashed())+ \ Testing.checkNotEquals(true.hashed(), false.hashed()) } unittest charHashed {- \ Testing.checkNotEquals('a'.hashed(),'b'.hashed())+ \ Testing.checkNotEquals('a'.hashed(), 'b'.hashed()) } unittest floatHashed {- \ Testing.checkNotEquals((1.1).hashed(),(1.2).hashed())+ \ Testing.checkNotEquals((1.1).hashed(), (1.2).hashed()) } unittest intHashed {- \ Testing.checkNotEquals((123).hashed(),(124).hashed())+ \ Testing.checkNotEquals((123).hashed(), (124).hashed()) } unittest stringHashed {- \ Testing.checkNotEquals("string12".hashed(),"string21".hashed())+ \ Testing.checkNotEquals("string12".hashed(), "string21".hashed()) } unittest stringLessThan {@@ -374,10 +374,10 @@ } unittest stringBuilder {- [Append<Formatted>&Build<String>] builder <- String.builder()- \ Testing.checkEquals(builder.build(),"")- \ Testing.checkEquals(builder.append("xyz").build(),"xyz")- \ Testing.checkEquals(builder.append(123).build(),"xyz123")+ [Append<Formatted> & Build<String>] builder <- String.builder()+ \ Testing.checkEquals(builder.build(), "")+ \ Testing.checkEquals(builder.append("xyz").build(), "xyz")+ \ Testing.checkEquals(builder.append(123).build(), "xyz123") } unittest charLessThan {@@ -534,38 +534,38 @@ unittest writeAndRead { CharBuffer buffer <- CharBuffer.new(5)- .writeAt(0,'a')- .writeAt(1,'b')- .writeAt(2,'c')- .writeAt(3,'d')- .writeAt(4,'e')+ .writeAt(0, 'a')+ .writeAt(1, 'b')+ .writeAt(2, 'c')+ .writeAt(3, 'd')+ .writeAt(4, 'e') // overwriting here- .writeAt(1,'B')- .writeAt(2,'C')+ .writeAt(1, 'B')+ .writeAt(2, 'C') - \ Testing.checkEquals(buffer.size(),5)- \ Testing.checkEquals(buffer.readAt(0),'a')- \ Testing.checkEquals(buffer.readAt(1),'B')- \ Testing.checkEquals(buffer.readAt(2),'C')- \ Testing.checkEquals(buffer.readAt(3),'d')- \ Testing.checkEquals(buffer.readAt(4),'e')+ \ Testing.checkEquals(buffer.size(), 5)+ \ Testing.checkEquals(buffer.readAt(0), 'a')+ \ Testing.checkEquals(buffer.readAt(1), 'B')+ \ Testing.checkEquals(buffer.readAt(2), 'C')+ \ Testing.checkEquals(buffer.readAt(3), 'd')+ \ Testing.checkEquals(buffer.readAt(4), 'e') } unittest resizeDown {- CharBuffer buffer <- CharBuffer.new(5).resize(3).writeAt(2,'a')- \ Testing.checkEquals(buffer.size(),3)- \ Testing.checkEquals(buffer.readAt(2),'a')+ CharBuffer buffer <- CharBuffer.new(5).resize(3).writeAt(2, 'a')+ \ Testing.checkEquals(buffer.size(), 3)+ \ Testing.checkEquals(buffer.readAt(2), 'a') } unittest resizeUp {- CharBuffer buffer <- CharBuffer.new(5).resize(7).writeAt(6,'a')- \ Testing.checkEquals(buffer.size(),7)- \ Testing.checkEquals(buffer.readAt(6),'a')+ CharBuffer buffer <- CharBuffer.new(5).resize(7).writeAt(6, 'a')+ \ Testing.checkEquals(buffer.size(), 7)+ \ Testing.checkEquals(buffer.readAt(6), 'a') } testcase "CharBuffer read negative" {- crash+ failure require "-10" require "bounds" }@@ -576,7 +576,7 @@ testcase "CharBuffer read past end" {- crash+ failure require "3" require "bounds" }@@ -587,29 +587,29 @@ testcase "CharBuffer write negative" {- crash+ failure require "-10" require "bounds" } unittest test {- \ CharBuffer.new(3).writeAt(-10,'a')+ \ CharBuffer.new(3).writeAt(-10, 'a') } testcase "CharBuffer write past end" {- crash+ failure require "3" require "bounds" } unittest test {- \ CharBuffer.new(3).writeAt(3,'a')+ \ CharBuffer.new(3).writeAt(3, 'a') } testcase "CharBuffer new negative" {- crash+ failure require "-10" require "size" }@@ -620,7 +620,7 @@ testcase "CharBuffer resize negative" {- crash+ failure require "-10" require "size" }@@ -640,7 +640,7 @@ if (!present(strong(value2))) { fail("Failed") }- [Append<Formatted>&Build<String>] builder <- String.builder().append(require(value1))+ [Append<Formatted> & Build<String>] builder <- String.builder().append(require(value1)) value1 <- empty if (present(strong(value2))) { fail("Failed")@@ -661,7 +661,7 @@ unittest subsequence { String s <- "abcde"- String s2 <- s.subSequence(1,3)+ String s2 <- s.subSequence(1, 3) if (s2 != "bcd") { fail(s2) }@@ -669,7 +669,7 @@ unittest emptySubsequence { String s <- ""- String s2 <- s.subSequence(0,0)+ String s2 <- s.subSequence(0, 0) if (s2 != "") { fail(s2) }@@ -689,26 +689,26 @@ String value <- "abcdefg" traverse (value.defaultOrder() -> Char c) {- \ Testing.checkEquals(c,value.readAt(index))+ \ Testing.checkEquals(c, value.readAt(index)) index <- index+1 } - \ Testing.checkEquals(index,7)+ \ Testing.checkEquals(index, 7) } unittest fromCharBuffer { CharBuffer buffer <- CharBuffer.new(5)- .writeAt(0,'a')- .writeAt(1,'b')- .writeAt(2,'c')- .writeAt(3,'d')- .writeAt(4,'e')- \ Testing.checkEquals(String.fromCharBuffer(buffer),"abcde")+ .writeAt(0, 'a')+ .writeAt(1, 'b')+ .writeAt(2, 'c')+ .writeAt(3, 'd')+ .writeAt(4, 'e')+ \ Testing.checkEquals(String.fromCharBuffer(buffer), "abcde") } testcase "String access negative" {- crash+ failure require "-10" require "bounds" }@@ -729,7 +729,7 @@ testcase "String access past end" {- crash+ failure require "3" require "bounds" }@@ -750,7 +750,7 @@ testcase "String subsequence past end" {- crash+ failure require "3" require "size" }@@ -761,7 +761,7 @@ define Test { run () {- \ "abc".subSequence(1,3)+ \ "abc".subSequence(1, 3) } } @@ -775,19 +775,19 @@ } unittest accurateMax {- \ Testing.checkEquals(Char.maxBound().asInt(),255)+ \ Testing.checkEquals(Char.maxBound().asInt(), 255) } unittest accurateMin {- \ Testing.checkEquals(Char.minBound().asInt(),0)+ \ Testing.checkEquals(Char.minBound().asInt(), 0) } unittest asIntIsUnsigned {- \ Testing.checkEquals('\xff'.asInt(),255)+ \ Testing.checkEquals('\xff'.asInt(), 255) } unittest asFloatIsUnsigned {- \ Testing.checkEquals('\xff'.asFloat(),255.0)+ \ Testing.checkEquals('\xff'.asFloat(), 255.0) } @@ -796,21 +796,21 @@ } unittest accurateMax {- \ Testing.checkEquals(Int.maxBound(),9223372036854775807)+ \ Testing.checkEquals(Int.maxBound(), 9223372036854775807) } unittest accurateMin {- \ Testing.checkEquals(Int.minBound(),-9223372036854775808)+ \ Testing.checkEquals(Int.minBound(), -9223372036854775808) } unittest asCharIsPeriodic {- \ Testing.checkEquals((65).asChar(),(65+256).asChar())- \ Testing.checkEquals((65).asChar(),(65+1024).asChar())- \ Testing.checkEquals((65).asChar(),(65-1024).asChar())+ \ Testing.checkEquals((65).asChar(), (65+256).asChar())+ \ Testing.checkEquals((65).asChar(), (65+1024).asChar())+ \ Testing.checkEquals((65).asChar(), (65-1024).asChar()) } unittest hexUnsigned {- \ Testing.checkEquals(\xffffffffffffffff,-1)+ \ Testing.checkEquals(\xffffffffffffffff, -1) } @@ -1057,4 +1057,34 @@ if (b2 != true) { fail(b2) }+}+++testcase "Float parsing" {+ success+}++unittest decUnescaped {+ \ Testing.checkEquals(123.456e-3, 123.0/1000.0+456.0/1000.0/1000.0)+ \ Testing.checkEquals(123.456e3, 123.0*1000.0+456.0)+}++unittest decEscaped {+ \ Testing.checkEquals(\d123.456, 123.456)+ \ Testing.checkEquals(\D123.456, 123.456)+}++unittest hexEscaped {+ \ Testing.checkEquals(\xff.ee, 255.0+238.0/256.0)+ \ Testing.checkEquals(\Xff.ee, 255.0+238.0/256.0)+}++unittest octEscaped {+ \ Testing.checkEquals(\o10.10, 8.125)+ \ Testing.checkEquals(\O10.10, 8.125)+}++unittest binEscaped {+ \ Testing.checkEquals(\b101.101, 5.0+5.0/8.0)+ \ Testing.checkEquals(\B101.101, 5.0+5.0/8.0) }
tests/check-defs/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "tests/check-defs"-mode: incremental {}+mode: incremental { }
tests/check-defs/private1.0rx view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -define Type {}+define Type { }
tests/check-defs/private2.0rx view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -define Type {}+define Type { }
tests/check-defs/public.0rp view
@@ -16,6 +16,6 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete Type {}+concrete Type { } -concrete Undefined {}+concrete Undefined { }
tests/cli-tests.sh view
@@ -1,7 +1,7 @@ #!/usr/bin/env bash # -------------------------------------------------------------------------------# Copyright 2020-2022 Kevin P. Barry+# Copyright 2020-2023 Kevin P. Barry # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.@@ -84,6 +84,22 @@ } +test_custom_testcase() {+ do_zeolite -p "$ZEOLITE_PATH" $PARALLEL -r tests/custom-testcase -f+ local output=$(do_zeolite -p "$ZEOLITE_PATH" -t tests/custom-testcase 2>&1 || true)+ if ! echo "$output" | egrep -q 'Passed.+ 0 .*Failed.+ 4 .*'; then+ show_message 'Expected 4 failed tests and 0 passing:'+ echo "$output" 1>&2+ return 1+ fi+ if [[ $(echo "$output" | egrep -c 'custom testcase') -ne 4 ]]; then+ show_message 'Expected 4 test failures to be related to "custom testcase":'+ echo "$output" 1>&2+ return 1+ fi+}++ require_patterns() { local output=$1 local error=0@@ -214,7 +230,7 @@ test_leak_check() {- local binary="$ZEOLITE_PATH/tests/leak-check/LeakTest"+ local binary="$ZEOLITE_PATH/tests/leak-check/LeakCheck" rm -f "$binary" do_zeolite -p "$ZEOLITE_PATH" $PARALLEL -r tests/leak-check -f # race-condition check@@ -304,12 +320,12 @@ test_module_only() { local output=$(do_zeolite -p "$ZEOLITE_PATH" -R tests/module-only -f || true)- if ! echo "$output" | egrep -q 'Type1 not found'; then+ if ! echo "$output" | egrep -q 'Type1.+not found'; then show_message 'Expected Type1 definition error from tests/module-only:' echo "$output" 1>&2 return 1 fi- if echo "$output" | egrep -q 'Type2 not found'; then+ if echo "$output" | egrep -q 'Type2.+not (found|visible)'; then show_message 'Unexpected Type2 definition error from tests/module-only:' echo "$output" 1>&2 return 1@@ -319,12 +335,12 @@ test_module_only2() { local output=$(do_zeolite -p "$ZEOLITE_PATH" -R tests/module-only2 -f || true)- if ! echo "$output" | egrep -q 'Type1'; then+ if ! echo "$output" | egrep -q 'Type1.+not visible'; then show_message 'Expected Type1 definition error from tests/module-only2:' echo "$output" 1>&2 return 1 fi- if echo "$output" | egrep -q 'Type2'; then+ if echo "$output" | egrep -q 'Type2.+not (found|visible)'; then show_message 'Unexpected Type2 definition error from tests/module-only2:' echo "$output" 1>&2 return 1@@ -567,6 +583,7 @@ test_bad_path test_bad_system_include test_check_defs+ test_custom_testcase test_example_hello test_example_parser test_example_primes
tests/conditionals.0rt view
@@ -33,7 +33,7 @@ } } -concrete Value {}+concrete Value { } testcase "return if/elif/else" {@@ -53,7 +53,7 @@ } } -concrete Value {}+concrete Value { } testcase "assign if/elif condition" {@@ -71,7 +71,7 @@ } } -concrete Value {}+concrete Value { } testcase "different in if and else" {@@ -81,8 +81,8 @@ } define Value {- @value process () -> (optional Value,optional Value)- process () (value1,value2) {+ @value process () -> (optional Value, optional Value)+ process () (value1, value2) { if (false) { value1 <- empty } else {@@ -91,7 +91,7 @@ } } -concrete Value {}+concrete Value { } testcase "missing in if" {@@ -111,7 +111,7 @@ } } -concrete Value {}+concrete Value { } testcase "missing in elif" {@@ -131,7 +131,7 @@ } } -concrete Value {}+concrete Value { } testcase "missing in else" {@@ -152,7 +152,7 @@ } -concrete Value {}+concrete Value { } testcase "missing in implicit else" {@@ -171,7 +171,7 @@ } } -concrete Value {}+concrete Value { } testcase "return set in predicate for subsequent blocks" {@@ -190,7 +190,7 @@ } } -concrete Value {}+concrete Value { } @@ -212,14 +212,14 @@ } } -concrete Value {}+concrete Value { } testcase "branch jump skips validation of named return" { compiles } -concrete Test {}+concrete Test { } define Test { @value process () -> (Bool)@@ -239,7 +239,7 @@ testcase "crash in if" {- crash+ failure require "empty" } @@ -252,7 +252,7 @@ testcase "crash in elif" {- crash+ failure require "empty" } @@ -270,8 +270,8 @@ } define Value {- @value process () -> (optional Value,optional Value)- process () (value1,value2) {+ @value process () -> (optional Value, optional Value)+ process () (value1, value2) { if (false) { value1 <- empty value2 <- empty@@ -285,7 +285,7 @@ } } -concrete Value {}+concrete Value { } testcase "multi missing in if" {@@ -294,8 +294,8 @@ } define Value {- @value process () -> (optional Value,optional Value)- process () (value1,value2) {+ @value process () -> (optional Value, optional Value)+ process () (value1, value2) { if (false) { value1 <- empty } elif (false) {@@ -308,7 +308,7 @@ } } -concrete Value {}+concrete Value { } testcase "multi missing in elif" {@@ -317,8 +317,8 @@ } define Value {- @value process () -> (optional Value,optional Value)- process () (value1,value2) {+ @value process () -> (optional Value, optional Value)+ process () (value1, value2) { if (false) { value1 <- empty value2 <- empty@@ -331,7 +331,7 @@ } } -concrete Value {}+concrete Value { } testcase "multi missing in else" {@@ -340,8 +340,8 @@ } define Value {- @value process () -> (optional Value,optional Value)- process () (value1,value2) {+ @value process () -> (optional Value, optional Value)+ process () (value1, value2) { if (false) { value1 <- empty value2 <- empty@@ -354,7 +354,7 @@ } } -concrete Value {}+concrete Value { } testcase "cleanup before return in if" {
tests/conversions.0rt view
@@ -21,33 +21,33 @@ } unittest toType {- \ Testing.checkEquals(Helper.getType(Value.create()?Base1),"Base1")+ \ Testing.checkEquals(Helper.getType(Value.create()?Base1), "Base1") } unittest toAny {- \ Testing.checkEquals(Helper.getType(Value.create()?any),"any")+ \ Testing.checkEquals(Helper.getType(Value.create()?any), "any") } unittest toUnion {- \ Testing.checkEquals(Helper.getType(Value.create()?[Base1|Base2]),"[Base1|Base2]")+ \ Testing.checkEquals(Helper.getType(Value.create()?[Base1 | Base2]), "[Base1|Base2]") } unittest toIntersect {- \ Testing.checkEquals(Helper.getType(Value.create()?[Base1&Base2]),"[Base1&Base2]")+ \ Testing.checkEquals(Helper.getType(Value.create()?[Base1 & Base2]), "[Base1&Base2]") } unittest toParam {- \ Testing.checkEquals(Helper.toParam<Value,Base1>(Value.create()),"Base1")+ \ Testing.checkEquals(Helper.toParam<Value, Base1>(Value.create()), "Base1") } unittest toTypeOptional { optional Value value <- Value.create()- \ Testing.checkEquals(Helper.getType2(value?Base1),"Base1")+ \ Testing.checkEquals(Helper.getType2(value?Base1), "Base1") } unittest toAnyOptional { optional Value value <- Value.create()- \ Testing.checkEquals(Helper.getType2(value?any),"any")+ \ Testing.checkEquals(Helper.getType2(value?any), "any") } unittest convertedCall {@@ -56,7 +56,7 @@ } concrete Helper {- @type toParam<#x,#y>+ @type toParam<#x, #y> #x requires #y (#x) -> (String) @@ -95,7 +95,7 @@ } define Value {- call () {}+ call () { } create () { return Value{}@@ -124,7 +124,7 @@ } define Value {- call () {}+ call () { } create () { return Value{}
+ tests/custom-testcase/.zeolite-module view
@@ -0,0 +1,3 @@+root: "../.."+path: "tests/custom-testcase"+mode: incremental { }
+ tests/custom-testcase/README.md view
@@ -0,0 +1,14 @@+# Custom `Testcase` Compiler Failures.++_All_ tests this module should **always fail**. It tests that compiling a+`testcase` with a custom `Testcase` catches type issues.++To compile and run the tests:++```shell+ZEOLITE_PATH=$(zeolite --get-path)+zeolite -p $ZEOLITE_PATH -r tests/custom-testcase+zeolite -p $ZEOLITE_PATH -t tests/custom-testcase+```++_Every_ test should fail with an error related to `custom testcase`.
+ tests/custom-testcase/tests.0rt view
@@ -0,0 +1,63 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "success with unknown type" {+ success Foo+}++unittest test { }+++testcase "success with non-Testcase type" {+ success String+}++unittest test { }+++testcase "success with param" {+ success Helper<#x>+}++concrete Helper<#x> {+ defines Testcase+}++define Helper {+ start () { }+ finish () { }+}++unittest test { }+++testcase "success with invalid substitution" {+ success Helper<CharBuffer>+}++concrete Helper<#x> {+ defines Testcase+ #x immutable+}++define Helper {+ start () { }+ finish () { }+}++unittest test { }
tests/defer.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -61,6 +61,34 @@ } +testcase "defer does not unset members" {+ success+}++concrete Test {+ @type new () -> (#self)+ @value deferMembers () -> ()+ @value getValueMember () -> (String)+ @value getCategoryMember () -> (String)+}++define Test {+ @category String categoryMember <- "abc"+ @value String valueMember++ new () { return #self{ "def" } }+ deferMembers () { categoryMember, valueMember <- defer }+ getValueMember () { return valueMember }+ getCategoryMember () { return categoryMember }+}++unittest test {+ Test test <- Test.new()+ \ Testing.checkEquals(test.getCategoryMember(), "abc")+ \ Testing.checkEquals(test.getValueMember(), "def")+}++ testcase "multiple deferred" { error require "value1"@@ -92,7 +120,7 @@ require "initialized" } -concrete Type {}+concrete Type { } define Type { @value Int value@@ -111,7 +139,7 @@ require "initialized" } -concrete Type {}+concrete Type { } define Type { @category Int value <- 1@@ -131,7 +159,7 @@ require "read-only" } -concrete Type {}+concrete Type { } define Type { @value call (Int) -> ()@@ -327,7 +355,7 @@ testcase "deferred not checked in condition that jumps" {- crash+ failure require "success" }
+ tests/delegation.0rt view
@@ -0,0 +1,294 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "delegate to functions" {+ success+}++unittest fromCategory {+ \ Testing.checkEquals(Value:call1(13, "message"), 123-13+7)+}++unittest fromType {+ \ Testing.checkEquals(Value.call2(13, "message"), 456-13+7)+}++unittest fromValue {+ \ Testing.checkEquals(Value.new().call3(13, "message"), 789-13+7)+}++concrete Value {+ @type new () -> (#self)+ @category call1 (Int, String) -> (Int)+ @type call2 (Int, String) -> (Int)+ @value call3 (Int, String) -> (Int)+}++define Value {+ new () { return #self{ } }++ call1 (number1, message1) {+ return delegate -> `delegatedTo1`+ }++ call2 (number2, message2) {+ \ delegate -> `delegatedTo1`+ return delegate -> `delegatedTo2`+ }++ call3 (number3, message3) {+ \ delegate -> `delegatedTo1`+ \ delegate -> `delegatedTo2`+ return delegate -> `delegatedTo3`+ }++ @category delegatedTo1 (Int, String) -> (Int)+ delegatedTo1 (number, message) {+ return 123-number+message.size()+ }++ @type delegatedTo2 (Int, String) -> (Int)+ delegatedTo2 (number, message) {+ return 456-number+message.size()+ }++ @value delegatedTo3 (Int, String) -> (Int)+ delegatedTo3 (number, message) {+ return 789-number+message.size()+ }+}+++testcase "delegate to correct initializer" {+ success+}++unittest fromCategory {+ Value value <- Value:new1(13, "message")+ \ Testing.checkEquals(value.getInt(), 13)+ \ Testing.checkEquals(value.getString(), "message")+}++unittest fromType {+ Value value <- Value.new2(13, "message")+ \ Testing.checkEquals(value.getInt(), 13)+ \ Testing.checkEquals(value.getString(), "message")+}++unittest fromValue {+ Value value <- Value.new2(9, "error")+ value <- value.new3(13, "message")+ \ Testing.checkEquals(value.getInt(), 13)+ \ Testing.checkEquals(value.getString(), "message")+}++concrete Value {+ @category new1 (Int, String) -> (Value)+ @type new2 (Int, String) -> (Value)+ @value new3 (Int, String) -> (Value)+ @value getInt () -> (Int)+ @value getString () -> (String)+}++define Value {+ @value Int number+ @value String message++ new1 (number1, message1) {+ return delegate -> Value+ }++ new2 (number2, message2) {+ return delegate -> Value+ }++ new3 (number3, message3) {+ return delegate -> Value+ }++ getInt () { return number }+ getString () { return message }+}+++testcase "delegate to #self" {+ success+}++unittest fromType {+ Value value <- Value.new1(13, "message")+ \ Testing.checkEquals(value.getInt(), 13)+ \ Testing.checkEquals(value.getString(), "message")+}++unittest fromValue {+ Value value <- Value.new1(9, "error")+ value <- value.new2(13, "message")+ \ Testing.checkEquals(value.getInt(), 13)+ \ Testing.checkEquals(value.getString(), "message")+}++concrete Value {+ @type new1 (Int, String) -> (Value)+ @value new2 (Int, String) -> (Value)+ @value getInt () -> (Int)+ @value getString () -> (String)+}++define Value {+ @value Int number+ @value String message++ new1 (number1, message1) {+ return delegate -> #self+ }++ new2 (number2, message2) {+ return delegate -> #self+ }++ getInt () { return number }+ getString () { return message }+}+++testcase "delegate fails from unittest" {+ error+ require compiler "delegation"+}++unittest test {+ \ delegate -> `Value:new`+}++concrete Value {+ @category new () -> (Value)+}++define Value {+ new () {+ return Value{ }+ }+}+++testcase "delegate fails from @category variable initializer" {+ error+ require compiler "delegation"+}++concrete Value { }++define Value {+ @category Value value <- delegate -> Value+}+++testcase "delegate fails with ignored args" {+ error+ require compiler "ignore"+}++concrete Value {+ @category new (Int, String) -> (Value)+}++define Value {+ new (value, _) {+ return delegate -> `delegatedTo`+ }++ @category delegatedTo (Int, String) -> (Value)+ delegatedTo (number, message) {+ return Value{ }+ }+}+++testcase "delegate fails with hidden args" {+ error+ require compiler "message"+ require compiler "hidden"+}++concrete Value {+ @category new (Int, String) -> (Value)+}++define Value {+ new (value, message) {+ $Hidden[message]$+ return delegate -> `delegatedTo`+ }++ @category delegatedTo (Int, String) -> (Value)+ delegatedTo (number, message) {+ return Value{ }+ }+}+++testcase "delegate fails with missing label" {+ error+ require compiler "message:"+}++concrete Value {+ @category new (Int, String) -> (Value)+}++define Value {+ new (number, message) {+ return delegate -> `delegatedTo`+ }++ @category delegatedTo (Int, String message:) -> (Value)+ delegatedTo (number, message) {+ return Value{ }+ }+}+++testcase "delegate passes along labels" {+ success+}++unittest test {+ \ Testing.checkEquals(Value:new(13, message: "message").getString(), "message")+}++concrete Value {+ @category new (Int, String message:) -> (Value)+ @value getString () -> (String)+}++define Value {+ @value Int number+ @value String message++ new (number, message) {+ return delegate -> `delegatedTo`+ }++ getString () { return message }++ @category delegatedTo (Int, String message:) -> (Value)+ delegatedTo (number, message) {+ return delegate -> Value+ }+}
tests/expr-lookup.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -27,7 +27,7 @@ testcase "MODULE_PATH is absolute" {- crash+ failure require "Failed condition: /.+/tests" } @@ -37,7 +37,7 @@ testcase "MODULE_PATH from regular source" {- crash+ failure require "Failed condition: /.+/tests" } @@ -57,7 +57,7 @@ testcase "macro used inline in expressions" {- crash+ failure require "Failed condition: /.+/tests is the path" } @@ -71,7 +71,7 @@ } unittest test {- \ Testing.checkEquals($ExprLookup[INT_EXPR]$,4)+ \ Testing.checkEquals($ExprLookup[INT_EXPR]$, 4) // Use it a second time to ensure that reserving the macro name doesn't // carry over to the next statement. \ $ExprLookup[INT_EXPR]$@@ -83,7 +83,7 @@ } unittest test {- \ Testing.checkEquals(ExprLookup.intExpr(),4)+ \ Testing.checkEquals(ExprLookup.intExpr(), 4) } @@ -99,7 +99,7 @@ @category String macroLocalVar <- "hello" run () {- \ Testing.checkEquals($ExprLookup[LOCAL_VAR]$,"hello")+ \ Testing.checkEquals($ExprLookup[LOCAL_VAR]$, "hello") } } @@ -124,7 +124,7 @@ } unittest test {- \ Testing.checkEquals(ExprLookup.localVar(),99)+ \ Testing.checkEquals(ExprLookup.localVar(), 99) } @@ -133,7 +133,7 @@ } unittest test {- \ Testing.checkEquals($ExprLookup[META_VAR]$,20)+ \ Testing.checkEquals($ExprLookup[META_VAR]$, 20) } @@ -142,17 +142,18 @@ } unittest test {- \ Testing.checkEquals($ExprLookup[INT_EXPR]$.formatted(),"4")+ \ Testing.checkEquals($ExprLookup[INT_EXPR]$.formatted(), "4") } testcase "source context" {- crash- require "tests/expr-lookup\.0rt"+ failure+ require "Failed condition: .*tests/expr-lookup\.0rt" } unittest test {- fail($SourceContext$)+ Formatted context <- $SourceContext$+ fail(context) } @@ -167,4 +168,22 @@ unittest test { String value <- $ExprLookup[USES_RECURSIVE]$+}+++testcase "call trace" {+ failure+ require "Failed condition: .*tests/expr-lookup\.0rt .*testcase"+}++unittest test {+ optional Order<Formatted> trace <- $CallTrace$+ \ Testing.checkPresent(trace)+ \ Testing.checkPresent(trace&.next())+ String combined <- String.builder()+ .append(require(trace).get())+ .append(" ")+ .append(require(trace&.next()).get())+ .build()+ fail(combined) }
tests/extension.0rt view
@@ -21,5 +21,5 @@ } unittest test {- \ Testing.checkEquals(Extension.execute(),"message")+ \ Testing.checkEquals(Extension.execute(), "message") }
tests/filters.0rt view
@@ -31,7 +31,7 @@ } define Value {- something () {}+ something () { } } @@ -42,13 +42,13 @@ require compiler "[Ll]ower.+ \[Type3\|Type4\]" } -@value interface Type1 {}+@value interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } -@value interface Type3 {}+@value interface Type3 { } -@value interface Type4 {}+@value interface Type4 { } concrete Value<#x> { #x requires Type1@@ -57,7 +57,7 @@ #x allows Type4 } -define Value {}+define Value { } testcase "implicit bound from reversing another filter" {@@ -67,46 +67,46 @@ require compiler "[Ll]ower.+ #y" } -@value interface Type {}+@value interface Type { } -concrete Value<#x,#y> {+concrete Value<#x, #y> { #x requires Type #y requires #x } -define Value {}+define Value { } testcase "defines filter is not an upper bound" { compiles } -@type interface Type1 {}+@type interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } concrete Value<#x> { #x defines Type1 #x allows Type2 } -define Value {}+define Value { } testcase "defines filter is not a lower bound" { compiles } -@type interface Type1 {}+@type interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } concrete Value<#x> { #x defines Type1 #x requires Type2 } -define Value {}+define Value { } testcase "function param bounded on both sides" {@@ -114,9 +114,9 @@ require compiler "#x.+bound" } -@value interface Type1 {}+@value interface Type1 { } -@value interface Type2 {}+@value interface Type2 { } @value interface Value { call<#x>@@ -138,7 +138,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -159,7 +159,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -180,7 +180,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -255,7 +255,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -276,7 +276,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -297,7 +297,7 @@ } define Type {- call () {}+ call () { } @category call2 () -> () call2 () {@@ -311,7 +311,7 @@ } concrete Type1 {- @type call<#i,#j,#k>+ @type call<#i, #j, #k> #i requires Formatted #j defines Equals<#j> #k allows Int@@ -319,10 +319,10 @@ } define Type1 {- call () {}+ call () { } } -concrete Type2<#x,#y,#z> {+concrete Type2<#x, #y, #z> { #x requires Formatted #y defines Equals<#y> #z allows Int@@ -332,7 +332,7 @@ define Type2 { call () {- \ Type1.call<#x,#y,#z>()+ \ Type1.call<#x, #y, #z>() } } @@ -347,7 +347,7 @@ #x requires String } -define Type {}+define Type { } concrete Test { @type call<#x>@@ -356,7 +356,7 @@ } define Test {- call (_) {}+ call (_) { } @type call2 () -> () call2 () {@@ -370,40 +370,40 @@ compiles } -concrete Test {}+concrete Test { } define Test {- @category call1<#x,#y>+ @category call1<#x, #y> #y immutable #x defines LessThan<#x> #x requires Formatted #y allows Int- (#x,#y) -> ()- call1 (x,y) {- \ call1<#x,#y>(x,y)+ (#x, #y) -> ()+ call1 (x, y) {+ \ call1<#x, #y>(x, y) } - @type call2<#x,#y>+ @type call2<#x, #y> #y immutable #x defines LessThan<#x> #x requires Formatted #y allows Int- (#x,#y) -> ()- call2 (x,y) {- \ call2<#x,#y>(x,y)- \ call1<#x,#y>(x,y)+ (#x, #y) -> ()+ call2 (x, y) {+ \ call2<#x, #y>(x, y)+ \ call1<#x, #y>(x, y) } - @value call3<#x,#y>+ @value call3<#x, #y> #y immutable #x defines LessThan<#x> #x requires Formatted #y allows Int- (#x,#y) -> ()- call3 (x,y) {- \ call3<#x,#y>(x,y)- \ call2<#x,#y>(x,y)- \ call1<#x,#y>(x,y)+ (#x, #y) -> ()+ call3 (x, y) {+ \ call3<#x, #y>(x, y)+ \ call2<#x, #y>(x, y)+ \ call1<#x, #y>(x, y) } } @@ -412,17 +412,17 @@ compiles } -concrete Test<#x,#y> {}+concrete Test<#x, #y> { } define Test {- @category call<#x,#y>+ @category call<#x, #y> #y immutable #x defines LessThan<#x> #x requires Formatted #y allows Int- (#x,#y) -> ()- call (x,y) {- \ call<#x,#y>(x,y)+ (#x, #y) -> ()+ call (x, y) {+ \ call<#x, #y>(x, y) } } @@ -437,7 +437,7 @@ concrete Test { @type call<#x>- #x allows [Formatted&AsBool]+ #x allows [Formatted & AsBool] () -> (#x) } @@ -462,7 +462,7 @@ concrete Test { @type call<#x>- #x allows [Formatted&AsBool]+ #x allows [Formatted & AsBool] () -> (#x) } @@ -483,7 +483,7 @@ concrete Test { @type call<#x>- #x requires [Int|String]+ #x requires [Int | String] (#x) -> () } @@ -507,7 +507,7 @@ concrete Test { @type call<#x>- #x requires [Int|String]+ #x requires [Int | String] (#x) -> () }
tests/freshness/.zeolite-module view
@@ -4,4 +4,4 @@ "tests/freshness/sub1" "tests/../tests/freshness/sub2" ]-mode: incremental {}+mode: incremental { }
tests/freshness/reverse/.zeolite-module view
@@ -3,4 +3,4 @@ private_deps: [ "../../../tests/freshness" ]-mode: incremental {}+mode: incremental { }
tests/function-calls.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -24,7 +24,7 @@ } unittest test {- [Value1|Value2] value <- Value1.create()+ [Value1 | Value2] value <- Value1.create() \ value.get() } @@ -72,7 +72,7 @@ } unittest test {- [Value1|Value2] value <- Value1.create()+ [Value1 | Value2] value <- Value1.create() \ value.get() } @@ -119,7 +119,7 @@ } unittest test {- [Int|String] value <- 1+ [Int | String] value <- 1 \ value.asFloat() } @@ -129,8 +129,8 @@ } unittest test {- [Value1|Value2] value <- Value1.create()- \ Testing.checkEquals(value.get().formatted(),"1")+ [Value1 | Value2] value <- Value1.create()+ \ Testing.checkEquals(value.get().formatted(), "1") } @value interface Base<|#x> {@@ -177,7 +177,7 @@ } unittest test {- [Value1|Value2] value <- Value1.create()+ [Value1 | Value2] value <- Value1.create() \ value.get()+1 } @@ -221,8 +221,8 @@ } unittest test {- [Value1|Value2] value <- Value1.create()- \ Testing.checkEquals(value?Base<Formatted>.get().formatted(),"1")+ [Value1 | Value2] value <- Value1.create()+ \ Testing.checkEquals(value?Base<Formatted>.get().formatted(), "1") } @value interface Base<|#x> {@@ -280,7 +280,7 @@ } unittest test {- [Base<AsBool>&Base<Formatted>] value <- Value1.create()+ [Base<AsBool> & Base<Formatted>] value <- Value1.create() \ value.get() } @@ -326,7 +326,7 @@ } unittest test {- [AsBool&Formatted] value <- 1+ [AsBool & Formatted] value <- 1 \ value.asFloat() } @@ -336,8 +336,8 @@ } unittest test {- [Base<Int>&Base<Formatted>] value <- Value1.create()- \ Testing.checkEquals(value.get(),1)+ [Base<Int> & Base<Formatted>] value <- Value1.create()+ \ Testing.checkEquals(value.get(), 1) } @value interface Base<|#x> {@@ -380,8 +380,8 @@ } unittest test {- [Base<AsBool>&Base<Formatted>] value <- Value1.create()- \ Testing.checkEquals(value?Base<Formatted>.get().formatted(),"1")+ [Base<AsBool> & Base<Formatted>] value <- Value1.create()+ \ Testing.checkEquals(value?Base<Formatted>.get().formatted(), "1") } @value interface Base<|#x> {@@ -436,7 +436,7 @@ } define Value {- call () {}+ call () { } } concrete Test {@@ -469,7 +469,7 @@ } } -concrete Test {}+concrete Test { } @@ -493,7 +493,7 @@ } define Value {- call () {}+ call () { } create () { return Value{}@@ -530,7 +530,7 @@ } } -concrete Test {}+concrete Test { } testcase "convert arg" {@@ -552,7 +552,7 @@ } define Value {- call () {}+ call () { } create () { return Value{}@@ -575,11 +575,11 @@ require "does not refine Value" } -@value interface Base {}+@value interface Base { } -concrete Value {}+concrete Value { } -define Value {}+define Value { } define Test { @type convert (Base) -> (Value)@@ -588,7 +588,7 @@ } } -concrete Test {}+concrete Test { } testcase "bad instance in param" {@@ -606,14 +606,14 @@ #x defines Equals<#x> } -define Value {}+define Value { } concrete Call { @type call<#x> () -> () } define Call {- call () {}+ call () { } } @@ -629,7 +629,7 @@ } } -concrete Test {}+concrete Test { } testcase "self in @category function" {@@ -644,7 +644,7 @@ } } -concrete Test {}+concrete Test { } testcase "large dispatch tables" {@@ -652,47 +652,47 @@ } unittest callDispatch {- \ Testing.checkEquals(Type.new().get(),00)- \ Testing.checkEquals(Type.new().get01(),01)- \ Testing.checkEquals(Type.new().get02(),02)- \ Testing.checkEquals(Type.new().get03(),03)- \ Testing.checkEquals(Type.new().get04(),04)- \ Testing.checkEquals(Type.new().get05(),05)- \ Testing.checkEquals(Type.new().get06(),06)- \ Testing.checkEquals(Type.new().get07(),07)- \ Testing.checkEquals(Type.new().get08(),08)- \ Testing.checkEquals(Type.new().get09(),09)- \ Testing.checkEquals(Type.new().get10(),10)- \ Testing.checkEquals(Type.new().get11(),11)- \ Testing.checkEquals(Type.new().get12(),12)- \ Testing.checkEquals(Type.new().get13(),13)- \ Testing.checkEquals(Type.new().get14(),14)- \ Testing.checkEquals(Type.new().get15(),15)- \ Testing.checkEquals(Type.new().get16(),16)- \ Testing.checkEquals(Type.new().get17(),17)- \ Testing.checkEquals(Type.new().get18(),18)+ \ Testing.checkEquals(Type.new().get(), 00)+ \ Testing.checkEquals(Type.new().get01(), 01)+ \ Testing.checkEquals(Type.new().get02(), 02)+ \ Testing.checkEquals(Type.new().get03(), 03)+ \ Testing.checkEquals(Type.new().get04(), 04)+ \ Testing.checkEquals(Type.new().get05(), 05)+ \ Testing.checkEquals(Type.new().get06(), 06)+ \ Testing.checkEquals(Type.new().get07(), 07)+ \ Testing.checkEquals(Type.new().get08(), 08)+ \ Testing.checkEquals(Type.new().get09(), 09)+ \ Testing.checkEquals(Type.new().get10(), 10)+ \ Testing.checkEquals(Type.new().get11(), 11)+ \ Testing.checkEquals(Type.new().get12(), 12)+ \ Testing.checkEquals(Type.new().get13(), 13)+ \ Testing.checkEquals(Type.new().get14(), 14)+ \ Testing.checkEquals(Type.new().get15(), 15)+ \ Testing.checkEquals(Type.new().get16(), 16)+ \ Testing.checkEquals(Type.new().get17(), 17)+ \ Testing.checkEquals(Type.new().get18(), 18) } unittest reduceBuiltin {- \ Testing.checkPresent(reduce<Type,Type>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base01>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base02>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base03>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base04>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base05>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base06>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base07>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base08>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base09>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base10>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base11>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base12>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base13>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base14>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base15>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base16>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base17>(Type.new()))- \ Testing.checkPresent(reduce<Type,Base18>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Type>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base01>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base02>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base03>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base04>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base05>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base06>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base07>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base08>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base09>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base10>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base11>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base12>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base13>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base14>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base15>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base16>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base17>(Type.new()))+ \ Testing.checkPresent(reduce<Type, Base18>(Type.new())) } concrete Type {@@ -774,7 +774,7 @@ execute (Formatted) -> () } -concrete Test {}+concrete Test { } define Test { @type test<#x>@@ -799,7 +799,7 @@ execute (Formatted) -> () } -concrete Test {}+concrete Test { } define Test { @type test<#x>@@ -826,7 +826,7 @@ execute () -> (String) } -concrete Test {}+concrete Test { } define Test { @type test<#x>@@ -853,7 +853,7 @@ execute () -> (String) } -concrete Test {}+concrete Test { } define Test { @type test<#x>@@ -871,12 +871,12 @@ } unittest test {- \ Testing.checkEquals(Value.create().call(1,"mess",2,"age"),"message")+ \ Testing.checkEquals(Value.create().call(1, "mess", 2, "age"), "message") } concrete Value { @type create () -> (Value)- @value call (Int,String,any,Formatted) -> (String)+ @value call (Int, String, any, Formatted) -> (String) } define Value {@@ -884,7 +884,7 @@ return Value{} } - call (_,x,_,y) {+ call (_, x, _, y) { return x+y.formatted() } }@@ -895,19 +895,19 @@ } unittest sameType {- \ Testing.checkEquals(Value<Int>.sameType(),"Value<Int>")+ \ Testing.checkEquals(Value<Int>.sameType(), "Value<Int>") } unittest sameValue {- \ Testing.checkEquals(Value<Int>.create().sameValue(),"Value<Int>")+ \ Testing.checkEquals(Value<Int>.create().sameValue(), "Value<Int>") } unittest diffType {- \ Testing.checkEquals(Value<Int>.diffType<String>(),"Value<String>")+ \ Testing.checkEquals(Value<Int>.diffType<String>(), "Value<String>") } unittest diffValue {- \ Testing.checkEquals(Value<Int>.create().diffValue<String>(),"Value<String>")+ \ Testing.checkEquals(Value<Int>.create().diffValue<String>(), "Value<String>") } concrete Value<#x> {@@ -942,5 +942,99 @@ diffValue () { return Value<#y>.call()+ }+}+++testcase "cannot use @category function as @type function" {+ error+ require "something"+ require "category"+}++concrete Test { }++define Test {+ @category something () -> ()+ something () { }++ @category test () -> ()+ test () {+ \ Test.something()+ }+}+++testcase "cannot use @category function as @value function" {+ error+ require "something"+ require "category"+}++concrete Test { }++define Test {+ @category something () -> ()+ something () { }++ @category test () -> ()+ test () {+ \ Test{ }.something()+ }+}+++testcase "cannot use @type function as @value function" {+ error+ require "something"+ require "value"+}++concrete Test { }++define Test {+ @type something () -> ()+ something () { }++ @category test () -> ()+ test () {+ \ Test{ }.something()+ }+}+++testcase "cannot use @value function as @type function" {+ error+ require "something"+ require "type"+}++concrete Test { }++define Test {+ @value something () -> ()+ something () { }++ @category test () -> ()+ test () {+ \ Test.something()+ }+}+++testcase "cannot implicitly use @value function as @type function" {+ error+ require "something"+}++concrete Test { }++define Test {+ @value something () -> ()+ something () { }++ @type test () -> ()+ test () {+ \ something() } }
tests/function-merging.0rt view
@@ -50,7 +50,7 @@ require "Interface2" } -@value interface Interface {}+@value interface Interface { } @value interface Interface2 { refines Interface@@ -108,7 +108,7 @@ require "Interface2" } -@value interface Interface {}+@value interface Interface { } @value interface Interface2 { refines Interface@@ -144,14 +144,14 @@ call (String) -> () } -concrete Type {}+concrete Type { } define Type { refines Base0 refines Base1 @value call (Formatted) -> ()- call (_) {}+ call (_) { } } @@ -175,7 +175,7 @@ refines Base1 @value call (Formatted) -> ()- call (_) {}+ call (_) { } } @@ -200,7 +200,7 @@ define Type { @value call (any) -> ()- call (_) {}+ call (_) { } } @@ -224,7 +224,7 @@ refines Base0 refines Base1 - call (_) {}+ call (_) { } } @@ -252,7 +252,7 @@ define Type { @value call (Formatted) -> ()- call (_) {}+ call (_) { } } @@ -280,7 +280,7 @@ refines Base0 refines Base1 - call (_) {}+ call (_) { } } @@ -316,7 +316,7 @@ refines Base3 @value call (any) -> ()- call (_) {}+ call (_) { } } @@ -356,5 +356,5 @@ refines Base2 refines Base3 - call (_) {}+ call (_) { } }
+ tests/function-visibility.0rt view
@@ -0,0 +1,419 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "visibility bad types" {+ error+ require "visibility"+ require "#x"+ require "Foo"+}++concrete Test {+ visibility Append<#x>, Foo+}++define Test { }+++testcase "visibility filters not checked" {+ compiles+}++concrete Test<#x> {+ #x requires Order<#x>++ visibility Test<Int>+}++define Test { }+++testcase "visibility disallows contravariant" {+ error+ require "visibility"+ require "#x"+ require "covariant"+}++concrete Test<#x|> {+ visibility #x+}++define Test { }+++testcase "visibility allows covariant" {+ compiles+}++concrete Test<|#x> {+ visibility #x+}++define Test { }+++testcase "visibility allowed types" {+ compiles+}++concrete Test<#x> {+ visibility [Int | Char], #self+ visibility _+ visibility #x, Test<#x>+}++define Test { }+++testcase "restricted visibility not allowed for @category" {+ error+ require "visibility"+ require "foo"+}++concrete Test {+ visibility all++ @category foo () -> ()+}++define Test {+ foo () { }+}+++testcase "restricted visibility not allowed for merge" {+ error+ require "visibility"+ require "default"+}++concrete Test {+ defines Default++ visibility all++ @type default () -> (Test)+}++define Test {+ default () { return #self{ } }+}+++testcase "restricted visibility not broken by internal merge" {+ compiles+}++concrete Test {+ visibility all++ @type default () -> (Test)+}++define Test {+ @type default () -> (Test)+ default () {+ return #self{ }+ }+}+++testcase "restricted visibility ignored in own category" {+ compiles+}++concrete Test {+ visibility all++ @type default () -> (Test)+}++define Test {+ default () {+ return #self{ }+ }++ @type foo () -> ()+ foo () {+ \ default()+ }++ @category bar () -> ()+ bar () {+ \ Test.default()+ }+}+++testcase "restricted visibility ignored in unittest" {+ success+}++unittest test {+ \ Test.default()+}++concrete Test {+ visibility all++ @type default () -> (Test)+}++define Test {+ default () {+ return #self{ }+ }+}+++testcase "visibilty checks correct conversion direction" {+ compiles+}++@value interface Base<|#x> { }++concrete Test {+ visibility Base<Formatted>++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ refines Base<String>++ @type test () -> ()+}++define Value {+ test () {+ \ Test.call()+ }+}+++testcase "visibilty checked in @category function" {+ error+ require "visibility"+ require "call"+}++concrete Test {+ visibility Value++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ @category test () -> ()+}++define Value {+ test () {+ \ Test.call()+ }+}+++testcase "visibilty checked in @category member" {+ error+ require "visibility"+ require "call"+}++concrete Test {+ visibility Value++ @type call () -> (Int)+}++define Test {+ call () {+ return 1+ }+}++concrete Value { }++define Value {+ @category Int value <- Test.call()+}+++testcase "visibilty checked in @category function with reset" {+ compiles+}++concrete Test {+ visibility Value+ visibility _++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ @category test () -> ()+}++define Value {+ test () {+ \ Test.call()+ }+}+++testcase "visibility handles #self" {+ error+ require "visibility"+ require "Order<Test>"+}++concrete Test {+ visibility Order<#self>++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ refines Order<Int>+}++define Value {+ next () {+ \ Test.call()+ return empty+ }++ get () {+ return 1+ }+}+++testcase "visibility handles params" {+ error+ require "visibility"+ require "Append<Int>"+}++concrete Test<#x> {+ visibility Append<#x>++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ refines Append<String>+}++define Value {+ append (_) {+ \ Test<Int>.call()+ return self+ }+}+++testcase "visibilty allows any" {+ compiles+}++@value interface Base { }++concrete Test {+ visibility String, Int, Base, Bool++ @type call () -> ()+}++define Test {+ call () { }+}++concrete Value {+ refines Base++ @type test () -> ()+}++define Value {+ test () {+ \ Test.call()+ }+}+++testcase "conversion can change visibility" {+ success+}++unittest test {+ \ Test.test()+}++@value interface Base<|#x> { }++concrete Value<|#x> {+ @type new () -> (#self)++ visibility Base<#x>++ @value call () -> ()+}++define Value {+ new () {+ return #self{ }+ }++ call () { }+}++concrete Test {+ refines Base<Formatted>++ @type test () -> ()+}++define Test {+ test () {+ Value<Int> value <- Value<Int>.new()+ \ value?Value<Formatted>.call()+ }+}
+ tests/identify.0rt view
@@ -0,0 +1,275 @@+/* -----------------------------------------------------------------------------+Copyright 2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "identifier comparisons" {+ success+}++unittest boxed {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$++ \ Testing.checkTrue((id1 < id2) ^ (id2 < id1))+ \ Testing.checkTrue((id1 > id2) ^ (id2 > id1))+ \ Testing.checkTrue((id1 <= id2) ^ (id2 <= id1))+ \ Testing.checkTrue((id1 >= id2) ^ (id2 >= id1))++ \ Testing.checkTrue(id1 <= id1)+ \ Testing.checkTrue(id1 >= id1)+ \ Testing.checkTrue(id1 == id1)++ \ Testing.checkFalse(id1 == id2)+ \ Testing.checkTrue(id1 != id2)+}++unittest unboxed {+ Int value1 <- 1+ Int value2 <- 2+ Int value3 <- 1+ Identifier<Int> id1 <- identify(value1)+ Identifier<Int> id2 <- identify(value2)+ Identifier<Int> id3 <- identify(value3)+ $Hidden[value1, value2, value3]$++ \ Testing.checkTrue((id1 < id2) ^ (id2 < id1))+ \ Testing.checkTrue((id1 > id2) ^ (id2 > id1))+ \ Testing.checkTrue((id1 <= id2) ^ (id2 <= id1))+ \ Testing.checkTrue((id1 >= id2) ^ (id2 >= id1))++ \ Testing.checkTrue(id1 <= id1)+ \ Testing.checkTrue(id1 >= id1)+ \ Testing.checkTrue(id1 == id1)++ \ Testing.checkFalse(id1 == id2)+ \ Testing.checkTrue(id1 != id2)++ \ Testing.checkTrue(id1 == id3)+}++unittest differentTypes {+ String value1 <- "value"+ Int value2 <- 2+ Identifier<String> id1 <- identify(value1)+ Identifier<Int> id2 <- identify(value2)+ $Hidden[value1, value2]$++ \ Testing.checkTrue((id1 < id2) ^ (id2 < id1))+ \ Testing.checkTrue((id1 > id2) ^ (id2 > id1))+ \ Testing.checkTrue((id1 <= id2) ^ (id2 <= id1))+ \ Testing.checkTrue((id1 >= id2) ^ (id2 >= id1))++ \ Testing.checkFalse(id1 == id2)+ \ Testing.checkTrue(id1 != id2)+}++unittest hashing {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$++ \ Testing.checkEquals(id1.hashed(), id1.hashed())+ \ Testing.checkNotEquals(id1.hashed(), id2.hashed())+}++unittest meta {+ String value1 <- "value"+ Int value2 <- 2+ Identifier<String> id1 <- identify(value1)+ Identifier<Int> id2 <- identify(value2)+ $Hidden[value1, value2]$++ \ Testing.checkTrue(id1 == `identify` id1)+ \ Testing.checkTrue(id2 == `identify` id2)+ \ Testing.checkFalse(`identify` id1 == `identify` id2)+}++unittest formatted {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$++ \ Testing.checkEquals(id1.formatted(), id1.formatted())+ \ Testing.checkNotEquals(id1.formatted(), id2.formatted())++ \ Testing.checkEquals((`identify` empty).formatted(), "0000000000000000")+}++unittest equals {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$++ \ Testing.checkTrue(id1 `Identifier<any>.equals` id1)+ \ Testing.checkFalse(id1 `Identifier<any>.equals` id2)+}++unittest lessThan {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$++ \ Testing.checkFalse(id1 `Identifier<any>.lessThan` id1)+ \ Testing.checkTrue((id1 `Identifier<any>.lessThan` id2) ^ (id2 `Identifier<any>.lessThan` id1))+}++unittest swap {+ String value1 <- "value"+ String value2 <- "value"+ Identifier<String> id1 <- `identify` value1+ Identifier<String> id2 <- `identify` value2+ $Hidden[value1, value2]$+ Identifier<String> id3 <- id1++ \ Testing.checkTrue(id1 == id3)+ \ Testing.checkFalse(id2 == id3)+ id1 <-> id2+ \ Testing.checkFalse(id1 == id3)+ \ Testing.checkTrue(id2 == id3)+}++unittest reduceTest {+ Identifier<String> id <- `identify` "value"+ \ Testing.checkEquals<Identifier<any>>(reduce<Identifier<String>, Identifier<Formatted>>(id), id)+ \ Testing.checkEquals<Identifier<any>>(reduce<Identifier<String>, Identifier<Int>>(id), empty)+ \ Testing.checkEquals<Identifier<any>>(reduce<Identifier<Formatted>, Identifier<String>>(id), empty)+}+++testcase "bad identifier conversion" {+ error+ require "Identifier<String>"+}++unittest test {+ Identifier<Int> value <- identify("value")+}+++testcase "identifier variable storage" {+ success+}++unittest test {+ \ Test.new().run()+}++concrete Test {+ @type new () -> (Test)+ @value run () -> ()+}++define Test {+ @value Identifier<String> valueId+ @value optional Identifier<String> optionalValueId+ @value weak Identifier<String> weakValueId++ @category Identifier<String> categoryId <- `identify` "value"+ @category optional Identifier<String> optionalCategoryId <- categoryId+ @category weak Identifier<String> weakCategoryId <- categoryId++ new () {+ Identifier<String> valueId <- `identify` "value"+ return Test{ valueId, valueId, valueId }+ }++ run () {+ // @value vs. local+ scoped {+ Identifier<String> localId <- valueId+ optional Identifier<String> optionalLocalId <- optionalValueId+ weak Identifier<String> weakLocalId <- weakValueId+ } in {+ \ Testing.checkEquals<Identifier<any>>(localId, valueId)+ \ Testing.checkEquals<Identifier<any>>(optionalLocalId, optionalValueId)+ \ Testing.checkEquals<Identifier<any>>(`strong` weakLocalId, `strong` weakLocalId)+ }+ // @category vs. local+ scoped {+ Identifier<String> localId <- categoryId+ optional Identifier<String> optionalLocalId <- optionalCategoryId+ weak Identifier<String> weakLocalId <- weakCategoryId+ } in {+ \ Testing.checkEquals<Identifier<any>>(localId, categoryId)+ \ Testing.checkEquals<Identifier<any>>(optionalLocalId, optionalCategoryId)+ \ Testing.checkEquals<Identifier<any>>(`strong` weakLocalId, `strong` weakLocalId)+ }+ }+}+++testcase "disallow identify on weak" {+ error+ require "[Ww]eak"+}++unittest test {+ weak String value <- empty+ \ identify(value)+}+++testcase "disallow identify with params" {+ error+ require "param"+}++unittest test {+ \ identify<Formatted>("value")+}+++testcase "too many args to identify" {+ error+ require "arg"+}++unittest test {+ \ identify("value", 123)+}+++testcase "too many returns passed to to identify" {+ error+ require "return"+ require "arg"+}++unittest test {+ \ identify(Helper.foo())+}++concrete Helper {+ @type foo () -> (Int, Int)+}++define Helper {+ foo () {+ return 1, 2+ }+}
tests/immutable.0rt view
@@ -168,7 +168,7 @@ require "value2" } -@value interface Foo {}+@value interface Foo { } concrete Test { immutable@@ -204,16 +204,16 @@ require "value" } -@value interface Foo {}+@value interface Foo { } -@value interface Bar {}+@value interface Bar { } concrete Test { immutable } define Test {- @value [Foo&Bar] value+ @value [Foo & Bar] value } @@ -221,7 +221,7 @@ compiles } -@value interface Foo {}+@value interface Foo { } @value interface Bar { immutable@@ -232,7 +232,7 @@ } define Test {- @value [Foo&Bar] value+ @value [Foo & Bar] value } @@ -242,7 +242,7 @@ require "value" } -@value interface Foo {}+@value interface Foo { } @value interface Bar { immutable@@ -253,7 +253,7 @@ } define Test {- @value [Foo|Bar] value+ @value [Foo | Bar] value } @@ -274,7 +274,7 @@ } define Test {- @value [Foo|Bar] value+ @value [Foo | Bar] value } @@ -373,7 +373,7 @@ require "Foo" } -@value interface Foo {}+@value interface Foo { } concrete Test<#x> { #x immutable@@ -421,7 +421,7 @@ require "Foo" } -@value interface Foo {}+@value interface Foo { } concrete Test { @type call<#x>@@ -474,9 +474,9 @@ immutable } -@value interface Foo {}+@value interface Foo { } -concrete Test {}+concrete Test { } define Test { refines Base@@ -497,9 +497,9 @@ immutable } -@value interface Foo {}+@value interface Foo { } -concrete Test {}+concrete Test { } define Test { defines Base
tests/inference.0rt view
@@ -21,23 +21,23 @@ } unittest test {- Int value1, String value2 <- Test.get<?,?>(10,"message")- \ Testing.checkEquals<?>(value1,10)- \ Testing.checkEquals<?>(value2,"message")+ Int value1, String value2 <- Test.get<?, ?>(10, "message")+ \ Testing.checkEquals<?>(value1, 10)+ \ Testing.checkEquals<?>(value2, "message") } unittest testImplicit {- Int value1, String value2 <- Test.get(10,"message")- \ Testing.checkEquals<?>(value1,10)- \ Testing.checkEquals<?>(value2,"message")+ Int value1, String value2 <- Test.get(10, "message")+ \ Testing.checkEquals<?>(value1, 10)+ \ Testing.checkEquals<?>(value2, "message") } concrete Test {- @type get<#x,#y> (#x,#y) -> (#x,#y)+ @type get<#x, #y> (#x, #y) -> (#x, #y) } define Test {- get (x,y) {+ get (x, y) { return x, y } }@@ -50,15 +50,15 @@ } unittest test {- Int value1, String value2 <- Test.get<?>(10,"message")+ Int value1, String value2 <- Test.get<?>(10, "message") } concrete Test {- @type get<#x,#y> (#x,#y) -> (#x,#y)+ @type get<#x, #y> (#x, #y) -> (#x, #y) } define Test {- get (x,y) {+ get (x, y) { return x, y } }@@ -192,7 +192,7 @@ } unittest test {- Type<Int> value <- Test.get<?>(Type<Int>.create(),"bad")+ Type<Int> value <- Test.get<?>(Type<Int>.create(), "bad") } concrete Type<#x> {@@ -206,11 +206,11 @@ } concrete Test {- @type get<#x> (Type<#x>,#x) -> (Type<#x>)+ @type get<#x> (Type<#x>, #x) -> (Type<#x>) } define Test {- get (x,_) {+ get (x, _) { return x } }@@ -256,7 +256,7 @@ } unittest test {- \ Test.get<Formatted,?>(Type<String>.new())+ \ Test.get<Formatted, ?>(Type<String>.new()) } concrete Type<#x> {@@ -268,7 +268,7 @@ } concrete Test {- @type get<#y,#x>+ @type get<#y, #x> #x allows #y (Type<#x>) -> (Type<#x>) }@@ -348,7 +348,7 @@ unittest test { Type<String> x <- Type<String>.create() Type<String> y <- Type<String>.create()- \ Test.get<?,?>(x,y)+ \ Test.get<?, ?>(x, y) } concrete Type<#x> {@@ -362,14 +362,14 @@ } concrete Test {- @type get<#x,#y>+ @type get<#x, #y> #x defines LessThan<#y> #y defines LessThan<#x>- (Type<#x>,Type<#y>) -> ()+ (Type<#x>, Type<#y>) -> () } define Test {- get (_,_) {}+ get (_, _) { } } @@ -379,13 +379,13 @@ unittest test { Type z <- Type.create()- \ Test.get<?,?,?>(z,1,"message")+ \ Test.get<?, ?, ?>(z, 1, "message") } -@type interface Base<#x,#y> {}+@type interface Base<#x, #y> { } concrete Type {- defines Base<Int,String>+ defines Base<Int, String> @type create () -> (Type) } @@ -396,13 +396,13 @@ } concrete Test {- @type get<#z,#x,#y>- #z defines Base<#x,#y>- (#z,#x,#y) -> ()+ @type get<#z, #x, #y>+ #z defines Base<#x, #y>+ (#z, #x, #y) -> () } define Test {- get (_,_,_) {}+ get (_, _, _) { } } @@ -411,7 +411,7 @@ } concrete Test {- @type call<#x,#y> (Convert<#x,#y>) -> (#x,#y)+ @type call<#x, #y> (Convert<#x, #y>) -> (#x, #y) } define Test {@@ -421,8 +421,8 @@ @value run () -> () run () {- any x1, all y1 <- call<?,?>(Convert<any,all>.create())- all x2, any y2 <- call<?,?>(Convert<all,any>.create())+ any x1, all y1 <- call<?, ?>(Convert<any, all>.create())+ all x2, any y2 <- call<?, ?>(Convert<all, any>.create()) } } @@ -438,7 +438,7 @@ testcase "dependent implicit param inferred from requires" {- crash+ failure require "m e s s a g e" } @@ -452,16 +452,16 @@ define Type { run () {- \ call<?,?>("message")- \ call<String,?>("message")+ \ call<?, ?>("message")+ \ call<String, ?>("message") } - @type call<#x,#c>+ @type call<#x, #c> #c requires Formatted #x requires DefaultOrder<#c> (#x) -> () call (value) {- [Append<Formatted>&Build<String>] builder <- String.builder()+ [Append<Formatted> & Build<String>] builder <- String.builder() traverse (value.defaultOrder() -> #c char) { \ builder.append(char).append(" ") }@@ -471,7 +471,7 @@ testcase "dependent implicit param inferred from defines" {- crash+ failure require "String" } @@ -485,11 +485,11 @@ define Type { run () {- \ call<?,?>("message")- \ call<String,?>("message")+ \ call<?, ?>("message")+ \ call<String, ?>("message") } - @type call<#x,#c>+ @type call<#x, #c> #x defines LessThan<#c> (#x) -> () call (value) {@@ -499,7 +499,7 @@ testcase "dependent implicit param inferred from allows" {- crash+ failure require "String" } @@ -513,11 +513,11 @@ define Type { run () {- \ call<?,?>("message")- \ call<String,?>("message")+ \ call<?, ?>("message")+ \ call<String, ?>("message") } - @type call<#x,#c>+ @type call<#x, #c> #x allows #c (#x) -> () call (value) {@@ -527,7 +527,7 @@ testcase "dependent implicit param inferred from reverse allows" {- crash+ failure require "String" } @@ -541,11 +541,11 @@ define Type { run () {- \ call<?,?>("message")- \ call<String,?>("message")+ \ call<?, ?>("message")+ \ call<String, ?>("message") } - @type call<#x,#c>+ @type call<#x, #c> #c allows #x (#x) -> () call (value) {@@ -555,7 +555,7 @@ testcase "dependent implicit param inferred from reverse requires" {- crash+ failure require "String" } @@ -569,11 +569,11 @@ define Type { run () {- \ call<?,?>("message")- \ call<String,?>("message")+ \ call<?, ?>("message")+ \ call<String, ?>("message") } - @type call<#x,#c>+ @type call<#x, #c> #c requires #x (#x) -> () call (value) {@@ -608,7 +608,7 @@ testcase "filter guess merged with arg guess" {- crash+ failure require "String" exclude "Formatted" }@@ -642,9 +642,9 @@ \ Test.call<?>(Type.create()) } -@value interface Base1<|#x> {}+@value interface Base1<|#x> { } -@value interface Base2<|#x> {}+@value interface Base2<|#x> { } concrete Type { refines Base1<Int>@@ -660,7 +660,7 @@ } concrete Test {- @type call<#x> ([Base1<#x>|Base2<#x>]) -> ()+ @type call<#x> ([Base1<#x> | Base2<#x>]) -> () } define Test {@@ -678,9 +678,9 @@ \ Test.call<?>(Type.create()) } -@value interface Base1<#x> {}+@value interface Base1<#x> { } -@value interface Base2<#x> {}+@value interface Base2<#x> { } concrete Type { refines Base1<Int>@@ -696,7 +696,7 @@ } concrete Test {- @type call<#x> ([Base1<#x>&Base2<#x>]) -> ()+ @type call<#x> ([Base1<#x> & Base2<#x>]) -> () } define Test {@@ -705,7 +705,7 @@ testcase "variance allows guesses to be merged using meta type" {- crash+ failure require "\[Int\|String\]" } @@ -713,9 +713,9 @@ \ Test.call<?>(Type.create()) } -@value interface Base1<|#x> {}+@value interface Base1<|#x> { } -@value interface Base2<|#x> {}+@value interface Base2<|#x> { } concrete Type { refines Base1<Int>@@ -731,7 +731,7 @@ } concrete Test {- @type call<#x> ([Base1<#x>&Base2<#x>]) -> ()+ @type call<#x> ([Base1<#x> & Base2<#x>]) -> () } define Test {@@ -742,7 +742,7 @@ testcase "alternative guess eliminated by filter" {- crash+ failure require "Int" } @@ -750,9 +750,9 @@ \ Test.call<?>(Type.create()) } -@value interface Base1<|#x> {}+@value interface Base1<|#x> { } -@value interface Base2<|#x> {}+@value interface Base2<|#x> { } concrete Type { refines Base1<Int>@@ -770,7 +770,7 @@ concrete Test { @type call<#x> #x requires AsChar- ([Base1<#x>|Base2<#x>]) -> ()+ ([Base1<#x> | Base2<#x>]) -> () } define Test {
tests/infix-functions.0rt view
@@ -28,11 +28,11 @@ } concrete Test {- @category add (Int,Int) -> (Int)+ @category add (Int, Int) -> (Int) } define Test {- add (x,y) {+ add (x, y) { return x + y } }@@ -50,11 +50,11 @@ } concrete Test {- @type add (Int,Int) -> (Int)+ @type add (Int, Int) -> (Int) } define Test {- add (x,y) {+ add (x, y) { return x + y } }@@ -73,7 +73,7 @@ concrete Arithmetic { @type create () -> (Arithmetic)- @value add (Int,Int) -> (Int)+ @value add (Int, Int) -> (Int) } define Arithmetic {@@ -81,7 +81,7 @@ return Arithmetic{ } } - add (x,y) {+ add (x, y) { return x + y } }@@ -96,8 +96,8 @@ } define Test {- @type add (Int,Int) -> (Int)- add (x,y) {+ @type add (Int, Int) -> (Int)+ add (x, y) { return x + y } @@ -126,11 +126,11 @@ } concrete Test {- @category add (Int,Int) -> (Int)+ @category add (Int, Int) -> (Int) } define Test {- add (x,y) {+ add (x, y) { return x + y } }@@ -148,11 +148,11 @@ } concrete Test {- @category add (Int,Int) -> (Int)+ @category add (Int, Int) -> (Int) } define Test {- add (x,y) {+ add (x, y) { return x + y } }@@ -172,20 +172,20 @@ define Test { check () {- \ Testing.checkEquals(1 `one` 2 `two` 4,5)+ \ Testing.checkEquals(1 `one` 2 `two` 4, 5) } - @type one (Int,Int) -> (Int)- one (x,y) {- \ Testing.checkEquals(x,1)- \ Testing.checkEquals(y,2)+ @type one (Int, Int) -> (Int)+ one (x, y) {+ \ Testing.checkEquals(x, 1)+ \ Testing.checkEquals(y, 2) return 3 } - @type two (Int,Int) -> (Int)- two (x,y) {- \ Testing.checkEquals(x,3)- \ Testing.checkEquals(y,4)+ @type two (Int, Int) -> (Int)+ two (x, y) {+ \ Testing.checkEquals(x, 3)+ \ Testing.checkEquals(y, 4) return 5 } }
tests/infix-operations.0rt view
@@ -21,55 +21,55 @@ } unittest plus {- \ Testing.checkEquals(8 + 2,10)+ \ Testing.checkEquals(8 + 2, 10) } unittest minus {- \ Testing.checkEquals(8 - 2,6)+ \ Testing.checkEquals(8 - 2, 6) } unittest times {- \ Testing.checkEquals(8 * 2,16)+ \ Testing.checkEquals(8 * 2, 16) } unittest divide {- \ Testing.checkEquals(8 / 2,4)+ \ Testing.checkEquals(8 / 2, 4) } unittest modulo {- \ Testing.checkEquals(8 % 2,0)+ \ Testing.checkEquals(8 % 2, 0) } unittest left {- \ Testing.checkEquals(1 << 2,4)+ \ Testing.checkEquals(1 << 2, 4) } unittest right {- \ Testing.checkEquals(7 >> 1,3)+ \ Testing.checkEquals(7 >> 1, 3) } unittest xor {- \ Testing.checkEquals(7 ^ 2 ,5)+ \ Testing.checkEquals(7 ^ 2 , 5) } unittest and {- \ Testing.checkEquals(7 & ~2,5)+ \ Testing.checkEquals(7 & ~2, 5) } unittest or {- \ Testing.checkEquals(5 | 2 ,7)+ \ Testing.checkEquals(5 | 2 , 7) } unittest arithmetic {- \ Testing.checkEquals(\x10 + 1 * 2 - 8 / 2 - 3 % 2,13)+ \ Testing.checkEquals(\x10 + 1 * 2 - 8 / 2 - 3 % 2, 13) } unittest bitwise {- \ Testing.checkEquals(1 << 4 | 7 >> 1 & ~2,17)+ \ Testing.checkEquals(1 << 4 | 7 >> 1 & ~2, 17) } unittest sameOperator {- \ Testing.checkEquals(2 - 1 - 1,0)+ \ Testing.checkEquals(2 - 1 - 1, 0) } unittest lessThan {@@ -136,14 +136,14 @@ unittest rightAssociative { Int x <- 2 Bool y <- true && (x <- 3) == 2 || x == 3- \ Testing.checkEquals(x,3)+ \ Testing.checkEquals(x, 3) \ Testing.checkTrue(y) } unittest shortCircuit { Int x <- 2 Bool y <- true || (x <- 3) == 2 || x == 3- \ Testing.checkEquals(x,2)+ \ Testing.checkEquals(x, 2) \ Testing.checkTrue(y) } @@ -153,7 +153,7 @@ } unittest precedence {- \ Testing.checkEquals(16.0 + 1.0 * 2.0 - 8.0 / 2.0 - 3.0 / 3.0,13.0)+ \ Testing.checkEquals(16.0 + 1.0 * 2.0 - 8.0 / 2.0 - 3.0 / 3.0, 13.0) } unittest lessThan {@@ -190,7 +190,7 @@ } unittest add {- \ Testing.checkEquals("x" + "y" + "z","xyz")+ \ Testing.checkEquals("x" + "y" + "z", "xyz") } unittest lessThan {@@ -227,7 +227,7 @@ } unittest minus {- \ Testing.checkEquals('z' - 'a',25)+ \ Testing.checkEquals('z' - 'a', 25) } unittest lessThan {
tests/internal-inheritance.0rt view
@@ -96,9 +96,9 @@ success } -unittest test {}+unittest test { } -concrete Value {}+concrete Value { } define Value { refines Formatted@@ -108,7 +108,7 @@ return "Value" } - equals (_,_) {+ equals (_, _) { return true } }@@ -121,7 +121,7 @@ unittest test { Value value1 <- Value.create(1) Value value2 <- Value.create(2)- if (Value.compare(value1,value2)) {+ if (Value.compare(value1, value2)) { fail("Failed") } }@@ -129,18 +129,18 @@ concrete Compare<#x> { #x defines Equals<#x> - @type compare (#x,#x) -> (Bool)+ @type compare (#x, #x) -> (Bool) } define Compare {- compare (x,y) {- return #x.equals(x,y)+ compare (x, y) {+ return #x.equals(x, y) } } concrete Value { @type create (Int) -> (Value)- @type compare (Value,Value) -> (Bool)+ @type compare (Value, Value) -> (Bool) } define Value {@@ -148,7 +148,7 @@ @value Int value - equals (x,y) {+ equals (x, y) { return x.get() == y.get() } @@ -156,8 +156,8 @@ return Value{ x } } - compare (x,y) {- return Compare<Value>.compare(x,y)+ compare (x, y) {+ return Compare<Value>.compare(x, y) } @value get () -> (Int)@@ -177,18 +177,18 @@ unittest test { Value value1 <- Value.create(1) Value value2 <- Value.create(2)- \ Compare<Value>.compare(value1,value2)+ \ Compare<Value>.compare(value1, value2) } concrete Compare<#x> { #x defines Equals<#x> - @type compare (#x,#x) -> (Bool)+ @type compare (#x, #x) -> (Bool) } define Compare {- compare (x,y) {- return #x.equals(x,y)+ compare (x, y) {+ return #x.equals(x, y) } } @@ -201,7 +201,7 @@ @value Int value - equals (x,y) {+ equals (x, y) { return x.get() == y.get() } @@ -222,9 +222,9 @@ require "type interface" } -@value interface Base {}+@value interface Base { } -concrete Type {}+concrete Type { } define Type { defines Base@@ -241,7 +241,7 @@ call (#x) -> () } -concrete Type<|#x> {}+concrete Type<|#x> { } define Type { refines Base<#x>@@ -258,7 +258,7 @@ call (#x) -> () } -concrete Type<|#x> {}+concrete Type<|#x> { } define Type { defines Base<#x>@@ -269,7 +269,7 @@ compiles } -@value interface Base1<#x> {}+@value interface Base1<#x> { } @value interface Base2<#x> { refines Base1<#x>
tests/leak-check/.zeolite-module view
@@ -12,6 +12,6 @@ "lib/util" ] mode: binary {- category: LeakTest+ category: LeakCheck function: run }
tests/leak-check/README.md view
@@ -17,7 +17,7 @@ ```shell # The "leak" argument is important.-valgrind --leak-check=yes $ZEOLITE_PATH/tests/leak-check/LeakTest leak+valgrind --leak-check=yes $ZEOLITE_PATH/tests/leak-check/LeakCheck leak ``` You should get output that looks something like this:@@ -26,7 +26,7 @@ ==8487== Memcheck, a memory error detector ==8487== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==8487== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info-==8487== Command: tests/leak-check/LeakTest leak+==8487== Command: tests/leak-check/LeakCheck leak ==8487== ==8487== ==8487== HEAP SUMMARY:@@ -58,7 +58,7 @@ ```shell # The "race" argument is important.-$ZEOLITE_PATH/tests/leak-check/LeakTest race+$ZEOLITE_PATH/tests/leak-check/LeakCheck race ``` *Do not use `valgrind` to run in `race` mode!* The latency introduced by@@ -70,10 +70,10 @@ --- -A more comprehensive test involves leaving `LeakTest` running for an hour or so.+A more comprehensive test involves leaving `LeakCheck` running indefinitely. ```shell-$ZEOLITE_PATH/tests/leak-check/LeakTest forever+$ZEOLITE_PATH/tests/leak-check/LeakCheck forever ``` This will cause `LeakCheck` to run for a very long time, while attempting to
tests/leak-check/leak-check.0rx view
@@ -1,20 +1,38 @@-concrete LeakTest {+/* -----------------------------------------------------------------------------+Copyright 2021-2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++concrete LeakCheck { @type run () -> () } -define LeakTest {+define LeakCheck { @value Vector<Int> memory run () { if (Argv.global().size() != 2) { \ message() } elif (Argv.global().readAt(1) == "race") {- \ runWith(1000,0)+ \ runWith(1000, 0) \ BasicOutput.stderr().writeNow("no race conditions this time\n") } elif (Argv.global().readAt(1) == "leak") {- \ runWith(100,0)+ \ runWith(100, 0) } elif (Argv.global().readAt(1) == "forever") {- \ runWith(10000000,1024*1024)+ \ runWith(10000000, 1024*1024) } else { \ message() }@@ -22,23 +40,23 @@ @type message () -> () message () {- fail(Argv.global().readAt(0) + " [race|leak|forever]")+ fail(Argv.global().readAt(0) + " [race | leak | forever]") } - @type runWith (Int,Int) -> ()- runWith (iterations,size) {- Int threads <- Ranges:max(3,$ExprLookup[CPU_CORE_COUNT]$-1)+ @type runWith (Int, Int) -> ()+ runWith (iterations, size) {+ Int threads <- Ranges:max(3, $ExprLookup[CPU_CORE_COUNT]$-1) ReadAt<BarrierWait> barriers <- EnumeratedBarrier.new(threads+1) traverse (Counter.zeroIndexed(iterations) -> Int i) {- \ doIteration<LastReference>(i,size,barriers)- \ doIteration<Chaos>(i,size,barriers)+ \ doIteration<LastReference>(i, size, barriers)+ \ doIteration<Chaos>(i, size, barriers) } } @type doIteration<#f> #f defines ThreadFactory- (Int,Int,ReadAt<BarrierWait>) -> ()- doIteration (i,size,barriers) {+ (Int, Int, ReadAt<BarrierWait>) -> ()+ doIteration (i, size, barriers) { \ BasicOutput.stderr() .write(typename<#f>()) .write(": iteration ")@@ -46,15 +64,15 @@ .write("\n") .flush() - optional LeakTest original <- LeakTest{ Vector:createSize<Int>(size) }- weak LeakTest checkedValue <- original+ optional LeakCheck original <- LeakCheck{ Vector:createSize<Int>(size) }+ weak LeakCheck checkedValue <- original $ReadOnly[checkedValue]$ scoped { Vector<Thread> threads <- Vector<Thread>.new() } in { traverse (Counter.zeroIndexed(barriers.size()-1) -> Int j) {- \ threads.push(ProcessThread.from(#f.create(original,barriers.readAt(j+1))).start())+ \ threads.push(ProcessThread.from(#f.create(original, barriers.readAt(j+1))).start()) } \ barriers.readAt(0).wait()@@ -71,7 +89,7 @@ } @type interface ThreadFactory {- create (optional LeakTest,BarrierWait) -> (Routine)+ create (optional LeakCheck, BarrierWait) -> (Routine) } concrete LastReference {@@ -83,10 +101,10 @@ refines Routine - @value weak LeakTest copy+ @value weak LeakCheck copy @value BarrierWait barrier - create (copy,barrier) {+ create (copy, barrier) { return LastReference{ copy, barrier } } @@ -105,23 +123,26 @@ refines Routine - @value weak LeakTest copy+ @value weak LeakCheck copy @value BarrierWait barrier - create (copy,barrier) {+ create (copy, barrier) { return Chaos{ copy, barrier } } run () {- weak LeakTest copy1 <- empty- weak LeakTest copy2 <- empty- weak LeakTest copy3 <- empty- weak LeakTest copy4 <- empty- weak LeakTest copy5 <- empty+ weak LeakCheck copy1 <- empty+ weak LeakCheck copy2 <- empty+ weak LeakCheck copy3 <- empty+ weak LeakCheck copy4 <- empty+ weak LeakCheck copy5 <- empty \ barrier.wait() copy1 <- copy copy2 <- copy1 copy3 <- copy1+ copy3 <-> copy1+ copy1 <-> copy1+ copy2 <-> copy1 copy <- empty copy4 <- strong(copy2) copy1 <- strong(copy3)
tests/local-rules.0rt view
@@ -52,7 +52,7 @@ $ReadOnly[foo]$ } foo <- 2- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) } @@ -82,7 +82,7 @@ $ReadOnly[foo]$ } foo <- 2- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) } @@ -97,9 +97,9 @@ foo <- 2 $ReadOnly[foo]$ }- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) foo <- 3- \ Testing.checkEquals(foo,3)+ \ Testing.checkEquals(foo, 3) } @@ -151,7 +151,7 @@ cleanup { foo <- 2 } in $ReadOnly[foo]$- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) } @@ -181,7 +181,7 @@ $Hidden[foo]$ } foo <- 2- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) } @@ -240,9 +240,9 @@ foo <- 2 $Hidden[foo]$ }- \ Testing.checkEquals(foo,2)+ \ Testing.checkEquals(foo, 2) foo <- 3- \ Testing.checkEquals(foo,3)+ \ Testing.checkEquals(foo, 3) } @@ -264,7 +264,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $ReadOnly[foo]$@@ -286,7 +286,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $Hidden[foo]$@@ -307,7 +307,7 @@ require "foo.+does not exist" } -concrete Type {}+concrete Type { } define Type { $Hidden[foo]$@@ -321,7 +321,7 @@ } unittest test {- \ Testing.checkEquals(Type:get(),2)+ \ Testing.checkEquals(Type:get(), 2) } concrete Type {@@ -347,7 +347,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $ReadOnly[foo]$@@ -369,7 +369,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $Hidden[foo]$@@ -390,7 +390,7 @@ require "foo.+does not exist" } -concrete Type {}+concrete Type { } define Type { $Hidden[foo]$@@ -404,7 +404,7 @@ } unittest test {- \ Testing.checkEquals(Type.create().get(),1)+ \ Testing.checkEquals(Type.create().get(), 1) } concrete Type {@@ -434,7 +434,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $ReadOnlyExcept[bar]$@@ -456,7 +456,7 @@ exclude "bar" } -concrete Type {}+concrete Type { } define Type { $ReadOnlyExcept[bar]$@@ -477,7 +477,7 @@ require "foo.+read-only" } -concrete Type {}+concrete Type { } define Type { $ReadOnlyExcept[foo]$@@ -497,7 +497,7 @@ require compiler "ReadOnlyExcept" } -concrete Type {}+concrete Type { } define Type { $ReadOnlyExcept[foo]$@@ -519,7 +519,7 @@ require "foo.+does not exist" } -concrete Type {}+concrete Type { } define Type { $ReadOnlyExcept[foo]$
tests/local.0rp view
@@ -18,4 +18,4 @@ $ModuleOnly$ -@value interface ModuleOnly {}+@value interface ModuleOnly { }
tests/member-init.0rt view
@@ -25,7 +25,7 @@ @type Bool value <- false } -concrete Test {}+concrete Test { } testcase "@category member from @type" {@@ -36,7 +36,7 @@ // NOTE: Executing the test ensures that C++ compilation works. } -concrete Test {}+concrete Test { } define Test { @category Bool value <- true@@ -56,7 +56,7 @@ // NOTE: Executing the test ensures that C++ compilation works. } -concrete Test {}+concrete Test { } define Test { @category Bool value <- true@@ -73,7 +73,7 @@ require "get" } -concrete Test {}+concrete Test { } define Test { @category Bool value <- get()@@ -90,7 +90,7 @@ } unittest test {- \ Testing.checkEquals(Test:get(),2)+ \ Testing.checkEquals(Test:get(), 2) } concrete Test {@@ -126,7 +126,7 @@ } } -concrete Test {}+concrete Test { } define Test { @category Bool value <- Util.doNotUse()@@ -134,7 +134,7 @@ testcase "@category member init when read" {- crash+ failure require "do not use" } @@ -166,7 +166,7 @@ testcase "@category member init when assigned" {- crash+ failure require "do not use" } @@ -198,7 +198,7 @@ testcase "@category member init when ignored" {- crash+ failure require "do not use" } @@ -258,8 +258,8 @@ testcase "@category init cycle" {- crash- require "Value1|Value2"+ failure+ require "Value1 | Value2" } unittest test {@@ -296,7 +296,7 @@ require "self" } -concrete Test {}+concrete Test { } define Test { @category Test value <- self@@ -308,7 +308,7 @@ require "disallowed" } -concrete Test {}+concrete Test { } define Test { @category Bool value <- get()@@ -325,7 +325,7 @@ require "value1.+read-only" } -concrete Test {}+concrete Test { } define Test { @category Int value1 <- 1@@ -338,7 +338,7 @@ require "Foo not found" } -concrete Test {}+concrete Test { } define Test { @category optional Foo value <- empty@@ -350,7 +350,7 @@ require "Foo not found" } -concrete Test {}+concrete Test { } define Test { @value Foo value@@ -362,7 +362,7 @@ require "#x not found" } -concrete Test<#x> {}+concrete Test<#x> { } define Test { @category optional #x value <- empty
tests/modified-storage.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -185,7 +185,7 @@ } concrete Test {- @type get () -> (Value,Value)+ @type get () -> (Value, Value) } define Test {@@ -260,7 +260,7 @@ return Test{ } } - call () {}+ call () { } } @@ -271,35 +271,405 @@ unittest boxed { String value <- "message" weak String value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$ } unittest int { Int value <- 1 weak Int value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$ } unittest char { Char value <- 'a' weak Char value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$ } unittest bool { Bool value <- false weak Bool value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$ } unittest float { Float value <- 1.0 weak Float value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$ } unittest emptyVal { optional all value <- empty weak all value2 <- value- $ValidateRefs[value,value2]$+ $ValidateRefs[value, value2]$+}+++testcase "call from empty" {+ error+ require "optional"+}++unittest test {+ \ empty.foo()+}+++testcase "inline assignment to weak" {+ success+}++unittest unboxed {+ weak Int value <- empty+ Int value2 <- (value <- 123)+ \ Testing.checkEquals(value2, 123)+ \ Testing.checkEquals(strong(value), 123)+}++unittest boxedNoRefs {+ weak String value <- empty+ \ Testing.checkEquals((value <- "message"), "message")+ \ Testing.checkEquals(strong(value), empty)+}++unittest boxedRefs {+ weak String value <- empty+ String original <- "message"+ String value2 <- (value <- original)+ \ Testing.checkEquals(value2, original)+ \ Testing.checkEquals(strong(value), original)+}++unittest weakToWeak {+ weak String value <- empty+ String original <- "message"+ weak String value2 <- original+ \ Testing.checkEquals(`strong` (value <- value2), original)+ \ Testing.checkEquals(strong(value), original)+}+++testcase "conditional inline assignment" {+ success+}++concrete Helper {+ @type notCalled () -> (all)+}++define Helper {+ notCalled () {+ fail("should not be called")+ }+}++unittest shortCircuit {+ optional Int value <- 123+ Int value2 <- (value <-| Helper.notCalled())+ \ Testing.checkEquals(value2, 123)+ \ Testing.checkEquals(value, 123)+}++unittest unboxedToUnboxed {+ optional Int value <- empty++ Int value2 <- (value <-| 123)+ \ Testing.checkEquals(value2, 123)+ \ Testing.checkEquals(value, 123)++ Int value3 <- (value <-| 456)+ \ Testing.checkEquals(value3, 123)+ \ Testing.checkEquals(value, 123)+}++unittest boxedToBoxed {+ optional String value <- empty++ String value2 <- (value <-| "message")+ \ Testing.checkEquals(value2, "message")+ \ Testing.checkEquals(value, "message")++ String value3 <- (value <-| "other")+ \ Testing.checkEquals(value3, "message")+ \ Testing.checkEquals(value, "message")+}+++testcase "conditional assignment" {+ success+}++concrete Helper {+ @type notCalled () -> (all)+}++define Helper {+ notCalled () {+ fail("should not be called")+ }+}++unittest shortCircuit {+ optional Int value <- 123+ value <-| Helper.notCalled()+ \ Testing.checkEquals(value, 123)+}++unittest unboxedToUnboxed {+ optional Int value <- empty++ value <-| 123+ \ Testing.checkEquals(value, 123)++ value <-| 456+ \ Testing.checkEquals(value, 123)+}++unittest boxedToBoxed {+ optional String value <- empty++ value <-| "message"+ \ Testing.checkEquals(value, "message")++ value <-| "other"+ \ Testing.checkEquals(value, "message")+}+++testcase "conditional inline assignment wrong return type" {+ error+ require "Formatted"+ require "Int"+}++unittest test {+ optional Formatted value <- empty+ Int value2 <- (value <-| 123)+}+++testcase "conditional inline assignment wrong return storage" {+ error+ require "storage modifier"+}++unittest test {+ optional Int value <- 123+ Int value2 <- (value <-| empty)+}+++testcase "conditional inline assignment deferred" {+ error+ require "initialized"+ require "value"+}++unittest test {+ optional Int value <- defer+ Int value2 <- (value <-| 123)+}+++testcase "conditional inline assignment required" {+ error+ require "optional"+}++unittest test {+ Int value <- 456+ Int value2 <- (value <-| 123)+}+++testcase "conditional inline assignment weak" {+ error+ require "optional"+}++unittest test {+ weak Int value <- 456+ Int value2 <- (value <-| 123)+}+++testcase "conditional assignment wrong return count" {+ error+ require "return"+}++concrete Helper {+ @type get () -> (Int, Int)+}++define Helper {+ get () {+ return 1, 2+ }+}++unittest test {+ optional Int value <- 456+ value <-| Helper.get()+}+++testcase "optional value calls" {+ success+}++concrete Helper {+ @type notCalled () -> (all)+}++define Helper {+ notCalled () {+ fail("should not be called")+ }+}++unittest nonEmpty {+ optional Int value <- 123+ \ Testing.checkEquals(value&.formatted(), "123")+}++unittest chainedCalls {+ optional Int value <- 123+ \ Testing.checkEquals(value&.formatted()&.readAt(0), '1')+}++unittest emptyValue {+ optional Int value <- empty+ \ Testing.checkEquals(value&.formatted(), empty)+}++unittest shortCircuit {+ optional String value <- empty+ \ value&.readAt(Helper.notCalled())+}+++testcase "conditional call return types become optional" {+ error+ require "storage modifier"+}++unittest test {+ optional Int value <- empty+ String value2 <- value&.formatted()+}+++testcase "conditional call not allowed for required" {+ error+ require "[Oo]ptional"+}++unittest test {+ \ "123"&.readAt(0)+}+++testcase "conditional call not allowed for weak" {+ error+ require "[Oo]ptional"+}++unittest test {+ weak String value <- empty+ \ value&.readAt(0)+}+++testcase "conditional call with multi returns" {+ success+}++concrete Value {+ @type new () -> (Value)+ @value get () -> (optional Int, Int)+}++define Value {+ new () {+ return Value{ }+ }++ get () {+ return 1, 2+ }+}++unittest chained {+ optional Value value <- Value.new()+ \ Testing.checkEquals(value&.get(){1}&.formatted(), "2")+}++unittest notCalled {+ optional Value value <- empty+ optional Int result1, optional Int result2 <- value&.get()+ \ Testing.checkEmpty(result1)+ \ Testing.checkEmpty(result2)++}+++testcase "conditional call only happens once" {+ success+}++concrete Value {+ @type new () -> (optional Value)+ @value get () -> (Int)+}++define Value {+ @category Bool used <- false++ new () {+ if (used) {+ fail("already called")+ }+ used <- true+ return Value{ }+ }++ get () {+ return 1+ }+}++unittest test {+ \ Testing.checkEquals(Value.new()&.get()&.formatted()&.readAt(0), '1')+}+++testcase "conditional call bad function name" {+ error+ require "foo"+}++unittest test {+ optional String value <- empty+ \ value&.foo()+}+++testcase "conditional call from empty" {+ error+ require "formatted"+ require "all"+}++unittest test {+ \ empty&.formatted()+}+++testcase "conditional call from converted empty" {+ success+}++unittest test {+ \ Testing.checkEmpty(empty?Formatted&.formatted()) }
tests/module-only/.zeolite-module view
@@ -3,4 +3,4 @@ private_deps: [ "internal" ]-mode: incremental {}+mode: incremental { }
tests/module-only/internal/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../../.." path: "tests/module-only/internal"-mode: incremental {}+mode: incremental { }
tests/module-only/internal/private.0rp view
@@ -18,4 +18,4 @@ $ModuleOnly$ -@value interface Type1 {}+@value interface Type1 { }
tests/module-only/internal/public.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -@value interface Type2 {}+@value interface Type2 { }
tests/module-only/private.0rx view
@@ -16,7 +16,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete Test {}+concrete Test { } define Test { @value Type1 val1
tests/module-only2/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "tests/module-only2"-mode: incremental {}+mode: incremental { }
tests/module-only2/private1.0rp view
@@ -18,4 +18,4 @@ $ModuleOnly$ -@value interface Type1 {}+@value interface Type1 { }
tests/module-only3/.zeolite-module view
@@ -7,4 +7,4 @@ "tests/module-only3/source1.cpp" "tests/module-only3/source2.cpp" ]-mode: incremental {}+mode: incremental { }
tests/module-only3/internal/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../../.." path: "tests/module-only3/internal"-mode: incremental {}+mode: incremental { }
tests/module-only3/internal/private.0rp view
@@ -18,4 +18,4 @@ $ModuleOnly$ -@value interface Type1 {}+@value interface Type1 { }
tests/module-only3/internal/public.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -@value interface Type2 {}+@value interface Type2 { }
tests/module-only4/.zeolite-module view
@@ -7,4 +7,4 @@ requires: [Type2] } ]-mode: incremental {}+mode: incremental { }
tests/multiple-returns.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -18,11 +18,11 @@ testcase "multi return to call" { error- require "call.+\{Value,Value\}"+ require "call.+Value.+Value" } @value interface Value {- get () -> (Value,Value)+ get () -> (Value, Value) call () -> () } @@ -33,12 +33,12 @@ } } -concrete Test {}+concrete Test { } testcase "zero return to call" { error- require "call.+\{\}"+ require "call.+none" } @value interface Value {@@ -53,7 +53,7 @@ } } -concrete Test {}+concrete Test { } testcase "multi return assign" {@@ -68,7 +68,7 @@ concrete Test { @type create () -> (Test)- @value double () -> (Test,Test)+ @value double () -> (Test, Test) } define Test {@@ -95,7 +95,7 @@ return 1, 2 } - call (x,y) {+ call (x, y) { if (x != 1) { fail("Failed") }@@ -106,26 +106,58 @@ } concrete Test {- @type get () -> (Int,Int)- @type call (Int,Int) -> ()+ @type get () -> (Int, Int)+ @type call (Int, Int) -> () } +testcase "multi return as args with params" {+ success+}++unittest testExplicit {+ \ Test.call<Int>(Test.get())+}++unittest testInferred {+ \ Test.call(Test.get())+}++define Test {+ get () {+ return 1, 2+ }++ call (x, y) {+ if (!(x `#x.lessThan` y)) {+ fail("Failed")+ }+ }+}++concrete Test {+ @type get () -> (Int, Int)+ @type call<#x>+ #x defines LessThan<#x>+ (#x, #x) -> ()+}++ testcase "return selection" { success } unittest correctPosition {- \ Testing.checkEquals(Test.get(){0},123)- \ Testing.checkEquals(Test.get(){1},"message")+ \ Testing.checkEquals(Test.get(){0}, 123)+ \ Testing.checkEquals(Test.get(){1}, "message") } unittest chainedCall {- \ Testing.checkEquals(Test.get(){0}.formatted(),"123")+ \ Testing.checkEquals(Test.get(){0}.formatted(), "123") } concrete Test {- @type get () -> (Int,String)+ @type get () -> (Int, String) } define Test {@@ -145,7 +177,7 @@ } concrete Test {- @type get () -> (Int,String)+ @type get () -> (Int, String) } define Test {
tests/named-returns.0rt view
@@ -21,13 +21,13 @@ require "value" } -@value interface Value {}+@value interface Value { } -concrete Test {}+concrete Test { } define Test { @value process () -> (Value)- process () (value) {}+ process () (value) { } } @@ -35,7 +35,7 @@ compiles } -concrete Test {}+concrete Test { } define Test { @value process () -> (Bool)@@ -50,7 +50,7 @@ require "value.+initialized" } -concrete Test {}+concrete Test { } define Test { @value process () -> (Bool)@@ -64,7 +64,7 @@ compiles } -concrete Test {}+concrete Test { } define Test { @value process () -> (Int)@@ -78,7 +78,7 @@ compiles } -concrete Test {}+concrete Test { } define Test { @value process () -> (Int)@@ -93,7 +93,7 @@ require "value.+initialized" } -concrete Test {}+concrete Test { } define Test { @category process () -> (Int)@@ -131,7 +131,7 @@ require "value.+initialized" } -concrete Test {}+concrete Test { } define Test { @category process () -> (Int)@@ -145,7 +145,7 @@ compiles } -concrete Test {}+concrete Test { } define Test { @category process () -> (Int)@@ -160,7 +160,7 @@ require "value.+initialized" } -concrete Test {}+concrete Test { } define Test { @category process () -> (Int)@@ -185,7 +185,7 @@ } concrete Test {- @type get () -> (Int,Int)+ @type get () -> (Int, Int) } define Test {@@ -220,11 +220,11 @@ } concrete Test {- @type get () -> (Value,Int,Int)+ @type get () -> (Value, Int, Int) } define Test {- get () (v,x,y) {+ get () (v, x, y) { // This makes sure that x and y (primitive) are offset. v <- Value.create() x <- 1@@ -248,11 +248,11 @@ } concrete Test {- @type get () -> (Int,Int)+ @type get () -> (Int, Int) } define Test {- get () (x,y) {+ get () (x, y) { x <- 1 y <- 2 return _@@ -261,7 +261,7 @@ testcase "positional return sets named return" {- crash+ failure require "message" } @@ -287,11 +287,11 @@ } unittest withScoped {- \ Testing.checkEquals(Test.withScoped(),"message")+ \ Testing.checkEquals(Test.withScoped(), "message") } unittest withCleanup {- \ Testing.checkEquals(Test.withCleanup(),"message")+ \ Testing.checkEquals(Test.withCleanup(), "message") } concrete Test {@@ -313,7 +313,7 @@ testcase "named return not checked in condition that jumps" {- crash+ failure require "success" }
tests/pointer/.zeolite-module view
@@ -1,8 +1,5 @@ root: "../.." path: "tests/pointer"-private_deps: [- "lib/testing"-] extra_files: [ category_source { source: "tests/pointer/Extension_Request.cpp"@@ -18,4 +15,4 @@ } "tests/pointer/call.hpp" ]-mode: incremental {}+mode: incremental { }
tests/pointer/call.0rp view
@@ -45,6 +45,6 @@ } concrete Service {- @type send (Pointer<Request>,Pointer<Response>) -> ()- @type send2 (Pointer<Message>,Pointer<Response>) -> ()+ @type send (Pointer<Request>, Pointer<Response>) -> ()+ @type send2 (Pointer<Message>, Pointer<Response>) -> () }
tests/pointer/call.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2022 Kevin P. Barry+Copyright 2022-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -31,26 +31,34 @@ Response response <- Response.create("") // This is just meant to test code generated for passing Pointer as a // function arg or return.- return Response.getData(callWithPointers(request.asRequest(),response.asResponse()))+ return Response.getData(callWithPointers(request.asRequest(), response.asResponse())) } call2 (data) { Request request <- Request.create(data) Response response <- Response.create("")- \ Service.send2(request.asMessage(),response.asResponse())+ \ Service.send2(request.asMessage(), response.asResponse()) return response.formatted() } - @type callWithPointers (Pointer<Request>,Pointer<Response>) -> (Pointer<Response>)- callWithPointers (request,response) {- \ Service.send(request,response)+ @type callWithPointers (Pointer<Request>, Pointer<Response>) -> (Pointer<Response>)+ callWithPointers (request, response) {+ \ Service.send(request, response) return response } } unittest test {- \ CallHelper.call("DATA") `Testing.checkEquals` "DATA has been processed as Request"- \ CallHelper.call2("DATA") `Testing.checkEquals` "REQUEST has been processed as Message"+ scoped {+ String value <- CallHelper.call("DATA")+ } in if (value != "DATA has been processed as Request") {+ fail(value)+ }+ scoped {+ String value <- CallHelper.call2("DATA")+ } in if (value != "REQUEST has been processed as Message") {+ fail(value)+ } } @@ -75,23 +83,70 @@ } call () {- \ Request.getData(requestPointer) `Testing.checkEquals` "request"- \ Response.getData(responsePointer) `Testing.checkEquals` "response"+ scoped {+ String value <- Request.getData(requestPointer)+ } in if (value != "request") {+ fail(value)+ }+ scoped {+ String value <- Response.getData(responsePointer)+ } in if (value != "response") {+ fail(value)+ } Pointer<Request> localRequest <- requestPointer Pointer<Response> localResponse <- responsePointer- \ Request.getData(localRequest) `Testing.checkEquals` "request"- \ Response.getData(localResponse) `Testing.checkEquals` "response"+ scoped {+ String value <- Request.getData(localRequest)+ } in if (value != "request") {+ fail(value)+ }+ scoped {+ String value <- Response.getData(localResponse)+ } in if (value != "response") {+ fail(value)+ } localRequest <- request.asRequest() localResponse <- response.asResponse()- \ Request.getData(localRequest) `Testing.checkEquals` "request"- \ Response.getData(localResponse) `Testing.checkEquals` "response"+ scoped {+ String value <- Request.getData(localRequest)+ } in if (value != "request") {+ fail(value)+ }+ scoped {+ String value <- Response.getData(localResponse)+ } in if (value != "response") {+ fail(value)+ } requestPointer <- localRequest responsePointer <- localResponse- \ Request.getData(requestPointer) `Testing.checkEquals` "request"- \ Response.getData(responsePointer) `Testing.checkEquals` "response"+ scoped {+ String value <- Request.getData(requestPointer)+ } in if (value != "request") {+ fail(value)+ }+ scoped {+ String value <- Response.getData(responsePointer)+ } in if (value != "response") {+ fail(value)+ }++ // Test swapping.+ Request request2 <- Request.create("request2")+ Pointer<Request> requestPointer2 <- request2.asRequest()+ localRequest <-> requestPointer2+ scoped {+ String value <- Request.getData(localRequest)+ } in if (value != "request2") {+ fail(value)+ }+ scoped {+ String value <- Request.getData(requestPointer2)+ } in if (value != "request") {+ fail(value)+ } } }
tests/positional-returns.0rt view
@@ -21,13 +21,13 @@ require "Value" } -@value interface Value {}+@value interface Value { } -concrete Test {}+concrete Test { } define Test { @value process () -> (Value)- process () {}+ process () { } } @@ -46,11 +46,11 @@ } concrete Test {- @type get () -> (Int,Int)+ @type get () -> (Int, Int) } define Test {- get () (x,y) {+ get () (x, y) { if (false) { x <- 1 } else {@@ -76,11 +76,11 @@ } concrete Test {- @type get () -> (Int,Int)+ @type get () -> (Int, Int) } define Test {- get () (x,y) {+ get () (x, y) { return 1, 2 } }@@ -101,11 +101,11 @@ } concrete Test {- @type get () -> (Int,Int)+ @type get () -> (Int, Int) } define Test {- get () (x,y) {+ get () (x, y) { y <- 2 if (false) { x <- 1
tests/program-exit.0rt view
@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "fail builtin" {- crash+ failure require stderr "Failed" require stderr "failedReturn" }@@ -80,7 +80,7 @@ testcase "exit builtin non-zero" {- crash+ failure // Should not output a stack trace. exclude "exitReturn" }@@ -112,7 +112,7 @@ testcase "require empty" {- crash+ failure require stderr "require.+empty" }
tests/reduce.0rt view
@@ -23,7 +23,7 @@ unittest test { Value value <- Value.create() scoped {- optional Value value2 <- reduce<Value,Value>(value)+ optional Value value2 <- reduce<Value, Value>(value) } in if (!present(value2)) { fail("Failed") }@@ -47,7 +47,7 @@ unittest test { Value value <- Value.create() scoped {- optional String value2 <- reduce<Value,String>(value)+ optional String value2 <- reduce<Value, String>(value) } in if (present(value2)) { fail("Failed") }@@ -73,7 +73,7 @@ unittest test { Value value <- Value.create()- optional Value value2 <- reduce<String,Value>(value)+ optional Value value2 <- reduce<String, Value>(value) } concrete Value {@@ -96,7 +96,7 @@ unittest test { Value value <- Value.create()- optional Value value2 <- reduce<Value,String>(value)+ optional Value value2 <- reduce<Value, String>(value) } concrete Value {@@ -136,11 +136,11 @@ } attempt () {- return reduce<Value<#x>,Value<#y>>(self)+ return reduce<Value<#x>, Value<#y>>(self) } } -@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1@@ -173,11 +173,11 @@ } attempt () {- return reduce<Value<#x>,Value<#y>>(self)+ return reduce<Value<#x>, Value<#y>>(self) } } -@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1@@ -210,11 +210,11 @@ } attempt () {- return reduce<Value<#x>,Value<#y>>(self)+ return reduce<Value<#x>, Value<#y>>(self) } } -@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1@@ -247,11 +247,11 @@ } attempt () {- return reduce<Value<#x>,Value<#y>>(self)+ return reduce<Value<#x>, Value<#y>>(self) } } -@value interface Type1 {}+@value interface Type1 { } @value interface Type2 { refines Type1@@ -263,15 +263,15 @@ } unittest test {- [Value1|Value2] value <- Value1.create()+ [Value1 | Value2] value <- Value1.create() scoped {- optional Base value2 <- reduce<[Value1|Value2],Base>(value)+ optional Base value2 <- reduce<[Value1 | Value2], Base>(value) } in if (!present(value2)) { fail("Failed") } } -@value interface Base {}+@value interface Base { } concrete Value1 { refines Base@@ -295,15 +295,15 @@ } unittest test {- [Value1|Value2] value <- Value1.create()+ [Value1 | Value2] value <- Value1.create() scoped {- optional Value2 value2 <- reduce<[Value1|Value2],Value2>(value)+ optional Value2 value2 <- reduce<[Value1 | Value2], Value2>(value) } in if (present(value2)) { fail("Failed") } } -@value interface Base {}+@value interface Base { } concrete Value1 { refines Base@@ -329,15 +329,15 @@ unittest test { Value value <- Value.create() scoped {- optional [Base1&Base2] value2 <- reduce<Value,[Base1&Base2]>(value)+ optional [Base1 & Base2] value2 <- reduce<Value, [Base1 & Base2]>(value) } in if (!present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } concrete Value { refines Base1@@ -360,15 +360,15 @@ unittest test { Value value <- Value.create() scoped {- optional [Base1&Base2] value2 <- reduce<Value,[Base1&Base2]>(value)+ optional [Base1 & Base2] value2 <- reduce<Value, [Base1 & Base2]>(value) } in if (present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } concrete Value { refines Base1@@ -388,17 +388,17 @@ } unittest test {- [Value1|Value2] value <- Value2.create()+ [Value1 | Value2] value <- Value2.create() scoped {- optional [Base1&Base2] value2 <- reduce<[Value1|Value2],[Base1&Base2]>(value)+ optional [Base1 & Base2] value2 <- reduce<[Value1 | Value2], [Base1 & Base2]>(value) } in if (!present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } @value interface Value1 { refines Base1@@ -424,17 +424,17 @@ } unittest test {- [Value1|Value2] value <- Value2.create()+ [Value1 | Value2] value <- Value2.create() scoped {- optional [Base1&Base2] value2 <- reduce<[Value1|Value2],[Base1&Base2]>(value)+ optional [Base1 & Base2] value2 <- reduce<[Value1 | Value2], [Base1 & Base2]>(value) } in if (present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } @value interface Value1 { refines Base1@@ -459,23 +459,23 @@ } unittest test {- [Value1&Value2] value <- Data.create()+ [Value1 & Value2] value <- Data.create() scoped {- optional [Base1|Base2] value2 <- reduce<[Value1&Value2],[Base1|Base2]>(value)+ optional [Base1 | Base2] value2 <- reduce<[Value1 & Value2], [Base1 | Base2]>(value) } in if (!present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } @value interface Value1 { refines Base1 } -@value interface Value2 {}+@value interface Value2 { } concrete Data { refines Value1@@ -496,21 +496,21 @@ } unittest test {- [Value1&Value2] value <- Data.create()+ [Value1 & Value2] value <- Data.create() scoped {- optional [Base1|Base2] value2 <- reduce<[Value1&Value2],[Base1|Base2]>(value)+ optional [Base1 | Base2] value2 <- reduce<[Value1 & Value2], [Base1 | Base2]>(value) } in if (present(value2)) { fail("Failed") } } -@value interface Base1 {}+@value interface Base1 { } -@value interface Base2 {}+@value interface Base2 { } -@value interface Value1 {}+@value interface Value1 { } -@value interface Value2 {}+@value interface Value2 { } concrete Data { refines Value1@@ -533,7 +533,7 @@ unittest test { Value<String> value <- Value<String>.create() scoped {- optional Value<any> value2 <- reduce<Value<String>,Value<any>>(value)+ optional Value<any> value2 <- reduce<Value<String>, Value<any>>(value) } in if (!present(value2)) { fail("Failed") }@@ -557,7 +557,7 @@ unittest test { Value<String> value <- Value<String>.create() scoped {- optional Value<all> value2 <- reduce<Value<String>,Value<all>>(value)+ optional Value<all> value2 <- reduce<Value<String>, Value<all>>(value) } in if (!present(value2)) { fail("Failed") }@@ -581,7 +581,7 @@ unittest test { Value<String> value <- Value<String>.create() scoped {- optional Value<any> value2 <- reduce<Value<String>,Value<any>>(value)+ optional Value<any> value2 <- reduce<Value<String>, Value<any>>(value) } in if (present(value2)) { fail("Failed") }@@ -605,7 +605,7 @@ unittest test { Value<all> value <- Value<all>.create() scoped {- optional Value<String> value2 <- reduce<Value<all>,Value<String>>(value)+ optional Value<String> value2 <- reduce<Value<all>, Value<String>>(value) } in if (!present(value2)) { fail("Failed") }@@ -629,7 +629,7 @@ unittest test { Value<any> value <- Value<any>.create() scoped {- optional Value<String> value2 <- reduce<Value<any>,Value<String>>(value)+ optional Value<String> value2 <- reduce<Value<any>, Value<String>>(value) } in if (!present(value2)) { fail("Failed") }@@ -653,7 +653,7 @@ unittest test { Value<all> value <- Value<all>.create() scoped {- optional Value<String> value2 <- reduce<Value<all>,Value<String>>(value)+ optional Value<String> value2 <- reduce<Value<all>, Value<String>>(value) } in if (present(value2)) { fail("Failed") }@@ -675,7 +675,7 @@ } unittest test {- if (!present(reduce<Base1,Base0>(Value.create()))) {+ if (!present(reduce<Base1, Base0>(Value.create()))) { fail("Failed") } }@@ -704,21 +704,21 @@ } unittest test {- if (!present(reduce<Value,Base2<Base0>>(Value.create()))) {+ if (!present(reduce<Value, Base2<Base0>>(Value.create()))) { fail("Failed") }- if (present(reduce<Value,Base2<Base1>>(Value.create()))) {+ if (present(reduce<Value, Base2<Base1>>(Value.create()))) { fail("Failed") } } -@value interface Base0 {}+@value interface Base0 { } @value interface Base1 { refines Base0 } -@value interface Base2<|#x> {}+@value interface Base2<|#x> { } concrete Value { refines Base2<Base0>@@ -738,9 +738,9 @@ success } -@value interface A {}-@value interface B {}-@value interface C {}+@value interface A { }+@value interface B { }+@value interface C { } concrete AB { refines A@@ -763,23 +763,23 @@ } unittest leftNestedInRight {- \ Testing.checkTrue(present(reduce<[A&B],[[A&B]|C]>(AB.create())))+ \ Testing.checkTrue(present(reduce<[A & B], [[A & B] | C]>(AB.create()))) } unittest rightNestedInLeft {- \ Testing.checkTrue(present(reduce<[[A|B]&C],[A|B]>(AC.create())))+ \ Testing.checkTrue(present(reduce<[[A | B] & C], [A | B]>(AC.create()))) } unittest unionToUnion {- \ Testing.checkTrue(present(reduce<[[A&B]|C],[[A&B]|C]>(AB.create())))+ \ Testing.checkTrue(present(reduce<[[A & B] | C], [[A & B] | C]>(AB.create()))) } unittest intersectToIntersect {- \ Testing.checkTrue(present(reduce<[[A|B]&C],[[A|B]&C]>(AC.create())))+ \ Testing.checkTrue(present(reduce<[[A | B] & C], [[A | B] & C]>(AC.create()))) } unittest unionToIntersect {- \ Testing.checkFalse(present(reduce<[A|B],[A&B]>(AB.create())))+ \ Testing.checkFalse(present(reduce<[A | B], [A & B]>(AB.create()))) } @@ -788,13 +788,13 @@ } unittest test {- \ Testing.checkTrue(present(reduce<Type,Build<AsBool>>(Type.new())))- \ Testing.checkTrue(present(reduce<Type,Build<ReadAt<Char>>>(Type.new())))- \ Testing.checkFalse(present(reduce<Type,Build<String>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Build<AsBool>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Build<ReadAt<Char>>>(Type.new())))+ \ Testing.checkFalse(present(reduce<Type, Build<String>>(Type.new()))) } concrete Type {- refines Build<[AsBool&ReadAt<Char>]>+ refines Build<[AsBool & ReadAt<Char>]> @type new () -> (Type) }@@ -810,11 +810,11 @@ } unittest test {- \ Testing.checkTrue(present(reduce<Type,Order<Type>>(Type.new())))- \ Testing.checkTrue(present(reduce<Type,Order<Order<Type>>>(Type.new())))- \ Testing.checkFalse(present(reduce<Type,Build<Type>>(Type.new())))- \ Testing.checkTrue(present(reduce<Type,Build<Order<Type>>>(Type.new())))- \ Testing.checkTrue(present(reduce<Type,Order<Formatted>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Order<Type>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Order<Order<Type>>>(Type.new())))+ \ Testing.checkFalse(present(reduce<Type, Build<Type>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Build<Order<Type>>>(Type.new())))+ \ Testing.checkTrue(present(reduce<Type, Order<Formatted>>(Type.new()))) } concrete Type {
tests/regressions.0rt view
@@ -30,7 +30,7 @@ } define Type1 {- call (_) {}+ call (_) { } } concrete Type2<#y> {@@ -82,8 +82,8 @@ } define Child {- call1 (_) {}- call2 (_) {}+ call1 (_) { }+ call2 (_) { } } @@ -139,7 +139,7 @@ } // The count here would be 4 if scoped was prepended to cleanup.- \ Testing.checkEquals<?>(count,3)+ \ Testing.checkEquals<?>(count, 3) } @@ -213,8 +213,8 @@ testcase "Issue #126 is fixed" { // https://github.com/ta0kira/zeolite/issues/126- crash- require "message,12345,false"+ failure+ require "message, 12345, false" } unittest test {@@ -222,15 +222,15 @@ } concrete Type {- @type call () -> (String,Int,Bool)+ @type call () -> (String, Int, Bool) } define Type {- call () (x,y,z) {+ call () (x, y, z) { cleanup { // Primitive variables y and z need to be explicitly set separately from // the return tuple, since the former are stored separately.- fail(x + "," + y.formatted() + "," + z.formatted())+ fail(x + ", " + y.formatted() + ", " + z.formatted()) } in return "message", 12345, false } }@@ -259,7 +259,7 @@ if (true && message != "message") { fail("failed") }- } in {}+ } in { } return "return" } }@@ -288,7 +288,7 @@ while (true && message != "message") { fail("failed") }- } in {}+ } in { } return "return" } }@@ -296,7 +296,7 @@ testcase "Issue #185 is fixed" { // https://github.com/ta0kira/zeolite/issues/185- crash+ failure require "message" }
tests/scoped.0rt view
@@ -47,7 +47,7 @@ compiles } -concrete Value {}+concrete Value { } define Value { @value process () -> (optional Value)@@ -63,7 +63,7 @@ compiles } -concrete Value {}+concrete Value { } define Value { @value process () -> (optional Value)@@ -93,7 +93,7 @@ compiles } -concrete Value {}+concrete Value { } define Value { @value process () -> (optional Value)@@ -109,7 +109,7 @@ compiles } -concrete Value {}+concrete Value { } define Value { @value process () -> (optional Value)@@ -196,7 +196,7 @@ testcase "positional return sets named returns for cleanup" {- crash+ failure require "message" exclude "failed" }@@ -208,11 +208,11 @@ concrete Test { // Using a second return ensures that assignment works properly when the // ReturnTuple is constructed during assignment.- @type get () -> (String,Int)+ @type get () -> (String, Int) } define Test {- get () (value,value2) {+ get () (value, value2) { value <- "failed" cleanup { fail(value)@@ -224,7 +224,7 @@ testcase "top-level assignment sets named return for cleanup" {- crash+ failure require "message" exclude "failed" }@@ -252,7 +252,7 @@ require "value.+not defined" } -concrete Test {}+concrete Test { } define Test { @type get () -> (Int)@@ -352,8 +352,8 @@ concrete Value { @type create () -> (Value)- @value call () -> (Int,Int,Int)- @value get () -> (Int,Int,Int)+ @value call () -> (Int, Int, Int)+ @value get () -> (Int, Int, Int) } define Value {@@ -396,7 +396,7 @@ value <- 1 } in Int value <- 2 - \ Testing.checkEquals(value,1)+ \ Testing.checkEquals(value, 1) } @@ -409,7 +409,7 @@ scoped { } cleanup { value <- 1- } in {}+ } in { } Int value <- 2 }@@ -462,7 +462,7 @@ testcase "cleanup skipped for fail" {- crash+ failure require "scoped" } @@ -563,7 +563,7 @@ testcase "separate trace context for cleanup" {- crash+ failure require "Failed" require "cleanup block" require "Test\.run"@@ -610,13 +610,13 @@ } } }- \ Testing.checkEquals(x,0)- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(x, 0)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) }- \ Testing.checkEquals(x,1)- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(x, 1)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) } @@ -634,8 +634,8 @@ } in { while ((called <- called+1) < 3) { if (called > 1) {- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) } cleanup { y <- 2@@ -647,14 +647,14 @@ } } }- \ Testing.checkEquals(called,3)- \ Testing.checkEquals(x,0)- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(called, 3)+ \ Testing.checkEquals(x, 0)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) }- \ Testing.checkEquals(x,1)- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(x, 1)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) } @@ -667,23 +667,23 @@ scoped { Int x, Int y, Int z <- value.call() } in {- \ Testing.checkEquals(x,0)- \ Testing.checkEquals(y,0)- \ Testing.checkEquals(z,0)+ \ Testing.checkEquals(x, 0)+ \ Testing.checkEquals(y, 0)+ \ Testing.checkEquals(z, 0) } scoped { Int x, Int y, Int z <- value.get() } in {- \ Testing.checkEquals(x,1)- \ Testing.checkEquals(y,2)- \ Testing.checkEquals(z,3)+ \ Testing.checkEquals(x, 1)+ \ Testing.checkEquals(y, 2)+ \ Testing.checkEquals(z, 3) } } concrete Value { @type create () -> (Value)- @value call () -> (Int,Int,Int)- @value get () -> (Int,Int,Int)+ @value call () -> (Int, Int, Int)+ @value get () -> (Int, Int, Int) } define Value {@@ -723,7 +723,7 @@ require compiler "assign.+value" } -concrete Test {}+concrete Test { } define Test { @type get () -> (String)@@ -739,7 +739,7 @@ compiles } -concrete Test {}+concrete Test { } define Test { @type get () -> (String)@@ -756,7 +756,7 @@ require compiler "return.+cleanup" } -concrete Test {}+concrete Test { } define Test { @type get () -> (Int)
tests/self-offset/.zeolite-module view
@@ -1,8 +1,5 @@ root: "../.." path: "tests/self-offset"-private_deps: [- "lib/testing"-] extra_files: [ category_source { source: "tests/self-offset/Extension_Destructor.cpp"@@ -13,4 +10,4 @@ categories: [Offset] } ]-mode: incremental {}+mode: incremental { }
tests/self-offset/offset.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -21,12 +21,16 @@ } unittest test {- \ Testing.checkEquals(Offset.new().call().get(),"different")+ scoped {+ String value <- Offset.new().call().get()+ } in if (value != "different") {+ fail(value)+ } } testcase "VAR_SELF not allowed in destructor" {- crash+ failure require "VAR_SELF" require "Destructor" }
tests/self-type.0rt view
@@ -37,7 +37,7 @@ require "#self not found" } -concrete Type {}+concrete Type { } define Type { @category optional #self value <- empty@@ -239,11 +239,11 @@ } checkFrom () {- return present(reduce<#self,#y>(self))+ return present(reduce<#self, #y>(self)) } checkTo (from) {- return present(reduce<#y,#self>(from))+ return present(reduce<#y, #self>(from)) } } @@ -253,7 +253,7 @@ } unittest test {- \ Testing.checkEquals(Type<Bool>.get(),"Type<Type<Bool>>")+ \ Testing.checkEquals(Type<Bool>.get(), "Type<Type<Bool>>") } concrete Type<#x> {@@ -374,12 +374,12 @@ unittest withConcrete { Type value <- Type.create()- \ Testing.checkEquals(value.next().prev().prev().next().next().get(),1)+ \ Testing.checkEquals(value.next().prev().prev().next().next().get(), 1) } unittest withIntersect {- [Cell<Int>&Forward&Reverse] value <- Type.create()- \ Testing.checkEquals(value.next().prev().prev().next().next().get(),1)+ [Cell<Int> & Forward & Reverse] value <- Type.create()+ \ Testing.checkEquals(value.next().prev().prev().next().next().get(), 1) } @value interface Cell<|#x> {@@ -431,7 +431,7 @@ unittest test { Type value <- Helper.new<Type>()- \ Testing.checkEquals((value `Advance.by` 3).get(),3)+ \ Testing.checkEquals((value `Advance.by` 3).get(), 3) } @value interface Forward {@@ -453,11 +453,11 @@ concrete Advance { @type by<#x> #x requires Forward- (#x,Int) -> (#x)+ (#x, Int) -> (#x) } define Advance {- by (x,i) (x2) {+ by (x, i) (x2) { x2 <- x scoped { Int count <- 0@@ -501,7 +501,7 @@ #x allows #self } -define Type {}+define Type { } testcase "#self nested in param filter" {@@ -513,9 +513,9 @@ #x defines Equals<#self> } -define Type {}+define Type { } -@value interface Writer<#x|> {}+@value interface Writer<#x|> { } testcase "#self nested in inheritance" {@@ -554,13 +554,13 @@ #x allows #self } -define Type1 {}+define Type1 { } concrete Type2<#x> { #x requires #self } -define Type2 {}+define Type2 { } testcase "#self allowed in covavariant position of function param filter" {@@ -654,7 +654,7 @@ exclude "#self" } -@value interface Reader<|#x> {}+@value interface Reader<|#x> { } concrete Type { refines Reader<#self>@@ -675,13 +675,13 @@ require "contravariant" } -@value interface Base<#x|> {}+@value interface Base<#x|> { } concrete Type { refines Base<#self> } -define Type {}+define Type { } testcase "#self cannot be contravariant in define" {@@ -691,13 +691,13 @@ require "contravariant" } -@type interface Base<#x|> {}+@type interface Base<#x|> { } concrete Type { defines Base<#self> } -define Type {}+define Type { } testcase "#self cannot be invariant in refine" {@@ -707,13 +707,13 @@ require "invariant" } -@value interface Base<#x> {}+@value interface Base<#x> { } concrete Type { refines Base<#self> } -define Type {}+define Type { } testcase "#self cannot be invariant in define" {@@ -723,13 +723,13 @@ require "invariant" } -@type interface Base<#x> {}+@type interface Base<#x> { } concrete Type { defines Base<#self> } -define Type {}+define Type { } testcase "#self nested in value init with filters" {@@ -737,7 +737,7 @@ } unittest test {- \ Testing.checkEquals(Type<Int>.create().formatted(),"Type<Type<Int>>")+ \ Testing.checkEquals(Type<Int>.create().formatted(), "Type<Type<Int>>") } concrete Type<|#x> {
tests/simple.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020,2022 Kevin P. Barry+Copyright 2020,2022-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -47,7 +47,7 @@ testcase "basic crash test" {- crash+ failure require stderr "testcase:" require stderr "failure message!!!" exclude stdout "failure message!!!"@@ -86,7 +86,7 @@ } // The declaration for String is in scope, but it lives outside of this module.-define String {}+define String { } testcase "attempt to define interface" {@@ -95,9 +95,9 @@ require "concrete" } -@value interface Type {}+@value interface Type { } -define Type {}+define Type { } testcase "no deadlock with recursive type" {@@ -113,7 +113,7 @@ } define Type {- call () {}+ call () { } } @@ -127,13 +127,13 @@ testcase "custom timeout works as expected" {- crash+ failure require "signal 14" timeout 1 } unittest test {- while (true) {}+ while (true) { } } @@ -144,4 +144,146 @@ args "\" }; exit(1); const char fake[] = { \"" } -unittest test {}+unittest test { }+++testcase "inline assignment return type" {+ success+}++unittest unboxedToUnboxed {+ Int value <- 456+ Int value2 <- (value <- 123)+ \ Testing.checkEquals(value2, 123)+ \ Testing.checkEquals(value, 123)+}++unittest unboxedToBoxed {+ optional Formatted value <- empty+ Int value2 <- (value <- 123)+ \ Testing.checkEquals(value2, 123)+ \ Testing.checkPresent(value)+ \ Testing.checkEquals(require(value).formatted(), "123")+}++unittest boxedToBoxed {+ optional Formatted value <- empty+ String value2 <- (value <- "message")+ \ Testing.checkEquals(value2, "message")+ \ Testing.checkPresent(value)+ \ Testing.checkEquals(require(value).formatted(), "message")+}+++testcase "inline assignment wrong return type" {+ error+ require "String"+ require "Int"+}++unittest test {+ optional Formatted value <- empty+ String value2 <- (value <- 123)+}+++testcase "custom testcase is started and finished" {+ failure Helper+ require "started"+ exclude "not started"+}++concrete Helper {+ defines Testcase+ @type started () -> (Bool)+}++define Helper {+ @category Bool started <- false++ started () {+ return started+ }++ start () {+ started <- true+ }++ finish () {+ if (started) {+ fail("started")+ } else {+ fail("not started")+ }+ }+}++unittest test {+ \ Testing.checkTrue(Helper.started())+}+++testcase "custom testcase is finished on exit" {+ failure Helper+ require "started"+ exclude "not started"+}++concrete Helper {+ defines Testcase+}++define Helper {+ @category Bool started <- false++ start () {+ started <- true+ }++ finish () {+ if (started) {+ fail("started")+ } else {+ fail("not started")+ }+ }+}++unittest test {+ exit(0)+}+++testcase "custom testcase is finished at most once with explicit exit" {+ success Helper+}++concrete Helper {+ defines Testcase+ @type started () -> (Bool)+}++define Helper {+ @category Bool started <- false+ @category Bool called <- false++ started () {+ return started+ }++ start () {+ started <- true+ }++ finish () {+ if (called) {+ fail("called twice")+ }+ called <- true+ }+}++unittest test {+ \ Testing.checkTrue(Helper.started())+ exit(0)+}
tests/simulate-refs/main.0rx view
@@ -47,17 +47,17 @@ @type getRoutines (ReferenceState) -> (DefaultOrder<StateMachine>) getRoutines (state) { return Vector<StateMachine>.new()- .append(Routines.newShared("shared1",state))- .append(Routines.newWeak("weak1",state))- .append(Routines.newWeak("weak2",state))+ .append(Routines.newShared("shared1", state))+ .append(Routines.newWeak("weak1", state))+ .append(Routines.newWeak("weak2", state)) } @type getRoutinesBroken (ReferenceState) -> (DefaultOrder<StateMachine>) getRoutinesBroken (state) { return Vector<StateMachine>.new()- .append(Routines.newSharedBroken("shared1",state))- .append(Routines.newWeakBroken("weak1",state))- .append(Routines.newWeakBroken("weak2",state))+ .append(Routines.newSharedBroken("shared1", state))+ .append(Routines.newWeakBroken("weak1", state))+ .append(Routines.newWeakBroken("weak2", state)) } @type runOnce (Bool) -> (Bool)@@ -69,7 +69,7 @@ } else { routines <- getRoutines(state) }- \ StateExecutor:multiplexStates(routines,random)+ \ StateExecutor:multiplexStates(routines, random) scoped { optional String error <- state.getError()
tests/simulate-refs/ref-state.0rp view
@@ -18,16 +18,6 @@ $ModuleOnly$ -@value interface ReferenceMachine {- immutable-- runWith (String,ReferenceState) -> (optional ReferenceMachine)-}--concrete Run {- @type then (ReferenceMachine,ReferenceMachine) -> (ReferenceMachine)-}- concrete ReferenceState { refines Formatted
tests/simulate-refs/ref-state.0rx view
@@ -22,7 +22,7 @@ @value Bool locked @value Int aliveCleanup @value Int dataCleanup- @value [Append<Formatted>&DefaultOrder<Formatted>] operations+ @value [Append<Formatted> & DefaultOrder<Formatted>] operations new () { return ReferenceState{ 0, 0, false, 0, 0, Vector<Formatted>.new() }@@ -136,36 +136,5 @@ .append(" DC: ") .append(dataCleanup) .build()- }-}--define Run {- then (first,second) {- return RunThen.new(first,second)- }-}--concrete RunThen {- @type new (ReferenceMachine,ReferenceMachine) -> (ReferenceMachine)-}--define RunThen {- refines ReferenceMachine-- @value ReferenceMachine first- @value ReferenceMachine second-- new (first,second) {- return RunThen{ first, second }- }-- runWith (name,state) {- scoped {- optional ReferenceMachine next <- first.runWith(name,state)- } in if (present(next)) {- return RunThen{ require(next), second }- } else {- return second- } } }
tests/simulate-refs/routines.0rp view
@@ -19,9 +19,9 @@ $ModuleOnly$ concrete Routines {- @type newShared (String,ReferenceState) -> (StateMachine)- @type newWeak (String,ReferenceState) -> (StateMachine)+ @type newShared (String, ReferenceState) -> (StateMachine)+ @type newWeak (String, ReferenceState) -> (StateMachine) - @type newSharedBroken (String,ReferenceState) -> (StateMachine)- @type newWeakBroken (String,ReferenceState) -> (StateMachine)+ @type newSharedBroken (String, ReferenceState) -> (StateMachine)+ @type newWeakBroken (String, ReferenceState) -> (StateMachine) }
tests/simulate-refs/routines.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,86 +17,69 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define Routines {- $ReadOnlyExcept[machine]$-- refines StateMachine-- @category ReferenceMachine dropWeak <-- IfElseDecrWeakIsZero.new(- /*if*/ FreeRef.new(),- /*else*/ empty)-- @category ReferenceMachine sharedThenDrop <-- LockRef.new() `Run.then`- IfElseIncrRefIsOne.new(- /*if*/ DecrRef.new() `Run.then`- UnlockRef.new() `Run.then`- dropWeak,- /*else*/ UnlockRef.new() `Run.then`- dropWeak `Run.then`- dropShared)+ @category optional StateTransition<String, ReferenceState> dropWeak <-+ Run:ifElse(+ test: DecrWeakIsZero.new(),+ doIf: FreeRef.new(),+ doElse: empty) - @category ReferenceMachine dropShared <-- LockRef.new() `Run.then`- IfElseDecrRefIsZero.new(- /*if*/ FreeObject.new() `Run.then`- UnlockRef.new() `Run.then`- IfElseDecrWeakIsZero.new(- /*if*/ FreeRef.new(),- /*else*/ empty),- /*else*/ UnlockRef.new())+ @category optional StateTransition<String, ReferenceState> sharedThenDrop <-+ LockRef.new() `Run:then`+ Run:ifElse(+ test: IncrRefIsOne.new(),+ doIf: DecrRef.new() `Run:then`+ UnlockRef.new() `Run:then`+ dropWeak,+ doElse: UnlockRef.new() `Run:then`+ dropWeak `Run:then`+ dropShared) - @category ReferenceMachine sharedThenDropBroken <-- IfElsePlusLockModLockZero.new(- /*if*/ MinusLock.new() `Run.then`- dropWeak,- /*else*/ MinusLockPlusOne.new() `Run.then`- dropWeak `Run.then`- dropSharedBroken)+ @category optional StateTransition<String, ReferenceState> dropShared <-+ LockRef.new() `Run:then`+ Run:ifElse(+ test: DecrRefIsZero.new(),+ doIf: FreeObject.new() `Run:then`+ UnlockRef.new() `Run:then`+ dropWeak,+ doElse: UnlockRef.new()) - @category ReferenceMachine dropSharedBroken <-- IfElseDecrRefIsZero.new(- /*if*/ FreeObject.new() `Run.then`- IfElseDecrWeakIsZero.new(- /*if*/ FreeRef.new(),- /*else*/ empty),- /*else*/ empty)+ @category optional StateTransition<String, ReferenceState> sharedThenDropBroken <-+ Run:ifElse(+ test: PlusLockModLockZero.new(),+ doIf: MinusLock.new() `Run:then`+ dropWeak,+ doElse: MinusLockPlusOne.new() `Run:then`+ dropWeak `Run:then`+ dropSharedBroken) - @value String name- @value ReferenceState state- @value optional ReferenceMachine machine+ @category optional StateTransition<String, ReferenceState> dropSharedBroken <-+ Run:ifElse(+ test: DecrRefIsZero.new(),+ doIf: FreeObject.new() `Run:then`+ dropWeak,+ doElse: empty) - newShared (name,state) {+ newShared (name, state) { if (state.addStrong() == 1) { \ state.addWeak() }- return #self{ name, state, dropShared }+ return LabeledStateMachine:new(name, state, dropShared) } - newWeak (name,state) {+ newWeak (name, state) { \ state.addWeak()- return #self{ name, state, sharedThenDrop }+ return LabeledStateMachine:new(name, state, sharedThenDrop) } - newSharedBroken (name,state) {+ newSharedBroken (name, state) { if (state.addStrong() == 1) { \ state.addWeak() }- return #self{ name, state, dropSharedBroken }+ return LabeledStateMachine:new(name, state, dropSharedBroken) } - newWeakBroken (name,state) {+ newWeakBroken (name, state) { \ state.addWeak()- return #self{ name, state, sharedThenDropBroken }- }-- transition () {- if (!present(machine)) {- return empty- } elif (present((machine <- require(machine).runWith(name,state)))) {- return self- } else {- return empty- }+ return LabeledStateMachine:new(name, state, sharedThenDropBroken) } }
tests/simulate-refs/state.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -22,6 +22,38 @@ transition () -> (optional StateMachine) } +@value interface StateTransition<#l, #s|> {+ immutable++ runWith (#l, #s) -> (optional StateTransition<#l, #s>)+}++@value interface StatePredicate<#l, #s|> {+ immutable++ test (#l, #s) -> (Bool)+}++concrete Run {+ @category then<#l, #s>+ (optional StateTransition<#l, #s>, optional StateTransition<#l, #s>) ->+ (optional StateTransition<#l, #s>)++ @category ifElse<#l, #s>+ (StatePredicate<#l, #s> test:,+ optional StateTransition<#l, #s> doIf:,+ optional StateTransition<#l, #s> doElse:) ->+ (StateTransition<#l, #s>)+}++concrete LabeledStateMachine<#l, #s> {+ #l immutable++ @category new<#l, #s>+ #l immutable+ (#l, #s, optional StateTransition<#l, #s>) -> (StateMachine)+}+ concrete StateExecutor {- @category multiplexStates (DefaultOrder<StateMachine>,Generator<Float>) -> ()+ @category multiplexStates (DefaultOrder<StateMachine>, Generator<Float>) -> () }
tests/simulate-refs/state.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -16,16 +16,107 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] +define Run {+ then (first, second) {+ return delegate -> `RunThen:new`+ }++ ifElse (test, doIf, doElse) {+ return delegate -> `RunIfElse:new`+ }+}++concrete RunThen<#l, #s|> {+ @category new<#l, #s> (optional StateTransition<#l, #s>, optional StateTransition<#l, #s>) -> (optional StateTransition<#l, #s>)+}++define RunThen {+ refines StateTransition<#l, #s>++ @value StateTransition<#l, #s> first+ @value StateTransition<#l, #s> second++ new (first, second) {+ if (! `present` first) {+ return second+ } elif (! `present` second) {+ return first+ } else {+ return RunThen<#l, #s>{ `require` first, `require` second }+ }+ }++ runWith (label, state) {+ scoped {+ optional StateTransition<#l, #s> next <- label `first.runWith` state+ } in if (`present` next) {+ return #self{ `require` next, second }+ } else {+ return second+ }+ }+}++concrete RunIfElse<#l, #s|> {+ @category new<#l, #s>+ (StatePredicate<#l, #s> test:, optional StateTransition<#l, #s> doIf:, optional StateTransition<#l, #s> doElse:) ->+ (StateTransition<#l, #s>)+}++define RunIfElse {+ refines StateTransition<#l, #s>++ @value StatePredicate<#l, #s> test+ @value optional StateTransition<#l, #s> doIf+ @value optional StateTransition<#l, #s> doElse++ new (test, doIf, doElse) {+ return delegate -> RunIfElse<#l, #s>+ }++ runWith (label, state) {+ if (label `test.test` state) {+ return doIf+ } else {+ return doElse+ }+ }+}++define LabeledStateMachine {+ $ReadOnlyExcept[machine]$++ refines StateMachine++ @value #l label+ @value #s state+ @value optional StateTransition<#l, #s> machine++ new (label, state, transition) {+ return delegate -> LabeledStateMachine<#l, #s>+ }++ transition () {+ if (!present(machine)) {+ return empty+ } elif (`present` (machine <- label `require(machine).runWith` state)) {+ return self+ } else {+ return empty+ }+ }+}+ define StateExecutor {- multiplexStates (original,random) {- HashedMap<Int,StateMachine> states <- HashedMap<Int,StateMachine>.new()+ multiplexStates (original, random) {+ HashedMap<Int, StateMachine> states <- HashedMap<Int, StateMachine>.new() CategoricalTree<Int> weights <- CategoricalTree<Int>.new() scoped { Int index <- 0 } in traverse (original.defaultOrder() -> StateMachine state) {- \ states.set(index,state)- \ weights.setWeight(index,1)+ \ index `states.set` state+ \ index `weights.setWeight` 1 } update { index <- index+1 }@@ -35,11 +126,11 @@ Int index <- weights.locate((random.generate()*weights.getTotal().asFloat()).asInt()) scoped { optional StateMachine newState <- require(states.get(index)).transition()- } in if (present(newState)) {- \ states.set(index,require(newState))+ } in if (`present` newState) {+ \ index `states.set` `require` newState } else {- \ states.remove(index)- \ weights.setWeight(index,0)+ \ `states.remove` index+ \ index `weights.setWeight` 0 } } }
tests/simulate-refs/transitions.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -19,49 +19,49 @@ $ModuleOnly$ concrete LockRef {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } -concrete IfElseDecrRefIsZero {- @type new (optional ReferenceMachine,optional ReferenceMachine) -> (ReferenceMachine)+concrete DecrRefIsZero {+ @type new () -> (StatePredicate<String, ReferenceState>) } concrete UnlockRef {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } concrete FreeObject {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } -concrete IfElseDecrWeakIsZero {- @type new (optional ReferenceMachine,optional ReferenceMachine) -> (ReferenceMachine)+concrete DecrWeakIsZero {+ @type new () -> (StatePredicate<String, ReferenceState>) } concrete FreeRef {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } -concrete IfElseIncrRefIsOne {- @type new (optional ReferenceMachine,optional ReferenceMachine) -> (ReferenceMachine)+concrete IncrRefIsOne {+ @type new () -> (StatePredicate<String, ReferenceState>) } concrete DecrRef {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } concrete DecrWeak {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } -concrete IfElsePlusLockModLockZero {- @type new (optional ReferenceMachine,optional ReferenceMachine) -> (ReferenceMachine)+concrete PlusLockModLockZero {+ @type new () -> (StatePredicate<String, ReferenceState>) } concrete MinusLockPlusOne {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) } concrete MinusLock {- @type new () -> (ReferenceMachine)+ @type new () -> (StateTransition<String, ReferenceState>) }
tests/simulate-refs/transitions.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021,2023 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -17,11 +17,11 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define LockRef {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) if (state.tryLock()) { return empty@@ -31,30 +31,23 @@ } } -define IfElseDecrRefIsZero {- refines ReferenceMachine-- @value optional ReferenceMachine doIf- @value optional ReferenceMachine doElse+define DecrRefIsZero {+ refines StatePredicate<String, ReferenceState> - new (doIf,doElse) { return #self{ doIf, doElse } }+ new () { return #self{ } } - runWith (name,state) {+ test (name, state) { \ state.addOperation<#self>(name)- if (state.remStrong() == 0) {- return doIf- } else {- return doElse- }+ return state.remStrong() == 0 } } define UnlockRef {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.remLock() return empty@@ -62,71 +55,57 @@ } define FreeObject {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.kill() return empty } } -define IfElseDecrWeakIsZero {- refines ReferenceMachine-- @value optional ReferenceMachine doIf- @value optional ReferenceMachine doElse+define DecrWeakIsZero {+ refines StatePredicate<String, ReferenceState> - new (doIf,doElse) { return #self{ doIf, doElse } }+ new () { return #self{ } } - runWith (name,state) {+ test (name, state) { \ state.addOperation<#self>(name)- if (state.remWeak() == 0) {- return doIf- } else {- return doElse- }+ return state.remWeak() == 0 } } define FreeRef {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.freeData() return empty } } -define IfElseIncrRefIsOne {- refines ReferenceMachine-- @value optional ReferenceMachine doIf- @value optional ReferenceMachine doElse+define IncrRefIsOne {+ refines StatePredicate<String, ReferenceState> - new (doIf,doElse) { return #self{ doIf, doElse } }+ new () { return #self{ } } - runWith (name,state) {+ test (name, state) { \ state.addOperation<#self>(name)- if (state.addStrong() == 1) {- return doIf- } else {- return doElse- }+ return state.addStrong() == 1 } } define DecrRef {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.remStrong() return empty@@ -134,41 +113,34 @@ } define DecrWeak {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.remWeak() return empty } } -define IfElsePlusLockModLockZero {- refines ReferenceMachine-- @value optional ReferenceMachine doIf- @value optional ReferenceMachine doElse+define PlusLockModLockZero {+ refines StatePredicate<String, ReferenceState> - new (doIf,doElse) { return #self{ doIf, doElse } }+ new () { return #self{ } } - runWith (name,state) {+ test (name, state) { \ state.addOperation<#self>(name)- if (state.plusStrong($ExprLookup[LOCK_VAL]$) % $ExprLookup[LOCK_VAL]$ == 0) {- return doIf- } else {- return doElse- }+ return state.plusStrong($ExprLookup[LOCK_VAL]$) % $ExprLookup[LOCK_VAL]$ == 0 } } define MinusLockPlusOne {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.minusStrong($ExprLookup[LOCK_VAL]$-1) return empty@@ -176,11 +148,11 @@ } define MinusLock {- refines ReferenceMachine+ refines StateTransition<String, ReferenceState> new () { return #self{ } } - runWith (name,state) {+ runWith (name, state) { \ state.addOperation<#self>(name) \ state.minusStrong($ExprLookup[LOCK_VAL]$) return empty
+ tests/swap.0rt view
@@ -0,0 +1,367 @@+/* -----------------------------------------------------------------------------+Copyright 2022-2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "successful swaps" {+ success+}++concrete Test {+ @type new () -> (#self)+ @value testUnboxedCategoryValue () -> ()+ @value testBoxedCategoryValue () -> ()+ @value testWeakCategoryValue () -> ()+ @value testCategorySame () -> ()+ @value testUnboxedValueSame () -> ()+ @value testBoxedValueSame () -> ()+ @value testUnboxedNamedReturn () -> ()+ @value testBoxedNamedReturn () -> ()+}++define Test {+ @category Int unboxedCategory <- 123+ @category String boxedCategory <- "abc"+ @category weak String weakCategory <- boxedCategory++ @value Int unboxedValue+ @value String boxedValue+ @value weak String weakValue++ new () {+ String value <- "def"+ return #self{ 456, value, value }+ }++ testUnboxedCategoryValue () {+ unboxedCategory <-> unboxedValue+ \ Testing.checkEquals(unboxedCategory, 456)+ \ Testing.checkEquals(unboxedValue, 123)+ unboxedValue <-> unboxedCategory+ \ Testing.checkEquals(unboxedCategory, 123)+ \ Testing.checkEquals(unboxedValue, 456)+ }++ testBoxedCategoryValue () {+ boxedCategory <-> boxedValue+ \ Testing.checkEquals(boxedCategory, "def")+ \ Testing.checkEquals(boxedValue, "abc")+ boxedValue <-> boxedCategory+ \ Testing.checkEquals(boxedCategory, "abc")+ \ Testing.checkEquals(boxedValue, "def")+ }++ testWeakCategoryValue () {+ weakCategory <-> weakValue+ \ Testing.checkEquals(`strong` weakCategory, "def")+ \ Testing.checkEquals(`strong` weakValue, "abc")+ weakValue <-> weakCategory+ \ Testing.checkEquals(`strong` weakCategory, "abc")+ \ Testing.checkEquals(`strong` weakValue, "def")+ }++ testCategorySame () {+ boxedCategory <-> boxedCategory+ \ Testing.checkEquals(boxedCategory, "abc")+ }++ testUnboxedValueSame () {+ unboxedValue <-> unboxedValue+ \ Testing.checkEquals(unboxedValue, 456)+ }++ testBoxedValueSame () {+ boxedValue <-> boxedValue+ \ Testing.checkEquals(boxedValue, "def")+ }++ testUnboxedNamedReturn () {+ \ Testing.checkEquals(callWithNamedUnboxed(), 456)+ }++ testBoxedNamedReturn () {+ \ Testing.checkEquals(callWithNamedBoxed(), "def")+ }++ @value callWithNamedUnboxed () -> (Int)+ callWithNamedUnboxed () (value1) {+ value1 <- 123+ Int value2 <- 456+ value1 <-> value2+ \ Testing.checkEquals(value1, 456)+ \ Testing.checkEquals(value2, 123)+ }++ @value callWithNamedBoxed () -> (String)+ callWithNamedBoxed () (value1) {+ value1 <- "abc"+ String value2 <- "def"+ value1 <-> value2+ \ Testing.checkEquals(value1, "def")+ \ Testing.checkEquals(value2, "abc")+ }+}++unittest testUnboxedCategoryValue {+ \ Test.new().testUnboxedCategoryValue()+}++unittest testBoxedCategoryValue {+ \ Test.new().testBoxedCategoryValue()+}++unittest testWeakCategoryValue {+ \ Test.new().testWeakCategoryValue()+}++unittest testCategorySame {+ \ Test.new().testCategorySame()+}++unittest testUnboxedValueSame {+ \ Test.new().testUnboxedValueSame()+}++unittest testBoxedValueSame {+ \ Test.new().testBoxedValueSame()+}++unittest testUnboxedNamedReturn {+ \ Test.new().testUnboxedNamedReturn()+}++unittest testBoxedNamedReturn {+ \ Test.new().testBoxedNamedReturn()+}++unittest testUnboxedLocal {+ Int value1 <- 123+ Int value2 <- 456+ value1 <-> value2+ \ Testing.checkEquals(value1, 456)+ \ Testing.checkEquals(value2, 123)+}++unittest testBoxedLocal {+ String value1 <- "abc"+ String value2 <- "def"+ value1 <-> value2+ \ Testing.checkEquals(value1, "def")+ \ Testing.checkEquals(value2, "abc")+}++unittest testOptionalLocal {+ optional String value1 <- "abc"+ optional String value2 <- "def"+ value1 <-> value2+ \ Testing.checkEquals(value1, "def")+ \ Testing.checkEquals(value2, "abc")+}++unittest testWeakLocal {+ optional String source1 <- "abc"+ optional String source2 <- "def"+ weak String value1 <- source1+ weak String value2 <- source2+ $Hidden[source1, source2]$+ value1 <-> value2+ \ Testing.checkEquals(`strong` value1, "def")+ \ Testing.checkEquals(`strong` value2, "abc")+}++unittest testUnboxedTopLevelScoped {+ Int value1 <- 123+ scoped {+ Int value2 <- 456+ } cleanup {+ \ Testing.checkEquals(value1, 456)+ } in value1 <-> value2+ \ Testing.checkEquals(value1, 456)+}++unittest testBoxedTopLevelScoped {+ String value1 <- "abc"+ weak String reference <- value1+ scoped {+ String value2 <- "def"+ } cleanup {+ \ Testing.checkEquals(value1, "def")+ \ Testing.checkEquals(value2, "abc")+ \ Testing.checkEquals(`strong` reference, "abc")+ } in value1 <-> value2+ \ Testing.checkEquals(value1, "def")+ // value2 is out of scope now.+ \ Testing.checkEmpty(`strong` reference)+}+++testcase "swap works with parameters" {+ success+}++concrete Test<#x> {+ #x requires Formatted+ #x defines Equals<#x>++ @type new (#x) -> (#self)+ @value testSwap (#x) -> ()+}++define Test {+ @value #x value++ new (value) { return #self{ value } }++ testSwap (value2) {+ // value2 is read-only because it's an argument.+ #x temp <- value2+ value <-> temp+ \ Testing.checkEquals(value, value2)+ }+}++unittest testUnboxed {+ \ Test<Int>.new(123).testSwap(456)+}++unittest testBxed {+ \ Test<String>.new("abc").testSwap("def")+}+++testcase "swap not allowed with incompatible types" {+ error+ require "Int"+ require "String"+}++unittest test {+ Int value1 <- 123+ String value2 <- "abc"+ value1 <-> value2+}+++testcase "swap not allowed with invalid left assignment" {+ error+ require "modifier"+}++unittest test {+ Int value1 <- 123+ optional Int value2 <- empty+ value1 <-> value2+}+++testcase "swap not allowed with invalid right assignment" {+ error+ require "modifier"+}++unittest test {+ optional Int value1 <- empty+ Int value2 <- 456+ value1 <-> value2+}+++testcase "swap not allowed with read-only left" {+ error+ require "value1"+ require "read-only"+ exclude "value2"+}++unittest test {+ Int value1 <- 1+ Int value2 <- 2+ $ReadOnly[value1]$+ value1 <-> value2+}+++testcase "swap not allowed with read-only right" {+ error+ require "value2"+ require "read-only"+ exclude "value1"+}++unittest test {+ Int value1 <- 1+ Int value2 <- 2+ $ReadOnly[value2]$+ value1 <-> value2+}+++testcase "swap not allowed with hidden left" {+ error+ require "value1"+ require "hidden"+ exclude "value2"+}++unittest test {+ Int value1 <- 1+ Int value2 <- 2+ $Hidden[value1]$+ value1 <-> value2+}+++testcase "swap not allowed with hidden right" {+ error+ require "value2"+ require "hidden"+ exclude "value1"+}++unittest test {+ Int value1 <- 1+ Int value2 <- 2+ $Hidden[value2]$+ value1 <-> value2+}+++testcase "swap not allowed with deferred left" {+ error+ require "value1"+ require "initialized"+ exclude "value2"+}++unittest test {+ Int value1 <- defer+ Int value2 <- 2+ value1 <-> value2+}+++testcase "swap not allowed with deferred right" {+ error+ require "value2"+ require "initialized"+ exclude "value1"+}++unittest test {+ Int value1 <- 1+ Int value2 <- defer+ value1 <-> value2+}
tests/templates/.zeolite-module view
@@ -10,4 +10,4 @@ categories: [Templated2] } ]-mode: incremental {}+mode: incremental { }
tests/templates/tests.0rt view
@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "template compiles to binary" {- crash+ failure require "Templated:create is not implemented" } @@ -27,7 +27,7 @@ testcase "private template generated" {- crash+ failure require "Templated2\.create is not implemented" }
+ tests/test-helpers.0rp view
@@ -0,0 +1,113 @@+/* -----------------------------------------------------------------------------+Copyright 2020-2021,2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$+$TestsOnly$++// General helpers for use in unit tests.+concrete Testing {+ // Check the values for equality. Crashes if they are not equal.+ //+ // Args:+ // - #x: Actual value.+ // - #x: Expected value.+ @type checkEquals<#x>+ #x defines Equals<#x>+ (optional #x, optional #x) -> ()++ // Check the values for inequality. Crashes if they are equal.+ //+ // Args:+ // - #x: Actual value.+ // - #x: Expected value.+ @type checkNotEquals<#x>+ #x defines Equals<#x>+ (optional #x, optional #x) -> ()++ // Check the value for empty. Crashes if present.+ //+ // Args:+ // - #x: Actual value.+ @type checkEmpty<#x> (optional #x) -> ()++ // Check the value for present. Crashes if empty.+ //+ // Args:+ // - optional any: Actual value.+ @type checkPresent (optional any) -> ()++ // Check the value for true. Crashes if false.+ //+ // Args:+ // - AsBool: Actual value.+ @type checkTrue (optional AsBool) -> ()++ // Check the value for false. Crashes if true.+ //+ // Args:+ // - AsBool: Actual value.+ @type checkFalse (optional AsBool) -> ()++ // Check that the value is within a range. Crashes if it is not in the range.+ //+ // Args:+ // - #x: Actual value.+ // - #x: Lower bound.+ // - #x: Upper bound.+ //+ // Notes:+ // - This could be done without Equals, except that some types have+ // "undefined" values (e.g., NaN, for Float) that prevent inferring equality+ // from less-than comparisons.+ @type checkBetween<#x>+ #x defines Equals<#x>+ #x defines LessThan<#x>+ (optional #x, #x, #x) -> ()++ // Check that the value is above the limit. Crashes if it is not in the range.+ //+ // Args:+ // - #x: Actual value.+ // - #x: Lower bound.+ //+ // Notes:+ // - This could be done without Equals, except that some types have+ // "undefined" values (e.g., NaN, for Float) that prevent inferring equality+ // from less-than comparisons.+ // - This comparison doesn't allow the value to equal the bound.+ @type checkGreaterThan<#x>+ #x defines Equals<#x>+ #x defines LessThan<#x>+ (optional #x, #x) -> ()++ // Check that the value is below the limit. Crashes if it is not in the range.+ //+ // Args:+ // - #x: Actual value.+ // - #x: Upper bound.+ //+ // Notes:+ // - This could be done without Equals, except that some types have+ // "undefined" values (e.g., NaN, for Float) that prevent inferring equality+ // from less-than comparisons.+ // - This comparison doesn't allow the value to equal the bound.+ @type checkLessThan<#x>+ #x defines Equals<#x>+ #x defines LessThan<#x>+ (optional #x, #x) -> ()+}
+ tests/test-helpers.0rt view
@@ -0,0 +1,300 @@+/* -----------------------------------------------------------------------------+Copyright 2020-2021,2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "checkEquals success" {+ success+}++unittest test {+ \ Testing.checkEquals(13, 13)+ \ Testing.checkEquals<Int>(empty, empty)+}+++testcase "checkEquals fail non-empty" {+ failure+ require stderr "13"+ require stderr "15"+}++unittest test {+ \ Testing.checkEquals(13, 15)+}+++testcase "checkEquals fail empty" {+ failure+ require stderr "13"+ require stderr "empty"+}++unittest test {+ \ Testing.checkEquals(13, empty)+}+++testcase "checkNotEquals success" {+ success+}++unittest test {+ \ Testing.checkNotEquals(12, 13)+ \ Testing.checkNotEquals(empty, 13)+ \ Testing.checkNotEquals(12, empty)+}+++testcase "checkNotEquals fail non-empty" {+ failure+ require stderr "13.*13"+}++unittest test {+ \ Testing.checkNotEquals(13, 13)+}+++testcase "checkNotEquals fail empty" {+ failure+ require stderr "empty.*empty"+}++unittest test {+ \ Testing.checkNotEquals<Int>(empty, empty)+}+++testcase "checkEmpty success" {+ success+}++unittest formatted {+ \ Testing.checkEmpty(empty)+}++unittest notFormatted {+ optional CharBuffer value <- empty+ \ Testing.checkEmpty(value)+}+++testcase "checkEmpty fail formatted" {+ failure+ require stderr "13"+ require stderr "empty"+}++unittest test {+ \ Testing.checkEmpty(13)+}+++testcase "checkEmpty fail unformatted" {+ failure+ require stderr "unknown"+ require stderr "empty"+}++unittest test {+ CharBuffer value <- CharBuffer.new(10)+ \ Testing.checkEmpty(value)+}+++testcase "checkPresent success" {+ success+}++unittest test {+ \ Testing.checkPresent(13)+}+++testcase "checkPresent fail" {+ failure+ require stderr "empty"+}++unittest test {+ \ Testing.checkPresent(empty)+}+++testcase "checkBetween success" {+ success+}++unittest test {+ \ Testing.checkBetween(13, 13, 15)+}+++testcase "checkBetween fail non-empty" {+ failure+ require stderr "13"+ require stderr "14"+ require stderr "15"+}++unittest test {+ \ Testing.checkBetween(13, 14, 15)+}+++testcase "checkBetween fail empty" {+ failure+ require stderr "empty"+ require stderr "14"+ require stderr "15"+}++unittest test {+ \ Testing.checkBetween(empty, 14, 15)+}+++testcase "checkBetween bad range" {+ failure+ exclude stderr "14"+ require stderr "13"+ require stderr "15"+}++unittest test {+ \ Testing.checkBetween(14, 15, 13)+}+++testcase "checkGreaterThan success" {+ success+}++unittest test {+ \ Testing.checkGreaterThan(13, 11)+}+++testcase "checkGreaterThan fail non-empty" {+ failure+ require stderr "13"+ require stderr "14"+}++unittest test {+ \ Testing.checkGreaterThan(13, 14)+}+++testcase "checkGreaterThan fail empty" {+ failure+ require stderr "empty"+ require stderr "14"+}++unittest test {+ \ Testing.checkGreaterThan(empty, 14)+}+++testcase "checkLessThan success" {+ success+}++unittest test {+ \ Testing.checkLessThan(13, 14)+}+++testcase "checkLessThan fail non-empty" {+ failure+ require stderr "13"+ require stderr "11"+}++unittest test {+ \ Testing.checkLessThan(13, 11)+}+++testcase "checkLessThan fail empty" {+ failure+ require stderr "empty"+ require stderr "11"+}++unittest test {+ \ Testing.checkLessThan(empty, 11)+}+++testcase "checkTrue success" {+ success+}++unittest test {+ \ Testing.checkTrue(1)+}+++testcase "checkTrue fail non-empty" {+ failure+ require stderr "true"+}++unittest test {+ \ Testing.checkTrue(0)+}+++testcase "checkTrue fail empty" {+ failure+ require stderr "true"+}++unittest test {+ \ Testing.checkTrue(empty)+}+++testcase "checkFalse success" {+ success+}++unittest test {+ \ Testing.checkFalse(0)+}+++testcase "checkFalse fail non-empty" {+ failure+ require stderr "false"+}++unittest test {+ \ Testing.checkFalse(1)+}+++testcase "checkFalse fail empty" {+ failure+ require stderr "false"+}++unittest test {+ \ Testing.checkFalse(empty)+}
+ tests/test-helpers.0rx view
@@ -0,0 +1,169 @@+/* -----------------------------------------------------------------------------+Copyright 2020-2021,2023 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$TestsOnly$++define Testing {+ checkEquals (x, y) { $NoTrace$+ Bool failed <- false+ if (`present` x && `present` y && !#x.equals(`require` x, `require` y)) {+ failed <- true+ } elif (`present` x != `present` y) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is not equal to ")+ .append(autoFormat(y))+ .build())+ }+ }++ checkNotEquals (x, y) { $NoTrace$+ Bool failed <- false+ if (`present` x && `present` y && #x.equals(`require` x, `require` y)) {+ failed <- true+ } elif (! `present` x && ! `present` y) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is equal to ")+ .append(autoFormat(y))+ .build())+ }+ }++ checkEmpty (x) { $NoTrace$+ if (present(x)) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is not empty")+ .build())+ }+ }++ checkPresent (x) { $NoTrace$+ if (!present(x)) {+ fail(String.builder()+ .append("expected non-empty value")+ .build())+ }+ }++ checkTrue (x) { $NoTrace$+ if (! `present` x) {+ fail("expected true but got empty")+ }+ if (!require(x).asBool()) {+ fail("expected true but got false")+ }+ }++ checkFalse (x) { $NoTrace$+ if (! `present` x) {+ fail("expected false but got empty")+ }+ if (require(x).asBool()) {+ fail("expected false but got true")+ }+ }++ checkBetween (x, l, h) { $NoTrace$+ if (!lessEquals(l, h)) {+ fail(String.builder()+ .append("Upper limit ")+ .append(autoFormat(l))+ .append(" is not at or above lower limit ")+ .append(autoFormat(h))+ .build())+ }+ Bool failed <- false+ if (! `present` x) {+ failed <- true+ } elif (!lessEquals(l, `require` x) || !lessEquals(`require` x, h)) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is not between ")+ .append(autoFormat(l))+ .append(" and ")+ .append(autoFormat(h))+ .build())+ }+ }++ checkGreaterThan (x, l) { $NoTrace$+ Bool failed <- false+ if (! `present` x) {+ failed <- true+ } elif (!lessEquals(l, `require` x)) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is not greater than ")+ .append(autoFormat(l))+ .build())+ }+ }++ checkLessThan (x, h) { $NoTrace$+ Bool failed <- false+ if (! `present` x) {+ failed <- true+ } elif (!lessEquals(`require` x, h)) {+ failed <- true+ }+ if (failed) {+ fail(String.builder()+ .append(autoFormat(x))+ .append(" is not less than ")+ .append(autoFormat(h))+ .build())+ }+ }++ @type autoFormat<#x> (optional #x) -> (Formatted)+ autoFormat (x) {+ if (! `present` x) {+ return "empty"+ }+ scoped {+ optional Formatted formatted <- reduce<#x, Formatted>(x)+ } in if (`present` formatted) {+ return `require` formatted+ } else {+ return "(unknown)"+ }+ }++ @type lessEquals<#x>+ #x defines Equals<#x>+ #x defines LessThan<#x>+ (#x, #x) -> (Bool)+ lessEquals (x, y) { $NoTrace$+ // Using !#x.lessThan(y, x) wouldn't account for NaNs.+ return #x.lessThan(x, y) || #x.equals(x, y)+ }+}
tests/tests-only/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "tests/tests-only"-mode: incremental {}+mode: incremental { }
tests/tests-only/private.0rx view
@@ -16,6 +16,6 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -define Type1 {}+define Type1 { } -define Type2 {}+define Type2 { }
tests/tests-only/public1.0rp view
@@ -18,4 +18,4 @@ $TestsOnly$ -concrete Type1 {}+concrete Type1 { }
tests/tests-only/public2.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete Type2 {}+concrete Type2 { }
tests/tests-only2/private.0rx view
@@ -19,5 +19,5 @@ $TestsOnly$ define Testing {- run () {}+ run () { } }
tests/tests-only3/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "tests/tests-only3"-mode: incremental {}+mode: incremental { }
tests/tests-only3/public.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete NotTestsOnly {}+concrete NotTestsOnly { }
tests/tests-only3/public.0rx view
@@ -18,4 +18,4 @@ $TestsOnly$ -define NotTestsOnly {}+define NotTestsOnly { }
tests/tests-only4/.zeolite-module view
@@ -10,4 +10,4 @@ categories: [Type3] } ]-mode: incremental {}+mode: incremental { }
tests/tests-only4/normal.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete Type3 {}+concrete Type3 { }
tests/tests-only4/testing.0rp view
@@ -18,6 +18,6 @@ $TestsOnly$ -concrete Type1 {}+concrete Type1 { } -@value interface Type2 {}+@value interface Type2 { }
tests/traces/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "tests/traces"-mode: incremental {}+mode: incremental { }
tests/traces/traces.0rx view
@@ -16,7 +16,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -concrete Test {}+concrete Test { } define Test { @type doNotExecute () -> ()
tests/tracing.0rt view
@@ -17,7 +17,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "NoTrace skips tracing" {- crash+ failure require "message" require "Test\.error" exclude "Test\.noTrace"@@ -43,7 +43,7 @@ } testcase "NoTrace works in cleanup" {- crash+ failure require "message" require "Test\.error" exclude "Test\.noTrace"@@ -66,13 +66,13 @@ error () { cleanup { fail("message")- } in {}+ } in { } } } testcase "TraceCreation captures trace" {- crash+ failure require "message" require "Type.+creation" }@@ -103,7 +103,7 @@ require compiler "tracing ignored" } -concrete Test {}+concrete Test { } define Test { @type run () -> ()@@ -112,7 +112,7 @@ testcase "TraceCreation still works with NoTrace" {- crash+ failure require "message" require "Type.+creation" exclude "Type\.call"@@ -140,7 +140,7 @@ testcase "TraceCreation only uses the latest" {- crash+ failure require "message" require "Type1.+creation" exclude "Type2.+creation"@@ -185,7 +185,7 @@ testcase "correct function name used for non-merged function" {- crash+ failure require "message" require "Type\.call" exclude "Base"
tests/traverse.0rt view
@@ -25,7 +25,7 @@ traverse (Counter.zeroIndexed(5) -> Int i) { total <- total+i }- \ Testing.checkEquals(total,10)+ \ Testing.checkEquals(total, 10) } unittest ignoreValue {@@ -33,7 +33,7 @@ traverse (Counter.zeroIndexed(5) -> _) { total <- total+1 }- \ Testing.checkEquals(total,5)+ \ Testing.checkEquals(total, 5) } unittest existingVariable {@@ -42,8 +42,8 @@ traverse (Counter.zeroIndexed(5) -> i) { total <- total+i }- \ Testing.checkEquals(total,10)- \ Testing.checkEquals(i,4)+ \ Testing.checkEquals(total, 10)+ \ Testing.checkEquals(i, 4) } unittest breakAtLimit {@@ -54,7 +54,7 @@ } total <- total+i }- \ Testing.checkEquals(total,10)+ \ Testing.checkEquals(total, 10) } unittest continueOnOdd {@@ -65,7 +65,7 @@ } total <- total+i }- \ Testing.checkEquals(total,20)+ \ Testing.checkEquals(total, 20) } unittest withUpdate {@@ -77,7 +77,7 @@ } update { total <- total+i }- \ Testing.checkEquals(total,45)+ \ Testing.checkEquals(total, 45) } unittest overwriteVisibleValue {@@ -86,7 +86,7 @@ // i shouldn't be overwritten after the last iteration. i <- 0 }- \ Testing.checkEquals(i,0)+ \ Testing.checkEquals(i, 0) } unittest overwriteLocalValue {@@ -95,7 +95,7 @@ i <- 0 } update { // i should also be visible here.- \ Testing.checkEquals(i,0)+ \ Testing.checkEquals(i, 0) } } @@ -138,7 +138,7 @@ } unittest test {- traverse (0 -> _) {}+ traverse (0 -> _) { } } @@ -168,7 +168,7 @@ } unittest test {- traverse (Empty:new<String>() -> Int i) {}+ traverse (Empty:new<String>() -> Int i) { } } @@ -191,7 +191,7 @@ traverse (Counter.new() -> Int i) { total <- total+i }- \ Testing.checkEquals(total,10)+ \ Testing.checkEquals(total, 10) } } @@ -242,7 +242,7 @@ traverse (Counter.new() -> Int i) { total <- total+i }- \ Testing.checkEquals(total,10)+ \ Testing.checkEquals(total, 10) } } @@ -280,7 +280,7 @@ } unittest test {- \ Testing.checkEquals(Test.run("message"),"message")+ \ Testing.checkEquals(Test.run("message"), "message") } concrete Test {@@ -291,24 +291,24 @@ run (x) (i) { i <- x Int total <- 0- traverse (Repeat:times(x,10) -> i) {+ traverse (Repeat:times(x, 10) -> i) { total <- total+1 }- \ Testing.checkEquals(total,10)+ \ Testing.checkEquals(total, 10) } } concrete Repeat<|#x> { refines Order<#x> - @category times<#y> (#y,Int) -> (optional Repeat<#y>)+ @category times<#y> (#y, Int) -> (optional Repeat<#y>) } define Repeat { @value #x value @value Int count - times (value,count) {+ times (value, count) { if (count < 1) { return empty } else {
tests/typename.0rt view
@@ -21,94 +21,94 @@ } unittest string {- \ Testing.checkEquals(typename<String>().formatted(),"String")+ \ Testing.checkEquals(typename<String>().formatted(), "String") } unittest int {- \ Testing.checkEquals(typename<Int>().formatted(),"Int")+ \ Testing.checkEquals(typename<Int>().formatted(), "Int") } unittest char {- \ Testing.checkEquals(typename<Char>().formatted(),"Char")+ \ Testing.checkEquals(typename<Char>().formatted(), "Char") } unittest charBuffer {- \ Testing.checkEquals(typename<CharBuffer>().formatted(),"CharBuffer")+ \ Testing.checkEquals(typename<CharBuffer>().formatted(), "CharBuffer") } unittest float {- \ Testing.checkEquals(typename<Float>().formatted(),"Float")+ \ Testing.checkEquals(typename<Float>().formatted(), "Float") } unittest bool {- \ Testing.checkEquals(typename<Bool>().formatted(),"Bool")+ \ Testing.checkEquals(typename<Bool>().formatted(), "Bool") } unittest anyType {- \ Testing.checkEquals(typename<any>().formatted(),"any")+ \ Testing.checkEquals(typename<any>().formatted(), "any") } unittest allType {- \ Testing.checkEquals(typename<all>().formatted(),"all")+ \ Testing.checkEquals(typename<all>().formatted(), "all") } unittest intersectDedup {- \ Testing.checkEquals(typename<[AsBool&Char&Formatted&Int]>().formatted(),- typename<[Char&Int]>().formatted())+ \ Testing.checkEquals(typename<[AsBool & Char & Formatted & Int]>().formatted(),+ typename<[Char & Int]>().formatted()) } unittest unionDedup {- \ Testing.checkEquals(typename<[AsBool|Char|Formatted|Int]>().formatted(),- typename<[AsBool|Formatted]>().formatted())+ \ Testing.checkEquals(typename<[AsBool | Char | Formatted | Int]>().formatted(),+ typename<[AsBool | Formatted]>().formatted()) } unittest param {- \ Testing.checkEquals(Wrapped:getTypename<String,Value<Int>>().formatted(),+ \ Testing.checkEquals(Wrapped:getTypename<String, Value<Int>>().formatted(), "Type<String,Value<Int>>") } unittest intersectParam {- String text <- Wrapped:getTypenameIntersect<Formatted,Int>().formatted()+ String text <- Wrapped:getTypenameIntersect<Formatted, Int>().formatted() if (text != "[Formatted&Int]") { fail(text) } } unittest unionParam {- String text <- Wrapped:getTypenameUnion<Formatted,Int>().formatted()+ String text <- Wrapped:getTypenameUnion<Formatted, Int>().formatted() if (text != "[Formatted|Int]") { fail(text) } } unittest intersectDedupParam {- \ Testing.checkEquals(Wrapped:getTypenameIntersect<Int,Int>().formatted(),"Int")+ \ Testing.checkEquals(Wrapped:getTypenameIntersect<Int, Int>().formatted(), "Int") } unittest unionDedupParam {- \ Testing.checkEquals(Wrapped:getTypenameUnion<Int,Int>().formatted(),"Int")+ \ Testing.checkEquals(Wrapped:getTypenameUnion<Int, Int>().formatted(), "Int") } -@value interface Value<#x> {}+@value interface Value<#x> { } -@value interface Type<#x,#y> {}+@value interface Type<#x, #y> { } concrete Wrapped {- @category getTypename<#x,#y> () -> (Formatted)- @category getTypenameIntersect<#x,#y> () -> (Formatted)- @category getTypenameUnion<#x,#y> () -> (Formatted)+ @category getTypename<#x, #y> () -> (Formatted)+ @category getTypenameIntersect<#x, #y> () -> (Formatted)+ @category getTypenameUnion<#x, #y> () -> (Formatted) } define Wrapped { getTypename () {- return typename<Type<#x,#y>>()+ return typename<Type<#x, #y>>() } getTypenameIntersect () {- return typename<[#x&#y]>()+ return typename<[#x & #y]>() } getTypenameUnion () {- return typename<[#x|#y]>()+ return typename<[#x | #y]>() } }
tests/unary-functions.0rt view
@@ -126,12 +126,12 @@ } concrete Test {- @category add (Int,Int) -> (Int)+ @category add (Int, Int) -> (Int) @category neg (Int) -> (Int) } define Test {- add (x,y) {+ add (x, y) { return x + y } @@ -147,7 +147,7 @@ unittest requireUnary { optional Int value <- 1- \ Testing.checkEquals(`require` value,1)+ \ Testing.checkEquals(`require` value, 1) } unittest presentUnary {@@ -165,6 +165,6 @@ } unittest reduceUnary {- optional Formatted value <- `reduce<Int,Formatted>` 123- \ Testing.checkEquals(require(value).formatted(),"123")+ optional Formatted value <- `reduce<Int, Formatted>` 123+ \ Testing.checkEquals(require(value).formatted(), "123") }
tests/unreachable.0rt view
@@ -43,7 +43,7 @@ require compiler "unreachable" } -concrete Test {}+concrete Test { } define Test { @category failedReturn () -> (Int)@@ -59,7 +59,7 @@ require compiler "unreachable" } -concrete Test {}+concrete Test { } define Test { @category failedReturn () -> (Int)@@ -79,7 +79,7 @@ require compiler "unreachable" } -concrete Test {}+concrete Test { } define Test { @category failedReturn () -> (Int)@@ -128,7 +128,7 @@ fail("message") } cleanup { \ empty- } in {}+ } in { } }
tests/visibility/.zeolite-module view
@@ -3,4 +3,4 @@ private_deps: [ "internal" ]-mode: incremental {}+mode: incremental { }
tests/visibility/internal/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "visibility/internal"-mode: incremental {}+mode: incremental { }
tests/visibility2/.zeolite-module view
@@ -3,4 +3,4 @@ private_deps: [ "internal" ]-mode: incremental {}+mode: incremental { }
tests/visibility2/internal/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../.." path: "visibility2/internal"-mode: incremental {}+mode: incremental { }
tests/warn-public/.zeolite-module view
@@ -4,4 +4,4 @@ "internal" "internal2" ]-mode: incremental {}+mode: incremental { }
tests/warn-public/internal/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../../.." path: "tests/warn-public/internal"-mode: incremental {}+mode: incremental { }
tests/warn-public/internal/public.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -@value interface Type1 {}+@value interface Type1 { }
tests/warn-public/internal2/.zeolite-module view
@@ -1,3 +1,3 @@ root: "../../.." path: "tests/warn-public/internal2"-mode: incremental {}+mode: incremental { }
tests/warn-public/internal2/public.0rp view
@@ -16,4 +16,4 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -@value interface Type2 {}+@value interface Type2 { }
tests/while.0rt view
@@ -21,9 +21,9 @@ require "value.+initialized" } -@value interface Value {}+@value interface Value { } -concrete Test {}+concrete Test { } define Test { @value process () -> (optional Value)@@ -40,9 +40,9 @@ require "return" } -@value interface Value {}+@value interface Value { } -concrete Test {}+concrete Test { } define Test { @value process () -> (optional Value)@@ -295,7 +295,7 @@ testcase "crash in while" {- crash+ failure require "empty" } @@ -336,7 +336,7 @@ while (true) { cleanup { fail(message)- } in {}+ } in { } } return "return" }@@ -353,7 +353,7 @@ while(true) { cleanup { break- } in {}+ } in { } } } @@ -368,7 +368,7 @@ while(true) { cleanup { continue- } in {}+ } in { } } } @@ -432,7 +432,7 @@ testcase "return set in predicate" {- crash+ failure require "message" }
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: zeolite-lang-version: 0.23.0.0+version: 0.24.0.0 synopsis: Zeolite is a statically-typed, general-purpose programming language. description:@@ -59,7 +59,7 @@ license-file: LICENSE author: Kevin P. Barry maintainer: Kevin P. Barry <ta0kira@gmail.com>-copyright: (c) Kevin P. Barry 2019-2022+copyright: (c) Kevin P. Barry 2019-2023 category: Compiler build-type: Simple @@ -102,8 +102,8 @@ lib/container/*.0rp, lib/container/src/*.0rp, lib/container/src/*.0rx,- lib/container/test/*.0rt, lib/container/src/*.cpp,+ lib/container/test/*.0rt, lib/file/README.md, lib/file/.zeolite-module, lib/file/*.0rp,@@ -120,7 +120,11 @@ lib/testing/README.md, lib/testing/.zeolite-module, lib/testing/*.0rp,+ lib/testing/src/*.0rp, lib/testing/src/*.0rx,+ lib/testing/src/*.cpp,+ lib/testing/test/*.0rp,+ lib/testing/test/*.0rx, lib/testing/test/*.0rt, lib/thread/README.md, lib/thread/.zeolite-module,@@ -147,6 +151,9 @@ tests/check-defs/.zeolite-module, tests/check-defs/*.0rp, tests/check-defs/*.0rx,+ tests/custom-testcase/README.md,+ tests/custom-testcase/.zeolite-module,+ tests/custom-testcase/*.0rt, tests/fast-static/README.md, tests/fast-static/*.0rx, tests/freshness/.zeolite-module,@@ -320,20 +327,20 @@ TypeSynonymInstances, Unsafe - build-depends: base >= 4.9 && < 4.15,+ build-depends: base >= 4.9 && < 4.20, containers >= 0.3 && < 0.7, directory >= 1.2.3 && < 1.4, filepath >= 1.0 && < 1.5,- hashable >= 1.0 && < 1.4,- megaparsec >= 7.0 && < 9.1,+ hashable >= 1.0 && < 1.5,+ megaparsec >= 7.0 && < 9.7, microlens >= 0.4.9 && < 0.5, microlens-th >= 0.1.0.0 && < 0.5,- mtl >= 1.0 && < 2.3,+ mtl >= 1.0 && < 2.4, parser-combinators >= 0.2 && < 2.0, regex-tdfa >= 1.0 && < 1.4,- time >= 1.0 && < 1.11,- transformers >= 0.1 && < 0.6,- unix >= 2.6 && <= 2.8+ time >= 1.0 && < 1.13,+ transformers >= 0.1 && < 0.7,+ unix >= 2.6 && <= 2.9 hs-source-dirs: src