Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
typon-compiler
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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
typon
typon-compiler
Commits
b738512a
Commit
b738512a
authored
Feb 28, 2024
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Builtin things work
parent
85f54768
Changes
26
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
696 additions
and
446 deletions
+696
-446
.gitignore
.gitignore
+2
-1
typon/include/python/basedef.hpp
typon/include/python/basedef.hpp
+2
-0
typon/include/python/builtins.hpp
typon/include/python/builtins.hpp
+31
-8
typon/include/python/builtins/int.hpp
typon/include/python/builtins/int.hpp
+134
-0
typon/include/python/builtins/print.hpp
typon/include/python/builtins/print.hpp
+3
-2
typon/include/python/builtins/range.hpp
typon/include/python/builtins/range.hpp
+5
-5
typon/include/python/referencemodel.hpp
typon/include/python/referencemodel.hpp
+79
-5
typon/runtime
typon/runtime
+1
-1
typon/trans/stdlib/builtins_.py
typon/trans/stdlib/builtins_.py
+6
-2
typon/trans/stdlib/typing_.py
typon/trans/stdlib/typing_.py
+2
-1
typon/trans/test_runner.py
typon/trans/test_runner.py
+3
-3
typon/trans/tests/builtins_test.py
typon/trans/tests/builtins_test.py
+27
-22
typon/trans/transpiler/error_display.py
typon/trans/transpiler/error_display.py
+41
-32
typon/trans/transpiler/phases/desugar_op/__init__.py
typon/trans/transpiler/phases/desugar_op/__init__.py
+17
-12
typon/trans/transpiler/phases/emit_cpp/class_.py
typon/trans/transpiler/phases/emit_cpp/class_.py
+2
-1
typon/trans/transpiler/phases/emit_cpp/expr.py
typon/trans/transpiler/phases/emit_cpp/expr.py
+86
-32
typon/trans/transpiler/phases/emit_cpp/function.py
typon/trans/transpiler/phases/emit_cpp/function.py
+56
-27
typon/trans/transpiler/phases/emit_cpp/visitors.py
typon/trans/transpiler/phases/emit_cpp/visitors.py
+17
-3
typon/trans/transpiler/phases/typing/block.py
typon/trans/transpiler/phases/typing/block.py
+51
-197
typon/trans/transpiler/phases/typing/class_.py
typon/trans/transpiler/phases/typing/class_.py
+35
-35
typon/trans/transpiler/phases/typing/common.py
typon/trans/transpiler/phases/typing/common.py
+30
-19
typon/trans/transpiler/phases/typing/expr.py
typon/trans/transpiler/phases/typing/expr.py
+18
-8
typon/trans/transpiler/phases/typing/modules.py
typon/trans/transpiler/phases/typing/modules.py
+27
-22
typon/trans/transpiler/phases/typing/stdlib.py
typon/trans/transpiler/phases/typing/stdlib.py
+6
-4
typon/trans/transpiler/phases/typing/types.py
typon/trans/transpiler/phases/typing/types.py
+7
-1
typon/trans/transpiler/transpiler.py
typon/trans/transpiler/transpiler.py
+8
-3
No files found.
.gitignore
View file @
b738512a
.idea
cmake-build-*
typon.egg-info
\ No newline at end of file
typon.egg-info
build
\ No newline at end of file
typon/include/python/basedef.hpp
View file @
b738512a
...
...
@@ -20,6 +20,8 @@ public:
return
sync_wrapper
(
std
::
forward
<
Args
>
(
args
)...);
}
};
/*
struct method {};
...
...
typon/include/python/builtins.hpp
View file @
b738512a
...
...
@@ -59,6 +59,8 @@ template <PySmartPtr T> struct RealType<T> {
using
type
=
typename
T
::
element_type
;
};
namespace
typon
{
//template <typename T> using TyObj = std::shared_ptr<typename RealType<T>::type>;
template
<
typename
T
>
...
...
@@ -135,6 +137,11 @@ template <typename T, typename... Args> auto pyobj_agg(Args &&...args) -> TyObj<
return
std
::
make_shared
<
typename
RealType
<
T
>::
type
>
((
typename
RealType
<
T
>::
type
)
{
std
::
forward
<
Args
>
(
args
)...
});
}
class
TyNone
{
};
}
// typon_len
template
<
typename
T
>
...
...
@@ -199,6 +206,7 @@ static constexpr auto PyNone = std::nullopt;
#include "builtins/bool.hpp"
#include "builtins/complex.hpp"
#include "builtins/dict.hpp"
#include "builtins/int.hpp"
#include "builtins/list.hpp"
#include "builtins/print.hpp"
#include "builtins/range.hpp"
...
...
@@ -307,7 +315,7 @@ typon::Task<typon::PyFile> open(const TyStr &path, std::string_view mode) {
std
::
cerr
<<
path
<<
","
<<
flags
<<
std
::
endl
;
system_error
(
-
fd
,
"openat()"
);
}
co_return
tyObj
<
typon
::
PyFile
>
(
fd
,
len
);
co_return
ty
pon
::
ty
Obj
<
typon
::
PyFile
>
(
fd
,
len
);
}
#include <typon/generator.hpp>
...
...
@@ -349,9 +357,9 @@ template<PySmartPtr T>
auto
&
iter_fix_ref
(
T
&
obj
)
{
return
*
obj
;
}
namespace
std
{
template
<
class
T
>
auto
begin
(
std
::
shared_ptr
<
T
>
&
obj
)
{
return
dot
p
(
obj
,
begin
)();
}
template
<
class
T
>
auto
begin
(
std
::
shared_ptr
<
T
>
&
obj
)
{
return
dot
(
obj
,
begin
)();
}
template
<
class
T
>
auto
end
(
std
::
shared_ptr
<
T
>
&
obj
)
{
return
dot
p
(
obj
,
end
)();
}
template
<
class
T
>
auto
end
(
std
::
shared_ptr
<
T
>
&
obj
)
{
return
dot
(
obj
,
end
)();
}
}
template
<
typename
T
>
...
...
@@ -365,18 +373,33 @@ struct ValueTypeEx {
using
type
=
decltype
(
*
std
::
begin
(
std
::
declval
<
Seq
&>
()));
};
// (2)
template
<
typename
Map
,
typename
Seq
,
typename
Filt
=
AlwaysTrue
<
typename
ValueTypeEx
<
Seq
>
::
type
>>
auto
mapFilter
(
Map
map
,
Seq
seq
,
Filt
filt
=
Filt
())
{
/*
template <typename Map, typename Seq, typename Filt = AlwaysTrue<typename ValueTypeEx<Seq>::type>>
typon::Task<
mapFilter(Map map, Seq seq, Filt filt = Filt()) {
//typedef typename Seq::value_type value_type;
using value_type = typename ValueTypeEx<Seq>::type;
using return_type = decltype(map(std::declval<value_type>()));
std::vector<return_type> result{};
for
(
auto
i
:
seq
|
std
::
views
::
filter
(
filt
)
|
std
::
views
::
transform
(
map
))
result
.
push_back
(
i
);
for (auto i : seq) {
if (co_await filt(i)) {
result.push_back(co_await map(i));
}
}
return typon::TyList(std::move(result));
}
}*/
#define MAP_FILTER(item, seq, map, filter) ({\
using value_type = typename ValueTypeEx<decltype(seq)>::type;\
value_type item;\
std::vector<decltype(map)> result{};\
for (auto item : seq) {\
if (filter) {\
result.push_back(map);\
}\
}\
typon::TyList(std::move(result));\
})
namespace
PYBIND11_NAMESPACE
{
namespace
detail
{
...
...
typon/include/python/builtins/int.hpp
0 → 100644
View file @
b738512a
//
// Created by Tom on 08/03/2023.
//
#ifndef TYPON_INT_HPP
#define TYPON_INT_HPP
#include <sstream>
#include <string>
#include <algorithm>
using
namespace
std
::
literals
;
#include "bytes.hpp"
#include "print.hpp"
#include "slice.hpp"
// #include <format>
#include <fmt/format.h>
#include <pybind11/cast.h>
namespace
typon
{
/*template <typename _Base0 = object>
class TyInt__oo : classtype<_Base0, Integer__oo<>> {
public:
struct : method {
auto operator()(auto self, int value) const {
self->value = value;
}
} static constexpr oo__init__oo {};
struct : method {
auto operator()(auto self, auto other) const {
return Integer(dot(self, value) + dot(other, value));
}
} static constexpr oo__add__oo {};
auto operator () (int value) const {
struct Obj : instance<Integer__oo<>, Obj> {
int value;
};
auto obj = rc(Obj{});
dot(obj, oo__init__oo)(value);
return obj;
}
constexpr TyInt(int value) : value(value) {}
constexpr TyInt() : value(0) {}
operator int() const { return value; }
// operators
template <typename T> TyInt operator+(T x) const { return value + x; }
template <typename T> TyInt operator-(T x) const { return value - x; }
template <typename T> TyInt operator*(T x) const { return value * x; }
template <typename T> TyInt operator/(T x) const { return value / x; }
template <typename T> TyInt operator%(T x) const { return value % x; }
template <typename T> TyInt operator&(T x) const { return value & x; }
template <typename T> TyInt operator|(T x) const { return value | x; }
template <typename T> TyInt operator^(T x) const { return value ^ x; }
template <typename T> TyInt operator<<(T x) const { return value << x; }
template <typename T> TyInt operator>>(T x) const { return value >> x; }
template <typename T> TyInt operator&&(T x) const { return value && x; }
template <typename T> TyInt operator||(T x) const { return value || x; }
template <typename T> TyInt operator==(T x) const { return value == x; }
template <typename T> TyInt operator<(T x) const { return value < x; }
TyInt operator-() const { return -value; }
private:
int value;
};*/
using
namespace
referencemodel
;
template
<
typename
_Base0
=
object
>
struct
Integer__oo
:
classtype
<
_Base0
,
Integer__oo
<>>
{
static
constexpr
std
::
string_view
name
=
"Integer"
;
struct
:
method
{
auto
operator
()(
auto
self
,
int
value
)
const
{
self
->
value
=
value
;
}
}
static
constexpr
oo__init__oo
{};
struct
:
method
{
auto
operator
()(
auto
self
,
auto
other
)
const
{
return
TyInt
(
dot
(
self
,
value
)
+
dot
(
other
,
value
));
}
}
static
constexpr
oo__add__oo
{};
struct
Obj
:
value
<
Integer__oo
<>
,
Obj
>
{
int
value
;
Obj
(
int
value
=
0
)
:
value
(
value
)
{}
operator
int
()
const
{
return
value
;
}
};
auto
operator
()
(
int
value
)
const
{
auto
obj
=
rc
(
Obj
{});
dot
(
obj
,
oo__init__oo
)(
value
);
return
obj
;
}
};
static
constexpr
Integer__oo
<>
TyInt
{};
}
inline
auto
operator
""
_pi
(
unsigned
long
long
int
v
)
noexcept
{
return
typon
::
TyInt
(
v
);
}
template
<
>
struct
std
::
hash
<
decltype
(
0
_pi
)
>
{
std
::
size_t
operator
()(
const
decltype
(
0
_pi
)
&
s
)
const
noexcept
{
return
std
::
hash
<
int
>
()(
s
);
}
};
namespace
PYBIND11_NAMESPACE
{
namespace
detail
{
template
<
>
struct
type_caster
<
decltype
(
0
_pi
)
>
:
type_caster
<
int
>
{};
}}
template
<
>
void
repr_to
(
const
decltype
(
0
_pi
)
&
x
,
std
::
ostream
&
s
)
{
s
<<
x
;
}
template
<
>
void
print_to
<
decltype
(
0
_pi
)
>
(
const
decltype
(
0
_pi
)
&
x
,
std
::
ostream
&
s
)
{
s
<<
x
;
}
#endif // TYPON_INT_HPP
typon/include/python/builtins/print.hpp
View file @
b738512a
...
...
@@ -86,13 +86,14 @@ typon::Task<void> print(T const &head, Args const &...args) {
}*/
struct
{
void
operator
()()
{
std
::
cout
<<
'\n'
;
}
typon
::
TyNone
operator
()()
{
std
::
cout
<<
'\n'
;
return
{}
;
}
template
<
Printable
T
,
Printable
...
Args
>
void
operator
()(
T
const
&
head
,
Args
const
&
...
args
)
{
typon
::
TyNone
operator
()(
T
const
&
head
,
Args
const
&
...
args
)
{
print_to
(
head
,
std
::
cout
);
(((
std
::
cout
<<
' '
),
print_to
(
args
,
std
::
cout
)),
...);
std
::
cout
<<
'\n'
;
return
{};
}
}
print
;
// typon::Task<void> print() { std::cout << '\n'; co_return; }
...
...
typon/include/python/builtins/range.hpp
View file @
b738512a
...
...
@@ -18,11 +18,7 @@ auto stride = [](int n) {
// todo: proper range support
struct
range_s
:
TyBuiltin
<
range_s
>
{
template
<
typename
T
>
auto
sync
(
T
stop
)
{
return
sync
(
0
,
stop
);
}
template
<
typename
T
>
auto
sync
(
T
start
,
T
stop
,
T
step
=
1
)
{
auto
sync
(
int
start
,
int
stop
,
int
step
=
1
)
{
// https://www.modernescpp.com/index.php/c-20-pythons-map-function/
if
(
step
==
0
)
{
throw
std
::
invalid_argument
(
"Step cannot be 0"
);
...
...
@@ -36,6 +32,10 @@ struct range_s : TyBuiltin<range_s>
return
start
<
stop
?
i
:
stop
-
(
i
-
start
);
});
}
auto
sync
(
int
stop
)
{
return
sync
(
0
,
stop
);
}
}
range
;
#endif // TYPON_RANGE_HPP
typon/include/python/referencemodel.hpp
View file @
b738512a
...
...
@@ -23,6 +23,9 @@ struct object;
template
<
typename
T
,
typename
O
>
struct
instance
;
template
<
typename
T
,
typename
O
>
struct
value
;
template
<
typename
B
,
typename
T
>
struct
classtype
;
...
...
@@ -168,6 +171,10 @@ using unwrap_pack = typename unwrap_pack_s<std::remove_cvref_t<T>>::type;
/* Meta-programming utilities for object model */
template
<
typename
T
>
concept
object
=
std
::
derived_from
<
unwrap_all
<
T
>
,
referencemodel
::
object
>
;
template
<
typename
T
>
concept
instance
=
std
::
derived_from
<
unwrap_all
<
T
>
,
...
...
@@ -215,7 +222,26 @@ concept boundmethod = boundmethod_s<std::remove_cvref_t<T>>::value;
template
<
typename
T
>
concept
value
=
!
instance
<
T
>
&&
!
boundmethod
<
T
>
;
struct
value_s
{
static
constexpr
bool
value
=
true
;
};
template
<
instance
T
>
struct
value_s
<
T
>
{
static
constexpr
bool
value
=
std
::
derived_from
<
unwrap_all
<
T
>
,
referencemodel
::
value
<
typename
unwrap_all
<
T
>::
type
,
unwrap_all
<
T
>>
>
;
};
template
<
typename
S
,
typename
F
>
struct
value_s
<
referencemodel
::
boundmethod
<
S
,
F
>>
{
static
constexpr
bool
value
=
value_s
<
S
>::
value
;
};
template
<
typename
T
>
concept
value
=
value_s
<
std
::
remove_cvref_t
<
T
>>::
value
;
/* Meta-programming utilities: wrapped and unwrapped */
...
...
@@ -963,6 +989,10 @@ struct instance : T {
};
template
<
typename
T
,
typename
O
>
struct
value
:
instance
<
T
,
O
>
{};
template
<
typename
B
,
typename
T
>
struct
classtype
:
B
{
using
base
=
B
;
...
...
@@ -1193,14 +1223,58 @@ decltype(auto) bind(S &&, const A & attr, T...) {
return
attr
;
}
}
// namespace referencemodel
#define dot(OBJ, NAME)\
[](auto && obj) -> decltype(auto) {\
return referencemodel::bind(std::forward<decltype(obj)>(obj), obj->NAME);\
}(OBJ)
/* Operators */
namespace
meta
{
/* + */
template
<
typename
Left
,
typename
Right
>
concept
LeftAddable
=
requires
(
Left
left
,
Right
right
)
{
// note: using dot here would cause hard failure instead of invalid constraint
left
->
oo__add__oo
(
left
,
right
);
};
template
<
typename
Left
,
typename
Right
>
concept
RightAddable
=
requires
(
Left
left
,
Right
right
)
{
// note: using dot here would cause hard failure instead of invalid constraint
right
->
oo__radd__oo
(
right
,
left
);
};
template
<
typename
Left
,
typename
Right
>
concept
Addable
=
LeftAddable
<
Left
,
Right
>
||
RightAddable
<
Left
,
Right
>
;
}
/* + */
template
<
meta
::
object
Left
,
meta
::
object
Right
>
requires
meta
::
Addable
<
Left
,
Right
>
auto
operator
+
(
Left
&&
left
,
Right
&&
right
)
{
if
constexpr
(
meta
::
LeftAddable
<
Left
,
Right
>
)
{
return
dot
(
std
::
forward
<
Left
>
(
left
),
oo__add__oo
)(
std
::
forward
<
Right
>
(
right
));
}
else
{
if
constexpr
(
meta
::
RightAddable
<
Left
,
Right
>
)
{
return
dot
(
std
::
forward
<
Right
>
(
right
),
oo__radd__oo
)(
std
::
forward
<
Left
>
(
left
));
}
}
}
}
// namespace referencemodel
#endif // REFERENCEMODEL_H
runtime
@
26c320d7
Subproject commit
79677d125f915f7c61492d8d1d8cde9fc6a11875
Subproject commit
26c320d77d368d0f482684ebd653d1702c75a7f2
typon/trans/stdlib/builtins_.py
View file @
b738512a
...
...
@@ -3,8 +3,8 @@ from typing import Self, Protocol, Optional
assert
5
class
object
:
def
__eq__
(
self
,
other
:
Self
)
->
bool
:
...
def
__ne__
(
self
,
other
:
Self
)
->
bool
:
...
def
__eq__
[
T
](
self
,
other
:
T
)
->
bool
:
...
def
__ne__
[
T
](
self
,
other
:
T
)
->
bool
:
...
class
int
:
def
__add__
(
self
,
other
:
Self
)
->
Self
:
...
...
...
@@ -96,6 +96,10 @@ assert [].__getitem__
assert
[
4
].
__getitem__
assert
[
1
,
2
,
3
][
1
]
class
set
[
U
]:
def
__len__
(
self
)
->
int
:
...
def
__contains__
(
self
,
item
:
U
)
->
bool
:
...
def
iter
[
U
](
x
:
Iterable
[
U
])
->
Iterator
[
U
]:
...
...
...
typon/trans/stdlib/typing_.py
View file @
b738512a
...
...
@@ -2,4 +2,5 @@
Protocol
=
BuiltinFeature
[
"Protocol"
]
Self
=
BuiltinFeature
[
"Self"
]
Optional
=
BuiltinFeature
[
"Optional"
]
\ No newline at end of file
Optional
=
BuiltinFeature
[
"Optional"
]
Callable
=
BuiltinFeature
[
"Callable"
]
\ No newline at end of file
typon/trans/test_runner.py
View file @
b738512a
...
...
@@ -88,15 +88,15 @@ def run_test(path, quiet=True):
if
args
.
compile
:
return
TestStatus
.
SUCCESS
execute_str
=
"true"
if
(
execute
and
not
args
.
generate
)
else
"false"
name_bin
=
path
.
with_suffix
(
""
).
as_posix
()
+
(
"$(python3-config --extension-suffix)"
if
extension
else
".exe"
)
if
exec_cmd
(
f'bash -c "export PYTHONPATH=stdlib; if
{
execute_str
}
; then
python3
./
{
path
.
as_posix
()
}
; fi"'
)
!=
0
:
name_bin
=
path
.
with_suffix
(
""
).
as_posix
()
+
(
"$(python3
.12
-config --extension-suffix)"
if
extension
else
".exe"
)
if
exec_cmd
(
f'bash -c "export PYTHONPATH=stdlib; if
{
execute_str
}
; then
echo python3.12
./
{
path
.
as_posix
()
}
; fi"'
)
!=
0
:
return
TestStatus
.
PYTHON_ERROR
if
compile
and
(
alt
:
=
environ
.
get
(
"ALT_RUNNER"
)):
if
(
code
:
=
exec_cmd
(
alt
.
format
(
name_bin
=
name_bin
,
name_cpp_posix
=
name_cpp
.
as_posix
(),
run_file
=
execute_str
,
test_exec
=
f"python3
{
path
.
with_suffix
(
'.post.py'
).
as_posix
()
}
"
if
extension
else
name_bin
,
test_exec
=
f"python3
.12
{
path
.
with_suffix
(
'.post.py'
).
as_posix
()
}
"
if
extension
else
name_bin
,
bonus_flags
=
"-e"
if
extension
else
""
)))
!=
0
:
return
TestStatus
(
code
)
...
...
typon/trans/tests/builtins_test.py
View file @
b738512a
...
...
@@ -4,9 +4,9 @@ from typon import is_cpp
import
sys
as
sis
from
sys
import
stdout
as
truc
foo
=
123
test
=
(
2
+
3
)
*
4
glob
=
5
#
foo = 123
#
test = (2 + 3) * 4
#
glob = 5
# def g():
# a = 8
...
...
@@ -20,32 +20,37 @@ glob = 5
# e = d + 1
# print(e)
def
f
(
x
):
return
x
+
1
def
fct
(
param
:
int
):
loc
=
f
(
456
)
global
glob
loc
=
789
glob
=
123
def
fct2
():
global
glob
glob
+=
5
#
def f(x):
#
return x + 1
#
#
#
def fct(param: int):
#
loc = f(456)
#
global glob
#
loc = 789
#
glob = 123
#
#
def fct2():
#
global glob
#
glob += 5
if
__name__
==
"__main__"
:
print
(
is_cpp
)
print
(
"is c++:"
,
is_cpp
()
)
# TODO: doesn't compile under G++ 12.2, fixed in trunk on March 15
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98056
sum
=
0
for
i
in
range
(
15
):
sum
+=
i
sum
=
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
]
#
b = [x for x in a if x % 2 == 0]
#
c = [y * y for y in b]
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
,
3j
,
sum
,
a
,
b
,
c
)
"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
,
a
)
print
(
"Typon"
)
print
()
typon/trans/transpiler/error_display.py
View file @
b738512a
...
...
@@ -2,10 +2,15 @@
import
ast
import
builtins
import
importlib
import
inspect
import
sys
import
traceback
import
colorful
as
cf
from
transpiler.exceptions
import
CompileError
from
transpiler.utils
import
highlight
def
exception_hook
(
exc_type
,
exc_value
,
tb
):
print
=
lambda
*
args
,
**
kwargs
:
builtins
.
print
(
*
args
,
**
kwargs
,
file
=
sys
.
stderr
)
last_node
=
None
...
...
@@ -49,40 +54,44 @@ def exception_hook(exc_type, exc_value, tb):
return
print
(
f"In file
{
cf
.
white
(
last_file
)
}
:
{
last_node
.
lineno
}
"
)
#print(f"From {last_node.lineno}:{last_node.col_offset} to {last_node.end_lineno}:{last_node.end_col_offset}")
with
open
(
last_file
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
code
=
f
.
read
()
hg
=
(
str
(
highlight
(
code
,
True
))
.
replace
(
"
\
x1b
[04m"
,
""
)
.
replace
(
"
\
x1b
[24m"
,
""
)
.
replace
(
"
\
x1b
[39;24m"
,
"
\
x1b
[39m"
)
.
splitlines
())
if
last_node
.
lineno
==
last_node
.
end_lineno
:
old
=
hg
[
last_node
.
lineno
-
1
]
start
,
end
=
find_indices
(
old
,
[
last_node
.
col_offset
,
last_node
.
end_col_offset
])
hg
[
last_node
.
lineno
-
1
]
=
old
[:
start
]
+
"
\
x1b
[4m"
+
old
[
start
:
end
]
+
"
\
x1b
[24m"
+
old
[
end
:]
try
:
with
open
(
last_file
,
"r"
,
encoding
=
"utf-8"
)
as
f
:
code
=
f
.
read
()
except
Exception
:
pass
else
:
old
=
hg
[
last_node
.
lineno
-
1
]
[
start
]
=
find_indices
(
old
,
[
last_node
.
col_offset
])
hg
[
last_node
.
lineno
-
1
]
=
old
[:
start
]
+
"
\
x1b
[4m"
+
old
[
start
:]
for
lineid
in
range
(
last_node
.
lineno
,
last_node
.
end_lineno
-
1
):
old
=
hg
[
lineid
]
hg
=
(
str
(
highlight
(
code
,
True
))
.
replace
(
"
\
x1b
[04m"
,
""
)
.
replace
(
"
\
x1b
[24m"
,
""
)
.
replace
(
"
\
x1b
[39;24m"
,
"
\
x1b
[39m"
)
.
splitlines
())
if
last_node
.
lineno
==
last_node
.
end_lineno
:
old
=
hg
[
last_node
.
lineno
-
1
]
start
,
end
=
find_indices
(
old
,
[
last_node
.
col_offset
,
last_node
.
end_col_offset
])
hg
[
last_node
.
lineno
-
1
]
=
old
[:
start
]
+
"
\
x1b
[4m"
+
old
[
start
:
end
]
+
"
\
x1b
[24m"
+
old
[
end
:]
else
:
old
=
hg
[
last_node
.
lineno
-
1
]
[
start
]
=
find_indices
(
old
,
[
last_node
.
col_offset
])
hg
[
last_node
.
lineno
-
1
]
=
old
[:
start
]
+
"
\
x1b
[4m"
+
old
[
start
:]
for
lineid
in
range
(
last_node
.
lineno
,
last_node
.
end_lineno
-
1
):
old
=
hg
[
lineid
]
first_nonspace
=
len
(
old
)
-
len
(
old
.
lstrip
())
hg
[
lineid
]
=
old
[:
first_nonspace
]
+
"
\
x1b
[4m"
+
old
[
first_nonspace
:]
+
"
\
x1b
[24m"
old
=
hg
[
last_node
.
end_lineno
-
1
]
first_nonspace
=
len
(
old
)
-
len
(
old
.
lstrip
())
hg
[
lineid
]
=
old
[:
first_nonspace
]
+
"
\
x1b
[4m"
+
old
[
first_nonspace
:]
+
"
\
x1b
[24m"
old
=
hg
[
last_node
.
end_lineno
-
1
]
first_nonspace
=
len
(
old
)
-
len
(
old
.
lstrip
())
[
end
]
=
find_indices
(
old
,
[
last_node
.
end_col_offset
])
hg
[
last_node
.
end_lineno
-
1
]
=
old
[:
first_nonspace
]
+
"
\
x1b
[4m"
+
old
[
first_nonspace
:
end
]
+
"
\
x1b
[24m"
+
old
[
end
:]
CONTEXT_SIZE
=
2
start
=
max
(
0
,
last_node
.
lineno
-
CONTEXT_SIZE
-
1
)
offset
=
start
+
1
for
i
,
line
in
enumerate
(
hg
[
start
:
last_node
.
end_lineno
+
CONTEXT_SIZE
]):
erroneous
=
last_node
.
lineno
<=
offset
+
i
<=
last_node
.
end_lineno
indicator
=
cf
.
white
(
" →"
)
if
erroneous
else
" "
bar
=
" ▎"
# bar = "│" if erroneous else "┊"
disp
=
f"
\
x1b
[24m
{
indicator
}{
cf
.
white
}{
(
offset
+
i
):
>
4
}{
cf
.
red
if
erroneous
else
cf
.
reset
}{
bar
}{
cf
.
reset
}
{
line
}\
x1b
[24m"
print
(
disp
)
# print(repr(disp))
[
end
]
=
find_indices
(
old
,
[
last_node
.
end_col_offset
])
hg
[
last_node
.
end_lineno
-
1
]
=
old
[:
first_nonspace
]
+
"
\
x1b
[4m"
+
old
[
first_nonspace
:
end
]
+
"
\
x1b
[24m"
+
old
[
end
:]
CONTEXT_SIZE
=
2
start
=
max
(
0
,
last_node
.
lineno
-
CONTEXT_SIZE
-
1
)
offset
=
start
+
1
for
i
,
line
in
enumerate
(
hg
[
start
:
last_node
.
end_lineno
+
CONTEXT_SIZE
]):
erroneous
=
last_node
.
lineno
<=
offset
+
i
<=
last_node
.
end_lineno
indicator
=
cf
.
white
(
" →"
)
if
erroneous
else
" "
bar
=
" ▎"
# bar = "│" if erroneous else "┊"
disp
=
f"
\
x1b
[24m
{
indicator
}{
cf
.
white
}{
(
offset
+
i
):
>
4
}{
cf
.
red
if
erroneous
else
cf
.
reset
}{
bar
}{
cf
.
reset
}
{
line
}\
x1b
[24m"
print
(
disp
)
# print(repr(disp))
print
()
if
isinstance
(
exc_value
,
CompileError
):
print
(
cf
.
red
(
"Error:"
),
exc_value
)
...
...
typon/trans/transpiler/phases/desugar_op/__init__.py
View file @
b738512a
...
...
@@ -24,7 +24,7 @@ DUNDER = {
class
DesugarOp
(
ast
.
NodeTransformer
):
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
):
lnd
=
linenodata
(
node
)
re
turn
ast
.
Call
(
re
s
=
ast
.
Call
(
func
=
ast
.
Attribute
(
value
=
self
.
visit
(
node
.
left
),
attr
=
f"__
{
DUNDER
[
type
(
node
.
op
)]
}
__"
,
...
...
@@ -35,26 +35,31 @@ class DesugarOp(ast.NodeTransformer):
keywords
=
{},
**
lnd
)
res
.
orig_node
=
node
return
res
def
visit_UnaryOp
(
self
,
node
:
ast
.
UnaryOp
):
lnd
=
linenodata
(
node
)
if
type
(
node
.
op
)
==
ast
.
Not
:
re
turn
ast
.
UnaryOp
(
re
s
=
ast
.
UnaryOp
(
operand
=
self
.
visit
(
node
.
operand
),
op
=
node
.
op
,
**
lnd
)
return
ast
.
Call
(
func
=
ast
.
Attribute
(
value
=
self
.
visit
(
node
.
operand
),
attr
=
f"__
{
DUNDER
[
type
(
node
.
op
)]
}
__"
,
ctx
=
ast
.
Load
(),
else
:
res
=
ast
.
Call
(
func
=
ast
.
Attribute
(
value
=
self
.
visit
(
node
.
operand
),
attr
=
f"__
{
DUNDER
[
type
(
node
.
op
)]
}
__"
,
ctx
=
ast
.
Load
(),
**
lnd
),
args
=
[],
keywords
=
{},
**
lnd
),
args
=
[],
keywords
=
{},
**
lnd
)
)
res
.
orig_node
=
node
return
res
# def visit_AugAssign(self, node: ast.AugAssign):
# return
typon/trans/transpiler/phases/emit_cpp/class_.py
View file @
b738512a
import
ast
from
typing
import
Iterable
def
emit_class
(
clazz
)
->
Iterable
[
str
]:
def
emit_class
(
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
yield
f"template <typename _Base0 = referencemodel::object>"
yield
f"struct
{
node
.
name
}
__oo : referencemodel::classtype<_Base0,
{
node
.
name
}
__oo<>> {{"
yield
f"static constexpr std::string_view name =
\
"
{
node
.
name
}\
"
;"
...
...
typon/trans/transpiler/phases/emit_cpp/expr.py
View file @
b738512a
...
...
@@ -5,8 +5,35 @@ from typing import Iterable
from
transpiler.phases.emit_cpp.visitors
import
NodeVisitor
,
CoroutineMode
,
join
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.utils
import
make_lnd
from
transpiler.utils
import
linenodata
SYMBOLS
=
{
ast
.
Eq
:
"=="
,
ast
.
NotEq
:
'!='
,
ast
.
Pass
:
'/* pass */'
,
ast
.
Mult
:
'*'
,
ast
.
Add
:
'+'
,
ast
.
Sub
:
'-'
,
ast
.
Div
:
'/'
,
ast
.
FloorDiv
:
'/'
,
# TODO
ast
.
Mod
:
'%'
,
ast
.
Lt
:
'<'
,
ast
.
Gt
:
'>'
,
ast
.
GtE
:
'>='
,
ast
.
LtE
:
'<='
,
ast
.
LShift
:
'<<'
,
ast
.
RShift
:
'>>'
,
ast
.
BitXor
:
'^'
,
ast
.
BitOr
:
'|'
,
ast
.
BitAnd
:
'&'
,
ast
.
Not
:
'!'
,
ast
.
IsNot
:
'!='
,
ast
.
USub
:
'-'
,
ast
.
And
:
'&&'
,
ast
.
Or
:
'||'
}
"""Mapping of Python AST nodes to C++ symbols."""
# noinspection PyPep8Naming
@
dataclass
...
...
@@ -33,7 +60,7 @@ class ExpressionVisitor(NodeVisitor):
yield
str
(
node
.
value
).
lower
()
elif
isinstance
(
node
.
value
,
int
):
# TODO: bigints
yield
str
(
node
.
value
)
yield
str
(
node
.
value
)
+
"_pi"
elif
isinstance
(
node
.
value
,
float
):
yield
repr
(
node
.
value
)
elif
isinstance
(
node
.
value
,
complex
):
...
...
@@ -44,7 +71,7 @@ class ExpressionVisitor(NodeVisitor):
raise
NotImplementedError
(
node
,
type
(
node
))
def
visit_Slice
(
self
,
node
:
ast
.
Slice
)
->
Iterable
[
str
]:
yield
"TySlice("
yield
"
typon::
TySlice("
yield
from
join
(
", "
,
(
self
.
visit
(
x
or
ast
.
Constant
(
value
=
None
))
for
x
in
(
node
.
lower
,
node
.
upper
,
node
.
step
)))
yield
")"
...
...
@@ -79,22 +106,22 @@ class ExpressionVisitor(NodeVisitor):
# yield from self.visit_binary_operation(op, left, right, make_lnd(left, right))
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
Iterable
[
str
]:
raise
NotImplementedError
()
# if len(node.values) == 1:
# yield from self.visit(node.values[0])
# return
# cpp_op = {
# ast.And: "&&",
# ast.Or: "||"
# }[type(node.op)]
# with self.prec_ctx(cpp_op):
# yield from self.visit_binary_operation(cpp_op, node.values[0], node.values[1], make_lnd(node.values[0], node.values[1]))
# for left, right in zip(node.values[1:], node.values[2:]):
# yield f" {cpp_op} "
# yield from self.visit_binary_operation(cpp_op, left, right, make_lnd(left, right))
if
len
(
node
.
values
)
==
1
:
yield
from
self
.
visit
(
node
.
values
[
0
])
return
cpp_op
=
{
ast
.
And
:
"&&"
,
ast
.
Or
:
"||"
}[
type
(
node
.
op
)]
yield
"("
yield
from
self
.
visit_binary_operation
(
cpp_op
,
node
.
values
[
0
],
node
.
values
[
1
],
make_lnd
(
node
.
values
[
0
],
node
.
values
[
1
]))
for
left
,
right
in
zip
(
node
.
values
[
1
:],
node
.
values
[
2
:]):
yield
f"
{
cpp_op
}
"
yield
from
self
.
visit_binary_operation
(
cpp_op
,
left
,
right
,
make_lnd
(
left
,
right
))
yield
")"
def
visit_Call
(
self
,
node
:
ast
.
Call
)
->
Iterable
[
str
]:
yield
"co_await"
yield
"("
yield
from
self
.
visit
(
node
.
func
)
yield
")("
...
...
@@ -158,6 +185,8 @@ class ExpressionVisitor(NodeVisitor):
templ
,
args
,
_
=
self
.
process_args
(
node
.
args
)
yield
templ
yield
args
yield
"->"
yield
from
self
.
visit
(
node
.
type
.
deref
().
return_type
)
yield
"{"
yield
"return"
yield
from
self
.
reset
().
visit
(
node
.
body
)
...
...
@@ -165,14 +194,20 @@ class ExpressionVisitor(NodeVisitor):
yield
"}"
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
)
->
Iterable
[
str
]:
raise
NotImplementedError
()
yield
from
self
.
visit_binary_operation
(
node
.
op
,
node
.
left
,
node
.
right
,
linenodata
(
node
))
def
visit_Compare
(
self
,
node
:
ast
.
Compare
)
->
Iterable
[
str
]:
raise
NotImplementedError
()
yield
from
self
.
visit_binary_operation
(
node
.
ops
[
0
],
node
.
left
,
node
.
comparators
[
0
],
linenodata
(
node
))
def
visit_binary_operation
(
self
,
op
,
left
:
ast
.
AST
,
right
:
ast
.
AST
,
lnd
:
dict
)
->
Iterable
[
str
]:
yield
"(co_await ("
yield
from
self
.
visit
(
left
)
yield
" "
yield
SYMBOLS
[
type
(
op
)]
yield
" "
yield
from
self
.
visit
(
right
)
yield
"))"
return
raise
NotImplementedError
()
# if type(op) == ast.In:
# call = ast.Call(ast.Attribute(right, "__contains__", **lnd), [left], [], **lnd)
...
...
@@ -205,7 +240,7 @@ class ExpressionVisitor(NodeVisitor):
def
visit_List
(
self
,
node
:
ast
.
List
)
->
Iterable
[
str
]:
if
node
.
elts
:
yield
"typon::TyList{"
yield
from
join
(
", "
,
map
(
self
.
reset
().
visit
,
node
.
elts
))
yield
from
join
(
", "
,
map
(
self
.
visit
,
node
.
elts
))
yield
"}"
else
:
yield
from
self
.
visit
(
node
.
type
)
...
...
@@ -214,7 +249,7 @@ class ExpressionVisitor(NodeVisitor):
def
visit_Set
(
self
,
node
:
ast
.
Set
)
->
Iterable
[
str
]:
if
node
.
elts
:
yield
"typon::TySet{"
yield
from
join
(
", "
,
map
(
self
.
reset
().
visit
,
node
.
elts
))
yield
from
join
(
", "
,
map
(
self
.
visit
,
node
.
elts
))
yield
"}"
else
:
yield
from
self
.
visit
(
node
.
type
)
...
...
@@ -223,9 +258,9 @@ class ExpressionVisitor(NodeVisitor):
def
visit_Dict
(
self
,
node
:
ast
.
Dict
)
->
Iterable
[
str
]:
def
visit_item
(
key
,
value
):
yield
"std::pair {"
yield
from
self
.
reset
().
visit
(
key
)
yield
from
self
.
visit
(
key
)
yield
", "
yield
from
self
.
reset
().
visit
(
value
)
yield
from
self
.
visit
(
value
)
yield
"}"
if
node
.
keys
:
...
...
@@ -256,12 +291,13 @@ class ExpressionVisitor(NodeVisitor):
yield
from
self
.
prec
(
"unary"
).
visit
(
operand
)
def
visit_IfExp
(
self
,
node
:
ast
.
IfExp
)
->
Iterable
[
str
]:
with
self
.
prec_ctx
(
"?:"
):
yield
from
self
.
visit
(
node
.
test
)
yield
" ? "
yield
from
self
.
visit
(
node
.
body
)
yield
" : "
yield
from
self
.
visit
(
node
.
orelse
)
yield
"("
yield
from
self
.
visit
(
node
.
test
)
yield
" ? "
yield
from
self
.
visit
(
node
.
body
)
yield
" : "
yield
from
self
.
visit
(
node
.
orelse
)
yield
")"
def
visit_Yield
(
self
,
node
:
ast
.
Yield
)
->
Iterable
[
str
]:
#if CoroutineMode.GENERATOR in self.generator:
...
...
@@ -279,8 +315,23 @@ class ExpressionVisitor(NodeVisitor):
if
len
(
node
.
generators
)
!=
1
:
raise
NotImplementedError
(
"Multiple generators not handled yet"
)
gen
:
ast
.
comprehension
=
node
.
generators
[
0
]
yield
"MAP_FILTER("
yield
from
self
.
visit
(
gen
.
target
)
yield
","
yield
from
self
.
visit
(
gen
.
iter
)
yield
", "
yield
from
self
.
visit
(
node
.
elt
)
yield
", "
if
gen
.
ifs
:
yield
from
self
.
visit
(
gen
.
ifs_node
)
else
:
yield
"true"
yield
")"
return
yield
"mapFilter([]("
yield
from
self
.
visit
(
node
.
input_item_type
)
#yield from self.visit(node.input_item_type)
yield
"auto"
yield
from
self
.
visit
(
gen
.
target
)
yield
") { return "
yield
from
self
.
visit
(
node
.
elt
)
...
...
@@ -289,9 +340,12 @@ class ExpressionVisitor(NodeVisitor):
if
gen
.
ifs
:
yield
", "
yield
"[]("
yield
from
self
.
visit
(
node
.
input_item_type
)
#yield from self.visit(node.input_item_type)
yield
"auto"
yield
from
self
.
visit
(
gen
.
target
)
yield
") { return "
yield
") -> typon::Task<"
yield
from
self
.
visit
(
gen
.
ifs_node
.
type
)
yield
"> { return "
yield
from
self
.
visit
(
gen
.
ifs_node
)
yield
"; }"
yield
")"
...
...
typon/trans/transpiler/phases/emit_cpp/function.py
View file @
b738512a
...
...
@@ -3,6 +3,7 @@ from dataclasses import dataclass, field
from
typing
import
Iterable
,
Optional
from
transpiler.phases.emit_cpp.expr
import
ExpressionVisitor
from
transpiler.phases.typing.common
import
IsDeclare
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.emit_cpp.visitors
import
NodeVisitor
,
flatmap
,
CoroutineMode
from
transpiler.phases.typing.types
import
CallableInstanceType
,
BaseType
...
...
@@ -10,7 +11,7 @@ from transpiler.phases.typing.types import CallableInstanceType, BaseType
def
emit_function
(
name
:
str
,
func
:
CallableInstanceType
)
->
Iterable
[
str
]:
yield
f"struct : referencemodel::function {{"
yield
"typon::Task<
void
> operator()("
yield
"typon::Task<
typon::TyNone
> operator()("
for
arg
,
ty
in
zip
(
func
.
block_data
.
node
.
args
.
args
,
func
.
parameters
):
yield
"auto "
...
...
@@ -151,32 +152,36 @@ class BlockVisitor(NodeVisitor):
#
# yield "}"
#
# def visit_lvalue(self, lvalue: ast.expr, declare: bool | list[bool] = False) -> Iterable[str]:
# if isinstance(lvalue, ast.Tuple):
# for name, decl, ty in zip(lvalue.elts, declare, lvalue.type.args):
# if decl:
# yield from self.visit_lvalue(name, True)
# yield ";"
# yield f"std::tie({', '.join(flatmap(self.visit_lvalue, lvalue.elts))})"
# elif isinstance(lvalue, ast.Name):
# if lvalue.id == "_":
# if not declare:
# yield "std::ignore"
# return
# name = self.fix_name(lvalue.id)
# # if name not in self._scope.vars:
# # if not self.scope.exists_local(name):
# # yield self.scope.declare(name, (" ".join(self.expr().visit(val)), val) if val else None,
# # getattr(val, "is_future", False))
# if declare:
# yield from self.visit(lvalue.type)
# yield name
# elif isinstance(lvalue, ast.Subscript):
# yield from self.expr().visit(lvalue)
# elif isinstance(lvalue, ast.Attribute):
# yield from self.expr().visit(lvalue)
# else:
# raise NotImplementedError(lvalue)
def
visit_lvalue
(
self
,
lvalue
:
ast
.
expr
,
declare
:
IsDeclare
)
->
Iterable
[
str
]:
if
isinstance
(
lvalue
,
ast
.
Tuple
):
raise
NotImplementedError
()
# for name, decl, ty in zip(lvalue.elts, declare, lvalue.type.args):
# if decl:
# yield from self.visit_lvalue(name, True)
# yield ";"
# yield f"std::tie({', '.join(flatmap(self.visit_lvalue, lvalue.elts))})"
elif
isinstance
(
lvalue
,
ast
.
Name
):
if
lvalue
.
id
==
"_"
:
if
not
declare
:
yield
"std::ignore"
return
name
=
self
.
fix_name
(
lvalue
.
id
)
# if name not in self._scope.vars:
# if not self.scope.exists_local(name):
# yield self.scope.declare(name, (" ".join(self.expr().visit(val)), val) if val else None,
# getattr(val, "is_future", False))
if
declare
:
yield
"decltype("
yield
from
self
.
expr
().
visit
(
declare
.
initial_value
)
yield
")"
#yield from self.visit(lvalue.type)
yield
name
elif
isinstance
(
lvalue
,
ast
.
Subscript
):
yield
from
self
.
expr
().
visit
(
lvalue
)
elif
isinstance
(
lvalue
,
ast
.
Attribute
):
yield
from
self
.
expr
().
visit
(
lvalue
)
else
:
raise
NotImplementedError
(
lvalue
)
def
visit_Assign
(
self
,
node
:
ast
.
Assign
)
->
Iterable
[
str
]:
if
len
(
node
.
targets
)
!=
1
:
...
...
@@ -192,3 +197,27 @@ class BlockVisitor(NodeVisitor):
yield
" = "
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
def
visit_For
(
self
,
node
:
ast
.
For
)
->
Iterable
[
str
]:
if
not
isinstance
(
node
.
target
,
ast
.
Name
):
raise
NotImplementedError
(
node
)
if
node
.
orelse
:
yield
"auto"
yield
node
.
orelse_variable
yield
"= true;"
yield
f"for (auto
{
node
.
target
.
id
}
: "
yield
from
self
.
expr
().
visit
(
node
.
iter
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
# TODO: why not reuse the scope used for analysis? same in while
if
node
.
orelse
:
yield
"if ("
yield
node
.
orelse_variable
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
orelse
)
def
emit_block
(
self
,
scope
:
Scope
,
items
:
Iterable
[
ast
.
stmt
])
->
Iterable
[
str
]:
yield
"{"
for
child
in
items
:
yield
from
BlockVisitor
(
scope
,
generator
=
self
.
generator
).
visit
(
child
)
yield
"}"
typon/trans/transpiler/phases/emit_cpp/visitors.py
View file @
b738512a
...
...
@@ -15,6 +15,9 @@ class UniversalVisitor:
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
# __TB_SKIP__ = True
if
orig
:
=
getattr
(
node
,
"orig_node"
,
None
):
node
=
orig
if
type
(
node
)
==
list
:
for
n
in
node
:
yield
from
self
.
visit
(
n
)
...
...
@@ -56,17 +59,28 @@ class NodeVisitor(UniversalVisitor):
match
node
:
case
types
.
TY_INT
:
yield
"
int
"
yield
"
decltype(0_pi)
"
case
types
.
TY_FLOAT
:
yield
"double"
case
types
.
TY_BOOL
:
yield
"bool"
case
types
.
TY_NONE
:
yield
"
void
"
yield
"
typon::TyNone
"
case
types
.
TY_STR
:
yield
"TyStr"
yield
"
typon::
TyStr"
case
types
.
TypeVariable
(
name
):
raise
UnresolvedTypeVariableError
(
node
)
case
types
.
GenericInstanceType
():
yield
from
self
.
visit
(
node
.
generic_parent
)
yield
"<"
yield
from
join
(
","
,
map
(
self
.
visit
,
node
.
generic_args
))
yield
">"
case
types
.
TY_LIST
:
yield
"typon::TyList"
case
types
.
TY_DICT
:
yield
"typon::TyDict"
case
types
.
TY_SET
:
yield
"typon::TySet"
case
_
:
raise
NotImplementedError
(
node
)
...
...
typon/trans/transpiler/phases/typing/block.py
View file @
b738512a
This diff is collapsed.
Click to expand it.
typon/trans/transpiler/phases/typing/class_.py
View file @
b738512a
# coding: utf-8
import
ast
from
dataclasses
import
dataclass
,
field
from
transpiler.phases.typing
import
FunctionType
,
ScopeKind
,
VarDecl
,
VarKind
,
TY_NONE
from
transpiler.phases.typing.common
import
ScoperVisitor
from
transpiler.phases.typing.types
import
PromiseKind
,
Promise
,
BaseType
,
MemberDef
@
dataclass
class
ScoperClassVisitor
(
ScoperVisitor
):
fdecls
:
list
[(
ast
.
FunctionDef
,
BaseType
)]
=
field
(
default_factory
=
list
)
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
):
assert
node
.
value
is
None
,
"Class field should not have a value"
assert
node
.
simple
==
1
,
"Class field should be simple (identifier, not parenthesized)"
assert
isinstance
(
node
.
target
,
ast
.
Name
)
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
=
MemberDef
(
self
.
visit_annotation
(
node
.
annotation
))
def
visit_Assign
(
self
,
node
:
ast
.
Assign
):
assert
len
(
node
.
targets
)
==
1
,
"Can't use destructuring in class static member"
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
.
fields
[
node
.
targets
[
0
].
id
]
=
MemberDef
(
valtype
,
node
.
value
)
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
ftype
=
self
.
parse_function
(
node
)
ftype
.
parameters
[
0
].
unify
(
self
.
scope
.
obj_type
)
inner
=
ftype
.
return_type
if
node
.
name
!=
"__init__"
:
ftype
.
return_type
=
Promise
(
ftype
.
return_type
,
PromiseKind
.
TASK
)
ftype
.
is_method
=
True
self
.
scope
.
obj_type
.
fields
[
node
.
name
]
=
MemberDef
(
ftype
,
node
)
return
(
node
,
inner
)
#
import ast
#
from dataclasses import dataclass, field
#
#
from transpiler.phases.typing import FunctionType, ScopeKind, VarDecl, VarKind, TY_NONE
#
from transpiler.phases.typing.common import ScoperVisitor
#
from transpiler.phases.typing.types import PromiseKind, Promise, BaseType, MemberDef
#
#
#
@dataclass
#
class ScoperClassVisitor(ScoperVisitor):
#
fdecls: list[(ast.FunctionDef, BaseType)] = field(default_factory=list)
#
#
def visit_AnnAssign(self, node: ast.AnnAssign):
#
assert node.value is None, "Class field should not have a value"
#
assert node.simple == 1, "Class field should be simple (identifier, not parenthesized)"
#
assert isinstance(node.target, ast.Name)
#
self.scope.obj_type.fields[node.target.id] = MemberDef(self.visit_annotation(node.annotation))
#
#
def visit_Assign(self, node: ast.Assign):
#
assert len(node.targets) == 1, "Can't use destructuring in class static member"
#
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.fields[node.targets[0].id] = MemberDef(valtype, node.value)
#
#
def visit_FunctionDef(self, node: ast.FunctionDef):
#
ftype = self.parse_function(node)
#
ftype.parameters[0].unify(self.scope.obj_type)
#
inner = ftype.return_type
#
if node.name != "__init__":
#
ftype.return_type = Promise(ftype.return_type, PromiseKind.TASK)
#
ftype.is_method = True
#
self.scope.obj_type.fields[node.name] = MemberDef(ftype, node)
#
return (node, inner)
typon/trans/transpiler/phases/typing/common.py
View file @
b738512a
import
ast
from
dataclasses
import
dataclass
,
field
from
typing
import
Dict
,
Optional
from
typing
import
Dict
,
Optional
,
TYPE_CHECKING
if
TYPE_CHECKING
:
from
transpiler.phases.typing.expr
import
ScoperExprVisitor
from
transpiler.utils
import
highlight
from
transpiler.phases.typing.annotations
import
TypeAnnotationVisitor
from
transpiler.phases.typing.scope
import
Scope
,
ScopeKind
,
VarDecl
,
VarKind
...
...
@@ -10,6 +12,7 @@ from transpiler.phases.utils import NodeVisitorSeq, AnnotationName
PRELUDE
=
Scope
.
make_global
()
@
dataclass
class
ScoperVisitor
(
NodeVisitorSeq
):
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
.
child
(
ScopeKind
.
GLOBAL
))
...
...
@@ -93,10 +96,11 @@ class ScoperVisitor(NodeVisitorSeq):
elif
len
(
visitor
.
fdecls
)
==
1
:
fnode
,
frtype
=
visitor
.
fdecls
[
0
]
self
.
visit_function_definition
(
fnode
,
frtype
)
#del node.inner_scope.vars[fnode.name]
#
del node.inner_scope.vars[fnode.name]
visitor
.
visit_assign_target
(
ast
.
Name
(
fnode
.
name
),
fnode
.
type
)
b
.
decls
=
decls
if
not
node
.
inner_scope
.
diverges
and
not
(
isinstance
(
node
.
type
.
return_type
,
Promise
)
and
node
.
type
.
return_type
.
kind
==
PromiseKind
.
GENERATOR
):
if
not
node
.
inner_scope
.
diverges
and
not
(
isinstance
(
node
.
type
.
return_type
,
Promise
)
and
node
.
type
.
return_type
.
kind
==
PromiseKind
.
GENERATOR
):
from
transpiler.phases.typing.exceptions
import
TypeMismatchError
try
:
rtype
.
unify
(
TY_NONE
)
...
...
@@ -104,21 +108,28 @@ class ScoperVisitor(NodeVisitorSeq):
from
transpiler.phases.typing.exceptions
import
MissingReturnError
raise
MissingReturnError
(
node
)
from
e
def
get_iter
(
seq_type
):
try
:
iter_type
=
seq_type
.
fields
[
"__iter__"
].
type
.
return_type
except
:
from
transpiler.phases.typing.exceptions
import
NotIterableError
raise
NotIterableError
(
seq_type
)
return
iter_type
def
get_next
(
iter_type
):
try
:
next_type
=
iter_type
.
fields
[
"__next__"
].
type
.
return_type
except
:
from
transpiler.phases.typing.exceptions
import
NotIteratorError
raise
NotIteratorError
(
iter_type
)
return
next_type
def
get_iter
(
self
,
seq_type
):
try
:
return
self
.
expr
().
visit_function_call
(
self
.
expr
().
visit_getattr
(
seq_type
,
"__iter__"
),
[])
except
:
from
transpiler.phases.typing.exceptions
import
NotIterableError
raise
NotIterableError
(
seq_type
)
def
get_next
(
self
,
iter_type
):
try
:
return
self
.
expr
().
visit_function_call
(
self
.
expr
().
visit_getattr
(
iter_type
,
"__next__"
),
[])
except
:
from
transpiler.phases.typing.exceptions
import
NotIterableError
raise
NotIterableError
(
iter_type
)
def
is_builtin
(
x
,
feature
):
return
isinstance
(
x
,
BuiltinFeatureType
)
and
x
.
feature
()
==
feature
\ No newline at end of file
return
isinstance
(
x
,
BuiltinFeatureType
)
and
x
.
feature
()
==
feature
@
dataclass
class
DeclareInfo
:
initial_value
:
Optional
[
ast
.
expr
]
=
None
IsDeclare
=
None
|
DeclareInfo
typon/trans/transpiler/phases/typing/expr.py
View file @
b738512a
...
...
@@ -4,7 +4,7 @@ import inspect
from
itertools
import
zip_longest
from
typing
import
List
from
transpiler.phases.typing.common
import
ScoperVisitor
,
get_iter
,
get_next
,
is_builtin
from
transpiler.phases.typing.common
import
ScoperVisitor
,
is_builtin
from
transpiler.phases.typing.exceptions
import
ArgumentCountMismatchError
,
TypeMismatchKind
,
TypeMismatchError
from
transpiler.phases.typing.types
import
BaseType
,
TY_STR
,
TY_BOOL
,
TY_INT
,
TY_COMPLEX
,
TY_FLOAT
,
TY_NONE
,
\
ClassTypeType
,
ResolvedConcreteType
,
GenericType
,
CallableInstanceType
,
TY_LIST
,
TY_SET
,
TY_DICT
,
RuntimeValue
,
\
...
...
@@ -141,7 +141,12 @@ class ScoperExprVisitor(ScoperVisitor):
if
not
a
.
try_assign
(
b
):
raise
TypeMismatchError
(
a
,
b
,
TypeMismatchKind
.
DIFFERENT_TYPE
)
return
ftype
.
return_type
if
not
ftype
.
is_native
:
from
transpiler.phases.typing.block
import
ScoperBlockVisitor
vis
=
ScoperBlockVisitor
(
ftype
.
block_data
.
scope
)
for
stmt
in
ftype
.
block_data
.
node
.
body
:
vis
.
visit
(
stmt
)
return
ftype
.
return_type
.
resolve
()
# if isinstance(ftype, TypeType):# and isinstance(ftype.type_object, UserType):
# init: FunctionType = self.visit_getattr(ftype, "__init__").remove_self()
# init.return_type = ftype.type_object
...
...
@@ -176,6 +181,10 @@ class ScoperExprVisitor(ScoperVisitor):
node
.
body
.
decls
=
decls
return
ftype
def
visit_BinOp
(
self
,
node
:
ast
.
BinOp
)
->
BaseType
:
left
,
right
=
map
(
self
.
visit
,
(
node
.
left
,
node
.
right
))
return
TypeVariable
()
# TODO
# def visit_BinOp(self, node: ast.BinOp) -> BaseType:
# left, right = map(self.visit, (node.left, node.right))
# return self.make_dunder([left, right], DUNDER[type(node.op)])
...
...
@@ -300,14 +309,15 @@ class ScoperExprVisitor(ScoperVisitor):
if
len
(
node
.
generators
)
!=
1
:
raise
NotImplementedError
(
"Multiple generators not handled yet"
)
gen
:
ast
.
comprehension
=
node
.
generators
[
0
]
iter_type
=
get_iter
(
self
.
visit
(
gen
.
iter
))
node
.
input_item_type
=
get_next
(
iter_type
)
iter_type
=
self
.
get_iter
(
self
.
visit
(
gen
.
iter
))
node
.
input_item_type
=
self
.
get_next
(
iter_type
)
virt_scope
=
self
.
scope
.
child
(
ScopeKind
.
FUNCTION_INNER
)
from
transpiler
import
ScoperBlockVisitor
from
transpiler
.phases.typing.block
import
ScoperBlockVisitor
visitor
=
ScoperBlockVisitor
(
virt_scope
)
visitor
.
visit_assign_target
(
gen
.
target
,
node
.
input_item_type
)
node
.
item_type
=
visitor
.
expr
().
visit
(
node
.
elt
)
for
if_
in
gen
.
ifs
:
visitor
.
expr
().
visit
(
if_
)
#
for if_ in gen.ifs:
#
visitor.expr().visit(if_)
gen
.
ifs_node
=
ast
.
BoolOp
(
ast
.
And
(),
gen
.
ifs
,
**
linenodata
(
node
))
return
TyList
(
node
.
item_type
)
\ No newline at end of file
visitor
.
expr
().
visit
(
gen
.
ifs_node
)
return
TY_LIST
.
instantiate
([
node
.
item_type
])
\ No newline at end of file
typon/trans/transpiler/phases/typing/modules.py
View file @
b738512a
...
...
@@ -4,7 +4,7 @@ from logging import debug
from
transpiler.phases.typing
import
PRELUDE
from
transpiler.phases.typing.scope
import
Scope
,
VarKind
,
VarDecl
,
ScopeKind
from
transpiler.phases.typing.types
import
MemberDef
,
ResolvedConcreteType
,
UniqueTypeMixin
from
transpiler.phases.typing.types
import
MemberDef
,
ResolvedConcreteType
,
UniqueTypeMixin
,
BlockData
class
ModuleType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
...
...
@@ -21,39 +21,44 @@ def make_module(name: str, scope: Scope) -> ModuleType:
visited_modules
=
{}
def
parse_module
(
mod_name
:
str
,
python_path
:
Path
,
scope
=
None
,
preprocess
=
None
):
path
=
python_path
/
mod_name
def
parse_module
(
mod_name
:
str
,
python_path
:
list
[
Path
],
scope
=
None
,
preprocess
=
None
)
->
ModuleType
:
for
path
in
python_path
:
path
=
path
/
mod_name
if
not
path
.
exists
():
path
=
path
.
with_suffix
(
".py"
)
if
not
path
.
exists
():
path
=
path
.
with_suffix
(
".py"
)
if
not
path
.
exists
():
path
=
path
.
with_stem
(
mod_name
+
"_"
)
if
not
path
.
exists
():
path
=
path
.
with_stem
(
mod_name
+
"_"
)
if
not
path
.
exists
():
raise
FileNotFoundError
(
f"Could not find
{
path
}
"
)
if
not
path
.
exists
():
continue
if
path
.
is_dir
():
real_path
=
path
/
"__init__.py"
break
else
:
real_path
=
path
raise
FileNotFoundError
(
f"Could not find
{
mod_name
}
"
)
if
path
.
is_dir
():
path
=
path
/
"__init__.py"
if
mod
:
=
visited_modules
.
get
(
real_
path
.
as_posix
()):
return
mod
if
mod
:
=
visited_modules
.
get
(
path
.
as_posix
()):
return
mod
.
type
mod_scope
=
scope
or
PRELUDE
.
child
(
ScopeKind
.
GLOBAL
)
if
real_path
.
suffix
==
".py"
:
from
transpiler.phases.typing.stdlib
import
StdlibVisitor
node
=
ast
.
parse
(
real_path
.
read_text
())
if
preprocess
:
node
=
preprocess
(
node
)
StdlibVisitor
(
python_path
,
mod_scope
).
visit
(
node
)
else
:
if
path
.
suffix
!=
".py"
:
raise
NotImplementedError
(
f"Unsupported file type
{
path
.
suffix
}
"
)
from
transpiler.phases.typing.stdlib
import
StdlibVisitor
node
=
ast
.
parse
(
path
.
read_text
())
if
preprocess
:
node
=
preprocess
(
node
)
from
transpiler.transpiler
import
TYPON_STD
StdlibVisitor
(
python_path
,
mod_scope
,
is_native
=
TYPON_STD
in
path
.
parents
).
visit
(
node
)
mod
=
make_module
(
mod_name
,
mod_scope
)
visited_modules
[
real_path
.
as_posix
()]
=
VarDecl
(
VarKind
.
LOCAL
,
mod
,
{
k
:
v
.
type
for
k
,
v
in
mod_scope
.
vars
.
items
()})
mod
.
block_data
=
BlockData
(
node
,
mod_scope
)
visited_modules
[
path
.
as_posix
()]
=
VarDecl
(
VarKind
.
LOCAL
,
mod
)
return
mod
# def process_module(mod_path: Path, scope):
...
...
typon/trans/transpiler/phases/typing/stdlib.py
View file @
b738512a
...
...
@@ -75,9 +75,10 @@ def visit_generic_item(
@
dataclass
class
StdlibVisitor
(
NodeVisitorSeq
):
python_path
:
Path
python_path
:
list
[
Path
]
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
)
cur_class
:
Optional
[
ResolvedConcreteType
]
=
None
is_native
:
bool
=
False
def
resolve_module_import
(
self
,
name
:
str
):
# tries = [
...
...
@@ -88,7 +89,7 @@ class StdlibVisitor(NodeVisitorSeq):
# if path.exists():
# return path
# raise FileNotFoundError(f"Could not find module {name}")
return
parse_module
(
name
,
self
.
python_path
)
return
parse_module
(
name
,
self
.
python_path
,
self
.
scope
.
child
(
ScopeKind
.
GLOBAL
)
)
def
expr
(
self
)
->
ScoperExprVisitor
:
return
ScoperExprVisitor
(
self
.
scope
)
...
...
@@ -122,7 +123,7 @@ class StdlibVisitor(NodeVisitorSeq):
for
alias
in
node
.
names
:
mod
=
self
.
resolve_module_import
(
alias
.
name
)
alias
.
module_obj
=
mod
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
mod
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
mod
)
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
if
existing
:
=
self
.
scope
.
get
(
node
.
name
):
...
...
@@ -137,7 +138,7 @@ class StdlibVisitor(NodeVisitorSeq):
cl_scope
=
scope
.
child
(
ScopeKind
.
CLASS
)
cl_scope
.
declare_local
(
"Self"
,
output
.
type_type
())
output
.
block_data
=
BlockData
(
node
,
scope
)
visitor
=
StdlibVisitor
(
self
.
python_path
,
cl_scope
,
output
)
visitor
=
StdlibVisitor
(
self
.
python_path
,
cl_scope
,
output
,
self
.
is_native
)
bases
=
[
self
.
anno
().
visit
(
base
)
for
base
in
node
.
bases
]
match
bases
:
case
[]:
...
...
@@ -163,6 +164,7 @@ class StdlibVisitor(NodeVisitorSeq):
output
.
return_type
=
arg_visitor
.
visit
(
node
.
returns
)
output
.
optional_at
=
len
(
node
.
args
.
args
)
-
len
(
node
.
args
.
defaults
)
output
.
is_variadic
=
args
.
vararg
is
not
None
output
.
is_native
=
self
.
is_native
@
dataclass
(
eq
=
False
,
init
=
False
)
class
InstanceType
(
CallableInstanceType
):
...
...
typon/trans/transpiler/phases/typing/types.py
View file @
b738512a
...
...
@@ -78,7 +78,10 @@ class BaseType(ABC):
return
(
needle
is
haystack
)
or
haystack
.
contains_internal
(
needle
)
def
try_assign
(
self
,
other
:
"BaseType"
)
->
bool
:
return
self
.
resolve
().
try_assign_internal
(
other
.
resolve
())
target
,
value
=
self
.
resolve
(),
other
.
resolve
()
if
type
(
value
)
==
TypeVariable
:
return
BaseType
.
try_assign_internal
(
target
,
other
)
return
target
.
try_assign_internal
(
other
)
def
try_assign_internal
(
self
,
other
:
"BaseType"
)
->
bool
:
...
...
@@ -489,6 +492,7 @@ class CallableInstanceType(GenericInstanceType, MethodType):
return_type
:
ConcreteType
optional_at
:
int
=
None
is_variadic
:
bool
=
False
is_native
:
bool
=
False
def
__post_init__
(
self
):
if
self
.
optional_at
is
None
and
self
.
parameters
is
not
None
:
...
...
@@ -560,6 +564,8 @@ def make_builtin_feature(name: str):
return
TY_OPTIONAL
case
"Union"
:
return
TY_UNION
case
"Callable"
:
return
TY_CALLABLE
case
_
:
class
CreatedType
(
BuiltinFeatureType
):
def
name
(
self
):
...
...
typon/trans/transpiler/transpiler.py
View file @
b738512a
# coding: utf-8
import
ast
from
pathlib
import
Path
import
colorama
...
...
@@ -14,14 +15,16 @@ from transpiler.phases.emit_cpp.module import emit_module
from
transpiler.phases.if_main
import
IfMainVisitor
from
transpiler.phases.typing
import
PRELUDE
from
transpiler.phases.typing.modules
import
parse_module
from
transpiler.phases.typing.stdlib
import
StdlibVisitor
TYPON_STD
=
Path
(
__file__
).
parent
.
parent
/
"stdlib"
def
init
():
error_display
.
init
()
colorama
.
init
()
typon_std
=
Path
(
__file__
).
parent
.
parent
/
"stdlib"
#discover_module(typon_std, PRELUDE.child(ScopeKind.GLOBAL))
parse_module
(
"builtins"
,
typon_std
,
PRELUDE
)
parse_module
(
"builtins"
,
[
TYPON_STD
]
,
PRELUDE
)
...
...
@@ -35,7 +38,7 @@ def transpile(source, name: str, path: Path):
node
=
DesugarOp
().
visit
(
node
)
return
node
module
=
parse_module
(
path
.
stem
,
path
.
parent
,
preprocess
=
preprocess
)
module
=
parse_module
(
path
.
stem
,
[
path
.
parent
,
TYPON_STD
]
,
preprocess
=
preprocess
)
def
disp_scope
(
scope
,
indent
=
0
):
debug
(
" "
*
indent
,
scope
.
kind
)
...
...
@@ -44,6 +47,8 @@ def transpile(source, name: str, path: Path):
for
var
in
scope
.
vars
.
items
():
debug
(
" "
*
(
indent
+
1
),
var
)
StdlibVisitor
([],
module
.
block_data
.
scope
).
expr
().
visit
(
ast
.
parse
(
"main()"
,
mode
=
"eval"
).
body
)
def
main_module
():
yield
from
emit_module
(
module
)
yield
"#ifdef TYPON_EXTENSION"
...
...
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