packages feed

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 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] = &param;+  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] = &param;+  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: