Commit f964bee3 authored by Tom Niget's avatar Tom Niget

Add initial support for generators with parameters

parent 5a5f093a
......@@ -35,19 +35,32 @@ template <PyLen T> size_t len(const T &t) { return t.py_len(); }
template <typename T>
concept PyNext = requires(T t) {
t.py_next();
{ t.py_next() } -> std::same_as<std::optional<typename T::value_type>>;
};
template <PyNext T> auto next(T &t) { return t.py_next(); }
template <PyNext T>
std::optional<typename T::value_type>
next(T &t, std::optional<typename T::value_type> def = std::nullopt) {
auto opt = t.py_next();
return opt ? opt : def;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, std::optional<T> const& opt)
{
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; }
class NoneType {
public:
template <typename T> operator T *() const { return nullptr; }
template <typename T> operator std::optional<T>() const {
return std::nullopt;
}
} PyNone{};
#include "builtins/bool.hpp"
#include "builtins/complex.hpp"
#include "builtins/dict.hpp"
......
......@@ -22,7 +22,7 @@ class Generator
Promise() = default;
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { final = true; return {}; }
void unhandled_exception() {
std::rethrow_exception(std::move(std::current_exception()));
}
......@@ -47,11 +47,13 @@ class Generator
}
bool finished() {
return !value.has_value();
//return !value.has_value();
return final;
}
private:
value_type value{};
bool final = false;
};
public:
......@@ -68,7 +70,9 @@ public:
Promise::value_type next() {
if (handle) {
if (!handle.promise().finished()) {
handle.resume();
}
return handle.promise().get_value();
}
else {
......@@ -135,7 +139,7 @@ public:
}
std::optional<value_type> py_next() {
return *begin();
return next();
}
private:
......
# coding: utf-8
def fib():
def fib(upto):
a = 0
b = 1
while True:
while b < upto:
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
f = fib(50)
for i in range(15):
print(next(f, None))
\ No newline at end of file
......@@ -129,17 +129,18 @@ class NodeVisitor:
else:
raise UnsupportedNodeError(node)
def process_args(self, node: ast.arguments) -> (str, str):
def process_args(self, node: ast.arguments) -> (str, str, str):
for field in ("posonlyargs", "vararg", "kwonlyargs", "kw_defaults", "kwarg", "defaults"):
if getattr(node, field, None):
raise NotImplementedError(node, field)
if not node.args:
return "", "()"
f_args = [(arg.arg, f"T{i + 1}") for i, arg in enumerate(node.args)]
return "", "()", []
f_args = [(self.fix_name(arg.arg), f"T{i + 1}") for i, arg in enumerate(node.args)]
return (
"<" + ", ".join(f"typename {t}" for _, t in f_args) + ">",
"(" + ", ".join(f"{t} {self.fix_name(n)}" for n, t in f_args) + ")"
"(" + ", ".join(f"{t} {n}" for n, t in f_args) + ")",
[n for n, _ in f_args]
)
def fix_name(self, name: str) -> str:
......@@ -205,6 +206,8 @@ class ExpressionVisitor(NodeVisitor):
yield str(node.value)
elif isinstance(node.value, complex):
yield f"PyComplex({node.value.real}, {node.value.imag})"
elif node.value is None:
yield "PyNone"
else:
raise NotImplementedError(node, type(node))
......@@ -234,7 +237,7 @@ class ExpressionVisitor(NodeVisitor):
def visit_Lambda(self, node: ast.Lambda) -> Iterable[str]:
yield "[]"
templ, args = self.process_args(node.args)
templ, args, _ = self.process_args(node.args)
yield templ
yield args
yield "{"
......@@ -409,18 +412,18 @@ class BlockVisitor(NodeVisitor):
raise
def visit_func(self, node: ast.FunctionDef, generator: CoroutineMode) -> Iterable[str]:
templ, args = self.process_args(node.args)
templ, args, names = self.process_args(node.args)
if templ:
yield "template"
yield templ
faked = f"FAKED_{node.name}"
if generator == CoroutineMode.FAKE:
yield f"static auto {faked}"
elif generator == CoroutineMode.GENERATOR:
yield f"typon::Generator<decltype({faked}())> {node.name}"
else:
yield f"auto {node.name}"
yield args
if generator == CoroutineMode.GENERATOR:
yield f"-> typon::Generator<decltype({faked}({', '.join(names)}))>"
yield "{"
inner_scope = self.scope.function()
for child in node.body:
......
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