Commit 31cd80fe authored by Tom Niget's avatar Tom Niget

Started implementing builtin types PyBytes, PyStr, Socket

parent 4136d4cf
......@@ -57,11 +57,22 @@ concept PyIterable = requires(T t) {
template <PyIterable T, PyIterator U> U iter(const T &t) { return t.py_iter(); }
template <typename T>
concept CppSize = requires(const T &t) {
{ t.size() } -> std::same_as<size_t>;
};
template <typename T>
concept PyLen = requires(const T &t) {
{ t.py_len() } -> std::same_as<size_t>;
};
template <CppSize T>
requires (!PyLen<T>)
size_t len(const T &t) { return t.size(); }
template <PyLen T> size_t len(const T &t) { return t.py_len(); }
template <typename T>
......
//
// Created by Tom on 13/06/2023.
//
#ifndef TYPON_BYTES_H
#define TYPON_BYTES_H
class PyStr;
class PyBytes : public std::string {
public:
PyBytes() : std::string() {}
PyBytes(const char *s) : std::string(s) {}
PyBytes(const std::string &s) : std::string(s) {}
PyBytes(std::string &&s) : std::string(std::move(s)) {}
template <class InputIterator>
PyBytes(InputIterator first, InputIterator last) : std::string(first, last) {}
PyStr decode(const std::string &encoding = "utf-8") const;
};
#endif // TYPON_BYTES_H
......@@ -10,7 +10,7 @@
// TODO: Hyrum's Law, maybe consider using composition instead to not expose
// that this is a std::vector?
template <typename T> class PyList : public std::vector<T> {
template <typename T> class PyList {
public:
PyList(std::shared_ptr<std::vector<T>> &&v) : _v(std::move(v)) {}
PyList(std::vector<T> &&v) : _v(std::move(std::make_shared<std::vector<T>>(std::move(v)))) {}
......@@ -27,6 +27,9 @@ public:
return *reinterpret_cast<std::vector<T> *>(this);
}*/
constexpr const T &operator[](size_t i) const { return _v->operator[](i); }
constexpr T &operator[](size_t i) { return _v->operator[](i); }
size_t py_len() const { return _v->size(); }
void py_repr(std::ostream &s) const {
......
......@@ -10,9 +10,34 @@
using namespace std::literals;
#include "bytes.hpp"
#include "print.hpp"
using PyStr = std::string;
//#include <format>
#include <fmt/format.h>
class PyStr : public std::string {
public:
PyStr() : std::string() {}
PyStr(const char *s) : std::string(s) {}
PyStr(const std::string &s) : std::string(s) {}
PyStr(std::string &&s) : std::string(std::move(s)) {}
template <class InputIterator>
PyStr(InputIterator first, InputIterator last) : std::string(first, last) {}
PyBytes encode(const std::string &encoding = "utf-8") const {
return PyBytes(this->begin(), this->end());
}
template <typename... T> PyStr format(T &&...args) const {
return PyStr(fmt::format(fmt::runtime(*this), std::forward<T>(args)...));
//return std::format(*this, std::forward<T>(args)...);
}
};
PyStr PyBytes::decode(const std::string &encoding) const {
return PyStr(this->begin(), this->end());
}
template <typename T> PyStr str(const T &x) {
std::stringstream s;
......
//
// Created by Tom on 13/06/2023.
//
#ifndef TYPON_SOCKET_HPP
#define TYPON_SOCKET_HPP
#undef SOCK_STREAM
#undef AF_INET6
#undef SOL_SOCKET
#undef SO_REUSEADDR
#include "builtins/bytes.hpp"
#include <tuple>
namespace py_socket {
struct socket_t {
int SOCK_STREAM = 1;
int AF_INET6 = 10;
int SOL_SOCKET = 1;
int SO_REUSEADDR = 2;
struct {
struct type {
struct {
std::tuple<type, std::string> operator()() { return {}; }
} accept;
struct {
void operator()() {}
} close;
struct {
void operator()(int backlog) {}
} listen;
struct {
void operator()(int level, int optname, int optval) {}
} setsockopt;
struct {
void operator()(std::tuple<std::string, int> address) {}
} bind;
struct {
PyBytes operator()(int bufsize) { return {}; }
} recv;
struct {
void operator()(PyBytes data) {}
} send;
};
type operator()(int family, int type) { return {}; }
} socket;
} all;
auto &get_all() { return all; }
} // namespace py_socket
namespace typon {
using PySocket = decltype(py_socket::all.socket)::type;
};
#endif // TYPON_SOCKET_HPP
......@@ -28,8 +28,6 @@
#include <utility>
#include <vector>
#include <liburing.h>
#include <typon/event_count.hpp>
#include <typon/garbage_collector.hpp>
#include <typon/pool.hpp>
......@@ -42,6 +40,8 @@
namespace typon
{
#include <liburing.h>
struct Scheduler
{
using uint = unsigned int;
......
from typing import Self, TypeVar, Generic, Tuple
from typing import Self, TypeVar, Generic
class int:
def __add__(self, other: Self) -> Self: ...
......@@ -15,13 +14,21 @@ assert int.__add__
U = TypeVar("U")
V = TypeVar("V")
class HasLen:
def __len__(self) -> int: ...
def len(x: HasLen) -> int:
...
class str(HasLen):
def find(self, sub: Self) -> int: ...
def format(self, *args) -> Self: ...
def encode(self, encoding: Self) -> bytes: ...
class bytes(HasLen):
def decode(self, encoding: str) -> str: ...
class list(Generic[U], HasLen):
......@@ -54,7 +61,7 @@ def identity(x: U) -> U:
assert identity(1)
assert identity("a")
def identity_2(x: U, y: V) -> Tuple[U, V]:
def identity_2(x: U, y: V) -> tuple[U, V]:
...
assert list.__add__
......@@ -67,6 +74,8 @@ assert lambda x: identity_2(x, x)
def print(*args) -> None: ...
assert print
def range(*args) -> Iterator[int]: ...
......
# coding: utf-8
from typing import Self
AF_INET6: int
SOCK_STREAM: int
SOL_SOCKET: int
SO_REUSEADDR: int
class socket:
def setsockopt(self, level: int, option: int, value: int) -> None:
pass
def bind(self, address: tuple[str, int]) -> None:
pass
def listen(self, backlog: int) -> None:
pass
def accept(self) -> tuple[Self, str]:
pass
def recv(self, bufsize: int) -> bytes:
pass
def send(self, data: bytes) -> None:
pass
def __init__(self, family: int, type: int) -> Self:
pass
def close(self) -> None:
pass
\ No newline at end of file
# coding: utf-8
import sys
from socket import socket as pysocket, SOCK_STREAM, AF_INET6, SOL_SOCKET, SO_REUSEADDR
from typon import fork
BACKLOG = 1024
PORT = 8000
response_fmt = \
"HTTP/1.0 200 OK\r\n" \
"Content-type: text/plain\r\n" \
"Content-length: {}\r\n" \
"\r\n" \
"{}"
def create_listening_socket(port):
sockfd = pysocket(AF_INET6, SOCK_STREAM)
sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sockfd.bind(("", port))
sockfd.listen(BACKLOG)
return sockfd
def handle_connection(connfd: pysocket, filepath):
buf = connfd.recv(1024).decode("utf-8")
length = buf.find("\r\n\r\n")
content = "Hello world"
response = response_fmt.format(len(content), content)
connfd.send(response.encode("utf-8"))
connfd.close()
def server_loop(sockfd: pysocket, filepath):
while True:
connfd, _ = sockfd.accept()
fork(lambda: handle_connection(connfd, filepath))
def server_loops(sockfd, filepath):
for i in range(20):
fork(lambda: server_loop(sockfd, filepath))
if __name__ == "__main__":
if len(sys.argv) > 2:
print("Usage: webserver [ filepath ]")
filepath = sys.argv[1] if len(sys.argv) == 2 else "webserver.cpp"
print("Serving", filepath, "on port", PORT)
sockfd = create_listening_socket(PORT)
server_loops(sockfd, filepath)
\ No newline at end of file
# coding: utf-8
import sys
BACKLOG = 1024
PORT = 8000
if __name__ == "__main__":
if len(sys.argv) > 2:
print("Usage: webserver [ filepath ]")
\ No newline at end of file
......@@ -7,7 +7,7 @@ from typing import Iterable
from transpiler.phases.emit_cpp.consts import MAPPINGS
from transpiler.phases.typing import TypeVariable
from transpiler.phases.typing.types import BaseType, TY_INT, TY_BOOL, TY_NONE, Promise, PromiseKind, TY_STR, UserType, \
TypeType
TypeType, TypeOperator
from transpiler.utils import UnsupportedNodeError
class UniversalVisitor:
......@@ -57,7 +57,7 @@ class NodeVisitor(UniversalVisitor):
elif node is TY_NONE:
yield "void"
elif node is TY_STR:
yield "std::string"
yield "PyStr"
elif isinstance(node, UserType):
yield f"PyObj<decltype({node.name})>"
elif isinstance(node, TypeType):
......@@ -81,6 +81,8 @@ class NodeVisitor(UniversalVisitor):
yield ">"
elif isinstance(node, TypeVariable):
raise NotImplementedError(f"Not unified type variable {node}")
elif isinstance(node, TypeOperator) and len(node.args) == 0:
yield "typon::Py" + node.name.title()
else:
raise NotImplementedError(node)
......
......@@ -238,8 +238,11 @@ class BlockVisitor(NodeVisitor):
def visit_lvalue(self, lvalue: ast.expr, declare: bool = False) -> Iterable[str]:
if isinstance(lvalue, ast.Tuple):
yield f"std::tie({', '.join(flatmap(self.expr().visit, lvalue.elts))})"
yield f"std::tie({', '.join(flatmap(self.visit_lvalue, lvalue.elts))})"
elif isinstance(lvalue, ast.Name):
if lvalue.id == "_":
yield "std::ignore"
return
name = self.fix_name(lvalue.id)
# if name not in self._scope.vars:
# if not self.scope.exists_local(name):
......
......@@ -26,7 +26,7 @@ class ScoperBlockVisitor(ScoperVisitor):
self.scope.vars[alias.asname or alias.name] = dataclasses.replace(mod, kind=VarKind.LOCAL)
def visit_ImportFrom(self, node: ast.ImportFrom):
module = self.scope.get(node.module, VarKind.MODULE) # TODO: VarKind.MODULE ?
module = self.scope.get(node.module, VarKind.MODULE)
if not module:
raise NameError(node.module)
if not isinstance(module.type, ModuleType):
......@@ -59,6 +59,8 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_assign_target(self, target, decl_val: BaseType) -> bool:
if isinstance(target, ast.Name):
if target.id == "_":
return False
target.type = decl_val
if vdecl := self.scope.get(target.id):
vdecl.type.unify(decl_val)
......@@ -71,7 +73,8 @@ class ScoperBlockVisitor(ScoperVisitor):
elif isinstance(target, ast.Tuple):
if not (isinstance(decl_val, TupleType) and len(target.elts) == len(decl_val.args)):
raise IncompatibleTypesError(f"Cannot unpack {decl_val} into {target}")
return any(self.visit_assign_target(t, ty) for t, ty in zip(target.elts, decl_val.args))
decls = [self.visit_assign_target(t, ty) for t, ty in zip(target.elts, decl_val.args)] # eager evaluated
return any(decls)
elif isinstance(target, ast.Attribute):
attr_type = self.expr().visit(target)
attr_type.unify(decl_val)
......
......@@ -91,7 +91,10 @@ class ScoperExprVisitor(ScoperVisitor):
ftype = self.visit(node.func)
if ftype.typevars:
ftype = ftype.gen_sub(None, {v.name: TypeVariable(v.name) for v in ftype.typevars})
rtype = self.visit_function_call(ftype, [self.visit(arg) for arg in node.args])
try:
rtype = self.visit_function_call(ftype, [self.visit(arg) for arg in node.args])
except IncompatibleTypesError as e:
raise IncompatibleTypesError(f"`{ast.unparse(node)}`: {e}")
actual = rtype
node.is_await = False
if isinstance(actual, Promise) and actual.kind != PromiseKind.GENERATOR:
......@@ -105,10 +108,9 @@ class ScoperExprVisitor(ScoperVisitor):
return actual
def visit_function_call(self, ftype: BaseType, arguments: List[BaseType]):
if isinstance(ftype, TypeType) and isinstance(ftype.type_object, UserType):
if isinstance(ftype, TypeType):# and isinstance(ftype.type_object, UserType):
init: FunctionType = self.visit_getattr(ftype.type_object, "__init__")
ctor = FunctionType(init.args[1:], ftype.type_object)
return self.visit_function_call(ctor, arguments)
return self.visit_function_call(init, arguments)
if not isinstance(ftype, FunctionType):
raise IncompatibleTypesError(f"Cannot call {ftype}")
#is_generic = any(isinstance(arg, TypeVariable) for arg in ftype.to_list())
......@@ -165,7 +167,7 @@ class ScoperExprVisitor(ScoperVisitor):
return attr
if meth := ltype.methods.get(name):
if bound:
return FunctionType(meth.parameters[1:], meth.return_type)
return meth.remove_self()
else:
return meth
raise IncompatibleTypesError(f"Type {ltype} has no attribute {name}")
......
......@@ -54,7 +54,10 @@ class StdlibVisitor(NodeVisitorSeq):
else:
parent = self.visit(b)
assert isinstance(parent, TypeType)
ty.type_object.gen_parents.append(parent.type_object)
if isinstance(ty.type_object, ABCMeta):
ty.type_object.gen_parents.append(parent.type_object)
else:
ty.type_object.parents.append(parent.type_object)
cl_scope = self.scope.child(ScopeKind.CLASS)
visitor = StdlibVisitor(cl_scope, ty)
for var in typevars:
......
......@@ -122,6 +122,13 @@ class TypeOperator(BaseType, ABC):
gen_methods: ClassVar[Dict[str, GenMethodFactory]] = {}
gen_parents: ClassVar[List[BaseType]] = []
@staticmethod
def make_type(name: str):
class TheType(TypeOperator):
def __init__(self):
super().__init__([], name)
return TheType()
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.gen_methods = {}
......@@ -249,6 +256,12 @@ class FunctionType(TypeOperator):
args = "()"
return f"{args} -> {ret}"
def remove_self(self):
res = FunctionType(self.parameters[1:], self.return_type)
res.variadic = self.variadic
res.optional_at = self.optional_at
return res
class CppType(TypeOperator):
def __init__(self, name: str):
......@@ -272,15 +285,16 @@ class TypeType(TypeOperator):
return self.args[0]
TY_TYPE = TypeOperator([], "type")
TY_INT = TypeOperator([], "int")
TY_STR = TypeOperator([], "str")
TY_BOOL = TypeOperator([], "bool")
TY_COMPLEX = TypeOperator([], "complex")
TY_NONE = TypeOperator([], "NoneType")
TY_TYPE = TypeOperator.make_type("type")
TY_INT = TypeOperator.make_type("int")
TY_STR = TypeOperator.make_type("str")
TY_BYTES = TypeOperator.make_type("bytes")
TY_BOOL = TypeOperator.make_type("bool")
TY_COMPLEX = TypeOperator.make_type("complex")
TY_NONE = TypeOperator.make_type("NoneType")
#TY_MODULE = TypeOperator([], "module")
TY_VARARG = TypeOperator([], "vararg")
TY_SELF = TypeOperator([], "Self")
TY_VARARG = TypeOperator.make_type("vararg")
TY_SELF = TypeOperator.make_type("Self")
TY_SELF.gen_sub = lambda this, typevars, _: this
......
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