Commit 6dc348c4 authored by Tom Niget's avatar Tom Niget

Add slices

parent ec94fcf5
...@@ -128,6 +128,7 @@ public: ...@@ -128,6 +128,7 @@ public:
#include "builtins/print.hpp" #include "builtins/print.hpp"
#include "builtins/range.hpp" #include "builtins/range.hpp"
#include "builtins/set.hpp" #include "builtins/set.hpp"
#include "builtins/slice.hpp"
#include "builtins/str.hpp" #include "builtins/str.hpp"
struct { struct {
......
//
// Created by Tom on 02/08/2023.
//
#ifndef TYPON_SLICE_HPP
#define TYPON_SLICE_HPP
#include <optional>
#include <utility>
#include <Python.h>
#include <stdint.h>
struct PySlice {
PySlice() = default;
PySlice(const PySlice &) = default;
PySlice(PySlice &&) = default;
PySlice &operator=(const PySlice &) = default;
PySlice &operator=(PySlice &&) = default;
PySlice(std::optional<ssize_t> start, std::optional<ssize_t> stop, std::optional<ssize_t> step) : start(start), stop(stop), step(step) {
if (step == 0) {
throw std::runtime_error("slice step cannot be zero");
}
}
std::optional<ssize_t> start = 0;
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;
}
if (this->stop == std::nullopt) {
res.stop = res.step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
}
std::cout << "adjust " << this->start << ' ' << this->stop << ' ' << this->step << std::endl;
auto len = PySlice_AdjustIndices(seq_length, &res.start, &res.stop, res.step);
return {len, res};
}
};
#endif // TYPON_SLICE_HPP
...@@ -12,6 +12,7 @@ using namespace std::literals; ...@@ -12,6 +12,7 @@ using namespace std::literals;
#include "bytes.hpp" #include "bytes.hpp"
#include "print.hpp" #include "print.hpp"
#include "slice.hpp"
// #include <format> // #include <format>
#include <fmt/format.h> #include <fmt/format.h>
...@@ -21,6 +22,7 @@ public: ...@@ -21,6 +22,7 @@ public:
PyStr(const std::string &s) : std::string(s) {} PyStr(const std::string &s) : std::string(s) {}
PyStr(std::string &&s) : std::string(std::move(s)) {} PyStr(std::string &&s) : std::string(std::move(s)) {}
constexpr PyStr(const char *s, size_t count) : std::string(s, count) {} constexpr PyStr(const char *s, size_t count) : std::string(s, count) {}
constexpr PyStr(size_t count, char ch) : std::string(count, ch) {}
template<typename... Args> template<typename... Args>
PyStr(Args&&... args) : std::string(std::forward<Args>(args)...) {} PyStr(Args&&... args) : std::string(std::forward<Args>(args)...) {}
...@@ -36,6 +38,48 @@ public: ...@@ -36,6 +38,48 @@ public:
} }
bool startswith(const std::string &s) const { return this->starts_with(s); } bool startswith(const std::string &s) const { return this->starts_with(s); }
PyStr operator[](PySlice slice) const {
auto [len, new_slice] = slice.adjust_indices(this->size());
PyStr result;
result.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.push_back(this->char_at(i));
}
}
} else {
if (new_slice.step < 0) {
for (auto i = new_slice.start; i > new_slice.stop;
i += new_slice.step) {
result.push_back(this->char_at(i));
}
}
}
return result;
}
PyStr operator[](ssize_t index) const {
if (index < 0) {
index += this->size();
}
return PyStr(1, std::string::operator[](index));
}
char char_at(ssize_t index) const {
if (index < 0) {
index += this->size();
}
return this->begin()[index];
}
}; };
inline constexpr PyStr operator""_ps(const char *s, size_t len) noexcept { inline constexpr PyStr operator""_ps(const char *s, size_t len) noexcept {
......
...@@ -9,11 +9,17 @@ class int: ...@@ -9,11 +9,17 @@ class int:
def __and__(self, other: Self) -> Self: ... def __and__(self, other: Self) -> Self: ...
def __neg__(self) -> Self: ...
def __init__(self, x: str) -> None: ...
assert int.__add__ assert int.__add__
U = TypeVar("U") U = TypeVar("U")
V = TypeVar("V") V = TypeVar("V")
class slice:
pass
class HasLen(Protocol): class HasLen(Protocol):
def __len__(self) -> int: ... def __len__(self) -> int: ...
...@@ -37,6 +43,7 @@ class str: ...@@ -37,6 +43,7 @@ class str:
def __add__(self, other: Self) -> Self: ... def __add__(self, other: Self) -> Self: ...
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: ...
assert len("a") assert len("a")
......
...@@ -11,7 +11,10 @@ class socket: ...@@ -11,7 +11,10 @@ class socket:
def setsockopt(self, level: int, option: int, value: int) -> None: def setsockopt(self, level: int, option: int, value: int) -> None:
pass pass
def bind(self, address: tuple[str, int]) -> None: def bind(self, address: tuple[str, int] | str) -> None:
pass
def connect(self, address: tuple[str, int] | str) -> None:
pass pass
def listen(self, backlog: int) -> None: def listen(self, backlog: int) -> None:
...@@ -31,3 +34,9 @@ class socket: ...@@ -31,3 +34,9 @@ class socket:
def close(self) -> Task[None]: def close(self) -> Task[None]:
pass pass
def getaddrinfo(host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> \
Task[list[tuple[int, int, int, str, tuple[str, int] | str]]]:
pass
AF_UNIX: int
\ No newline at end of file
...@@ -43,13 +43,14 @@ def run_tests(): ...@@ -43,13 +43,14 @@ def run_tests():
continue continue
name_bin = path.with_suffix('').as_posix() name_bin = path.with_suffix('').as_posix()
commands = [ commands = [
f"bash -c 'PYTHONPATH=stdlib python3 ./{path.as_posix()}'", f'bash -c "PYTHONPATH=stdlib python3 ./{path.as_posix()}"',
] ]
if alt := environ.get("ALT_RUNNER"): if alt := environ.get("ALT_RUNNER"):
commands.append(alt.format(name_bin=name_bin, name_cpp_posix=name_cpp.as_posix())) commands.append(alt.format(name_bin=name_bin, name_cpp_posix=name_cpp.as_posix()))
else: else:
print("no ALT_RUNNER") print("no ALT_RUNNER")
for cmd in commands: for cmd in commands:
print(cmd)
if system(cmd) != 0: if system(cmd) != 0:
print(f"Error running command: {cmd}") print(f"Error running command: {cmd}")
break break
......
import sys import sys
import math import math
x = [6]
if __name__ == "__main__": if __name__ == "__main__":
pass a = "hello, world"
\ No newline at end of file print(a, a[::-1])
\ No newline at end of file
""" import sys
import socket
def sense(self):
host = self.getConfig('host')
port = self.getConfig('port')
path = self.getConfig('pathname')
abstract = self.getConfig('abstract')
if host: if __name__ == "__main__":
if path or abstract or not port: s: socket.socket
self.logger.error(ADDRESS_USAGE) if len(sys.argv) == 3:
return host = sys.argv[1]
# type of port must be int or str, unicode is not accepted. port = sys.argv[2]
family, _, _, _, addr = socket.getaddrinfo(host, int(port))[0] family, _, _, _, addr = socket.getaddrinfo(host, int(port))[0]
else: s = socket.socket(family, socket.SOCK_STREAM)
if bool(path) == bool(abstract):
self.logger.error(ADDRESS_USAGE)
return
family = socket.AF_UNIX
addr = path or '\0' + abstract
s = socket.socket(family, socket.SOCK_STREAM)
try:
s.connect(addr) s.connect(addr)
except socket.error as e: elif len(sys.argv) == 2:
self.logger.error('%s: %s', type(e).__name__, e) path = sys.argv[1]
else: addr: str
self.logger.info("socket connection OK %r", addr) if path.startswith('@'):
finally: addr = '\0' + path[1:]
s.close() else:
addr = path
""" s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(addr)
import sys else:
print("Usage:", sys.argv[0] , "host port | path | @abstract")
# prog host port sys.exit(1)
# prog path
# prog @abstract
if __name__ == "__main__": s.close()
pass \ No newline at end of file
\ No newline at end of file
...@@ -74,6 +74,11 @@ class ExpressionVisitor(NodeVisitor): ...@@ -74,6 +74,11 @@ class ExpressionVisitor(NodeVisitor):
else: else:
raise NotImplementedError(node, type(node)) raise NotImplementedError(node, type(node))
def visit_Slice(self, node: ast.Slice) -> Iterable[str]:
yield "PySlice("
yield from join(", ", (self.visit(x or ast.Constant(value=None)) for x in (node.lower, node.upper, node.step)))
yield ")"
def visit_Name(self, node: ast.Name) -> Iterable[str]: def visit_Name(self, node: ast.Name) -> Iterable[str]:
res = self.fix_name(node.id) res = self.fix_name(node.id)
if self.scope.function and (decl := self.scope.get(res)) and decl.type is self.scope.function.obj_type: if self.scope.function and (decl := self.scope.get(res)) and decl.type is self.scope.function.obj_type:
......
...@@ -5,7 +5,7 @@ from transpiler.phases.typing.scope import VarKind, VarDecl, ScopeKind, Scope ...@@ -5,7 +5,7 @@ from transpiler.phases.typing.scope import VarKind, VarDecl, ScopeKind, Scope
from transpiler.phases.typing.stdlib import PRELUDE, StdlibVisitor from transpiler.phases.typing.stdlib import PRELUDE, StdlibVisitor
from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_COMPLEX, TY_NONE, FunctionType, \ from transpiler.phases.typing.types import TY_TYPE, TY_INT, TY_STR, TY_BOOL, TY_COMPLEX, TY_NONE, FunctionType, \
TypeVariable, CppType, PyList, TypeType, Forked, Task, Future, PyIterator, TupleType, TypeOperator, BaseType, \ TypeVariable, CppType, PyList, TypeType, Forked, Task, Future, PyIterator, TupleType, TypeOperator, BaseType, \
ModuleType, TY_BYTES, TY_FLOAT, PyDict ModuleType, TY_BYTES, TY_FLOAT, PyDict, TY_SLICE
PRELUDE.vars.update({ PRELUDE.vars.update({
# "int": VarDecl(VarKind.LOCAL, TY_TYPE, TY_INT), # "int": VarDecl(VarKind.LOCAL, TY_TYPE, TY_INT),
...@@ -34,6 +34,7 @@ PRELUDE.vars.update({ ...@@ -34,6 +34,7 @@ PRELUDE.vars.update({
"Future": VarDecl(VarKind.LOCAL, TypeType(Future)), "Future": VarDecl(VarKind.LOCAL, TypeType(Future)),
"Iterator": VarDecl(VarKind.LOCAL, TypeType(PyIterator)), "Iterator": VarDecl(VarKind.LOCAL, TypeType(PyIterator)),
"tuple": VarDecl(VarKind.LOCAL, TypeType(TupleType)), "tuple": VarDecl(VarKind.LOCAL, TypeType(TupleType)),
"slice": VarDecl(VarKind.LOCAL, TypeType(TY_SLICE))
}) })
typon_std = Path(__file__).parent.parent.parent.parent / "stdlib" typon_std = Path(__file__).parent.parent.parent.parent / "stdlib"
......
...@@ -4,7 +4,7 @@ from dataclasses import dataclass, field ...@@ -4,7 +4,7 @@ from dataclasses import dataclass, field
from typing import Optional, List from typing import Optional, List
from transpiler.phases.typing.scope import Scope from transpiler.phases.typing.scope import Scope
from transpiler.phases.typing.types import BaseType, TY_NONE, TypeType, TY_SELF, TypeVariable from transpiler.phases.typing.types import BaseType, TY_NONE, TypeType, TY_SELF, TypeVariable, UnionType
from transpiler.phases.utils import NodeVisitorSeq from transpiler.phases.utils import NodeVisitorSeq
...@@ -60,3 +60,8 @@ class TypeAnnotationVisitor(NodeVisitorSeq): ...@@ -60,3 +60,8 @@ class TypeAnnotationVisitor(NodeVisitorSeq):
res = left.members[node.attr] res = left.members[node.attr]
assert isinstance(res, TypeType) assert isinstance(res, TypeType)
return res.type_object return res.type_object
def visit_BinOp(self, node: ast.BinOp) -> BaseType:
if isinstance(node.op, ast.BitOr):
return UnionType(self.visit(node.left), self.visit(node.right))
raise NotImplementedError(node.op)
...@@ -6,7 +6,8 @@ from typing import List ...@@ -6,7 +6,8 @@ from typing import List
from transpiler.phases.typing import ScopeKind, VarDecl, VarKind from transpiler.phases.typing import ScopeKind, VarDecl, VarKind
from transpiler.phases.typing.common import ScoperVisitor from transpiler.phases.typing.common import ScoperVisitor
from transpiler.phases.typing.types import BaseType, TupleType, TY_STR, TY_BOOL, TY_INT, \ from transpiler.phases.typing.types import BaseType, TupleType, TY_STR, TY_BOOL, TY_INT, \
TY_COMPLEX, TY_NONE, FunctionType, PyList, TypeVariable, PySet, TypeType, PyDict, Promise, PromiseKind, UserType TY_COMPLEX, TY_NONE, FunctionType, PyList, TypeVariable, PySet, TypeType, PyDict, Promise, PromiseKind, UserType, \
TY_SLICE
DUNDER = { DUNDER = {
ast.Eq: "eq", ast.Eq: "eq",
...@@ -45,6 +46,13 @@ class ScoperExprVisitor(ScoperVisitor): ...@@ -45,6 +46,13 @@ class ScoperExprVisitor(ScoperVisitor):
def visit_Tuple(self, node: ast.Tuple) -> BaseType: def visit_Tuple(self, node: ast.Tuple) -> BaseType:
return TupleType(*[self.visit(e) for e in node.elts]) return TupleType(*[self.visit(e) for e in node.elts])
def visit_Slice(self, node: ast.Slice) -> BaseType:
for n in ("lower", "upper", "step"):
if arg := getattr(node, n):
self.visit(arg).unify(TY_INT)
return TY_SLICE
def visit_Yield(self, node: ast.Yield) -> BaseType: def visit_Yield(self, node: ast.Yield) -> BaseType:
ytype = self.visit(node.value) ytype = self.visit(node.value)
......
...@@ -334,6 +334,7 @@ TY_NONE = TypeOperator.make_type("NoneType") ...@@ -334,6 +334,7 @@ TY_NONE = TypeOperator.make_type("NoneType")
TY_VARARG = TypeOperator.make_type("vararg") TY_VARARG = TypeOperator.make_type("vararg")
TY_SELF = TypeOperator.make_type("Self") TY_SELF = TypeOperator.make_type("Self")
TY_SELF.gen_sub = lambda this, typevars, _: this TY_SELF.gen_sub = lambda this, typevars, _: this
TY_SLICE = TypeOperator.make_type("slice")
class PyList(TypeOperator): class PyList(TypeOperator):
...@@ -446,3 +447,8 @@ class UserType(TypeOperator): ...@@ -446,3 +447,8 @@ class UserType(TypeOperator):
if type(self) != type(other): if type(self) != type(other):
from transpiler.phases.typing.exceptions import TypeMismatchError, TypeMismatchKind from transpiler.phases.typing.exceptions import TypeMismatchError, TypeMismatchKind
raise TypeMismatchError(self, other, TypeMismatchKind.DIFFERENT_TYPE) raise TypeMismatchError(self, other, TypeMismatchKind.DIFFERENT_TYPE)
class UnionType(TypeOperator):
def __init__(self, *args: List[BaseType]):
super().__init__(args, "Union")
self.parents.extend(args)
\ 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