Commit 4dda1cb4 authored by Tom Niget's avatar Tom Niget

Python ext works

parent fe2492d6
......@@ -318,7 +318,7 @@ struct ValueTypeEx {
// has ::iterator type
template <typename T> struct ValueType {
using type = typename T::iterator::value_type;
using type = decltype(*std::declval<T>().begin());
};
template <typename T>
......
......@@ -180,8 +180,10 @@ struct TyDict__oo : classtype<_Base0, TyDict__oo<>> {
Obj(std::unordered_map<K, V> &&m)
: _m(std::move(
std::make_shared<std::unordered_map<K, V>>(std::move(m)))) {}*/
Obj(std::initializer_list<typename map_type::value_type> &&m)
: _m(std::make_shared<map_type>(std::move(m))) {}
/*Obj(std::initializer_list<typename map_type::value_type> &&m)
: _m(std::make_shared<map_type>(std::move(m))) {}*/
Obj(std::initializer_list<std::pair<K, V>> && init)
: _m(std::make_shared<std::unordered_map<K, V>>(init.begin(), init.end())) {}
Obj() : _m(std::make_shared<map_type>()) {}
template <typename... Args>
......
......@@ -24,9 +24,17 @@ struct TyList__oo : classtype<_Base0, TyList__oo<>> {
auto operator()(auto self, auto other) const {
self->_v.reserve(self->_v.size() + other.size());
self->_v.insert(self->_v.end(), other.begin(), other.end());
return None;
}
} static constexpr extend{};
// append
struct : method {
auto operator()(auto self, auto value) const { self->_v->push_back(value);
return None;
}
} static constexpr append{};
struct : method {
auto operator()(auto self, auto other) const {
auto result = TyList__oo<>{}(self->_v);
......
#ifndef TYPON_DATACLASSES_HPP
#define TYPON_DATACLASSES_HPP
#include "builtins.hpp"
namespace py_dataclasses {
template <typename _Unused = void>
struct dataclasses__oo : referencemodel::moduletype<dataclasses__oo<>> {
};
dataclasses__oo<> all;
} // namespace py_dataclasses
#endif //TYPON_DATACLASSES_HPP
\ No newline at end of file
#ifndef TYPON_TYPON_HPP
#define TYPON_TYPON_HPP
#include "builtins.hpp"
namespace py_typon {
template <typename _Unused = void>
struct typon__oo : referencemodel::moduletype<typon__oo<>> {
};
typon__oo<> all;
} // namespace py_typon
#endif //TYPON_TYPON_HPP
\ No newline at end of file
def is_cpp() -> bool:
return False
export: BuiltinFeature["PybindExport"]
\ No newline at end of file
......@@ -90,7 +90,7 @@ def run_test(path, quiet=True):
if args.compile:
return TestStatus.SUCCESS
execute_str = "true" if (execute and not args.generate) else "false"
name_bin = path.with_suffix("").as_posix() + ("$(python3.12-config --extension-suffix)" if extension else ".exe")
name_bin = path.with_suffix("").as_posix() + ("\\$(python3.12-config --extension-suffix)" if extension else ".exe")
if exec_cmd(f'bash -c "export PYTHONPATH=stdlib; if {execute_str}; then echo python3.12 ./{path.as_posix()}; fi"') != 0:
return TestStatus.PYTHON_ERROR
if compile and (alt := environ.get("ALT_RUNNER")):
......
import pyext
p = pyext.Person("jean", 123)
print("Imported:", pyext.add(5, 3), pyext.fibo(10), pyext.squares(), p)
print(p.afficher("Bonjour"))
print(p.name, p.age)
\ No newline at end of file
# p = pyext.Person("jean", 123)
print("Imported:", pyext.add(5, 3), pyext.fibo(10), pyext.squares())
# print(p.afficher("Bonjour"))
# print(p.name, p.age)
\ No newline at end of file
# coding: utf-8
# extension
from typon import export
import numpy as np
from dataclasses import dataclass
# from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
def afficher(self, msg: str):
print(msg, ",", self.name, self.age)
return 123
# @dataclass
# class Person:
# name: str
# age: int
#
# def afficher(self, msg: str):
# print(msg, ",", self.name, self.age)
# return 123
@export([int, int])
def add(x, y):
return x + y
@export([int])
def fibo(n):
res = [0, 1]
for i in range(2, n):
res.append(res[i - 1] + res[i - 2])
return res
@export([])
def squares() -> list[int]:
return np.square([x for x in range(5)])
if __name__ == "__main__":
p = Person("jean", 123)
print("Python:", add(5, 3), fibo(10), squares(), p)
p.afficher("Bonjour")
\ No newline at end of file
# p = Person("jean", 123)
print("Python:", add(5, 3), fibo(10), squares())
# p.afficher("Bonjour")
\ No newline at end of file
......@@ -31,7 +31,6 @@ def handle_connection(connfd):
else:
http_pos = buf.find("HTTP/1.1\r\n")
s = "str(" + buf[12:http_pos-1] + ")"
#resp = eval(s, {"req": buf})
context = {"req": buf}
resp = eval(s, context)
response = response_fmt.format(len(resp), resp)
......
......@@ -7,7 +7,7 @@ from transpiler.phases.emit_cpp.function import emit_function, BlockVisitor
from transpiler.phases.emit_cpp.visitors import NodeVisitor, CoroutineMode
from transpiler.phases.typing.modules import ModuleType, TyponModuleType, PythonModuleType
from transpiler.phases.typing.types import CallableInstanceType, ClassTypeType, TypeVariable, BaseType, GenericType, \
GenericInstanceType, UserGenericType, RuntimeValue
GenericInstanceType, UserGenericType, RuntimeValue, BuiltinFeatureType
from transpiler.utils import linenodata
......@@ -83,9 +83,9 @@ def emit_module(mod: ModuleType) -> Iterable[str]:
yield from emit(node.module_obj)
prefix = "python_" if isinstance(node.module_obj, PythonModuleType) else ""
for alias in names:
if isinstance(node.module_obj, PythonModuleType):
if isinstance(node.module_obj.fields[alias.name].type.resolve(), TypeVariable):
continue # unused function
# if isinstance(node.module_obj, PythonModuleType):
if isinstance(node.module_obj.fields[alias.name].type.resolve(), (TypeVariable, BuiltinFeatureType)):
continue # unused function
incl_vars.append(f"auto& {alias.asname or alias.name} = py_{prefix}{node.module_obj.name()}::all.{alias.name};")
yield "namespace PROGRAMNS {"
yield from incl_vars
......
import ast
import copy
import dataclasses
from abc import ABCMeta
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, List, Dict, Callable
from logging import debug
from pathlib import Path
from typing import Optional, Callable
from transpiler.phases.typing.modules import parse_module
from transpiler.utils import highlight, linenodata
from transpiler.phases.typing.annotations import TypeAnnotationVisitor
from transpiler.phases.typing.common import PRELUDE, is_builtin
from transpiler.phases.typing.expr import ScoperExprVisitor
from transpiler.phases.typing.modules import parse_module
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, BlockData, TY_TASK, UserGenericType, UserType, BoundFuncTypeBase
MethodType, GenericType, BlockData, TY_TASK, UserGenericType, UserType, BoundFuncTypeBase
from transpiler.phases.utils import NodeVisitorSeq
from transpiler.utils import highlight, linenodata
def visit_generic_item(
visit_nongeneric: Callable[[Scope, ResolvedConcreteType], None],
node,
output_type: BuiltinGenericType,
scope: Scope,
instance_type = None,
force_generic = False):
instance_type=None,
force_generic=False):
if force_generic or node.type_params:
output_type.parameters = []
for param in node.type_params:
......@@ -41,6 +40,7 @@ def visit_generic_item(
if instance_type is None:
class instance_type(GenericInstanceType):
pass
instance_type.__name__ = f"GenericInstance${node.name}"
def instantiate(args: list[ConcreteType]) -> GenericInstanceType:
......@@ -64,12 +64,13 @@ def visit_generic_item(
new_scope.declare_local(name, TypeTupleType(list(args_iter)).type_type())
for a, b in constraints:
assert b.try_assign(a)
# todo
#  todo
new_output_type = instance_type()
new_output_type.generic_parent = output_type
new_output_type.generic_args = args
visit_nongeneric(new_scope, new_output_type)
return new_output_type
output_type.constraints_ = []
output_type.instantiate_ = instantiate
else:
......@@ -112,7 +113,7 @@ class StdlibVisitor(NodeVisitorSeq):
ty = self.anno().visit(node.annotation)
if self.cur_class:
assert isinstance(self.cur_class, ResolvedConcreteType)
self.cur_class.fields[node.target.id] = MemberDef(ty)
self.cur_class.fields[node.target.id] = MemberDef(ty, in_class_def=True, from_node=node)
self.scope.vars[node.target.id] = VarDecl(VarKind.LOCAL, ty)
def visit_ImportFrom(self, node: ast.ImportFrom):
......@@ -139,7 +140,8 @@ class StdlibVisitor(NodeVisitorSeq):
NewType = existing.type.inner_type
else:
if node.type_params or force_generic:
base_class, base_type = create_builtin_generic_type, (BuiltinGenericType if self.is_native else UserGenericType)
base_class, base_type = create_builtin_generic_type, (
BuiltinGenericType if self.is_native else UserGenericType)
else:
base_class, base_type = create_builtin_type, (BuiltinType if self.is_native else UserType)
NewType = base_class(node.name,
......@@ -163,6 +165,36 @@ class StdlibVisitor(NodeVisitorSeq):
raise NotImplementedError("parents not handled yet: " + ", ".join(map(ast.unparse, node.bases)))
for stmt in node.body:
visitor.visit(stmt)
for deco_node in node.decorator_list:
deco = self.expr().visit(deco_node)
match deco:
case dc if is_builtin(dc, "dataclass"):
real_fields = {k: m for k, m in output.fields.items() if
not isinstance(m.from_node, ast.FunctionDef)}
generated_init = ast.FunctionDef(
name="__init__",
args=ast.arguments(
posonlyargs=[],
args=[ast.arg(arg="self", annotation=None)] +
[ast.arg(arg=k, annotation=None) for k, m in real_fields.items()],
vararg=None, kwonlyargs=[],
kw_defaults=[], kwarg=None,
defaults=[]), body=[
ast.Assign(
targets=[
ast.Attribute(value=ast.Name("self", ast.Load()), attr=k, ctx=ast.Store())
],
value=ast.Name(k, ast.Load()),
type_comment=None,
**linenodata(node)
) for k in real_fields],
decorator_list=[],
returns=None,
type_params=[],
**linenodata(node))
visitor.visit(generated_init)
case _:
raise NotImplementedError(f"Decorator {deco} not handled yet")
if "__init__" not in output.fields:
visitor.visit(ast.FunctionDef(
name="__init__",
......@@ -226,11 +258,11 @@ class StdlibVisitor(NodeVisitorSeq):
arg_name = "Self"
else:
arg_name = f"AutoVar${abs(hash(arg.arg))}"
node.type_params.append(ast.TypeVar(arg_name, None)) # todo: bounds
node.type_params.append(ast.TypeVar(arg_name, None)) # todo: bounds
arg.annotation = ast.Name(arg_name, ast.Load())
else:
if isinstance(arg.annotation, ast.Name) and (
#arg.annotation.id == "Self" or
# arg.annotation.id == "Self" or
any(k.name == arg.annotation.id for k in node.type_params)
):
# annotation is type variable so we keep it
......@@ -252,6 +284,7 @@ class StdlibVisitor(NodeVisitorSeq):
cur_class_ref = self.cur_class
if cur_class_ref is not None:
bases.append(MethodType)
class FuncType(*bases):
def name(self):
return f"FuncTypeGen${node.name}"
......@@ -278,9 +311,26 @@ class StdlibVisitor(NodeVisitorSeq):
NewType = base_class()
FuncType.__name__ = NewType.name()
self.scope.vars[node.name] = VarDecl(VarKind.LOCAL, NewType, is_item_decl=True)
for deco_node in copy.deepcopy(node.decorator_list):
if isinstance(deco_node, ast.Call):
deco_args = deco_node.args
deco_node = deco_node.func
else:
deco_args = []
deco = self.expr().visit(deco_node)
match deco:
case dc if is_builtin(dc, "PybindExport"):
assert len(deco_args) == 1
export = deco_args[0]
assert isinstance(export, ast.List)
exports = [self.anno().visit(e) for e in export.elts]
NewType.pybind_exports = exports
case _:
raise NotImplementedError(f"Decorator {deco} not handled yet")
self.scope.vars[node.name] = VarDecl(VarKind.LOCAL, NewType, is_item_decl=True, from_node=node)
if self.cur_class is not None:
self.cur_class.fields[node.name] = MemberDef(NewType, node, in_class_def=True)
self.cur_class.fields[node.name] = MemberDef(NewType, node, in_class_def=True, from_node=node)
visit_generic_item(visit_nongeneric, node, NewType, self.scope, InstanceType, True)
......@@ -306,4 +356,4 @@ class StdlibVisitor(NodeVisitorSeq):
raise UnknownNameError(node)
def visit_Name(self, node: ast.Name) -> BaseType:
return self.visit_str(node.id)
\ No newline at end of file
return self.visit_str(node.id)
......@@ -13,6 +13,7 @@ from transpiler.phases.desugar_op import DesugarOp
from transpiler.phases.desugar_subscript import DesugarSubscript
from transpiler.phases.desugar_with import DesugarWith
from transpiler.phases.emit_cpp.module import emit_module
from transpiler.phases.emit_cpp.visitors import NodeVisitor
from transpiler.phases.if_main import IfMainVisitor
from transpiler.phases.typing import PRELUDE
from transpiler.phases.typing.modules import parse_module
......@@ -54,12 +55,33 @@ def transpile(source, name: str, path: Path):
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}'\";"
yield f"PYBIND11_MODULE({module.name()}, m) {{"
yield f"m.doc() = \"Typon extension module '{module.name()}'\";"
for n, f in module.fields.items():
if not f.in_class_def:
continue
node = f.from_node
if getattr(node, "is_main", False):
continue
if isinstance(node, ast.FunctionDef):
if (exports := getattr(f.type, "pybind_exports", None)) is not None:
yield f'm.def("{n}", []('
for i, ty in enumerate(exports):
if i != 0:
yield ","
yield from NodeVisitor().visit_BaseType(ty)
yield f"arg{i}"
yield ") {"
yield f"return PROGRAMNS::{module.name()}.{node.name}("
for i, _ in enumerate(exports):
if i != 0:
yield ","
yield f"arg{i}"
yield ").call(); });"
# visitor = ModuleVisitorExt(self.scope)
# code = [line for stmt in node.body for line in visitor.visit(stmt)]
# yield from code
# yield "}"
yield "}"
yield "#else"
yield "typon::Root root() {"
yield f"co_await dot(PROGRAMNS::{module.name()}, main)();"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment