Commit fe2492d6 authored by Tom Niget's avatar Tom Niget

webserver_eval works, many things work

parent 909e37a5
......@@ -65,8 +65,16 @@ namespace typon {
// class TyNone {};
using TyNone = std::nullopt_t;
auto None = std::nullopt;
//using TyNone = std::nullopt_t;
struct TyNone {
operator bool() const { return false; }
operator std::nullopt_t() const { return std::nullopt; }
template <typename T>
operator std::optional<T>() const { return std::nullopt; }
};
auto None = TyNone{};
} // namespace typon
......
......@@ -173,21 +173,24 @@ struct TyDict__oo : classtype<_Base0, TyDict__oo<>> {
template <typename K, typename V>
struct Obj : instance<TyDict__oo<>, Obj<K, V>> {
using map_type = std::unordered_map<K, V>;
std::shared_ptr<map_type> _m;
std::shared_ptr<std::unordered_map<K, V>> _m;
Obj(std::shared_ptr<std::unordered_map<K, V>> &&m) : _m(std::move(m)) {}
/*Obj(std::shared_ptr<std::unordered_map<K, V>> &&m) : _m(std::move(m)) {}
Obj(std::unordered_map<K, V> &&m)
: _m(std::move(
std::make_shared<std::unordered_map<K, V>>(std::move(m)))) {}
Obj(std::initializer_list<std::pair<K, V>> &&m)
: _m(std::make_shared<std::unordered_map<K, V>>(std::move(m))) {}
std::make_shared<std::unordered_map<K, V>>(std::move(m)))) {}*/
Obj(std::initializer_list<typename map_type::value_type> &&m)
: _m(std::make_shared<map_type>(std::move(m))) {}
Obj() : _m(std::make_shared<std::unordered_map<K, V>>()) {}
Obj() : _m(std::make_shared<map_type>()) {}
template <typename... Args>
Obj(Args &&...args)
: _m(std::make_shared<std::unordered_map<K, V>>(
: _m(std::make_shared<map_type>(
std::forward<Args>(args)...)) {}
auto begin() const { return _m->begin(); }
auto end() const { return _m->end(); }
};
template <typename T> auto operator()(std::initializer_list<T> &&v) const {
......
......@@ -13,6 +13,10 @@
namespace typon {
using namespace referencemodel;
struct UnpackedSlice {
ssize_t start, stop, step;
};
template <typename _Base0 = object>
struct TySlice__oo : classtype<_Base0, TySlice__oo<>> {
static constexpr std::string_view name = "TySlice";
......@@ -25,6 +29,33 @@ struct TySlice__oo : classtype<_Base0, TySlice__oo<>> {
Obj(Start start, Stop stop, Step step)
: start(start), stop(stop), step(step) {}
std::pair<ssize_t, UnpackedSlice> adjust_indices(ssize_t seq_length) {
UnpackedSlice res;
if constexpr (std::is_same_v<Step, TyNone>) {
res.step = 1;
} else {
res.step = this->step;
}
if constexpr (std::is_same_v<Start, TyNone>) {
res.start = res.step < 0 ? PY_SSIZE_T_MAX : 0;
} else {
res.start = this->start;
}
if constexpr (std::is_same_v<Stop, TyNone>) {
res.stop = res.step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
} else {
res.stop = this->stop;
}
auto len =
PySlice_AdjustIndices(seq_length, &res.start, &res.stop, res.step);
return {len, res};
}
};
template <typename Stop> auto operator()(Stop stop) const {
......@@ -64,36 +95,9 @@ static constexpr TySlice__oo<> TySlice{};
std::optional<ssize_t> stop = 0;
std::optional<ssize_t> step = 1;
struct UnpackedSlice {
ssize_t start, stop, step;
};
std::pair<ssize_t, UnpackedSlice> adjust_indices(ssize_t seq_length) {
UnpackedSlice res;
if (this->step == std::nullopt) {
res.step = 1;
} else {
res.step = this->step.value();
}
if (this->start == std::nullopt) {
res.start = res.step < 0 ? PY_SSIZE_T_MAX : 0;
} else {
res.start = this->start.value();
}
if (this->stop == std::nullopt) {
res.stop = res.step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
} else {
res.stop = this->stop.value();
}
auto len =
PySlice_AdjustIndices(seq_length, &res.start, &res.stop, res.step);
return {len, res};
}
};*/
#endif // TYPON_SLICE_HPP
......@@ -178,6 +178,28 @@ struct TyStr__oo : classtype<_Base0, TyStr__oo<>> {
// getitem
struct : method {
auto operator()(auto self, TySlice__oo<>::Obj<auto, auto, auto> slice) const {
auto [len, new_slice] = slice.adjust_indices(self->value.size());
Obj result;
result.value.reserve(len);
if (new_slice.start < new_slice.stop) {
if (new_slice.step > 0) {
for (auto i = new_slice.start; i < new_slice.stop;
i += new_slice.step) {
result.value.push_back(self->value[i]);
}
}
} else {
if (new_slice.step < 0) {
for (auto i = new_slice.start; i > new_slice.stop;
i += new_slice.step) {
result.value.push_back(self->value[i]);
}
}
}
return result;
}
auto operator()(auto self, auto index) const {
if (index < 0) {
index += self->value.size();
......@@ -186,12 +208,24 @@ struct TyStr__oo : classtype<_Base0, TyStr__oo<>> {
}
} static constexpr oo__getitem__oo{};
/*struct : method {
struct : method {
auto operator()(auto self, auto other) const {
auto pos = self->value.find(other->value);
return typon::TyInt(pos == std::string::npos ? -1 : pos);
return (pos == std::string::npos ? -1 : pos);
}
} static constexpr oo__find__oo{};*/
} static constexpr find{};
struct : method {
auto operator()(auto self, auto other) const {
return self->value.starts_with(other->value);
}
} static constexpr startswith{};
struct : method {
auto operator()(auto self, auto encoding = Obj(std::string("utf-8"))) const {
return Obj(self->value);
}
} static constexpr encode{};
// format
/*
......@@ -208,12 +242,19 @@ struct TyStr__oo : classtype<_Base0, TyStr__oo<>> {
} static constexpr format{};
struct Obj : value<TyStr__oo<>, Obj> {
using value_type = std::string::value_type;
std::string value;
constexpr Obj() : value() {}
constexpr Obj(std::string value) : value(value) {}
constexpr Obj(const char* value, size_t count) : value(value, count) {}
operator std::string() const { return value; }
operator std::string_view() const { return value; }
auto data() const { return value.data(); }
auto size() const { return value.size(); }
bool operator ==(const Obj &other) const { return value == other.value; }
};
auto operator()(std::string value) const { return Obj(value); }
......@@ -226,6 +267,12 @@ inline constexpr auto operator""_ps(const char *s, size_t len) noexcept {
return typon::TyStr__oo<>::Obj(std::string(s, len));
}
template <> struct std::hash<decltype(""_ps)> {
std::size_t operator()(const decltype(""_ps) &s) const noexcept {
return std::hash<std::string>()(s);
}
};
/*template <typename T> auto str(const T &x) { return dot(x, oo__str__oo)(); }
template <typename T>
......@@ -264,4 +311,11 @@ template <typename T> auto repr(const T &x) {
}
}
namespace PYBIND11_NAMESPACE {
namespace detail {
template<>
struct type_caster<decltype(""_ps)>
: string_caster<decltype(""_ps)> {};
}}
#endif // TYPON_STR_HPP
Subproject commit 76287636438cf0a82701102ccb8014c66ea88506
Subproject commit f58767e045d32aaaed44c68082220e08c481c159
......@@ -49,7 +49,8 @@ class Iterable[U](Protocol):
class str:
def find(self, sub: Self) -> int: ...
def format(self, *args) -> Self: ...
def encode(self, encoding: Self) -> bytes: ...
def encode(self, encoding: Self) -> Self: ... # TODO: bytes
def decode(self, encoding: Self) -> Self: ...
def __len__(self) -> int: ...
def __add__(self, other: Self) -> Self: ...
def __mul__(self, other: int) -> Self: ...
......
......@@ -3,8 +3,7 @@
import sys
from socket import socket, SOCK_STREAM, AF_INET6, SOL_SOCKET, SO_REUSEADDR
from typon import fork
from builtins import eval
from python.builtins import eval
#fork = lambda x: x()
BACKLOG = 1024
......@@ -25,21 +24,24 @@ def create_listening_socket(port):
return sockfd
def handle_connection(connfd):
buf = connfd.recv(1024).decode("utf-8")
buf: str = connfd.recv(1024).decode("utf-8")
resp: str
if not buf.startswith("GET /eval?e="):
resp = "Expression missing"
else:
http_pos = buf.find("HTTP/1.1\r\n")
s = "str(" + buf[12:http_pos-1] + ")"
resp = eval(s, {"req": buf})
#resp = eval(s, {"req": buf})
context = {"req": buf}
resp = eval(s, context)
response = response_fmt.format(len(resp), resp)
connfd.send(response.encode("utf-8"))
connfd.close()
def server_loop(sockfd):
while True:
connfd, _ = sockfd.accept()
#connfd, _ = sockfd.accept()
connfd = sockfd.accept()[0]
fork(lambda: handle_connection(connfd))
......
......@@ -345,19 +345,18 @@ class ExpressionVisitor(NodeVisitor):
def visit_Dict(self, node: ast.Dict) -> Iterable[str]:
def visit_item(key, value):
yield "std::pair {"
yield "{"
yield from self.visit(key)
yield ", "
yield from self.visit(value)
yield "}"
if node.keys:
#yield from self.visit(node.type)
yield "typon::TyDict("
yield "{"
yield from self.visit(node.type)
#yield "typon::TyDict("
yield "({"
yield from join(", ", map(visit_item, node.keys, node.values))
yield "}"
yield ")"
yield "})"
else:
yield from self.visit(node.type)
yield "{}"
......@@ -394,8 +393,10 @@ class ExpressionVisitor(NodeVisitor):
def visit_unary_operation(self, op, operand) -> Iterable[str]:
if type(op) != str:
op = SYMBOLS[type(op)]
yield "("
yield op
yield from self.prec("unary").visit(operand)
yield from self.visit(operand)
yield ")"
def visit_IfExp(self, node: ast.IfExp) -> Iterable[str]:
yield "("
......
......@@ -38,11 +38,16 @@ def emit_function(name: str, func: CallableInstanceType, base="function", gen_p=
yield rty
yield " {"
for var, initval in func.block_data.scope.root_decls.items():
yield "typename std::remove_reference<decltype(" # TODO: duplicate code in visit_lvalue
yield from ExpressionVisitor(func.block_data.scope, mode).visit(initval)
yield ")>::type"
__TB_NODE__ = initval
if isinstance(initval, BaseType):
yield from NodeVisitor().visit_BaseType(initval)
else:
yield "typename std::remove_reference<decltype(" # TODO: duplicate code in visit_lvalue
yield from ExpressionVisitor(func.block_data.scope, mode).visit(initval)
yield ")>::type"
yield var
yield ";"
__TB_NODE__ = func.block_data.node
vis = BlockVisitor(func.block_data.scope, generator=mode)
for stmt in func.block_data.node.body:
yield from vis.visit(stmt)
......
......@@ -2,11 +2,13 @@ import ast
from typing import Iterable
from transpiler.phases.emit_cpp.class_ import emit_class
from transpiler.phases.emit_cpp.function import emit_function
from transpiler.phases.emit_cpp.visitors import NodeVisitor
from transpiler.phases.emit_cpp.expr import ExpressionVisitor
from transpiler.phases.emit_cpp.function import emit_function, BlockVisitor
from transpiler.phases.emit_cpp.visitors import NodeVisitor, CoroutineMode
from transpiler.phases.typing.modules import ModuleType, TyponModuleType, PythonModuleType
from transpiler.phases.typing.types import CallableInstanceType, ClassTypeType, TypeVariable, BaseType, GenericType, \
GenericInstanceType, UserGenericType
GenericInstanceType, UserGenericType, RuntimeValue
from transpiler.utils import linenodata
def emit_module(mod: ModuleType) -> Iterable[str]:
......@@ -24,7 +26,7 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
case TyponModuleType():
yield f"#include <python/{name}.hpp>"
case PythonModuleType():
yield f"namespace py_{name} {{"
yield f"namespace py_python_{name} {{"
yield "template <typename _Unused = void>"
yield f"struct {name}__oo : referencemodel::moduletype<{name}__oo<>> {{"
......@@ -75,24 +77,43 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
case ast.Import(names):
for alias in names:
yield from emit(alias.module_obj)
incl_vars.append(f"auto& {alias.asname or alias.name} = py_{alias.name}::all;")
prefix = "python_" if isinstance(alias.module_obj, PythonModuleType) else ""
incl_vars.append(f"auto& {alias.asname or alias.name} = py_{prefix}{alias.module_obj.name()}::all;")
case ast.ImportFrom(module, names, _):
yield from emit(node.module_obj)
prefix = "python_" if isinstance(node.module_obj, PythonModuleType) else ""
for alias in names:
incl_vars.append(f"auto& {alias.asname or alias.name} = py_{module}::all.{alias.name};")
if isinstance(node.module_obj, PythonModuleType):
if isinstance(node.module_obj.fields[alias.name].type.resolve(), TypeVariable):
continue # unused function
incl_vars.append(f"auto& {alias.asname or alias.name} = py_{prefix}{node.module_obj.name()}::all.{alias.name};")
yield "namespace PROGRAMNS {"
yield from incl_vars
yield "template <typename _Unused = void>"
yield f"struct {mod.name()}__oo : referencemodel::moduletype<{mod.name()}__oo<>>"
yield "{"
init_lines = []
for name, field in mod.fields.items():
if not field.in_class_def:
continue
if isinstance(field.type, ClassTypeType):
ty = field.type.inner_type
else:
ty = field.type
ty = field.type
if isinstance(field.from_node, ast.Assign):
yield "static inline"
yield from NodeVisitor().visit_BaseType(field.from_node.value.type)
yield name
yield "="
yield from ExpressionVisitor(mod.block_data.scope, CoroutineMode.SYNC).visit(field.from_node.value)
yield ";"
# if not isinstance(field.from_node.value, RuntimeValue):
# assign_node = ast.Assign([ast.Name(name)], field.from_node.value, None, **linenodata(field.from_node))
# assign_node.is_declare = None
# init_lines.append(BlockVisitor(mod.block_data.scope).visit(assign_node))
continue
if isinstance(ty, ClassTypeType):
ty = ty.inner_type
gen_p = [TypeVariable(p.name, emit_as_is=True) for p in ty.parameters]
ty = ty.instantiate(gen_p)
......@@ -109,7 +130,12 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
case _:
raise NotImplementedError(f"Unsupported module item type {ty}")
yield f"{mod.name()}__oo() {{"
for line in init_lines:
yield from line
yield "}"
yield "};"
yield f"constexpr {mod.name()}__oo<> {mod.name()};"
yield f"{mod.name()}__oo<> {mod.name()};"
yield f"static_assert(sizeof {mod.name()} == 1);"
yield "}"
......@@ -73,6 +73,8 @@ class NodeVisitor(UniversalVisitor):
yield 'decltype(""_ps)'
case types.TY_LIST:
yield "typon::TyList__oo<>::Obj"
case types.TY_DICT:
yield "typon::TyDict__oo<>::Obj"
case types.TypeVariable(name, emit_as_is=em, decltype_str=dt):
if em:
yield name
......
......@@ -115,8 +115,10 @@ class ScoperBlockVisitor(ScoperVisitor):
# return True
val = val or RuntimeValue()
self.scope.function.vars[target.id] = VarDecl(VarKind.LOCAL, decl_val, val)
if self.scope.kind == ScopeKind.FUNCTION_INNER:
self.scope.function.root_decls[target.id] = val
#if self.scope.kind == ScopeKind.FUNCTION_INNER:
#if not isinstance(val, RuntimeValue):
if True:
self.scope.function.root_decls[target.id] = val if not isinstance(val, RuntimeValue) else decl_val
return False
return True
elif isinstance(target, ast.Tuple):
......
......@@ -322,11 +322,14 @@ class ScoperExprVisitor(ScoperVisitor):
def visit_Dict(self, node: ast.Dict) -> BaseType:
if not node.keys:
return TY_DICT.instantiate_default()
keys = [self.visit(e) for e in node.keys]
values = [self.visit(e) for e in node.values]
if len(set(keys)) != 1 or len(set(values)) != 1:
raise NotImplementedError(f"Dict with different types not handled yet in `{ast.unparse(node)}`")
return TY_DICT.instantiate([keys[0], values[0]])
key_type = TypeVariable()
value_type = TypeVariable()
for k, v in zip(node.keys, node.values):
if not key_type.try_assign(self.visit(k)):
raise NotImplementedError(f"Dict with different key types not handled yet in `{ast.unparse(node)}`")
if not value_type.try_assign(self.visit(v)):
raise NotImplementedError(f"Dict with different value types not handled yet in `{ast.unparse(node)}`")
return TY_DICT.instantiate([key_type, value_type])
def visit_Subscript(self, node: ast.Subscript) -> BaseType:
left = self.visit(node.value)
......
......@@ -23,7 +23,7 @@ def make_module(name: str, scope: Scope) -> TyponModuleType:
return name
ty = CreatedType()
for n, v in scope.vars.items():
ty.fields[n] = MemberDef(v.type, v.val, v.is_item_decl)
ty.fields[n] = MemberDef(v.type, v.val, v.is_item_decl, v.from_node)
return ty
visited_modules = {}
......@@ -62,6 +62,8 @@ def parse_module(mod_name: str, python_path: list[Path], scope=None, preprocess=
"""
if mod_name.startswith("python."):
mod_name = mod_name[len("python."):]
try:
py_mod = importlib.import_module(mod_name)
except ModuleNotFoundError:
......
......@@ -29,6 +29,7 @@ class VarDecl:
type: BaseType
val: Any = RuntimeValue()
is_item_decl: bool = False
from_node: ast.AST = None
class ScopeKind(Enum):
......
......@@ -102,7 +102,11 @@ class StdlibVisitor(NodeVisitorSeq):
self.visit(stmt)
def visit_Assign(self, node: ast.Assign):
self.scope.vars[node.targets[0].id] = VarDecl(VarKind.LOCAL, self.anno().visit(node.value).type_type())
if self.is_native:
decl = VarDecl(VarKind.LOCAL, self.anno().visit(node.value).type_type())
else:
decl = VarDecl(VarKind.LOCAL, self.expr().visit(node.value), is_item_decl=True, from_node=node)
self.scope.vars[node.targets[0].id] = decl
def visit_AnnAssign(self, node: ast.AnnAssign):
ty = self.anno().visit(node.annotation)
......
......@@ -24,6 +24,7 @@ class MemberDef:
type: "BaseType"
val: typing.Any = RuntimeValue()
in_class_def: bool = True
from_node: ast.AST = None
@dataclass
class UnifyMode:
......
#include <python/builtins.hpp>
#include <python/socket.hpp>
#include <python/sys.hpp>
namespace py_python_builtins {
template <typename _Unused = void>
struct builtins__oo : referencemodel::moduletype<builtins__oo<>> {
struct : referencemodel::function {
auto
operator()(lvalue_or_rvalue<decltype(""_ps)> arg0,
lvalue_or_rvalue<
typon::TyDict__oo<>::Obj<decltype(""_ps), decltype(""_ps)>>
arg1) const {
InterpGuard guard{};
try {
return py::module_::import("builtins")
.attr("eval")(*arg0, *arg1)
.cast<decltype(""_ps)>();
} catch (py::error_already_set &e) {
std::cerr << "Python exception: " << e.what() << std::endl;
throw;
}
}
} static constexpr eval{};
};
builtins__oo<> all;
} // namespace py_python_builtins
namespace PROGRAMNS {
auto &sys = py_sys::all;
auto &socket = py_socket::all.socket;
auto &SOCK_STREAM = py_socket::all.SOCK_STREAM;
auto &AF_INET6 = py_socket::all.AF_INET6;
auto &SOL_SOCKET = py_socket::all.SOL_SOCKET;
auto &SO_REUSEADDR = py_socket::all.SO_REUSEADDR;
auto &eval = py_python_builtins::all.eval;
template <typename _Unused = void>
struct webserver_eval__oo : referencemodel::moduletype<webserver_eval__oo<>> {
static decltype(0_pi) BACKLOG;
static decltype(0_pi) PORT;
static decltype(""_ps) response_fmt;
struct : referencemodel::function {
template <typename AutoVar$9120453574589009546 = void,
typename AutoVar$return = void>
auto typon$$sync(AutoVar$9120453574589009546 port) const {
auto sockfd = call_sync(socket)(AF_INET6, SOCK_STREAM);
call_sync(dot((sockfd), setsockopt))(SOL_SOCKET, SO_REUSEADDR, 1_pi);
call_sync(dot((sockfd), bind))(std::make_tuple(""_ps, port));
call_sync(dot((sockfd), listen))(BACKLOG);
return sockfd;
}
using has_sync = std::true_type;
template <typename AutoVar$9120453574589009546 = void,
typename AutoVar$return = void>
auto operator()(AutoVar$9120453574589009546 port) const
-> typon::Task<decltype(typon$$sync(port))> {
auto sockfd = co_await (socket)(AF_INET6, SOCK_STREAM);
co_await (dot((sockfd), setsockopt))(SOL_SOCKET, SO_REUSEADDR, 1_pi);
co_await (dot((sockfd), bind))(std::make_tuple(""_ps, port));
co_await (dot((sockfd), listen))(BACKLOG);
co_return sockfd;
}
} static constexpr create_listening_socket{};
static_assert(HasSync<decltype(create_listening_socket)>);
static_assert(sizeof create_listening_socket == 1);
struct : referencemodel::function {
template <typename AutoVar$1818216228010231424 = void,
typename AutoVar$return = void>
auto operator()(AutoVar$1818216228010231424 connfd) const
-> typon::Task<typon::TyNone> {
auto buf = co_await (dot((co_await (dot((connfd), recv))(1024_pi)), decode))(
"utf-8"_ps);
if ((!co_await (dot((buf), startswith))("GET /eval?e="_ps))) {
auto resp = "Expression missing"_ps;
} else
{
auto http_pos = co_await (dot((buf), find))("HTTP/1.1\r\n"_ps);
auto s = ( (( ("str("_ps
+
( dot(buf, oo__getitem__oo)(
typon::TySlice(12_pi,
( (http_pos
-
1_pi)),
None)))))
+
")"_ps));
//auto resp = co_await (eval)(s, typon::TyDict({std::pair{"req"_ps, buf}}));
}
co_return None;
}
} static constexpr handle_connection{};
static_assert(sizeof handle_connection == 1);
struct : referencemodel::function {
template <typename AutoVar$1872507998259318362 = void,
typename AutoVar$return = void>
auto operator()(AutoVar$1872507998259318362 sockfd) const
-> typon::Join<typon::TyNone> {
while (typon::TyBool(true)) {
auto connfd = (co_await typon::constant_get<0>(
co_await (dot((sockfd), accept))()));
co_await typon::fork(handle_connection(connfd));
}
co_return None;
}
} static constexpr server_loop{};
static_assert(sizeof server_loop == 1);
struct : referencemodel::function {
template <typename AutoVar$return = void>
auto operator()() const -> typon::Task<typon::TyNone> {
co_await (print)("Serving on port"_ps, PORT);
co_await (print)();
auto sockfd = co_await (create_listening_socket)(PORT);
co_await (server_loop)(sockfd);
co_return None;
}
} static constexpr main{};
static_assert(sizeof main == 1);
webserver_eval__oo() {
BACKLOG = 1024_pi;
PORT = 8000_pi;
response_fmt =
"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\nContent-length: {}\r\n\r\n{}"_ps;
}
};
webserver_eval__oo<> webserver_eval;
static_assert(sizeof webserver_eval == 1);
} // namespace PROGRAMNS
#ifdef TYPON_EXTENSION
#else
typon::Root root() { co_await dot(PROGRAMNS::webserver_eval, main)(); }
int main(int argc, char *argv[]) {
py_sys::all.argv = typon::TyList__oo<>::Obj(
std::vector<typon::TyStr__oo<>::Obj>(argv, argv + argc));
root().call();
}
#endif
\ No newline at end of file
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