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
Hide 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)> {
...
@@ -116,7 +116,53 @@ template <> struct std::hash<decltype(0_pi)> {
namespace
PYBIND11_NAMESPACE
{
namespace
PYBIND11_NAMESPACE
{
namespace
detail
{
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 detail
}
// namespace PYBIND11_NAMESPACE
}
// namespace PYBIND11_NAMESPACE
...
...
typon/trans/tests/a_a_call_py_1.py
View file @
9dc8cec5
# test numpy interop
# test numpy interop
from
numpy
import
square
#
from numpy import square
import
math
import
math
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
x
=
[
1
,
2
,
3
,
4
]
x
=
[
1
,
2
,
3
,
4
]
y
:
list
[
int
]
=
square
(
x
)
#
y: list[int] = square(x)
print
(
x
,
y
)
#
print(x, y)
f
:
int
=
math
.
factorial
(
5
)
f
:
int
=
math
.
factorial
(
5
)
print
(
"5! ="
,
f
)
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
...
@@ -3,7 +3,8 @@ from typing import Iterable
from
transpiler.phases.emit_cpp.class_
import
emit_class
from
transpiler.phases.emit_cpp.class_
import
emit_class
from
transpiler.phases.emit_cpp.function
import
emit_function
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
,
\
from
transpiler.phases.typing.types
import
CallableInstanceType
,
ClassTypeType
,
TypeVariable
,
BaseType
,
GenericType
,
\
GenericInstanceType
,
UserGenericType
GenericInstanceType
,
UserGenericType
...
@@ -12,15 +13,71 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
...
@@ -12,15 +13,71 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
__TB_NODE__
=
mod
.
block_data
.
node
__TB_NODE__
=
mod
.
block_data
.
node
yield
"#include <python/builtins.hpp>"
yield
"#include <python/builtins.hpp>"
yield
"#include <python/sys.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
=
[]
incl_vars
=
[]
for
node
in
mod
.
block_data
.
node
.
body
:
for
node
in
mod
.
block_data
.
node
.
body
:
match
node
:
match
node
:
case
ast
.
Import
(
names
):
case
ast
.
Import
(
names
):
for
alias
in
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;"
)
incl_vars
.
append
(
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
alias
.
name
}
::all;"
)
case
ast
.
ImportFrom
(
module
,
names
,
_
):
case
ast
.
ImportFrom
(
module
,
names
,
_
):
yield
f
"#include <python/
{
module
}
.hpp>"
yield
f
rom
emit
(
node
.
module_obj
)
for
alias
in
names
:
for
alias
in
names
:
incl_vars
.
append
(
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
module
}
::all.
{
alias
.
name
}
;"
)
incl_vars
.
append
(
f"auto&
{
alias
.
asname
or
alias
.
name
}
= py_
{
module
}
::all.
{
alias
.
name
}
;"
)
yield
"namespace PROGRAMNS {"
yield
"namespace PROGRAMNS {"
...
...
typon/trans/transpiler/phases/typing/expr.py
View file @
9dc8cec5
...
@@ -110,8 +110,8 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -110,8 +110,8 @@ class ScoperExprVisitor(ScoperVisitor):
ty
=
obj
.
type
.
resolve
()
ty
=
obj
.
type
.
resolve
()
# if isinstance(ty, TypeType) and isinstance(ty.type_object, TypeVariable):
# if isinstance(ty, TypeType) and isinstance(ty.type_object, TypeVariable):
# raise NameError(f"Use of type variable") # todo: when does this happen exactly?
# raise NameError(f"Use of type variable") # todo: when does this happen exactly?
if
getattr
(
ty
,
"is_python_func"
,
False
):
#
if getattr(ty, "is_python_func", False):
ty
.
python_func_used
=
True
#
ty.python_func_used = True
return
ty
return
ty
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
BaseType
:
def
visit_BoolOp
(
self
,
node
:
ast
.
BoolOp
)
->
BaseType
:
...
@@ -149,6 +149,13 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -149,6 +149,13 @@ class ScoperExprVisitor(ScoperVisitor):
# assert isinstance(ftype, CallableInstanceType) TODO
# 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
):
if
not
isinstance
(
ftype
,
CallableInstanceType
):
return
TypeVariable
()
return
TypeVariable
()
...
@@ -272,8 +279,8 @@ class ScoperExprVisitor(ScoperVisitor):
...
@@ -272,8 +279,8 @@ class ScoperExprVisitor(ScoperVisitor):
# return meth
# return meth
if
field
:
=
ltype
.
fields
.
get
(
name
):
if
field
:
=
ltype
.
fields
.
get
(
name
):
ty
=
field
.
type
.
resolve
()
ty
=
field
.
type
.
resolve
()
if
getattr
(
ty
,
"is_python_func"
,
False
):
#
if getattr(ty, "is_python_func", False):
ty
.
python_func_used
=
True
#
ty.python_func_used = True
if
isinstance
(
ty
,
MethodType
):
if
isinstance
(
ty
,
MethodType
):
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
if
bound
and
field
.
in_class_def
and
type
(
field
.
val
)
!=
RuntimeValue
:
return
ty
.
remove_self
(
ltype
)
return
ty
.
remove_self
(
ltype
)
...
...
typon/trans/transpiler/phases/typing/modules.py
View file @
9dc8cec5
import
ast
import
ast
import
importlib
from
pathlib
import
Path
from
pathlib
import
Path
from
logging
import
debug
from
logging
import
debug
from
transpiler.phases.typing
import
PRELUDE
from
transpiler.phases.typing
import
PRELUDE
from
transpiler.phases.typing.scope
import
Scope
,
VarKind
,
VarDecl
,
ScopeKind
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
):
class
ModuleType
(
UniqueTypeMixin
,
ResolvedConcreteType
):
pass
pass
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
ModuleType
:
class
TyponModuleType
(
ModuleType
):
class
CreatedType
(
ModuleType
):
pass
class
PythonModuleType
(
ModuleType
):
pass
def
make_module
(
name
:
str
,
scope
:
Scope
)
->
TyponModuleType
:
class
CreatedType
(
TyponModuleType
):
def
name
(
self
):
def
name
(
self
):
return
name
return
name
ty
=
CreatedType
()
ty
=
CreatedType
()
...
@@ -36,7 +43,49 @@ def parse_module(mod_name: str, python_path: list[Path], scope=None, preprocess=
...
@@ -36,7 +43,49 @@ def parse_module(mod_name: str, python_path: list[Path], scope=None, preprocess=
break
break
else
:
else
:
raise
FileNotFoundError
(
f"Could not find
{
mod_name
}
"
)
"""
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
():
if
path
.
is_dir
():
path
=
path
/
"__init__.py"
path
=
path
/
"__init__.py"
...
...
typon/trans/transpiler/phases/typing/types.py
View file @
9dc8cec5
...
@@ -120,6 +120,7 @@ class TypeVariable(ConcreteType):
...
@@ -120,6 +120,7 @@ class TypeVariable(ConcreteType):
resolved
:
Optional
[
ConcreteType
]
=
None
resolved
:
Optional
[
ConcreteType
]
=
None
emit_as_is
:
bool
=
False
emit_as_is
:
bool
=
False
decltype_str
:
Optional
[
str
]
=
None
decltype_str
:
Optional
[
str
]
=
None
python_func_placeholder
:
bool
=
False
def
resolve
(
self
)
->
ConcreteType
:
def
resolve
(
self
)
->
ConcreteType
:
if
self
.
resolved
is
None
:
if
self
.
resolved
is
None
:
...
@@ -577,6 +578,10 @@ class CallableInstanceType(GenericInstanceType, MethodType):
...
@@ -577,6 +578,10 @@ class CallableInstanceType(GenericInstanceType, MethodType):
def
__post_init__
(
self
):
def
__post_init__
(
self
):
if
self
.
optional_at
is
None
and
self
.
parameters
is
not
None
:
if
self
.
optional_at
is
None
and
self
.
parameters
is
not
None
:
self
.
optional_at
=
len
(
self
.
parameters
)
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
):
def
remove_self
(
self
,
self_type
):
assert
self
.
parameters
[
0
].
try_assign
(
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