// Copyright 2021 Benjamin Barenblat // // 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 // // https://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. // An extremely simple EDSL for describing output to the terminal. It supports // exactly two instructions: "send some bytes to the terminal" and "sleep". The // string capability interpreter produces terms in this EDSL, which makes it // easier to test. #ifndef EC_GOLDFISHTERM_INTERNAL_EMIT_H_ #define EC_GOLDFISHTERM_INTERNAL_EMIT_H_ #include #include #include #include #include #include "third_party/abseil/absl/strings/str_cat.h" #include "third_party/abseil/absl/strings/string_view.h" #include "third_party/abseil/absl/time/time.h" #include "third_party/abseil/absl/types/span.h" namespace goldfishterm_internal { class EmitTerm { public: virtual void Emit(std::ostream&) const = 0; virtual ~EmitTerm() noexcept = default; }; class EmitBytes final : public EmitTerm { public: explicit EmitBytes() noexcept = default; explicit EmitBytes(absl::string_view bytes) noexcept : bytes_(bytes) {} EmitBytes(const EmitBytes&) = default; EmitBytes& operator=(const EmitBytes&) = default; EmitBytes(EmitBytes&&) noexcept = default; EmitBytes& operator=(EmitBytes&&) noexcept = default; bool empty() const noexcept { return bytes_.empty(); } void Append(absl::string_view more) noexcept { absl::StrAppend(&bytes_, more); } void Emit(std::ostream&) const override; bool operator==(const EmitBytes& other) const noexcept { return bytes_ == other.bytes_; } friend std::ostream& operator<<(std::ostream& out, const EmitBytes& emit) noexcept { return out << "EmitBytes(" << emit.bytes_ << ')'; } private: std::string bytes_; }; class EmitDelay final : public EmitTerm { public: explicit EmitDelay() noexcept = default; explicit EmitDelay(absl::Duration delay) : delay_(std::move(delay)) {} EmitDelay(const EmitDelay&) = default; EmitDelay& operator=(const EmitDelay&) = default; EmitDelay(EmitDelay&&) noexcept = default; EmitDelay& operator=(EmitDelay&&) noexcept = default; bool zero() const noexcept { return delay_ == absl::ZeroDuration(); } void Increase(absl::Duration more) noexcept { delay_ += more; } void Emit(std::ostream&) const noexcept override; bool operator==(const EmitDelay& other) const noexcept { return delay_ == other.delay_; } private: absl::Duration delay_; }; // Runs an entire program in the emitter EDSL. void Emit(absl::Span>, std::ostream&); } // namespace goldfishterm_internal #endif // EC_GOLDFISHTERM_INTERNAL_EMIT_H_