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
90409113
Commit
90409113
authored
Feb 08, 2024
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
work
parent
8fd5e9fb
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1019 additions
and
679 deletions
+1019
-679
notes2.txt
notes2.txt
+2
-0
typon/trans/tests/user_generics.py
typon/trans/tests/user_generics.py
+4
-0
typon/trans/transpiler/__init__.py
typon/trans/transpiler/__init__.py
+34
-11
typon/trans/transpiler/phases/emit_cpp/__init__.py
typon/trans/transpiler/phases/emit_cpp/__init__.py
+0
-154
typon/trans/transpiler/phases/emit_cpp/class_.py
typon/trans/transpiler/phases/emit_cpp/class_.py
+34
-137
typon/trans/transpiler/phases/emit_cpp/function.py
typon/trans/transpiler/phases/emit_cpp/function.py
+161
-108
typon/trans/transpiler/phases/emit_cpp/module.py
typon/trans/transpiler/phases/emit_cpp/module.py
+30
-222
typon/trans/transpiler/phases/emit_cpp/visitors.py
typon/trans/transpiler/phases/emit_cpp/visitors.py
+92
-0
typon/trans/transpiler/phases/emit_cpp2/__init__.py
typon/trans/transpiler/phases/emit_cpp2/__init__.py
+133
-0
typon/trans/transpiler/phases/emit_cpp2/block.py
typon/trans/transpiler/phases/emit_cpp2/block.py
+1
-1
typon/trans/transpiler/phases/emit_cpp2/class_.py
typon/trans/transpiler/phases/emit_cpp2/class_.py
+137
-0
typon/trans/transpiler/phases/emit_cpp2/consts.py
typon/trans/transpiler/phases/emit_cpp2/consts.py
+0
-0
typon/trans/transpiler/phases/emit_cpp2/expr.py
typon/trans/transpiler/phases/emit_cpp2/expr.py
+6
-24
typon/trans/transpiler/phases/emit_cpp2/file.py
typon/trans/transpiler/phases/emit_cpp2/file.py
+0
-0
typon/trans/transpiler/phases/emit_cpp2/function.py
typon/trans/transpiler/phases/emit_cpp2/function.py
+126
-0
typon/trans/transpiler/phases/emit_cpp2/module.py
typon/trans/transpiler/phases/emit_cpp2/module.py
+224
-0
typon/trans/transpiler/phases/emit_cpp2/search.py
typon/trans/transpiler/phases/emit_cpp2/search.py
+0
-0
typon/trans/transpiler/phases/typing/modules.py
typon/trans/transpiler/phases/typing/modules.py
+13
-11
typon/trans/transpiler/phases/typing/scope.py
typon/trans/transpiler/phases/typing/scope.py
+1
-0
typon/trans/transpiler/phases/typing/stdlib.py
typon/trans/transpiler/phases/typing/stdlib.py
+16
-10
typon/trans/transpiler/phases/typing/types.py
typon/trans/transpiler/phases/typing/types.py
+5
-1
No files found.
notes2.txt
View file @
90409113
...
...
@@ -64,3 +64,5 @@ fonction : type concret qui a un type caché qui correspond à ce qui sera gén
pareil pour les classes
donc on peut passer des types génériques puisqu'ils sont wrappés par un type concret
----------------
faire des tags v0.1 v0.2 pour proto 1 et version qui marche
\ No newline at end of file
typon/trans/tests/user_generics.py
View file @
90409113
...
...
@@ -20,3 +20,7 @@
# b = Thing[str]("abc")
# print(a)
# print(b)
if
__name__
==
"__main__"
:
x
=
5
\ No newline at end of file
typon/trans/transpiler/__init__.py
View file @
90409113
...
...
@@ -13,8 +13,10 @@ import colorama
from
transpiler.phases.desugar_compare
import
DesugarCompare
from
transpiler.phases.desugar_op
import
DesugarOp
from
transpiler.phases.emit_cpp.module
import
emit_module
from
transpiler.phases.typing
import
PRELUDE
from
transpiler.phases.typing.modules
import
parse_module
from
transpiler.phases.typing.stdlib
import
StdlibVisitor
colorama
.
init
()
...
...
@@ -182,19 +184,18 @@ typon_std = Path(__file__).parent.parent / "stdlib"
parse_module
(
"builtins"
,
typon_std
,
PRELUDE
)
def
transpile
(
source
,
name
:
str
,
path
=
None
):
def
transpile
(
source
,
name
:
str
,
path
:
Path
):
__TB__
=
f"transpiling module
{
cf
.
white
(
name
)
}
"
res
=
ast
.
parse
(
source
,
type_comments
=
True
)
exit
()
IfMainVisitor
().
visit
(
res
)
res
=
DesugarWith
().
visit
(
res
)
res
=
DesugarCompare
().
visit
(
res
)
res
=
DesugarOp
().
visit
(
res
)
#ScoperBlockVisitor().visit(res)
# print(res.scope)
def
preprocess
(
node
):
IfMainVisitor
().
visit
(
node
)
node
=
DesugarWith
().
visit
(
node
)
node
=
DesugarCompare
().
visit
(
node
)
node
=
DesugarOp
().
visit
(
node
)
return
node
module
=
parse_module
(
path
.
stem
,
path
.
parent
,
preprocess
=
preprocess
)
# display each scope
def
disp_scope
(
scope
,
indent
=
0
):
debug
(
" "
*
indent
,
scope
.
kind
)
for
child
in
scope
.
children
:
...
...
@@ -202,7 +203,29 @@ def transpile(source, name: str, path=None):
for
var
in
scope
.
vars
.
items
():
debug
(
" "
*
(
indent
+
1
),
var
)
disp_scope
(
res
.
scope
)
def
main_module
():
yield
from
emit_module
(
module
)
yield
"#ifdef TYPON_EXTENSION"
# yield f"PYBIND11_MODULE({self.module_name}, m) {{"
# yield f"m.doc() = \"Typon extension module '{self.module_name}'\";"
# visitor = ModuleVisitorExt(self.scope)
# code = [line for stmt in node.body for line in visitor.visit(stmt)]
# yield from code
# yield "}"
yield
"#else"
yield
"typon::Root root() const {"
yield
f"co_await dot(PROGRAMNS::
{
module
.
name
()
}
, main)();"
yield
"}"
yield
"int main(int argc, char* argv[]) {"
yield
"py_sys::all.argv = typon::PyList<PyStr>(std::vector<PyStr>(argv, argv + argc));"
yield
f"root().call();"
yield
"}"
yield
"#endif"
code
=
"
\
n
"
.
join
(
filter
(
None
,
main_module
()))
return
code
exit
()
assert
isinstance
(
res
,
ast
.
Module
)
...
...
typon/trans/transpiler/phases/emit_cpp/__init__.py
View file @
90409113
# coding: utf-8
import
ast
import
enum
from
enum
import
Flag
from
itertools
import
chain
from
typing
import
Iterable
from
transpiler.phases.emit_cpp.consts
import
MAPPINGS
from
transpiler.phases.typing
import
TypeVariable
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
,
\
TypeType
,
TypeOperator
,
TY_FLOAT
,
FunctionType
,
UnionType
from
transpiler.utils
import
UnsupportedNodeError
,
highlight
class
UniversalVisitor
:
def
visit
(
self
,
node
):
"""Visit a node."""
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
# __TB_SKIP__ = True
if
type
(
node
)
==
list
:
for
n
in
node
:
yield
from
self
.
visit
(
n
)
else
:
for
parent
in
node
.
__class__
.
__mro__
:
if
visitor
:
=
getattr
(
self
,
'visit_'
+
parent
.
__name__
,
None
):
yield
from
visitor
(
node
)
break
else
:
yield
from
self
.
missing_impl
(
node
)
def
missing_impl
(
self
,
node
):
raise
UnsupportedNodeError
(
node
)
class
NodeVisitor
(
UniversalVisitor
):
def
process_args
(
self
,
node
:
ast
.
arguments
)
->
(
str
,
str
,
str
):
for
field
in
(
"posonlyargs"
,
"vararg"
,
"kwonlyargs"
,
"kw_defaults"
,
"kwarg"
,
"defaults"
):
if
getattr
(
node
,
field
,
None
):
raise
NotImplementedError
(
node
,
field
)
if
not
node
.
args
:
return
""
,
"()"
,
[]
f_args
=
[(
self
.
fix_name
(
arg
.
arg
),
f"T
{
i
+
1
}
"
)
for
i
,
arg
in
enumerate
(
node
.
args
)]
return
(
"<"
+
", "
.
join
(
f"typename
{
t
}
"
for
_
,
t
in
f_args
)
+
">"
,
"("
+
", "
.
join
(
f"
{
t
}
{
n
}
"
for
n
,
t
in
f_args
)
+
")"
,
[
n
for
n
,
_
in
f_args
]
)
def
fix_name
(
self
,
name
:
str
)
->
str
:
if
name
.
startswith
(
"__"
)
and
name
.
endswith
(
"__"
):
return
f"py_
{
name
[
2
:
-
2
]
}
"
return
MAPPINGS
.
get
(
name
,
name
)
def
visit_BaseType
(
self
,
node
:
BaseType
)
->
Iterable
[
str
]:
node
=
node
.
resolve
()
if
node
is
TY_INT
:
yield
"int"
elif
node
is
TY_FLOAT
:
yield
"double"
elif
node
is
TY_BOOL
:
yield
"bool"
elif
node
is
TY_NONE
:
yield
"void"
elif
node
is
TY_STR
:
yield
"PyStr"
elif
isinstance
(
node
,
UserType
):
# if node.is_reference:
# yield "PyObj<"
#yield "auto"
yield
f"referencemodel::Rc<__main____oo<>::
{
node
.
name
}
__oo<>::Obj>"
# if node.is_reference:
# yield "::py_type>"
elif
isinstance
(
node
,
TypeType
):
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
):
yield
"typon::"
if
node
.
kind
==
PromiseKind
.
TASK
:
yield
"Task"
elif
node
.
kind
==
PromiseKind
.
JOIN
:
yield
"Join"
elif
node
.
kind
==
PromiseKind
.
FUTURE
:
yield
"Future"
elif
node
.
kind
==
PromiseKind
.
FORKED
:
yield
"Forked"
elif
node
.
kind
==
PromiseKind
.
GENERATOR
:
yield
"Generator"
else
:
raise
NotImplementedError
(
node
)
yield
"<"
yield
from
self
.
visit
(
node
.
return_type
)
yield
">"
elif
isinstance
(
node
,
TypeVariable
):
# yield f"TYPEVAR_{node.name}";return
raise
UnresolvedTypeVariableError
(
node
)
elif
isinstance
(
node
,
UnionType
)
and
(
ty
:
=
node
.
is_optional
()):
yield
"std::optional<"
yield
from
self
.
visit
(
ty
)
yield
">"
elif
isinstance
(
node
,
TypeOperator
):
yield
"typon::Py"
+
node
.
name
.
title
()
if
node
.
args
:
yield
"<"
yield
from
join
(
", "
,
map
(
self
.
visit
,
node
.
args
))
yield
">"
else
:
raise
NotImplementedError
(
node
)
class
CoroutineMode
(
Flag
):
SYNC
=
1
FAKE
=
2
|
SYNC
ASYNC
=
4
GENERATOR
=
8
|
ASYNC
TASK
=
16
|
ASYNC
JOIN
=
32
|
ASYNC
class
FunctionEmissionKind
(
enum
.
Enum
):
DECLARATION
=
enum
.
auto
()
DEFINITION
=
enum
.
auto
()
METHOD
=
enum
.
auto
()
LAMBDA
=
enum
.
auto
()
def
join
(
sep
:
str
,
items
:
Iterable
[
Iterable
[
str
]])
->
Iterable
[
str
]:
items
=
iter
(
items
)
try
:
it
=
next
(
items
)
if
type
(
it
)
is
str
:
yield
it
else
:
yield
from
it
for
item
in
items
:
yield
sep
it
=
item
if
type
(
it
)
is
str
:
yield
it
else
:
yield
from
it
except
StopIteration
:
return
def
flatmap
(
f
,
items
):
return
chain
.
from_iterable
(
map
(
f
,
items
))
typon/trans/transpiler/phases/emit_cpp/class_.py
View file @
90409113
# coding: utf-8
import
ast
from
typing
import
Iterable
from
dataclasses
import
dataclass
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.emit_cpp
import
NodeVisitor
,
FunctionEmissionKind
def
emit_class
(
clazz
)
->
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
}\
"
;"
class
ClassVisitor
(
NodeVisitor
):
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
inner
=
ClassInnerVisitor2
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
f"struct
{
node
.
name
}
_s;"
yield
f"extern
{
node
.
name
}
_s
{
node
.
name
}
;"
yield
f"struct
{
node
.
name
}
_s {{"
yield
f"struct Obj : referencemodel::instance<
{
node
.
name
}
__oo<>, Obj> {{"
yield
"struct py_type {"
inner
=
ClassInnerVisitor
(
node
.
inner_scope
)
inner
=
ClassInnerVisitor4
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
"template<typename... T> py_type(T&&... args) {"
yield
"__init__(this, std::forward<T>(args)...);"
yield
"}"
yield
"py_type() {}"
yield
"py_type(const py_type&) = delete;"
yield
"py_type(py_type&&) = delete;"
if
getattr
(
node
.
type
,
"is_enum"
,
False
):
yield
"int value;"
yield
"operator int() const { return value; }"
yield
"void py_repr(std::ostream &s) const {"
yield
f's << "
{
node
.
name
}
.";'
yield
"}"
else
:
yield
"void py_repr(std::ostream &s) const {"
yield
f's << "
{
node
.
name
}
(";'
for
i
,
(
name
,
memb
)
in
enumerate
(
node
.
type
.
get_members
().
items
()):
if
i
!=
0
:
yield
's << ", ";'
yield
f's << "
{
name
}
=";'
yield
f"repr_to(
{
name
}
, s);"
yield
"s << ')';"
yield
"template <typename... U>"
yield
"Obj(U&&... args) {"
yield
"dot(this, __init__)(this, std::forward<U>(args)...);"
yield
"}"
yield
"void py_print(std::ostream &s) const {"
yield
"py_repr(s);"
yield
"}"
yield
"};"
yield
"template<typename... T> auto operator()(T&&... args) {"
yield
"return pyobj<py_type>(std::forward<T>(args)...);"
yield
"template <typename... T>"
yield
"auto operator() (T&&... args) const {"
yield
"return referencemodel::rc(Obj{std::forward<T>(args)...});"
yield
"}"
# outer = ClassOuterVisitor(node.inner_scope)
# for stmt in node.body:
# yield from outer.visit(stmt)
yield
f"}}
{
node
.
name
}
;"
@
dataclass
class
ClassInnerVisitor
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
member
=
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
yield
from
self
.
visit
(
member
.
type
)
yield
node
.
target
.
id
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
]:
# yield "struct {"
# yield "type* self;"
# from transpiler.phases.emit_cpp.block import BlockVisitor
# yield from BlockVisitor(self.scope).visit_func_new(node, FunctionEmissionKind.METHOD, True)
# yield f"}} {node.name} {{ this }};"
yield
f"struct
{
node
.
name
}
_m_s : referencemodel::method {{"
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
yield
from
BlockVisitor
(
self
.
scope
).
visit_func_new
(
node
,
FunctionEmissionKind
.
METHOD
)
yield
f"}} static constexpr
{
node
.
name
}
{{}};"
yield
""
@
dataclass
class
ClassOuterVisitor
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
yield
""
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"struct {"
yield
"template<typename Self, typename... T>"
yield
"auto operator()(Self self, T&&... args) {"
yield
f"return dotp(self,
{
node
.
name
}
)(std::forward<T>(args)...);"
yield
"}"
yield
f"}}
{
node
.
name
}
;"
yield
""
# yield "struct : function {"
# from transpiler.phases.emit_cpp.block import BlockVisitor
# yield from BlockVisitor(self.scope).visit_func_new(node, FunctionEmissionKind.METHOD)
# yield f"}} static constexpr {node.name} {{}};"
@
dataclass
class
ClassInnerVisitor2
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
yield
""
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"struct : referencemodel::method {"
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
yield
from
BlockVisitor
(
self
.
scope
).
visit_func_new
(
node
,
FunctionEmissionKind
.
METHOD
)
yield
f"}} static constexpr
{
node
.
name
}
{{}};"
@
dataclass
class
ClassInnerVisitor4
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
member
=
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
yield
from
self
.
visit
(
member
.
type
)
yield
node
.
target
.
id
yield
";"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
""
\ No newline at end of file
yield
f"}};"
yield
f"static constexpr
{
node
.
name
}
__oo<>
{
node
.
name
}
{{}};"
yield
f"static_assert(sizeof
{
node
.
name
}
== 1);"
\ No newline at end of file
typon/trans/transpiler/phases/emit_cpp/function.py
View file @
90409113
# coding: utf-8
import
ast
from
dataclasses
import
dataclass
from
typing
import
Iterable
from
transpiler.phases.emit_cpp.consts
import
SYMBOLS
from
transpiler.phases.emit_cpp
import
CoroutineMode
,
FunctionEmissionKind
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.utils
import
PlainBlock
from
transpiler
import
Scope
from
transpiler.phases.emit_cpp.visitors
import
NodeVisitor
,
flatmap
from
transpiler.phases.typing.types
import
CallableInstanceType
# noinspection PyPep8Naming
def
emit_function
(
name
:
str
,
func
:
CallableInstanceType
)
->
Iterable
[
str
]:
yield
f"struct : function {{"
yield
"typon::Task<void> operator()() const {"
yield
"}"
yield
f"}} static constexpr
{
name
}
{{}};"
yield
f"static_assert(sizeof
{
name
}
== 1);"
@
dataclass
class
FunctionVisitor
(
BlockVisitor
):
def
visit_Expr
(
self
,
node
:
ast
.
Expr
)
->
Iterable
[
str
]:
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
class
BlockVisitor
(
NodeVisitor
):
scope
:
Scope
#generator: CoroutineMode = field(default=CoroutineMode.SYNC, kw_only=True)
def
visit_AugAssign
(
self
,
node
:
ast
.
AugAssign
)
->
Iterable
[
str
]
:
yield
from
self
.
visit_lvalue
(
node
.
target
,
False
)
yield
SYMBOLS
[
type
(
node
.
op
)]
+
"="
yield
from
self
.
expr
().
visit
(
node
.
value
)
def
expr
(
self
)
->
ExpressionVisitor
:
return
ExpressionVisitor
(
self
.
scope
,
self
.
generator
)
def
visit_Pass
(
self
,
node
:
ast
.
Pass
)
->
Iterable
[
str
]:
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
# def visit_FunctionDef(self, node: ast.FunctionDef) -> Iterable[str]:
# yield from self.visit_free_func(node)
def
visit_free_func
(
self
,
node
:
ast
.
FunctionDef
,
emission
:
FunctionEmissionKind
)
->
Iterable
[
str
]:
if
getattr
(
node
,
"is_main"
,
False
):
if
emission
==
FunctionEmissionKind
.
DECLARATION
:
return
# Special case handling for Python's interesting way of defining an entry point.
# I mean, it's not *that* bad, it's just an attempt at retrofitting an "entry point" logic in a scripting
# language that, by essence, uses "the start of the file" as the implicit entry point, since files are
# read and executed line-by-line, contrary to usual structured languages that mark a distinction between
# declarations (functions, classes, modules, ...) and code.
# Also, for nitpickers, the C++ standard explicitly allows for omitting a `return` statement in the `main`.
# 0 is returned by default.
yield
"typon::Root root() const"
def
block
():
yield
from
node
.
body
yield
ast
.
Return
()
from
transpiler.phases.emit_cpp.function
import
FunctionVisitor
yield
"{"
yield
from
self
.
visit_func_decls
(
block
(),
node
.
scope
,
CoroutineMode
.
TASK
)
yield
"}"
return
if
emission
==
FunctionEmissionKind
.
DECLARATION
:
yield
f"struct
{
node
.
name
}
_inner {{"
yield
from
self
.
visit_func_new
(
node
,
emission
)
if
emission
==
FunctionEmissionKind
.
DECLARATION
:
yield
f"}}
{
node
.
name
}
;"
def
visit_func_decls
(
self
,
body
:
list
[
ast
.
stmt
],
inner_scope
:
Scope
,
mode
=
CoroutineMode
.
ASYNC
)
->
Iterable
[
str
]:
for
child
in
body
:
from
transpiler.phases.emit_cpp.function
import
FunctionVisitor
child_visitor
=
FunctionVisitor
(
inner_scope
,
generator
=
mode
)
for
name
,
decl
in
getattr
(
child
,
"decls"
,
{}).
items
():
#yield f"decltype({' '.join(self.expr().visit(decl.type))}) {name};"
yield
from
self
.
visit
(
decl
.
type
)
yield
f"
{
name
}
;"
yield
from
child_visitor
.
visit
(
child
)
def
visit_func_params
(
self
,
args
:
Iterable
[
tuple
[
str
,
BaseType
,
Optional
[
ast
.
expr
]]],
emission
:
FunctionEmissionKind
)
->
Iterable
[
str
]:
for
i
,
(
arg
,
argty
,
default
)
in
enumerate
(
args
):
if
i
!=
0
:
yield
", "
if
emission
==
FunctionEmissionKind
.
METHOD
and
i
==
0
:
yield
"Self"
else
:
yield
from
self
.
visit
(
argty
)
yield
arg
if
emission
in
{
FunctionEmissionKind
.
DECLARATION
,
FunctionEmissionKind
.
LAMBDA
,
FunctionEmissionKind
.
METHOD
}
and
default
:
yield
" = "
yield
from
self
.
expr
().
visit
(
default
)
def
visit_func_new
(
self
,
node
:
ast
.
FunctionDef
,
emission
:
FunctionEmissionKind
,
skip_first_arg
:
bool
=
False
)
->
Iterable
[
str
]:
if
emission
==
FunctionEmissionKind
.
LAMBDA
:
yield
"[&]"
else
:
if
emission
==
FunctionEmissionKind
.
METHOD
:
yield
"template <typename Self>"
yield
from
self
.
visit
(
node
.
type
.
return_type
)
if
emission
==
FunctionEmissionKind
.
DEFINITION
:
yield
f"
{
node
.
name
}
_inner::"
yield
"operator()"
yield
"("
padded_defaults
=
[
None
]
*
(
len
(
node
.
args
.
args
)
if
node
.
type
.
optional_at
is
None
else
node
.
type
.
optional_at
)
+
node
.
args
.
defaults
args_iter
=
zip
(
node
.
args
.
args
,
node
.
type
.
parameters
,
padded_defaults
)
if
skip_first_arg
:
next
(
args_iter
)
yield
from
self
.
visit_func_params
(((
arg
.
arg
,
argty
,
default
)
for
arg
,
argty
,
default
in
args_iter
),
emission
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
orelse
)
def
visit_If
(
self
,
node
:
ast
.
If
)
->
Iterable
[
str
]:
yield
"if ("
yield
from
self
.
expr
().
visit
(
node
.
test
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
yield
"else "
if
isinstance
(
node
.
orelse
,
ast
.
If
):
yield
from
self
.
visit
(
node
.
orelse
)
else
:
yield
from
self
.
emit_block
(
node
.
orelse_scope
,
node
.
orelse
)
if
emission
==
FunctionEmissionKind
.
METHOD
:
yield
"const"
def
visit_PlainBlock
(
self
,
node
:
PlainBlock
)
->
Iterable
[
str
]:
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
inner_scope
=
node
.
inner_scope
def
visit_Return
(
self
,
node
:
ast
.
Return
)
->
Iterable
[
str
]:
if
CoroutineMode
.
ASYNC
in
self
.
generator
:
yield
"co_return "
else
:
yield
"return "
if
node
.
value
:
yield
from
self
.
expr
().
visit
(
node
.
value
)
if
emission
==
FunctionEmissionKind
.
DECLARATION
:
yield
";"
return
def
visit_While
(
self
,
node
:
ast
.
While
)
->
Iterable
[
str
]:
if
node
.
orelse
:
yield
"auto"
yield
node
.
orelse_variable
yield
"= true;"
yield
"while ("
yield
from
self
.
expr
().
visit
(
node
.
test
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
yield
"if ("
yield
node
.
orelse_variable
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
orelse
)
if
emission
==
FunctionEmissionKind
.
LAMBDA
:
yield
"->"
yield
from
self
.
visit
(
node
.
type
.
return_type
)
def
visit_Global
(
self
,
node
:
ast
.
Global
)
->
Iterable
[
str
]:
yield
""
yield
"{"
def
visit_Nonlocal
(
self
,
node
:
ast
.
Nonlocal
)
->
Iterable
[
str
]:
yield
""
class
ReturnVisitor
(
SearchVisitor
):
def
visit_Return
(
self
,
node
:
ast
.
Return
)
->
bool
:
yield
True
def
block2
(
self
)
->
"FunctionVisitor"
:
# See the comments in visit_FunctionDef.
# A Python code block does not introduce a new scope, so we create a new `Scope` object that shares the same
# variables as the parent scope.
return
FunctionVisitor
(
self
.
scope
.
child_share
(),
generator
=
self
.
generator
)
def
visit_Yield
(
self
,
node
:
ast
.
Yield
)
->
bool
:
yield
True
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
):
yield
from
()
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
yield
from
()
has_return
=
ReturnVisitor
().
match
(
node
.
body
)
yield
from
self
.
visit_func_decls
(
node
.
body
,
inner_scope
)
# if not has_return and isinstance(node.type.return_type, Promise):
# yield "co_return;"
def
emit_block
(
self
,
scope
:
Scope
,
items
:
Iterable
[
ast
.
stmt
])
->
Iterable
[
str
]:
yield
"{"
for
child
in
items
:
yield
from
FunctionVisitor
(
scope
,
generator
=
self
.
generator
).
visit
(
child
)
yield
"}"
def
visit_Break
(
self
,
node
:
ast
.
Break
)
->
Iterable
[
str
]:
if
(
loop
:
=
self
.
scope
.
is_in_loop
()).
orelse
:
yield
loop
.
orelse_variable
yield
" = false;"
yield
"break;"
def
visit_Try
(
self
,
node
:
ast
.
Try
)
->
Iterable
[
str
]:
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
raise
NotImplementedError
(
node
,
"orelse"
)
if
node
.
finalbody
:
raise
NotImplementedError
(
node
,
"finalbody"
)
for
handler
in
node
.
handlers
:
#yield from self.visit(handler)
pass
# todo
def
visit_Raise
(
self
,
node
:
ast
.
Raise
)
->
Iterable
[
str
]:
yield
"// raise"
# TODO
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"auto"
yield
self
.
fix_name
(
node
.
name
)
yield
"="
yield
from
self
.
visit_func_new
(
node
,
FunctionEmissionKind
.
LAMBDA
)
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_Assign
(
self
,
node
:
ast
.
Assign
)
->
Iterable
[
str
]:
if
len
(
node
.
targets
)
!=
1
:
raise
NotImplementedError
(
node
)
yield
from
self
.
visit_lvalue
(
node
.
targets
[
0
],
node
.
is_declare
)
yield
" = "
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
yield
from
self
.
visit_lvalue
(
node
.
target
,
node
.
is_declare
)
if
node
.
value
:
yield
" = "
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
typon/trans/transpiler/phases/emit_cpp/module.py
View file @
90409113
# coding: utf-8
import
ast
from
typing
import
Iterable
from
dataclasses
import
dataclass
,
field
from
transpiler.phases.typing
import
FunctionType
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.emit_cpp
import
CoroutineMode
,
FunctionEmissionKind
,
NodeVisitor
,
join
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
from
transpiler.phases.emit_cpp.class_
import
ClassVisitor
,
ClassInnerVisitor
,
ClassInnerVisitor2
,
ClassInnerVisitor4
from
transpiler.phases.emit_cpp.function
import
FunctionVisitor
from
transpiler.utils
import
compare_ast
,
highlight
IGNORED_IMPORTS
=
{
"typon"
,
"typing"
,
"__future__"
,
"dataclasses"
,
"enum"
}
# noinspection PyPep8Naming
@
dataclass
class
ModuleVisitor
(
BlockVisitor
):
includes
:
list
[
str
]
=
field
(
default_factory
=
list
)
def
visit_Import
(
self
,
node
:
ast
.
Import
)
->
Iterable
[
str
]:
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
for
alias
in
node
.
names
:
concrete
=
self
.
fix_name
(
alias
.
asname
or
alias
.
name
)
if
alias
.
module_obj
.
is_python
:
yield
f"namespace py_
{
concrete
}
{{"
yield
f"struct
{
concrete
}
_t {{"
for
name
,
obj
in
alias
.
module_obj
.
fields
.
items
():
ty
=
obj
.
type
.
resolve
()
if
getattr
(
ty
,
"python_func_used"
,
False
):
yield
from
self
.
emit_python_func
(
alias
.
name
,
name
,
name
,
ty
)
yield
"} all;"
yield
f"auto& get_all() {{ return all; }}"
yield
"}"
yield
f'auto&
{
concrete
}
= py_
{
concrete
}
::get_all();'
elif
alias
.
name
in
IGNORED_IMPORTS
:
yield
""
else
:
yield
from
self
.
import_module
(
alias
.
name
)
yield
f'auto&
{
concrete
}
= py_
{
alias
.
name
}
::get_all();'
def
import_module
(
self
,
name
:
str
)
->
Iterable
[
str
]:
self
.
includes
.
append
(
f'#include <python/
{
name
}
.hpp>'
)
yield
""
def
emit_python_func
(
self
,
mod
:
str
,
name
:
str
,
alias
:
str
,
fty
:
FunctionType
)
->
Iterable
[
str
]:
__TB__
=
f"emitting C++ code for Python function
{
highlight
(
f'
{
mod
}
.
{
name
}
')
}
"
yield
"struct {"
yield
f"auto operator()("
for
i
,
argty
in
enumerate
(
fty
.
parameters
):
if
i
!=
0
:
yield
", "
yield
"lvalue_or_rvalue<"
yield
from
self
.
visit
(
argty
)
yield
f"> arg
{
i
}
"
yield
") {"
yield
"InterpGuard guard{};"
yield
"try {"
yield
f"return py::module_::import(
\
"
{
mod
}\
"
).attr(
\
"
{
name
}\
"
)("
for
i
,
argty
in
enumerate
(
fty
.
parameters
):
if
i
!=
0
:
yield
", "
yield
f"*arg
{
i
}
"
yield
").cast<"
yield
from
self
.
visit
(
fty
.
return_type
)
yield
">();"
yield
"} catch (py::error_already_set& e) {"
yield
'std::cerr << "Python exception: " << e.what() << std::endl;'
yield
"throw;"
yield
"}"
yield
"}"
yield
f"}}
{
alias
}
;"
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
)
->
Iterable
[
str
]:
if
node
.
module
in
IGNORED_IMPORTS
:
yield
""
elif
node
.
module_obj
.
is_python
:
for
alias
in
node
.
names
:
fty
=
alias
.
item_obj
.
resolve
()
#assert isinstance(fty, FunctionType)
yield
from
self
.
emit_python_func
(
node
.
module
,
alias
.
name
,
alias
.
asname
or
alias
.
name
,
fty
)
else
:
yield
from
self
.
import_module
(
node
.
module
)
for
alias
in
node
.
names
:
yield
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
node
.
module
}
::get_all().
{
alias
.
name
}
;"
def
visit_Expr
(
self
,
node
:
ast
.
Expr
)
->
Iterable
[
str
]:
if
isinstance
(
node
.
value
,
ast
.
Str
):
if
"
\
n
"
in
node
.
value
.
s
:
yield
f"/*
{
node
.
value
.
s
}
*/"
else
:
yield
f"//
{
node
.
value
.
s
}
"
else
:
raise
NotImplementedError
(
node
)
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
#yield from ClassVisitor().visit(node)
yield
from
()
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
super
().
visit_free_func
(
node
,
FunctionEmissionKind
.
DECLARATION
)
@
dataclass
class
ModuleVisitor2
(
NodeVisitor
):
scope
:
Scope
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
BlockVisitor
(
self
.
scope
).
visit_free_func
(
node
,
FunctionEmissionKind
.
DEFINITION
)
def
visit_AST
(
self
,
node
:
ast
.
AST
)
->
Iterable
[
str
]:
yield
""
pass
@
dataclass
class
ModuleVisitor3
(
NodeVisitor
):
scope
:
Scope
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
yield
from
()
return
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
yield
f"static constexpr _detail_<__main__>::
{
node
.
name
}
<>
{
node
.
name
}
{{}};"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
BlockVisitor
(
self
.
scope
).
visit_free_func
(
node
,
FunctionEmissionKind
.
DEFINITION
)
@
dataclass
class
ModuleVisitor4
(
NodeVisitor
):
scope
:
Scope
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
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
}\
"
;"
inner
=
ClassInnerVisitor2
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
f"struct Obj : referencemodel::instance<
{
node
.
name
}
__oo<>, Obj> {{"
inner
=
ClassInnerVisitor4
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
"template <typename... U>"
yield
"Obj(U&&... args) {"
yield
"dot(this, __init__)(this, std::forward<U>(args)...);"
yield
"}"
from
transpiler.phases.emit_cpp.class_
import
emit_class
from
transpiler.phases.emit_cpp.function
import
emit_function
from
transpiler.phases.typing.modules
import
ModuleType
from
transpiler.phases.typing.types
import
CallableInstanceType
,
ClassTypeType
def
emit_module
(
mod
:
ModuleType
)
->
Iterable
[
str
]:
yield
"#include <python/builtins.hpp>"
yield
"#include <python/sys.hpp>"
yield
"namespace PROGRAMNS {"
yield
"template <typename _Unused = void>"
yield
f"struct
{
mod
.
name
()
}
__oo : referencemodel::moduletype<
{
mod
.
name
()
}
__oo<>>"
yield
"{"
for
name
,
field
in
mod
.
fields
.
items
():
if
not
field
.
in_class_def
:
continue
ty
=
field
.
type
.
deref
()
x
=
5
match
ty
:
case
CallableInstanceType
():
yield
from
emit_function
(
name
,
ty
)
case
ClassTypeType
():
yield
from
emit_class
(
ty
)
case
_
:
raise
NotImplementedError
(
f"Unsupported module item type
{
ty
}
"
)
yield
"};"
yield
"template <typename... T>"
yield
"auto operator() (T&&... args) const {"
yield
"return referencemodel::rc(Obj{std::forward<T>(args)...});"
yield
f"constexpr
{
mod
.
name
()
}
__oo<>
{
mod
.
name
()
}
;"
yield
f"static_assert(sizeof
{
mod
.
name
()
}
== 1);"
yield
"}"
yield
f"}};"
yield
f"static constexpr
{
node
.
name
}
__oo<>
{
node
.
name
}
{{}};"
yield
f"static_assert(sizeof
{
node
.
name
}
== 1);"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
()
@
dataclass
class
ModuleVisitorExt
(
NodeVisitor
):
scope
:
Scope
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
if
getattr
(
node
,
"is_main"
,
False
):
yield
from
()
return
#yield from BlockVisitor(self.scope).visit_free_func(node, FunctionEmissionKind.DEFINITION)
#yield f'm.def("{node.name}", CoroWrapper(PROGRAMNS::{node.name}));'
yield
f'm.def("
{
node
.
name
}
", PROGRAMNS::
{
node
.
name
}
);'
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
yield
f"py::class_<PROGRAMNS::
{
node
.
name
}
_s::py_type>(m,
\
"
{
node
.
name
}\
"
)"
if
init
:
=
node
.
type
.
fields
.
get
(
"__init__"
,
None
):
init
=
init
.
type
.
resolve
().
remove_self
()
init_params
=
init
.
parameters
yield
".def(py::init<"
yield
from
join
(
", "
,
map
(
self
.
visit
,
init_params
))
yield
">())"
yield
f'.def("__repr__", [](const PROGRAMNS::
{
node
.
name
}
_s::py_type& self)'
yield
"{ return repr(self); })"
for
f
,
v
in
node
.
type
.
fields
.
items
():
if
f
==
"__init__"
:
continue
if
isinstance
(
v
.
type
,
FunctionType
):
meth
=
v
.
type
.
remove_self
()
yield
f'.def("
{
f
}
", [](const PROGRAMNS::
{
node
.
name
}
_s::py_type& a'
if
meth
.
parameters
:
yield
","
vis
=
BlockVisitor
(
node
.
scope
)
yield
from
vis
.
visit_func_params
(((
f"arg
{
i
}
"
,
ty
,
None
)
for
i
,
ty
in
enumerate
(
meth
.
parameters
)),
FunctionEmissionKind
.
LAMBDA
)
yield
f') {{ return dotp(&a,
{
f
}
)('
if
meth
.
parameters
:
yield
from
join
(
", "
,
(
f"arg
{
i
}
"
for
i
,
_
in
enumerate
(
meth
.
parameters
)))
yield
').call(); })'
else
:
yield
f'.def_readwrite("
{
f
}
", &PROGRAMNS::
{
node
.
name
}
_s::py_type::
{
f
}
)'
yield
";"
pass
def
visit_AST
(
self
,
node
:
ast
.
AST
)
->
Iterable
[
str
]:
yield
from
()
pass
typon/trans/transpiler/phases/emit_cpp/visitors.py
0 → 100644
View file @
90409113
import
ast
from
itertools
import
chain
from
typing
import
Iterable
from
transpiler
import
highlight
import
transpiler.phases.typing.types
as
types
from
transpiler.phases.typing.exceptions
import
UnresolvedTypeVariableError
from
transpiler.phases.typing.types
import
BaseType
from
transpiler.utils
import
UnsupportedNodeError
class
UniversalVisitor
:
def
visit
(
self
,
node
):
"""Visit a node."""
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
# __TB_SKIP__ = True
if
type
(
node
)
==
list
:
for
n
in
node
:
yield
from
self
.
visit
(
n
)
else
:
for
parent
in
node
.
__class__
.
__mro__
:
if
visitor
:
=
getattr
(
self
,
'visit_'
+
parent
.
__name__
,
None
):
yield
from
visitor
(
node
)
break
else
:
yield
from
self
.
missing_impl
(
node
)
def
missing_impl
(
self
,
node
):
raise
UnsupportedNodeError
(
node
)
class
NodeVisitor
(
UniversalVisitor
):
def
process_args
(
self
,
node
:
ast
.
arguments
)
->
(
str
,
str
,
str
):
for
field
in
(
"posonlyargs"
,
"vararg"
,
"kwonlyargs"
,
"kw_defaults"
,
"kwarg"
,
"defaults"
):
if
getattr
(
node
,
field
,
None
):
raise
NotImplementedError
(
node
,
field
)
if
not
node
.
args
:
return
""
,
"()"
,
[]
f_args
=
[(
self
.
fix_name
(
arg
.
arg
),
f"T
{
i
+
1
}
"
)
for
i
,
arg
in
enumerate
(
node
.
args
)]
return
(
"<"
+
", "
.
join
(
f"typename
{
t
}
"
for
_
,
t
in
f_args
)
+
">"
,
"("
+
", "
.
join
(
f"
{
t
}
{
n
}
"
for
n
,
t
in
f_args
)
+
")"
,
[
n
for
n
,
_
in
f_args
]
)
def
fix_name
(
self
,
name
:
str
)
->
str
:
if
name
.
startswith
(
"__"
)
and
name
.
endswith
(
"__"
):
return
f"py_
{
name
[
2
:
-
2
]
}
"
return
MAPPINGS
.
get
(
name
,
name
)
def
visit_BaseType
(
self
,
node
:
BaseType
)
->
Iterable
[
str
]:
node
=
node
.
resolve
()
match
node
:
case
types
.
TY_INT
:
yield
"int"
case
types
.
TY_FLOAT
:
yield
"double"
case
types
.
TY_BOOL
:
yield
"bool"
case
types
.
TY_NONE
:
yield
"void"
case
types
.
TY_STR
:
yield
"PyStr"
case
types
.
TypeVariable
(
name
):
raise
UnresolvedTypeVariableError
(
node
)
case
_
:
raise
NotImplementedError
(
node
)
def
join
(
sep
:
str
,
items
:
Iterable
[
Iterable
[
str
]])
->
Iterable
[
str
]:
items
=
iter
(
items
)
try
:
it
=
next
(
items
)
if
type
(
it
)
is
str
:
yield
it
else
:
yield
from
it
for
item
in
items
:
yield
sep
it
=
item
if
type
(
it
)
is
str
:
yield
it
else
:
yield
from
it
except
StopIteration
:
return
def
flatmap
(
f
,
items
):
return
chain
.
from_iterable
(
map
(
f
,
items
))
typon/trans/transpiler/phases/emit_cpp2/__init__.py
0 → 100644
View file @
90409113
# coding: utf-8
import
ast
import
enum
from
enum
import
Flag
from
itertools
import
chain
from
typing
import
Iterable
from
transpiler.phases.emit_cpp.consts
import
MAPPINGS
from
transpiler.phases.typing
import
TypeVariable
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
,
\
TypeType
,
TypeOperator
,
TY_FLOAT
,
FunctionType
,
UnionType
from
transpiler.utils
import
UnsupportedNodeError
,
highlight
class
UniversalVisitor
:
def
visit
(
self
,
node
):
"""Visit a node."""
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
# __TB_SKIP__ = True
if
type
(
node
)
==
list
:
for
n
in
node
:
yield
from
self
.
visit
(
n
)
else
:
for
parent
in
node
.
__class__
.
__mro__
:
if
visitor
:
=
getattr
(
self
,
'visit_'
+
parent
.
__name__
,
None
):
yield
from
visitor
(
node
)
break
else
:
yield
from
self
.
missing_impl
(
node
)
def
missing_impl
(
self
,
node
):
raise
UnsupportedNodeError
(
node
)
class
NodeVisitor
(
UniversalVisitor
):
def
process_args
(
self
,
node
:
ast
.
arguments
)
->
(
str
,
str
,
str
):
for
field
in
(
"posonlyargs"
,
"vararg"
,
"kwonlyargs"
,
"kw_defaults"
,
"kwarg"
,
"defaults"
):
if
getattr
(
node
,
field
,
None
):
raise
NotImplementedError
(
node
,
field
)
if
not
node
.
args
:
return
""
,
"()"
,
[]
f_args
=
[(
self
.
fix_name
(
arg
.
arg
),
f"T
{
i
+
1
}
"
)
for
i
,
arg
in
enumerate
(
node
.
args
)]
return
(
"<"
+
", "
.
join
(
f"typename
{
t
}
"
for
_
,
t
in
f_args
)
+
">"
,
"("
+
", "
.
join
(
f"
{
t
}
{
n
}
"
for
n
,
t
in
f_args
)
+
")"
,
[
n
for
n
,
_
in
f_args
]
)
def
fix_name
(
self
,
name
:
str
)
->
str
:
if
name
.
startswith
(
"__"
)
and
name
.
endswith
(
"__"
):
return
f"py_
{
name
[
2
:
-
2
]
}
"
return
MAPPINGS
.
get
(
name
,
name
)
def
visit_BaseType
(
self
,
node
:
BaseType
)
->
Iterable
[
str
]:
node
=
node
.
resolve
()
if
node
is
TY_INT
:
yield
"int"
elif
node
is
TY_FLOAT
:
yield
"double"
elif
node
is
TY_BOOL
:
yield
"bool"
elif
node
is
TY_NONE
:
yield
"void"
elif
node
is
TY_STR
:
yield
"PyStr"
elif
isinstance
(
node
,
UserType
):
# if node.is_reference:
# yield "PyObj<"
#yield "auto"
yield
f"referencemodel::Rc<__main____oo<>::
{
node
.
name
}
__oo<>::Obj>"
# if node.is_reference:
# yield "::py_type>"
elif
isinstance
(
node
,
TypeType
):
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
):
yield
"typon::"
if
node
.
kind
==
PromiseKind
.
TASK
:
yield
"Task"
elif
node
.
kind
==
PromiseKind
.
JOIN
:
yield
"Join"
elif
node
.
kind
==
PromiseKind
.
FUTURE
:
yield
"Future"
elif
node
.
kind
==
PromiseKind
.
FORKED
:
yield
"Forked"
elif
node
.
kind
==
PromiseKind
.
GENERATOR
:
yield
"Generator"
else
:
raise
NotImplementedError
(
node
)
yield
"<"
yield
from
self
.
visit
(
node
.
return_type
)
yield
">"
elif
isinstance
(
node
,
TypeVariable
):
# yield f"TYPEVAR_{node.name}";return
raise
UnresolvedTypeVariableError
(
node
)
elif
isinstance
(
node
,
UnionType
)
and
(
ty
:
=
node
.
is_optional
()):
yield
"std::optional<"
yield
from
self
.
visit
(
ty
)
yield
">"
elif
isinstance
(
node
,
TypeOperator
):
yield
"typon::Py"
+
node
.
name
.
title
()
if
node
.
args
:
yield
"<"
yield
from
join
(
", "
,
map
(
self
.
visit
,
node
.
args
))
yield
">"
else
:
raise
NotImplementedError
(
node
)
class
CoroutineMode
(
Flag
):
SYNC
=
1
FAKE
=
2
|
SYNC
ASYNC
=
4
GENERATOR
=
8
|
ASYNC
TASK
=
16
|
ASYNC
JOIN
=
32
|
ASYNC
class
FunctionEmissionKind
(
enum
.
Enum
):
DECLARATION
=
enum
.
auto
()
DEFINITION
=
enum
.
auto
()
METHOD
=
enum
.
auto
()
LAMBDA
=
enum
.
auto
()
typon/trans/transpiler/phases/emit_cpp/block.py
→
typon/trans/transpiler/phases/emit_cpp
2
/block.py
View file @
90409113
...
...
@@ -5,7 +5,7 @@ from typing import Iterable, Optional
from
transpiler.phases.typing.common
import
is_builtin
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.typing.types
import
BaseType
,
TY_INT
,
TY_BOOL
,
TypeVariable
,
Promise
,
TypeType
from
transpiler.phases.typing.types
import
BaseType
,
TY_INT
,
TY_BOOL
,
TypeVariable
from
transpiler.utils
import
compare_ast
from
transpiler.phases.emit_cpp
import
NodeVisitor
,
CoroutineMode
,
flatmap
,
FunctionEmissionKind
from
transpiler.phases.emit_cpp.expr
import
ExpressionVisitor
...
...
typon/trans/transpiler/phases/emit_cpp2/class_.py
0 → 100644
View file @
90409113
# coding: utf-8
import
ast
from
typing
import
Iterable
from
dataclasses
import
dataclass
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.emit_cpp
import
NodeVisitor
,
FunctionEmissionKind
class
ClassVisitor
(
NodeVisitor
):
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
yield
f"struct
{
node
.
name
}
_s;"
yield
f"extern
{
node
.
name
}
_s
{
node
.
name
}
;"
yield
f"struct
{
node
.
name
}
_s {{"
yield
"struct py_type {"
inner
=
ClassInnerVisitor
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
"template<typename... T> py_type(T&&... args) {"
yield
"__init__(this, std::forward<T>(args)...);"
yield
"}"
yield
"py_type() {}"
yield
"py_type(const py_type&) = delete;"
yield
"py_type(py_type&&) = delete;"
if
getattr
(
node
.
type
,
"is_enum"
,
False
):
yield
"int value;"
yield
"operator int() const { return value; }"
yield
"void py_repr(std::ostream &s) const {"
yield
f's << "
{
node
.
name
}
.";'
yield
"}"
else
:
yield
"void py_repr(std::ostream &s) const {"
yield
f's << "
{
node
.
name
}
(";'
for
i
,
(
name
,
memb
)
in
enumerate
(
node
.
type
.
get_members
().
items
()):
if
i
!=
0
:
yield
's << ", ";'
yield
f's << "
{
name
}
=";'
yield
f"repr_to(
{
name
}
, s);"
yield
"s << ')';"
yield
"}"
yield
"void py_print(std::ostream &s) const {"
yield
"py_repr(s);"
yield
"}"
yield
"};"
yield
"template<typename... T> auto operator()(T&&... args) {"
yield
"return pyobj<py_type>(std::forward<T>(args)...);"
yield
"}"
# outer = ClassOuterVisitor(node.inner_scope)
# for stmt in node.body:
# yield from outer.visit(stmt)
yield
f"}}
{
node
.
name
}
;"
@
dataclass
class
ClassInnerVisitor
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
member
=
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
yield
from
self
.
visit
(
member
.
type
)
yield
node
.
target
.
id
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
]:
# yield "struct {"
# yield "type* self;"
# from transpiler.phases.emit_cpp.block import BlockVisitor
# yield from BlockVisitor(self.scope).visit_func_new(node, FunctionEmissionKind.METHOD, True)
# yield f"}} {node.name} {{ this }};"
yield
f"struct
{
node
.
name
}
_m_s : referencemodel::method {{"
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
yield
from
BlockVisitor
(
self
.
scope
).
visit_func_new
(
node
,
FunctionEmissionKind
.
METHOD
)
yield
f"}} static constexpr
{
node
.
name
}
{{}};"
yield
""
@
dataclass
class
ClassOuterVisitor
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
yield
""
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"struct {"
yield
"template<typename Self, typename... T>"
yield
"auto operator()(Self self, T&&... args) {"
yield
f"return dotp(self,
{
node
.
name
}
)(std::forward<T>(args)...);"
yield
"}"
yield
f"}}
{
node
.
name
}
;"
yield
""
# yield "struct : function {"
# from transpiler.phases.emit_cpp.block import BlockVisitor
# yield from BlockVisitor(self.scope).visit_func_new(node, FunctionEmissionKind.METHOD)
# yield f"}} static constexpr {node.name} {{}};"
@
dataclass
class
ClassInnerVisitor2
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
yield
""
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"struct : referencemodel::method {"
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
yield
from
BlockVisitor
(
self
.
scope
).
visit_func_new
(
node
,
FunctionEmissionKind
.
METHOD
)
yield
f"}} static constexpr
{
node
.
name
}
{{}};"
@
dataclass
class
ClassInnerVisitor4
(
NodeVisitor
):
scope
:
Scope
def
visit_AnnAssign
(
self
,
node
:
ast
.
AnnAssign
)
->
Iterable
[
str
]:
member
=
self
.
scope
.
obj_type
.
fields
[
node
.
target
.
id
]
yield
from
self
.
visit
(
member
.
type
)
yield
node
.
target
.
id
yield
";"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
""
\ No newline at end of file
typon/trans/transpiler/phases/emit_cpp/consts.py
→
typon/trans/transpiler/phases/emit_cpp
2
/consts.py
View file @
90409113
File moved
typon/trans/transpiler/phases/emit_cpp/expr.py
→
typon/trans/transpiler/phases/emit_cpp
2
/expr.py
View file @
90409113
...
...
@@ -219,30 +219,12 @@ class ExpressionVisitor(NodeVisitor):
yield
")"
def
visit_Attribute
(
self
,
node
:
ast
.
Attribute
)
->
Iterable
[
str
]:
use_dot
=
None
if
type
(
node
.
value
.
type
)
==
TypeType
:
use_dot
=
"dots"
elif
isinstance
(
node
.
type
,
FunctionType
)
and
node
.
type
.
is_method
and
not
isinstance
(
node
.
value
.
type
,
Promise
):
if
node
.
value
.
type
.
resolve
().
is_reference
:
use_dot
=
"dotp"
else
:
use_dot
=
"dot"
if
use_dot
:
use_dot
=
"dot"
if
use_dot
:
yield
use_dot
yield
"dot"
yield
"(("
yield
from
self
.
visit
(
node
.
value
)
yield
"), "
yield
self
.
fix_name
(
node
.
attr
)
yield
")"
else
:
yield
from
self
.
prec
(
"."
).
visit
(
node
.
value
)
if
node
.
value
.
type
.
resolve
().
is_reference
:
yield
"->"
else
:
yield
"."
yield
self
.
fix_name
(
node
.
attr
)
def
visit_List
(
self
,
node
:
ast
.
List
)
->
Iterable
[
str
]:
if
node
.
elts
:
...
...
typon/trans/transpiler/phases/emit_cpp/file.py
→
typon/trans/transpiler/phases/emit_cpp
2
/file.py
View file @
90409113
File moved
typon/trans/transpiler/phases/emit_cpp2/function.py
0 → 100644
View file @
90409113
# coding: utf-8
import
ast
from
dataclasses
import
dataclass
from
typing
import
Iterable
from
transpiler.phases.emit_cpp.consts
import
SYMBOLS
from
transpiler.phases.emit_cpp
import
CoroutineMode
,
FunctionEmissionKind
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.utils
import
PlainBlock
# noinspection PyPep8Naming
@
dataclass
class
FunctionVisitor
(
BlockVisitor
):
def
visit_Expr
(
self
,
node
:
ast
.
Expr
)
->
Iterable
[
str
]:
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
def
visit_AugAssign
(
self
,
node
:
ast
.
AugAssign
)
->
Iterable
[
str
]:
yield
from
self
.
visit_lvalue
(
node
.
target
,
False
)
yield
SYMBOLS
[
type
(
node
.
op
)]
+
"="
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
visit_If
(
self
,
node
:
ast
.
If
)
->
Iterable
[
str
]:
yield
"if ("
yield
from
self
.
expr
().
visit
(
node
.
test
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
yield
"else "
if
isinstance
(
node
.
orelse
,
ast
.
If
):
yield
from
self
.
visit
(
node
.
orelse
)
else
:
yield
from
self
.
emit_block
(
node
.
orelse_scope
,
node
.
orelse
)
def
visit_PlainBlock
(
self
,
node
:
PlainBlock
)
->
Iterable
[
str
]:
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
def
visit_Return
(
self
,
node
:
ast
.
Return
)
->
Iterable
[
str
]:
if
CoroutineMode
.
ASYNC
in
self
.
generator
:
yield
"co_return "
else
:
yield
"return "
if
node
.
value
:
yield
from
self
.
expr
().
visit
(
node
.
value
)
yield
";"
def
visit_While
(
self
,
node
:
ast
.
While
)
->
Iterable
[
str
]:
if
node
.
orelse
:
yield
"auto"
yield
node
.
orelse_variable
yield
"= true;"
yield
"while ("
yield
from
self
.
expr
().
visit
(
node
.
test
)
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
yield
"if ("
yield
node
.
orelse_variable
yield
")"
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
orelse
)
def
visit_Global
(
self
,
node
:
ast
.
Global
)
->
Iterable
[
str
]:
yield
""
def
visit_Nonlocal
(
self
,
node
:
ast
.
Nonlocal
)
->
Iterable
[
str
]:
yield
""
def
block2
(
self
)
->
"FunctionVisitor"
:
# See the comments in visit_FunctionDef.
# A Python code block does not introduce a new scope, so we create a new `Scope` object that shares the same
# variables as the parent scope.
return
FunctionVisitor
(
self
.
scope
.
child_share
(),
generator
=
self
.
generator
)
def
emit_block
(
self
,
scope
:
Scope
,
items
:
Iterable
[
ast
.
stmt
])
->
Iterable
[
str
]:
yield
"{"
for
child
in
items
:
yield
from
FunctionVisitor
(
scope
,
generator
=
self
.
generator
).
visit
(
child
)
yield
"}"
def
visit_Break
(
self
,
node
:
ast
.
Break
)
->
Iterable
[
str
]:
if
(
loop
:
=
self
.
scope
.
is_in_loop
()).
orelse
:
yield
loop
.
orelse_variable
yield
" = false;"
yield
"break;"
def
visit_Try
(
self
,
node
:
ast
.
Try
)
->
Iterable
[
str
]:
yield
from
self
.
emit_block
(
node
.
inner_scope
,
node
.
body
)
if
node
.
orelse
:
raise
NotImplementedError
(
node
,
"orelse"
)
if
node
.
finalbody
:
raise
NotImplementedError
(
node
,
"finalbody"
)
for
handler
in
node
.
handlers
:
#yield from self.visit(handler)
pass
# todo
def
visit_Raise
(
self
,
node
:
ast
.
Raise
)
->
Iterable
[
str
]:
yield
"// raise"
# TODO
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
"auto"
yield
self
.
fix_name
(
node
.
name
)
yield
"="
yield
from
self
.
visit_func_new
(
node
,
FunctionEmissionKind
.
LAMBDA
)
yield
";"
typon/trans/transpiler/phases/emit_cpp2/module.py
0 → 100644
View file @
90409113
# coding: utf-8
import
ast
from
typing
import
Iterable
from
dataclasses
import
dataclass
,
field
from
transpiler.phases.typing
import
FunctionType
from
transpiler.phases.typing.scope
import
Scope
from
transpiler.phases.emit_cpp
import
CoroutineMode
,
FunctionEmissionKind
,
NodeVisitor
,
join
from
transpiler.phases.emit_cpp.block
import
BlockVisitor
from
transpiler.phases.emit_cpp.class_
import
ClassVisitor
,
ClassInnerVisitor
,
ClassInnerVisitor2
,
ClassInnerVisitor4
from
transpiler.phases.emit_cpp.function
import
FunctionVisitor
from
transpiler.utils
import
compare_ast
,
highlight
IGNORED_IMPORTS
=
{
"typon"
,
"typing"
,
"__future__"
,
"dataclasses"
,
"enum"
}
# noinspection PyPep8Naming
@
dataclass
class
ModuleVisitor
(
BlockVisitor
):
includes
:
list
[
str
]
=
field
(
default_factory
=
list
)
def
visit_Import
(
self
,
node
:
ast
.
Import
)
->
Iterable
[
str
]:
__TB__
=
f"emitting C++ code for
{
highlight
(
node
)
}
"
for
alias
in
node
.
names
:
concrete
=
self
.
fix_name
(
alias
.
asname
or
alias
.
name
)
if
alias
.
module_obj
.
is_python
:
yield
f"namespace py_
{
concrete
}
{{"
yield
f"struct
{
concrete
}
_t {{"
for
name
,
obj
in
alias
.
module_obj
.
fields
.
items
():
ty
=
obj
.
type
.
resolve
()
if
getattr
(
ty
,
"python_func_used"
,
False
):
yield
from
self
.
emit_python_func
(
alias
.
name
,
name
,
name
,
ty
)
yield
"} all;"
yield
f"auto& get_all() {{ return all; }}"
yield
"}"
yield
f'auto&
{
concrete
}
= py_
{
concrete
}
::get_all();'
elif
alias
.
name
in
IGNORED_IMPORTS
:
yield
""
else
:
yield
from
self
.
import_module
(
alias
.
name
)
yield
f'auto&
{
concrete
}
= py_
{
alias
.
name
}
::get_all();'
def
import_module
(
self
,
name
:
str
)
->
Iterable
[
str
]:
self
.
includes
.
append
(
f'#include <python/
{
name
}
.hpp>'
)
yield
""
def
emit_python_func
(
self
,
mod
:
str
,
name
:
str
,
alias
:
str
,
fty
:
FunctionType
)
->
Iterable
[
str
]:
__TB__
=
f"emitting C++ code for Python function
{
highlight
(
f'
{
mod
}
.
{
name
}
')
}
"
yield
"struct {"
yield
f"auto operator()("
for
i
,
argty
in
enumerate
(
fty
.
parameters
):
if
i
!=
0
:
yield
", "
yield
"lvalue_or_rvalue<"
yield
from
self
.
visit
(
argty
)
yield
f"> arg
{
i
}
"
yield
") {"
yield
"InterpGuard guard{};"
yield
"try {"
yield
f"return py::module_::import(
\
"
{
mod
}\
"
).attr(
\
"
{
name
}\
"
)("
for
i
,
argty
in
enumerate
(
fty
.
parameters
):
if
i
!=
0
:
yield
", "
yield
f"*arg
{
i
}
"
yield
").cast<"
yield
from
self
.
visit
(
fty
.
return_type
)
yield
">();"
yield
"} catch (py::error_already_set& e) {"
yield
'std::cerr << "Python exception: " << e.what() << std::endl;'
yield
"throw;"
yield
"}"
yield
"}"
yield
f"}}
{
alias
}
;"
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
)
->
Iterable
[
str
]:
if
node
.
module
in
IGNORED_IMPORTS
:
yield
""
elif
node
.
module_obj
.
is_python
:
for
alias
in
node
.
names
:
fty
=
alias
.
item_obj
.
resolve
()
#assert isinstance(fty, FunctionType)
yield
from
self
.
emit_python_func
(
node
.
module
,
alias
.
name
,
alias
.
asname
or
alias
.
name
,
fty
)
else
:
yield
from
self
.
import_module
(
node
.
module
)
for
alias
in
node
.
names
:
yield
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
node
.
module
}
::get_all().
{
alias
.
name
}
;"
def
visit_Expr
(
self
,
node
:
ast
.
Expr
)
->
Iterable
[
str
]:
if
isinstance
(
node
.
value
,
ast
.
Str
):
if
"
\
n
"
in
node
.
value
.
s
:
yield
f"/*
{
node
.
value
.
s
}
*/"
else
:
yield
f"//
{
node
.
value
.
s
}
"
else
:
raise
NotImplementedError
(
node
)
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
#yield from ClassVisitor().visit(node)
yield
from
()
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
super
().
visit_free_func
(
node
,
FunctionEmissionKind
.
DECLARATION
)
@
dataclass
class
ModuleVisitor2
(
NodeVisitor
):
scope
:
Scope
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
BlockVisitor
(
self
.
scope
).
visit_free_func
(
node
,
FunctionEmissionKind
.
DEFINITION
)
def
visit_AST
(
self
,
node
:
ast
.
AST
)
->
Iterable
[
str
]:
yield
""
pass
@
dataclass
class
ModuleVisitor3
(
NodeVisitor
):
scope
:
Scope
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
yield
from
()
return
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
yield
f"static constexpr _detail_<__main__>::
{
node
.
name
}
<>
{
node
.
name
}
{{}};"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
BlockVisitor
(
self
.
scope
).
visit_free_func
(
node
,
FunctionEmissionKind
.
DEFINITION
)
@
dataclass
class
ModuleVisitor4
(
NodeVisitor
):
scope
:
Scope
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
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
}\
"
;"
inner
=
ClassInnerVisitor2
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
f"struct Obj : referencemodel::instance<
{
node
.
name
}
__oo<>, Obj> {{"
inner
=
ClassInnerVisitor4
(
node
.
inner_scope
)
for
stmt
in
node
.
body
:
yield
from
inner
.
visit
(
stmt
)
yield
"template <typename... U>"
yield
"Obj(U&&... args) {"
yield
"dot(this, __init__)(this, std::forward<U>(args)...);"
yield
"}"
yield
"};"
yield
"template <typename... T>"
yield
"auto operator() (T&&... args) const {"
yield
"return referencemodel::rc(Obj{std::forward<T>(args)...});"
yield
"}"
yield
f"}};"
yield
f"static constexpr
{
node
.
name
}
__oo<>
{
node
.
name
}
{{}};"
yield
f"static_assert(sizeof
{
node
.
name
}
== 1);"
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
yield
from
()
@
dataclass
class
ModuleVisitorExt
(
NodeVisitor
):
scope
:
Scope
def
visit_FunctionDef
(
self
,
node
:
ast
.
FunctionDef
)
->
Iterable
[
str
]:
if
getattr
(
node
,
"is_main"
,
False
):
yield
from
()
return
#yield from BlockVisitor(self.scope).visit_free_func(node, FunctionEmissionKind.DEFINITION)
#yield f'm.def("{node.name}", CoroWrapper(PROGRAMNS::{node.name}));'
yield
f'm.def("
{
node
.
name
}
", PROGRAMNS::
{
node
.
name
}
);'
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
)
->
Iterable
[
str
]:
if
gen_instances
:
=
getattr
(
node
,
"gen_instances"
,
None
):
for
args
,
inst
in
gen_instances
.
items
():
yield
from
self
.
visit_ClassDef
(
inst
)
return
yield
f"py::class_<PROGRAMNS::
{
node
.
name
}
_s::py_type>(m,
\
"
{
node
.
name
}\
"
)"
if
init
:
=
node
.
type
.
fields
.
get
(
"__init__"
,
None
):
init
=
init
.
type
.
resolve
().
remove_self
()
init_params
=
init
.
parameters
yield
".def(py::init<"
yield
from
join
(
", "
,
map
(
self
.
visit
,
init_params
))
yield
">())"
yield
f'.def("__repr__", [](const PROGRAMNS::
{
node
.
name
}
_s::py_type& self)'
yield
"{ return repr(self); })"
for
f
,
v
in
node
.
type
.
fields
.
items
():
if
f
==
"__init__"
:
continue
if
isinstance
(
v
.
type
,
FunctionType
):
meth
=
v
.
type
.
remove_self
()
yield
f'.def("
{
f
}
", [](const PROGRAMNS::
{
node
.
name
}
_s::py_type& a'
if
meth
.
parameters
:
yield
","
vis
=
BlockVisitor
(
node
.
scope
)
yield
from
vis
.
visit_func_params
(((
f"arg
{
i
}
"
,
ty
,
None
)
for
i
,
ty
in
enumerate
(
meth
.
parameters
)),
FunctionEmissionKind
.
LAMBDA
)
yield
f') {{ return dotp(&a,
{
f
}
)('
if
meth
.
parameters
:
yield
from
join
(
", "
,
(
f"arg
{
i
}
"
for
i
,
_
in
enumerate
(
meth
.
parameters
)))
yield
').call(); })'
else
:
yield
f'.def_readwrite("
{
f
}
", &PROGRAMNS::
{
node
.
name
}
_s::py_type::
{
f
}
)'
yield
";"
pass
def
visit_AST
(
self
,
node
:
ast
.
AST
)
->
Iterable
[
str
]:
yield
from
()
pass
typon/trans/transpiler/phases/emit_cpp/search.py
→
typon/trans/transpiler/phases/emit_cpp
2
/search.py
View file @
90409113
File moved
typon/trans/transpiler/phases/typing/modules.py
View file @
90409113
...
...
@@ -5,18 +5,21 @@ from transpiler.phases.typing.scope import Scope, VarKind, VarDecl, ScopeKind
from
transpiler.phases.typing.types
import
MemberDef
,
ResolvedConcreteType
,
UniqueTypeMixin
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ResolvedConcreteType
:
class
CreatedType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
class
ModuleType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
pass
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ModuleType
:
class
CreatedType
(
ModuleType
):
def
name
(
self
):
return
name
ty
=
CreatedType
()
for
n
,
v
in
scope
.
vars
.
items
():
ty
.
fields
[
n
]
=
MemberDef
(
v
.
type
,
v
.
val
,
False
)
ty
.
fields
[
n
]
=
MemberDef
(
v
.
type
,
v
.
val
,
v
.
is_item_decl
)
return
ty
visited_modules
=
{}
def
parse_module
(
mod_name
:
str
,
python_path
:
Path
,
scope
=
None
):
def
parse_module
(
mod_name
:
str
,
python_path
:
Path
,
scope
=
None
,
preprocess
=
None
):
path
=
python_path
/
mod_name
if
not
path
.
exists
():
...
...
@@ -41,12 +44,15 @@ def parse_module(mod_name: str, python_path: Path, scope=None):
if
real_path
.
suffix
==
".py"
:
from
transpiler.phases.typing.stdlib
import
StdlibVisitor
StdlibVisitor
(
python_path
,
mod_scope
).
visit
(
ast
.
parse
(
real_path
.
read_text
()))
node
=
ast
.
parse
(
real_path
.
read_text
())
if
preprocess
:
node
=
preprocess
(
node
)
StdlibVisitor
(
python_path
,
mod_scope
).
visit
(
node
)
else
:
raise
NotImplementedError
(
f"Unsupported file type
{
path
.
suffix
}
"
)
mod
=
make_mod
_decl
(
mod_name
,
mod_scope
)
visited_modules
[
real_path
.
as_posix
()]
=
mod
mod
=
make_mod
ule
(
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
()})
return
mod
# def process_module(mod_path: Path, scope):
...
...
@@ -82,7 +88,3 @@ def parse_module(mod_name: str, python_path: Path, scope=None):
# child_mod = process_module(child, scope)
# visited_modules[child.as_posix()] = child_mod
# return mod
def
make_mod_decl
(
child
,
mod_scope
):
return
VarDecl
(
VarKind
.
LOCAL
,
make_module
(
child
,
mod_scope
),
{
k
:
v
.
type
for
k
,
v
in
mod_scope
.
vars
.
items
()})
\ No newline at end of file
typon/trans/transpiler/phases/typing/scope.py
View file @
90409113
...
...
@@ -28,6 +28,7 @@ class VarDecl:
kind
:
VarKind
type
:
BaseType
val
:
Any
=
RuntimeValue
()
is_item_decl
:
bool
=
False
class
ScopeKind
(
Enum
):
...
...
typon/trans/transpiler/phases/typing/stdlib.py
View file @
90409113
...
...
@@ -15,7 +15,7 @@ from transpiler.phases.typing.scope import Scope, VarDecl, VarKind, ScopeKind
from
transpiler.phases.typing.types
import
BaseType
,
BuiltinGenericType
,
BuiltinType
,
create_builtin_generic_type
,
\
create_builtin_type
,
ConcreteType
,
GenericInstanceType
,
TypeListType
,
TypeTupleType
,
GenericParameter
,
\
GenericParameterKind
,
TypeVariable
,
ResolvedConcreteType
,
MemberDef
,
ClassTypeType
,
CallableInstanceType
,
\
MethodType
,
UniqueTypeMixin
,
GenericType
MethodType
,
UniqueTypeMixin
,
GenericType
,
BlockData
from
transpiler.phases.utils
import
NodeVisitorSeq
def
visit_generic_item
(
...
...
@@ -79,7 +79,7 @@ class StdlibVisitor(NodeVisitorSeq):
scope
:
Scope
=
field
(
default_factory
=
lambda
:
PRELUDE
)
cur_class
:
Optional
[
ResolvedConcreteType
]
=
None
def
resolve_module_import
(
self
,
name
:
str
)
->
VarDecl
:
def
resolve_module_import
(
self
,
name
:
str
):
# tries = [
# self.python_path.parent / f"{name}.py",
# self.python_path.parent / name
...
...
@@ -109,19 +109,19 @@ class StdlibVisitor(NodeVisitorSeq):
def
visit_ImportFrom
(
self
,
node
:
ast
.
ImportFrom
):
module
=
self
.
resolve_module_import
(
node
.
module
)
node
.
module_obj
=
module
.
type
node
.
module_obj
=
module
for
alias
in
node
.
names
:
thing
=
module
.
val
.
get
(
alias
.
name
)
thing
=
module
.
fields
.
get
(
alias
.
name
)
if
not
thing
:
from
transpiler.phases.typing.exceptions
import
UnknownModuleMemberError
raise
UnknownModuleMemberError
(
node
.
module
,
alias
.
name
)
alias
.
item_obj
=
thing
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
thing
)
alias
.
item_obj
=
thing
.
type
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
thing
.
type
)
def
visit_Import
(
self
,
node
:
ast
.
Import
):
for
alias
in
node
.
names
:
mod
=
self
.
resolve_module_import
(
alias
.
name
)
alias
.
module_obj
=
mod
.
type
alias
.
module_obj
=
mod
self
.
scope
.
vars
[
alias
.
asname
or
alias
.
name
]
=
mod
def
visit_ClassDef
(
self
,
node
:
ast
.
ClassDef
):
...
...
@@ -131,11 +131,12 @@ class StdlibVisitor(NodeVisitorSeq):
else
:
base_class
=
create_builtin_generic_type
if
node
.
type_params
else
create_builtin_type
NewType
=
base_class
(
node
.
name
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
.
type_type
())
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
.
type_type
()
,
is_item_decl
=
True
)
def
visit_nongeneric
(
scope
:
Scope
,
output
:
ResolvedConcreteType
):
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
)
bases
=
[
self
.
anno
().
visit
(
base
)
for
base
in
node
.
bases
]
match
bases
:
...
...
@@ -157,6 +158,7 @@ class StdlibVisitor(NodeVisitorSeq):
def
visit_nongeneric
(
scope
,
output
:
CallableInstanceType
):
scope
=
scope
.
child
(
ScopeKind
.
FUNCTION
)
arg_visitor
=
TypeAnnotationVisitor
(
scope
)
output
.
block_data
=
BlockData
(
node
,
scope
)
output
.
parameters
=
[
arg_visitor
.
visit
(
arg
.
annotation
)
for
arg
in
node
.
args
.
args
]
output
.
return_type
=
arg_visitor
.
visit
(
node
.
returns
)
output
.
optional_at
=
len
(
node
.
args
.
args
)
-
len
(
node
.
args
.
defaults
)
...
...
@@ -198,6 +200,10 @@ class StdlibVisitor(NodeVisitorSeq):
node
.
type_params
.
append
(
ast
.
TypeVar
(
arg_name
,
arg
.
annotation
))
arg
.
annotation
=
ast
.
Name
(
arg_name
,
ast
.
Load
())
if
node
.
returns
is
None
:
node
.
returns
=
ast
.
Name
(
"AutoVar$return"
,
ast
.
Load
())
node
.
type_params
.
append
(
ast
.
TypeVar
(
"AutoVar$return"
,
None
))
# if self.cur_class is not None:
# node.type_params.append(ast.TypeVar("Self", None))
...
...
@@ -232,9 +238,9 @@ class StdlibVisitor(NodeVisitorSeq):
NewType
=
base_class
()
FuncType
.
__name__
=
NewType
.
name
()
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
)
self
.
scope
.
vars
[
node
.
name
]
=
VarDecl
(
VarKind
.
LOCAL
,
NewType
,
is_item_decl
=
True
)
if
self
.
cur_class
is
not
None
:
self
.
cur_class
.
fields
[
node
.
name
]
=
MemberDef
(
NewType
,
node
)
self
.
cur_class
.
fields
[
node
.
name
]
=
MemberDef
(
NewType
,
node
,
in_class_def
=
True
)
visit_generic_item
(
visit_nongeneric
,
node
,
NewType
,
self
.
scope
,
InstanceType
,
True
)
...
...
typon/trans/transpiler/phases/typing/types.py
View file @
90409113
...
...
@@ -287,7 +287,9 @@ class GenericParameterKind(enum.Enum):
@
dataclass
class
GenericParameter
:
name
:
str
kind
:
GenericParameterKind
kind
:
GenericParameterKind
=
GenericParameterKind
.
NORMAL
gparam
=
GenericParameter
@
dataclass
class
GenericConstraint
:
...
...
@@ -589,6 +591,8 @@ class ClassTypeType(GenericInstanceType):
inner_type
:
BaseType
class
ClassType
(
UniqueTypeMixin
,
GenericType
):
parameters
=
[
gparam
(
"T"
)]
def
name
(
self
):
return
"Type"
...
...
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