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
9dc8cec5
Commit
9dc8cec5
authored
Mar 27, 2024
by
Tom Niget
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix first python interop
parent
7044ede9
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
179 additions
and
15 deletions
+179
-15
typon/include/python/builtins/int.hpp
typon/include/python/builtins/int.hpp
+47
-1
typon/trans/tests/a_a_call_py_1.py
typon/trans/tests/a_a_call_py_1.py
+3
-3
typon/trans/transpiler/phases/emit_cpp/module.py
typon/trans/transpiler/phases/emit_cpp/module.py
+60
-3
typon/trans/transpiler/phases/typing/expr.py
typon/trans/transpiler/phases/typing/expr.py
+11
-4
typon/trans/transpiler/phases/typing/modules.py
typon/trans/transpiler/phases/typing/modules.py
+53
-4
typon/trans/transpiler/phases/typing/types.py
typon/trans/transpiler/phases/typing/types.py
+5
-0
No files found.
typon/include/python/builtins/int.hpp
View file @
9dc8cec5
...
...
@@ -116,7 +116,53 @@ template <> struct std::hash<decltype(0_pi)> {
namespace
PYBIND11_NAMESPACE
{
namespace
detail
{
template
<
>
struct
type_caster
<
decltype
(
0
_pi
)
>
:
type_caster
<
int
>
{};
template
<
>
struct
type_caster
<
decltype
(
0
_pi
)
>
{
public:
/**
* This macro establishes the name 'inty' in
* function signatures and declares a local variable
* 'value' of type inty
*/
PYBIND11_TYPE_CASTER
(
decltype
(
0
_pi
),
const_name
(
"TyInt"
));
/**
* Conversion part 1 (Python->C++): convert a PyObject into a inty
* instance or return false upon failure. The second argument
* indicates whether implicit conversions should be applied.
*/
bool
load
(
handle
src
,
bool
)
{
/* Extract PyObject from handle */
PyObject
*
source
=
src
.
ptr
();
/* Try converting into a Python integer value */
PyObject
*
tmp
=
PyNumber_Long
(
source
);
if
(
!
tmp
)
return
false
;
/* Now try to convert into a C++ int */
dot
(
value
,
value
)
=
PyLong_AsLong
(
tmp
);
Py_DECREF
(
tmp
);
/* Ensure return code was OK (to avoid out-of-range errors etc) */
return
!
(
dot
(
value
,
value
)
==
-
1
&&
!
PyErr_Occurred
());
}
/**
* Conversion part 2 (C++ -> Python): convert an inty instance into
* a Python object. The second and third arguments are used to
* indicate the return value policy and parent object (for
* ``return_value_policy::reference_internal``) and are generally
* ignored by implicit casters.
*/
static
handle
cast
(
auto
src
,
return_value_policy
/* policy */
,
handle
/* parent */
)
{
return
PyLong_FromLong
(
dot
(
src
,
value
));
}
};
}
// namespace detail
}
// namespace PYBIND11_NAMESPACE
...
...
typon/trans/tests/a_a_call_py_1.py
View file @
9dc8cec5
# test numpy interop
from
numpy
import
square
#
from numpy import square
import
math
if
__name__
==
"__main__"
:
x
=
[
1
,
2
,
3
,
4
]
y
:
list
[
int
]
=
square
(
x
)
print
(
x
,
y
)
#
y: list[int] = square(x)
#
print(x, y)
f
:
int
=
math
.
factorial
(
5
)
print
(
"5! ="
,
f
)
\ No newline at end of file
typon/trans/transpiler/phases/emit_cpp/module.py
View file @
9dc8cec5
...
...
@@ -3,7 +3,8 @@ from typing import Iterable
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.emit_cpp.visitors
import
NodeVisitor
from
transpiler.phases.typing.modules
import
ModuleType
,
TyponModuleType
,
PythonModuleType
from
transpiler.phases.typing.types
import
CallableInstanceType
,
ClassTypeType
,
TypeVariable
,
BaseType
,
GenericType
,
\
GenericInstanceType
,
UserGenericType
...
...
@@ -12,15 +13,71 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
__TB_NODE__
=
mod
.
block_data
.
node
yield
"#include <python/builtins.hpp>"
yield
"#include <python/sys.hpp>"
emitted
=
set
()
def
emit
(
mod_obj
:
ModuleType
):
if
mod_obj
in
emitted
:
return
emitted
.
add
(
mod_obj
)
name
=
mod_obj
.
name
()
match
mod_obj
:
case
TyponModuleType
():
yield
f"#include <python/
{
name
}
.hpp>"
case
PythonModuleType
():
yield
f"namespace py_
{
name
}
{{"
yield
"template <typename _Unused = void>"
yield
f"struct
{
name
}
__oo : referencemodel::moduletype<
{
name
}
__oo<>> {{"
for
fname
,
obj
in
mod_obj
.
fields
.
items
():
obj
=
obj
.
type
.
resolve
()
if
type
(
obj
)
is
TypeVariable
:
continue
# unused python function
assert
isinstance
(
obj
,
CallableInstanceType
)
yield
"struct : referencemodel::function {"
yield
"auto operator()("
for
i
,
argty
in
enumerate
(
obj
.
parameters
):
if
i
!=
0
:
yield
", "
yield
"lvalue_or_rvalue<"
yield
from
NodeVisitor
().
visit_BaseType
(
argty
)
yield
f"> arg
{
i
}
"
yield
") const {"
yield
"InterpGuard guard{};"
yield
"try {"
yield
f"return py::module_::import(
\
"
{
name
}\
"
).attr(
\
"
{
fname
}\
"
)("
for
i
,
argty
in
enumerate
(
obj
.
parameters
):
if
i
!=
0
:
yield
", "
yield
f"*arg
{
i
}
"
yield
").cast<"
yield
from
NodeVisitor
().
visit_BaseType
(
obj
.
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"}} static constexpr
{
fname
}
{{}};"
yield
"};"
yield
f"
{
name
}
__oo<> all;"
yield
"}"
incl_vars
=
[]
for
node
in
mod
.
block_data
.
node
.
body
:
match
node
:
case
ast
.
Import
(
names
):
for
alias
in
names
:
yield
f
"#include <python/
{
alias
.
name
}
.hpp>"
yield
f
rom
emit
(
alias
.
module_obj
)
incl_vars
.
append
(
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
alias
.
name
}
::all;"
)
case
ast
.
ImportFrom
(
module
,
names
,
_
):
yield
f
"#include <python/
{
module
}
.hpp>"
yield
f
rom
emit
(
node
.
module_obj
)
for
alias
in
names
:
incl_vars
.
append
(
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
module
}
::all.
{
alias
.
name
}
;"
)
yield
"namespace PROGRAMNS {"
...
...
typon/trans/transpiler/phases/typing/expr.py
View file @
9dc8cec5
...
...
@@ -110,8 +110,8 @@ class ScoperExprVisitor(ScoperVisitor):
ty
=
obj
.
type
.
resolve
()
# if isinstance(ty, TypeType) and isinstance(ty.type_object, TypeVariable):
# raise NameError(f"Use of type variable") # todo: when does this happen exactly?
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
#
if getattr(ty, "is_python_func", False):
#
ty.python_func_used = True
return
ty
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
BaseType
:
...
...
@@ -149,6 +149,13 @@ class ScoperExprVisitor(ScoperVisitor):
# assert isinstance(ftype, CallableInstanceType) TODO
if
isinstance
(
ftype
,
TypeVariable
)
and
ftype
.
python_func_placeholder
:
ret
=
TypeVariable
()
new_ftype
=
CallableInstanceType
(
arguments
,
ret
)
new_ftype
.
is_native
=
True
ftype
.
unify
(
new_ftype
)
return
ret
if
not
isinstance
(
ftype
,
CallableInstanceType
):
return
TypeVariable
()
...
...
@@ -272,8 +279,8 @@ class ScoperExprVisitor(ScoperVisitor):
# return meth
if
field
:
=
ltype
.
fields
.
get
(
name
):
ty
=
field
.
type
.
resolve
()
if
getattr
(
ty
,
"is_python_func"
,
False
):
ty
.
python_func_used
=
True
#
if getattr(ty, "is_python_func", False):
#
ty.python_func_used = True
if
isinstance
(
ty
,
MethodType
):
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
return
ty
.
remove_self
(
ltype
)
...
...
typon/trans/transpiler/phases/typing/modules.py
View file @
9dc8cec5
import
ast
import
importlib
from
pathlib
import
Path
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
,
BlockData
from
transpiler.phases.typing.types
import
MemberDef
,
ResolvedConcreteType
,
UniqueTypeMixin
,
BlockData
,
TypeVariable
class
ModuleType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
pass
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ModuleType
:
class
CreatedType
(
ModuleType
):
class
TyponModuleType
(
ModuleType
):
pass
class
PythonModuleType
(
ModuleType
):
pass
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
TyponModuleType
:
class
CreatedType
(
TyponModuleType
):
def
name
(
self
):
return
name
ty
=
CreatedType
()
...
...
@@ -36,7 +43,49 @@ def parse_module(mod_name: str, python_path: list[Path], scope=None, preprocess=
break
else
:
"""
py_mod = importlib.import_module(name)
mod_scope = Scope()
# copy all functions to mod_scope
for fname, obj in py_mod.__dict__.items():
if callable(obj):
# fty = FunctionType([], TypeVariable())
# fty.is_python_func = True
fty = TypeVariable()
fty.is_python_func = True
mod_scope.vars[fname] = VarDecl(VarKind.LOCAL, fty)
mod = make_mod_decl(name, mod_scope)
mod.type.is_python = True
self.scope.vars[name] = mod
"""
try
:
py_mod
=
importlib
.
import_module
(
mod_name
)
except
ModuleNotFoundError
:
raise
FileNotFoundError
(
f"Could not find
{
mod_name
}
"
)
else
:
if
mod
:
=
visited_modules
.
get
(
py_mod
):
return
mod
.
type
try
:
class
OurModule
(
PythonModuleType
):
def
name
(
self
):
return
mod_name
mod
=
OurModule
()
# copy all functions to mod_scope
for
fname
,
obj
in
py_mod
.
__dict__
.
items
():
if
callable
(
obj
):
# fty = FunctionType([], TypeVariable())
# fty.is_python_func = True
fty
=
TypeVariable
(
python_func_placeholder
=
True
)
#fty.is_python_func = True
mod
.
fields
[
fname
]
=
MemberDef
(
fty
)
visited_modules
[
py_mod
]
=
VarDecl
(
VarKind
.
LOCAL
,
mod
)
return
mod
except
:
raise
NotImplementedError
(
f"Could not process python module
{
mod_name
}
"
)
if
path
.
is_dir
():
path
=
path
/
"__init__.py"
...
...
typon/trans/transpiler/phases/typing/types.py
View file @
9dc8cec5
...
...
@@ -120,6 +120,7 @@ class TypeVariable(ConcreteType):
resolved
:
Optional
[
ConcreteType
]
=
None
emit_as_is
:
bool
=
False
decltype_str
:
Optional
[
str
]
=
None
python_func_placeholder
:
bool
=
False
def
resolve
(
self
)
->
ConcreteType
:
if
self
.
resolved
is
None
:
...
...
@@ -577,6 +578,10 @@ class CallableInstanceType(GenericInstanceType, MethodType):
def
__post_init__
(
self
):
if
self
.
optional_at
is
None
and
self
.
parameters
is
not
None
:
self
.
optional_at
=
len
(
self
.
parameters
)
if
not
hasattr
(
self
,
"generic_args"
)
and
self
.
parameters
is
not
None
:
self
.
generic_args
=
[
*
self
.
parameters
,
self
.
return_type
]
if
not
hasattr
(
self
,
"generic_parent"
):
self
.
generic_parent
=
None
def
remove_self
(
self
,
self_type
):
assert
self
.
parameters
[
0
].
try_assign
(
self_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