Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
typon
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Tom Niget
typon
Commits
31cd80fe
Commit
31cd80fe
authored
Jun 13, 2023
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Started implementing builtin types PyBytes, PyStr, Socket
parent
4136d4cf
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
275 additions
and
37 deletions
+275
-37
rt/include/python/builtins.hpp
rt/include/python/builtins.hpp
+11
-0
rt/include/python/builtins/bytes.hpp
rt/include/python/builtins/bytes.hpp
+24
-0
rt/include/python/builtins/list.hpp
rt/include/python/builtins/list.hpp
+4
-1
rt/include/python/builtins/str.hpp
rt/include/python/builtins/str.hpp
+27
-2
rt/include/python/socket.hpp
rt/include/python/socket.hpp
+65
-0
rt/include/typon/scheduler.hpp
rt/include/typon/scheduler.hpp
+2
-2
trans/stdlib/__init__.py
trans/stdlib/__init__.py
+12
-3
trans/stdlib/socket.py
trans/stdlib/socket.py
+33
-0
trans/tests/a_a_a_webserver.py
trans/tests/a_a_a_webserver.py
+51
-0
trans/tests/b_webserver.py
trans/tests/b_webserver.py
+0
-10
trans/transpiler/phases/emit_cpp/__init__.py
trans/transpiler/phases/emit_cpp/__init__.py
+4
-2
trans/transpiler/phases/emit_cpp/block.py
trans/transpiler/phases/emit_cpp/block.py
+4
-1
trans/transpiler/phases/typing/block.py
trans/transpiler/phases/typing/block.py
+5
-2
trans/transpiler/phases/typing/expr.py
trans/transpiler/phases/typing/expr.py
+7
-5
trans/transpiler/phases/typing/stdlib.py
trans/transpiler/phases/typing/stdlib.py
+4
-1
trans/transpiler/phases/typing/types.py
trans/transpiler/phases/typing/types.py
+22
-8
No files found.
rt/include/python/builtins.hpp
View file @
31cd80fe
...
...
@@ -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
>
...
...
rt/include/python/builtins/bytes.hpp
0 → 100644
View file @
31cd80fe
//
// 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
rt/include/python/builtins/list.hpp
View file @
31cd80fe
...
...
@@ -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
{
...
...
rt/include/python/builtins/str.hpp
View file @
31cd80fe
...
...
@@ -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
;
...
...
rt/include/python/socket.hpp
0 → 100644
View file @
31cd80fe
//
// 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
rt/include/typon/scheduler.hpp
View file @
31cd80fe
...
...
@@ -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
;
...
...
trans/stdlib/__init__.py
View file @
31cd80fe
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
)
->
T
uple
[
U
,
V
]:
def
identity_2
(
x
:
U
,
y
:
V
)
->
t
uple
[
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
]:
...
...
...
trans/stdlib/socket.py
0 → 100644
View file @
31cd80fe
# 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
trans/tests/a_a_a_webserver.py
0 → 100644
View file @
31cd80fe
# 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
trans/tests/b_webserver.py
deleted
100644 → 0
View file @
4136d4cf
# 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
trans/transpiler/phases/emit_cpp/__init__.py
View file @
31cd80fe
...
...
@@ -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
)
...
...
trans/transpiler/phases/emit_cpp/block.py
View file @
31cd80fe
...
...
@@ -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):
...
...
trans/transpiler/phases/typing/block.py
View file @
31cd80fe
...
...
@@ -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
)
...
...
trans/transpiler/phases/typing/expr.py
View file @
31cd80fe
...
...
@@ -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
}
"
)
...
...
trans/transpiler/phases/typing/stdlib.py
View file @
31cd80fe
...
...
@@ -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
:
...
...
trans/transpiler/phases/typing/types.py
View file @
31cd80fe
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment