Commit 213b5302 authored by Tom Niget's avatar Tom Niget

Rename type to py_type, add support for static members

parent 20578e6d
...@@ -50,7 +50,7 @@ auto dot_bind(Obj, Attr attr) { ...@@ -50,7 +50,7 @@ auto dot_bind(Obj, Attr attr) {
#define dot(OBJ, NAME) [](auto && obj) -> auto { return dot_bind(obj, obj.NAME); }(OBJ) #define dot(OBJ, NAME) [](auto && obj) -> auto { return dot_bind(obj, obj.NAME); }(OBJ)
#define dotp(OBJ, NAME) [](auto && obj) -> auto { return dot_bind(obj, obj->NAME); }(OBJ) #define dotp(OBJ, NAME) [](auto && obj) -> auto { return dot_bind(obj, obj->NAME); }(OBJ)
#define dots(OBJ, NAME) [](auto && obj) -> auto { return std::remove_reference<decltype(obj)>::type::type::NAME; }(OBJ) #define dots(OBJ, NAME) [](auto && obj) -> auto { return std::remove_reference<decltype(obj)>::type::py_type::NAME; }(OBJ)
#endif // TYPON_BASEDEF_HPP #endif // TYPON_BASEDEF_HPP
...@@ -45,14 +45,14 @@ template <typename T> ...@@ -45,14 +45,14 @@ template <typename T>
concept PySmartPtr = requires { typename T::element_type; }; concept PySmartPtr = requires { typename T::element_type; };
template <typename T> template <typename T>
concept PyUserType = requires { typename T::type; }; concept PyUserType = requires { typename T::py_type; };
template <typename T> struct RealType { template <typename T> struct RealType {
using type = T; using type = T;
}; };
template <PyUserType T> struct RealType<T> { template <PyUserType T> struct RealType<T> {
using type = typename T::type; using type = typename T::py_type;
}; };
template <PySmartPtr T> struct RealType<T> { template <PySmartPtr T> struct RealType<T> {
...@@ -149,7 +149,7 @@ public: ...@@ -149,7 +149,7 @@ public:
#include "builtins/str.hpp" #include "builtins/str.hpp"
struct file_s { struct file_s {
struct type { struct py_type {
METHOD( METHOD(
typon::Task<PyStr>, read, (Self self, size_t size = -1), { typon::Task<PyStr>, read, (Self self, size_t size = -1), {
if (size == -1) { if (size == -1) {
...@@ -178,9 +178,9 @@ struct file_s { ...@@ -178,9 +178,9 @@ struct file_s {
typon::Task<void>, flush, (Self self), typon::Task<void>, flush, (Self self),
{ co_await typon::io::fsync(self->fd); }) { co_await typon::io::fsync(self->fd); })
type(int fd = -1, size_t len = 0) : fd(fd), len(len) {} py_type(int fd = -1, size_t len = 0) : fd(fd), len(len) {}
type(const type &other) py_type(const py_type &other)
: fd(other.fd), len(other.len) {} : fd(other.fd), len(other.len) {}
METHOD( METHOD(
...@@ -198,7 +198,7 @@ struct file_s { ...@@ -198,7 +198,7 @@ struct file_s {
} file; } file;
namespace typon { namespace typon {
using PyFile = PyObj<decltype(file)::type>; using PyFile = PyObj<decltype(file)::py_type>;
} }
typon::Task<typon::PyFile> open(const PyStr &path, std::string_view mode) { typon::Task<typon::PyFile> open(const PyStr &path, std::string_view mode) {
...@@ -280,6 +280,8 @@ struct lvalue_or_rvalue { ...@@ -280,6 +280,8 @@ struct lvalue_or_rvalue {
namespace typon { namespace typon {
template< class... Types > template< class... Types >
using PyTuple = std::tuple<Types...>; using PyTuple = std::tuple<Types...>;
} }
template<typename T> template<typename T>
......
//
// Created by Tom on 18/08/2023.
//
#ifndef TYPON_EXCEPTION_HPP
#define TYPON_EXCEPTION_HPP
#include "str.hpp"
struct PyException_s {
struct py_type {
PyStr message;
};
auto operator()(const PyStr &message) const {
return py_type{message};
}
};
namespace typon {
using PyException = PyObj<PyException_s>;
}
#endif // TYPON_EXCEPTION_HPP
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include <functional>
#include "str.hpp" #include "str.hpp"
#include <typon/typon.hpp> #include <typon/typon.hpp>
...@@ -56,6 +56,12 @@ void repr_to(const T &x, std::ostream &s) { ...@@ -56,6 +56,12 @@ void repr_to(const T &x, std::ostream &s) {
s << "<function at 0x" << std::hex << (size_t)x << std::dec << ">"; s << "<function at 0x" << std::hex << (size_t)x << std::dec << ">";
} }
template <typename T>
void repr_to(const std::function<T> &x, std::ostream &s) {
s << "<function at 0x" << std::hex << (size_t)x.template target<T*>() << std::dec
<< ">";
}
template <> void repr_to(const PyStr &x, std::ostream &s) { template <> void repr_to(const PyStr &x, std::ostream &s) {
s << '"' << x << '"'; s << '"' << x << '"';
} }
...@@ -96,4 +102,14 @@ struct { ...@@ -96,4 +102,14 @@ struct {
} }
} print; } print;
// typon::Task<void> print() { std::cout << '\n'; co_return; } // typon::Task<void> print() { std::cout << '\n'; co_return; }
struct {
PyStr operator()(const PyStr& s = ""_ps) {
std::cout << s;
PyStr input;
std::getline(std::cin, input);
return input;
}
} input;
#endif // TYPON_PRINT_HPP #endif // TYPON_PRINT_HPP
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <algorithm>
using namespace std::literals; using namespace std::literals;
...@@ -47,6 +48,14 @@ public: ...@@ -47,6 +48,14 @@ public:
return pos == std::string::npos ? -1 : pos; return pos == std::string::npos ? -1 : pos;
}) })
METHOD(bool, isspace, (Self self), {
return std::all_of(self.begin(), self.end(), isspace);
})
METHOD(auto, py_contains, (Self self, const std::string &x), {
return self.std::string::find(x) != std::string::npos;
})
PyStr operator[](PySlice slice) const { PyStr operator[](PySlice slice) const {
auto [len, new_slice] = slice.adjust_indices(this->size()); auto [len, new_slice] = slice.adjust_indices(this->size());
......
...@@ -20,16 +20,16 @@ struct hashlib_t { ...@@ -20,16 +20,16 @@ struct hashlib_t {
typedef int (*openssl_final)(unsigned char *md, void *context); typedef int (*openssl_final)(unsigned char *md, void *context);
struct _Hash_s { struct _Hash_s {
struct type { struct py_type {
type(PyObj<void> context, openssl_update update, openssl_final final, py_type(PyObj<void> context, openssl_update update, openssl_final final,
int diglen) int diglen)
: _context(context), _update(update), _final(final), _diglen(diglen) { : _context(context), _update(update), _final(final), _diglen(diglen) {
} }
type() {} py_type() {}
type(const type &other) py_type(const py_type &other)
: _context(other._context), _update(other._update), : _context(other._context), _update(other._update),
_final(other._final), _diglen(other._diglen) {} _final(other._final), _diglen(other._diglen) {}
......
...@@ -25,7 +25,7 @@ struct os_t { ...@@ -25,7 +25,7 @@ struct os_t {
auto, fsdecode, (std::string s) { return s; }) auto, fsdecode, (std::string s) { return s; })
struct Stat_Result_s { struct Stat_Result_s {
struct type { struct py_type {
int st_mode; int st_mode;
unsigned long long st_ino; unsigned long long st_ino;
dev_t st_dev; dev_t st_dev;
...@@ -45,14 +45,14 @@ struct os_t { ...@@ -45,14 +45,14 @@ struct os_t {
} Stat_Result; } Stat_Result;
struct DirEntry_s { struct DirEntry_s {
struct type { struct py_type {
PyStr name; PyStr name;
PyStr path; PyStr path;
}; };
} DirEntry; } DirEntry;
struct _Scandiriterator_s { struct _Scandiriterator_s {
struct type { struct py_type {
using value_type = PyObj<DirEntry_s>; using value_type = PyObj<DirEntry_s>;
using reference = PyObj<DirEntry_s>; using reference = PyObj<DirEntry_s>;
...@@ -65,14 +65,14 @@ struct os_t { ...@@ -65,14 +65,14 @@ struct os_t {
METHOD(auto, begin, (Self self), { return *self; }) METHOD(auto, begin, (Self self), { return *self; })
METHOD(auto, end, (Self self), METHOD(auto, end, (Self self),
{ return type(self->basepath, self->namelist, self->n, self->n); }) { return py_type(self->basepath, self->namelist, self->n, self->n); })
auto operator*() { auto operator*() {
auto name = PyStr(this->namelist[this->current]->d_name); auto name = PyStr(this->namelist[this->current]->d_name);
return pyobj_agg<DirEntry_s>(name, this->basepath + name); return pyobj_agg<DirEntry_s>(name, this->basepath + name);
} }
type(const PyStr &basepath, struct dirent **namelist, int n, py_type(const PyStr &basepath, struct dirent **namelist, int n,
int current = 0) int current = 0)
: basepath(basepath), namelist(namelist), n(n), current(current) { : basepath(basepath), namelist(namelist), n(n), current(current) {
if (this->basepath[this->basepath.size() - 1] != '/') { if (this->basepath[this->basepath.size() - 1] != '/') {
...@@ -80,9 +80,9 @@ struct os_t { ...@@ -80,9 +80,9 @@ struct os_t {
} }
} }
type() {} py_type() {}
bool operator!=(const type &other) { bool operator!=(const py_type &other) {
return this->current != other.current; return this->current != other.current;
} }
...@@ -103,7 +103,7 @@ struct os_t { ...@@ -103,7 +103,7 @@ struct os_t {
STATX_SIZE, &statxbuf)) { STATX_SIZE, &statxbuf)) {
system_error(-err, "statx()"); system_error(-err, "statx()");
} }
co_return PyObj<Stat_Result_s>(new Stat_Result_s::type{ co_return PyObj<Stat_Result_s>(new Stat_Result_s::py_type{
statxbuf.stx_mode, statxbuf.stx_mode,
statxbuf.stx_ino, statxbuf.stx_ino,
makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor), makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor),
......
...@@ -23,13 +23,13 @@ struct socket_t { ...@@ -23,13 +23,13 @@ struct socket_t {
static constexpr int AF_UNIX = 1; static constexpr int AF_UNIX = 1;
struct socket_s { struct socket_s {
struct type { struct py_type {
METHOD(typon::Task<std::tuple<PyObj<type> COMMA() std::string>>, accept, (Self self), { METHOD(typon::Task<std::tuple<PyObj<py_type> COMMA() std::string>>, accept, (Self self), {
int connfd = co_await typon::io::accept(self->fd, NULL, NULL); int connfd = co_await typon::io::accept(self->fd, NULL, NULL);
if (connfd < 0) { if (connfd < 0) {
system_error(-connfd, "accept()"); system_error(-connfd, "accept()");
} }
co_return std::make_tuple(pyobj<type>(connfd), std::string("")); // TODO co_return std::make_tuple(pyobj<py_type>(connfd), std::string("")); // TODO
}) })
METHOD(typon::Task<void>, close, (Self self), METHOD(typon::Task<void>, close, (Self self),
...@@ -74,9 +74,9 @@ struct socket_t { ...@@ -74,9 +74,9 @@ struct socket_t {
} }
}) })
type(int fd = -1) : fd(fd) {} py_type(int fd = -1) : fd(fd) {}
type(const type &other) py_type(const py_type &other)
: fd(other.fd) {} : fd(other.fd) {}
int fd; int fd;
...@@ -84,7 +84,7 @@ struct socket_t { ...@@ -84,7 +84,7 @@ struct socket_t {
auto operator()(int family, int type_) { auto operator()(int family, int type_) {
if (int fd = ::socket(family, type_, 0); fd >= 0) { if (int fd = ::socket(family, type_, 0); fd >= 0) {
return pyobj<type>(fd); return pyobj<py_type>(fd);
} else { } else {
system_error(errno, "socket()"); system_error(errno, "socket()");
} }
......
...@@ -14,11 +14,14 @@ class int: ...@@ -14,11 +14,14 @@ class int:
def __and__(self, other: Self) -> Self: ... def __and__(self, other: Self) -> Self: ...
def __neg__(self) -> Self: ... def __neg__(self) -> Self: ...
def __init__(self, x: str) -> None: ... def __init__(self, x: object) -> None: ...
def __lt__(self, other: Self) -> bool: ... def __lt__(self, other: Self) -> bool: ...
def __gt__(self, other: Self) -> bool: ... def __gt__(self, other: Self) -> bool: ...
def __mod__(self, other: Self) -> Self: ... def __mod__(self, other: Self) -> Self: ...
def __ge__(self, other: Self) -> bool: ...
class float:
def __init__(self, x: object) -> None: ...
assert int.__add__ assert int.__add__
U = TypeVar("U") U = TypeVar("U")
...@@ -51,6 +54,8 @@ class str: ...@@ -51,6 +54,8 @@ class str:
def __mul__(self, other: int) -> Self: ... def __mul__(self, other: int) -> Self: ...
def startswith(self, prefix: Self) -> bool: ... def startswith(self, prefix: Self) -> bool: ...
def __getitem__(self, item: int | slice) -> Self: ... def __getitem__(self, item: int | slice) -> Self: ...
def isspace(self) -> bool: ...
def __contains__(self, item: Self) -> bool: ...
assert len("a") assert len("a")
...@@ -120,6 +125,8 @@ def print(*args) -> None: ... ...@@ -120,6 +125,8 @@ def print(*args) -> None: ...
assert print assert print
def input(prompt: str = "") -> str:
...
def range(*args) -> Iterator[int]: ... def range(*args) -> Iterator[int]: ...
...@@ -159,3 +166,8 @@ assert __test_type().test_opt(5) ...@@ -159,3 +166,8 @@ assert __test_type().test_opt(5)
assert __test_type().test_opt(5, 6) assert __test_type().test_opt(5, 6)
assert not __test_type().test_opt(5, 6, 7) assert not __test_type().test_opt(5, 6, 7)
assert not __test_type().test_opt() assert not __test_type().test_opt()
def exit(code: int | None = None) -> None: ...
class Exception:
def __init__(self, message: str) -> None: ...
\ No newline at end of file
# coding: utf-8
Enum: BuiltinFeature["Enum"]
\ No newline at end of file
import sys import sys
import math import math
from typing import Callable
# def f(x: Callable[[int], int]):
# return x(5)
x = 4
def f():
if True:
next = 5
x = 7
def g():
nonlocal x
x = 6
return 123
# def h(x):
# y = len(x)
# z = x[4]
if __name__ == "__main__": if __name__ == "__main__":
a = [n for n in range(10)] #print(f(lambda n: n + 1)) # todo
b = [x for x in a if x % 2 == 0] print(f())
c = [y * y for y in b]
print(a, b, c)
\ No newline at end of file for i in range(10):
if i > 4:
break
else:
print("else")
\ No newline at end of file
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Callable from typing import Any, Callable, Optional
from enum import Enum from enum import Enum
from itertools import groupby
import operator import operator
import string
@dataclass @dataclass
...@@ -20,8 +18,11 @@ OPERATORS = [ ...@@ -20,8 +18,11 @@ OPERATORS = [
BinOperator("/", 1, operator.truediv) BinOperator("/", 1, operator.truediv)
] ]
# ops_by_priority = [list(it) for _, it in groupby(OPERATORS, lambda op: op.priority)]
ops_by_priority = [list(it) for _, it in groupby(OPERATORS, lambda op: op.priority)] ops_by_priority = [
[OPERATORS[0], OPERATORS[1]],
[OPERATORS[2], OPERATORS[3]]
]
MAX_PRIORITY = len(ops_by_priority) MAX_PRIORITY = len(ops_by_priority)
ops_syms = [op.symbol for op in OPERATORS] ops_syms = [op.symbol for op in OPERATORS]
...@@ -35,7 +36,8 @@ class TokenType(Enum): ...@@ -35,7 +36,8 @@ class TokenType(Enum):
@dataclass @dataclass
class Token: class Token:
type: TokenType type: TokenType
val: Any val: str
num: float
def tokenize(inp: str): def tokenize(inp: str):
...@@ -67,28 +69,30 @@ def tokenize(inp: str): ...@@ -67,28 +69,30 @@ def tokenize(inp: str):
if not has() or peek() not in "0123456789.": if not has() or peek() not in "0123456789.":
break break
return Token(TokenType.NUMBER, float(res) if "." in res else int(res)) return Token(TokenType.NUMBER, res, float(res)) # if "." in res else int(res))
while has(): while has():
skip_spaces() skip_spaces()
next = peek() next = peek()
tok: Token
if next in ops_syms: if next in ops_syms:
tok = Token(TokenType.OPERATION, read()) tok = Token(TokenType.OPERATION, read(), 0)
elif next in "()": elif next in "()":
tok = Token(TokenType.PARENTHESIS, read()) tok = Token(TokenType.PARENTHESIS, read(), 0)
elif next in "0123456789.": elif next in "0123456789.":
tok = read_number() tok = read_number()
else: else:
raise Exception(f"invalid character '{next}'", index) raise Exception("invalid character '{}' at {}".format(next, index))
tokens.append(tok) tokens.append(tok)
return tokens return tokens
def parse(tokens): def parse(tokens: list[Token]):
index = 0 index = 0
def has(): def has():
...@@ -99,25 +103,27 @@ def parse(tokens): ...@@ -99,25 +103,27 @@ def parse(tokens):
raise Exception("expected token, got EOL") raise Exception("expected token, got EOL")
return tokens[index] return tokens[index]
def match(type: TokenType, val: Any = None): def match(type: TokenType, val: Optional[str] = None):
return has() and tokens[index].type == type and (val is None or tokens[index].val == val) return has() and tokens[index].type == type and (val is None or tokens[index].val == val)
def accept(type: TokenType, val: Any = None): def accept(type: TokenType, val: Optional[str] = None):
nonlocal index nonlocal index
if match(type, val): if match(type, val):
index += 1 index += 1
return True return True
return False return False
def expect(type: TokenType, val: Any = None): def expect(type: TokenType, val: Optional[str] = None):
nonlocal index nonlocal index
if match(type, val): if match(type, val):
index += 1 index += 1
return tokens[index - 1] return tokens[index - 1]
if not has(): if not has():
raise Exception(f"expected {type}, got EOL") raise Exception("expected {}, got EOL".format(type))
else: else:
raise Exception(f"expected {type}, got {current().type}") raise Exception("expected {}, got {}".format(type, current().type))
parse_term: Callable[[], None]
def parse_bin(priority=0): def parse_bin(priority=0):
if priority >= MAX_PRIORITY: if priority >= MAX_PRIORITY:
...@@ -137,31 +143,34 @@ def parse(tokens): ...@@ -137,31 +143,34 @@ def parse(tokens):
return left return left
def parse_expr():
return parse_bin()
def parse_term(): def parse_term():
token = current() token = current()
if token.type == TokenType.NUMBER: if token.type == TokenType.NUMBER:
return expect(TokenType.NUMBER).val return expect(TokenType.NUMBER).num
elif accept(TokenType.PARENTHESIS, "("): elif accept(TokenType.PARENTHESIS, "("):
val = parse_expr() val = parse_expr()
expect(TokenType.PARENTHESIS, ")") expect(TokenType.PARENTHESIS, ")")
return val return val
else: else:
raise Exception(f"expected term, got {token.type}") raise Exception("expected term, got {}".format(token.type))
def parse_expr():
return parse_bin()
return parse_expr() return parse_expr()
if __name__ == "__main__": if __name__ == "__main__":
while True: while True:
inp = input("> ") # inp = input("> ")
inp = "2 + 3 * 4"
try: try:
tok = tokenize(inp) tok = tokenize(inp)
res = parse(tok) res = parse(tok)
print(res) print(res)
except Exception as e: except Exception as e:
print(e) # print(e)
pass
print() print()
break
...@@ -42,7 +42,10 @@ if __name__ == "__main__": ...@@ -42,7 +42,10 @@ if __name__ == "__main__":
sum = 0 sum = 0
for i in range(15): for i in range(15):
sum += i sum += i
a = [n for n in range(10)]
b = [x for x in a if x % 2 == 0]
c = [y * y for y in b]
print("C++ " if is_cpp() else "Python", print("C++ " if is_cpp() else "Python",
"res=", 5, ".", True, [4, 5, 6], {7, 8, 9}, [1, 2] + [3, 4], [5, 6] * 3, {1: 7, 9: 3}, 0x55 & 7 == 5, "res=", 5, ".", True, [4, 5, 6], {7, 8, 9}, [1, 2] + [3, 4], [5, 6] * 3, {1: 7, 9: 3}, 0x55 & 7 == 5,
3j, sum) 3j, sum, a, b, c)
print() print()
...@@ -9,7 +9,7 @@ from transpiler.phases.emit_cpp.consts import MAPPINGS ...@@ -9,7 +9,7 @@ from transpiler.phases.emit_cpp.consts import MAPPINGS
from transpiler.phases.typing import TypeVariable from transpiler.phases.typing import TypeVariable
from transpiler.phases.typing.exceptions import UnresolvedTypeVariableError from transpiler.phases.typing.exceptions import UnresolvedTypeVariableError
from transpiler.phases.typing.types import BaseType, TY_INT, TY_BOOL, TY_NONE, Promise, PromiseKind, TY_STR, UserType, \ from transpiler.phases.typing.types import BaseType, TY_INT, TY_BOOL, TY_NONE, Promise, PromiseKind, TY_STR, UserType, \
TypeType, TypeOperator, TY_FLOAT TypeType, TypeOperator, TY_FLOAT, FunctionType
from transpiler.utils import UnsupportedNodeError, highlight from transpiler.utils import UnsupportedNodeError, highlight
...@@ -70,6 +70,12 @@ class NodeVisitor(UniversalVisitor): ...@@ -70,6 +70,12 @@ class NodeVisitor(UniversalVisitor):
yield f"PyObj<decltype({node.name})>" yield f"PyObj<decltype({node.name})>"
elif isinstance(node, TypeType): elif isinstance(node, TypeType):
yield "auto" # TODO yield "auto" # TODO
elif isinstance(node, FunctionType):
yield "std::function<"
yield from self.visit(node.return_type)
yield "("
yield from join(", ", map(self.visit, node.parameters))
yield ")>"
elif isinstance(node, Promise): elif isinstance(node, Promise):
yield "typon::" yield "typon::"
if node.kind == PromiseKind.TASK: if node.kind == PromiseKind.TASK:
...@@ -88,7 +94,7 @@ class NodeVisitor(UniversalVisitor): ...@@ -88,7 +94,7 @@ class NodeVisitor(UniversalVisitor):
yield from self.visit(node.return_type) yield from self.visit(node.return_type)
yield ">" yield ">"
elif isinstance(node, TypeVariable): elif isinstance(node, TypeVariable):
#yield f"TYPEVAR_{node.name}";return # yield f"TYPEVAR_{node.name}";return
raise UnresolvedTypeVariableError(node) raise UnresolvedTypeVariableError(node)
elif isinstance(node, TypeOperator): elif isinstance(node, TypeOperator):
yield "typon::Py" + node.name.title() yield "typon::Py" + node.name.title()
......
...@@ -13,17 +13,17 @@ class ClassVisitor(NodeVisitor): ...@@ -13,17 +13,17 @@ class ClassVisitor(NodeVisitor):
yield f"extern {node.name}_s {node.name};" yield f"extern {node.name}_s {node.name};"
yield f"struct {node.name}_s {{" yield f"struct {node.name}_s {{"
yield "struct type {" yield "struct py_type {"
inner = ClassInnerVisitor(node.inner_scope) inner = ClassInnerVisitor(node.inner_scope)
for stmt in node.body: for stmt in node.body:
yield from inner.visit(stmt) yield from inner.visit(stmt)
yield "template<typename... T> type(T&&... args) {" yield "template<typename... T> py_type(T&&... args) {"
yield "__init__(this, std::forward<T>(args)...);" yield "__init__(this, std::forward<T>(args)...);"
yield "}" yield "}"
yield "type() {}" yield "py_type() {}"
yield "type(const type&) = delete;" yield "py_type(const py_type&) = delete;"
yield "type(type&&) = delete;" yield "py_type(py_type&&) = delete;"
yield "void py_repr(std::ostream &s) const {" yield "void py_repr(std::ostream &s) const {"
yield "s << '{';" yield "s << '{';"
...@@ -42,7 +42,7 @@ class ClassVisitor(NodeVisitor): ...@@ -42,7 +42,7 @@ class ClassVisitor(NodeVisitor):
yield "};" yield "};"
yield "template<typename... T> auto operator()(T&&... args) {" yield "template<typename... T> auto operator()(T&&... args) {"
yield "return pyobj<type>(std::forward<T>(args)...);" yield "return pyobj<py_type>(std::forward<T>(args)...);"
yield "}" yield "}"
# outer = ClassOuterVisitor(node.inner_scope) # outer = ClassOuterVisitor(node.inner_scope)
...@@ -61,6 +61,11 @@ class ClassInnerVisitor(NodeVisitor): ...@@ -61,6 +61,11 @@ class ClassInnerVisitor(NodeVisitor):
yield node.target.id yield node.target.id
yield ";" yield ";"
def visit_Assign(self, node: ast.Assign) -> Iterable[str]:
yield "static constexpr"
from transpiler.phases.emit_cpp.block import BlockVisitor
yield from BlockVisitor(self.scope).visit_Assign(node)
def visit_FunctionDef(self, node: ast.FunctionDef) -> Iterable[str]: def visit_FunctionDef(self, node: ast.FunctionDef) -> Iterable[str]:
# yield "struct {" # yield "struct {"
# yield "type* self;" # yield "type* self;"
......
...@@ -74,6 +74,7 @@ PRECEDENCE_LEVELS = {op: i for i, ops in enumerate(PRECEDENCE) for op in ops} ...@@ -74,6 +74,7 @@ PRECEDENCE_LEVELS = {op: i for i, ops in enumerate(PRECEDENCE) for op in ops}
MAPPINGS = { MAPPINGS = {
"True": "true", "True": "true",
"False": "false", "False": "false",
"None": "nullptr" "None": "nullptr",
"operator": "operator_",
} }
"""Mapping of Python builtin constants to C++ equivalents.""" """Mapping of Python builtin constants to C++ equivalents."""
...@@ -3,7 +3,7 @@ import ast ...@@ -3,7 +3,7 @@ import ast
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import List, Iterable from typing import List, Iterable
from transpiler.phases.typing.types import UserType, FunctionType, Promise from transpiler.phases.typing.types import UserType, FunctionType, Promise, TypeType
from transpiler.phases.utils import make_lnd from transpiler.phases.utils import make_lnd
from transpiler.utils import compare_ast, linenodata from transpiler.utils import compare_ast, linenodata
from transpiler.phases.emit_cpp.consts import SYMBOLS, PRECEDENCE_LEVELS, DUNDER_SYMBOLS from transpiler.phases.emit_cpp.consts import SYMBOLS, PRECEDENCE_LEVELS, DUNDER_SYMBOLS
...@@ -215,11 +215,16 @@ class ExpressionVisitor(NodeVisitor): ...@@ -215,11 +215,16 @@ class ExpressionVisitor(NodeVisitor):
yield ")" yield ")"
def visit_Attribute(self, node: ast.Attribute) -> Iterable[str]: def visit_Attribute(self, node: ast.Attribute) -> Iterable[str]:
if isinstance(node.type, FunctionType) and not isinstance(node.value.type, Promise): use_dot = None
if type(node.value.type) == TypeType:
use_dot = "dots"
elif isinstance(node.type, FunctionType) and not isinstance(node.value.type, Promise):
if node.value.type.resolve().is_reference: if node.value.type.resolve().is_reference:
yield "dotp" use_dot = "dotp"
else: else:
yield "dot" use_dot = "dot"
if use_dot:
yield use_dot
yield "((" yield "(("
yield from self.visit(node.value) yield from self.visit(node.value)
yield "), " yield "), "
......
...@@ -4,7 +4,7 @@ from dataclasses import dataclass ...@@ -4,7 +4,7 @@ from dataclasses import dataclass
from typing import Iterable from typing import Iterable
from transpiler.phases.emit_cpp.consts import SYMBOLS from transpiler.phases.emit_cpp.consts import SYMBOLS
from transpiler.phases.emit_cpp import CoroutineMode from transpiler.phases.emit_cpp import CoroutineMode, FunctionEmissionKind
from transpiler.phases.emit_cpp.block import BlockVisitor from transpiler.phases.emit_cpp.block import BlockVisitor
from transpiler.phases.typing.scope import Scope from transpiler.phases.typing.scope import Scope
from transpiler.phases.utils import PlainBlock from transpiler.phases.utils import PlainBlock
......
...@@ -12,6 +12,7 @@ from transpiler.phases.emit_cpp.class_ import ClassVisitor ...@@ -12,6 +12,7 @@ from transpiler.phases.emit_cpp.class_ import ClassVisitor
from transpiler.phases.emit_cpp.function import FunctionVisitor from transpiler.phases.emit_cpp.function import FunctionVisitor
from transpiler.utils import compare_ast, highlight from transpiler.utils import compare_ast, highlight
IGNORED_IMPORTS = {"typon", "typing", "__future__", "dataclasses", "enum"}
# noinspection PyPep8Naming # noinspection PyPep8Naming
@dataclass @dataclass
...@@ -20,7 +21,7 @@ class ModuleVisitor(BlockVisitor): ...@@ -20,7 +21,7 @@ class ModuleVisitor(BlockVisitor):
def visit_Import(self, node: ast.Import) -> Iterable[str]: def visit_Import(self, node: ast.Import) -> Iterable[str]:
TB = f"emitting C++ code for {highlight(node)}" TB = f"emitting C++ code for {highlight(node)}"
for alias in node.names: for alias in node.names:
concrete = alias.asname or alias.name concrete = self.fix_name(alias.asname or alias.name)
if alias.module_obj.is_python: if alias.module_obj.is_python:
yield f"namespace py_{concrete} {{" yield f"namespace py_{concrete} {{"
yield f"struct {concrete}_t {{" yield f"struct {concrete}_t {{"
...@@ -33,7 +34,7 @@ class ModuleVisitor(BlockVisitor): ...@@ -33,7 +34,7 @@ class ModuleVisitor(BlockVisitor):
yield f"auto& get_all() {{ return all; }}" yield f"auto& get_all() {{ return all; }}"
yield "}" yield "}"
yield f'auto& {concrete} = py_{concrete}::get_all();' yield f'auto& {concrete} = py_{concrete}::get_all();'
elif alias.name in {"typon", "typing", "__future__"}: elif alias.name in IGNORED_IMPORTS:
yield "" yield ""
else: else:
yield from self.import_module(alias.name) yield from self.import_module(alias.name)
...@@ -70,7 +71,7 @@ class ModuleVisitor(BlockVisitor): ...@@ -70,7 +71,7 @@ class ModuleVisitor(BlockVisitor):
yield f"}} {alias};" yield f"}} {alias};"
def visit_ImportFrom(self, node: ast.ImportFrom) -> Iterable[str]: def visit_ImportFrom(self, node: ast.ImportFrom) -> Iterable[str]:
if node.module in {"typon", "typing", "__future__"}: if node.module in IGNORED_IMPORTS:
yield "" yield ""
elif node.module_obj.is_python: elif node.module_obj.is_python:
for alias in node.names: for alias in node.names:
......
...@@ -6,7 +6,7 @@ from dataclasses import dataclass ...@@ -6,7 +6,7 @@ from dataclasses import dataclass
from transpiler.exceptions import CompileError from transpiler.exceptions import CompileError
from transpiler.utils import highlight, linenodata from transpiler.utils import highlight, linenodata
from transpiler.phases.typing import make_mod_decl from transpiler.phases.typing import make_mod_decl
from transpiler.phases.typing.common import ScoperVisitor, get_iter, get_next from transpiler.phases.typing.common import ScoperVisitor, get_iter, get_next, is_builtin
from transpiler.phases.typing.expr import ScoperExprVisitor, DUNDER from transpiler.phases.typing.expr import ScoperExprVisitor, DUNDER
from transpiler.phases.typing.class_ import ScoperClassVisitor from transpiler.phases.typing.class_ import ScoperClassVisitor
from transpiler.phases.typing.scope import VarDecl, VarKind, ScopeKind, Scope from transpiler.phases.typing.scope import VarDecl, VarKind, ScopeKind, Scope
...@@ -19,9 +19,6 @@ from transpiler.phases.utils import PlainBlock, AnnotationName ...@@ -19,9 +19,6 @@ from transpiler.phases.utils import PlainBlock, AnnotationName
class ScoperBlockVisitor(ScoperVisitor): class ScoperBlockVisitor(ScoperVisitor):
stdlib: bool = False stdlib: bool = False
def expr(self) -> ScoperExprVisitor:
return ScoperExprVisitor(self.scope, self.root_decls)
def visit_Pass(self, node: ast.Pass): def visit_Pass(self, node: ast.Pass):
pass pass
...@@ -107,7 +104,7 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -107,7 +104,7 @@ class ScoperBlockVisitor(ScoperVisitor):
if target.id == "_": if target.id == "_":
return False return False
target.type = decl_val target.type = decl_val
if vdecl := self.scope.get(target.id): if vdecl := self.scope.get(target.id, {VarKind.LOCAL, VarKind.GLOBAL, VarKind.NONLOCAL}, restrict_function=True):
TB = f"unifying existing variable {highlight(target.id)} of type {highlight(vdecl.type)} with assigned value {highlight(decl_val)}" TB = f"unifying existing variable {highlight(target.id)} of type {highlight(vdecl.type)} with assigned value {highlight(decl_val)}"
vdecl.type.unify(decl_val) vdecl.type.unify(decl_val)
return False return False
...@@ -115,6 +112,7 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -115,6 +112,7 @@ class ScoperBlockVisitor(ScoperVisitor):
self.scope.vars[target.id] = VarDecl(VarKind.LOCAL, decl_val) self.scope.vars[target.id] = VarDecl(VarKind.LOCAL, decl_val)
if self.scope.kind == ScopeKind.FUNCTION_INNER: if self.scope.kind == ScopeKind.FUNCTION_INNER:
self.root_decls[target.id] = VarDecl(VarKind.OUTER_DECL, decl_val) self.root_decls[target.id] = VarDecl(VarKind.OUTER_DECL, decl_val)
return False
return True return True
elif isinstance(target, ast.Tuple): elif isinstance(target, ast.Tuple):
if not isinstance(decl_val, TupleType): if not isinstance(decl_val, TupleType):
...@@ -180,7 +178,7 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -180,7 +178,7 @@ class ScoperBlockVisitor(ScoperVisitor):
visitor.visit_block(node.body) visitor.visit_block(node.body)
for deco in node.decorator_list: for deco in node.decorator_list:
deco = self.expr().visit(deco) deco = self.expr().visit(deco)
if isinstance(deco, BuiltinFeature) and deco.val == "dataclass": if is_builtin(deco, "dataclass"):
# init_type = FunctionType([cttype, *cttype.members.values()], TypeVariable()) # init_type = FunctionType([cttype, *cttype.members.values()], TypeVariable())
# cttype.methods["__init__"] = init_type # cttype.methods["__init__"] = init_type
lnd = linenodata(node) lnd = linenodata(node)
...@@ -210,6 +208,13 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -210,6 +208,13 @@ class ScoperBlockVisitor(ScoperVisitor):
visitor.visit_function_definition(init_method, rtype) visitor.visit_function_definition(init_method, rtype)
else: else:
raise NotImplementedError(deco) raise NotImplementedError(deco)
for base in node.bases:
base = self.expr().visit(base)
if is_builtin(base, "Enum"):
for k in ctype.members:
ctype.members[k] = ctype
else:
raise NotImplementedError(base)
def visit_If(self, node: ast.If): def visit_If(self, node: ast.If):
scope = self.scope.child(ScopeKind.FUNCTION_INNER) scope = self.scope.child(ScopeKind.FUNCTION_INNER)
...@@ -270,8 +275,8 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -270,8 +275,8 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_Return(self, node: ast.Return): def visit_Return(self, node: ast.Return):
fct = self.scope.function fct = self.scope.function
if fct is None: if fct is None:
from transpiler.phases.typing.exceptions import ReturnOutsideFunctionError from transpiler.phases.typing.exceptions import OutsideFunctionError
raise ReturnOutsideFunctionError() raise OutsideFunctionError()
ftype = fct.obj_type ftype = fct.obj_type
assert isinstance(ftype, FunctionType) assert isinstance(ftype, FunctionType)
vtype = self.expr().visit(node.value) if node.value else TY_NONE vtype = self.expr().visit(node.value) if node.value else TY_NONE
...@@ -284,6 +289,16 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -284,6 +289,16 @@ class ScoperBlockVisitor(ScoperVisitor):
if name not in self.scope.global_scope.vars: if name not in self.scope.global_scope.vars:
self.scope.global_scope.vars[name] = VarDecl(VarKind.LOCAL, None) self.scope.global_scope.vars[name] = VarDecl(VarKind.LOCAL, None)
def visit_Nonlocal(self, node: ast.Global):
fct = self.scope.function
if fct is None:
from transpiler.phases.typing.exceptions import OutsideFunctionError
raise OutsideFunctionError()
for name in node.names:
fct.vars[name] = VarDecl(VarKind.NONLOCAL, None)
if name not in fct.parent.vars:
fct.parent.vars[name] = VarDecl(VarKind.LOCAL, None)
def visit_AugAssign(self, node: ast.AugAssign): def visit_AugAssign(self, node: ast.AugAssign):
target, value = map(self.get_type, (node.target, node.value)) target, value = map(self.get_type, (node.target, node.value))
try: try:
......
...@@ -17,6 +17,14 @@ class ScoperClassVisitor(ScoperVisitor): ...@@ -17,6 +17,14 @@ class ScoperClassVisitor(ScoperVisitor):
assert isinstance(node.target, ast.Name) assert isinstance(node.target, ast.Name)
self.scope.obj_type.members[node.target.id] = self.visit_annotation(node.annotation) self.scope.obj_type.members[node.target.id] = self.visit_annotation(node.annotation)
def visit_Assign(self, node: ast.Assign):
assert len(node.targets) == 1, "Class field should be assigned to only once"
assert isinstance(node.targets[0], ast.Name)
node.is_declare = True
valtype = self.expr().visit(node.value)
node.targets[0].type = valtype
self.scope.obj_type.members[node.targets[0].id] = valtype
def visit_FunctionDef(self, node: ast.FunctionDef): def visit_FunctionDef(self, node: ast.FunctionDef):
from transpiler.phases.typing.block import ScoperBlockVisitor from transpiler.phases.typing.block import ScoperBlockVisitor
# TODO: maybe merge this code with ScoperBlockVisitor.visit_FunctionDef # TODO: maybe merge this code with ScoperBlockVisitor.visit_FunctionDef
......
...@@ -271,9 +271,9 @@ class NotIteratorError(CompileError): ...@@ -271,9 +271,9 @@ class NotIteratorError(CompileError):
""" """
@dataclass @dataclass
class ReturnOutsideFunctionError(CompileError): class OutsideFunctionError(CompileError):
def __str__(self) -> str: def __str__(self) -> str:
return f"{highlight('return')} cannot be used outside of a function" return f"{highlight('return')} and {highlight('nonlocal')} cannot be used outside of a function"
def detail(self, last_node: ast.AST = None) -> str: def detail(self, last_node: ast.AST = None) -> str:
return "" return ""
......
...@@ -105,6 +105,11 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -105,6 +105,11 @@ class ScoperExprVisitor(ScoperVisitor):
ftype = self.visit(node.func) ftype = self.visit(node.func)
if ftype.typevars: if ftype.typevars:
ftype = ftype.gen_sub(None, {v.name: TypeVariable(v.name) for v in ftype.typevars}) ftype = ftype.gen_sub(None, {v.name: TypeVariable(v.name) for v in ftype.typevars})
from transpiler.exceptions import CompileError
try:
argtypes = [self.visit(arg) for arg in node.args]
except CompileError as e:
pass
rtype = self.visit_function_call(ftype, [self.visit(arg) for arg in node.args]) rtype = self.visit_function_call(ftype, [self.visit(arg) for arg in node.args])
actual = rtype actual = rtype
node.is_await = False node.is_await = False
...@@ -193,14 +198,20 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -193,14 +198,20 @@ class ScoperExprVisitor(ScoperVisitor):
return self.visit_getattr(p, name) return self.visit_getattr(p, name)
except MissingAttributeError as e: except MissingAttributeError as e:
pass pass
# class MemberProtocol(TypeOperator):
# pass
raise MissingAttributeError(ltype, name) raise MissingAttributeError(ltype, name)
def visit_List(self, node: ast.List) -> BaseType: def visit_List(self, node: ast.List) -> BaseType:
if not node.elts: if not node.elts:
return PyList(TypeVariable()) return PyList(TypeVariable())
elems = [self.visit(e) for e in node.elts] elems = [self.visit(e) for e in node.elts]
if len(set(elems)) != 1: first, *rest = elems
raise NotImplementedError("List with different types not handled yet") for e in rest:
try:
first.unify(e)
except:
raise NotImplementedError(f"List with different types not handled yet: {', '.join(map(str, elems))}")
return PyList(elems[0]) return PyList(elems[0])
def visit_Set(self, node: ast.Set) -> BaseType: def visit_Set(self, node: ast.Set) -> BaseType:
......
...@@ -73,6 +73,8 @@ class Scope: ...@@ -73,6 +73,8 @@ class Scope:
def child(self, kind: ScopeKind): def child(self, kind: ScopeKind):
res = Scope(self, kind, self.function, self.global_scope) res = Scope(self, kind, self.function, self.global_scope)
if kind == ScopeKind.GLOBAL:
res.global_scope = res
self.children.append(res) self.children.append(res)
return res return res
...@@ -80,12 +82,18 @@ class Scope: ...@@ -80,12 +82,18 @@ class Scope:
"""Declares a local variable""" """Declares a local variable"""
self.vars[name] = VarDecl(VarKind.LOCAL, type) self.vars[name] = VarDecl(VarKind.LOCAL, type)
def get(self, name: str, kind: VarKind = VarKind.LOCAL) -> Optional[VarDecl]: def get(self, name: str, kind: VarKind | set[VarKind] = VarKind.LOCAL, restrict_function: bool = False) -> Optional[VarDecl]:
""" """
Gets the variable declaration of a variable in the current scope or any parent scope. Gets the variable declaration of a variable in the current scope or any parent scope.
""" """
if (res := self.vars.get(name)) and res.kind == kind: if type(kind) is VarKind:
kind = {kind}
if (res := self.vars.get(name)) and res.kind in kind:
if res.kind == VarKind.GLOBAL:
return self.global_scope.get(name, kind)
elif res.kind == VarKind.NONLOCAL:
return self.function.parent.get(name, VarKind.LOCAL, True)
return res return res
if self.parent is not None: if self.parent is not None and not (self.kind == ScopeKind.FUNCTION and restrict_function):
return self.parent.get(name, kind) return self.parent.get(name, kind, restrict_function)
return None return None
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