diff options
Diffstat (limited to 'goldfishterm/internal/emit.h')
-rw-r--r-- | goldfishterm/internal/emit.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/goldfishterm/internal/emit.h b/goldfishterm/internal/emit.h new file mode 100644 index 0000000..371f6b0 --- /dev/null +++ b/goldfishterm/internal/emit.h @@ -0,0 +1,106 @@ +// 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 <stdint.h> + +#include <memory> +#include <ostream> +#include <string> +#include <utility> + +#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<const std::shared_ptr<const EmitTerm>>, std::ostream&); + +} // namespace goldfishterm_internal + +#endif // EC_GOLDFISHTERM_INTERNAL_EMIT_H_ |