zeolite-lang 0.21.0.0 → 0.22.0.0
raw patch · 114 files changed
+4655/−1669 lines, 114 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Types.Procedure: ConvertedCall :: [c] -> TypeInstance -> FunctionCall c -> ValueOperation c
+ Compilation.CompilerState: ccCanForward :: CompilerContext c m s a => a -> [ParamName] -> [VariableName] -> m Bool
+ Compilation.CompilerState: csCanForward :: CompilerContext c m s a => [ParamName] -> [VariableName] -> CompilerState a m Bool
+ Compilation.ProcedureContext: [_pcParentCall] :: ProcedureContext c -> Maybe (Positional ParamName, Positional VariableName)
+ Types.Procedure: TypeConversion :: [c] -> GeneralInstance -> ValueOperation c
+ Types.Procedure: inputValueName :: InputValue c -> VariableName
+ Types.TypeInstance: reverseSelfInstance :: CollectErrorsM m => TypeInstance -> GeneralInstance -> m GeneralInstance
- Compilation.ProcedureContext: ProcedureContext :: SymbolScope -> CategoryName -> Positional (ValueParam c) -> [DefinedMember c] -> CategoryMap c -> ParamFilters -> [ParamFilter c] -> Map ParamName SymbolScope -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ReturnValidation c -> DeferVariable c -> JumpType -> Bool -> [ReturnVariable] -> Set CategoryName -> [String] -> Bool -> LoopSetup [String] -> [Maybe (CleanupBlock c [String])] -> Bool -> [UsedVariable c] -> ExprMap c -> [(MacroName, [c])] -> Bool -> [String] -> ProcedureContext c
+ Compilation.ProcedureContext: ProcedureContext :: SymbolScope -> CategoryName -> Positional (ValueParam c) -> [DefinedMember c] -> CategoryMap c -> ParamFilters -> [ParamFilter c] -> Map ParamName SymbolScope -> Map FunctionName (ScopedFunction c) -> Map VariableName (VariableValue c) -> ReturnValidation c -> DeferVariable c -> JumpType -> Bool -> [ReturnVariable] -> Set CategoryName -> [String] -> Bool -> LoopSetup [String] -> [Maybe (CleanupBlock c [String])] -> Bool -> [UsedVariable c] -> ExprMap c -> [(MacroName, [c])] -> Bool -> [String] -> Maybe (Positional ParamName, Positional VariableName) -> ProcedureContext c
Files
- ChangeLog.md +173/−0
- base/builtin.0rp +34/−0
- base/category-source.hpp +1/−1
- base/function.hpp +13/−13
- base/src/Extension_Bool.cpp +13/−0
- base/src/Extension_Char.cpp +6/−0
- base/src/Extension_Float.cpp +6/−0
- base/src/Extension_Int.cpp +6/−0
- base/src/Extension_String.cpp +16/−0
- example/hello/hello-demo.0rx +8/−12
- example/parser/parser.0rx +11/−11
- example/primes/prime-tracker.0rx +5/−5
- example/primes/primes-demo.0rx +11/−20
- example/random/random-demo.0rx +6/−9
- lib/container/.zeolite-module +18/−0
- lib/container/auto-tree.0rp +4/−4
- lib/container/hashed-map.0rp +40/−0
- lib/container/hashed-set.0rp +37/−0
- lib/container/interfaces.0rp +36/−1
- lib/container/search-tree.0rp +0/−66
- lib/container/sorted-map.0rp +70/−0
- lib/container/sorted-set.0rp +67/−0
- lib/container/sorting.0rp +9/−0
- lib/container/src/Extension_Vector.cpp +13/−20
- lib/container/src/auto-tree.0rx +36/−48
- lib/container/src/hashed-map.0rx +295/−0
- lib/container/src/hashed-set.0rx +59/−0
- lib/container/src/search-tree.0rx +0/−195
- lib/container/src/sorted-map.0rx +215/−0
- lib/container/src/sorted-set.0rx +71/−0
- lib/container/src/sorting.0rx +31/−18
- lib/container/src/tree-set.0rx +0/−100
- lib/container/src/type-map.0rx +15/−7
- lib/container/src/validated-tree.0rp +1/−1
- lib/container/src/wrappers.0rp +31/−0
- lib/container/src/wrappers.0rx +96/−0
- lib/container/test/hashed-map.0rt +239/−0
- lib/container/test/hashed-set.0rt +105/−0
- lib/container/test/helpers.0rt +5/−5
- lib/container/test/list.0rt +5/−5
- lib/container/test/search-tree.0rt +0/−213
- lib/container/test/sorted-map.0rt +336/−0
- lib/container/test/sorted-set.0rt +205/−0
- lib/container/test/sorting.0rt +7/−7
- lib/container/test/tree-set.0rt +0/−186
- lib/container/test/type-map.0rt +28/−22
- lib/container/test/vector.0rt +24/−20
- lib/container/tree-set.0rp +0/−62
- lib/container/type-map.0rp +2/−0
- lib/container/vector.0rp +3/−4
- lib/math/categorical-tree.0rp +32/−23
- lib/math/random.0rp +44/−0
- lib/math/src/Extension_RandomUniform.cpp +5/−0
- lib/math/src/categorical-tree.0rx +8/−4
- lib/math/src/random.0rx +47/−2
- lib/math/src/token.0rx +5/−1
- lib/math/test/categorical-tree.0rt +5/−5
- lib/math/test/random.0rt +120/−9
- lib/math/test/token.0rt +6/−0
- lib/math/token.0rp +1/−0
- lib/testing/helpers.0rp +10/−0
- lib/testing/src/helpers.0rx +10/−0
- lib/testing/test/tests.0rt +19/−0
- lib/util/.zeolite-module +8/−8
- lib/util/extra.0rp +5/−6
- lib/util/helpers.0rp +101/−0
- lib/util/input.0rp +3/−3
- lib/util/interfaces.0rp +3/−10
- lib/util/output.0rp +14/−23
- lib/util/src/Extension_BasicInput.cpp +97/−0
- lib/util/src/Extension_BasicOutput.cpp +154/−0
- lib/util/src/Extension_SimpleInput.cpp +0/−97
- lib/util/src/Extension_SimpleOutput.cpp +0/−142
- lib/util/src/extra.0rx +12/−4
- lib/util/src/helpers.0rx +116/−2
- lib/util/src/input.0rx +5/−5
- lib/util/src/output.0rx +0/−45
- lib/util/src/parse.0rx +0/−4
- lib/util/test/counters.0rt +18/−0
- lib/util/test/extra.0rt +20/−0
- lib/util/test/helpers.0rt +226/−0
- lib/util/test/input.0rt +1/−1
- lib/util/test/output.0rt +18/−6
- lib/util/test/parse.0rt +8/−0
- src/Compilation/CompilerState.hs +5/−0
- src/Compilation/ProcedureContext.hs +33/−12
- src/CompilerCxx/CategoryContext.hs +13/−3
- src/CompilerCxx/CxxFiles.hs +22/−2
- src/CompilerCxx/Procedure.hs +76/−34
- src/Module/ProcessMetadata.hs +6/−1
- src/Parser/Common.hs +1/−1
- src/Parser/Procedure.hs +21/−6
- src/Parser/TypeInstance.hs +2/−2
- src/Test/Procedure.hs +27/−17
- src/Test/testfiles/procedures.0rx +1/−1
- src/Types/DefinedCategory.hs +5/−3
- src/Types/Procedure.hs +6/−1
- src/Types/TypeCategory.hs +17/−13
- src/Types/TypeInstance.hs +12/−1
- tests/builtin-types.0rt +61/−6
- tests/cli-tests.sh +10/−3
- tests/conversions.0rt +144/−0
- tests/defer.0rt +22/−6
- tests/fast-static/program.0rx +4/−4
- tests/filters.0rt +152/−0
- tests/function-calls.0rt +231/−63
- tests/leak-check/leak-check.0rx +8/−10
- tests/self-type.0rt +172/−0
- tests/simulate-refs/main.0rx +20/−20
- tests/simulate-refs/ref-state.0rx +1/−1
- tests/simulate-refs/state.0rx +1/−1
- tests/unary-functions.0rt +30/−1
- tests/value-init.0rt +18/−1
- zeolite-lang.cabal +1/−1
ChangeLog.md view
@@ -1,5 +1,178 @@ # Revision history for zeolite-lang +## 0.22.0.0 -- 2021-12-11++### Libraries++* **[breaking]** Revises basic input and output provided by `lib/util`:++ - **[breaking]** Renames `SimpleInput` to `BasicInput`.++ - **[breaking]** Renames `SimpleOutput` to `BasicOutput`.++ - **[breaking]** Removes `LazyStream`. To construct and write output, there+ are a few options:++ ```text+ // Incrementally.+ \ BasicOutput.stderr()+ .write(someValue)+ .write("\n")+ .flush()+ ```++ ```text+ // Preformatted.+ \ BasicOutput.stderr().writeNow(String.builder()+ .append(someValue)+ .append("\n")+ .build())+ ```++* **[breaking]** Renames `SearchTree` to `SortedMap` in `lib/container`.++* **[breaking]** Renames `TreeSet` to `SortedSet` in `lib/container`.++* **[breaking]** `Vector` changes (`lib/container`):++ * **[breaking]** Replaces `Vector:create<#x>()` with `Vector<#x>.new()` for+ consistency with other `@value` construction.++ * **[breaking]** Removes `Vector:copyFrom` since it was too specific.++* **[breaking]** Removes `set` and `remove` from `AutoBinaryTree`, and adds the+ `swap` function, which can handle both `set` and `remove` operations.++* **[breaking]** Removes `void` from `Void` in `lib/util`. Use `Void.default()`+ instead.++* **[new]** New categories:++ * **[new]** Adds the `HashedMap` and `HashedSet` containers to+ `lib/container`.++ * **[new]** Adds `CategoricalReader`, `RandomCategorical`, and+ `GenerateConstant` to `lib/math`.++ * **[new]** Adds `FormattedH:try` to `lib/util` for formatting values during+ debugging and logging.++ * **[new]** Adds the `LessThan2` `@value interface` to `lib/util`.++ * **[new]** Adds the `KVExchange`, `KeyOrder`, and `ValueOrder`+ `@value interface`s in `lib/container` for additional map operations.++* **[new]** New functionality for existing categories:++ * **[new]** Implements the new `KVExchange`, `KeyOrder`, and `ValueOrder`+ `interface`s for `SortedMap` (previously `SearchTree`) in `lib/container`.++ * **[new]** Adds `copyTo` and `duplicateTo` to `OrderH` and `ReadAtH` in+ `lib/util` for general container duplication.++ * **[new]** Adds `forwardOrder`, `reverseOrder`, and `iterateWith` to+ `ReadAtH` in `lib/util` for iterating over `ReadAt` containers.++ * **[new]** Implements `Default` for containers in `lib/container` and+ `lib/math`.++ * **[new]** Implements `Default`, `Duplicate`, and `Hashed` for `Void` in+ `lib/util`.++ * **[new]** Implements `Sorting` functions in `lib/container` that use the+ new `LessThan2` `interface`.++ * **[new]** Implements `Append<Formatted>` for `BasicOutput` (previously+ `SimpleOutput`) in `lib/util`.++ * **[new]** Adds `permuteFromWeight` to `Randomize` in `lib/math`.++ * **[new]** Adds `probability` to `RandomUniform` in `lib/math`.++ * **[new]** Adds `checkNotEquals` to `Testing` in `lib/testing`.++### Language++* **[breaking]** Makes the `Duplicate` `@value interface` from `lib/util` a+ builtin and implements it for `Bool`, `Char`, `Float`, `Int`, and `String`.++* **[breaking]** Adds the `Hashed` builtin `@value interface` and implements it+ for `Bool`, `Char`, `Float`, `Int`, and `String`.++* **[breaking]** Replaces `@value` conversion for function calls (e.g.,+ `foo.Base.call()` to choose `call` from `Base`) with general type conversions+ using `value?Type` syntax.++ ```text+ // Explicitly converts foo to Base.+ \ foo?Base.call()+ ```++ The primary use-case is still to convert a union or interesection value to a+ specific type to resolve an ambiguity in function selection. Conversions can+ also be used to influence type inference in function calls by changing the+ type of a passed argument.++ ```text+ // Convert the argument when using type inference.+ \ call<?>(foo?[Container&ReadAt<#x>])+ \ call<?>(foo?any)+ ```++ This can also be used to convert the underlying types of `optional` and `weak`+ values, while still preserving the `optional`/`weak` storage modifier.++* **[fix]** Fixes checking of `defer` in `in` blocks of `scoped`. Previously, a+ `defer`red variable was only marked as set if the `cleanup` set it, even if+ all paths through the `in` actually set it.++ ```text+ Int value <- defer+ scoped {+ // ...+ } in if (true) {+ value <- 1+ } else {+ value <- 2+ }+ // Previously, value appeared to be unintialized here.+ \ foo(value)+ ```++* **[fix]** Fixes a bug in type checking of conversions to a parent+ `@value interface` when the `refines` contains `#self`.++ ```text+ concrete Foo {+ // Previously, there would have been an error converting Foo -> Bar<Foo>.+ refines Bar<#self>+ }+ ```++* **[fix]** Fixes bug in validation of internal `@category` functions with a+ param that has the same name as a category param, where the `@category`+ function has a filter that the category does not have.++* **[new]** Allows `present`, `require`, `strong`, and `reduce<#x,#y>` builtin+ functions to have unary notation, e.g., ``y <- `require` x``.++* **[new]** Compiler now does more work attempting to resolve function calls for+ `@value`s with union types. Previously, explicit type conversions were always+ required to make calls from unions.++* **[new]** Allows `requires` and `allows` filters to use unions and+ intersections on the right side, e.g., `#x allows [Foo&Bar]`.++* **[new]** Allows `defer` to be used with `@value` and `@category` members.+ This is primarily because the restriction was somewhat arbitrary.++* **[new]** Implements `LessThan` for `Bool`.++### Compiler CLI++* **[fix]** Makes `PARAM_SELF` work when used in `@value` implementations in C+++ extensions.+ ## 0.21.0.0 -- 2021-11-19 ### Compiler CLI
base/builtin.0rp view
@@ -29,10 +29,13 @@ refines AsBool refines AsInt refines AsFloat+ refines Duplicate refines Formatted+ refines Hashed defines Default defines Equals<Bool>+ defines LessThan<Bool> } // Built-in 8-bit character type.@@ -55,7 +58,9 @@ refines AsChar refines AsInt refines AsFloat+ refines Duplicate refines Formatted+ refines Hashed defines Bounded defines Default@@ -77,7 +82,9 @@ refines AsBool refines AsInt refines AsFloat+ refines Duplicate refines Formatted+ refines Hashed defines Default defines Equals<Float>@@ -108,7 +115,9 @@ refines AsChar refines AsInt refines AsFloat+ refines Duplicate refines Formatted+ refines Hashed defines Bounded defines Default@@ -128,7 +137,9 @@ refines AsBool refines DefaultOrder<Char>+ refines Duplicate refines Formatted+ refines Hashed refines ReadAt<Char> refines SubSequence @@ -258,10 +269,33 @@ defaultOrder () -> (optional Order<#x>) } +// Can be hashed.+//+// Notes:+// - This interface is primarily intended for use with containers.+// - The returned hash does not need to match across different executions of the+// same program.+@value interface Hashed {+ // Hashes the object.+ hashed () -> (Int)+}+ // Contains a flexible number of values of some type. @value interface Container { // Return the number of values. size () -> (Int)+}++// Can be duplicated.+@value interface Duplicate {+ // Creates a duplicate that can be mutated without changing the original.+ //+ // Notes:+ // - This does not need to be a deep copy. The only requirement is that+ // mutating functions can be called on the copy without counterintuitive+ // results. For example, if the object is a container, the duplicate could+ // be a copy of the structure, while still referring to the same objects.+ duplicate () -> (#self) } // Random-access reading from a container.
base/category-source.hpp view
@@ -44,7 +44,7 @@ #define VAR_SELF TypeValue::Var_self(this) -#define PARAM_SELF shared_from_this()+#define PARAM_SELF Param_self() BoxedValue Box_Bool(PrimBool value); BoxedValue Box_String(const PrimString& value);
base/function.hpp view
@@ -84,9 +84,9 @@ template<int Pn, int An> void Init() {} - template<int Pn, int An, class... Ps>- void Init(const S<const TypeInstance>& param, const Ps&... passed) {- params[Pn] = ¶m;+ template<int Pn, int An, class T, class... Ps>+ void Init(const S<const T>& param, const Ps&... passed) {+ params[Pn] = param; Init<Pn+1, An>(passed...); } @@ -102,7 +102,7 @@ if (pos < 0 || pos >= P) { FAIL() << "Bad param index"; }- return *params[pos];+ return params[pos]; } int NumArgs() const final { return A; }@@ -114,8 +114,8 @@ return *args[pos]; } - const S<const TypeInstance>* params[P];- const BoxedValue* args[A];+ S<const TypeInstance> params[P];+ const BoxedValue* args[A]; }; template<>@@ -144,9 +144,9 @@ Init<0>(passed...); } - template<int Pn, class... Ps>- void Init(const S<const TypeInstance>& param, const Ps&... passed) {- params[Pn] = ¶m;+ template<int Pn, class T, class... Ps>+ void Init(const S<const T>& param, const Ps&... passed) {+ params[Pn] = param; Init<Pn+1>(passed...); } @@ -161,13 +161,13 @@ if (pos < 0 || pos >= P) { FAIL() << "Bad param index"; }- return *params[pos];+ return params[pos]; } int NumArgs() const final { return returns->Size(); } const BoxedValue& GetArg(int pos) const final { return returns->At(pos); } - const S<const TypeInstance>* params[P];+ S<const TypeInstance> params[P]; const ReturnTuple* returns; }; @@ -194,8 +194,8 @@ using Type = PassReturns<P>; }; -template<int P, class... Ps>-struct AutoCall<P, S<const TypeInstance>, Ps...> {+template<int P, class T, class... Ps>+struct AutoCall<P, S<const T>, Ps...> { using Type = typename AutoCall<P+1, Ps...>::Type; };
base/src/Extension_Bool.cpp view
@@ -23,9 +23,11 @@ #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" @@ -50,6 +52,13 @@ 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,@@ -61,8 +70,12 @@ 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();
base/src/Extension_Char.cpp view
@@ -25,9 +25,11 @@ #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"@@ -83,8 +85,12 @@ 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();
base/src/Extension_Float.cpp view
@@ -25,9 +25,11 @@ #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"@@ -71,12 +73,16 @@ 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();
base/src/Extension_Int.cpp view
@@ -28,9 +28,11 @@ #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"@@ -86,8 +88,12 @@ 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();
base/src/Extension_String.cpp view
@@ -27,8 +27,10 @@ #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"@@ -153,9 +155,23 @@ } } + 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 {
example/hello/hello-demo.0rx view
@@ -5,24 +5,20 @@ define HelloDemo { run () { scoped {- TextReader reader <- TextReader.fromBlockReader(SimpleInput.stdin())+ TextReader reader <- TextReader.fromBlockReader(BasicInput.stdin()) } cleanup {- \ LazyStream<Formatted>.new()- .append("Goodbye.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("Goodbye.\n") } in while (!reader.pastEnd()) {- \ LazyStream<Formatted>.new()- .append("What is your name? ")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("What is your name? ") String name <- reader.readNextLine() if (name.size() == 0) { break }- \ LazyStream<Formatted>.new()- .append("Hello \"")- .append(name)- .append("\", if that's your real name.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr()+ .write("Hello \"")+ .write(name)+ .write("\", if that's your real name.\n")+ .flush() } } }
example/parser/parser.0rx view
@@ -94,7 +94,7 @@ @category new (String) -> (ParseState<any>) new (data) {- return ParseState<any>{ data, 0, 1, 1, ErrorOr:value(Void.void()), empty }+ return ParseState<any>{ data, 0, 1, 1, ErrorOr:value(Void.default()), empty } } @value getError () -> (Formatted)@@ -109,18 +109,18 @@ @value sanityCheck () -> () sanityCheck () { if (hasBrokenInput()) {- \ LazyStream<Formatted>.new()- .append("Error at ")- .append(getPosition())- .append(": ")- .append(getError())- .writeTo(SimpleOutput.error())+ \ BasicOutput.error()+ .write("Error at ")+ .write(getPosition())+ .write(": ")+ .write(getError())+ .flush() } if (atEof()) {- \ LazyStream<Formatted>.new()- .append("Reached end of input at ")- .append(getPosition())- .writeTo(SimpleOutput.error())+ \ BasicOutput.error()+ .write("Reached end of input at ")+ .write(getPosition())+ .flush() } } }
example/primes/prime-tracker.0rx view
@@ -3,7 +3,7 @@ @value Int nextPossible create () {- return PrimeTracker{ Vector:create<Int>(), 2 }+ return PrimeTracker{ Vector<Int>.new(), 2 } } checkNextPossible (flag) {@@ -31,10 +31,10 @@ nextPossible <- nextPossible+1 if (isPrime) {- \ LazyStream<Formatted>.new()- .append("\r")- .append(toCheck)- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr()+ .write("\r")+ .write(toCheck)+ .flush() \ primes.push(toCheck) } return self
example/primes/primes-demo.0rx view
@@ -11,13 +11,12 @@ // Interactive input loop. scoped {- TextReader reader <- TextReader.fromBlockReader(SimpleInput.stdin())+ TextReader reader <- TextReader.fromBlockReader(BasicInput.stdin()) } in while (!reader.pastEnd()) { $Hidden[tracker,thread]$ - \ LazyStream<Formatted>.new()- .append("Press [Enter] to toggle start/stop computation thread. Type \"exit\" to exit.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr()+ .writeNow("Press [Enter] to toggle start/stop computation thread. Type \"exit\" to exit.\n") String input <- reader.readNextLine() if (reader.pastEnd()) { break@@ -26,37 +25,29 @@ if (input == "") { if (flag.getEnabled()) { \ flag.stop()- \ LazyStream<Formatted>.new()- .append("Stopped.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("Stopped.\n") } else { \ flag.start()- \ LazyStream<Formatted>.new()- .append("Started.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("Started.\n") } } elif (input == "exit") { break } else {- \ LazyStream<Formatted>.new()- .append("Please try again!\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("Please try again!\n") } } // Wait for the thread to exit, then print the results. \ flag.cancel()- \ LazyStream<Formatted>.new()- .append("Exiting.\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("Exiting.\n") \ thread.join() traverse (tracker.getResults() -> Int prime) {- \ LazyStream<Formatted>.new()- .append(prime)- .append("\n")- .writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout()+ .write(prime)+ .write("\n")+ .flush() } } }
example/random/random-demo.0rx view
@@ -42,9 +42,7 @@ .setWeight('y',1974) .setWeight('z',74) - // We could use weights.getTotal() as the upper limit here, but setting it- // to 1.0 allows us to account for changes to weights.- Generator<Float> letter <- RandomUniform.new(0.0,1.0)+ Generator<Char> letter <- weights `RandomCategorical:sampleWith` RandomUniform.probability() Generator<Float> length <- RandomGaussian.new(5.0,3.0) Generator<Float> timing <- RandomExponential.new(4.0) @@ -58,15 +56,14 @@ // Populate the letters using their relative frequencies. traverse (Counter.zeroIndexed(buffer.size()) -> Int pos) {- Int offset <- (weights.getTotal().asFloat()*letter.generate()).asInt()- \ buffer.writeAt(pos,weights.locate(offset))+ \ buffer.writeAt(pos,letter.generate()) } // Print the word.- \ LazyStream<Formatted>.new()- .append(String.fromCharBuffer(buffer))- .append("\n")- .writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout()+ .write(String.fromCharBuffer(buffer))+ .write("\n")+ .flush() // Wait a random amount of time. \ Realtime.sleepSeconds(timing.generate())
lib/container/.zeolite-module view
@@ -1,5 +1,23 @@ root: "../.." path: "lib/container"+expression_map: [+ expression_macro {+ name: HASH_TABLE_MIN_SIZE+ expression: 1+ }+ expression_macro {+ // Overfilling bins makes container iteration more efficient because we+ // don't have as many empty bins to skip over.+ name: HASH_TABLE_EXPAND_RATIO+ expression: 2+ }+ expression_macro {+ // Assumption: Container iteration is less likely when the caller is+ // removing a lot of elements, so we allow more underfilled bins.+ name: HASH_TABLE_CONTRACT_RATIO+ expression: 3+ }+] extra_paths: [ "lib/container/src" "lib/container/test"
lib/container/auto-tree.0rp view
@@ -52,19 +52,19 @@ // Get the value associated with the key. @value get (#k) -> (optional #v) - // Set the value associated with the key.+ // Set 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 set (#k,#v) -> ()+ @value weakSet (#k,#v) -> (#v) - // Remove the node associated with the key.+ // 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 remove (#k) -> ()+ @value swap (#k,optional #v) -> (optional #v) } // An interface for reading the state of a BST node.
+ lib/container/hashed-map.0rp view
@@ -0,0 +1,40 @@+/* -----------------------------------------------------------------------------+Copyright 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]++// A hash table for key-value storage.+//+// Params:+// - #k: The key type.+// - #v: The value type.+concrete HashedMap<#k,#v> {+ defines Default+ refines Container+ refines DefaultOrder<KeyValue<#k,#v>>+ refines Duplicate+ refines KeyOrder<#k>+ refines KVExchange<#k,#v>+ refines KVWriter<#k,#v>+ refines KVReader<#k,#v>+ refines ValueOrder<#v>+ #k immutable+ #k defines Equals<#k>+ #k requires Hashed++ // Create an empty table.+ @type new () -> (#self)+}
+ lib/container/hashed-set.0rp view
@@ -0,0 +1,37 @@+/* -----------------------------------------------------------------------------+Copyright 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]++// A hash-based set.+//+// Params:+// - #k: The element type.+concrete HashedSet<#k> {+ defines Default+ refines Append<#k>+ refines Container+ refines DefaultOrder<#k>+ refines Duplicate+ refines SetReader<#k>+ refines SetWriter<#k>+ #k immutable+ #k defines Equals<#k>+ #k requires Hashed++ // Create a new set.+ @type new () -> (#self)+}
lib/container/interfaces.0rp view
@@ -51,12 +51,46 @@ get (#k) -> (optional #v) } +// Reading keys from key-value storage.+@value interface KeyOrder<|#k> {+ // Returns an iterator for the container's keys.+ keyOrder () -> (optional Order<#k>)+}++// Reading values from key-value storage.+@value interface ValueOrder<|#v> {+ // Returns an iterator for the container's values.+ valueOrder () -> (optional Order<#v>)+}++// Exchanging values in key-value storage.+//+// Params:+// - #k: The key type.+// - #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)++ // Swap the value associated with the key.+ //+ // Args:+ // - #k: Key to look up.+ // - optional #v: Replacement value. If empty, remove the entry.+ //+ // Returns:+ // - optional #v: Previous value, or empty if none existed.+ swap (#k,optional #v) -> (optional #v)+}+ // Writing to a set of values. // // Params: // - #k: The type stored in the set. @value interface SetWriter<#k|> {- add (#k) -> (#self)+ // Adds the value to the set.+ add (#k) -> (#self)+ // Removes the value. remove (#k) -> (#self) } @@ -65,6 +99,7 @@ // Params: // - #k: The type stored in the set. @value interface SetReader<#k|> {+ // Returns true if the set contains the value. member (#k) -> (Bool) }
− lib/container/search-tree.0rp
@@ -1,66 +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]--// A binary search tree for key-value storage.-//-// Params:-// - #k: The key type.-// - #v: The value type.-concrete SearchTree<#k,#v> {- refines Container- refines DefaultOrder<KeyValue<#k,#v>>- refines Duplicate- refines KVWriter<#k,#v>- refines KVReader<#k,#v>- #k immutable- #k defines LessThan<#k>-- // Create an empty tree.- @type new () -> (#self)-- // Traverse in the default order.- //- // Notes:- // - This is from DefaultOrder, but is made explicit for documentation.- // - Traversal of the entire tree 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>>)-- // Traverse the tree in the reverse order of defaultOrder().- //- // Notes:- // - Traversal of the entire tree 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>>)-- // Start forward traversal (same as defaultOrder()) from the specified key.- //- // Notes:- // - If the key does not exist in the SearchTree, the position right after- // where it would be (in the forward direction) is returned.- @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 SearchTree, the position right after- // where it would be (in the reverse direction) is returned.- @value getReverse (#k) -> (optional Order<KeyValue<#k,#v>>)-}
+ lib/container/sorted-map.0rp view
@@ -0,0 +1,70 @@+/* -----------------------------------------------------------------------------+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]++// A binary search map for key-value storage.+//+// Params:+// - #k: The key type.+// - #v: The value type.+concrete SortedMap<#k,#v> {+ defines Default+ refines Container+ refines DefaultOrder<KeyValue<#k,#v>>+ refines Duplicate+ refines KeyOrder<#k>+ refines KVExchange<#k,#v>+ refines KVWriter<#k,#v>+ refines KVReader<#k,#v>+ refines ValueOrder<#v>+ #k immutable+ #k defines LessThan<#k>++ // Create an empty map.+ @type new () -> (#self)++ // Traverse in the default order.+ //+ // Notes:+ // - This is from DefaultOrder, but is made explicit for documentation.+ // - 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>>)++ // Traverse the map in the reverse order of defaultOrder().+ //+ // Notes:+ // - 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>>)++ // 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>>)++ // 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>>)+}
+ lib/container/sorted-set.0rp view
@@ -0,0 +1,67 @@+/* -----------------------------------------------------------------------------+Copyright 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]++// A map-based set.+//+// Params:+// - #k: The element type.+concrete SortedSet<#k> {+ defines Default+ refines Append<#k>+ refines Container+ refines DefaultOrder<#k>+ refines Duplicate+ refines SetReader<#k>+ refines SetWriter<#k>+ #k immutable+ #k defines LessThan<#k>++ // Create a new set.+ @type new () -> (#self)++ // Traverse in the default order.+ //+ // Notes:+ // - This is from DefaultOrder, but is made explicit for documentation.+ // - Traversal of the entire set 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<#k>)++ // Traverse the set in the reverse order of defaultOrder().+ //+ // Notes:+ // - Traversal of the entire set 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<#k>)++ // 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<#k>)++ // 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<#k>)+}
lib/container/sorting.0rp view
@@ -48,6 +48,10 @@ #xx defines LessThan<#x> ([ReadAt<#x>&WriteAt<#x>]) -> () + // The same as sortWith, but with LessThan2 instead of LessThan.+ @category sortWith2<#x>+ ([ReadAt<#x>&WriteAt<#x>],LessThan2<#x>) -> ()+ // In-place order reversal of a random-access container. @category reverse<#x> ([ReadAt<#x>&WriteAt<#x>]) -> () @@ -94,6 +98,11 @@ #xx defines LessThan<#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) // Reverses the list in place and returns the new head. //
lib/container/src/Extension_Vector.cpp view
@@ -24,6 +24,7 @@ #include "Category_Container.hpp" #include "Category_Default.hpp" #include "Category_DefaultOrder.hpp"+#include "Category_Duplicate.hpp" #include "Category_Formatted.hpp" #include "Category_Order.hpp" #include "Category_ReadAt.hpp"@@ -41,31 +42,13 @@ BoxedValue CreateValue_Vector(S<const Type_Vector> parent, VectorType values); struct ExtCategory_Vector : public Category_Vector {- ReturnTuple Call_copyFrom(const ParamsArgs& params_args) final {- TRACE_FUNCTION("Vector:copyFrom")- const S<const TypeInstance> Param_y = params_args.GetParam(0);- const BoxedValue& Var_arg1 = (params_args.GetArg(0));- VectorType values;- const PrimInt size = TypeValue::Call(Var_arg1, Function_Container_size, PassParamsArgs()).At(0).AsInt();- for (int i = 0; i < size; ++i) {- values.push_back(TypeValue::Call(Var_arg1, Function_ReadAt_readAt, PassParamsArgs(Box_Int(i))).At(0));- }- return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), std::move(values)));- }-- ReturnTuple Call_create(const ParamsArgs& params_args) final {- TRACE_FUNCTION("Vector:create")- const S<const TypeInstance> Param_y = params_args.GetParam(0);- return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), VectorType()));- }- ReturnTuple Call_createSize(const ParamsArgs& params_args) final { TRACE_FUNCTION("Vector:createSize") const S<const TypeInstance> Param_y = params_args.GetParam(0); const PrimInt Var_arg1 = (params_args.GetArg(0)).AsInt();- VectorType values;+ VectorType values(Var_arg1); for (int i = 0; i < Var_arg1; ++i) {- values.push_back(TypeInstance::Call(Param_y, Function_Default_default, PassParamsArgs()).At(0));+ values[i] = TypeInstance::Call(Param_y, Function_Default_default, PassParamsArgs()).At(0); } return ReturnTuple(CreateValue_Vector(CreateType_Vector(Params<1>::Type(Param_y)), std::move(values))); }@@ -73,6 +56,16 @@ struct ExtType_Vector : public Type_Vector { inline ExtType_Vector(Category_Vector& p, Params<1>::Type params) : Type_Vector(p, params) {}++ ReturnTuple Call_new(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Vector.new")+ return ReturnTuple(CreateValue_Vector(PARAM_SELF, VectorType()));+ }++ ReturnTuple Call_default(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Vector.default")+ return Call_new(PassParamsArgs());+ } }; class VectorOrder : public TypeValue {
lib/container/src/auto-tree.0rx view
@@ -44,58 +44,71 @@ return find(root,k) } - set (k,v) {- root, Bool added <- insert(root,k,v)- if (added) {+ weakSet (k,v) {+ root, optional #v v2 <- insertWeak(root,k,v)+ if (`present` v2) {+ return `require` v2+ } else { treeSize <- treeSize+1+ return v } } - remove (k) {- root, Bool removed <- delete(root,k)- if (removed) {+ swap (k,v) (old) {+ root, old <- exchange(root,k,v)+ if (!present(v) && present(old)) { treeSize <- treeSize-1+ } elif (present(v) && !present(old)) {+ treeSize <- treeSize+1 } } -- @type insert (optional #n,#k,#v) -> (optional #n,Bool)- insert (node,k,v) (newRoot,added) {+ @type exchange (optional #n,#k,optional #v) -> (optional #n,optional #v)+ exchange (node,k,v) (newRoot,old) { if (!present(node)) {- return #n.newNode(k,v), true+ if (present(v)) {+ return #n.newNode(k,require(v)), empty+ } else {+ return empty, empty+ } } #n node2 <- require(node) if (k `#k.lessThan` node2.getKey()) {- newRoot, added <- insert(node2.getLower(),k,v)+ newRoot, old <- exchange(node2.getLower(),k,v) \ node2.setLower(newRoot) newRoot <- rebalance(node2) } elif (node2.getKey() `#k.lessThan` k) {- newRoot, added <- insert(node2.getHigher(),k,v)+ newRoot, old <- exchange(node2.getHigher(),k,v) \ node2.setHigher(newRoot) newRoot <- rebalance(node2)- } else {- \ node2.setValue(v)+ } elif (present(v)) {+ old <- node2.getValue()+ newRoot <- node2+ \ node2.setValue(require(v)) \ node2.updateNode()- return node2, false+ } else {+ old <- node2.getValue()+ newRoot <- rebalance(removeNode(node2)) } } - @type delete (optional #n,#k) -> (optional #n,Bool)- delete (node,k) (newRoot,removed) {++ @type insertWeak (optional #n,#k,#v) -> (optional #n,optional #v)+ insertWeak (node,k,v) (newRoot,value) { if (!present(node)) {- return empty, false+ return #n.newNode(k,v), empty } #n node2 <- require(node) if (k `#k.lessThan` node2.getKey()) {- newRoot, removed <- delete(node2.getLower(),k)+ newRoot, value <- insertWeak(node2.getLower(),k,v) \ node2.setLower(newRoot) newRoot <- rebalance(node2) } elif (node2.getKey() `#k.lessThan` k) {- newRoot, removed <- delete(node2.getHigher(),k)+ newRoot, value <- insertWeak(node2.getHigher(),k,v) \ node2.setHigher(newRoot) newRoot <- rebalance(node2) } else {- return rebalance(removeNode(node2)), true+ return node2, node2.getValue() } } @@ -234,31 +247,6 @@ } } -concrete TreeKeyValue<|#k,#v> {- refines KeyValue<#k,#v>-- @category create<#k,#v> (#k,#v) -> (TreeKeyValue<#k,#v>)-}--define TreeKeyValue {- $ReadOnly[key,value]$-- @value #k key- @value #v value-- create (key,value) {- return TreeKeyValue<#k,#v>{ key, value }- }-- getKey () {- return key- }-- getValue () {- return value- }-}- define ForwardTreeOrder { $ReadOnly[node,prev]$ @@ -304,7 +292,7 @@ } get () {- return TreeKeyValue:create(node.getKey(),node.getValue())+ return SimpleKeyValue:new(node.getKey(),node.getValue()) } } @@ -353,6 +341,6 @@ } get () {- return TreeKeyValue:create(node.getKey(),node.getValue())+ return SimpleKeyValue:new(node.getKey(),node.getValue()) } }
+ lib/container/src/hashed-map.0rx view
@@ -0,0 +1,295 @@+/* -----------------------------------------------------------------------------+Copyright 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]++define HashedMap {+ @value Int itemCount+ @value [DefaultOrder<HashRoot<#k,#v>>&ReadAt<HashRoot<#k,#v>>] table++ new () {+ return #self{ 0, Vector:createSize<HashRoot<#k,#v>>($ExprLookup[HASH_TABLE_MIN_SIZE]$) }+ }++ default () {+ return new()+ }++ duplicate () {+ return #self{ itemCount, table.defaultOrder() `OrderH:duplicateTo` Vector<HashRoot<#k,#v>>.new() }+ }++ size () {+ return itemCount+ }++ get (k) {+ return table.readAt(getBin(k.hashed())).find(k)+ }++ set (k,v) {+ \ swap(k,v)+ return self+ }++ remove (k) {+ \ swap(k,empty)+ return self+ }++ weakSet (k,v) {+ optional #v value <- table.readAt(getBin(k.hashed())).weakReplace(k,v)+ if (`present` value) {+ return `require` value+ } else {+ itemCount <- itemCount+1+ \ maybeResize()+ return v+ }+ }++ swap (k,v) (old) {+ old <- table.readAt(getBin(k.hashed())).exchange(k,v)+ if (!present(v) && present(old)) {+ itemCount <- itemCount-1+ \ maybeResize()+ } elif (present(v) && !present(old)) {+ itemCount <- itemCount+1+ \ maybeResize()+ }+ }++ defaultOrder () {+ return HashedMapOrder<#k,#v>.new(itemCount,table)+ }++ keyOrder () {+ return MapKeyOrder:new(defaultOrder())+ }++ valueOrder () {+ return MapValueOrder:new(defaultOrder())+ }++ @value getBin (Int) -> (Int)+ getBin (hash) {+ if (hash < 0) {+ return -hash % table.size()+ } else {+ return hash % table.size()+ }+ }++ @value maybeResize () -> ()+ maybeResize () {+ 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())+ } 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)+ }+ if (`present` newTable) {+ [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())+ }+ }+ }+ }+}++concrete HashNode<#k,#v> {+ refines Duplicate+ refines Order<#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)+}++define HashNode {+ $ReadOnly[key]$++ @value #k key+ @value #v value+ @value optional HashNode<#k,#v> next++ new (key,value,next) {+ return #self{ key, value, next }+ }++ duplicate () {+ optional HashNode<#k,#v> next2 <- empty+ if (`present` next) {+ next2 <- require(next).duplicate()+ }+ return #self{ key, value, next2 }+ }++ getKey () { return key }+ getValue () { return value }+ setValue (value2) { value <- value2 }+ get () { return self }+ next () { return next }+ setNext (next2) {+ cleanup {+ next <- next2+ } in return next+ }+}++concrete HashRoot<#k,#v> {+ defines Default+ 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 find (#k) -> (optional #v)+ // Override to allow returning HashNode directly.+ @value defaultOrder () -> (optional HashNode<#k,#v>)+}++define HashRoot {+ @value optional HashNode<#k,#v> root++ default () {+ return #self{ empty }+ }++ defaultOrder () {+ return root+ }++ duplicate () {+ if (`present` root) {+ return #self{ require(root).duplicate() }+ } else {+ return #self{ empty }+ }+ }++ exchange (k,v) (old) {+ old <- empty+ scoped {+ 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)+ if (`present` prev) {+ \ require(prev).setNext(next)+ } else {+ root <- next+ }+ }+ return _+ }+ } update {+ prev <- node+ }+ if (`present` v) {+ root <- HashNode<#k,#v>.new(k,`require` v,root)+ }+ }++ 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)+ return empty+ }++ find (k) (v) {+ v <- empty+ traverse (root -> HashNode<#k,#v> node) {+ if (node.getKey() `#k.equals` k) {+ return node.getValue()+ }+ }+ }+}++concrete HashedMapOrder<#k,#v> {+ refines Order<KeyValue<#k,#v>>++ @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++ new (count,table) (next) {+ next <- empty+ if (count > 0) {+ scoped {+ optional Order<HashRoot<#k,#v>> root, optional HashNode<#k,#v> node <- seekNext(table.defaultOrder())+ } in if (`present` node) {+ next <- #self{ count, root, `require` node }+ }+ }+ }++ get () {+ return SimpleKeyValue:new(node.getKey(),node.getValue())+ }++ next () (next) {+ next <- empty+ if ((count <- count-1) > 0) {+ scoped {+ 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)+ } in if (`present` newNode) {+ node <- `require` newNode+ return self+ }+ }+ }++ @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]$+ while (`present` root) {+ node <- require(root).get().defaultOrder()+ root <- require(root).next()+ if (`present` node) {+ return _+ }+ }+ }+}
+ lib/container/src/hashed-set.0rx view
@@ -0,0 +1,59 @@+/* -----------------------------------------------------------------------------+Copyright 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]++define HashedSet {+ @value HashedMap<#k,any> map++ default () {+ return new()+ }++ new () {+ return #self{ HashedMap<#k,any>.new() }+ }++ size () {+ return map.size()+ }++ duplicate () {+ return #self{ map.duplicate() }+ }++ add (k) {+ \ map.set(k,Void.default())+ return self+ }++ append (k) {+ return add(k)+ }++ remove (k) {+ \ map.remove(k)+ return self+ }++ member (k) {+ return present(map.get(k))+ }++ defaultOrder () {+ return MapKeyOrder:new(map.defaultOrder())+ }+}
− lib/container/src/search-tree.0rx
@@ -1,195 +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]--define SearchTree {- @value AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> tree-- new () {- return #self{ AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() }- }-- size () {- return tree.size()- }-- duplicate () {- return #self{ tree.duplicate() }- }-- set (k,v) {- \ tree.set(k,v)- return self- }-- remove (k) {- \ tree.remove(k)- return self- }-- get (k) {- return tree.get(k)- }-- defaultOrder () {- return ForwardTreeOrder:create(tree.getRoot())- }-- reverseOrder () {- return ReverseTreeOrder:create(tree.getRoot())- }-- getForward (k) {- return ForwardTreeOrder:seek(k,tree.getRoot())- }-- getReverse (k) {- return ReverseTreeOrder:seek(k,tree.getRoot())- }-}--define ValidatedTree {- @value AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> tree-- new () { $NoTrace$- return #self{ AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() }- }-- size () { $NoTrace$- return tree.size()- }-- set (k,v) { $NoTrace$- \ tree.set(k,v)- \ validate(tree.getRoot())- return self- }-- remove (k) { $NoTrace$- \ tree.remove(k)- \ validate(tree.getRoot())- return self- }-- get (k) { $NoTrace$- return tree.get(k)- }-- @type validate (optional BinaryTreeNode<#k,#v>) -> ()- validate (node) { $NoTrace$- if (present(node)) {- \ validateOrder(require(node))- \ validateBalance(require(node))- }- }-- @type validateOrder (BinaryTreeNode<#k,#v>) -> ()- validateOrder (node) { $NoTrace$- if (present(node.getLower())) {- if (!(require(node.getLower()).getKey() `#k.lessThan` node.getKey())) {- fail("bad lower order")- }- \ validateOrder(require(node.getLower()))- }- if (present(node.getHigher())) {- if (!(node.getKey() `#k.lessThan` require(node.getHigher()).getKey())) {- fail("bad higher order")- }- \ validateOrder(require(node.getHigher()))- }- }-- @type validateBalance (BinaryTreeNode<#k,#v>) -> ()- validateBalance (node) { $NoTrace$- scoped {- Int balance <- 0- if (present(node.getLower())) {- balance <- balance-require(node.getLower()).getHeight()- }- if (present(node.getHigher())) {- balance <- balance+require(node.getHigher()).getHeight()- }- $ReadOnly[balance]$- } in if (balance > 1 || balance < -1) {- fail("out of balance: " + balance.formatted())- }- if (present(node.getLower())) {- \ validateBalance(require(node.getLower()))- }- if (present(node.getHigher())) {- \ validateBalance(require(node.getHigher()))- }- }-}--concrete SearchTreeNode<#k,#v> {- defines KVFactory<#k,#v>- refines BalancedTreeNode<SearchTreeNode<#k,#v>,#k,#v>- refines Duplicate-}--define SearchTreeNode {- $ReadOnly[key]$-- @value Int height- @value #k key- @value #v value- @value optional #self lower- @value optional #self higher-- newNode (k,v) {- return #self{ 1, k, v, empty, empty }- }-- duplicate () {- optional #self lower2 <- empty- if (present(lower)) {- lower2 <- require(lower).duplicate()- }- optional #self higher2 <- empty- if (present(higher)) {- higher2 <- require(higher).duplicate()- }- return #self{ height, key, value, lower2, higher2 }- }-- getLower () { return lower }- setLower (l) { lower <- l }- getHigher () { return higher }- setHigher (h) { higher <- h }- getKey () { return key }- getValue () { return value }- setValue (v) { value <- v }- getHeight () { return height }-- updateNode () {- scoped {- Int l <- 0- Int h <- 0- if (present(lower)) {- l <- require(lower).getHeight()- }- if (present(higher)) {- h <- require(higher).getHeight()- }- } in if (l > h) {- height <- l + 1- } else {- height <- h + 1- }- }-}
+ lib/container/src/sorted-map.0rx view
@@ -0,0 +1,215 @@+/* -----------------------------------------------------------------------------+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]++define SortedMap {+ @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() }+ }++ size () {+ return map.size()+ }++ duplicate () {+ return #self{ map.duplicate() }+ }++ get (k) {+ return map.get(k)+ }++ set (k,v) {+ \ swap(k,v)+ return self+ }++ remove (k) {+ \ swap(k,empty)+ return self+ }++ weakSet (k,v) {+ return map.weakSet(k,v)+ }++ swap (k,v) {+ return map.swap(k,v)+ }++ defaultOrder () {+ return ForwardTreeOrder:create(map.getRoot())+ }++ reverseOrder () {+ return ReverseTreeOrder:create(map.getRoot())+ }++ getForward (k) {+ return ForwardTreeOrder:seek(k,map.getRoot())+ }++ getReverse (k) {+ return ReverseTreeOrder:seek(k,map.getRoot())+ }++ keyOrder () {+ return MapKeyOrder:new(defaultOrder())+ }++ valueOrder () {+ return MapValueOrder:new(defaultOrder())+ }+}++define ValidatedTree {+ @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() }+ }++ size () { $NoTrace$+ return map.size()+ }++ set (k,v) { $NoTrace$+ \ map.swap(k,v)+ \ validate(map.getRoot())+ return self+ }++ remove (k) { $NoTrace$+ \ map.swap(k,empty)+ \ validate(map.getRoot())+ return self+ }++ get (k) { $NoTrace$+ return map.get(k)+ }++ @type validate (optional BinaryTreeNode<#k,#v>) -> ()+ validate (node) { $NoTrace$+ if (present(node)) {+ \ validateOrder(require(node))+ \ validateBalance(require(node))+ }+ }++ @type validateOrder (BinaryTreeNode<#k,#v>) -> ()+ validateOrder (node) { $NoTrace$+ if (present(node.getLower())) {+ if (!(require(node.getLower()).getKey() `#k.lessThan` node.getKey())) {+ fail("bad lower order")+ }+ \ validateOrder(require(node.getLower()))+ }+ if (present(node.getHigher())) {+ if (!(node.getKey() `#k.lessThan` require(node.getHigher()).getKey())) {+ fail("bad higher order")+ }+ \ validateOrder(require(node.getHigher()))+ }+ }++ @type validateBalance (BinaryTreeNode<#k,#v>) -> ()+ validateBalance (node) { $NoTrace$+ scoped {+ Int balance <- 0+ if (present(node.getLower())) {+ balance <- balance-require(node.getLower()).getHeight()+ }+ if (present(node.getHigher())) {+ balance <- balance+require(node.getHigher()).getHeight()+ }+ $ReadOnly[balance]$+ } in if (balance > 1 || balance < -1) {+ fail("out of balance: " + balance.formatted())+ }+ if (present(node.getLower())) {+ \ validateBalance(require(node.getLower()))+ }+ if (present(node.getHigher())) {+ \ validateBalance(require(node.getHigher()))+ }+ }+}++concrete SortedMapNode<#k,#v> {+ defines KVFactory<#k,#v>+ refines BalancedTreeNode<SortedMapNode<#k,#v>,#k,#v>+ refines Duplicate+}++define SortedMapNode {+ $ReadOnly[key]$++ @value Int height+ @value #k key+ @value #v value+ @value optional #self lower+ @value optional #self higher++ newNode (k,v) {+ return #self{ 1, k, v, empty, empty }+ }++ duplicate () {+ optional #self lower2 <- empty+ if (present(lower)) {+ lower2 <- require(lower).duplicate()+ }+ optional #self higher2 <- empty+ if (present(higher)) {+ higher2 <- require(higher).duplicate()+ }+ return #self{ height, key, value, lower2, higher2 }+ }++ getLower () { return lower }+ setLower (l) { lower <- l }+ getHigher () { return higher }+ setHigher (h) { higher <- h }+ getKey () { return key }+ getValue () { return value }+ setValue (v) { value <- v }+ getHeight () { return height }++ updateNode () {+ scoped {+ Int l <- 0+ Int h <- 0+ if (present(lower)) {+ l <- require(lower).getHeight()+ }+ if (present(higher)) {+ h <- require(higher).getHeight()+ }+ } in if (l > h) {+ height <- l + 1+ } else {+ height <- h + 1+ }+ }+}
+ lib/container/src/sorted-set.0rx view
@@ -0,0 +1,71 @@+/* -----------------------------------------------------------------------------+Copyright 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]++define SortedSet {+ @value SortedMap<#k,any> map++ default () {+ return new()+ }++ new () {+ return #self{ SortedMap<#k,any>.new() }+ }++ size () {+ return map.size()+ }++ duplicate () {+ return #self{ map.duplicate() }+ }++ add (k) {+ \ map.set(k,Void.default())+ return self+ }++ append (k) {+ return add(k)+ }++ remove (k) {+ \ map.remove(k)+ return self+ }++ member (k) {+ return present(map.get(k))+ }++ defaultOrder () {+ return MapKeyOrder:new(map.defaultOrder())+ }++ reverseOrder () {+ return MapKeyOrder:new(map.reverseOrder())+ }++ getForward (k) {+ return MapKeyOrder:new(map.getForward(k))+ }++ getReverse (k) {+ return MapKeyOrder:new(map.getReverse(k))+ }+}
lib/container/src/sorting.0rx view
@@ -22,9 +22,13 @@ } sortWith (seq) {- \ HeapSort<#x,#xx>.inPlace(seq)+ \ seq `sortWith2` AsLessThan2<#x,#xx>.new() } + sortWith2 (seq,compare) {+ \ HeapSort<#x>.inPlace(seq,compare)+ }+ reverse (seq) { scoped { Int i <- seq.size()/2-1@@ -44,9 +48,13 @@ } sortListWith (head) {- return MergeSort<#n,#x,#xx>.sort(head)+ return head `sortListWith2` AsLessThan2<#x,#xx>.new() } + sortListWith2 (head,compare) {+ return MergeSort<#n,#x>.sort(head,compare)+ }+ reverseList (head) (head2) { if (!present(head)) { return empty@@ -71,19 +79,18 @@ // Putting the params at the top level allows helpers to be called without // needing to pass the params every time.-concrete HeapSort<#x,#xx> {- #xx defines LessThan<#x>-- @type inPlace ([ReadAt<#x>&WriteAt<#x>]) -> ()+concrete HeapSort<#x> {+ @type inPlace ([ReadAt<#x>&WriteAt<#x>],LessThan2<#x>) -> () } define HeapSort {- $ReadOnly[seq]$+ $ReadOnly[seq,compare]$ @value [ReadAt<#x>&WriteAt<#x>] seq+ @value LessThan2<#x> compare - inPlace (seq) {- \ #self{ seq }.execute()+ inPlace (seq,compare) {+ \ #self{ seq, compare }.execute() } @value execute () -> ()@@ -121,10 +128,10 @@ Int left <- 2*last+1 Int right <- 2*last+2 $ReadOnly[left,right]$- if (seq.readAt(indexLargest) `#xx.lessThan` seq.readAt(left)) {+ if (seq.readAt(indexLargest) `compare.lessThan2` seq.readAt(left)) { indexLargest <- left }- if (right < size && seq.readAt(indexLargest) `#xx.lessThan` seq.readAt(right)) {+ if (right < size && seq.readAt(indexLargest) `compare.lessThan2` seq.readAt(right)) { indexLargest <- right } if (indexLargest == last) {@@ -148,15 +155,21 @@ // Putting the params at the top level allows helpers to be called without // needing to pass the params every time.-concrete MergeSort<#n,#x,#xx> {- #xx defines LessThan<#x>+concrete MergeSort<#n,#x> { #n requires ListNode<#n,#x> - @type sort (optional #n) -> (optional #n)+ @type sort (optional #n,LessThan2<#x>) -> (optional #n) } define MergeSort {- sort (head) (head2) {+ @value LessThan2<#x> compare++ sort (head,compare) {+ return #self{ compare }.iterated(head)+ }++ @value iterated (optional #n) -> (optional #n)+ iterated (head) (head2) { head2 <- head $Hidden[head]$ @@ -190,7 +203,7 @@ } } - @type splitAt (optional #n,Int) -> (optional #n)+ @value splitAt (optional #n,Int) -> (optional #n) splitAt (head,n) { optional #n head2 <- head $Hidden[head]$@@ -210,7 +223,7 @@ return empty } - @type merge (optional #n,optional #n) -> (optional #n,optional #n)+ @value merge (optional #n,optional #n) -> (optional #n,optional #n) merge (left,right) (head,tail) { head <- empty tail <- empty@@ -221,7 +234,7 @@ while (present(left2) && present(right2)) { #n append <- defer- if (require(left2).get() `#xx.lessThan` require(right2).get()) {+ if (require(left2).get() `compare.lessThan2` require(right2).get()) { left2 <- (append <- require(left2)).next() } else { right2 <- (append <- require(right2)).next()
− lib/container/src/tree-set.0rx
@@ -1,100 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 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]--define TreeSet {- @value SearchTree<#k,any> tree-- new () {- return #self{ SearchTree<#k,any>.new() }- }-- size () {- return tree.size()- }-- duplicate () {- return #self{ tree.duplicate() }- }-- add (k) {- \ tree.set(k,Void.void())- return self- }-- append (k) {- return add(k)- }-- remove (k) {- \ tree.remove(k)- return self- }-- member (k) {- return present(tree.get(k))- }-- defaultOrder () {- return TreeSetOrder<#k>.wrap(tree.defaultOrder())- }-- reverseOrder () {- return TreeSetOrder<#k>.wrap(tree.reverseOrder())- }-- getForward (k) {- return TreeSetOrder<#k>.wrap(tree.getForward(k))- }-- getReverse (k) {- return TreeSetOrder<#k>.wrap(tree.getReverse(k))- }-}--concrete TreeSetOrder<#k> {- refines Order<#k>-- @type wrap (optional Order<KeyValue<#k,any>>) -> (optional TreeSetOrder<#k>)-}--define TreeSetOrder {- @value Order<KeyValue<#k,any>> order-- wrap (order) {- if (!present(order)) {- return empty- } else {- return #self{ require(order) }- }- }-- next () {- scoped {- optional Order<KeyValue<#k,any>> order2 <- order.next()- } in if (present(order2)) {- order <- require(order2)- return self- } else {- return empty- }- }-- get () {- return order.get().getKey()- }-}
lib/container/src/type-map.0rx view
@@ -17,29 +17,33 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define TypeMap {- @value SearchTree<TypeKey<any>,GenericValue<any>> tree+ @value SortedMap<TypeKey<any>,GenericValue<any>> map + default () {+ return new()+ }+ new () {- return TypeMap{ SearchTree<TypeKey<any>,GenericValue<any>>.new() }+ return TypeMap{ SortedMap<TypeKey<any>,GenericValue<any>>.new() } } duplicate () {- return #self{ tree.duplicate() }+ return #self{ map.duplicate() } } set (k,v) {- \ tree.set(k,GenericValue:create(v))+ \ map.set(k,GenericValue:create(v)) return self } remove (k) {- \ tree.remove(k)+ \ map.remove(k) return self } get (k) { scoped {- optional GenericValue<any> value <- tree.get(k)+ optional GenericValue<any> value <- map.get(k) } in if (present(value)) { return require(value).check<#x>() } else {@@ -48,7 +52,7 @@ } getAll (output) {- traverse (tree.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)) {@@ -81,6 +85,10 @@ .append(index) .append("}") .build()+ }++ hashed () {+ return index.hashed() } lessThan (l,r) {
lib/container/src/validated-tree.0rp view
@@ -21,7 +21,7 @@ // A validated binary search tree for key-value storage. // // Notes:-// - This is the same as SearchTree, but it validates the tree structure every+// - This is the same as SortedMap, but it validates the tree structure every // time there is a modification, which is extremely inefficient. This should // therefore only be used in tests. concrete ValidatedTree<#k|#v|> {
+ lib/container/src/wrappers.0rp view
@@ -0,0 +1,31 @@+/* -----------------------------------------------------------------------------+Copyright 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]++$ModuleOnly$++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>)+}++concrete MapValueOrder<#v> {+ @category new<#v> (optional Order<KeyValue<any,#v>>) -> (optional Order<#v>)+}
+ lib/container/src/wrappers.0rx view
@@ -0,0 +1,96 @@+/* -----------------------------------------------------------------------------+Copyright 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]++define SimpleKeyValue {+ $ReadOnly[key,value]$++ refines KeyValue<#k,#v>++ @value #k key+ @value #v value++ new (key,value) {+ return SimpleKeyValue<#k,#v>{ key, value }+ }++ getKey () {+ return key+ }++ getValue () {+ return value+ }+}++define MapKeyOrder {+ refines Order<#k>++ @value Order<KeyValue<#k,any>> order++ new (order) {+ if (!present(order)) {+ return empty+ } else {+ return MapKeyOrder<#k>{ require(order) }+ }+ }++ next () {+ scoped {+ optional Order<KeyValue<#k,any>> order2 <- order.next()+ } in if (present(order2)) {+ order <- require(order2)+ return self+ } else {+ return empty+ }+ }++ get () {+ return order.get().getKey()+ }+}++define MapValueOrder {+ refines Order<#v>++ @value Order<KeyValue<any,#v>> order++ new (order) {+ if (!present(order)) {+ return empty+ } else {+ return MapValueOrder<#v>{ require(order) }+ }+ }++ next () {+ scoped {+ optional Order<KeyValue<any,#v>> order2 <- order.next()+ } in if (present(order2)) {+ order <- require(order2)+ return self+ } else {+ return empty+ }+ }++ get () {+ return order.get().getValue()+ }+}
+ lib/container/test/hashed-map.0rt view
@@ -0,0 +1,239 @@+/* -----------------------------------------------------------------------------+Copyright 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 "HashedMap tests" {+ success+}++unittest integrationTest {+ 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)+ }++ // Check and remove values.+ traverse (Counter.zeroIndexed(count) -> Int i) {+ Int new <- ((i + 13) * 3547) % count+ scoped {+ optional Int value <- map.get(new)+ } in if (!present(value)) {+ \ BasicOutput.error()+ .write("Not found ")+ .write(new)+ .write(" but should have been ")+ .write(i)+ .flush()+ } elif (require(value) != i) {+ \ BasicOutput.error()+ .write("Element ")+ .write(new)+ .write(" should have been ")+ .write(i)+ .write(" but was ")+ .write(require(value))+ .flush()+ }+ \ map.remove(new)+ \ Testing.checkEquals(map.size(),count-i-1)+ }+}++unittest removeNotPresent {+ 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)+}++unittest defaultOrder {+ HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ Vector<Bool> visited <- Vector:createSize<Bool>(max)++ // 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)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest defaultOrderEmpty {+ traverse (HashedMap<Int,Int>.new().defaultOrder() -> _) {+ fail("not empty")+ }+}++unittest keyOrder {+ HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ Vector<Bool> visited <- Vector:createSize<Bool>(max)++ // Validate traversal coverage.+ Int index <- 0+ traverse (map.keyOrder() -> Int key) {+ \ Testing.checkFalse(visited.readAt(key))+ \ visited.writeAt(key,true)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest valueOrder {+ HashedMap<Int,Int> map <- HashedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ Vector<Bool> visited <- Vector:createSize<Bool>(max)++ // Validate traversal coverage.+ Int index <- 0+ traverse (map.valueOrder() -> Int value) {+ \ Testing.checkFalse(visited.readAt(value))+ \ visited.writeAt(value,true)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest duplicate {+ HashedMap<Int,Int> map <- HashedMap<Int,Int>.default()+ Int max <- 31+ $ReadOnly[max]$++ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ map.set(i,i)+ }++ HashedMap<Int,Int> copy <- map.duplicate()+ \ Testing.checkEquals(copy.size(),map.size())+ traverse (Counter.zeroIndexed(max) -> Int i) {+ $Hidden[map]$+ \ Testing.checkOptional(copy.get(i),i)+ }++ \ copy.set(2,5)+ \ copy.remove(7)+ $Hidden[copy]$++ \ Testing.checkEquals(map.size(),max)+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ Testing.checkOptional(map.get(i),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)+}++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))++ Value value0 <- Value.new(5)+ Value value1 <- map.weakSet(1,value0)+ \ Testing.checkEquals(map.size(),3)++ \ Testing.checkEquals(value0.get(),5)+ \ Testing.checkEquals(value1.get(),1)++ \ value0.set(10)+ \ Testing.checkEquals(value1.get(),1)+ \ Testing.checkOptional(map.get(1),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))++ Value value0 <- Value.new(5)+ Value value1 <- map.weakSet(7,value0)+ \ Testing.checkEquals(map.size(),4)++ \ Testing.checkEquals(value0.get(),5)+ \ Testing.checkEquals(value1.get(),5)++ \ value0.set(10)+ \ Testing.checkEquals(value1.get(),10)+ \ Testing.checkOptional(map.get(7),Value.new(10))+}++concrete Value {+ defines Equals<Value>+ refines Formatted++ @type new (Int) -> (Value)+ @value get () -> (Int)+ @value set (Int) -> ()+}++define Value {+ @value Int value++ new (value) { return Value{ value } }+ get () { return value }+ set (value2) { value <- value2 }++ formatted () {+ return value.formatted()+ }++ equals (x,y) {+ return x.get() == y.get()+ }+}
+ lib/container/test/hashed-set.0rt view
@@ -0,0 +1,105 @@+/* -----------------------------------------------------------------------------+Copyright 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 "HashedSet tests" {+ success+}++unittest addAndRemove {+ HashedSet<Int> set <- HashedSet<Int>.default()+ Int hash <- 13+ Int max <- 20+ $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)+ }++ // Remove only the odd elements.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ if (i%2 == 1) {+ // Remove it twice to ensure idempotence.+ \ set.remove(i).remove(i)+ }+ \ Testing.checkEquals(set.size(),max-(i+1)/2)+ }++ // Validate set membership.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ Testing.checkEquals(set.member(i),i%2 == 0)+ }+}++unittest append {+ HashedSet<Int> set <- HashedSet<Int>.new()+ \ set.append(3)+ \ Testing.checkEquals(set.size(),1)+ \ Testing.checkTrue(set.member(3))+}++unittest removeNotPresent {+ HashedSet<Int> set <- HashedSet<Int>.new().add(1).add(2).add(4)+ \ set.remove(3)+ \ Testing.checkEquals(set.size(),3)+}++unittest defaultOrder {+ HashedSet<Int> set <- HashedSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ Vector<Bool> visited <- Vector:createSize<Bool>(max)++ // Validate traversal coverage.+ Int index <- 0+ traverse (set.defaultOrder() -> Int entry) {+ \ Testing.checkFalse(visited.readAt(entry))+ \ visited.writeAt(entry,true)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest defaultOrderEmpty {+ traverse (HashedSet<Int>.new().defaultOrder() -> _) {+ fail("not empty")+ }+}++unittest duplicate {+ 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.remove(2)+ \ Testing.checkEquals(copy.size(),1)+ \ Testing.checkTrue(copy.member(1))+ \ Testing.checkTrue(set.member(2))+}
lib/container/test/helpers.0rt view
@@ -59,14 +59,14 @@ } unittest integrationTest {- SearchTree<Int,String> tree1 <- SearchTree<Int,String>.new()+ SortedMap<Int,String> map1 <- SortedMap<Int,String>.new() .set(1,"d").set(2,"c").set(3,"b").set(4,"a")- SearchTree<Int,String> tree2 <- SearchTree<Int,String>.new()+ SortedMap<Int,String> map2 <- SortedMap<Int,String>.new() .set(1,"a").set(2,"b").set(3,"c").set(4,"d") - \ Testing.checkTrue(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,AlwaysEqual>>` tree2.defaultOrder())- \ Testing.checkFalse(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,String>>` tree2.defaultOrder())- \ Testing.checkFalse(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<AlwaysEqual,String>>` tree2.defaultOrder())+ \ 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()) } concrete KVEquals<#k,#v> {
lib/container/test/list.0rt view
@@ -31,7 +31,7 @@ .append(4) .build() - DefaultOrder<Int> expected <- Vector:create<Int>()+ DefaultOrder<Int> expected <- Vector<Int>.new() .append(3) .append(2) .append(5)@@ -58,7 +58,7 @@ .append(4) .build() - DefaultOrder<Int> expected <- Vector:create<Int>()+ DefaultOrder<Int> expected <- Vector<Int>.new() .append(4) .append(6) .append(1)@@ -228,7 +228,7 @@ .append(4) .build() - DefaultOrder<Int> expected <- Vector:create<Int>()+ DefaultOrder<Int> expected <- Vector<Int>.new() .append(3) .append(2) .append(5)@@ -266,7 +266,7 @@ .append(4) .build() - DefaultOrder<Int> expected <- Vector:create<Int>()+ DefaultOrder<Int> expected <- Vector<Int>.new() .append(3) .append(2) .append(5)@@ -292,7 +292,7 @@ .append(4) .build() - DefaultOrder<Int> expected <- Vector:create<Int>()+ DefaultOrder<Int> expected <- Vector<Int>.new() .append(3) .append(2) .append(5)
− lib/container/test/search-tree.0rt
@@ -1,213 +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]--testcase "SearchTree tests" {- success-}--unittest integrationTest {- ValidatedTree<Int,Int> tree <- ValidatedTree<Int,Int>.new()- Int count <- 33- $ReadOnly[count]$-- // Insert values.- traverse (Counter.zeroIndexed(count) -> Int i) {- Int new <- ((i + 13) * 3547) % count- \ tree.set(new,i)- \ Testing.checkEquals(tree.size(),i+1)- }-- // Check and remove values.- traverse (Counter.zeroIndexed(count) -> Int i) {- Int new <- ((i + 13) * 3547) % count- scoped {- optional Int value <- tree.get(new)- } in if (!present(value)) {- \ LazyStream<Formatted>.new()- .append("Not found ")- .append(new)- .append(" but should have been ")- .append(i)- .writeTo(SimpleOutput.error())- } elif (require(value) != i) {- \ LazyStream<Formatted>.new()- .append("Element ")- .append(new)- .append(" should have been ")- .append(i)- .append(" but was ")- .append(require(value))- .writeTo(SimpleOutput.error())- }- \ tree.remove(new)- \ Testing.checkEquals(tree.size(),count-i-1)- }-}--unittest defaultOrder {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the tree in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ ((i*hash)%max) `tree.set` i- }-- // Validate the traversal order.- Int index <- 0- traverse (tree.defaultOrder() -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())- index <- index+1- }-- \ Testing.checkEquals(index,max)-}--unittest reverseOrder {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the tree in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ ((i*hash)%max) `tree.set` i- }-- // Validate the traversal order.- Int index <- max- traverse (tree.reverseOrder() -> KeyValue<Int,Int> entry) {- index <- index-1- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())- }-- \ Testing.checkEquals(index,0)-}--unittest getForward {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the tree in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ ((i*hash)%max) `tree.set` i- }-- // Validate the traversal order from every starting point.- traverse (Counter.zeroIndexed(max) -> Int i) {- Int index <- i- traverse (tree.getForward(index) -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())- index <- index+1- }- \ Testing.checkEquals(index,max)- }-}--unittest getForwardNotFound {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- \ tree.set(1,1).set(3,3).set(5,5)-- scoped {- optional Order<KeyValue<Int,Int>> start <- tree.getForward(4)- } in if (!present(start)) {- fail("Failed")- } else {- \ Testing.checkEquals(require(start).get().getKey(),5)- }-- scoped {- optional Order<KeyValue<Int,Int>> start <- tree.getForward(6)- } in if (present(start)) {- fail("Failed")- }-}--unittest getReverse {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the tree in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ ((i*hash)%max) `tree.set` i- }-- // Validate the traversal order from every starting point.- traverse (Counter.zeroIndexed(max) -> Int i) {- Int index <- i- traverse (tree.getReverse(index) -> KeyValue<Int,Int> entry) {- \ Testing.checkEquals(entry.getKey(),index)- \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())- index <- index-1- }- \ Testing.checkEquals(index,-1)- }-}--unittest getReverseNotFound {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()- \ tree.set(1,1).set(3,3).set(5,5)-- scoped {- optional Order<KeyValue<Int,Int>> start <- tree.getReverse(2)- } in if (!present(start)) {- fail("Failed")- } else {- \ Testing.checkEquals(require(start).get().getKey(),1)- }-- scoped {- optional Order<KeyValue<Int,Int>> start <- tree.getReverse(0)- } in if (present(start)) {- fail("Failed")- }-}--unittest duplicate {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new().set(1,1).set(2,2).set(3,3)-- SearchTree<Int,Int> copy <- tree.duplicate()- \ Testing.checkEquals(copy.size(),3)- \ Testing.checkOptional(copy.get(1),1)- \ Testing.checkOptional(copy.get(2),2)- \ Testing.checkOptional(copy.get(3),3)-- \ copy.remove(2)- $Hidden[copy]$-- \ Testing.checkEquals(tree.size(),3)- \ Testing.checkOptional(tree.get(1),1)- \ Testing.checkOptional(tree.get(2),2)- \ Testing.checkOptional(tree.get(3),3)-}--unittest duplicateEmpty {- SearchTree<Int,Int> tree <- SearchTree<Int,Int>.new()-- SearchTree<Int,Int> copy <- tree.duplicate()- \ Testing.checkEquals(copy.size(),0)-}
+ lib/container/test/sorted-map.0rt view
@@ -0,0 +1,336 @@+/* -----------------------------------------------------------------------------+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]++testcase "SortedMap tests" {+ success+}++unittest integrationTest {+ 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)+ }++ // Check and remove values.+ traverse (Counter.zeroIndexed(count) -> Int i) {+ Int new <- ((i + 13) * 3547) % count+ scoped {+ optional Int value <- map.get(new)+ } in if (!present(value)) {+ \ BasicOutput.error()+ .write("Not found ")+ .write(new)+ .write(" but should have been ")+ .write(i)+ .flush()+ } elif (require(value) != i) {+ \ BasicOutput.error()+ .write("Element ")+ .write(new)+ .write(" should have been ")+ .write(i)+ .write(" but was ")+ .write(require(value))+ .flush()+ }+ \ map.remove(new)+ \ Testing.checkEquals(map.size(),count-i-1)+ }+}++unittest removeNotPresent {+ 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)+}++unittest defaultOrder {+ SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // 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())+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest defaultOrderEmpty {+ traverse (SortedMap<Int,Int>.new().defaultOrder() -> _) {+ fail("not empty")+ }+}++unittest keyOrder {+ SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // Validate the traversal order.+ Int index <- 0+ traverse (map.keyOrder() -> Int key) {+ \ Testing.checkEquals(key,index)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest valueOrder {+ SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // Validate the traversal order.+ Int index <- 0+ traverse (map.valueOrder() -> Int value) {+ \ Testing.checkEquals((value*hash)%max,index)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest reverseOrder {+ SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // Validate the traversal order.+ Int index <- max+ traverse (map.reverseOrder() -> KeyValue<Int,Int> entry) {+ index <- index-1+ \ Testing.checkEquals(entry.getKey(),index)+ \ Testing.checkEquals((entry.getValue()*hash)%max,entry.getKey())+ }++ \ Testing.checkEquals(index,0)+}++unittest getForward {+ SortedMap<Int,Int> map <- SortedMap<Int,Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // 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())+ index <- index+1+ }+ \ Testing.checkEquals(index,max)+ }+}++unittest getForwardNotFound {+ 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)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals(require(start).get().getKey(),5)+ }++ scoped {+ 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()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the map in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ ((i*hash)%max) `map.set` i+ }++ // 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())+ index <- index-1+ }+ \ Testing.checkEquals(index,-1)+ }+}++unittest getReverseNotFound {+ 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)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals(require(start).get().getKey(),1)+ }++ scoped {+ 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()+ Int max <- 31+ $ReadOnly[max]$++ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ map.set(i,i)+ }++ SortedMap<Int,Int> copy <- map.duplicate()+ \ Testing.checkEquals(copy.size(),map.size())+ traverse (Counter.zeroIndexed(max) -> Int i) {+ $Hidden[map]$+ \ Testing.checkOptional(copy.get(i),i)+ }++ \ copy.set(2,5)+ \ copy.remove(7)+ $Hidden[copy]$++ \ Testing.checkEquals(map.size(),max)+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ Testing.checkOptional(map.get(i),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)+}++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))++ Value value0 <- Value.new(5)+ Value value1 <- map.weakSet(1,value0)+ \ Testing.checkEquals(map.size(),3)++ \ Testing.checkEquals(value0.get(),5)+ \ Testing.checkEquals(value1.get(),1)++ \ value0.set(10)+ \ Testing.checkEquals(value1.get(),1)+ \ Testing.checkOptional(map.get(1),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))++ Value value0 <- Value.new(5)+ Value value1 <- map.weakSet(7,value0)+ \ Testing.checkEquals(map.size(),4)++ \ Testing.checkEquals(value0.get(),5)+ \ Testing.checkEquals(value1.get(),5)++ \ value0.set(10)+ \ Testing.checkEquals(value1.get(),10)+ \ Testing.checkOptional(map.get(7),Value.new(10))+}++concrete Value {+ defines Equals<Value>+ refines Formatted++ @type new (Int) -> (Value)+ @value get () -> (Int)+ @value set (Int) -> ()+}++define Value {+ @value Int value++ new (value) { return Value{ value } }+ get () { return value }+ set (value2) { value <- value2 }++ formatted () {+ return value.formatted()+ }++ equals (x,y) {+ return x.get() == y.get()+ }+}
+ lib/container/test/sorted-set.0rt view
@@ -0,0 +1,205 @@+/* -----------------------------------------------------------------------------+Copyright 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 "SortedSet tests" {+ success+}++unittest addAndRemove {+ SortedSet<Int> set <- SortedSet<Int>.default()+ Int hash <- 13+ Int max <- 20+ $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)+ }++ // Remove only the odd elements.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ if (i%2 == 1) {+ // Remove it twice to ensure idempotence.+ \ set.remove(i).remove(i)+ }+ \ Testing.checkEquals(set.size(),max-(i+1)/2)+ }++ // Validate set membership.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ Testing.checkEquals(set.member(i),i%2 == 0)+ }+}++unittest append {+ SortedSet<Int> set <- SortedSet<Int>.new()+ \ set.append(3)+ \ Testing.checkEquals(set.size(),1)+ \ Testing.checkTrue(set.member(3))+}++unittest removeNotPresent {+ SortedSet<Int> set <- SortedSet<Int>.new().add(1).add(2).add(4)+ \ set.remove(3)+ \ Testing.checkEquals(set.size(),3)+}++unittest defaultOrder {+ SortedSet<Int> set <- SortedSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order.+ Int index <- 0+ traverse (set.defaultOrder() -> Int entry) {+ \ Testing.checkEquals(entry,index)+ index <- index+1+ }++ \ Testing.checkEquals(index,max)+}++unittest defaultOrderEmpty {+ traverse (SortedSet<Int>.new().defaultOrder() -> _) {+ fail("not empty")+ }+}++unittest reverseOrder {+ SortedSet<Int> set <- SortedSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order.+ Int index <- max+ traverse (set.reverseOrder() -> Int entry) {+ index <- index-1+ \ Testing.checkEquals(entry,index)+ }++ \ Testing.checkEquals(index,0)+}++unittest getForward {+ SortedSet<Int> set <- SortedSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order from every starting point.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ Int index <- i+ traverse (set.getForward(index) -> Int entry) {+ \ Testing.checkEquals(entry,index)+ index <- index+1+ }+ \ Testing.checkEquals(index,max)+ }+}++unittest getForwardNotFound {+ SortedSet<Int> set <- SortedSet<Int>.new()+ \ set.add(1).add(3).add(5)++ scoped {+ optional Order<Int> start <- set.getForward(4)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals(require(start).get(),5)+ }++ scoped {+ optional Order<Int> start <- set.getForward(6)+ } in if (present(start)) {+ fail("Failed")+ }+}++unittest getReverse {+ SortedSet<Int> set <- SortedSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order from every starting point.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ Int index <- i+ traverse (set.getReverse(index) -> Int entry) {+ \ Testing.checkEquals(entry,index)+ index <- index-1+ }+ \ Testing.checkEquals(index,-1)+ }+}++unittest getReverseNotFound {+ SortedSet<Int> set <- SortedSet<Int>.new()+ \ set.add(1).add(3).add(5)++ scoped {+ optional Order<Int> start <- set.getReverse(2)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals(require(start).get(),1)+ }++ scoped {+ optional Order<Int> start <- set.getReverse(0)+ } in if (present(start)) {+ fail("Failed")+ }+}++unittest duplicate {+ 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.remove(2)+ \ Testing.checkEquals(copy.size(),1)+ \ Testing.checkTrue(copy.member(1))+ \ Testing.checkTrue(set.member(2))+}
lib/container/test/sorting.0rt view
@@ -107,7 +107,7 @@ unittest sortList { ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137 $ReadOnly[hash,size]$@@ -129,7 +129,7 @@ unittest sortListSingle { $DisableCoverage$ ListBuilder<Int,ForwardNode<Int>> builder <- ForwardNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137 $ReadOnly[hash,size]$@@ -155,7 +155,7 @@ unittest sortListPow2 { $DisableCoverage$ ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 256 $ReadOnly[hash,size]$@@ -177,7 +177,7 @@ unittest sortListWith { $DisableCoverage$ ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int hash <- 269 Int size <- 137 $ReadOnly[hash,size]$@@ -199,7 +199,7 @@ unittest reverseList { ListBuilder<Int,LinkedNode<Int>> builder <- LinkedNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int size <- 101 $ReadOnly[size]$ @@ -223,7 +223,7 @@ unittest reverseListSingle { $DisableCoverage$ ListBuilder<Int,ForwardNode<Int>> builder <- ForwardNode<Int>.builder()- Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() Int size <- 101 $ReadOnly[size]$ @@ -263,7 +263,7 @@ @value Vector<Int> seq create () {- return TestSequence{ Vector:create<Int>() }+ return TestSequence{ Vector<Int>.new() } } formatted () {
− lib/container/test/tree-set.0rt
@@ -1,186 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 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 "TreeSet tests" {- success-}--unittest addAndRemove {- TreeSet<Int> set <- TreeSet<Int>.new()- Int hash <- 13- Int max <- 20- $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)- }-- // Remove only the odd elements.- traverse (Counter.zeroIndexed(max) -> Int i) {- if (i%2 == 1) {- // Remove it twice to ensure idempotence.- \ set.remove(i).remove(i)- }- \ Testing.checkEquals(set.size(),max-(i+1)/2)- }-- // Validate set membership.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ Testing.checkEquals(set.member(i),i%2 == 0)- }-}--unittest defaultOrder {- TreeSet<Int> set <- TreeSet<Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the set in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ set.add((i*hash)%max)- }-- // Validate the traversal order.- Int index <- 0- traverse (set.defaultOrder() -> Int entry) {- \ Testing.checkEquals(entry,index)- index <- index+1- }-- \ Testing.checkEquals(index,max)-}--unittest reverseOrder {- TreeSet<Int> set <- TreeSet<Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the set in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ set.add((i*hash)%max)- }-- // Validate the traversal order.- Int index <- max- traverse (set.reverseOrder() -> Int entry) {- index <- index-1- \ Testing.checkEquals(entry,index)- }-- \ Testing.checkEquals(index,0)-}--unittest getForward {- TreeSet<Int> set <- TreeSet<Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the set in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ set.add((i*hash)%max)- }-- // Validate the traversal order from every starting point.- traverse (Counter.zeroIndexed(max) -> Int i) {- Int index <- i- traverse (set.getForward(index) -> Int entry) {- \ Testing.checkEquals(entry,index)- index <- index+1- }- \ Testing.checkEquals(index,max)- }-}--unittest getForwardNotFound {- TreeSet<Int> set <- TreeSet<Int>.new()- \ set.add(1).add(3).add(5)-- scoped {- optional Order<Int> start <- set.getForward(4)- } in if (!present(start)) {- fail("Failed")- } else {- \ Testing.checkEquals(require(start).get(),5)- }-- scoped {- optional Order<Int> start <- set.getForward(6)- } in if (present(start)) {- fail("Failed")- }-}--unittest getReverse {- TreeSet<Int> set <- TreeSet<Int>.new()- Int hash <- 13- Int max <- 20- $ReadOnly[hash,max]$-- // Populate the set in a pseudo-random order.- traverse (Counter.zeroIndexed(max) -> Int i) {- \ set.add((i*hash)%max)- }-- // Validate the traversal order from every starting point.- traverse (Counter.zeroIndexed(max) -> Int i) {- Int index <- i- traverse (set.getReverse(index) -> Int entry) {- \ Testing.checkEquals(entry,index)- index <- index-1- }- \ Testing.checkEquals(index,-1)- }-}--unittest getReverseNotFound {- TreeSet<Int> set <- TreeSet<Int>.new()- \ set.add(1).add(3).add(5)-- scoped {- optional Order<Int> start <- set.getReverse(2)- } in if (!present(start)) {- fail("Failed")- } else {- \ Testing.checkEquals(require(start).get(),1)- }-- scoped {- optional Order<Int> start <- set.getReverse(0)- } in if (present(start)) {- fail("Failed")- }-}--unittest duplicate {- TreeSet<Int> set <- TreeSet<Int>.new().add(1).add(2)-- TreeSet<Int> copy <- set.duplicate()- \ Testing.checkEquals(copy.size(),2)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(copy.member(1))-- \ copy.remove(2)- \ Testing.checkEquals(copy.size(),1)- \ Testing.checkTrue(copy.member(1))- \ Testing.checkTrue(set.member(2))-}
lib/container/test/type-map.0rt view
@@ -21,66 +21,66 @@ } unittest basicOperations {- TypeMap tree <- TypeMap.new()+ TypeMap map <- TypeMap.default() TypeKey<Int> keyInt <- TypeKey<Int>.new() TypeKey<String> keyString <- TypeKey<String>.new() TypeKey<Value> keyValue <- TypeKey<Value>.new() - \ Testing.checkOptional(tree.get(keyInt), empty)- \ Testing.checkOptional(tree.get(keyString),empty)- \ Testing.checkOptional(tree.get(keyValue), empty)+ \ Testing.checkOptional(map.get(keyInt), empty)+ \ Testing.checkOptional(map.get(keyString),empty)+ \ Testing.checkOptional(map.get(keyValue), empty) - \ tree.set(keyInt,1)- \ tree.set(keyString,"a")- \ tree.set(keyValue,Value.new())+ \ map.set(keyInt,1)+ \ map.set(keyString,"a")+ \ map.set(keyValue,Value.new()) - \ Testing.checkOptional(tree.get(keyInt), 1)- \ Testing.checkOptional(tree.get(keyString),"a")- \ Testing.checkOptional(tree.get(keyValue), Value.new())+ \ Testing.checkOptional(map.get(keyInt), 1)+ \ Testing.checkOptional(map.get(keyString),"a")+ \ Testing.checkOptional(map.get(keyValue), Value.new()) - \ tree.remove(keyString)+ \ map.remove(keyString) - \ Testing.checkOptional(tree.get(keyString),empty)+ \ Testing.checkOptional(map.get(keyString),empty) } unittest wrongReturnType {- TypeMap tree <- TypeMap.new()+ TypeMap map <- TypeMap.new() TypeKey<String> keyString <- TypeKey<String>.new() // Added as Formatted, which means it cannot be retrieved as String later.- \ tree.set<Formatted>(keyString,"a")- \ Testing.checkOptional(tree.get<String>(keyString),empty)+ \ map.set<Formatted>(keyString,"a")+ \ Testing.checkOptional(map.get<String>(keyString),empty) - \ tree.set<String>(keyString,"a")- \ Testing.checkOptional(tree.get<String>(keyString),"a")+ \ map.set<String>(keyString,"a")+ \ Testing.checkOptional(map.get<String>(keyString),"a") } unittest duplicate { TypeKey<Int> keyInt <- TypeKey<Int>.new() TypeKey<String> keyString <- TypeKey<String>.new() - TypeMap tree <- TypeMap.new().set(keyInt,1).set(keyString,"a")+ TypeMap map <- TypeMap.new().set(keyInt,1).set(keyString,"a") - TypeMap copy <- tree.duplicate()+ TypeMap copy <- map.duplicate() \ Testing.checkOptional(copy.get(keyInt),1) \ Testing.checkOptional(copy.get(keyString),"a") \ copy.remove(keyString) \ Testing.checkOptional(copy.get(keyInt),1) \ Testing.checkOptional(copy.get(keyString),empty)- \ Testing.checkOptional(tree.get(keyString),"a")+ \ Testing.checkOptional(map.get(keyString),"a") } unittest getValues {- TypeMap tree <- TypeMap.new()+ TypeMap map <- TypeMap.new() .set(TypeKey<String>.new(),"one") .set(TypeKey<Int>.new(),2) .set(TypeKey<String>.new(),"two") .set(TypeKey<Int>.new(),1) - [Container&SetReader<String>] actual <- tree.getAll(TreeSet<String>.new())+ [Container&SetReader<String>] actual <- map.getAll(SortedSet<String>.new()) \ Testing.checkEquals(actual.size(),2) \ Testing.checkTrue(actual.member("one"))@@ -94,6 +94,12 @@ \ Testing.checkEquals<TypeKey<Int>>(key1,key1) \ Testing.checkFalse(key1 `TypeKey<any>.equals` key2) \ Testing.checkFalse(key1 `TypeKey<any>.equals` key3)+}++unittest keyHashed {+ TypeKey<Int> key1 <- TypeKey<Int>.new()+ TypeKey<Int> key2 <- TypeKey<Int>.new()+ \ Testing.checkNotEquals(key1.hashed(),key2.hashed()) } concrete Value {
lib/container/test/vector.0rt view
@@ -33,22 +33,8 @@ } } -unittest copyFrom {- String original <- "abcde"- Vector<Char> values <- Vector:copyFrom(original)- \ Testing.checkEquals(values.size(),original.size())-- scoped {- Int i <- 0- } in while (i < original.size()) {- \ Testing.checkEquals(values.readAt(i),original.readAt(i))- } update {- i <- i+1- }-}- unittest append {- Vector<Int> values <- Vector:create<Int>()+ Vector<Int> values <- Vector<Int>.new() scoped { Int i <- 0@@ -70,7 +56,7 @@ } unittest pushAndPop {- Vector<Int> values <- Vector:create<Int>()+ Vector<Int> values <- Vector<Int>.new() scoped { Int i <- 0@@ -115,7 +101,7 @@ unittest traverseVector { Int index <- 0- Vector<Int> vector <- Vector:create<Int>()+ Vector<Int> vector <- Vector<Int>.new() \ vector.push(2) \ vector.push(6) \ vector.push(3)@@ -132,20 +118,38 @@ } unittest duplicate {- Vector<Int> vector <- Vector:create<Int>().push(1).push(2)+ 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.writeAt(1,3) \ copy.pop() \ Testing.checkEquals(copy.size(),1) \ Testing.checkEquals(copy.readAt(0),1) \ Testing.checkEquals(vector.readAt(1),2) } +concrete Value {+ refines Duplicate + @type new (Int) -> (#self)+ @value set (Int) -> ()+ @value get () -> (Int)+}++define Value {+ @value Int value++ new (value) { return Value{ value } }+ set (value2) { value <- value2 }+ get () { return value }+ duplicate () { return new(value) }+}++ testcase "distinct default values in pre-sized Vector" { success }@@ -211,7 +215,7 @@ } unittest test {- Vector<Int> values <- Vector:create<Int>()+ Vector<Int> values <- Vector<Int>.new() \ values.readAt(-1) } @@ -221,6 +225,6 @@ } unittest test {- Vector<Int> values <- Vector:create<Int>()+ Vector<Int> values <- Vector<Int>.new() \ values.readAt(1) }
− lib/container/tree-set.0rp
@@ -1,62 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 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]--concrete TreeSet<#k> {- refines Append<#k>- refines Container- refines DefaultOrder<#k>- refines Duplicate- refines SetReader<#k>- refines SetWriter<#k>- #k immutable- #k defines LessThan<#k>-- // Create a new set.- @type new () -> (#self)-- // Traverse in the default order.- //- // Notes:- // - This is from DefaultOrder, but is made explicit for documentation.- // - Traversal of the entire set 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<#k>)-- // Traverse the set in the reverse order of defaultOrder().- //- // Notes:- // - Traversal of the entire set 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<#k>)-- // Start forward traversal (same as defaultOrder()) from the specified key.- //- // Notes:- // - If the key does not exist in the SearchTree, the position right after- // where it would be (in the forward direction) is returned.- @value getForward (#k) -> (optional Order<#k>)-- // Start reverse traversal (same as reverseOrder()) from the specified key.- //- // Notes:- // - If the key does not exist in the SearchTree, the position right after- // where it would be (in the reverse direction) is returned.- @value getReverse (#k) -> (optional Order<#k>)-}
lib/container/type-map.0rp view
@@ -18,6 +18,7 @@ // A map that stores values of arbitrary types. concrete TypeMap {+ defines Default refines Duplicate // Create a new map.@@ -56,6 +57,7 @@ immutable refines Formatted+ refines Hashed defines LessThan<TypeKey<any>> defines Equals<TypeKey<any>>
lib/container/vector.0rp view
@@ -21,18 +21,17 @@ // Params: // - #x: The value type contained. concrete Vector<#x> {+ defines Default refines Append<#x> refines DefaultOrder<#x>+ // Does not duplicate individual elements. refines Duplicate refines Stack<#x> refines ReadAt<#x> refines WriteAt<#x> - // Create a copy from another random-access container.- @category copyFrom<#y> (ReadAt<#y>) -> (Vector<#y>)- // Create an empty Vector.- @category create<#y> () -> (Vector<#y>)+ @type new () -> (#self) // Create a pre-sized vector of default values. //
lib/math/categorical-tree.0rp view
@@ -16,10 +16,38 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] +// A read-only categorical distribution.+//+// Params:+// - #c: The type of category (i.e., object) used in the distribution.+@value interface CategoricalReader<#c> {+ // Get the sum of all weights in the distribution.+ getTotal () -> (Int)++ // Get the relative weight of a value.+ //+ // Notes:+ // - If the category isn't present, its weight is 0.+ getWeight (#c) -> (Int)++ // Return the value at the given offset.+ //+ // Notes:+ // - 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+ // CategoricalReader, each repeated the number of times indicated by its+ // respective weight.+ // - Also see RandomCategorical in random.0rp.+ locate (Int) -> (#c)+}+ // A categorical distribution represented as a tree. // // Params:-// #c: The type of category (i.e., object) used in the distribution.+// - #c: The type of category (i.e., object) used in the distribution. // // Notes: // - CategoricalTree is intended for use in random sampling of arbitrary objects@@ -31,17 +59,16 @@ // - The required storage space is independent of the weights; it only depends // on the number of distinct #c values with non-zero weights. concrete CategoricalTree<#c> {- refines ReadAt<#c>+ defines Default+ refines CategoricalReader<#c> refines Duplicate+ refines ReadAt<#c> #c immutable #c defines LessThan<#c> // Create a new distribution. @type new () -> (#self) - // Get the sum of all weights in the distribution.- @value getTotal () -> (Int)- // Set the relative weight of a value. // // Notes:@@ -49,12 +76,6 @@ // - The sum of all weights (see getTotal()) must not exceed Int.maxBound(). @value setWeight (#c,Int) -> (#self) - // Get the relative weight of a value.- //- // Notes:- // - If the category isn't in the tree, its weight is 0.- @value getWeight (#c) -> (Int)- // Increments the weight of the value by 1. @value incrWeight (#c) -> (#self) @@ -64,18 +85,6 @@ // - Do not call this for values that already have 0 weight. This is primarily // meant for use when locate is used to choose a value to decrement. @value decrWeight (#c) -> (#self)-- // Return the value at the given offset.- //- // Notes:- // - 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- // CategoricalTree, each repeated the number of times indicated by its- // respective weight.- @value locate (Int) -> (#c) // Identical to locate(). (From ReadAt.) @value readAt (Int) -> (#c)
lib/math/random.0rp view
@@ -50,10 +50,42 @@ // Creates a new generator with the specified min and max values. @type new (Float,Float) -> (#self) + // Creates a new generator for the range [0.0,1.0).+ @type probability () -> (#self)+ // Resets the seed for RNG. @value setSeed (Int) -> (#self) } +// Always returns a constant value.+concrete GenerateConstant {+ refines Generator<Float>++ // Creates a new generator with the specified constant values.+ @type new (Float) -> (#self)+}++// Generates values of the provided type.+concrete RandomCategorical<|#c> {+ refines Generator<#c>++ // Creates a generator for the provided distribution.+ //+ // Notes:+ // - 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>)++ // Returns true if the distribution is empty.+ //+ // Note:+ // - Do not call generate() if this returns true, since there are no values to+ // sample from.+ @value isEmpty () -> (Bool)+}++// General randomization functions. concrete Randomize { // Creates a permutation from the CategoricalTree. //@@ -62,5 +94,17 @@ // // Notes: // - 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>) -> ()++ // Creates a permutation from the CategoricalTree.+ //+ // 1. Creates a copy of the CategoricalTree.+ // 2. Samples from the copy *without* replacement until the tree is empty.+ //+ // Notes:+ // - 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>) -> () }
lib/math/src/Extension_RandomUniform.cpp view
@@ -45,6 +45,11 @@ } return ReturnTuple(CreateValue_RandomUniform(PARAM_SELF, params_args)); }++ ReturnTuple Call_probability(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("RandomUniform.probability")+ return Call_new(PassParamsArgs(Box_Float(0.0), Box_Float(1.0)));+ } }; struct ExtValue_RandomUniform : public Value_RandomUniform {
lib/math/src/categorical-tree.0rx view
@@ -19,6 +19,10 @@ define CategoricalTree { @value AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>> tree + default () {+ return new()+ }+ new () { return #self{ AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>>.new() } }@@ -35,9 +39,9 @@ if (size < 0) { fail("size must not be negative") } elif (size > 0) {- \ tree.set(cat,size)+ \ tree.swap(cat,size) } else {- \ tree.remove(cat)+ \ tree.swap(cat,empty) } return self }@@ -96,9 +100,9 @@ if (size < 0) { fail("size must not be negative") } elif (size > 0) {- \ tree.set(cat,size)+ \ tree.swap(cat,size) } else {- \ tree.remove(cat)+ \ tree.swap(cat,empty) } \ validateTotal(tree.getRoot()) return self
lib/math/src/random.0rx view
@@ -19,11 +19,56 @@ define Randomize { permuteFrom (tree,random,output) { CategoricalTree<#c> copy <- tree.duplicate()- $Hidden[tree]$+ Generator<#c> generator <- copy `RandomCategorical:sampleWith` random+ $Hidden[tree,random]$ while (copy.getTotal() > 0) {- #c cat <- copy.locate((random.generate()*copy.getTotal().asFloat()).asInt())+ #c cat <- generator.generate() \ output.append(cat) \ copy.decrWeight(cat) }+ }++ permuteFromWeight (tree,random,output) {+ CategoricalTree<#c> copy <- tree.duplicate()+ Generator<#c> generator <- copy `RandomCategorical:sampleWith` random+ $Hidden[tree,random]$+ while (copy.getTotal() > 0) {+ #c cat <- generator.generate()+ \ output.append(cat)+ \ copy.setWeight(cat,0)+ }+ }+}++define GenerateConstant {+ $ReadOnly[constant]$++ @value Float constant++ new (constant) {+ return GenerateConstant{ constant }+ }++ generate () {+ return constant+ }+}++define RandomCategorical {+ $ReadOnly[categorical,random]$++ @value CategoricalReader<#c> categorical+ @value Generator<Float> random++ sampleWith (categorical,random) {+ return RandomCategorical<#c>{ categorical, random }+ }++ generate () {+ return categorical.locate((categorical.getTotal().asFloat()*random.generate()).asInt())+ }++ isEmpty () {+ return categorical.getTotal() == 0 } }
lib/math/src/token.0rx view
@@ -20,7 +20,7 @@ $ReadOnly[mutex,toToken]$ @category Mutex mutex <- SpinlockMutex.new()- @category SearchTree<String,Token> toToken <- SearchTree<String,Token>.new()+ @category HashedMap<String,Token> toToken <- HashedMap<String,Token>.new() @category Int counter <- 0 @value String string@@ -41,6 +41,10 @@ formatted () { return string+ }++ hashed () {+ return value.hashed() } equals (x,y) {
lib/math/test/categorical-tree.0rt view
@@ -21,7 +21,7 @@ } unittest simpleInsertion {- CategoricalTree<Int> tree <- CategoricalTree<Int>.new()+ CategoricalTree<Int> tree <- CategoricalTree<Int>.default() .setWeight(1,3) .setWeight(6,2) .setWeight(3,1)@@ -29,7 +29,7 @@ .setWeight(4,3) .setWeight(2,7) - Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() .push(1).push(1).push(1) .push(2).push(2).push(2).push(2).push(2).push(2).push(2) .push(3)@@ -63,7 +63,7 @@ .setWeight(5,1) .setWeight(3,0) - Vector<Int> expected <- Vector:create<Int>()+ Vector<Int> expected <- Vector<Int>.new() .push(1).push(1).push(1) .push(2).push(2).push(2).push(2).push(2).push(2).push(2) .push(4).push(4).push(4)@@ -126,8 +126,8 @@ } unittest integrationTest { $DisableCoverage$- ValidatedTree<Int> tree <- ValidatedTree<Int>.new()- SearchTree<Int,Int> expected <- SearchTree<Int,Int>.new()+ ValidatedTree<Int> tree <- ValidatedTree<Int>.new()+ SortedMap<Int,Int> expected <- SortedMap<Int,Int>.new() Int count <- 137 Int maxSize <- 15
lib/math/test/random.0rt view
@@ -35,7 +35,29 @@ Float value <- random.generate() } +unittest probability {+ Generator<Float> random <- RandomUniform.probability()+ Float value <- random.generate()+} +unittest constant {+ Generator<Float> random <- GenerateConstant.new(1.0)+ Float value <- random.generate()+}++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)+ RandomCategorical<Float> random <- tree `RandomCategorical:sampleWith` RandomUniform.probability()+ \ Testing.checkFalse(random.isEmpty())+ Float value <- random.generate()+}++ testcase "negative lambda in exponential" { crash require "lambda"@@ -69,6 +91,19 @@ } +testcase "sampling with empty CategoricalTree" {+ crash+ 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())+ Float value <- random.generate()+}++ testcase "distribution sanity checks" { success }@@ -121,10 +156,61 @@ sum <- sum+value } - \ Testing.checkBetween(sum/count.asFloat(),min-0.1*(max-min),max-0.1*(max-min))+ \ Testing.checkBetween(sum/count.asFloat(),(min+max)/2.0-0.1*(max-min),(min+max)/2.0+0.1*(max-min)) } +unittest probability { $DisableCoverage$+ Int count <- 10000+ $ReadOnly[count]$ + Generator<Float> random <- RandomUniform.probability()++ Float sum <- 0.0+ traverse (Counter.zeroIndexed(count) -> _) {+ Float value <- random.generate()+ \ Testing.checkBetween(value,0.0,1.0)+ sum <- sum+value+ }++ \ Testing.checkBetween(sum/count.asFloat(),0.4,0.6)+}++unittest constant { $DisableCoverage$+ Int count <- 10000+ Float constant <- 12345.0+ $ReadOnly[count,constant]$++ Generator<Float> random <- GenerateConstant.new(constant)++ traverse (Counter.zeroIndexed(count) -> _) {+ Float value <- random.generate()+ \ Testing.checkEquals(constant,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]$++ 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)+ sum <- sum+value+ }++ \ Testing.checkBetween(sum/count.asFloat(),1.9,2.1)+}++ testcase "distribution seed checks" { success }@@ -143,8 +229,8 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkFalse(v1 == v2)- \ Testing.checkFalse(v1 == v3)+ \ Testing.checkNotEquals(v1,v2)+ \ Testing.checkNotEquals(v1,v3) \ Testing.checkEquals(v3,v4) } @@ -163,8 +249,8 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkFalse(v1 == v2)- \ Testing.checkFalse(v1 == v3)+ \ Testing.checkNotEquals(v1,v2)+ \ Testing.checkNotEquals(v1,v3) \ Testing.checkEquals(v3,v4) } @@ -183,8 +269,8 @@ random2 <- random2.setSeed(123) Float v4 <- random2.generate() - \ Testing.checkFalse(v1 == v2)- \ Testing.checkFalse(v1 == v3)+ \ Testing.checkNotEquals(v1,v2)+ \ Testing.checkNotEquals(v1,v3) \ Testing.checkEquals(v3,v4) } @@ -199,7 +285,7 @@ .setWeight("b",3) .setWeight("c",1) - Vector<String> expected <- Vector:create<String>()+ Vector<String> expected <- Vector<String>.new() .append("a") .append("a") .append("b")@@ -207,8 +293,33 @@ .append("b") .append("c") - Vector<String> output <- Vector:create<String>()+ Vector<String> output <- Vector<String>.new() \ Randomize:permuteFrom(tree,RandomUniform.new(0.0,1.0),output)+ \ Sorting:sort(output)++ \ Testing.checkEquals(output.size(),expected.size())+ traverse (Counter.zeroIndexed(output.size()) -> Int pos) {+ \ Testing.checkEquals(output.readAt(pos),expected.readAt(pos))+ }++ \ Testing.checkEquals(tree.getWeight("a"),2)+ \ Testing.checkEquals(tree.getWeight("b"),3)+ \ Testing.checkEquals(tree.getWeight("c"),1)+}++unittest permuteFromWeight {+ CategoricalTree<String> tree <- CategoricalTree<String>.new()+ .setWeight("a",2)+ .setWeight("b",3)+ .setWeight("c",1)++ Vector<String> expected <- Vector<String>.new()+ .append("a")+ .append("b")+ .append("c")++ Vector<String> output <- Vector<String>.new()+ \ Randomize:permuteFromWeight(tree,RandomUniform.new(0.0,1.0),output) \ Sorting:sort(output) \ Testing.checkEquals(output.size(),expected.size())
lib/math/test/token.0rt view
@@ -34,3 +34,9 @@ unittest formatted { \ Testing.checkEquals(Token.from("message").formatted(),"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())+}
lib/math/token.0rp view
@@ -22,6 +22,7 @@ defines Equals<Token> // LessThan is not lexicographical. defines LessThan<Token>+ refines Hashed refines Formatted // Get a Token from the provided String.
lib/testing/helpers.0rp view
@@ -30,6 +30,16 @@ #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:
lib/testing/src/helpers.0rx view
@@ -29,6 +29,16 @@ } } + 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 {
lib/testing/test/tests.0rt view
@@ -36,6 +36,25 @@ } +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 }
lib/util/.zeolite-module view
@@ -15,6 +15,14 @@ ] extra_files: [ category_source {+ source: "lib/util/src/Extension_BasicInput.cpp"+ categories: [BasicInput]+ }+ category_source {+ source: "lib/util/src/Extension_BasicOutput.cpp"+ categories: [BasicOutput]+ }+ category_source { source: "lib/util/src/Extension_Argv.cpp" categories: [Argv] }@@ -23,16 +31,8 @@ categories: [MutexLock] } category_source {- source: "lib/util/src/Extension_SimpleInput.cpp"- categories: [SimpleInput]- }- category_source { source: "lib/util/src/Extension_SimpleMutex.cpp" categories: [SimpleMutex]- }- category_source {- source: "lib/util/src/Extension_SimpleOutput.cpp"- categories: [SimpleOutput] } category_source { source: "lib/util/src/Extension_SpinlockMutex.cpp"
lib/util/extra.0rp view
@@ -19,18 +19,17 @@ // A type with only one value. // // Notes:+// - Get the Void value using Void.default(). // - The built-in type with no values is the meta-type all. Void should be used // when an actual value is required but no other type makes sense. concrete Void { immutable-- refines Formatted-+ defines Default defines Equals<Void> defines LessThan<Void>-- // Return the only value of type Void.- @type void () -> (Void)+ refines Duplicate+ refines Formatted+ refines Hashed } // Contains either a value or an error message.
lib/util/helpers.0rp view
@@ -65,6 +65,39 @@ @category equalsWith<#x,#xx> #xx defines Equals<#x> (optional Order<#x>,optional Order<#x>) -> (Bool)++ // Copies references to all elements to the destination.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #c: Container type.+ //+ // Args:+ // - optional Order<#x>: Element source.+ // - #c: Output container.+ //+ // Returns:+ // - #c: The container originally passed.+ @category copyTo<#x,#c>+ #c requires Append<#x>+ (optional Order<#x>,#c) -> (#c)++ // Duplicates all elements to the destination.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #c: Container type.+ //+ // Args:+ // - optional Order<#x>: Element source.+ // - #c: Output container.+ //+ // Returns:+ // - #c: The container originally passed.+ @category duplicateTo<#x,#c>+ #x requires Duplicate+ #c requires Append<#x>+ (optional Order<#x>,#c) -> (#c) } // Helpers to extend functionality to the ReadAt<#x> built-in.@@ -116,8 +149,65 @@ @category equalsWith<#x,#xx> #xx defines Equals<#x> (ReadAt<#x>,ReadAt<#x>) -> (Bool)++ // Copies references to all elements to the destination.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #c: Container type.+ //+ // Args:+ // - ReadAt<#x>: Element source.+ // - #c: Output container.+ //+ // Returns:+ // - #c: The container originally passed.+ @category copyTo<#x,#c>+ #c requires Append<#x>+ (ReadAt<#x>,#c) -> (#c)++ // Duplicates all elements to the destination.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #c: Container type.+ //+ // Args:+ // - ReadAt<#x>: Element source.+ // - #c: Output container.+ //+ // Returns:+ // - #c: The container originally passed.+ @category duplicateTo<#x,#c>+ #x requires Duplicate+ #c requires Append<#x>+ (ReadAt<#x>,#c) -> (#c)++ // Iterates over the container from 0 to the end.+ @category forwardOrder<#x> (ReadAt<#x>) -> (optional Order<#x>)++ // Iterates over the container from the end to 0.+ @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>) } +// Helpers to extend functionality to the Formatted built-in.+concrete FormattedH {+ // Attempts to convert the value to Formatted.+ //+ // Notes:+ // - This is primarily meant for debugging and logging. Program logic should+ // not rely on the returned values.+ // - If the value is not Formatted, a fabricated Formatted will be returned.+ //+ // Example:+ //+ // fail(FormattedH:try(badValue))+ @category try<#x> (optional #x) -> (Formatted)+}+ // Reverse an existing LessThan<#x> comparison. concrete Reversed<#x|> { defines LessThan<#x>@@ -138,4 +228,15 @@ concrete AlwaysEqual { defines Equals<any> defines LessThan<any>+}++// Creates a LessThan2 from a LessThan.+//+// Params:+// - #x: Object type to be compared.+// - #xx: Comparator for #x.+concrete AsLessThan2<#x|#xx|> {+ #xx defines LessThan<#x>++ @type new () -> (LessThan2<#x>) }
lib/util/input.0rp view
@@ -54,10 +54,10 @@ @value pastEnd () -> (Bool) } -// Simple input sources.-concrete SimpleInput {+// Basic input sources.+concrete BasicInput { refines BlockReader<String> // Returns a BlockReader for standard input.- @type stdin () -> (BlockReader<String>)+ @type stdin () -> (#self) }
lib/util/interfaces.0rp view
@@ -16,14 +16,7 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -// Can be duplicated.-@value interface Duplicate {- // Creates a duplicate that can be mutated without changing the original.- //- // Notes:- // - This does not need to be a deep copy. The only requirement is that- // mutating functions can be called on the copy without counterintuitive- // results. For example, if the object is a container, the duplicate could- // be a copy of the structure, while still referring to the same objects.- duplicate () -> (#self)+// A @value version of the LessThan @type interface.+@value interface LessThan2<#x|> {+ lessThan2 (#x,#x) -> (Bool) }
lib/util/output.0rp view
@@ -21,7 +21,7 @@ // Params: // - #x: The value type to be written. @value interface Writer<#x|> {- write (#x) -> ()+ write (#x) -> (#self) } // A sink that can be flushed.@@ -31,7 +31,7 @@ @value interface BufferedWriter<#x|> { refines Writer<#x> - flush () -> ()+ flush () -> (#self) } // A sink that might perform a partial write.@@ -43,27 +43,18 @@ writeBlock (#x) -> (Int) } -// A lazy output stream that delays writing.-//-// Params:-// - #x: The value type to be written.-concrete LazyStream<#x> {- refines Append<#x>-- // Create a new stream.- @type new () -> (LazyStream<#x>)- // Write the data to the BufferedWriter. (Do not mutate the stream.)- @value writeTo (BufferedWriter<#x>) -> ()-}--// Simple output destinations.-concrete SimpleOutput {+// Basic output destinations.+concrete BasicOutput {+ refines Append<Formatted> refines BufferedWriter<Formatted> - // Returns a BufferedWriter for standard output.- @type stdout () -> (BufferedWriter<Formatted>)- // Returns a BufferedWriter for standard error.- @type stderr () -> (BufferedWriter<Formatted>)- // Returns a BufferedWriter that crashes with the output as the error message.- @type error () -> (BufferedWriter<Formatted>)+ // Immediately writes the data and flushes the buffer.+ @value writeNow (Formatted) -> (#self)++ // Standard output writer.+ @type stdout () -> (#self)+ // Standard error writer.+ @type stderr () -> (#self)+ // Crashes with the written data as the error when flushed.+ @type error () -> (#self) }
+ lib/util/src/Extension_BasicInput.cpp view
@@ -0,0 +1,97 @@+/* -----------------------------------------------------------------------------+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]++// TODO: Maybe use C++ instead.+#include <unistd.h>++#include "category-source.hpp"+#include "Streamlined_BasicInput.hpp"+#include "Category_Formatted.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++namespace {+extern const BoxedValue Var_stdin;+} // namespace++struct ExtCategory_BasicInput : public Category_BasicInput {+};++struct ExtType_BasicInput : public Type_BasicInput {+ inline ExtType_BasicInput(Category_BasicInput& p, Params<0>::Type params) : Type_BasicInput(p, params) {}++ ReturnTuple Call_stdin(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("BasicInput.stdin")+ return ReturnTuple(Var_stdin);+ }+};++struct ExtValue_BasicInput : public Value_BasicInput {+ inline ExtValue_BasicInput(S<const Type_BasicInput> p)+ : Value_BasicInput(std::move(p)) {}++ ReturnTuple Call_pastEnd(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicInput.pastEnd")+ std::lock_guard<std::mutex> lock(mutex);+ return ReturnTuple(Box_Bool(zero_read));+ }++ ReturnTuple Call_readBlock(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicInput.readBlock")+ std::lock_guard<std::mutex> lock(mutex);+ const int size = params_args.GetArg(0).AsInt();+ if (size < 0) {+ FAIL() << "Read size " << size << " is invalid";+ }+ std::string buffer(size, '\x00');+ const int read_size = read(STDIN_FILENO, &buffer[0], size);+ if (read_size < 0) {+ return ReturnTuple(Box_String(""));+ } else {+ zero_read = read_size == 0;+ return ReturnTuple(Box_String(buffer.substr(0, read_size)));+ }+ }++ bool zero_read = false;+ std::mutex mutex;+};++namespace {+const BoxedValue Var_stdin = BoxedValue::New<ExtValue_BasicInput>(CreateType_BasicInput(Params<0>::Type()));+} // namespace++Category_BasicInput& CreateCategory_BasicInput() {+ static auto& category = *new ExtCategory_BasicInput();+ return category;+}++S<const Type_BasicInput> CreateType_BasicInput(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_BasicInput(CreateCategory_BasicInput(), Params<0>::Type()));+ return cached;+}++void RemoveType_BasicInput(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ lib/util/src/Extension_BasicOutput.cpp view
@@ -0,0 +1,154 @@+/* -----------------------------------------------------------------------------+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 <iostream>+#include <mutex>+#include <sstream>++#include "category-source.hpp"+#include "Streamlined_BasicOutput.hpp"+#include "Category_Formatted.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++namespace {+extern const BoxedValue Var_stdout;+extern const BoxedValue Var_stderr;+extern const BoxedValue Var_error;+} // namespace++struct ExtCategory_BasicOutput : public Category_BasicOutput {+};++struct ExtType_BasicOutput : public Type_BasicOutput {+ inline ExtType_BasicOutput(Category_BasicOutput& p, Params<0>::Type params) : Type_BasicOutput(p, params) {}++ ReturnTuple Call_error(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("BasicOutput.error")+ return ReturnTuple(Var_error);+ }++ ReturnTuple Call_stderr(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("BasicOutput.stderr")+ return ReturnTuple(Var_stderr);+ }++ ReturnTuple Call_stdout(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("BasicOutput.stdout")+ return ReturnTuple(Var_stdout);+ }+};++namespace {+struct Writer {+ virtual void Write(const PrimString& message) = 0;+ virtual void Flush() = 0;+ virtual ~Writer() {}+};+} // namespace++struct ExtValue_BasicOutput : public Value_BasicOutput {+ inline ExtValue_BasicOutput(S<const Type_BasicOutput> p, S<Writer> w)+ : Value_BasicOutput(std::move(p)), writer(w) {}++ ReturnTuple Call_append(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicOutput.append")+ return Call_write(params_args);+ }++ ReturnTuple Call_flush(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicOutput.flush")+ std::lock_guard<std::mutex> lock(mutex);+ writer->Flush();+ return ReturnTuple(VAR_SELF);+ }++ ReturnTuple Call_write(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicOutput.write")+ const BoxedValue& Var_arg1 = (params_args.GetArg(0));+ std::lock_guard<std::mutex> lock(mutex);+ writer->Write(TypeValue::Call(params_args.GetArg(0), Function_Formatted_formatted,+ PassParamsArgs()).At(0).AsString());+ return ReturnTuple(VAR_SELF);+ }++ ReturnTuple Call_writeNow(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("BasicOutput.writeNow")+ (void) Call_write(params_args);+ (void) Call_flush(PassParamsArgs());+ return ReturnTuple(VAR_SELF);+ }++ std::mutex mutex;+ const S<Writer> writer;+};++namespace {++class StreamWriter : public Writer {+ public:+ StreamWriter(std::ostream& o) : output(o) {}++ void Write(const PrimString& message) final {+ output << message;+ }++ void Flush() final {}++ private:+ std::ostream& output;+};++class ErrorWriter : public Writer {+ public:+ void Write(const PrimString& message) final {+ output << message;+ }++ void Flush() final {+ FAIL() << output.str();+ }++ std::ostringstream output;+};++const BoxedValue Var_stdout = BoxedValue::New<ExtValue_BasicOutput>(CreateType_BasicOutput(Params<0>::Type()), S_get(new StreamWriter(std::cout)));+const BoxedValue Var_stderr = BoxedValue::New<ExtValue_BasicOutput>(CreateType_BasicOutput(Params<0>::Type()), S_get(new StreamWriter(std::cerr)));+const BoxedValue Var_error = BoxedValue::New<ExtValue_BasicOutput>(CreateType_BasicOutput(Params<0>::Type()), S_get(new ErrorWriter()));++} // namespace++Category_BasicOutput& CreateCategory_BasicOutput() {+ static auto& category = *new ExtCategory_BasicOutput();+ return category;+}++S<const Type_BasicOutput> CreateType_BasicOutput(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_BasicOutput(CreateCategory_BasicOutput(), Params<0>::Type()));+ return cached;+}++void RemoveType_BasicOutput(const Params<0>::Type& params) {}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
− lib/util/src/Extension_SimpleInput.cpp
@@ -1,97 +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]--// TODO: Maybe use C++ instead.-#include <unistd.h>--#include "category-source.hpp"-#include "Streamlined_SimpleInput.hpp"-#include "Category_Formatted.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--namespace {-extern const BoxedValue Var_stdin;-} // namespace--struct ExtCategory_SimpleInput : public Category_SimpleInput {-};--struct ExtType_SimpleInput : public Type_SimpleInput {- inline ExtType_SimpleInput(Category_SimpleInput& p, Params<0>::Type params) : Type_SimpleInput(p, params) {}-- ReturnTuple Call_stdin(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("SimpleInput.stdin")- return ReturnTuple(Var_stdin);- }-};--struct ExtValue_SimpleInput : public Value_SimpleInput {- inline ExtValue_SimpleInput(S<const Type_SimpleInput> p)- : Value_SimpleInput(std::move(p)) {}-- ReturnTuple Call_pastEnd(const ParamsArgs& params_args) final {- TRACE_FUNCTION("SimpleInput.pastEnd")- std::lock_guard<std::mutex> lock(mutex);- return ReturnTuple(Box_Bool(zero_read));- }-- ReturnTuple Call_readBlock(const ParamsArgs& params_args) final {- TRACE_FUNCTION("SimpleInput.readBlock")- std::lock_guard<std::mutex> lock(mutex);- const int size = params_args.GetArg(0).AsInt();- if (size < 0) {- FAIL() << "Read size " << size << " is invalid";- }- std::string buffer(size, '\x00');- const int read_size = read(STDIN_FILENO, &buffer[0], size);- if (read_size < 0) {- return ReturnTuple(Box_String(""));- } else {- zero_read = read_size == 0;- return ReturnTuple(Box_String(buffer.substr(0, read_size)));- }- }-- bool zero_read = false;- std::mutex mutex;-};--namespace {-const BoxedValue Var_stdin = BoxedValue::New<ExtValue_SimpleInput>(CreateType_SimpleInput(Params<0>::Type()));-} // namespace--Category_SimpleInput& CreateCategory_SimpleInput() {- static auto& category = *new ExtCategory_SimpleInput();- return category;-}--S<const Type_SimpleInput> CreateType_SimpleInput(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_SimpleInput(CreateCategory_SimpleInput(), Params<0>::Type()));- return cached;-}--void RemoveType_SimpleInput(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
− lib/util/src/Extension_SimpleOutput.cpp
@@ -1,142 +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 <iostream>-#include <mutex>-#include <sstream>--#include "category-source.hpp"-#include "Streamlined_SimpleOutput.hpp"-#include "Category_Formatted.hpp"-#include "Category_String.hpp"--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--namespace {-extern const BoxedValue Var_stdout;-extern const BoxedValue Var_stderr;-extern const BoxedValue Var_error;-} // namespace--struct ExtCategory_SimpleOutput : public Category_SimpleOutput {-};--struct ExtType_SimpleOutput : public Type_SimpleOutput {- inline ExtType_SimpleOutput(Category_SimpleOutput& p, Params<0>::Type params) : Type_SimpleOutput(p, params) {}-- ReturnTuple Call_error(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("SimpleOutput.error")- return ReturnTuple(Var_error);- }-- ReturnTuple Call_stderr(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("SimpleOutput.stderr")- return ReturnTuple(Var_stderr);- }-- ReturnTuple Call_stdout(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("SimpleOutput.stdout")- return ReturnTuple(Var_stdout);- }-};--namespace {-struct Writer {- virtual void Write(const PrimString& message) = 0;- virtual void Flush() = 0;- virtual ~Writer() {}-};-} // namespace--struct ExtValue_SimpleOutput : public Value_SimpleOutput {- inline ExtValue_SimpleOutput(S<const Type_SimpleOutput> p, S<Writer> w)- : Value_SimpleOutput(std::move(p)), writer(w) {}-- ReturnTuple Call_flush(const ParamsArgs& params_args) final {- TRACE_FUNCTION("SimpleOutput.flush")- std::lock_guard<std::mutex> lock(mutex);- writer->Flush();- return ReturnTuple();- }-- ReturnTuple Call_write(const ParamsArgs& params_args) final {- TRACE_FUNCTION("SimpleOutput.write")- const BoxedValue& Var_arg1 = (params_args.GetArg(0));- std::lock_guard<std::mutex> lock(mutex);- writer->Write(TypeValue::Call(params_args.GetArg(0), Function_Formatted_formatted,- PassParamsArgs()).At(0).AsString());- return ReturnTuple();- }-- std::mutex mutex;- const S<Writer> writer;-};--namespace {--class StreamWriter : public Writer {- public:- StreamWriter(std::ostream& o) : output(o) {}-- void Write(const PrimString& message) final {- output << message;- }-- void Flush() final {}-- private:- std::ostream& output;-};--class ErrorWriter : public Writer {- public:- void Write(const PrimString& message) final {- output << message;- }-- void Flush() final {- FAIL() << output.str();- }-- std::ostringstream output;-};--const BoxedValue Var_stdout = BoxedValue::New<ExtValue_SimpleOutput>(CreateType_SimpleOutput(Params<0>::Type()), S_get(new StreamWriter(std::cout)));-const BoxedValue Var_stderr = BoxedValue::New<ExtValue_SimpleOutput>(CreateType_SimpleOutput(Params<0>::Type()), S_get(new StreamWriter(std::cerr)));-const BoxedValue Var_error = BoxedValue::New<ExtValue_SimpleOutput>(CreateType_SimpleOutput(Params<0>::Type()), S_get(new ErrorWriter()));--} // namespace--Category_SimpleOutput& CreateCategory_SimpleOutput() {- static auto& category = *new ExtCategory_SimpleOutput();- return category;-}--S<const Type_SimpleOutput> CreateType_SimpleOutput(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_SimpleOutput(CreateCategory_SimpleOutput(), Params<0>::Type()));- return cached;-}--void RemoveType_SimpleOutput(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
lib/util/src/extra.0rx view
@@ -19,8 +19,16 @@ define Void { @category Void singleton <- Void{ } + default () {+ return singleton+ }++ duplicate () {+ return singleton+ }+ formatted () {- return "void"+ return "Void" } equals (_,_) {@@ -28,11 +36,11 @@ } lessThan (_,_) {- return true+ return false } - void () {- return singleton+ hashed () {+ return 123456789 } }
lib/util/src/helpers.0rx view
@@ -58,6 +58,22 @@ } return !present(xx) && !present(yy) }++ copyTo (input,output) (original) {+ original <- output+ $Hidden[original]$+ traverse (input -> #x value) {+ \ output.append(value)+ }+ }++ duplicateTo (input,output) (original) {+ original <- output+ $Hidden[original]$+ traverse (input -> #x value) {+ \ output.append(value.duplicate())+ }+ } } define ReadAtH {@@ -66,7 +82,7 @@ } lessThanWith (x,y) {- traverse (Counter.zeroIndexed(Ranges:min(x.size(),y.size())) -> Int i) {+ traverse (`Counter.zeroIndexed` (x.size() `Ranges:min` y.size()) -> Int i) { $ReadOnly[i]$ if (x.readAt(i) `#xx.lessThan` y.readAt(i)) { return true@@ -85,7 +101,7 @@ if (x.size() != y.size()) { return false }- traverse (Counter.zeroIndexed(x.size()) -> Int i) {+ traverse (`Counter.zeroIndexed` x.size() -> Int i) { $ReadOnly[i]$ if (!(x.readAt(i) `#xx.equals` y.readAt(i))) { return false@@ -93,8 +109,94 @@ } return true }++ copyTo (input,output) (original) {+ original <- output+ $Hidden[original]$+ traverse (`Counter.zeroIndexed` input.size() -> Int i) {+ \ output.append(input.readAt(i))+ }+ }++ duplicateTo (input,output) (original) {+ original <- output+ $Hidden[original]$+ traverse (`Counter.zeroIndexed` input.size() -> Int i) {+ \ output.append(input.readAt(i).duplicate())+ }+ }++ forwardOrder (input) {+ return input `iterateWith` `Counter.zeroIndexed` input.size()+ }++ reverseOrder (input) {+ return input `iterateWith` `Counter.revZeroIndexed` input.size()+ }++ iterateWith (input,order) {+ return input `IndexOrder:iterateWith` order+ } } +define FormattedH {+ try (x) {+ if (present(x)) {+ scoped {+ optional Formatted formatted <- reduce<#x,Formatted>(x)+ } in if (present(formatted)) {+ return require(formatted)+ } else {+ return String.builder()+ .append(typename<#x>())+ .append("{?}")+ .build()+ }+ } else {+ return String.builder()+ .append(typename<#x>())+ .append("{empty}")+ .build()+ }+ }+}++concrete IndexOrder<#x> {+ refines Order<#x>++ @category iterateWith<#x> (ReadAt<#x>,optional Order<Int>) -> (optional Order<#x>)+}++define IndexOrder {+ $ReadOnly[container]$++ @value ReadAt<#x> container+ @value Order<Int> index++ iterateWith (container,index) {+ if (`present` index) {+ return IndexOrder<#x>{ container, `require` index }+ } else {+ return empty+ }+ }++ get () {+ return container.readAt(index.get())+ }++ next () {+ scoped {+ optional Order<Int> index2 <- index.next()+ } in if (`present` index2) {+ index <- `require` index2+ return self+ } else {+ return empty+ }+ }+}+ define Reversed { lessThan (x,y) { return y `#x.lessThan` x@@ -118,5 +220,17 @@ lessThan (_,_) { return false+ }+}++define AsLessThan2 {+ refines LessThan2<#x>++ new () {+ return #self{ }+ }++ lessThan2 (x,y) {+ return x `#xx.lessThan` y } }
lib/util/src/input.0rx view
@@ -32,14 +32,15 @@ return builder.build() } - readNextLine () {+ readNextLine () (line) {+ line <- "" while (true) { Int newline <- findNewline() if (newline < 0) { if (reader.pastEnd()) {- cleanup {- buffer <- ""- } in return buffer+ line <- buffer+ buffer <- ""+ break } else { buffer <- buffer+reader.readBlock($ExprLookup[BLOCK_READ_SIZE]$) }@@ -47,7 +48,6 @@ return takeLine(newline) } }- return "" } pastEnd () {
− lib/util/src/output.0rx
@@ -1,45 +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]--define LazyStream {- @value optional #x value- @value optional LazyStream<#x> next-- new () {- return LazyStream<#x>{ empty, empty }- }-- append (value2) {- return LazyStream<#x>{ value2, self }- }-- @value recursive (Writer<#x>) -> ()- recursive (writer) {- if (present(next)) {- \ require(next).recursive(writer)- }- if (present(value)) {- \ writer.write(require(value))- }- }-- writeTo (writer) {- \ recursive(writer)- \ writer.flush()- }-}
lib/util/src/parse.0rx view
@@ -129,10 +129,6 @@ } - if (present(curr)) {- return autoFail<Float>(require(curr).get())- }- if (needExpDigits) { return ErrorOr:error("missing digits in Float exponent") }
lib/util/test/counters.0rt view
@@ -31,6 +31,12 @@ \ Testing.checkEquals(index,10) } +unittest zeroIndexedEmpty {+ traverse (Counter.zeroIndexed(0) -> Int i) {+ fail("not empty")+ }+}+ unittest revZeroIndexed { Int index <- 10 @@ -42,6 +48,12 @@ \ Testing.checkEquals(index,0) } +unittest revZeroIndexedEmpty {+ traverse (Counter.revZeroIndexed(0) -> Int i) {+ fail("not empty")+ }+}+ unittest unlimitedCount { Int index <- 0 @@ -64,6 +76,12 @@ } \ Testing.checkEquals(index,10)+}++unittest timesEmpty {+ traverse ("message" `Repeat:times` 0 -> _) {+ fail("not empty")+ } } unittest unlimitedValue {
lib/util/test/extra.0rt view
@@ -116,3 +116,23 @@ \ value.convertError() } ++testcase "Void tests" {+ success+}++unittest formatted {+ \ Testing.checkEquals(Void.default().formatted(),"Void")+}++unittest lessThan {+ \ Testing.checkFalse(Void.default() `Void.lessThan` Void.default())+}++unittest equals {+ \ Testing.checkTrue(Void.default() `Void.equals` Void.default())+}++unittest hashed {+ \ Testing.checkEquals(Void.default().duplicate().hashed(),Void.default().hashed())+}
lib/util/test/helpers.0rt view
@@ -137,3 +137,229 @@ \ Testing.checkTrue("ac" `AlwaysEqual.equals` "b") \ Testing.checkTrue("a" `AlwaysEqual.equals` "b") }+++testcase "iteration tests" {+ success+}++unittest orderHCopyTo {+ ValueCheck output <- ValueCheck.new(10)+ \ 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+ \ output.checkEnd()+}++unittest readAtHCopyTo {+ ValueCheck output <- ValueCheck.new(10)+ \ ValueSource.new(false,10) `ReadAtH:copyTo` output+ \ output.checkEnd()+}++unittest readAtHDuplicateTo {+ ValueCheck output <- ValueCheck.new(10)+ \ ValueSource.new(true,10) `ReadAtH:duplicateTo` output+ \ output.checkEnd()+}++unittest readAtHForwardOrder {+ ValueSource source <- ValueSource.new(false,10)+ Int expected <- 0+ traverse (`ReadAtH:forwardOrder` source -> Value actual) {+ \ Testing.checkEquals(actual.get(),expected)+ } update {+ expected <- expected+1+ }+ \ Testing.checkEquals(expected,10)+}++unittest readAtHForwardOrderEmpty {+ ValueSource source <- ValueSource.new(false,0)+ traverse (`ReadAtH:forwardOrder` source -> _) {+ fail("not empty")+ }+}++unittest readAtHReverseOrder {+ ValueSource source <- ValueSource.new(false,10)+ Int expected <- 9+ traverse (`ReadAtH:reverseOrder` source -> Value actual) {+ \ Testing.checkEquals(actual.get(),expected)+ } update {+ expected <- expected-1+ }+ \ Testing.checkEquals(expected,-1)+}++unittest readAtHReverseOrderEmpty {+ ValueSource source <- ValueSource.new(false,0)+ traverse (`ReadAtH:reverseOrder` source -> _) {+ fail("not empty")+ }+}++unittest readAtHIterateWith {+ ValueSource source <- ValueSource.new(false,10)+ Int expected <- 0+ traverse (source `ReadAtH:iterateWith` `Counter.zeroIndexed` 5 -> Value actual) {+ \ Testing.checkEquals(actual.get(),expected)+ } update {+ expected <- expected+1+ }+ \ Testing.checkEquals(expected,5)+}++concrete ValueOrder {+ refines Order<Value>++ @type wrap (Bool,optional Order<Int>) -> (optional Order<Value>)+}++define ValueOrder {+ $ReadOnly[original]$++ @value Bool original+ @value Order<Int> order++ wrap (original,order) {+ if (!present(order)) {+ return empty+ } else {+ return ValueOrder{ original, require(order) }+ }+ }++ next () {+ optional Order<Int> order2 <- order.next()+ if (present(order2)) {+ order <- require(order2)+ return self+ } else {+ return empty+ }+ }++ get () {+ return Value.new(original,order.get())+ }+}++concrete ValueCheck {+ // Must append the next value in the sequence [0,size).+ refines Append<Value>++ @type new (Int) -> (ValueCheck)+ @value checkEnd () -> ()+}++define ValueCheck {+ $ReadOnly[target]$++ @value Int current+ @value Int target++ new (target) {+ return ValueCheck{ 0, target }+ }++ checkEnd () {+ \ Testing.checkEquals(current,target)+ }++ append (x) {+ \ Testing.checkEquals(x.get(),current)+ current <- current+1+ return self+ }+}++concrete Value {+ // Crashes if "original" is already false.+ refines Duplicate++ // Args:+ // - Bool: Whether or not the value is "original".+ // - Int: Value to return from get().+ @type new (Bool,Int) -> (Value)++ // Crashes if "original" is true.+ @value get () -> (Int)+}++define Value {+ $ReadOnly[original,value]$++ @value Bool original+ @value Int value++ new (original,value) {+ return Value{ original, value }+ }++ get () {+ if (original) {+ fail("not duplicated")+ }+ return value+ }++ duplicate () {+ if (!original) {+ fail("already duplicated")+ }+ return Value{ false, value }+ }+}++concrete ValueSource {+ // 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)+}++define ValueSource {+ $ReadOnly[original,size]$++ @value Bool original+ @value Int size++ new (original,size) {+ return ValueSource{ original, size }+ }++ size () {+ return size+ }++ readAt (i) {+ \ Testing.checkBetween(i,0,size-1)+ return Value.new(original,i)+ }+}+++testcase "formatting tests" {+ success+}++unittest emptyValue {+ \ Testing.checkEquals(FormattedH:try<Char>(empty).formatted(),"Char{empty}")+ \ Testing.checkEquals(FormattedH:try(empty).formatted(),"all{empty}")+}++unittest formattedValue {+ \ Testing.checkEquals(FormattedH:try(123).formatted(),"123")+}++unittest nonFormattedValue {+ \ Testing.checkEquals(FormattedH:try(String.builder()).formatted(),"[Append<Formatted>&Build<String>]{?}")+}
lib/util/test/input.0rt view
@@ -95,5 +95,5 @@ } unittest test {- \ Testing.checkEquals(TextReader.readAll(SimpleInput.stdin()),"")+ \ Testing.checkEquals(TextReader.readAll(BasicInput.stdin()),"") }
lib/util/test/output.0rt view
@@ -18,31 +18,43 @@ testcase "stdout writer" { success- require stdout "message"+ require stdout "message1"+ require stdout "message2"+ require stdout "message3" exclude stderr "message" } unittest test {- \ LazyStream<Formatted>.new().append("message").writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout().write("message1\n")+ \ BasicOutput.stdout().append("message2\n")+ \ BasicOutput.stdout().writeNow("message3\n") } testcase "stderr writer" { success- require stderr "message"+ require stderr "message1"+ require stderr "message2"+ require stderr "message3" exclude stdout "message" } unittest test {- \ LazyStream<Formatted>.new().append("message").writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().write("message1\n")+ \ BasicOutput.stderr().append("message2\n")+ \ BasicOutput.stderr().writeNow("message3\n") } testcase "error writer" { crash- require "message"+ require "message1"+ require "message2"+ require "message3" } unittest test {- \ LazyStream<Formatted>.new().append("message").writeTo(SimpleOutput.error())+ \ BasicOutput.error().write("message1\n")+ \ BasicOutput.error().append("message2\n")+ \ BasicOutput.error().writeNow("message3\n") }
lib/util/test/parse.0rt view
@@ -108,6 +108,14 @@ \ UtilTesting.checkError(ParseChars.float("123E5Q")) } +unittest floatBadCharAfterDigit {+ \ UtilTesting.checkError(ParseChars.float("123X"))+}++unittest floatMissingExponentDigits {+ \ UtilTesting.checkError(ParseChars.float("123E"))+}+ unittest int { \ UtilTesting.checkSuccess(ParseChars.int("1234"),1234) }
src/Compilation/CompilerState.hs view
@@ -43,6 +43,7 @@ csAddUsed, csAddVariable, csAllFilters,+ csCanForward, csCheckValueInit, csCheckVariableInit, csClearOutput,@@ -151,6 +152,7 @@ ccGetNoTrace :: a -> m Bool ccAddTrace :: a -> String -> m a ccGetTraces :: a -> m [String]+ ccCanForward :: a -> [ParamName] -> [VariableName] -> m Bool data MemberValue c = MemberValue {@@ -359,6 +361,9 @@ 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 data CompiledData s = CompiledData {
src/Compilation/ProcedureContext.hs view
@@ -89,7 +89,8 @@ _pcExprMap :: ExprMap c, _pcReservedMacros :: [(MacroName,[c])], _pcNoTrace :: Bool,- _pcTraces :: [String]+ _pcTraces :: [String],+ _pcParentCall :: Maybe (Positional ParamName,Positional VariableName) } $(makeLenses ''ProcedureContext)@@ -154,6 +155,9 @@ tryMergeFrom fs f = do mapCompilerM_ (tryMergeFunc f) fs return f+ tryMergeTo fs f = do+ mapCompilerM_ (flip tryMergeFunc f) fs+ return f tryMergeFunc f1 f2 = do f1' <- parsedToFunctionType f1 f2' <- parsedToFunctionType f2@@ -161,14 +165,21 @@ allFilters <- ccAllFilters ctx silenceErrorsM $ checkFunctionConvert r allFilters Map.empty f2' f1' getFunction t0 t2 = reduceMergeTree getFromAny getFromAll (getFromSingle t0) t2- getFromAny _ =- compilerErrorM $ "Use explicit type conversion to call " ++ show n ++ " from " ++ show t+ getFromAny fs = do+ let (Just t') = t -- #self will never be a union.+ fs2 <- fmap concat (collectAllM fs) <!! "Function " ++ show n ++ " is not available for type " ++ show t' ++ formatFullContextBrace c+ case Map.toList $ Map.fromList $ map (\f -> (sfType f,sfContext f)) fs2 of+ -- For unions, we want the most general rather than the least+ -- general. Since the top level finds the least general, we can+ -- only return one match here.+ [_] -> fmap (:[]) $ collectFirstM $ map (tryMergeTo fs2) fs2 ++ [multipleMatchError t' fs2]+ [] -> compilerErrorM $ "Function " ++ show n ++ " is not available for type " ++ show t' ++ formatFullContextBrace c+ cs -> "Use an explicit conversion to call " ++ show n ++ " for type " ++ show t' ++ formatFullContextBrace c !!>+ mapErrorsM (map (\(t2,c2) -> "Function " ++ show n ++ " in " ++ show t2 ++ formatFullContextBrace c2) cs) getFromAll fs = do- t' <- case t of- Just t2 -> return t2- Nothing -> fmap (singleType . JustTypeInstance) $ ccSelfType ctx+ let (Just t') = t -- #self will never be an intersection. collectFirstM_ fs <!!- "Function " ++ show n ++ " not available for type " ++ show t' ++ formatFullContextBrace c+ "Function " ++ show n ++ " is not available for type " ++ show t' ++ formatFullContextBrace c fmap concat $ collectAnyM fs getFromSingle t0 (JustParamName _ p) = do fa <- ccAllFilters ctx@@ -224,6 +235,8 @@ validateTypeInstanceForCall r allFilters t' -- Check initializer types. ms <- fmap Positional $ mapCompilerM (subSingle pa) (ctx ^. pcMembers)+ -- Do a size comparison first so that the error message is readable.+ processPairs_ alwaysPair (fmap mvType ms) ts processPairs_ (checkInit r allFilters) ms (Positional $ zip ([1..] :: [Int]) $ pValues ts) return () where@@ -254,10 +267,7 @@ (VariableValue c2 s t _) <- ccGetVariable ctx v return $ ctx & pcVariables %~ Map.insert n (VariableValue c2 s t (VariableReadOnly c)) ccSetDeferred ctx v@(UsedVariable c n) = do- (VariableValue c2 s t r) <- ccGetVariable ctx v- when (s /= LocalScope) $- compilerErrorM $ "Variable " ++ show n ++ formatFullContextBrace c2 ++- " cannot be marked as deferred because it is not locally scoped" ++ formatFullContextBrace c+ (VariableValue c2 _ t r) <- ccGetVariable ctx v case r of VariableReadOnly c3 -> compilerErrorM $ "Variable " ++ show n ++ formatFullContextBrace c2 ++ " cannot be marked as deferred " ++ formatFullContextBrace c ++@@ -309,7 +319,8 @@ combineParallel (da1,ValidateNames ns ts ra1,j1) (da2,ValidateNames _ _ ra2,j2) = (branchDeferred [da1,da2],ValidateNames ns ts $ branchDeferred [ra1,ra2],min j1 j2) combineParallel (da1,r@(ValidatePositions _),j1) (da2,_,j2) = (branchDeferred [da1,da2],r,min j1 j2) combineParallel (da1,_,j1) (da2,r@(ValidatePositions _),j2) = (branchDeferred [da1,da2],r,min j1 j2)- ccInheritDeferred ctx ds = return $ ctx & pcDeferred .~ ds+ ccInheritDeferred ctx ds = return $ ctx & pcDeferred .~ deferred where+ deferred = (ctx ^. pcDeferred) `followDeferred` ds ccInheritUsed ctx ctx2 = return $ ctx & pcUsedVars <>~ (ctx2 ^. pcUsedVars) ccRegisterReturn ctx c vs = do returns <- check (ctx ^. pcReturns)@@ -401,6 +412,16 @@ ccAddTrace ctx "" = return ctx ccAddTrace ctx t = return $ ctx & pcTraces <>~ [t] ccGetTraces = return . (^. pcTraces)+ ccCanForward ctx ps as = handle (ctx ^. pcParentCall) where+ handle Nothing = return False+ handle (Just (ps0,as0)) = collectFirstM [checkMatch ps0 as0,return False]+ checkMatch ps0 as0 = do+ processPairs_ equalOrError ps0 (Positional ps)+ processPairs_ equalOrError as0 (Positional as)+ return True+ equalOrError x y+ | x == y = return ()+ | otherwise = emptyErrorM updateReturnVariables :: (Show c, CollectErrorsM m) => (Map.Map VariableName (VariableValue c)) ->
src/CompilerCxx/CategoryContext.hs view
@@ -85,7 +85,8 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,- _pcTraces = []+ _pcTraces = [],+ _pcParentCall = Nothing } getProcedureContext :: (Show c, CollectErrorsM m) =>@@ -145,10 +146,18 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,- _pcTraces = []+ _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 getMainContext :: CollectErrorsM m => CategoryMap c -> ExprMap c -> m (ProcedureContext c) getMainContext tm em = return $ ProcedureContext {@@ -177,5 +186,6 @@ _pcExprMap = em, _pcReservedMacros = [], _pcNoTrace = False,- _pcTraces = []+ _pcTraces = [],+ _pcParentCall = Nothing }
src/CompilerCxx/CxxFiles.hs view
@@ -410,10 +410,12 @@ return $ onlyCode "};" ] where members = filter ((== CategoryScope). dmScope) $ dcMembers d+ defineConcreteType fs t = concatM [ return $ onlyCode $ "struct " ++ className ++ " : public " ++ typeBase ++ ", std::enable_shared_from_this<" ++ className ++ "> {", fmap indentCompiled $ inlineTypeConstructor t, fmap indentCompiled $ inlineTypeDestructor False t,+ fmap indentCompiled $ inlineTypeParamSelf t, return declareTypeOverrides, fmap indentCompiled $ concatM $ map (declareProcedure t False) fs, return $ indentCompiled $ createParams $ getCategoryParams t,@@ -425,6 +427,7 @@ defineConcreteValue r params fs t d = concatM [ return $ onlyCode $ "struct " ++ valueName (getCategoryName t) ++ " : public " ++ valueBase ++ " {", fmap indentCompiled $ inlineValueConstructor t d,+ fmap indentCompiled $ inlineValueParamSelf t, fmap indentCompiled $ inlineFlatCleanup d, return declareValueOverrides, fmap indentCompiled $ concatM $ map (declareProcedure t False) fs,@@ -446,10 +449,12 @@ return $ onlyCode $ " virtual inline ~" ++ categoryName (getCategoryName t) ++ "() {}", return $ onlyCode "};" ]+ defineAbstractType t = concatM [ return $ onlyCode $ "struct " ++ className ++ " : public " ++ typeBase ++ ", std::enable_shared_from_this<" ++ className ++ "> {", fmap indentCompiled $ inlineTypeConstructor t, fmap indentCompiled $ inlineTypeDestructor True t,+ fmap indentCompiled $ inlineTypeParamSelf t, return declareTypeOverrides, fmap indentCompiled $ concatM $ map (declareProcedure t True) $ filter ((== TypeScope). sfScope) $ getCategoryFunctions t, return $ indentCompiled $ createParams $ getCategoryParams t,@@ -457,9 +462,11 @@ return $ onlyCode "};" ] where className = typeName (getCategoryName t)+ defineAbstractValue t = concatM [ return $ onlyCode $ "struct " ++ valueName (getCategoryName t) ++ " : public " ++ valueBase ++ " {", fmap indentCompiled $ abstractValueConstructor t,+ fmap indentCompiled $ inlineValueParamSelf t, return declareValueOverrides, fmap indentCompiled $ concatM $ map (declareProcedure t True) $ filter ((== ValueScope). sfScope) $ getCategoryFunctions t, return $ onlyCode $ " virtual inline ~" ++ valueName (getCategoryName t) ++ "() {}",@@ -608,7 +615,7 @@ let argParent = "S<const " ++ typeName (getCategoryName t) ++ "> p" let argsPassed = "const ParamsArgs& params_args" let allArgs = intercalate ", " [argParent,argsPassed]- let initParent = "parent(p)"+ let initParent = "parent(std::move(p))" let initArgs = map (\(i,m) -> variableName (dmName m) ++ "(" ++ unwrappedArg i m ++ ")") $ zip ([0..] :: [Int]) members let allInit = intercalate ", " $ initParent:initArgs return $ onlyCode $ "inline " ++ valueName (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" where@@ -618,7 +625,7 @@ abstractValueConstructor t = do let argParent = "S<const " ++ typeName (getCategoryName t) ++ "> p" let allArgs = intercalate ", " [argParent]- let initParent = "parent(p)"+ let initParent = "parent(std::move(p))" let allInit = initParent return $ onlyCode $ "inline " ++ valueName (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}" @@ -629,12 +636,25 @@ let allArgs = intercalate ", " [argParent,paramsPassed] let allInit = typeName (getCategoryName t) ++ "(p, params)" return $ onlyCode $ "inline " ++ typeCustom (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}"+ customValueConstructor t = do let argParent = "S<const " ++ typeName (getCategoryName t) ++ "> p" let argsPassed = "const ParamsArgs& params_args" let allArgs = intercalate ", " [argParent,argsPassed] let allInit = valueName (getCategoryName t) ++ "(std::move(p))" return $ onlyCode $ "inline " ++ valueCustom (getCategoryName t) ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}"++ inlineTypeParamSelf t = return $ onlyCodes [+ "inline S<const " ++ typeName (getCategoryName t) ++ "> Param_self() const {",+ " return shared_from_this();",+ "}"+ ]++ inlineValueParamSelf t = return $ onlyCodes [+ "inline S<const " ++ typeName (getCategoryName t) ++ "> Param_self() const {",+ " return parent;",+ "}"+ ] allowTestsOnly | testing = (testsOnlySourceGuard ++)
src/CompilerCxx/Procedure.hs view
@@ -704,16 +704,15 @@ show t2 ++ formatFullContextBrace c glueInfix t1 t2 e3 o2 e4 = UnboxedPrimitive t2 $ "(" ++ useAsUnboxed t1 e3 ++ ")" ++ o2 ++ "(" ++ useAsUnboxed t1 e4 ++ ")"- transform e (ConvertedCall c t f) = do+ transform e (TypeConversion c t) = do (Positional ts,e') <- e t' <- requireSingle c ts r <- csResolver fa <- csAllFilters- let vt = ValueType RequiredValue $ singleType $ JustTypeInstance t+ let vt = ValueType (vtRequired t') t (lift $ checkValueAssignment r fa t' vt) <??- "In converted call at " ++ formatFullContext c- f' <- lookupValueFunction vt f- compileFunctionCall (Just $ useAsUnwrapped e') f' f+ "In explicit type conversion at " ++ formatFullContext c+ return (Positional [vt],e') transform e (ValueCall c f) = do (Positional ts,e') <- e t' <- requireSingle c ts@@ -735,10 +734,10 @@ CompilerContext c m [String] a) => ValueType -> FunctionCall c -> CompilerState a m (ScopedFunction c) lookupValueFunction (ValueType WeakValue t) (FunctionCall c _ _ _) =- compilerErrorM $ "Use strong to convert " ++ show t +++ compilerErrorM $ "Use strong to convert weak " ++ show t ++ " to optional first" ++ formatFullContextBrace c lookupValueFunction (ValueType OptionalValue t) (FunctionCall c _ _ _) =- compilerErrorM $ "Use require to convert " ++ show t +++ 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@@ -778,11 +777,18 @@ formatFullContextBrace c csAddRequired $ Set.unions $ map categoriesFromTypes [t'] csAddRequired $ Set.fromList [sfType f']- t2 <- expandGeneralInstance t'- compileFunctionCall (Just t2) f' f+ same <- maybeSingleType t' >>= checkSame+ t2 <- if same+ then return Nothing+ else fmap Just $ expandGeneralInstance t'+ compileFunctionCall t2 f' f+ where+ maybeSingleType = lift . tryCompilerM . matchOnlyLeaf+ checkSame (Just (JustTypeInstance t2)) = csSameType t2+ checkSame _ = return False compileExpressionStart (UnqualifiedCall c f@(FunctionCall _ n _ _)) = do ctx <- get- f' <- lift $ collectFirstM [tryCategory ctx,tryNonCategory ctx]+ f' <- lift $ collectFirstM [tryCategory ctx,tryNonCategory ctx] <?? "In function call at " ++ formatFullContext c csAddRequired $ Set.fromList [sfType f'] compileFunctionCall Nothing f' f where@@ -907,11 +913,12 @@ sameType <- csSameType t' s <- csCurrentScope let typeInstance = getType t' sameType s params+ args <- getArgs es'' -- TODO: This is unsafe if used in a type or category constructor. return (Positional [ValueType RequiredValue $ singleType $ JustTypeInstance t'],- UnwrappedSingle $ valueCreator (tiName t') ++ "(" ++ typeInstance ++ ", PassParamsArgs(" ++ es'' ++ "))")+ UnwrappedSingle $ valueCreator (tiName t') ++ "(" ++ typeInstance ++ ", " ++ args ++ ")") where- getType _ True ValueScope _ = "parent"+ getType _ True ValueScope _ = "PARAM_SELF" getType _ True TypeScope _ = "PARAM_SELF" getType t2 _ _ params = typeCreator (tiName t2) ++ "(" ++ params ++ ")" -- Single expression, but possibly multi-return.@@ -924,6 +931,14 @@ checkArity (_,Positional [_]) = return () checkArity (i,Positional ts) = compilerErrorM $ "Initializer position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"+ getArgs argEs = do+ asNames <- lift $ collectArgNames $ pValues es+ canForward <- case asNames of+ Just an -> csCanForward [] an+ _ -> return False+ if canForward+ then return "params_args"+ else return $ "PassParamsArgs(" ++ argEs ++ ")" compileExpressionStart (UnambiguousLiteral l) = compileValueLiteral l compileValueLiteral :: (Ord c, Show c, CollectErrorsM m,@@ -995,7 +1010,8 @@ params <- expandParams2 ps2 scope <- csCurrentScope scoped <- autoScope (sfScope f)- call <- assemble e scoped scope (sfScope f) params es''+ paramsArgs <- getParamsArgs (pValues ps2) params es''+ call <- assemble e scoped scope (sfScope f) paramsArgs return $ (ftReturns f'',OpaqueMulti call) where replaceSelfParam self (AssignedInstance c2 t) = do@@ -1007,21 +1023,29 @@ compilerBackgroundM $ "Parameter " ++ show n ++ " (from " ++ show (sfType f) ++ "." ++ show (sfName f) ++ ") inferred as " ++ show t ++ " at " ++ formatFullContext c2 backgroundMessage _ = return ()- joinParamsArgs ps2 es2 = "PassParamsArgs(" ++ intercalate ", " (ps2 ++ es2) ++ ")"- assemble Nothing _ ValueScope ValueScope ps2 es2 =- return $ callName (sfName f) ++ "(" ++ joinParamsArgs ps2 es2 ++ ")"- assemble Nothing _ TypeScope TypeScope ps2 es2 =- return $ callName (sfName f) ++ "(" ++ joinParamsArgs ps2 es2 ++ ")"- assemble Nothing scoped ValueScope TypeScope ps2 es2 =- return $ scoped ++ callName (sfName f) ++ "(" ++ joinParamsArgs ps2 es2 ++ ")"- assemble Nothing scoped _ _ ps2 es2 =- return $ scoped ++ callName (sfName f) ++ "(" ++ joinParamsArgs ps2 es2 ++ ")"- assemble (Just e2) _ _ ValueScope ps2 es2 =- return $ valueBase ++ "::Call(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ joinParamsArgs ps2 es2 ++ ")"- assemble (Just e2) _ _ TypeScope ps2 es2 =- return $ typeBase ++ "::Call(" ++ e2 ++ ", " ++ functionName f ++ ", " ++ joinParamsArgs ps2 es2 ++ ")"- assemble (Just e2) _ _ _ ps2 es2 =- return $ e2 ++ ".Call(" ++ functionName f ++ ", " ++ joinParamsArgs ps2 es2 ++ ")"+ getParamsArgs ps2 paramEs argEs = do+ psNames <- lift $ collectParamNames ps2+ asNames <- lift $ collectArgNames $ pValues es+ canForward <- case (psNames,asNames) of+ (Just pn,Just an) -> csCanForward pn an+ _ -> return False+ if canForward+ then return "params_args"+ else return $ "PassParamsArgs(" ++ intercalate ", " (paramEs ++ argEs) ++ ")"+ assemble Nothing _ ValueScope ValueScope paramsArgs =+ return $ callName (sfName f) ++ "(" ++ paramsArgs ++ ")"+ assemble Nothing _ TypeScope TypeScope paramsArgs =+ return $ callName (sfName f) ++ "(" ++ paramsArgs ++ ")"+ assemble Nothing scoped ValueScope TypeScope paramsArgs =+ return $ scoped ++ callName (sfName f) ++ "(" ++ paramsArgs ++ ")"+ assemble Nothing scoped _ _ paramsArgs =+ return $ scoped ++ callName (sfName f) ++ "(" ++ paramsArgs ++ ")"+ assemble (Just e2) _ _ ValueScope paramsArgs =+ 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 ++ ")" -- TODO: Lots of duplication with assignments and initialization. -- Single expression, but possibly multi-return. getValues [(Positional ts,e2)] = return (ts,[useAsArgs e2])@@ -1035,7 +1059,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)+ collectParamNames = fmap sequence . mapCompilerM collectParamName+ collectParamName = fmap getParamName . tryCompilerM . matchOnlyLeaf+ getParamName (Just (JustParamName _ n)) = Just n+ getParamName _ = Nothing +collectArgNames :: CollectErrorsM m => [Expression c] -> m (Maybe [VariableName])+collectArgNames = fmap sequence . mapCompilerM collectArgName where+ collectArgName (Expression _ (NamedVariable (OutputValue _ n)) []) = return $ Just n+ collectArgName _ = return Nothing+ guessParamsFromArgs :: (Ord c, Show c, CollectErrorsM m, TypeResolver r) => r -> ParamFilters -> ScopedFunction c -> Positional (InstanceOrInferred c) -> Positional ValueType -> m (Positional GeneralInstance)@@ -1171,19 +1204,28 @@ expandGeneralInstance :: (CollectErrorsM m, CompilerContext c m s a) => GeneralInstance -> CompilerState a m String-expandGeneralInstance t- | t == minBound = return $ allGetter ++ "()"- | t == maxBound = return $ anyGetter ++ "()" expandGeneralInstance t = do r <- csResolver f <- csAllFilters+ scope <- csCurrentScope t' <- lift $ dedupGeneralInstance r f t- reduceMergeTree getAny getAll getSingle t' where+ t'' <- case scope of+ CategoryScope -> return t'+ _ -> do+ self <- csSelfType+ lift $ reverseSelfInstance self t'+ expand t'' where+ expand t2+ | t2 == minBound = return $ allGetter ++ "()"+ | t2 == maxBound = return $ anyGetter ++ "()"+ | otherwise = reduceMergeTree getAny getAll getSingle t2 getAny ts = combine ts >>= return . (unionGetter ++) getAll ts = combine ts >>= return . (intersectGetter ++) getSingle (JustTypeInstance (TypeInstance t2 ps)) = do- ps' <- sequence $ map expandGeneralInstance $ pValues ps- return $ typeGetter t2 ++ "(T_get(" ++ intercalate "," ps' ++ "))"+ ps' <- sequence $ map expand $ pValues ps+ let count = length ps'+ return $ typeGetter t2 ++ "(Params<" ++ show count ++ ">::Type(" ++ intercalate "," ps' ++ "))"+ getSingle (JustParamName _ ParamSelf) = return "S<const TypeInstance>(PARAM_SELF)" getSingle (JustParamName _ p) = do s <- csGetParamScope p scoped <- autoScope s
src/Module/ProcessMetadata.hs view
@@ -327,7 +327,8 @@ let rs = Set.toList $ Set.fromList $ concat $ map getRequires os expectedFiles <- mapCompilerM (errorFromIO . canonicalizePath . (p2</>)) (ps++xs++ts) actualFiles <- mapCompilerM (errorFromIO . canonicalizePath . (p2</>)) (ps2++xs2++ts2)- inputFiles <- mapCompilerM (errorFromIO . canonicalizePath . (p2</>)) (xs++ts)+ inputFiles <- mapCompilerM (errorFromIO . canonicalizePath . (p2</>)) (ps++xs)+ testFiles <- mapCompilerM (errorFromIO . canonicalizePath . (p2</>)) ts collectAllM_ $ [ checkHash, checkInput time (p </> moduleFilename),@@ -335,6 +336,7 @@ ] ++ (map (checkDep time) $ is ++ is2) ++ (map (checkInput time) inputFiles) +++ (map checkPresent testFiles) ++ (map (checkInput time . getCachedPath d "") $ hxx ++ cxx) ++ (map checkOutput bs) ++ (map checkOutput ls) ++@@ -344,6 +346,9 @@ checkHash = when (not $ checkModuleVersionHash h m) $ compilerErrorM $ "Module \"" ++ p ++ "\" was compiled with a different compiler setup"+ checkPresent f = do+ exists <- doesFileOrDirExist f+ when (not exists) $ compilerErrorM $ "Required path \"" ++ f ++ "\" is missing" checkInput time f = do exists <- doesFileOrDirExist f when (not exists) $ compilerErrorM $ "Required path \"" ++ f ++ "\" is missing"
src/Parser/Common.hs view
@@ -311,7 +311,7 @@ compilerErrorM "#self is not allowed here" operatorSymbol :: TextParser Char-operatorSymbol = labeled "operator symbol" $ satisfy (`Set.member` Set.fromList "+-*/%=!<>&|?")+operatorSymbol = labeled "operator symbol" $ satisfy (`Set.member` Set.fromList "+-*/%=!<>&|") isKeyword :: TextParser () isKeyword = foldr (<|>) empty $ map try [
src/Parser/Procedure.hs view
@@ -405,7 +405,7 @@ asInfix [e] [] <|> return e where -- NOTE: InitializeValue is parsed as ExpressionStart.- notInfix = literal <|> unary <|> expression+ notInfix = literal <|> try unaryBuiltin <|> unary <|> expression asInfix es os = do c <- getSourceContext o <- infixOperator <|> functionOperator@@ -428,6 +428,16 @@ literal = do l <- sourceParser return $ Literal l+ unaryBuiltin = do+ c <- getSourceContext+ infixFuncStart+ n <- builtinUnary+ ps <- try $ between (sepAfter $ string_ "<")+ (sepAfter $ string_ ">")+ (sepBy sourceParser (sepAfter $ string_ ",")) <|> return []+ infixFuncEnd+ e <- notInfix+ return $ Expression [c] (BuiltinCall [c] $ FunctionCall [c] n (Positional ps) (Positional [e])) [] unary = do c <- getSourceContext o <- unaryOperator <|> functionOperator@@ -510,6 +520,14 @@ kwTypename >> return BuiltinTypename ] +builtinUnary :: TextParser FunctionName+builtinUnary = foldr (<|>) empty $ map try [+ kwPresent >> return BuiltinPresent,+ kwReduce >> return BuiltinReduce,+ kwRequire >> return BuiltinRequire,+ kwStrong >> return BuiltinStrong+ ]+ instance ParseFromSource (ExpressionStart SourceContext) where sourceParser = labeled "expression start" $ parens <|>@@ -667,12 +685,9 @@ return $ ValueCall [c] f conversion = labeled "type conversion" $ do c <- getSourceContext- valueSymbolGet+ inferredParam t <- sourceParser -- NOTE: Should not need try here.- typeSymbolGet- n <- sourceParser- f <- parseFunctionCall c n- return $ ConvertedCall [c] t f+ return $ TypeConversion [c] t selectReturn = labeled "return selection" $ do c <- getSourceContext sepAfter_ (string_ "{")
src/Parser/TypeInstance.hs view
@@ -126,11 +126,11 @@ requires = labeled "requires filter" $ do kwRequires t <- sourceParser- return $ TypeFilter FilterRequires $ singleType t+ return $ TypeFilter FilterRequires t allows = labeled "allows filter" $ do kwAllows t <- sourceParser- return $ TypeFilter FilterAllows $ singleType t+ return $ TypeFilter FilterAllows t defines = labeled "defines filter" $ do kwDefines t <- sourceParser
src/Test/Procedure.hs view
@@ -41,9 +41,12 @@ checkShortParseFail "return var var", checkShortParseFail "return _ var", checkShortParseSuccess "return call()",- checkShortParseSuccess "return var.T<#x>.func()",- checkShortParseSuccess "return var, var.T<#x>.func()",- checkShortParseFail "return var var.T<#x>.func()",+ checkShortParseSuccess "return var?T<#x>.func()",+ checkShortParseSuccess "return var?T<#x>",+ checkShortParseSuccess "return var, var?T<#x>.func()",+ checkShortParseFail "return var var?T<#x>.func()",+ checkShortParseFail "return var.T<#x>.func()",+ checkShortParseFail "return var.T<#x>", checkShortParseFail "return var, _", checkShortParseFail "return T<#x> var", checkShortParseSuccess "return T<#x>{ val }",@@ -60,15 +63,16 @@ checkShortParseSuccess "\\ var", checkShortParseFail "\\ var var",- checkShortParseSuccess "\\ var.T<#x>.func().func2().func3()",+ checkShortParseSuccess "\\ var?T<#x>.func().func2().func3()", checkShortParseSuccess "\\ T<#x>.func().func2().func3()", checkShortParseSuccess "\\ #x.func().func2().func3()",- checkShortParseFail "\\ var.T<#x>.T<#x>.func()",- checkShortParseFail "\\ var.T<#x>.T<#x>.func()",- checkShortParseFail "\\ var.T<#x>",+ checkShortParseSuccess "\\ var?T<#x>?T<#x>.func()",+ checkShortParseSuccess "\\ var?T<#x>",+ checkShortParseSuccess "\\ var?#x",+ checkShortParseSuccess "\\ var?[T1|T2]", checkShortParseFail "\\ T<#x> var",- checkShortParseSuccess "\\ T<#x>{ val, var.T<#x>.func() }",- checkShortParseFail "\\ T<#x>{ val var.T<#x>.func() }",+ checkShortParseSuccess "\\ T<#x>{ val, var?T<#x>.func() }",+ checkShortParseFail "\\ T<#x>{ val var?T<#x>.func() }", checkShortParseSuccess "\\ T<#x>{}.call()", checkShortParseFail "\\ T<#x>$call()", checkShortParseSuccess "\\ (T<#x>{}).call()",@@ -122,28 +126,28 @@ checkShortParseSuccess "while (var.func()) { \\ val.call() } update { \\ call() }", checkShortParseSuccess "scoped { T<#x> x <- y } in return _",- checkShortParseSuccess "scoped { T<#x> x <- y } in return var, var.T<#x>.func()",- checkShortParseSuccess "scoped { T<#x> x <- y } in \\ var.T<#x>.func()",+ checkShortParseSuccess "scoped { T<#x> x <- y } in return var, var?T<#x>.func()",+ checkShortParseSuccess "scoped { T<#x> x <- y } in \\ var?T<#x>.func()", checkShortParseSuccess "scoped { T<#x> x <- y } in _, weak T<#x> x <- var.func()", checkShortParseSuccess "scoped { T<#x> x <- y } in if (var.func()) { \\ val.call() }", checkShortParseSuccess "scoped { T<#x> x <- y } in while (var.func()) { \\ val.call() }", - checkShortParseSuccess "x <- (((var.func())).T.call())",+ checkShortParseSuccess "x <- (((var.func()))?T.call())", checkShortParseSuccess "\\ (x <- var).func()", checkShortParseFail "x <- (((var.func()))", checkShortParseFail "(((x <- var.func())))", checkShortParseFail "(x) <- y", checkShortParseFail "T (x) <- y", checkShortParseFail "\\ (T x <- var).func()",- checkShortParseSuccess "\\ call(((var.func())).T.call())",- checkShortParseSuccess "if (((var.func()).T.call())) { }",+ checkShortParseSuccess "\\ call(((var.func()))?T.call())",+ checkShortParseSuccess "if (((var.func())?T.call())) { }", checkShortParseSuccess "fail(\"reason\")", checkShortParseFail "\\ fail(\"reason\")", checkShortParseSuccess "failed <- 10", - checkShortParseSuccess "\\var.T<#x>.func().func2().func3()",- checkShortParseSuccess "\\T<#x>{val,var.T<#x>.func()}",+ checkShortParseSuccess "\\var?T<#x>.func().func2().func3()",+ checkShortParseSuccess "\\T<#x>{val,var?T<#x>.func()}", checkShortParseSuccess "x<-var.func()", checkShortParseSuccess "T<#x>x<-var.func()", checkShortParseSuccess "_,weak T<#x>x<-var.func()",@@ -151,7 +155,7 @@ checkShortParseSuccess "if(v){\\c()}elif(v){\\c()}else{\\c()}", checkShortParseSuccess "if(v){\\c()}elif(v){\\c()}elif(v){\\c()}", checkShortParseSuccess "while(var.func()){\\val.call()}",- checkShortParseSuccess "scoped{T<#x>x<-y}in\\var.T<#x>.func()",+ checkShortParseSuccess "scoped{T<#x>x<-y}in\\var?T<#x>.func()", checkShortParseSuccess "scoped{T<#x>x<-y}in{x<-1}", checkShortParseSuccess "scoped{T<#x>x<-y}in x<-1", checkShortParseFail "scoped{T<#x>x<-y}in{x}",@@ -227,6 +231,12 @@ checkShortParseSuccess "\\ call(){0}.bar()", checkShortParseFail "\\ call(){x}", checkShortParseFail "\\ call(){-1}",++ checkShortParseSuccess "x <- `strong` y",+ checkShortParseSuccess "x <- `present` y",+ checkShortParseSuccess "x <- `require` y",+ checkShortParseSuccess "x <- `reduce<#x,#y>` y",+ checkShortParseFail "x <- `typename<#y>` y", checkParsesAs "'\"'" (\e -> case e of
src/Test/testfiles/procedures.0rx view
@@ -31,7 +31,7 @@ \ z.call().call() x, weak [#k|Type] y, _ <- z.call()- x <- z.T<#z>.call().call()+ x <- z?T<#z>.call().call() return _ return a return a, z.call().call(), c
src/Types/DefinedCategory.hs view
@@ -142,7 +142,9 @@ "\n ->\n" ++ show f ++ "\n---\n") ??> do f0' <- parsedToFunctionType f0 f' <- parsedToFunctionType f- checkFunctionConvert r fm pm f0' f'+ 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' pairProceduresToFunctions :: (Show c, CollectErrorsM m) =>@@ -176,7 +178,7 @@ formatFullContextBrace (epContext p) ++ " does not correspond to a function" getPair (Just f) (Just p) = do- processPairs_ alwaysPair (sfArgs f) (avNames $ epArgs p) <!!+ processPairs_ alwaysPair (fmap pvType $ sfArgs f) (fmap inputValueName $ avNames $ epArgs p) <!! ("Procedure for " ++ show (sfName f) ++ formatFullContextBrace (avContext $ epArgs p) ++ " has the wrong number of arguments" ++@@ -184,7 +186,7 @@ if isUnnamedReturns (epReturns p) then return () else do- processPairs_ alwaysPair (sfReturns f) (nrNames $ epReturns p) <!!+ processPairs_ alwaysPair (fmap pvType $ sfReturns f) (fmap ovName $ nrNames $ epReturns p) <!! ("Procedure for " ++ show (sfName f) ++ formatFullContextBrace (nrContext $ epReturns p) ++ " has the wrong number of returns" ++
src/Types/Procedure.hs view
@@ -51,6 +51,7 @@ getOperatorContext, getOperatorName, getStatementContext,+ inputValueName, isAssignableDiscard, isDiscardedInput, isFunctionOperator,@@ -132,6 +133,10 @@ iiContext :: [c] } +inputValueName :: InputValue c -> VariableName+inputValueName (DiscardInput _) = discardInputName+inputValueName (InputValue _ n) = n+ isDiscardedInput :: InputValue c -> Bool isDiscardedInput (DiscardInput _) = True isDiscardedInput _ = False@@ -330,7 +335,7 @@ getValueLiteralContext (EmptyLiteral c) = c data ValueOperation c =- ConvertedCall [c] TypeInstance (FunctionCall c) |+ TypeConversion [c] GeneralInstance | ValueCall [c] (FunctionCall c) | SelectReturn [c] Int deriving (Show)
src/Types/TypeCategory.hs view
@@ -357,12 +357,13 @@ } instance Show c => TypeResolver (CategoryResolver c) where- trRefines (CategoryResolver tm) (TypeInstance n1 ps1) n2+ trRefines (CategoryResolver tm) ta@(TypeInstance n1 ps1) n2 | n1 == n2 = do (_,t) <- getValueCategory tm ([],n1) processPairs_ alwaysPair (Positional $ map vpParam $ getCategoryParams t) ps1 return ps1 | otherwise = do+ let self = singleType $ JustTypeInstance ta (_,t) <- getValueCategory tm ([],n1) let params = map vpParam $ getCategoryParams t assigned <- fmap Map.fromList $ processPairs alwaysPair (Positional params) ps1@@ -370,8 +371,9 @@ ps2 <- case n2 `Map.lookup` pa of (Just x) -> return x _ -> compilerErrorM $ "Category " ++ show n1 ++ " does not refine " ++ show n2- fmap Positional $ mapCompilerM (subAllParams assigned) $ pValues ps2- trDefines (CategoryResolver tm) (TypeInstance n1 ps1) n2 = do+ fmap Positional $ mapCompilerM (subAllParams assigned >=> replaceSelfInstance self) $ pValues ps2+ trDefines (CategoryResolver tm) ta@(TypeInstance n1 ps1) n2 = do+ let self = singleType $ JustTypeInstance ta (_,t) <- getValueCategory tm ([],n1) let params = map vpParam $ getCategoryParams t assigned <- fmap Map.fromList $ processPairs alwaysPair (Positional params) ps1@@ -379,7 +381,7 @@ ps2 <- case n2 `Map.lookup` pa of (Just x) -> return x _ -> compilerErrorM $ "Category " ++ show n1 ++ " does not define " ++ show n2- fmap Positional $ mapCompilerM (subAllParams assigned) $ pValues ps2+ fmap Positional $ mapCompilerM (subAllParams assigned >=> replaceSelfInstance self) $ pValues ps2 trVariance (CategoryResolver tm) n = do (_,t) <- getCategory tm ([],n) return $ Positional $ map vpVariance $ getCategoryParams t@@ -878,7 +880,7 @@ 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 r fm inheritByName explicitByName) allNames where+ mapCompilerM (mergeByName inheritByName explicitByName) allNames where getRefinesFuncs tm2 (ValueRefine c (TypeInstance n ts2)) = do (_,t) <- getValueCategory tm2 (c,n) let ps = map vpParam $ getCategoryParams t@@ -893,27 +895,27 @@ paired <- processPairs alwaysPair (Positional ps) ts2 let assigned = Map.fromList $ (ParamSelf,selfType):paired mapCompilerM (unfixedSubFunction assigned) fs2- mergeByName r2 fm2 im em n =- tryMerge r2 fm2 n (n `Map.lookup` im) (n `Map.lookup` em)+ mergeByName im em n =+ tryMerge n (n `Map.lookup` im) (n `Map.lookup` em) -- Inherited without an override.- tryMerge _ _ n (Just is) Nothing+ tryMerge n (Just is) Nothing | length is == 1 = return $ head is | otherwise = compilerErrorM $ "Function " ++ show n ++ " is inherited " ++ show (length is) ++ " times:\n---\n" ++ intercalate "\n---\n" (map show is) -- Not inherited.- tryMerge r2 fm2 n Nothing es = tryMerge r2 fm2 n (Just []) es+ tryMerge n Nothing es = tryMerge n (Just []) es -- Explicit override, possibly inherited.- tryMerge r2 fm2 n (Just is) (Just es)+ tryMerge n (Just is) (Just es) | length es /= 1 = compilerErrorM $ "Function " ++ show n ++ " is declared " ++ 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- mapCompilerM_ (checkMerge r2 fm2 ff) is+ mapCompilerM_ (checkMerge ff) is return $ ScopedFunction c n2 t s as rs2 ps fa (ms ++ is) where- checkMerge r3 fm3 f1 f2+ checkMerge f1 f2 | sfScope f1 /= sfScope f2 = compilerErrorM $ "Cannot merge " ++ show (sfScope f2) ++ " with " ++ show (sfScope f1) ++ " in function merge:\n---\n" ++@@ -922,7 +924,9 @@ "In function merge:\n---\n" ++ show f2 ++ "\n ->\n" ++ show f1 ++ "\n---\n" ??> do f1' <- parsedToFunctionType f1 f2' <- parsedToFunctionType f2- checkFunctionConvert r3 fm3 pm f2' f1'+ case sfScope f1 of+ CategoryScope -> checkFunctionConvert r Map.empty Map.empty f2' f1'+ _ -> checkFunctionConvert r fm pm f2' f1' data FunctionName = FunctionName {
src/Types/TypeInstance.hs view
@@ -62,6 +62,7 @@ replaceSelfValueType, requiredParam, requiredSingleton,+ reverseSelfInstance, selfType, uncheckedSubFilter, uncheckedSubFilters,@@ -724,6 +725,16 @@ fs' <- mapCompilerM (uncheckedSubFilter replace) fs return (n,fs') +reverseSelfInstance :: CollectErrorsM m =>+ TypeInstance -> GeneralInstance -> m GeneralInstance+reverseSelfInstance self = reduceMergeTree subAny subAll subSingle where+ -- NOTE: Don't use mergeAnyM because it will fail if the union is empty.+ subAny = fmap mergeAny . sequence+ subAll = fmap mergeAll . sequence+ -- NOTE: Equality should be fine here, since self should only have param names.+ subSingle (JustTypeInstance t) | t == self = return $ singleType $ JustParamName True ParamSelf+ subSingle t = return $ singleType t+ replaceSelfValueType :: CollectErrorsM m => GeneralInstance -> ValueType -> m ValueType replaceSelfValueType self (ValueType s t) = do@@ -738,7 +749,7 @@ subAll = fmap mergeAll . sequence subSingle (JustParamName _ ParamSelf) = return self subSingle (JustTypeInstance t) = fmap (singleType . JustTypeInstance) $ replaceSelfSingle self t- subSingle p = return $ singleType p+ subSingle t = return $ singleType t replaceSelfSingle :: CollectErrorsM m => GeneralInstance -> TypeInstance -> m TypeInstance
tests/builtin-types.0rt view
@@ -321,14 +321,48 @@ \ Testing.checkEquals(String.default(),"") } -unittest stringLessThan {- if (!("x" `String.lessThan` "y")) {- fail("Failed")- }+unittest boolDuplicate {+ \ Testing.checkTrue(true.duplicate()) } -unittest boolEquals {- if (!(true `Bool.equals` true)) {+unittest charDuplicate {+ \ Testing.checkEquals('a'.duplicate(),'a')+}++unittest floatDuplicate {+ \ Testing.checkEquals((1.1).duplicate(),1.1)+}++unittest intDuplicate {+ \ Testing.checkEquals((123).duplicate(),123)+}++unittest stringDuplicate {+ \ Testing.checkEquals("string".duplicate(),"string")+}++unittest boolHashed {+ \ Testing.checkNotEquals(true.hashed(),false.hashed())+}++unittest charHashed {+ \ Testing.checkNotEquals('a'.hashed(),'b'.hashed())+}++unittest floatHashed {+ \ Testing.checkNotEquals((1.1).hashed(),(1.2).hashed())+}++unittest intHashed {+ \ Testing.checkNotEquals((123).hashed(),(124).hashed())+}++unittest stringHashed {+ \ Testing.checkNotEquals("string12".hashed(),"string21".hashed())+}++unittest stringLessThan {+ if (!("x" `String.lessThan` "y")) { fail("Failed") } }@@ -428,6 +462,27 @@ String s <- (1.1).formatted() if (s != "1.1") { // precision might vary fail(s)+ }+}++unittest boolEquals {+ if (!(true `Bool.equals` true)) {+ fail("Failed")+ }+}++unittest boolLessThan {+ if (!(false `Bool.lessThan` true)) {+ fail("Failed")+ }+ if (true `Bool.lessThan` true) {+ fail("Failed")+ }+ if (true `Bool.lessThan` false) {+ fail("Failed")+ }+ if (false `Bool.lessThan` false) {+ fail("Failed") } }
tests/cli-tests.sh view
@@ -147,31 +147,38 @@ local output=$(do_zeolite -p "$ZEOLITE_PATH" -t tests/freshness || true) require_patterns "$output" <<END tests/freshness[^/].+out of date+freshness/private2\.0rp.+missing+freshness/public1\.0rp.+newer+freshness/public2\.0rp.+missing freshness/public3\.0rp.+not present freshness/source1\.0rx.+newer freshness/source2\.0rx.+missing freshness/source3\.0rx.+not present+freshness/sub1/private2\.0rp.+missing+freshness/sub1/public1\.0rp.+newer+freshness/sub1/public2\.0rp.+missing freshness/sub1/public3\.0rp.+not present freshness/sub1/source1\.0rx.+newer freshness/sub1/source2\.0rx.+missing freshness/sub1/source3\.0rx.+not present-freshness/sub1/test1\.0rt.+newer freshness/sub1/test2\.0rt.+missing freshness/sub1/test3\.0rt.+not present+freshness/sub2/private2\.0rp.+missing+freshness/sub2/public1\.0rp.+newer+freshness/sub2/public2\.0rp.+missing freshness/sub2/public3\.0rp.+not present freshness/sub2/source1\.0rx.+newer freshness/sub2/source2\.0rx.+missing freshness/sub2/source3\.0rx.+not present-freshness/sub2/test1\.0rt.+newer freshness/sub2/test2\.0rt.+missing freshness/sub2/test3\.0rt.+not present-freshness/test1\.0rt.+newer freshness/test2\.0rt.+missing freshness/test3\.0rt.+not present freshness/.zeolite-cache/public_[a-f0-9]+\.so.+missing END [[ $? -eq 0 ]] || return 1 exclude_patterns "$output" <<END+\.0rt.+newer cpp hpp \.o\b
+ tests/conversions.0rt view
@@ -0,0 +1,144 @@+/* -----------------------------------------------------------------------------+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 "type conversions" {+ success+}++unittest toType {+ \ Testing.checkEquals(Helper.getType(Value.create()?Base1),"Base1")+}++unittest toAny {+ \ Testing.checkEquals(Helper.getType(Value.create()?any),"any")+}++unittest toUnion {+ \ Testing.checkEquals(Helper.getType(Value.create()?[Base1|Base2]),"[Base1|Base2]")+}++unittest toIntersect {+ \ Testing.checkEquals(Helper.getType(Value.create()?[Base1&Base2]),"[Base1&Base2]")+}++unittest toParam {+ \ Testing.checkEquals(Helper.toParam<Value,Base1>(Value.create()),"Base1")+}++unittest toTypeOptional {+ optional Value value <- Value.create()+ \ Testing.checkEquals(Helper.getType2(value?Base1),"Base1")+}++unittest toAnyOptional {+ optional Value value <- Value.create()+ \ Testing.checkEquals(Helper.getType2(value?any),"any")+}++unittest convertedCall {+ Value value <- Value.create()+ \ value?Base1.call()+}++concrete Helper {+ @type toParam<#x,#y>+ #x requires #y+ (#x) -> (String)++ @type getType<#x> (#x) -> (String)+ @type getType2<#x> (optional #x) -> (String)+}++define Helper {+ toParam (x) {+ return getType(x?#y)+ }++ getType (_) {+ return typename<#x>().formatted()+ }++ getType2 (_) {+ return typename<#x>().formatted()+ }+}++@value interface Base2 {+ call () -> ()+}++@value interface Base1 {+ call () -> ()+}++concrete Value {+ refines Base1+ refines Base2++ @type create () -> (Value)+ @value call () -> ()+}++define Value {+ call () {}++ create () {+ return Value{}+ }+}+++testcase "conversion bad type" {+ error+ require "Base"+ require "Value"+}++unittest test {+ Value value <- Value.create()+ \ value?Base+}++@value interface Base {+ call () -> ()+}++concrete Value {+ @value call () -> ()+ @type create () -> (Value)+}++define Value {+ call () {}++ create () {+ return Value{}+ }+}+++testcase "conversion of optional preserves optional" {+ error+ require "require"+ require "optional Formatted"+}++unittest test {+ optional Int value <- empty+ \ value?Formatted.formatted()+}
tests/defer.0rt view
@@ -86,11 +86,10 @@ } -testcase "cannot defer @value member" {+testcase "can defer @value member" { error- require "defer" require "value"- require "local"+ require "initialized" } concrete Type {}@@ -101,15 +100,15 @@ @value call () -> () call () { value <- defer+ \ value } } -testcase "cannot defer @category member" {+testcase "can defer @category member" { error- require "defer" require "value"- require "local"+ require "initialized" } concrete Type {}@@ -120,6 +119,7 @@ @value call () -> () call () { value <- defer+ \ value } } @@ -286,6 +286,22 @@ unittest test { scoped { } in Int value <- defer+}+++testcase "deferred propagated from scoped statement" {+ compiles+}++unittest test {+ Int value <- defer+ scoped {+ } in if (true) {+ value <- 1+ } else {+ value <- 2+ }+ \ value }
tests/fast-static/program.0rx view
@@ -4,9 +4,9 @@ define Program { run () {- \ LazyStream<Formatted>.new()- .append($ExprLookup[MODULE_PATH]$ + "\n")- .append("Static linking works!\n")- .writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout()+ .write($ExprLookup[MODULE_PATH]$ + "\n")+ .write("Static linking works!\n")+ .flush() } }
tests/filters.0rt view
@@ -364,3 +364,155 @@ \ call<Char>(empty) } }+++testcase "filters with internal functions" {+ compiles+}++concrete Test {}++define Test {+ @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)+ }++ @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)+ }++ @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)+ }+}+++testcase "filters on internal @category function with same param names as category" {+ compiles+}++concrete Test<#x,#y> {}++define Test {+ @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)+ }+}+++testcase "allows intersection success" {+ compiles+}++unittest test {+ \ Test.call<AsBool>()+}++concrete Test {+ @type call<#x>+ #x allows [Formatted&AsBool]+ () -> (#x)+}++define Test {+ call () {+ return "message"+ }+}+++testcase "allows intersection fail" {+ error+ require "Int"+ require "Formatted"+ require "AsBool"+ exclude "String"+}++unittest test {+ \ Test.call<Int>()+}++concrete Test {+ @type call<#x>+ #x allows [Formatted&AsBool]+ () -> (#x)+}++define Test {+ call () {+ return "message"+ }+}+++testcase "requires union success" {+ compiles+}++unittest test {+ \ Test.call<Int>(1)+}++concrete Test {+ @type call<#x>+ #x requires [Int|String]+ (#x) -> ()+}++define Test {+ call (x) {+ \ x?Formatted.formatted()+ }+}+++testcase "requires union fail" {+ error+ require "Formatted"+ require "Int"+ require "String"+}++unittest test {+ \ Test.call<Formatted>(1)+}++concrete Test {+ @type call<#x>+ #x requires [Int|String]+ (#x) -> ()+}++define Test {+ call (x) {+ \ x?Formatted.formatted()+ }+}
tests/function-calls.0rt view
@@ -16,157 +16,269 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -testcase "converted call" {- success+testcase "call from union failed merge" {+ error+ require "\[Value1\|Value2\]"+ require "get"+ require "[Mm]ultiple" } unittest test {- Value value <- Value.create()- \ value.Base.call()+ [Value1|Value2] value <- Value1.create()+ \ value.get() } -@value interface Base {- call () -> ()+@value interface Base<|#x> {+ get () -> (#x) } -concrete Value {- refines Base+concrete Value1 {+ refines Base<Int>+ @type create () -> (Value1)+} - @type create () -> (Value)+define Value1 {+ get () {+ return 1+ }++ create () {+ return Value1{ }+ } } -define Value {- call () {}+concrete Value2 {+ refines Base<String>+ @type create () -> (Value2)+} +define Value2 {+ get () {+ return "message"+ }+ create () {- return Value{}+ return Value2{ } } } -testcase "converted call bad type" {+testcase "call from union ambiguous base" { error+ require "\[Value1\|Value2\]"+ require "get"+ require "explicit" require "Base" } unittest test {- Value value <- Value.create()- \ value.Base.call()+ [Value1|Value2] value <- Value1.create()+ \ value.get() } -@value interface Base {- call () -> ()+@value interface Base<|#x> {+ get () -> (#x) } -concrete Value {- @value call () -> ()- @type create () -> (Value)+concrete Value1 {+ refines Base<Int>+ @type create () -> (Value1)+ @value get () -> (Int) } -define Value {- call () {}+define Value1 {+ get () {+ return 1+ } create () {- return Value{}+ return Value1{ } } } +concrete Value2 {+ refines Base<String>+ @type create () -> (Value2)+} -testcase "call from union" {+define Value2 {+ get () {+ return "message"+ }++ create () {+ return Value2{ }+ }+}+++testcase "call from union bad function name" { error- require "\[Base\|Value\]"+ require "\[Int\|String\]"+ require "asFloat" } unittest test {- [Base|Value] value <- Value.create()- \ value.call()+ [Int|String] value <- 1+ \ value.asFloat() } -@value interface Base {- call () -> ()++testcase "call from union automatic merge" {+ success } -concrete Value {- refines Base+unittest test {+ [Value1|Value2] value <- Value1.create()+ \ Testing.checkEquals(value.get().formatted(),"1")+} - @type create () -> (Value)+@value interface Base<|#x> {+ get () -> (#x) } -define Value {- call () {}+concrete Value1 {+ refines Base<Formatted>+ @type create () -> (Value1)+} +define Value1 {+ get () {+ return 1+ }+ create () {- return Value{}+ return Value1{ } } } +concrete Value2 {+ refines Base<String>+ @type create () -> (Value2)+} -testcase "call from union with conversion" {- success+define Value2 {+ get () {+ return "message"+ }++ create () {+ return Value2{ }+ } } ++testcase "call from union automatic merge correct direction" {+ error+ require "Formatted.+Int"+ require "\+"+ exclude "\[Value1\|Value2\]"+ exclude "get"+}+ unittest test {- [Base|Value] value <- Value.create()- \ value.Base.call()+ [Value1|Value2] value <- Value1.create()+ \ value.get()+1 } -@value interface Base {- call () -> ()+@value interface Base<|#x> {+ get () -> (#x) } -concrete Value {- refines Base+concrete Value1 {+ refines Base<Int>+ @type create () -> (Value1)+} - @type create () -> (Value)+define Value1 {+ get () {+ return 1+ }++ create () {+ return Value1{ }+ } } -define Value {- call () {}+concrete Value2 {+ refines Base<Formatted>+ @type create () -> (Value2)+} +define Value2 {+ get () {+ return "message"+ }+ create () {- return Value{}+ return Value2{ } } } -testcase "call from intersect" {+testcase "call from union explicit conversion" { success } unittest test {- [Base1&Base2] value <- Value.create()- \ value.call()+ [Value1|Value2] value <- Value1.create()+ \ Testing.checkEquals(value?Base<Formatted>.get().formatted(),"1") } -@value interface Base1 {- call () -> ()+@value interface Base<|#x> {+ get () -> (#x) } -@value interface Base2 {}+concrete Value1 {+ refines Base<Int>+ @type create () -> (Value1)+} -concrete Value {- refines Base1- refines Base2+define Value1 {+ get () {+ return 1+ } - @type create () -> (Value)+ create () {+ return Value1{ }+ } } -define Value {- call () {}+concrete Value2 {+ refines Base<String>+ @type create () -> (Value2)+} +define Value2 {+ get () {+ return "message"+ }+ create () {- return Value{}+ return Value2{ } } } -testcase "call from intersect with conversion" {+testcase "call from all fails" {+ error+ require "formatted"+ require "all"+}++unittest test {+ optional all value <- empty+ \ require(value).formatted()+}+++testcase "call from intersect" { success } unittest test { [Base1&Base2] value <- Value.create()- \ value.Base1.call()+ \ value.call() } @value interface Base1 {@@ -197,7 +309,7 @@ unittest test { [Base1&Base2] value <- Value.create()- \ value.Base1.call()+ \ value?Base1.call() } @value interface Base1 {@@ -734,5 +846,61 @@ call (_,x,_,y) { return x+y.formatted()+ }+}+++testcase "@type function calls" {+ success+}++unittest sameType {+ \ Testing.checkEquals(Value<Int>.sameType(),"Value<Int>")+}++unittest sameValue {+ \ Testing.checkEquals(Value<Int>.create().sameValue(),"Value<Int>")+}++unittest diffType {+ \ Testing.checkEquals(Value<Int>.diffType<String>(),"Value<String>")+}++unittest diffValue {+ \ Testing.checkEquals(Value<Int>.create().diffValue<String>(),"Value<String>")+}++concrete Value<#x> {+ @type create () -> (#self)+ @type call () -> (String)+ @type sameType () -> (String)+ @value sameValue () -> (String)+ @type diffType<#y> () -> (String)+ @value diffValue<#y> () -> (String)+}++define Value {+ create () {+ return #self{ }+ }++ call () {+ return typename<#self>().formatted()+ }++ sameType () {+ return Value<#x>.call()+ }++ sameValue () {+ return Value<#x>.call()+ }++ diffType () {+ return Value<#y>.call()+ }++ diffValue () {+ return Value<#y>.call() } }
tests/leak-check/leak-check.0rx view
@@ -10,9 +10,7 @@ \ message() } elif (Argv.global().readAt(1) == "race") { \ runWith(1000,0)- \ LazyStream<Formatted>.new()- .append("no race conditions this time\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr().writeNow("no race conditions this time\n") } elif (Argv.global().readAt(1) == "leak") { \ runWith(100,0) } elif (Argv.global().readAt(1) == "forever") {@@ -41,19 +39,19 @@ #f defines ThreadFactory (Int,Int,ReadAt<BarrierWait>) -> () doIteration (i,size,barriers) {- \ LazyStream<Formatted>.new()- .append(typename<#f>())- .append(": iteration ")- .append(i)- .append("\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr()+ .write(typename<#f>())+ .write(": iteration ")+ .write(i)+ .write("\n")+ .flush() optional LeakTest original <- LeakTest{ Vector:createSize<Int>(size) } weak LeakTest checkedValue <- original $ReadOnly[checkedValue]$ scoped {- Vector<Thread> threads <- Vector:create<Thread>()+ 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())
tests/self-type.0rt view
@@ -584,3 +584,175 @@ #x requires #self () -> () }+++testcase "convert self to interface with #self as param" {+ compiles+}++@value interface Reader<|#x> {+ call () -> (Reader<#x>)+}++@type interface Factory<|#x> {+ create () -> (Reader<#x>)+}++concrete Type {+ defines Factory<#self>+ refines Reader<#self>+}++define Type {+ call () (y) {+ y <- self+ return self+ }++ create () (y) {+ y <- Type{ }+ return Type{ }+ }++ @category something () -> (Reader<Type>)+ something () (y) {+ y <- Type{ }+ return Type{ }+ }+}+++testcase "bad implicit conversion with #self in param" {+ error+ require "Int"+ require "Type"+ require "Reader"+ exclude "#self"+}++@value interface Reader<|#x> {+ call () -> (Reader<#x>)+}++concrete Type {+ refines Reader<#self>+}++define Type {+ call () (y) {+ optional Reader<Int> value <- empty+ y <- require(value)+ }+}+++testcase "bad explicit conversion with #self in param" {+ error+ require "Int"+ require "Type"+ require "Reader"+ exclude "#self"+}++@value interface Reader<|#x> {}++concrete Type {+ refines Reader<#self>+}++define Type {+ @value call () -> ()+ call () {+ \ self?Reader<Int>+ }+}+++testcase "#self cannot be contravariant in refine" {+ error+ require "#self"+ require "Base"+ require "contravariant"+}++@value interface Base<#x|> {}++concrete Type {+ refines Base<#self>+}++define Type {}+++testcase "#self cannot be contravariant in define" {+ error+ require "#self"+ require "Base"+ require "contravariant"+}++@type interface Base<#x|> {}++concrete Type {+ defines Base<#self>+}++define Type {}+++testcase "#self cannot be invariant in refine" {+ error+ require "#self"+ require "Base"+ require "invariant"+}++@value interface Base<#x> {}++concrete Type {+ refines Base<#self>+}++define Type {}+++testcase "#self cannot be invariant in define" {+ error+ require "#self"+ require "Base"+ require "invariant"+}++@type interface Base<#x> {}++concrete Type {+ defines Base<#self>+}++define Type {}+++testcase "#self nested in value init with filters" {+ success+}++unittest test {+ \ Testing.checkEquals(Type<Int>.create().formatted(),"Type<Type<Int>>")+}++concrete Type<|#x> {+ refines Formatted+ #x requires Formatted++ @type create () -> (Type<#self>)+}++define Type {+ create () {+ return Type<#self>{ }+ }++ formatted () {+ return typename<#self>().formatted()+ }+}
tests/simulate-refs/main.0rx view
@@ -22,7 +22,7 @@ define SimulateRefs { @category Int errorLimit <- 10- @category RandomUniform random <- RandomUniform.new(0.0,1.0).setSeed(Realtime.monoSeconds().asInt())+ @category RandomUniform random <- RandomUniform.probability().setSeed(Realtime.monoSeconds().asInt()) run () { Bool useBroken <- Argv.global().size() > 1 && Argv.global().readAt(1) == "broken"@@ -32,11 +32,11 @@ } traverse (Counter.unlimited() -> Int i) {- \ LazyStream<Formatted>.new()- .append("Iteration ")- .append(i)- .append("\n")- .writeTo(SimpleOutput.stderr())+ \ BasicOutput.stderr()+ .write("Iteration ")+ .write(i)+ .write("\n")+ .flush() if (!runOnce(useBroken) && (errorLimit <- errorLimit-1) == 0) { break@@ -46,7 +46,7 @@ @type getRoutines (ReferenceState) -> (DefaultOrder<StateMachine>) getRoutines (state) {- return Vector:create<StateMachine>()+ return Vector<StateMachine>.new() .append(Routines.newShared("shared1",state)) .append(Routines.newWeak("weak1",state)) .append(Routines.newWeak("weak2",state))@@ -54,7 +54,7 @@ @type getRoutinesBroken (ReferenceState) -> (DefaultOrder<StateMachine>) getRoutinesBroken (state) {- return Vector:create<StateMachine>()+ return Vector<StateMachine>.new() .append(Routines.newSharedBroken("shared1",state)) .append(Routines.newWeakBroken("weak1",state)) .append(Routines.newWeakBroken("weak2",state))@@ -80,19 +80,19 @@ error <- "expected unlocked final reference" } } in if (present(error)) {- \ LazyStream<Formatted>.new()- .append("Error in final state: ")- .append(require(error))- .append("\nFinal state: ")- .append(state)- .append("\n")- .writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout()+ .write("Error in final state: ")+ .write(require(error))+ .write("\nFinal state: ")+ .write(state)+ .write("\n")+ .flush() traverse (state.getOperations() -> Formatted operation) {- \ LazyStream<Formatted>.new()- .append(" ")- .append(operation)- .append("\n")- .writeTo(SimpleOutput.stdout())+ \ BasicOutput.stdout()+ .write(" ")+ .write(operation)+ .write("\n")+ .flush() } return false } else {
tests/simulate-refs/ref-state.0rx view
@@ -25,7 +25,7 @@ @value [Append<Formatted>&DefaultOrder<Formatted>] operations new () {- return ReferenceState{ 0, 0, false, 0, 0, Vector:create<Formatted>() }+ return ReferenceState{ 0, 0, false, 0, 0, Vector<Formatted>.new() } } addOperation (name) {
tests/simulate-refs/state.0rx view
@@ -18,7 +18,7 @@ define StateExecutor { multiplexStates (original,random) {- SearchTree<Int,StateMachine> states <- SearchTree<Int,StateMachine>.new()+ HashedMap<Int,StateMachine> states <- HashedMap<Int,StateMachine>.new() CategoricalTree<Int> weights <- CategoricalTree<Int>.new() scoped {
tests/unary-functions.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+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.@@ -138,4 +138,33 @@ neg (x) { return -x }+}+++testcase "builtins as unary" {+ success+}++unittest requireUnary {+ optional Int value <- 1+ \ Testing.checkEquals(`require` value,1)+}++unittest presentUnary {+ optional Int value <- 1+ \ Testing.checkTrue(`present` value)+ value <- empty+ \ Testing.checkTrue(! `present` value)+}++unittest strongUnary {+ weak Int value <- 1+ optional Int value2 <- `strong` value+ \ Testing.checkTrue(present(value2))+ \ Testing.checkTrue(`present` `strong` value)+}++unittest reduceUnary {+ optional Formatted value <- `reduce<Int,Formatted>` 123+ \ Testing.checkEquals(require(value).formatted(),"123") }
tests/value-init.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+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.@@ -164,5 +164,22 @@ get () { return value+ }+}+++testcase "wrong base type" {+ error+ require "Value"+ require "Int"+}++concrete Value {+ @type create () -> (Int)+}++define Value {+ create () {+ return Int{ } } }
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: zeolite-lang-version: 0.21.0.0+version: 0.22.0.0 synopsis: Zeolite is a statically-typed, general-purpose programming language. description: