Commit 5a5f093a authored by Tom Niget's avatar Tom Niget

Add basic support for generators (co_yield)

parent 22b92fbe
......@@ -33,6 +33,19 @@ concept PyLen = requires(const T &t) {
template <PyLen T> size_t len(const T &t) { return t.py_len(); }
template <typename T>
concept PyNext = requires(T t) {
t.py_next();
};
template <PyNext T> auto next(T &t) { return t.py_next(); }
template<typename T>
std::ostream& operator<<(std::ostream& os, std::optional<T> const& opt)
{
return opt ? os << opt.value() : os << "None";
}
bool is_cpp() { return true; }
#include "builtins/bool.hpp"
......@@ -44,4 +57,6 @@ bool is_cpp() { return true; }
#include "builtins/set.hpp"
#include "builtins/str.hpp"
#include "../typon/generator.hpp"
#endif // TYPON_BUILTINS_HPP
//
// Created by Tom on 13/03/2023.
//
#ifndef TYPON_RANGE_HPP
#define TYPON_RANGE_HPP
#include <ranges>
// todo: proper range support
template <typename T> auto range(T stop) { return std::views::iota(0, stop); }
template <typename T> auto range(T start, T stop) {
return std::views::iota(start, stop);
}
#endif // TYPON_RANGE_HPP
//
// Created by Tom on 13/03/2023.
//
#ifndef TYPON_GENERATOR_HPP
#define TYPON_GENERATOR_HPP
#include <coroutine>
namespace typon {
/**
* https://github.com/feabhas/coroutines-blog
*/
template <typename T>
class Generator
{
class Promise
{
public:
using value_type = std::optional<T>;
Promise() = default;
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() {
std::rethrow_exception(std::move(std::current_exception()));
}
std::suspend_always yield_value(T value) {
this->value = std::move(value);
return {};
}
// void return_value(T value) {
// this->value = std::move(value);
// }
void return_void() {
this->value = std::nullopt;
}
inline Generator get_return_object();
value_type get_value() {
return std::move(value);
}
bool finished() {
return !value.has_value();
}
private:
value_type value{};
};
public:
using value_type = T;
using promise_type = Promise;
explicit Generator(std::coroutine_handle<Promise> handle)
: handle (handle)
{}
~Generator() {
if (handle) { handle.destroy(); }
}
Promise::value_type next() {
if (handle) {
handle.resume();
return handle.promise().get_value();
}
else {
return {};
}
}
struct end_iterator {};
class iterator
{
public:
using value_type = Promise::value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
iterator() = default;
iterator(Generator& generator) : generator{&generator}
{}
value_type operator*() const {
if (generator) {
return generator->handle.promise().get_value();
}
return {};
}
value_type operator->() const {
if (generator) {
return generator->handle.promise().get_value();
}
return {};
}
iterator& operator++() {
if (generator && generator->handle) {
generator->handle.resume();
}
return *this;
}
iterator& operator++(int) {
if (generator && generator->handle) {
generator->handle.resume();
}
return *this;
}
bool operator== (const end_iterator&) const {
return generator ? generator->handle.promise().finished() : true;
}
private:
Generator* generator{};
};
iterator begin() {
iterator it{*this};
return ++it;
}
end_iterator end() {
return end_sentinel;
}
std::optional<value_type> py_next() {
return *begin();
}
private:
end_iterator end_sentinel{};
std::coroutine_handle<Promise> handle;
};
template <typename T>
inline Generator<T> Generator<T>::Promise::get_return_object()
{
return Generator{ std::coroutine_handle<Promise>::from_promise(*this) };
}
} // namespace typon
#endif // TYPON_GENERATOR_HPP
......@@ -10,6 +10,9 @@ from transpiler.format import format_code
def run_tests():
for path in Path('tests').glob('*.py'):
print(path.name)
if path.name.startswith('_'):
print("Skipping")
continue
with open(path, "r", encoding="utf-8") as f:
res = format_code(transpile(f.read()))
name_cpp = path.with_suffix('.cpp')
......
# coding: utf-8
def fib():
a = 0
b = 1
while True:
yield a
a, b = b, a + b
if __name__ == "__main__":
f = fib()
for i in range(10):
print(next(f))
\ No newline at end of file
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment