zeolite-lang 0.22.1.0 → 0.23.0.0
raw patch · 56 files changed
+1614/−625 lines, 56 files
Files
- ChangeLog.md +42/−0
- base/.zeolite-module +4/−0
- base/boxed.hpp +30/−13
- base/builtin.0rp +14/−1
- base/category-source.hpp +33/−10
- base/src/Extension_Bool.cpp +1/−5
- base/src/Extension_Char.cpp +1/−5
- base/src/Extension_Float.cpp +1/−5
- base/src/Extension_Int.cpp +1/−5
- base/src/Extension_Pointer.cpp +62/−0
- base/src/boxed.cpp +49/−43
- base/src/logging.cpp +19/−14
- base/types.hpp +4/−1
- bin/zeolite.hs +12/−2
- example/random/.zeolite-module +0/−1
- lib/thread/.zeolite-module +0/−4
- lib/thread/src/Extension_ProcessThread.cpp +37/−8
- lib/thread/src/Extension_Realtime.cpp +0/−106
- lib/thread/src/testing.0rp +7/−1
- lib/thread/src/testing.0rx +11/−1
- lib/thread/test/thread.0rt +31/−1
- lib/thread/test/time.0rt +0/−79
- lib/thread/time.0rp +0/−35
- lib/util/.zeolite-module +4/−0
- lib/util/counters.0rp +52/−1
- lib/util/src/Extension_Realtime.cpp +106/−0
- lib/util/src/counters.0rx +84/−68
- lib/util/test/counters.0rt +38/−4
- lib/util/test/time.0rt +79/−0
- lib/util/time.0rp +35/−0
- src/Cli/Compiler.hs +21/−16
- src/Compilation/CompilerState.hs +2/−2
- src/CompilerCxx/Code.hs +112/−94
- src/CompilerCxx/Procedure.hs +16/−3
- src/Module/ProcessMetadata.hs +18/−14
- src/Parser/Common.hs +6/−1
- src/Parser/Procedure.hs +7/−1
- src/Parser/TypeInstance.hs +2/−1
- src/Test/Procedure.hs +5/−1
- src/Types/Builtin.hs +12/−2
- src/Types/Procedure.hs +3/−1
- src/Types/TypeInstance.hs +3/−1
- tests/cli-tests.sh +9/−2
- tests/failure.0rt +0/−69
- tests/pointer/.zeolite-module +21/−0
- tests/pointer/Extension_Request.cpp +92/−0
- tests/pointer/Extension_Response.cpp +92/−0
- tests/pointer/Extension_Service.cpp +82/−0
- tests/pointer/README.md +11/−0
- tests/pointer/call.0rp +50/−0
- tests/pointer/call.0rt +100/−0
- tests/pointer/call.hpp +53/−0
- tests/program-exit.0rt +121/−0
- tests/simple.0rt +11/−1
- tests/simulate-refs/.zeolite-module +0/−1
- zeolite-lang.cabal +8/−2
ChangeLog.md view
@@ -1,5 +1,47 @@ # Revision history for zeolite-lang +## 0.23.0.0 -- 2022-10-08++### Language++* **[breaking]** Adds the `exit` builtin to terminate the program with an exit+ code, with the usual semantics, i.e., 0 means success. This is breaking+ because `exit` is now a reserved name.++* **[breaking]** Adds the `Pointer<#x>` builtin `concrete` category, for use in+ C++ extensions. (This is breaking because `Pointer` is now reserved.)++### Compiler CLI++* **[new]** Adds general pointer storage to `BoxedValue` to allow C++ extensions+ to pass data to each other without marshaling.++ ```c+++ // Create a value that can be returned/passed in Zeolite function calls.+ BoxedValue boxed = Box_Pointer<Foo>(&value);++ // Access the pointer stored in the value.+ Foo* unboxed = boxed.AsPointer<Foo>();+ ```++ This is only type-safe if the Zeolite code uses a different `#x` in+ `Pointer<#x>` for each different type used with `Box_Pointer`/`AsPointer`.+ For example, the code above uses `Foo`, so `Pointer<Foo>` should be used+ everywhere such values are passed around in the Zeolite code. (`#x` is+ arbitrary, but it's more clear if the name used in Zeolite corresponds to the+ name of the C++ type.)++* **[new]** Adds % code coverage in output of `zeolite --missed-lines`.++### Libraries++* **[new]** Moves `Realtime` from `lib/thread` to `lib/util` since it doesn't+ inherently require threads. (This isn't breaking because `lib/util` was+ already a *public* dependency of `lib/thread`.)++* **[new]** Adds the `Counter.builder()` function to `lib/util` to build `Int`+ counters with more flexibile limits and increments.+ ## 0.22.1.0 -- 2022-04-18 ### Language
base/.zeolite-module view
@@ -25,6 +25,10 @@ source: "base/src/Extension_String.cpp" categories: [String] }+ category_source {+ source: "base/src/Extension_Pointer.cpp"+ categories: [Pointer]+ } "base/boxed.hpp" "base/category-header.hpp" "base/category-source.hpp"
base/boxed.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -38,6 +38,7 @@ CHAR, INT, FLOAT,+ POINTER, BOXED, }; @@ -54,11 +55,12 @@ union { unsigned char* as_bytes_;- Pointer* as_pointer_;- PrimBool as_bool_;- PrimChar as_char_;- PrimInt as_int_;- PrimFloat as_float_;+ Pointer* as_boxed_;+ PrimBool as_bool_;+ PrimChar as_char_;+ PrimInt as_int_;+ PrimFloat as_float_;+ PrimPointer as_pointer_; } __attribute__((packed)) value_; } __attribute__((packed)); @@ -66,13 +68,13 @@ class BoxedValue { public: constexpr BoxedValue()- : union_{ .type_ = UnionValue::Type::EMPTY, .value_ = { .as_pointer_ = nullptr } } {}+ : union_{ .type_ = UnionValue::Type::EMPTY, .value_ = { .as_boxed_ = nullptr } } {} inline BoxedValue(const BoxedValue& other) : union_(other.union_) { switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->strong_;+ ++union_.value_.as_boxed_->strong_; break; default: break;@@ -87,7 +89,7 @@ union_ = other.union_; switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->strong_;+ ++union_.value_.as_boxed_->strong_; break; default: break;@@ -99,7 +101,7 @@ inline BoxedValue(BoxedValue&& other) : union_(other.union_) { other.union_.type_ = UnionValue::Type::EMPTY;- other.union_.value_.as_pointer_ = nullptr;+ other.union_.value_.as_boxed_ = nullptr; } inline BoxedValue& operator = (BoxedValue&& other) {@@ -109,7 +111,7 @@ } union_ = other.union_; other.union_.type_ = UnionValue::Type::EMPTY;- other.union_.value_.as_pointer_ = nullptr;+ other.union_.value_.as_boxed_ = nullptr; } return *this; }@@ -126,6 +128,9 @@ inline BoxedValue(PrimFloat value) : union_{ .type_ = UnionValue::Type::FLOAT, .value_ = { .as_float_ = value } } {} + inline BoxedValue(PrimPointer value)+ : union_{ .type_ = UnionValue::Type::POINTER, .value_ = { .as_pointer_ = value } } {}+ template<class T, class... As> static inline BoxedValue New(const As&... args) { using Pointer = UnionValue::Pointer;@@ -188,6 +193,18 @@ } } + template<class T>+ inline T* AsPointer() const {+ switch (union_.type_) {+ case UnionValue::Type::POINTER:+ return reinterpret_cast<T*>(union_.value_.as_boxed_);+ default:+ FAIL() << union_.CategoryName() << " is not a Pointer value";+ __builtin_unreachable();+ break;+ }+ }+ inline static bool Present(const BoxedValue& target) { return target.union_.type_ != UnionValue::Type::EMPTY; }@@ -229,8 +246,8 @@ value.union_.type_ = UnionValue::Type::BOXED; value.union_.value_.as_bytes_ = reinterpret_cast<unsigned char*>(const_cast<T*>(pointer))-sizeof(UnionValue::Pointer);- if (value.union_.value_.as_pointer_->object_ != pointer ||- ++value.union_.value_.as_pointer_->strong_ == 1) {+ if (value.union_.value_.as_boxed_->object_ != pointer ||+ ++value.union_.value_.as_boxed_->strong_ == 1) { FAIL() << "Bad VAR_SELF pointer " << pointer << " in " << pointer->CategoryName(); } return value;
base/builtin.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -183,6 +183,19 @@ // Specifically, resizing down and then back up again could either preserve // or overwrite any of the data. @value resize (Int) -> (CharBuffer)+}++// A raw pointer type for use in C++ extensions.+//+// Literals: None.+//+// Notes:+// - #x is mostly irrelevant. It is only intended for differentiating between+// values with incompatible types.+// - This is category is only meant for passing C++ data between extensions when+// it would otherwise require marshaling, which is why it has no functions.+concrete Pointer<#x> {+ immutable } // Convertible to Bool.
base/category-source.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -19,6 +19,7 @@ #ifndef CATEGORY_SOURCE_HPP_ #define CATEGORY_SOURCE_HPP_ +#include <cstdlib> #include <iostream> // For occasional debugging output in generated code. #include <map> #include <sstream>@@ -32,25 +33,47 @@ #define BUILTIN_FAIL(e) { \- FAIL() << TypeValue::Call((e), Function_Formatted_formatted, \- PassParamsArgs()).At(0).AsString(); \- __builtin_unreachable(); \+ FAIL() << TypeValue::Call((e), Function_Formatted_formatted, \+ PassParamsArgs()).At(0).AsString(); \+ __builtin_unreachable(); \ } +#define BUILTIN_EXIT(e) { \+ std::exit(e); \+ __builtin_unreachable(); \+ }+ #define RAW_FAIL(e) { \- FAIL() << e; \- __builtin_unreachable(); \+ FAIL() << e; \+ __builtin_unreachable(); \ } #define VAR_SELF TypeValue::Var_self(this) #define PARAM_SELF Param_self() -BoxedValue Box_Bool(PrimBool value);+inline BoxedValue Box_Bool(PrimBool value) {+ return BoxedValue(value);+}++inline BoxedValue Box_Char(PrimChar value) {+ return BoxedValue(value);+}++inline BoxedValue Box_Float(PrimFloat value) {+ return BoxedValue(value);+}++inline BoxedValue Box_Int(PrimInt value) {+ return BoxedValue(value);+}++template<class T1, class T2>+inline BoxedValue Box_Pointer(T2* value) {+ return BoxedValue(reinterpret_cast<PrimPointer>(static_cast<T1*>(value)));+}+ BoxedValue Box_String(const PrimString& value);-BoxedValue Box_Char(PrimChar value);-BoxedValue Box_Int(PrimInt value);-BoxedValue Box_Float(PrimFloat value); S<const TypeInstance> Merge_Intersect(const L<S<const TypeInstance>>& params); S<const TypeInstance> Merge_Union(const L<S<const TypeInstance>>& params);
base/src/Extension_Bool.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -98,7 +98,3 @@ } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE; #endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue Box_Bool(PrimBool value) {- return BoxedValue(value);-}
base/src/Extension_Char.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -113,7 +113,3 @@ } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE; #endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue Box_Char(PrimChar value) {- return BoxedValue(value);-}
base/src/Extension_Float.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -105,7 +105,3 @@ } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE; #endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue Box_Float(PrimFloat value) {- return BoxedValue(value);-}
base/src/Extension_Int.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -116,7 +116,3 @@ } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE; #endif // ZEOLITE_PUBLIC_NAMESPACE--BoxedValue Box_Int(PrimInt value) {- return BoxedValue(value);-}
+ base/src/Extension_Pointer.cpp view
@@ -0,0 +1,62 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Pointer.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Pointer : public Category_Pointer {+};++struct ExtType_Pointer : public Type_Pointer {+ inline ExtType_Pointer(Category_Pointer& p, Params<1>::Type params) : Type_Pointer(p, params) {}+};++ReturnTuple DispatchPointer(PrimPointer value, const ValueFunction& label,+ const ParamsArgs& params_args) {+ switch (label.collection) {+ default:+ FAIL() << "Pointer does not implement " << label;+ __builtin_unreachable();+ }+}++Category_Pointer& CreateCategory_Pointer() {+ static auto& category = *new ExtCategory_Pointer();+ return category;+}++static auto& Pointer_instance_cache = *new InstanceCache<1, Type_Pointer>([](const Params<1>::Type& params) {+ return S_get(new ExtType_Pointer(CreateCategory_Pointer(), params));+ });++S<const Type_Pointer> CreateType_Pointer(const Params<1>::Type& params) {+ return Pointer_instance_cache.GetOrCreate(params);+}++void RemoveType_Pointer(const Params<1>::Type& params) {+ Pointer_instance_cache.Remove(params);+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
base/src/boxed.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -39,6 +39,9 @@ ReturnTuple DispatchFloat(PrimFloat value, const ValueFunction& label, const ParamsArgs& params_args) __attribute__((weak)); +ReturnTuple DispatchPointer(PrimPointer value, const ValueFunction& label,+ const ParamsArgs& params_args) __attribute__((weak));+ #ifdef ZEOLITE_PUBLIC_NAMESPACE } // namespace ZEOLITE_PUBLIC_NAMESPACE using namespace ZEOLITE_PUBLIC_NAMESPACE;@@ -51,26 +54,26 @@ void Validate(const std::string& name, const UnionValue& the_union) { if (the_union.type_ == UnionValue::Type::BOXED) {- const auto strong = the_union.value_.as_pointer_->strong_.load();- const auto weak = the_union.value_.as_pointer_->weak_.load();- const TypeValue* const object = the_union.value_.as_pointer_->object_;+ const auto strong = the_union.value_.as_boxed_->strong_.load();+ const auto weak = the_union.value_.as_boxed_->weak_.load();+ const TypeValue* const object = the_union.value_.as_boxed_->object_; const std::string type = object ? the_union.CategoryName() : "deleted value"; if (strong == 0 && object) { FAIL() << "Leaked " << type << " " << name << " at "- << ((void*) the_union.value_.as_pointer_) << " (S: "+ << ((void*) the_union.value_.as_boxed_) << " (S: " << std::hex << strong << " W: " << weak << ")"; } if (strong != 0 && !object) { FAIL() << "Prematurely deleted value " << name << " at "- << ((void*) the_union.value_.as_pointer_) << " (S: "+ << ((void*) the_union.value_.as_boxed_) << " (S: " << std::hex << strong << " W: " << weak << ")"; } if (strong < 0 || weak < 0 || (weak == 0 && strong > 0)) { FAIL() << "Invalid counts for " << type << " " << name << " at "- << ((void*) the_union.value_.as_pointer_) << " (S: "+ << ((void*) the_union.value_.as_boxed_) << " (S: " << std::hex << strong << " W: " << weak << ")"; } }@@ -80,16 +83,17 @@ std::string UnionValue::CategoryName() const { switch (type_) {- case UnionValue::Type::EMPTY: return "empty";- case UnionValue::Type::BOOL: return "Bool";- case UnionValue::Type::CHAR: return "Char";- case UnionValue::Type::INT: return "Int";- case UnionValue::Type::FLOAT: return "Float";+ case UnionValue::Type::EMPTY: return "empty";+ case UnionValue::Type::BOOL: return "Bool";+ case UnionValue::Type::CHAR: return "Char";+ case UnionValue::Type::INT: return "Int";+ case UnionValue::Type::FLOAT: return "Float";+ case UnionValue::Type::POINTER: return "Pointer"; case UnionValue::Type::BOXED:- if (!value_.as_pointer_ || !value_.as_pointer_->object_) {+ if (!value_.as_boxed_ || !value_.as_boxed_->object_) { FAIL() << "Function called on null pointer"; }- return value_.as_pointer_->object_->CategoryName();+ return value_.as_boxed_->object_->CategoryName(); } } @@ -97,14 +101,14 @@ : union_(other.union_) { switch (union_.type_) { case UnionValue::Type::BOXED:- while (union_.value_.as_pointer_->lock_.test_and_set(std::memory_order_acquire));- if (++union_.value_.as_pointer_->strong_ == 1) {- --union_.value_.as_pointer_->strong_;- union_.value_.as_pointer_->lock_.clear(std::memory_order_release);+ while (union_.value_.as_boxed_->lock_.test_and_set(std::memory_order_acquire));+ if (++union_.value_.as_boxed_->strong_ == 1) {+ --union_.value_.as_boxed_->strong_;+ union_.value_.as_boxed_->lock_.clear(std::memory_order_release); union_.type_ = UnionValue::Type::EMPTY;- union_.value_.as_pointer_ = nullptr;+ union_.value_.as_boxed_ = nullptr; } else {- union_.value_.as_pointer_->lock_.clear(std::memory_order_release);+ union_.value_.as_boxed_->lock_.clear(std::memory_order_release); } break; default:@@ -119,10 +123,10 @@ const PrimString& BoxedValue::AsString() const { switch (union_.type_) { case UnionValue::Type::BOXED:- if (!union_.value_.as_pointer_ || !union_.value_.as_pointer_->object_) {+ if (!union_.value_.as_boxed_ || !union_.value_.as_boxed_->object_) { FAIL() << "Function called on null pointer"; }- return union_.value_.as_pointer_->object_->AsString();+ return union_.value_.as_boxed_->object_->AsString(); default: FAIL() << union_.CategoryName() << " is not a String value"; __builtin_unreachable();@@ -133,10 +137,10 @@ PrimCharBuffer& BoxedValue::AsCharBuffer() const { switch (union_.type_) { case UnionValue::Type::BOXED:- if (!union_.value_.as_pointer_ || !union_.value_.as_pointer_->object_) {+ if (!union_.value_.as_boxed_ || !union_.value_.as_boxed_->object_) { FAIL() << "Function called on null pointer"; }- return union_.value_.as_pointer_->object_->AsCharBuffer();+ return union_.value_.as_boxed_->object_->AsCharBuffer(); default: FAIL() << union_.CategoryName() << " is not a CharBuffer value"; __builtin_unreachable();@@ -159,24 +163,26 @@ return DispatchInt(union_.value_.as_int_, label, params_args); case UnionValue::Type::FLOAT: return DispatchFloat(union_.value_.as_float_, label, params_args);+ case UnionValue::Type::POINTER:+ return DispatchPointer(union_.value_.as_pointer_, label, params_args); case UnionValue::Type::BOXED:- if (!union_.value_.as_pointer_ || !union_.value_.as_pointer_->object_) {+ if (!union_.value_.as_boxed_ || !union_.value_.as_boxed_->object_) { FAIL() << "Function called on null pointer"; }- return union_.value_.as_pointer_->object_->Dispatch(label, params_args);+ return union_.value_.as_boxed_->object_->Dispatch(label, params_args); } } void BoxedValue::Cleanup() { while (union_.type_ == UnionValue::Type::BOXED) {- while (union_.value_.as_pointer_->lock_.test_and_set(std::memory_order_acquire));- if (--union_.value_.as_pointer_->strong_ == 0) {- TypeValue* const object = union_.value_.as_pointer_->object_;- union_.value_.as_pointer_->object_ = nullptr;- union_.value_.as_pointer_->lock_.clear(std::memory_order_release);+ while (union_.value_.as_boxed_->lock_.test_and_set(std::memory_order_acquire));+ if (--union_.value_.as_boxed_->strong_ == 0) {+ TypeValue* const object = union_.value_.as_boxed_->object_;+ union_.value_.as_boxed_->object_ = nullptr;+ union_.value_.as_boxed_->lock_.clear(std::memory_order_release); BoxedValue next = object->FlatCleanup(); object->~TypeValue();- if (--union_.value_.as_pointer_->weak_ == 0) {+ if (--union_.value_.as_boxed_->weak_ == 0) { // NOTE: as_bytes_ contains object => ~TypeValue() must happen first. free(union_.value_.as_bytes_); }@@ -184,23 +190,23 @@ // This is only to skip cleanup of next. next.union_.type_ = UnionValue::Type::EMPTY; } else {- union_.value_.as_pointer_->lock_.clear(std::memory_order_release);+ union_.value_.as_boxed_->lock_.clear(std::memory_order_release); break; } } union_.type_ = UnionValue::Type::EMPTY;- union_.value_.as_pointer_ = nullptr;+ union_.value_.as_boxed_ = nullptr; } WeakValue::WeakValue()- : union_{ .type_ = UnionValue::Type::EMPTY, .value_ = { .as_pointer_ = nullptr } } {}+ : union_{ .type_ = UnionValue::Type::EMPTY, .value_ = { .as_boxed_ = nullptr } } {} WeakValue::WeakValue(const WeakValue& other) : union_(other.union_) { switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->weak_;+ ++union_.value_.as_boxed_->weak_; break; default: break;@@ -213,7 +219,7 @@ union_ = other.union_; switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->weak_;+ ++union_.value_.as_boxed_->weak_; break; default: break;@@ -225,7 +231,7 @@ WeakValue::WeakValue(WeakValue&& other) : union_(other.union_) { other.union_.type_ = UnionValue::Type::EMPTY;- other.union_.value_.as_pointer_ = nullptr;+ other.union_.value_.as_boxed_ = nullptr; } WeakValue& WeakValue::operator = (WeakValue&& other) {@@ -233,7 +239,7 @@ Cleanup(); union_ = other.union_; other.union_.type_ = UnionValue::Type::EMPTY;- other.union_.value_.as_pointer_ = nullptr;+ other.union_.value_.as_boxed_ = nullptr; } return *this; }@@ -242,7 +248,7 @@ : union_(other.union_) { switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->weak_;+ ++union_.value_.as_boxed_->weak_; break; default: break;@@ -254,7 +260,7 @@ union_ = other.union_; switch (union_.type_) { case UnionValue::Type::BOXED:- ++union_.value_.as_pointer_->weak_;+ ++union_.value_.as_boxed_->weak_; break; default: break;@@ -273,7 +279,7 @@ void WeakValue::Cleanup() { switch (union_.type_) { case UnionValue::Type::BOXED:- if (--union_.value_.as_pointer_->weak_ == 0) {+ if (--union_.value_.as_boxed_->weak_ == 0) { free(union_.value_.as_bytes_); } break;@@ -281,7 +287,7 @@ break; } union_.type_ = UnionValue::Type::EMPTY;- union_.value_.as_pointer_ = nullptr;+ union_.value_.as_boxed_ = nullptr; } } // namespace zeolite_internal
base/src/logging.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -191,6 +191,22 @@ return argv_; } +namespace {++std::unique_ptr<std::fstream> TryOpenOutputLog(const std::string& filename) {+ if (filename.empty()) return nullptr;+ std::unique_ptr<std::fstream> file(new std::fstream(+ filename, std::ios::in | std::ios::out | std::ios::ate | std::ios::app));+ if (*file) return file;+ // Maybe the file isn't seekable.+ file.reset(new std::fstream(filename, std::ios::out));+ if (*file) return file;+ FAIL() << "Failed to open call log " << filename << " for writing";+ __builtin_unreachable();+}++} // namespace+ unsigned int UniqueId() { const auto time = std::chrono::steady_clock::now().time_since_epoch(); return (1000000009 * std::chrono::duration_cast<std::chrono::microseconds>(time).count());@@ -206,19 +222,8 @@ LogCallsToFile::LogCallsToFile(std::string filename) : unique_id_(UniqueId()), filename_(std::move(filename)),- log_file_(filename_.empty()?- nullptr :- new std::fstream(filename_, std::ios::in |- std::ios::out |- std::ios::ate |- std::ios::app)),- cross_and_capture_to_(this) {- if (log_file_) {- if (!*log_file_) {- FAIL() << "Failed to open call log " << filename_ << " for writing";- }- }-}+ log_file_(TryOpenOutputLog(filename_)),+ cross_and_capture_to_(this) {} void LogCallsToFile::LogCall(const char* name, const char* at) { if (log_file_ && enable_coverage) {
base/types.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -43,6 +43,9 @@ using PrimChar = char; using PrimCharBuffer = std::string; using PrimFloat = double;++class OpaqueObject { ~OpaqueObject() = default; };+using PrimPointer = OpaqueObject*; template<int S> inline PrimString PrimString_FromLiteral(const char(&literal)[S]) {
bin/zeolite.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -24,6 +24,7 @@ import System.Exit import GHC.IO.Handle import System.IO+import Text.Printf (printf) import qualified Data.Map as Map import qualified Data.Set as Set @@ -122,8 +123,17 @@ h <- getCompilerHash backend expected <- fmap Set.unions $ mapCompilerM (getTraces h) ps actual <- loadTraces- mapM_ (errorFromIO . hPutStrLn stdout) $ Set.toList $ expected `Set.difference` actual+ let difference = expected `Set.difference` actual+ mapM_ (errorFromIO . hPutStrLn stdout) $ Set.toList $ difference+ errorFromIO $ hPutStrLn stdout $ formatCoverage difference expected exitSuccess where+ formatCoverage difference expected =+ "Coverage: " ++ show actualSize ++ " of " ++ show expectedSize +++ " lines (" ++ printf "%.2f" coverage ++ "%)" where+ diffSize = length $ Set.toList $ difference+ expectedSize = length $ Set.toList $ expected+ actualSize = expectedSize - diffSize+ coverage = 100.0 * (fromIntegral actualSize :: Double) / (fromIntegral expectedSize :: Double) loadTraces = do l' <- errorFromIO $ canonicalizePath (root </> l) errorFromIO $ hPutStrLn stderr $ "Loading trace data from \"" ++ l' ++ "\"."
example/random/.zeolite-module view
@@ -3,7 +3,6 @@ private_deps: [ "lib/util" "lib/math"- "lib/thread" ] mode: binary { category: RandomDemo
lib/thread/.zeolite-module view
@@ -16,10 +16,6 @@ categories: [ProcessThread] } category_source {- source: "lib/thread/src/Extension_Realtime.cpp"- categories: [Realtime]- }- category_source { source: "lib/thread/src/Extension_ThreadCondition.cpp" categories: [ThreadCondition] }
lib/thread/src/Extension_ProcessThread.cpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -31,6 +31,28 @@ namespace ZEOLITE_PUBLIC_NAMESPACE { #endif // ZEOLITE_PUBLIC_NAMESPACE +namespace {++class InheritTrace : public TraceContext {+ public:+ inline explicit InheritTrace(const TraceList& trace)+ : trace_(trace), capture_to_(this) {}++ private:+ void SetLocal(const char*) final {}++ void AppendTrace(TraceList& trace) const final{+ trace.insert(trace.end(), trace_.begin(), trace_.end());+ }++ const TraceContext* GetNext() const final { return nullptr; }++ const TraceList& trace_;+ const ScopedCapture capture_to_;+};++} // namespace+ BoxedValue CreateValue_ProcessThread(S<const Type_ProcessThread> parent, const ParamsArgs& params_args); struct ExtCategory_ProcessThread : public Category_ProcessThread {@@ -53,7 +75,7 @@ TRACE_FUNCTION("ProcessThread.detach") S<std::thread> temp = thread; thread = nullptr;- if (!isJoinable(temp.get())) {+ if (!IsJoinable(temp.get())) { FAIL() << "thread has not been started"; } else { temp->detach();@@ -63,14 +85,14 @@ ReturnTuple Call_isRunning(const ParamsArgs& params_args) final { TRACE_FUNCTION("ProcessThread.isRunning")- return ReturnTuple(Box_Bool(isJoinable(thread.get())));+ return ReturnTuple(Box_Bool(IsJoinable(thread.get()))); } ReturnTuple Call_join(const ParamsArgs& params_args) final { TRACE_FUNCTION("ProcessThread.join") S<std::thread> temp = thread; thread = nullptr;- if (!isJoinable(temp.get())) {+ if (!IsJoinable(temp.get())) { FAIL() << "thread has not been started"; } else { temp->join();@@ -79,8 +101,9 @@ } ReturnTuple Call_start(const ParamsArgs& params_args) final {+ const TraceList copied_trace = TraceContext::GetTrace(); TRACE_FUNCTION("ProcessThread.start")- if (isJoinable(thread.get())) {+ if (IsJoinable(thread.get())) { FAIL() << "thread is already running"; } else { // NOTE: Capture VAR_SELF so that the thread retains a reference while@@ -88,7 +111,13 @@ // the thread. const BoxedValue self = VAR_SELF; thread.reset(new std::thread(- capture_thread::ThreadCrosser::WrapCall([this,self] {+ capture_thread::ThreadCrosser::WrapCall([this,self,copied_trace] {+#ifndef DISABLE_TRACING+ InheritTrace inherit_trace(copied_trace);+#endif+ // NOTE: Don't include this in copied_trace because the latter defines+ // SetLocal as a no-op.+ TRACE_FUNCTION("ProcessThread.start") TRACE_CREATION TypeValue::Call(routine, Function_Routine_run, PassParamsArgs()); })));@@ -96,14 +125,14 @@ return ReturnTuple(VAR_SELF); } - inline static bool isJoinable(std::thread* thread) {+ inline static bool IsJoinable(std::thread* thread) { return thread && thread->joinable(); } ~ExtValue_ProcessThread() { S<std::thread> temp = thread; thread = nullptr;- if (isJoinable(temp.get())) {+ if (IsJoinable(temp.get())) { temp->detach(); } }
− lib/thread/src/Extension_Realtime.cpp
@@ -1,106 +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]--#include <errno.h>-#include <math.h>-#include <string.h>-#include <time.h>--#include <chrono>-#include <iomanip>-#include <thread>--#include "category-source.hpp"-#include "Streamlined_Realtime.hpp"-#include "Category_Float.hpp"-#include "Category_Realtime.hpp"--#ifndef SLEEP_SPINLOCK_LIMIT-#define SLEEP_SPINLOCK_LIMIT 0.001-#endif--#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE--struct ExtCategory_Realtime : public Category_Realtime {-};--struct ExtType_Realtime : public Type_Realtime {- inline ExtType_Realtime(Category_Realtime& p, Params<0>::Type params) : Type_Realtime(p, params) {}-- ReturnTuple Call_sleepSeconds(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Realtime.sleepSeconds")- const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();- if (Var_arg1 > 0) {- std::this_thread::sleep_for(std::chrono::duration<double>(Var_arg1));- }- return ReturnTuple();- }-- ReturnTuple Call_sleepSecondsPrecise(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Realtime.sleepSecondsPrecise")- const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();-- const auto spinlock_limit = std::chrono::duration<double>(SLEEP_SPINLOCK_LIMIT);-- const auto target_time =- std::chrono::high_resolution_clock::now().time_since_epoch() +- std::chrono::duration<double>(Var_arg1);-- while (true) {- const auto now = std::chrono::high_resolution_clock::now().time_since_epoch();- if (now >= target_time) break;- const auto sleep_time = target_time - now;- if (sleep_time <= spinlock_limit) {- while (std::chrono::high_resolution_clock::now().time_since_epoch() < target_time);- break;- } else {- std::this_thread::sleep_for(sleep_time - spinlock_limit);- }- }-- return ReturnTuple();- }-- ReturnTuple Call_monoSeconds(const ParamsArgs& params_args) const final {- TRACE_FUNCTION("Realtime.monoSeconds")- const auto time = std::chrono::steady_clock::now().time_since_epoch();- const PrimFloat seconds =- (PrimFloat) std::chrono::duration_cast<std::chrono::microseconds>(time).count() /- (PrimFloat) 1000000.0;- return ReturnTuple(Box_Float(seconds));- }-};--Category_Realtime& CreateCategory_Realtime() {- static auto& category = *new ExtCategory_Realtime();- return category;-}--S<const Type_Realtime> CreateType_Realtime(const Params<0>::Type& params) {- static const auto cached = S_get(new ExtType_Realtime(CreateCategory_Realtime(), Params<0>::Type()));- return cached;-}--void RemoveType_Realtime(const Params<0>::Type& params) {}--#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE
lib/thread/src/testing.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -23,6 +23,12 @@ refines Routine @type create () -> (NoOpRoutine)+}++concrete CrashRoutine {+ refines Routine++ @type create () -> (CrashRoutine) } concrete InfiniteRoutine {
lib/thread/src/testing.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -24,6 +24,16 @@ } run () {}+}++define CrashRoutine {+ create () {+ return CrashRoutine{ }+ }++ run () {+ fail("CrashRoutine")+ } } define InfiniteRoutine {
lib/thread/test/thread.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -241,5 +241,35 @@ weak Thread thread <- ProcessThread.from(NoOpRoutine.create()) if (present(strong(thread))) { fail("thread is still present")+ }+}+++testcase "creation tracing in Thread" {+ crash+ // Thread creation.+ require "CrashThread\.new"+ // Inherited trace from start call.+ require "CrashThread\.execute"+}++unittest testName {+ \ CrashThread.new().execute()+}++concrete CrashThread {+ @type new () -> (CrashThread)+ @value execute () -> ()+}++define CrashThread {+ @value ProcessThread thread++ new () {+ return CrashThread{ ProcessThread.from(CrashRoutine.create()) }+ }++ execute () {+ \ thread.start().join() } }
− lib/thread/test/time.0rt
@@ -1,79 +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 "zero sleep is allowed" {- success-}--unittest zeroSleep {- \ Realtime.sleepSeconds(0.0)-}--unittest negativeSleep {- \ Realtime.sleepSeconds(-0.1)-}--unittest zeroPrecise {- \ Realtime.sleepSecondsPrecise(0.0)-}--unittest negativePrecise {- \ Realtime.sleepSecondsPrecise(-0.1)-}---testcase "sleepSeconds() does not interfere with test timeout" {- crash- require "signal 14"- timeout 1-}--unittest test {- \ Realtime.sleepSeconds(5.0)-}---testcase "sleepSecondsPrecise() does not interfere with test timeout" {- crash- require "signal 14"- timeout 1-}--unittest test {- \ Realtime.sleepSecondsPrecise(5.0)-}---testcase "monoSeconds() diff is somewhat accurate" {- success- timeout 2-}--unittest testSleep {- Float start <- Realtime.monoSeconds()- \ Realtime.sleepSeconds(0.5)- Float stop <- Realtime.monoSeconds()- \ Testing.checkBetween(stop-start,0.5,0.6)-}--unittest testPrecise {- Float start <- Realtime.monoSeconds()- \ Realtime.sleepSecondsPrecise(0.5)- Float stop <- Realtime.monoSeconds()- \ Testing.checkBetween(stop-start,0.5,0.51)-}
− lib/thread/time.0rp
@@ -1,35 +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]--// Functions for realtime computation.-concrete Realtime {- // Sleep for the given number of seconds.- @type sleepSeconds (Float) -> ()-- // Sleep for the given number of seconds, with more precision.- @type sleepSecondsPrecise (Float) -> ()-- // Get a timestamp from a monotonic clock.- //- // Notes:- // - The absolute timestamp is fairly meaningless; use timestamp diffs- // instead, e.g., to compute the wall time of an operation.- // - In theory, this is microsecond-precise; however, the effective resolution- // could depend more on the kernel's latency.- @type monoSeconds () -> (Float)-}
lib/util/.zeolite-module view
@@ -31,6 +31,10 @@ categories: [MutexLock] } category_source {+ source: "lib/util/src/Extension_Realtime.cpp"+ categories: [Realtime]+ }+ category_source { source: "lib/util/src/Extension_SimpleMutex.cpp" categories: [SimpleMutex] }
lib/util/counters.0rp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -24,6 +24,8 @@ @type revZeroIndexed (Int) -> (optional Order<Int>) // Create an unbounded Int sequence. @type unlimited () -> (optional Order<Int>)+ // Create a counter using a builder.+ @type builder () -> (CounterBuilder) } // Creates an Order<#x> that repeats a single value, for use with traverse.@@ -50,4 +52,53 @@ @category minMax<#x> #x defines LessThan<#x> (#x,#x) -> (#x,#x)+}++// Builds a sequence of values.+//+// Many of the functions here overlap; therefore, you should never need all of+// them for a single counter.+//+// Example combinations:+//+// - start+count: Set the first value and the number of items, using the default+// increment between items.+// - count+reverse: Use the default start and default increment, but reverse the+// order that the items are returned in.+// - start+increment+limit: Count by the specified increment starting with the+// specified starting point until the specified limit.+concrete CounterBuilder {+ @type new () -> (#self)++ // Finalize the counter.+ @value done () -> (optional Order<Int>)++ // Set the first value in the counter.+ @value start (Int) -> (#self)++ // Set the number of items returned.+ //+ // Notes:+ // - This overrides limit.+ @value count (Int) -> (#self)++ // Set a strict threshold that will not be met or exceeded.+ //+ // Notes:+ // - If increment < 0 then all items will be > limit.+ // - If increment > 0 then all items will be < limit.+ // - This overrides count.+ @value limit (Int) -> (#self)++ // Set the difference between consecutive items.+ @value increment (Int) -> (#self)++ // Reverse the order that the items are returned in.+ //+ // Notes:+ // - This has no effect if the count is unlimited, since the last item does+ // not exist.+ // - This has the same effect regardless of when it gets called.+ // - Calling this twice reverts the counter to forward again.+ @value reverse () -> (#self) }
+ lib/util/src/Extension_Realtime.cpp view
@@ -0,0 +1,106 @@+/* -----------------------------------------------------------------------------+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]++#include <errno.h>+#include <math.h>+#include <string.h>+#include <time.h>++#include <chrono>+#include <iomanip>+#include <thread>++#include "category-source.hpp"+#include "Streamlined_Realtime.hpp"+#include "Category_Float.hpp"+#include "Category_Realtime.hpp"++#ifndef SLEEP_SPINLOCK_LIMIT+#define SLEEP_SPINLOCK_LIMIT 0.001+#endif++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Realtime : public Category_Realtime {+};++struct ExtType_Realtime : public Type_Realtime {+ inline ExtType_Realtime(Category_Realtime& p, Params<0>::Type params) : Type_Realtime(p, params) {}++ ReturnTuple Call_sleepSeconds(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Realtime.sleepSeconds")+ const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();+ if (Var_arg1 > 0) {+ std::this_thread::sleep_for(std::chrono::duration<double>(Var_arg1));+ }+ return ReturnTuple();+ }++ ReturnTuple Call_sleepSecondsPrecise(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Realtime.sleepSecondsPrecise")+ const PrimFloat Var_arg1 = (params_args.GetArg(0)).AsFloat();++ const auto spinlock_limit = std::chrono::duration<double>(SLEEP_SPINLOCK_LIMIT);++ const auto target_time =+ std::chrono::high_resolution_clock::now().time_since_epoch() ++ std::chrono::duration<double>(Var_arg1);++ while (true) {+ const auto now = std::chrono::high_resolution_clock::now().time_since_epoch();+ if (now >= target_time) break;+ const auto sleep_time = target_time - now;+ if (sleep_time <= spinlock_limit) {+ while (std::chrono::high_resolution_clock::now().time_since_epoch() < target_time);+ break;+ } else {+ std::this_thread::sleep_for(sleep_time - spinlock_limit);+ }+ }++ return ReturnTuple();+ }++ ReturnTuple Call_monoSeconds(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Realtime.monoSeconds")+ const auto time = std::chrono::steady_clock::now().time_since_epoch();+ const PrimFloat seconds =+ (PrimFloat) std::chrono::duration_cast<std::chrono::microseconds>(time).count() /+ (PrimFloat) 1000000.0;+ return ReturnTuple(Box_Float(seconds));+ }+};++Category_Realtime& CreateCategory_Realtime() {+ static auto& category = *new ExtCategory_Realtime();+ return category;+}++S<const Type_Realtime> CreateType_Realtime(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Realtime(CreateCategory_Realtime(), Params<0>::Type()));+ return cached;+}++void RemoveType_Realtime(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/counters.0rx view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -18,99 +18,114 @@ define Counter { zeroIndexed (max) {- return ForwardCounter.new(max)+ return builder().count(max).done() } revZeroIndexed (max) {- return ReverseCounter.new(max)+ return builder().count(max).reverse().done() } unlimited () {- return UnlimitedCounter.new()+ return builder().done() }-} -concrete ForwardCounter {- @type new (Int) -> (optional Order<Int>)+ builder () {+ return CounterBuilder.new()+ } } -define ForwardCounter {- $ReadOnly[limit]$-- refines Order<Int>-- @value Int current- @value Int limit+define CounterBuilder {+ @value Int start+ @value Int increment+ @value optional Int limit+ @value optional Int count+ @value Bool reverse - new (max) {- if (max > 0) {- return #self{ 0, max }- } else {- return empty- }+ new () {+ return #self{ 0, 1, empty, empty, false } } - next () {- if (current < limit-1) {- current <- current+1- return self+ done () {+ optional Int actualCount <- defer+ if (`present` limit) {+ if (increment != 0) {+ Bool missedStart <- (`require` limit - start) % increment != 0+ // NOTE: This still works if limit < start and increment < 0.+ actualCount <- (`require` limit - start) / increment + missedStart.asInt()+ } else {+ actualCount <- empty+ } } else {- return empty+ actualCount <- count }+ Int actualStart <- start+ Int actualIncrement <- increment+ if (reverse && `present` actualCount) {+ actualStart <- start + increment*(require(actualCount)-1)+ actualIncrement <- -increment+ }+ return IntCounter.new(actualStart,actualIncrement,actualCount) } - get () {- return current+ start (x) {+ start <- x+ return self }-} -concrete ReverseCounter {- @type new (Int) -> (optional Order<Int>)-}--define ReverseCounter {- refines Order<Int>-- @value Int current+ count (n) {+ limit <- empty+ count <- n+ return self+ } - new (max) {- if (max > 0) {- return #self{ max-1 }- } else {- return empty- }+ limit (x) {+ count <- empty+ limit <- x+ return self } - next () {- if (current > 0) {- current <- current-1- return self- } else {- return empty- }+ increment (x) {+ increment <- x+ return self } - get () {- return current+ reverse () {+ reverse <- !reverse+ return self } } -concrete UnlimitedCounter {- @type new () -> (optional Order<Int>)+concrete IntCounter {+ @type new (Int,Int,optional Int) -> (optional Order<Int>) } -define UnlimitedCounter {+define IntCounter {+ $ReadOnly[increment]$+ refines Order<Int> @value Int current+ @value Int increment+ @value optional Int remaining - new () {- return #self{ 0 }+ new (start,increment,count) {+ if (`present` count && `require` count <= 0) {+ return empty+ } else {+ return #self{ start, increment, count }+ } } next () {- current <- current+1- return self+ if (`present` remaining && `require` remaining - 1 <= 0) {+ return empty+ } else {+ if (`present` remaining) {+ remaining <- `require` remaining - 1+ }+ current <- current+increment+ return self+ } } get () {@@ -119,32 +134,33 @@ } define Repeat {- $ReadOnlyExcept[current]$+ $ReadOnlyExcept[counter]$ refines Order<#x> @value #x value- @value Int current- @value optional Int limit+ @value Order<any> counter times (value,max) {- if (max <= 0) {+ optional Order<any> counter <- Counter.builder().count(max).done()+ if (! `present` counter) { return empty } else {- return Repeat<#y>{ value, 0, max }+ return Repeat<#y>{ value, `require` counter } } } unlimited (value) {- return Repeat<#y>{ value, 0, empty }+ return Repeat<#y>{ value, `require` Counter.builder().done() } } next () {- if (!present(limit) || current+1 < require(limit)) {- current <- current+1- return self- } else {+ optional Order<any> next <- counter.next()+ if (! `present` next) { return empty+ } else {+ counter <- `require` next+ return self } }
lib/util/test/counters.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2021 Kevin P. Barry+Copyright 2021-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -38,14 +38,14 @@ } unittest revZeroIndexed {- Int index <- 10+ Int index <- 9 traverse (Counter.revZeroIndexed(10) -> Int i) {- index <- index-1 \ Testing.checkEquals(i,index)+ index <- index-1 } - \ Testing.checkEquals(index,0)+ \ Testing.checkEquals(index,-1) } unittest revZeroIndexedEmpty {@@ -65,6 +65,40 @@ } \ Testing.checkEquals(index,10)+}++unittest builderReversePositive {+ // Forward sequence: 3 8 13+ Int index <- 13++ traverse (Counter.builder()+ .start(3)+ .increment(5)+ .limit(17)+ .reverse()+ .done() -> Int i) {+ \ Testing.checkEquals(i,index)+ index <- index-5+ }++ \ Testing.checkEquals(index,-2)+}++unittest builderReverseNegative {+ // Forward sequence: 17 12 7+ Int index <- 7++ traverse (Counter.builder()+ .start(17)+ .increment(-5)+ .limit(3)+ .reverse()+ .done() -> Int i) {+ \ Testing.checkEquals(i,index)+ index <- index+5+ }++ \ Testing.checkEquals(index,22) } unittest times {
+ lib/util/test/time.0rt view
@@ -0,0 +1,79 @@+/* -----------------------------------------------------------------------------+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 "zero sleep is allowed" {+ success+}++unittest zeroSleep {+ \ Realtime.sleepSeconds(0.0)+}++unittest negativeSleep {+ \ Realtime.sleepSeconds(-0.1)+}++unittest zeroPrecise {+ \ Realtime.sleepSecondsPrecise(0.0)+}++unittest negativePrecise {+ \ Realtime.sleepSecondsPrecise(-0.1)+}+++testcase "sleepSeconds() does not interfere with test timeout" {+ crash+ require "signal 14"+ timeout 1+}++unittest test {+ \ Realtime.sleepSeconds(5.0)+}+++testcase "sleepSecondsPrecise() does not interfere with test timeout" {+ crash+ require "signal 14"+ timeout 1+}++unittest test {+ \ Realtime.sleepSecondsPrecise(5.0)+}+++testcase "monoSeconds() diff is somewhat accurate" {+ success+ timeout 2+}++unittest testSleep {+ Float start <- Realtime.monoSeconds()+ \ Realtime.sleepSeconds(0.5)+ Float stop <- Realtime.monoSeconds()+ \ Testing.checkBetween(stop-start,0.5,0.6)+}++unittest testPrecise {+ Float start <- Realtime.monoSeconds()+ \ Realtime.sleepSecondsPrecise(0.5)+ Float stop <- Realtime.monoSeconds()+ \ Testing.checkBetween(stop-start,0.5,0.51)+}
+ lib/util/time.0rp view
@@ -0,0 +1,35 @@+/* -----------------------------------------------------------------------------+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]++// Functions for realtime computation.+concrete Realtime {+ // Sleep for the given number of seconds.+ @type sleepSeconds (Float) -> ()++ // Sleep for the given number of seconds, with more precision.+ @type sleepSecondsPrecise (Float) -> ()++ // Get a timestamp from a monotonic clock.+ //+ // Notes:+ // - The absolute timestamp is fairly meaningless; use timestamp diffs+ // instead, e.g., to compute the wall time of an operation.+ // - In theory, this is microsecond-precise; however, the effective resolution+ // could depend more on the kernel's latency.+ @type monoSeconds () -> (Float)+}
src/Cli/Compiler.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -28,7 +28,7 @@ import Control.Monad (foldM,when) import Data.Either (partitionEithers) import Data.List (isSuffixOf,nub,sort)-import Data.Time.LocalTime (getZonedTime)+import Data.Time.Clock (getCurrentTime) import System.Directory import System.FilePath import System.IO@@ -86,6 +86,7 @@ compileModule :: (PathIOHandler r, CompilerBackend b) => r -> b -> ModuleSpec -> TrackedErrorsIO () compileModule resolver backend (ModuleSpec p d ee em is is2 ps xs ts es cs ep m f pn) = do+ time <- errorFromIO getCurrentTime as <- fmap fixPaths $ mapCompilerM (resolveModule resolver (p </> d)) is as2 <- fmap fixPaths $ mapCompilerM (resolveModule resolver (p </> d)) is2 let ca0 = Map.empty@@ -103,7 +104,6 @@ else do bpDeps <- loadPublicDeps compilerHash f ca2 [base] return $ bpDeps ++ deps1- time <- errorFromIO getZonedTime root <- errorFromIO $ canonicalizePath p path <- errorFromIO $ canonicalizePath (p </> d) extra <- errorFromIO $ sequence $ map (canonicalizePath . (p</>)) ee@@ -134,7 +134,7 @@ let paths2 = base:s0:s1:(getIncludePathsForDeps (deps1' ++ deps2)) ++ ep' ++ paths' let hxx = filter (isSuffixOf ".hpp" . coFilename) fs let other = filter (not . isSuffixOf ".hpp" . coFilename) fs- os1 <- mapCompilerM (writeOutputFile paths2)(hxx ++ other) >>= compileGenerated+ os1 <- mapCompilerM (writeOutputFile paths2 time) (hxx ++ other) >>= compileGenerated let files = map (\f2 -> getCachedPath (p </> d) (show $ coNamespace f2) (coFilename f2)) fs ++ map (\f2 -> p </> getSourceFile f2) es files' <- mapCompilerM checkOwnedFile files@@ -171,7 +171,7 @@ cmLinkFlags = getLinkFlags m, cmObjectFiles = os1' ++ osOther ++ map OtherObjectFile os' }- bs <- createBinary compilerHash paths' (cm2:(deps1' ++ deps2)) m mf+ bs <- createBinary compilerHash paths' (cm2:(deps1' ++ deps2)) time m mf let cm2' = CompileMetadata { cmVersionHash = cmVersionHash cm2, cmRoot = cmRoot cm2,@@ -195,7 +195,7 @@ cmLinkFlags = cmLinkFlags cm2, cmObjectFiles = cmObjectFiles cm2 }- writeMetadata (p </> d) cm2'+ writeMetadata (p </> d) cm2' time let traces = Set.unions $ map coPossibleTraces $ hxx ++ other writePossibleTraces (p </> d) traces where ep' = fixPaths $ map (p </>) ep@@ -206,9 +206,9 @@ " already defined at " ++ formatFullContextBrace (csContext cc2) Nothing -> return () return $ Map.insert n cc cm- writeOutputFile paths ca@(CxxOutput _ f2 ns _ _ _ content) = do+ writeOutputFile paths time ca@(CxxOutput _ f2 ns _ _ _ content) = do errorFromIO $ hPutStrLn stderr $ "Writing file " ++ f2- writeCachedFile (p </> d) (show ns) f2 $ concat $ map (++ "\n") content+ _ <- writeCachedFile (p </> d) (show ns) f2 (Just time) $ concat $ map (++ "\n") content if isSuffixOf ".cpp" f2 || isSuffixOf ".cc" f2 then do let f2' = getCachedPath (p </> d) (show ns) f2@@ -269,14 +269,14 @@ return $ Left $ asyncCxxCommand backend command | isSuffixOf ".a" f2 || isSuffixOf ".o" f2 = return $ Right [f2] | otherwise = return $ Right []- createBinary compilerHash paths deps (CompileBinary n _ lm o lf) [CxxOutput _ _ _ ns2 req _ content] = do+ createBinary compilerHash paths deps time (CompileBinary n _ lm o lf) [CxxOutput _ _ _ ns2 req _ content] = do f0 <- if null o then errorFromIO $ canonicalizePath $ p </> d </> show n else errorFromIO $ canonicalizePath $ p </> d </> o let main = takeFileName f0 ++ ".cpp" errorFromIO $ hPutStrLn stderr $ "Writing file " ++ main let mainAbs = getCachedPath (p </> d) "main" main- writeCachedFile (p </> d) "main" main $ concat $ map (++ "\n") content+ _ <- writeCachedFile (p </> d) "main" main (Just time) $ concat $ map (++ "\n") content base <- resolveBaseModule resolver deps2 <- loadPrivateDeps compilerHash f (mapMetadata deps) deps let paths' = fixPaths $ paths ++ base:(getIncludePathsForDeps deps)@@ -293,11 +293,11 @@ getCommand LinkDynamic mainAbs f0 deps2 paths2 = do let objects = getLibrariesForDeps deps2 return $ CompileToBinary mainAbs objects [] f0 paths2 []- createBinary _ _ _ (CompileBinary n _ _ _ _) [] =+ createBinary _ _ _ _ (CompileBinary n _ _ _ _) [] = compilerErrorM $ "Main category " ++ show n ++ " not found."- createBinary _ _ _ (CompileBinary n _ _ _ _) _ =+ createBinary _ _ _ _ (CompileBinary n _ _ _ _) _ = compilerErrorM $ "Multiple matches for main category " ++ show n ++ "."- createBinary _ _ _ _ _ = return []+ createBinary _ _ _ _ _ _ = return [] createLibrary _ _ [] [] = return [] createLibrary name lf deps os = do let flags = lf ++ getLinkFlagsForDeps deps@@ -314,6 +314,7 @@ Map.Map CategoryName (CategorySpec SourceContext) ->[CompileMetadata] -> [CompileMetadata] -> TrackedErrorsIO () createModuleTemplates resolver p d ds cm deps1 deps2 = do+ time <- errorFromIO getCurrentTime (ps,xs,_) <- findSourceFiles p (d:ds) (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _) <- fmap (createLanguageModule [] Map.empty . fst) $ loadModuleGlobals resolver p (PublicNamespace,PrivateNamespace) ps Nothing deps1 deps2@@ -326,12 +327,12 @@ let ca' = foldr Set.delete ca $ map dcName ds3 let testingCats = Set.fromList $ map getCategoryName ts1 ts <- fmap concat $ mapCompilerM (\n -> generate (n `Set.member` testingCats) tm n) $ Set.toList ca'- mapCompilerM_ writeTemplate ts where+ mapCompilerM_ (writeTemplate time) ts where generate testing tm n = do (_,t) <- getConcreteCategory tm ([],n) let spec = Map.findWithDefault (CategorySpec [] [] []) (getCategoryName t) cm generateStreamlinedTemplate testing tm t spec- writeTemplate (CxxOutput _ n _ _ _ _ content) = do+ writeTemplate time (CxxOutput _ n _ _ _ _ content) = do let n' = p </> d </> n exists <- errorFromIO $ doesFileExist n' if exists@@ -339,6 +340,10 @@ else do errorFromIO $ hPutStrLn stderr $ "Writing file " ++ n errorFromIO $ writeFile n' $ concat $ map (++ "\n") content+ -- This is to avoid a race condition when the module is compiled+ -- immediately after generating templates, since the former+ -- explicitly sets the metadata timestamp.+ errorFromIO $ setModificationTime n' time runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath -> FilePath -> [FilePath] -> LoadedTests ->@@ -359,7 +364,7 @@ loadPrivateSource :: PathIOHandler r => r -> VersionHash -> FilePath -> FilePath -> TrackedErrorsIO (PrivateSource SourceContext) loadPrivateSource resolver h p f = do [f'] <- zipWithContents resolver p [f]- time <- errorFromIO getZonedTime+ time <- errorFromIO getCurrentTime path <- errorFromIO $ canonicalizePath (p </> f) let ns = StaticNamespace $ privateNamespace $ show time ++ show h ++ path (pragmas,cs,ds) <- parseInternalSource f'
src/Compilation/CompilerState.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -201,7 +201,7 @@ JumpContinue | JumpBreak | JumpReturn |- JumpFailCall |+ JumpImmediateExit | JumpMax -- Max value for use as initial state in folds. deriving (Eq,Ord,Show)
src/CompilerCxx/Code.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -125,19 +125,21 @@ showCreationTrace = "TRACE_CREATION" hasPrimitiveValue :: CategoryName -> Bool-hasPrimitiveValue BuiltinBool = True-hasPrimitiveValue BuiltinInt = True-hasPrimitiveValue BuiltinFloat = True-hasPrimitiveValue BuiltinChar = True-hasPrimitiveValue _ = False+hasPrimitiveValue BuiltinBool = True+hasPrimitiveValue BuiltinInt = True+hasPrimitiveValue BuiltinFloat = True+hasPrimitiveValue BuiltinChar = True+hasPrimitiveValue BuiltinPointer = True+hasPrimitiveValue _ = False isStoredUnboxed :: ValueType -> Bool isStoredUnboxed t- | t == boolRequiredValue = True- | t == intRequiredValue = True- | t == floatRequiredValue = True- | t == charRequiredValue = True- | otherwise = False+ | t == boolRequiredValue = True+ | t == intRequiredValue = True+ | t == floatRequiredValue = True+ | t == charRequiredValue = True+ | isPointerRequiredValue t = True+ | otherwise = False expressionFromLiteral :: PrimitiveType -> String -> (ExpressionType,ExpressionValue) expressionFromLiteral PrimString e =@@ -150,6 +152,7 @@ (Positional [floatRequiredValue],UnboxedPrimitive PrimFloat $ "PrimFloat(" ++ e ++ ")") expressionFromLiteral PrimBool e = (Positional [boolRequiredValue],UnboxedPrimitive PrimBool e)+expressionFromLiteral PrimPointer _ = undefined getFromLazy :: ExpressionValue -> ExpressionValue getFromLazy (OpaqueMulti e) = OpaqueMulti $ e ++ ".Get()"@@ -168,94 +171,105 @@ useAsWhatever (LazySingle e) = useAsWhatever $ getFromLazy e useAsReturns :: ExpressionValue -> String-useAsReturns (OpaqueMulti e) = e-useAsReturns (WrappedSingle e) = "ReturnTuple(" ++ e ++ ")"-useAsReturns (UnwrappedSingle e) = "ReturnTuple(" ++ e ++ ")"-useAsReturns (BoxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"-useAsReturns (BoxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"-useAsReturns (UnboxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"-useAsReturns (LazySingle e) = useAsReturns $ getFromLazy e+useAsReturns (OpaqueMulti e) = e+useAsReturns (WrappedSingle e) = "ReturnTuple(" ++ e ++ ")"+useAsReturns (UnwrappedSingle e) = "ReturnTuple(" ++ e ++ ")"+useAsReturns (BoxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"+useAsReturns (BoxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimBool e) = "ReturnTuple(Box_Bool(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimString e) = "ReturnTuple(Box_String(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimChar e) = "ReturnTuple(Box_Char(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimInt e) = "ReturnTuple(Box_Int(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimFloat e) = "ReturnTuple(Box_Float(" ++ e ++ "))"+useAsReturns (UnboxedPrimitive PrimPointer e) = "ReturnTuple(Box_Pointer<void>(" ++ e ++ "))"+useAsReturns (LazySingle e) = useAsReturns $ getFromLazy e useAsArgs :: ExpressionValue -> String-useAsArgs (OpaqueMulti e) = e-useAsArgs (WrappedSingle e) = e-useAsArgs (UnwrappedSingle e) = e-useAsArgs (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsArgs (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsArgs (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsArgs (LazySingle e) = useAsArgs $ getFromLazy e+useAsArgs (OpaqueMulti e) = e+useAsArgs (WrappedSingle e) = e+useAsArgs (UnwrappedSingle e) = e+useAsArgs (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsArgs (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsArgs (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsArgs (LazySingle e) = useAsArgs $ getFromLazy e useAsUnwrapped :: ExpressionValue -> String-useAsUnwrapped (OpaqueMulti e) = "(" ++ e ++ ").At(0)"-useAsUnwrapped (WrappedSingle e) = e-useAsUnwrapped (UnwrappedSingle e) = e-useAsUnwrapped (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsUnwrapped (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"-useAsUnwrapped (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"-useAsUnwrapped (LazySingle e) = useAsUnwrapped $ getFromLazy e+useAsUnwrapped (OpaqueMulti e) = "(" ++ e ++ ").At(0)"+useAsUnwrapped (WrappedSingle e) = e+useAsUnwrapped (UnwrappedSingle e) = e+useAsUnwrapped (BoxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsUnwrapped (BoxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimBool e) = "Box_Bool(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimString e) = "Box_String(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimChar e) = "Box_Char(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimInt e) = "Box_Int(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimFloat e) = "Box_Float(" ++ e ++ ")"+useAsUnwrapped (UnboxedPrimitive PrimPointer e) = "Box_Pointer<void>(" ++ e ++ ")"+useAsUnwrapped (LazySingle e) = useAsUnwrapped $ getFromLazy e useAsUnboxed :: PrimitiveType -> ExpressionValue -> String-useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsBool()"-useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsString()"-useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsChar()"-useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsInt()"-useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsFloat()"-useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ").AsBool()"-useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ").AsString()"-useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ").AsChar()"-useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ").AsInt()"-useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ").AsFloat()"-useAsUnboxed PrimBool (UnwrappedSingle e) = "(" ++ e ++ ").AsBool()"-useAsUnboxed PrimString (UnwrappedSingle e) = "(" ++ e ++ ").AsString()"-useAsUnboxed PrimChar (UnwrappedSingle e) = "(" ++ e ++ ").AsChar()"-useAsUnboxed PrimInt (UnwrappedSingle e) = "(" ++ e ++ ").AsInt()"-useAsUnboxed PrimFloat (UnwrappedSingle e) = "(" ++ e ++ ").AsFloat()"+useAsUnboxed PrimBool (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsBool()"+useAsUnboxed PrimString (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsString()"+useAsUnboxed PrimChar (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsChar()"+useAsUnboxed PrimInt (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsInt()"+useAsUnboxed PrimFloat (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsFloat()"+useAsUnboxed PrimPointer (OpaqueMulti e) = "(" ++ e ++ ").At(0).AsPointer<OpaqueObject>()"+useAsUnboxed PrimBool (WrappedSingle e) = "(" ++ e ++ ").AsBool()"+useAsUnboxed PrimString (WrappedSingle e) = "(" ++ e ++ ").AsString()"+useAsUnboxed PrimChar (WrappedSingle e) = "(" ++ e ++ ").AsChar()"+useAsUnboxed PrimInt (WrappedSingle e) = "(" ++ e ++ ").AsInt()"+useAsUnboxed PrimFloat (WrappedSingle e) = "(" ++ e ++ ").AsFloat()"+useAsUnboxed PrimPointer (WrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()"+useAsUnboxed PrimBool (UnwrappedSingle e) = "(" ++ e ++ ").AsBool()"+useAsUnboxed PrimString (UnwrappedSingle e) = "(" ++ e ++ ").AsString()"+useAsUnboxed PrimChar (UnwrappedSingle e) = "(" ++ e ++ ").AsChar()"+useAsUnboxed PrimInt (UnwrappedSingle e) = "(" ++ e ++ ").AsInt()"+useAsUnboxed PrimFloat (UnwrappedSingle e) = "(" ++ e ++ ").AsFloat()"+useAsUnboxed PrimPointer (UnwrappedSingle e) = "(" ++ e ++ ").AsPointer<OpaqueObject>()" useAsUnboxed _ (BoxedPrimitive _ e) = e useAsUnboxed _ (UnboxedPrimitive _ e) = e useAsUnboxed t (LazySingle e) = useAsUnboxed t $ getFromLazy e valueAsWrapped :: ExpressionValue -> ExpressionValue-valueAsWrapped (UnwrappedSingle e) = WrappedSingle e-valueAsWrapped (BoxedPrimitive _ e) = WrappedSingle e-valueAsWrapped (UnboxedPrimitive PrimBool e) = WrappedSingle $ "Box_Bool(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimString e) = WrappedSingle $ "Box_String(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimChar e) = WrappedSingle $ "Box_Char(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimInt e) = WrappedSingle $ "Box_Int(" ++ e ++ ")"-valueAsWrapped (UnboxedPrimitive PrimFloat e) = WrappedSingle $ "Box_Float(" ++ e ++ ")"-valueAsWrapped (LazySingle e) = valueAsWrapped $ getFromLazy e-valueAsWrapped v = v+valueAsWrapped (UnwrappedSingle e) = WrappedSingle e+valueAsWrapped (BoxedPrimitive _ e) = WrappedSingle e+valueAsWrapped (UnboxedPrimitive PrimBool e) = WrappedSingle $ "Box_Bool(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimString e) = WrappedSingle $ "Box_String(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimChar e) = WrappedSingle $ "Box_Char(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimInt e) = WrappedSingle $ "Box_Int(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimFloat e) = WrappedSingle $ "Box_Float(" ++ e ++ ")"+valueAsWrapped (UnboxedPrimitive PrimPointer e) = WrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"+valueAsWrapped (LazySingle e) = valueAsWrapped $ getFromLazy e+valueAsWrapped v = v valueAsUnwrapped :: ExpressionValue -> ExpressionValue-valueAsUnwrapped (OpaqueMulti e) = UnwrappedSingle $ "(" ++ e ++ ").At(0)"-valueAsUnwrapped (WrappedSingle e) = UnwrappedSingle e-valueAsUnwrapped (UnboxedPrimitive PrimBool e) = UnwrappedSingle $ "Box_Bool(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimString e) = UnwrappedSingle $ "Box_String(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimChar e) = UnwrappedSingle $ "Box_Char(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimInt e) = UnwrappedSingle $ "Box_Int(" ++ e ++ ")"-valueAsUnwrapped (UnboxedPrimitive PrimFloat e) = UnwrappedSingle $ "Box_Float(" ++ e ++ ")"-valueAsUnwrapped (LazySingle e) = valueAsUnwrapped $ getFromLazy e-valueAsUnwrapped v = v+valueAsUnwrapped (OpaqueMulti e) = UnwrappedSingle $ "(" ++ e ++ ").At(0)"+valueAsUnwrapped (WrappedSingle e) = UnwrappedSingle e+valueAsUnwrapped (UnboxedPrimitive PrimBool e) = UnwrappedSingle $ "Box_Bool(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimString e) = UnwrappedSingle $ "Box_String(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimChar e) = UnwrappedSingle $ "Box_Char(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimInt e) = UnwrappedSingle $ "Box_Int(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimFloat e) = UnwrappedSingle $ "Box_Float(" ++ e ++ ")"+valueAsUnwrapped (UnboxedPrimitive PrimPointer e) = UnwrappedSingle $ "Box_Pointer<void>(" ++ e ++ ")"+valueAsUnwrapped (LazySingle e) = valueAsUnwrapped $ getFromLazy e+valueAsUnwrapped v = v variableStoredType :: ValueType -> String variableStoredType t@@ -263,6 +277,7 @@ | t == intRequiredValue = "PrimInt" | t == floatRequiredValue = "PrimFloat" | t == charRequiredValue = "PrimChar"+ | isPointerRequiredValue t = "PrimPointer" | isWeakValue t = "WeakValue" | otherwise = "BoxedValue" @@ -275,24 +290,27 @@ | t == intRequiredValue = "PrimInt" | t == floatRequiredValue = "PrimFloat" | t == charRequiredValue = "PrimChar"+ | isPointerRequiredValue t = "PrimPointer" | isWeakValue t = "WeakValue&" | otherwise = "BoxedValue&" readStoredVariable :: Bool -> ValueType -> String -> ExpressionValue readStoredVariable True t s = LazySingle $ readStoredVariable False t s readStoredVariable False t s- | t == boolRequiredValue = UnboxedPrimitive PrimBool s- | t == intRequiredValue = UnboxedPrimitive PrimInt s- | t == floatRequiredValue = UnboxedPrimitive PrimFloat s- | t == charRequiredValue = UnboxedPrimitive PrimChar s+ | t == boolRequiredValue = UnboxedPrimitive PrimBool s+ | t == intRequiredValue = UnboxedPrimitive PrimInt s+ | t == floatRequiredValue = UnboxedPrimitive PrimFloat s+ | t == charRequiredValue = UnboxedPrimitive PrimChar s+ | isPointerRequiredValue t = UnboxedPrimitive PrimPointer s | otherwise = UnwrappedSingle s writeStoredVariable :: ValueType -> ExpressionValue -> String writeStoredVariable t e- | t == boolRequiredValue = useAsUnboxed PrimBool e- | t == intRequiredValue = useAsUnboxed PrimInt e- | t == floatRequiredValue = useAsUnboxed PrimFloat e- | t == charRequiredValue = useAsUnboxed PrimChar e+ | t == boolRequiredValue = useAsUnboxed PrimBool e+ | t == intRequiredValue = useAsUnboxed PrimInt e+ | t == floatRequiredValue = useAsUnboxed PrimFloat e+ | t == charRequiredValue = useAsUnboxed PrimChar e+ | isPointerRequiredValue t = useAsUnboxed PrimPointer e | otherwise = useAsUnwrapped e functionLabelType :: ScopedFunction c -> String
src/CompilerCxx/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -269,11 +269,24 @@ fa <- csAllFilters lift $ (checkValueAssignment r fa t0 formattedRequiredValue) <?? "In fail call at " ++ formatFullContext c- csSetJumpType c JumpFailCall+ csSetJumpType c JumpImmediateExit maybeSetTrace c csWrite ["BUILTIN_FAIL(" ++ useAsUnwrapped e0 ++ ")"]+compileStatement (ExitCall c e) = do+ csAddRequired (Set.fromList [BuiltinInt])+ e' <- compileExpression e+ when (length (pValues $ fst e') /= 1) $+ compilerErrorM $ "Expected single return in argument" ++ formatFullContextBrace c+ let (Positional [t0],e0) = e'+ r <- csResolver+ fa <- csAllFilters+ lift $ (checkValueAssignment r fa t0 intRequiredValue) <??+ "In exit call at " ++ formatFullContext c+ csSetJumpType c JumpImmediateExit+ maybeSetTrace c+ csWrite ["BUILTIN_EXIT(" ++ useAsUnboxed PrimInt e0 ++ ")"] compileStatement (RawFailCall s) = do- csSetJumpType [] JumpFailCall+ csSetJumpType [] JumpImmediateExit csWrite ["RAW_FAIL(" ++ show s ++ ")"] compileStatement (IgnoreValues c e) = do (_,e') <- compileExpression e
src/Module/ProcessMetadata.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2020-2021 Kevin P. Barry+Copyright 2020-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -33,7 +33,6 @@ getObjectFileResolver, getRealPathsForDeps, getRecompilePath,- getSourceFilesForDeps, isPathConfigured, isPathUpToDate, isPrivateSource,@@ -60,6 +59,7 @@ import Control.Monad (when) import Data.List (isSuffixOf,nub) import Data.Maybe (isJust)+import Data.Time.Clock (UTCTime) import System.Directory import System.FilePath import System.IO@@ -140,12 +140,12 @@ m <- errorFromIO $ toTrackedErrors $ loadRecompile (p </> d) return $ not $ isCompilerError m -writeMetadata :: FilePath -> CompileMetadata -> TrackedErrorsIO ()-writeMetadata p m = do+writeMetadata :: FilePath -> CompileMetadata -> UTCTime -> TrackedErrorsIO ()+writeMetadata p m t = do p' <- errorFromIO $ canonicalizePath p errorFromIO $ hPutStrLn stderr $ "Writing metadata for \"" ++ p' ++ "\"." m' <- autoWriteConfig m <?? "In data for " ++ p- writeCachedFile p' "" metadataFilename m'+ writeCachedFile p' "" metadataFilename (Just t) m' writeRecompile :: FilePath -> ModuleConfig -> TrackedErrorsIO () writeRecompile p m = do@@ -158,7 +158,7 @@ writePossibleTraces :: FilePath -> Set.Set String -> TrackedErrorsIO () writePossibleTraces p ts = do p' <- errorFromIO $ canonicalizePath p- writeCachedFile p' "" tracesFilename $ concat $ map (++"\n") $ Set.toList ts+ writeCachedFile p' "" tracesFilename Nothing $ concat $ map (++"\n") $ Set.toList ts readPossibleTraces :: FilePath -> TrackedErrorsIO (Set.Set String) readPossibleTraces p = do@@ -190,11 +190,15 @@ errorFromIO $ createDirectoryIfMissing False d2 return d2 -writeCachedFile :: FilePath -> String -> FilePath -> String -> TrackedErrorsIO ()-writeCachedFile p ns f c = do+writeCachedFile :: FilePath -> String -> FilePath -> Maybe UTCTime -> String -> TrackedErrorsIO ()+writeCachedFile p ns f t c = do createCachePath p errorFromIO $ createDirectoryIfMissing False $ p </> cachedDataPath </> ns- errorFromIO $ writeFile (getCachedPath p ns f) c+ let filename = getCachedPath p ns f+ errorFromIO $ writeFile filename c+ case t of+ Just t2 -> errorFromIO $ setModificationTime filename t2+ Nothing -> return () getCachedPath :: FilePath -> String -> FilePath -> FilePath getCachedPath p ns f = fixPath $ p </> cachedDataPath </> ns </> f@@ -225,9 +229,9 @@ getRealPathsForDeps :: [CompileMetadata] -> [FilePath] getRealPathsForDeps = map cmPath -getSourceFilesForDeps :: [CompileMetadata] -> [FilePath]-getSourceFilesForDeps = concat . map extract where- extract m = map (cmRoot m </>) (filter isPublicSource $ cmPublicFiles m ++ cmPrivateFiles m)+getSourceFilesForDeps :: [CompileMetadata] -> [(FilePath,[FilePath])]+getSourceFilesForDeps = map extract where+ extract m = (cmRoot m,filter isPublicSource $ cmPublicFiles m ++ cmPrivateFiles m) getNamespacesForDeps :: [CompileMetadata] -> [Namespace] getNamespacesForDeps = filter (not . isNoNamespace) . map cmPublicNamespace@@ -460,7 +464,7 @@ let deps2' = filter (\cm -> not $ cmPath cm `Set.member` public) deps2 cs0 <- fmap concat $ mapCompilerM (processDeps False [FromDependency]) deps1 cs1 <- fmap concat $ mapCompilerM (processDeps False [FromDependency,ModuleOnly]) deps2'- (cs2,xa) <- loadAllPublic (ns0,ns1) fs+ (cs2,xa) <- loadAllPublic (ns0,ns1) [(p,fs)] cs3 <- case m of Just m2 -> processDeps True [FromDependency] m2 _ -> return []@@ -475,7 +479,7 @@ else cs return $ map (updateCodeVisibility (Set.union (Set.fromList ss))) cs' loadAllPublic (ns2,ns3) fs2 = do- fs2' <- zipWithContents r p fs2+ fs2' <- fmap concat $ mapCompilerM (uncurry $ zipWithContents r) fs2 loaded <- mapCompilerM loadPublic fs2' return (concat $ map fst loaded,Set.fromList $ concat $ map snd loaded) where
src/Parser/Common.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -46,6 +46,7 @@ kwElif, kwElse, kwEmpty,+ kwExit, kwFail, kwFalse, kwIf,@@ -217,6 +218,9 @@ kwEmpty :: TextParser () kwEmpty = keyword "empty" +kwExit :: TextParser ()+kwExit = keyword "exit"+ kwFail :: TextParser () kwFail = keyword "fail" @@ -329,6 +333,7 @@ kwElif, kwElse, kwEmpty,+ kwExit, kwFail, kwFalse, kwIf,
src/Parser/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -131,6 +131,7 @@ parseBreak <|> parseContinue <|> parseFailCall <|>+ parseExitCall <|> parseVoid <|> parseAssign <|> parsePragma <|>@@ -161,6 +162,11 @@ kwFail e <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser return $ FailCall [c] e+ parseExitCall = do+ c <- getSourceContext+ kwExit+ e <- between (sepAfter $ string_ "(") (sepAfter $ string_ ")") sourceParser+ return $ ExitCall [c] e parseIgnore = do c <- getSourceContext statementStart
src/Parser/TypeInstance.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2020,2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -81,6 +81,7 @@ | n == "Int" = BuiltinInt | n == "Float" = BuiltinFloat | n == "String" = BuiltinString+ | n == "Pointer" = BuiltinPointer | n == "Formatted" = BuiltinFormatted | otherwise = CategoryName n
src/Test/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -144,6 +144,10 @@ checkShortParseSuccess "if (((var.func())?T.call())) { }", checkShortParseSuccess "fail(\"reason\")", checkShortParseFail "\\ fail(\"reason\")",+ checkShortParseFail "\\ fail()",+ checkShortParseSuccess "exit(1)",+ checkShortParseFail "\\ exit(1)",+ checkShortParseFail "\\ exit()", checkShortParseSuccess "failed <- 10", checkShortParseSuccess "\\var?T<#x>.func().func2().func3()",
src/Types/Builtin.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -28,6 +28,7 @@ floatRequiredValue, formattedRequiredValue, intRequiredValue,+ isPointerRequiredValue, isOpaqueMulti, orderOptionalValue, stringRequiredValue,@@ -36,6 +37,7 @@ import qualified Data.Map as Map import Base.GeneralType+import Base.MergeTree (reduceMergeTree) import Base.Positional import Types.TypeCategory import Types.TypeInstance@@ -59,6 +61,13 @@ orderOptionalValue :: GeneralInstance -> ValueType orderOptionalValue t = ValueType OptionalValue $ singleType $ JustTypeInstance $ TypeInstance BuiltinOrder (Positional [t]) +isPointerRequiredValue :: ValueType -> Bool+isPointerRequiredValue (ValueType RequiredValue t) = check $ extractSingle t where+ check (Just (JustTypeInstance (TypeInstance BuiltinPointer (Positional [_])))) = True+ check _ = False+ extractSingle = reduceMergeTree (const Nothing) (const Nothing) Just+isPointerRequiredValue _ = False+ emptyType :: ValueType emptyType = ValueType OptionalValue minBound @@ -67,7 +76,8 @@ PrimChar | PrimInt | PrimFloat |- PrimString+ PrimString |+ PrimPointer deriving (Eq,Show) data ExpressionValue =
src/Types/Procedure.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -176,6 +176,7 @@ LoopBreak [c] | LoopContinue [c] | FailCall [c] (Expression c) |+ ExitCall [c] (Expression c) | RawFailCall String | IgnoreValues [c] (Expression c) | Assignment [c] (Positional (Assignable c)) (Expression c) |@@ -198,6 +199,7 @@ getStatementContext (LoopBreak c) = c getStatementContext (LoopContinue c) = c getStatementContext (FailCall c _) = c+getStatementContext (ExitCall c _) = c getStatementContext (RawFailCall _) = [] getStatementContext (IgnoreValues c _) = c getStatementContext (Assignment c _ _) = c
src/Types/TypeInstance.hs view
@@ -1,5 +1,5 @@ {- ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry+Copyright 2019-2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -140,6 +140,7 @@ BuiltinInt | BuiltinFloat | BuiltinString |+ BuiltinPointer | BuiltinFormatted | BuiltinOrder | CategoryNone@@ -152,6 +153,7 @@ show BuiltinInt = "Int" show BuiltinFloat = "Float" show BuiltinString = "String"+ show BuiltinPointer = "Pointer" show BuiltinFormatted = "Formatted" show BuiltinOrder = "Order" show CategoryNone = "(none)"
tests/cli-tests.sh view
@@ -1,7 +1,7 @@ #!/usr/bin/env bash # -------------------------------------------------------------------------------# Copyright 2020-2021 Kevin P. Barry+# Copyright 2020-2022 Kevin P. Barry # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.@@ -29,7 +29,7 @@ ZEOLITE=("$@") -if [[ "$PARALLEL" ]]; then+if [[ "${PARALLEL-}" ]]; then PARALLEL="-j $PARALLEL" else PARALLEL='-j 1'@@ -378,6 +378,12 @@ } +test_pointer() {+ do_zeolite -p "$ZEOLITE_PATH" $PARALLEL -r tests/pointer -f+ do_zeolite -p "$ZEOLITE_PATH" -t tests/pointer+}++ test_self_offset() { do_zeolite -p "$ZEOLITE_PATH" $PARALLEL -r tests/self-offset -f do_zeolite -p "$ZEOLITE_PATH" -t tests/self-offset@@ -573,6 +579,7 @@ test_module_only2 test_module_only3 test_module_only4+ test_pointer test_self_offset test_show_deps test_simulate_refs
− tests/failure.0rt
@@ -1,69 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020 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 "fail builtin" {- crash- require stderr "Failed"- require stderr "failedReturn"-}--unittest test {- Int value <- Test:failedReturn()-}--concrete Test {- @category failedReturn () -> (Int)-}--define Test {- failedReturn () {- fail("Failed")- }-}----testcase "wrong type for fail" {- error- require "fail"- require "Formatted"-}--unittest test {- fail(Value.create())-}--concrete Value {- @type create () -> (Value)-}--define Value {- create () {- return Value{}- }-}---testcase "require empty" {- crash- require stderr "require.+empty"-}--unittest test {- \ require(empty)-}
+ tests/pointer/.zeolite-module view
@@ -0,0 +1,21 @@+root: "../.."+path: "tests/pointer"+private_deps: [+ "lib/testing"+]+extra_files: [+ category_source {+ source: "tests/pointer/Extension_Request.cpp"+ categories: [Request]+ }+ category_source {+ source: "tests/pointer/Extension_Response.cpp"+ categories: [Response]+ }+ category_source {+ source: "tests/pointer/Extension_Service.cpp"+ categories: [Service]+ }+ "tests/pointer/call.hpp"+]+mode: incremental {}
+ tests/pointer/Extension_Request.cpp view
@@ -0,0 +1,92 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Request.hpp"+#include "Category_Message.hpp"+#include "Category_Pointer.hpp"+#include "Category_Request.hpp"+#include "Category_String.hpp"++#include "call.hpp"++#ifdef ZEOLITE_PRIVATE_NAMESPACE+namespace ZEOLITE_PRIVATE_NAMESPACE {+#endif // ZEOLITE_PRIVATE_NAMESPACE++BoxedValue CreateValue_Request(S<const Type_Request> parent, const ParamsArgs& params_args);++struct ExtCategory_Request : public Category_Request {+};++struct ExtType_Request : public Type_Request {+ inline ExtType_Request(Category_Request& p, Params<0>::Type params) : Type_Request(p, params) {}++ ReturnTuple Call_create(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Request.create")+ return ReturnTuple(CreateValue_Request(PARAM_SELF, params_args));+ }++ ReturnTuple Call_getData(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Request.getData")+ return ReturnTuple(Box_String(params_args.GetArg(0).AsPointer<Request>()->request_data));+ }+};++struct ExtValue_Request : public Value_Request {+ inline ExtValue_Request(S<const Type_Request> p, const ParamsArgs& params_args)+ : Value_Request(std::move(p)),+ request_{params_args.GetArg(0).AsString()} {}++ ReturnTuple Call_asMessage(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Request.asMessage")+ return ReturnTuple(Box_Pointer<Message>(&request_));+ }++ ReturnTuple Call_asRequest(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Request.asRequest")+ return ReturnTuple(Box_Pointer<Request>(&request_));+ }++ ReturnTuple Call_formatted(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Request.formatted")+ return ReturnTuple(Box_String(request_.request_data));+ }++ Request request_;+};++Category_Request& CreateCategory_Request() {+ static auto& category = *new ExtCategory_Request();+ return category;+}++S<const Type_Request> CreateType_Request(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Request(CreateCategory_Request(), Params<0>::Type()));+ return cached;+}++void RemoveType_Request(const Params<0>::Type& params) {}+BoxedValue CreateValue_Request(S<const Type_Request> parent, const ParamsArgs& params_args) {+ return BoxedValue::New<ExtValue_Request>(std::move(parent), params_args);+}++#ifdef ZEOLITE_PRIVATE_NAMESPACE+} // namespace ZEOLITE_PRIVATE_NAMESPACE+using namespace ZEOLITE_PRIVATE_NAMESPACE;+#endif // ZEOLITE_PRIVATE_NAMESPACE
+ tests/pointer/Extension_Response.cpp view
@@ -0,0 +1,92 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Response.hpp"+#include "Category_Message.hpp"+#include "Category_Pointer.hpp"+#include "Category_Response.hpp"+#include "Category_String.hpp"++#include "call.hpp"++#ifdef ZEOLITE_PRIVATE_NAMESPACE+namespace ZEOLITE_PRIVATE_NAMESPACE {+#endif // ZEOLITE_PRIVATE_NAMESPACE++BoxedValue CreateValue_Response(S<const Type_Response> parent, const ParamsArgs& params_args);++struct ExtCategory_Response : public Category_Response {+};++struct ExtType_Response : public Type_Response {+ inline ExtType_Response(Category_Response& p, Params<0>::Type params) : Type_Response(p, params) {}++ ReturnTuple Call_create(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Response.create")+ return ReturnTuple(CreateValue_Response(PARAM_SELF, params_args));+ }++ ReturnTuple Call_getData(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Response.getData")+ return ReturnTuple(Box_String(params_args.GetArg(0).AsPointer<Response>()->response_data));+ }+};++struct ExtValue_Response : public Value_Response {+ inline ExtValue_Response(S<const Type_Response> p, const ParamsArgs& params_args)+ : Value_Response(std::move(p)),+ response_{params_args.GetArg(0).AsString()} {}++ ReturnTuple Call_asMessage(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Response.asMessage")+ return ReturnTuple(Box_Pointer<Message>(&response_));+ }++ ReturnTuple Call_asResponse(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Response.asResponse")+ return ReturnTuple(Box_Pointer<Response>(&response_));+ }++ ReturnTuple Call_formatted(const ParamsArgs& params_args) final {+ TRACE_FUNCTION("Response.formatted")+ return ReturnTuple(Box_String(response_.response_data));+ }++ Response response_;+};++Category_Response& CreateCategory_Response() {+ static auto& category = *new ExtCategory_Response();+ return category;+}++S<const Type_Response> CreateType_Response(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Response(CreateCategory_Response(), Params<0>::Type()));+ return cached;+}++void RemoveType_Response(const Params<0>::Type& params) {}+BoxedValue CreateValue_Response(S<const Type_Response> parent, const ParamsArgs& params_args) {+ return BoxedValue::New<ExtValue_Response>(std::move(parent), params_args);+}++#ifdef ZEOLITE_PRIVATE_NAMESPACE+} // namespace ZEOLITE_PRIVATE_NAMESPACE+using namespace ZEOLITE_PRIVATE_NAMESPACE;+#endif // ZEOLITE_PRIVATE_NAMESPACE
+ tests/pointer/Extension_Service.cpp view
@@ -0,0 +1,82 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Service.hpp"+#include "Category_Request.hpp"+#include "Category_Response.hpp"+#include "Category_Service.hpp"++#include "call.hpp"++#ifdef ZEOLITE_PRIVATE_NAMESPACE+namespace ZEOLITE_PRIVATE_NAMESPACE {+#endif // ZEOLITE_PRIVATE_NAMESPACE++BoxedValue CreateValue_Service(S<const Type_Service> parent, const ParamsArgs& params_args);++struct ExtCategory_Service : public Category_Service {+};++struct ExtType_Service : public Type_Service {+ inline ExtType_Service(Category_Service& p, Params<0>::Type params) : Type_Service(p, params) {}++ ReturnTuple Call_send(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Service.send")+ const Request* const request = params_args.GetArg(0).AsPointer<Request>();+ Response* const response = params_args.GetArg(1).AsPointer<Response>();+ if (!request) FAIL() << "Invalid Pointer<Request>";+ if (!response) FAIL() << "Invalid Pointer<Response>";+ response->response_data = request->request_data + " has been processed as Request";+ return ReturnTuple();+ }++ ReturnTuple Call_send2(const ParamsArgs& params_args) const final {+ TRACE_FUNCTION("Service.send2")+ const Message* const request = params_args.GetArg(0).AsPointer<Message>();+ Response* const response = params_args.GetArg(1).AsPointer<Response>();+ if (!request) FAIL() << "Invalid Pointer<Message>";+ if (!response) FAIL() << "Invalid Pointer<Response>";+ response->response_data = request->message_data + " has been processed as Message";+ return ReturnTuple();+ }+};++struct ExtValue_Service : public Value_Service {+ inline ExtValue_Service(S<const Type_Service> p, const ParamsArgs& params_args) : Value_Service(std::move(p)) {}+};++Category_Service& CreateCategory_Service() {+ static auto& category = *new ExtCategory_Service();+ return category;+}++S<const Type_Service> CreateType_Service(const Params<0>::Type& params) {+ static const auto cached = S_get(new ExtType_Service(CreateCategory_Service(), Params<0>::Type()));+ return cached;+}++void RemoveType_Service(const Params<0>::Type& params) {}+BoxedValue CreateValue_Service(S<const Type_Service> parent, const ParamsArgs& params_args) {+ return BoxedValue::New<ExtValue_Service>(std::move(parent), params_args);+}++#ifdef ZEOLITE_PRIVATE_NAMESPACE+} // namespace ZEOLITE_PRIVATE_NAMESPACE+using namespace ZEOLITE_PRIVATE_NAMESPACE;+#endif // ZEOLITE_PRIVATE_NAMESPACE
+ tests/pointer/README.md view
@@ -0,0 +1,11 @@+# C++ Pointer Wrapping Test++This module tests `Pointer<#x>` in C++ extensions.++To compile and execute:++```shell+ZEOLITE_PATH=$(zeolite --get-path)+zeolite -p $ZEOLITE_PATH -r tests/pointer+zeolite -p $ZEOLITE_PATH -t tests/pointer+```
+ tests/pointer/call.0rp view
@@ -0,0 +1,50 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$+$TestsOnly$++@value interface Message {+ asMessage () -> (Pointer<Message>)+}++// NOTE: Inheriting Message doesn't matter for the purposes of Pointer; it's+// just an arbitrary substitution for type checking.++concrete Request {+ refines Formatted+ refines Message++ @type create (String) -> (#self)+ @type getData (Pointer<Request>) -> (String)+ @value asRequest () -> (Pointer<Request>)+}++concrete Response {+ refines Formatted+ refines Message++ @type create (String) -> (#self)+ @type getData (Pointer<Response>) -> (String)+ @value asResponse () -> (Pointer<Response>)+}++concrete Service {+ @type send (Pointer<Request>,Pointer<Response>) -> ()+ @type send2 (Pointer<Message>,Pointer<Response>) -> ()+}
+ tests/pointer/call.0rt view
@@ -0,0 +1,100 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "Pointer passing" {+ success+}++concrete CallHelper {+ @type call (String) -> (String)+ @type call2 (String) -> (String)+}++define CallHelper {+ call (data) {+ Request request <- Request.create(data)+ Response response <- Response.create("")+ // This is just meant to test code generated for passing Pointer as a+ // function arg or return.+ return Response.getData(callWithPointers(request.asRequest(),response.asResponse()))+ }++ call2 (data) {+ Request request <- Request.create(data)+ Response response <- Response.create("")+ \ Service.send2(request.asMessage(),response.asResponse())+ return response.formatted()+ }++ @type callWithPointers (Pointer<Request>,Pointer<Response>) -> (Pointer<Response>)+ callWithPointers (request,response) {+ \ Service.send(request,response)+ return response+ }+}++unittest test {+ \ CallHelper.call("DATA") `Testing.checkEquals` "DATA has been processed as Request"+ \ CallHelper.call2("DATA") `Testing.checkEquals` "REQUEST has been processed as Message"+}+++testcase "Pointer storage" {+ success+}++concrete Helper {+ @type new () -> (Helper)+ @value call () -> ()+}++define Helper {+ @category Request request <- Request.create("request")+ @category Pointer<Request> requestPointer <- request.asRequest()+ @value Response response+ @value Pointer<Response> responsePointer++ new () {+ Response response <- Response.create("response")+ return #self{ response, response.asResponse() }+ }++ call () {+ \ Request.getData(requestPointer) `Testing.checkEquals` "request"+ \ Response.getData(responsePointer) `Testing.checkEquals` "response"++ Pointer<Request> localRequest <- requestPointer+ Pointer<Response> localResponse <- responsePointer+ \ Request.getData(localRequest) `Testing.checkEquals` "request"+ \ Response.getData(localResponse) `Testing.checkEquals` "response"++ localRequest <- request.asRequest()+ localResponse <- response.asResponse()+ \ Request.getData(localRequest) `Testing.checkEquals` "request"+ \ Response.getData(localResponse) `Testing.checkEquals` "response"++ requestPointer <- localRequest+ responsePointer <- localResponse+ \ Request.getData(requestPointer) `Testing.checkEquals` "request"+ \ Response.getData(responsePointer) `Testing.checkEquals` "response"+ }+}++unittest test {+ \ Helper.new().call()+}
+ tests/pointer/call.hpp view
@@ -0,0 +1,53 @@+/* -----------------------------------------------------------------------------+Copyright 2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#ifndef CALL_H_+#define CALL_H_++#include <string>++struct Message {+ std::string message_data;+};++struct OtherBase {+ std::string other_base_data;+};++// NOTE: The inheritance of Message here doesn't need to match the inheritance+// in call.0rp because inheritance doesn't matter for Pointer.++// The virtual base class is meant to change the offset.+struct Request : public OtherBase, virtual public Message {+ explicit inline Request(std::string data)+ : Message{ "REQUEST" },+ request_data(std::move(data)) {}++ std::string request_data;+};++// The virtual base class is meant to change the offset.+struct Response : public OtherBase, virtual public Message {+ explicit inline Response(std::string data)+ : Message{ "RESPONSE" },+ response_data(std::move(data)) {}++ std::string response_data;+};++#endif // CALL_H_
+ tests/program-exit.0rt view
@@ -0,0 +1,121 @@+/* -----------------------------------------------------------------------------+Copyright 2020,2022 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "fail builtin" {+ crash+ require stderr "Failed"+ require stderr "failedReturn"+}++unittest test {+ Int value <- Test:failedReturn()+}++concrete Test {+ @category failedReturn () -> (Int)+}++define Test {+ failedReturn () {+ // Calling within a function also validates that return checks are skipped.+ fail("Failed")+ }+}+++testcase "wrong type for fail" {+ error+ require "fail"+ require "Formatted"+}++unittest test {+ fail(Value.create())+}++concrete Value {+ @type create () -> (Value)+}++define Value {+ create () {+ return Value{}+ }+}+++testcase "exit builtin zero" {+ success+}++unittest test {+ Int value <- Test:exitReturn()+}++concrete Test {+ @category exitReturn () -> (Int)+}++define Test {+ exitReturn () {+ // Calling within a function also validates that return checks are skipped.+ exit(0)+ }+}+++testcase "exit builtin non-zero" {+ crash+ // Should not output a stack trace.+ exclude "exitReturn"+}++unittest test {+ Int value <- Test:exitReturn()+}++concrete Test {+ @category exitReturn () -> (Int)+}++define Test {+ exitReturn () {+ exit(1)+ }+}+++testcase "wrong type for exit" {+ error+ require "exit"+ require "Int"+}++unittest test {+ exit("message")+}+++testcase "require empty" {+ crash+ require stderr "require.+empty"+}++unittest test {+ \ require(empty)+}
tests/simple.0rt view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry+Copyright 2020,2022 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -135,3 +135,13 @@ unittest test { while (true) {} }+++testcase "args escaped properly" {+ success+ // If the compiler uses quotes without escaping individual characters then+ // main will exit with an error without executing the test.+ args "\" }; exit(1); const char fake[] = { \""+}++unittest test {}
tests/simulate-refs/.zeolite-module view
@@ -9,7 +9,6 @@ private_deps: [ "lib/container" "lib/math"- "lib/thread" "lib/util" ] mode: binary {
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: zeolite-lang-version: 0.22.1.0+version: 0.23.0.0 synopsis: Zeolite is a statically-typed, general-purpose programming language. description:@@ -59,7 +59,7 @@ license-file: LICENSE author: Kevin P. Barry maintainer: Kevin P. Barry <ta0kira@gmail.com>-copyright: (c) Kevin P. Barry 2019-2021+copyright: (c) Kevin P. Barry 2019-2022 category: Compiler build-type: Simple @@ -174,6 +174,12 @@ tests/module-only4/*.0rp, tests/module-only4/*.0rt, tests/module-only4/*.0rx,+ tests/pointer/README.md,+ tests/pointer/.zeolite-module,+ tests/pointer/*.cpp,+ tests/pointer/*.hpp,+ tests/pointer/*.0rp,+ tests/pointer/*.0rt, tests/self-offset/README.md, tests/self-offset/.zeolite-module, tests/self-offset/*.cpp,