Skip to content

Commit 97d82c4

Browse files
committed
Core compilation routines for Alternative, NamedTuple, Tuple.
1 parent 923452b commit 97d82c4

13 files changed

Lines changed: 564 additions & 38 deletions

nativepython/expression_conversion_context.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,8 @@ def convert_expression_ast(self, ast):
502502
return pythonObjectRepresentation(self, __builtins__[ast.id])
503503

504504
if ast.id not in self.functionContext._varname_to_type:
505-
raise ConversionException(
506-
"can't find variable %s" % ast.id
507-
)
505+
self.pushException(NameError, "name '%s' is not defined" % ast.id)
506+
return None
508507

509508
if ast.matches.Num:
510509
if ast.n.matches.None_:

nativepython/python_object_representation.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
from nativepython.type_wrappers.python_typed_function_wrapper import PythonTypedFunctionWrapper
88
from nativepython.type_wrappers.tuple_of_wrapper import TupleOfWrapper
99
from nativepython.type_wrappers.one_of_wrapper import OneOfWrapper
10-
from nativepython.type_wrappers.class_wrapper import ClassWrapper, BoundMethodWrapper
10+
from nativepython.type_wrappers.class_wrapper import ClassWrapper
11+
from nativepython.type_wrappers.tuple_wrapper import TupleWrapper, NamedTupleWrapper
12+
from nativepython.type_wrappers.alternative_wrapper import makeAlternativeWrapper
13+
from nativepython.type_wrappers.bound_method_wrapper import BoundMethodWrapper
1114
from nativepython.type_wrappers.len_wrapper import LenWrapper
1215
from nativepython.type_wrappers.arithmetic_wrapper import Int64Wrapper, Float64Wrapper, BoolWrapper
1316
from nativepython.type_wrappers.string_wrapper import StringWrapper
@@ -52,6 +55,18 @@ def _typedPythonTypeToTypeWrapper(t):
5255
if t.__typed_python_category__ == "Class":
5356
return ClassWrapper(t)
5457

58+
if t.__typed_python_category__ == "Alternative":
59+
return makeAlternativeWrapper(t)
60+
61+
if t.__typed_python_category__ == "ConcreteAlternative":
62+
return makeAlternativeWrapper(t)
63+
64+
if t.__typed_python_category__ == "NamedTuple":
65+
return NamedTupleWrapper(t)
66+
67+
if t.__typed_python_category__ == "Tuple":
68+
return TupleWrapper(t)
69+
5570
if t.__typed_python_category__ == "Function":
5671
return PythonTypedFunctionWrapper(t)
5772

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2018 Braxton Mckee
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typed_python import *
16+
import typed_python._types as _types
17+
from nativepython.runtime import Runtime
18+
import unittest
19+
import time
20+
import psutil
21+
22+
def Compiled(f):
23+
f = TypedFunction(f)
24+
return Runtime.singleton().compile(f)
25+
26+
class TestAlternativeCompilation(unittest.TestCase):
27+
def test_simple_alternative_passing(self):
28+
Simple = Alternative("Simple", A={}, B={}, C={})
29+
30+
@Compiled
31+
def f(s: Simple):
32+
y = s
33+
return y
34+
35+
self.assertEqual(f(Simple.A()), Simple.A())
36+
self.assertEqual(f(Simple.B()), Simple.B())
37+
self.assertEqual(f(Simple.C()), Simple.C())
38+
39+
def test_complex_alternative_passing(self):
40+
Complex = Alternative("Complex",
41+
A={'a': str, 'b': int},
42+
B={'a': str, 'c': int},
43+
C={'a': str, 'd': lambda: Complex}
44+
)
45+
46+
c = Complex.A(a="hi", b=20)
47+
c2 = Complex.C(a="hi", d=c)
48+
49+
@Compiled
50+
def f(c: Complex):
51+
y = c
52+
return y
53+
54+
self.assertEqual(f(c), c)
55+
self.assertEqual(f(c2), c2)
56+
57+
self.assertEqual(_types.refcount(c), 2)
58+
self.assertEqual(_types.refcount(c2), 1)

nativepython/tests/conversion_test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,14 @@ def g(x: int):
290290

291291
self.assertEqual(g(1), None)
292292

293+
def test_nonexistent_variable(self):
294+
@Compiled
295+
def f():
296+
return this_variable_name_is_undefined
297+
298+
with self.assertRaisesRegex(Exception, "name 'this_variable_name_is_undefined' is not defined"):
299+
f()
300+
293301

294302

295303

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright 2018 Braxton Mckee
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typed_python import *
16+
import typed_python._types as _types
17+
from nativepython.runtime import Runtime
18+
import unittest
19+
import time
20+
import psutil
21+
22+
def Compiled(f):
23+
f = TypedFunction(f)
24+
return Runtime.singleton().compile(f)
25+
26+
class TestTupleCompilation(unittest.TestCase):
27+
def test_tuple_passing(self):
28+
T = Tuple(float, int, str)
29+
30+
@Compiled
31+
def f(x: T) -> T:
32+
y = x
33+
return y
34+
35+
t = T((0.0,1,"hi"))
36+
self.assertEqual(f(t), t)
37+
38+
def test_named_tuple_passing(self):
39+
NT = NamedTuple(a=float, b=int, c=str)
40+
41+
@Compiled
42+
def f(x: NT) -> NT:
43+
y = x
44+
return y
45+
46+
nt = NT(a=0.0, b=1, c="hi")
47+
self.assertEqual(f(nt), nt)
48+
49+
def test_named_tuple_getattr(self):
50+
NT = NamedTuple(a=float, b=int, c=str)
51+
52+
@Compiled
53+
def f(x: NT) -> str:
54+
return x.c + x.c
55+
56+
nt = NT(a=0.0, b=1, c="hi")
57+
self.assertEqual(f(nt), "hihi")
58+
59+
def test_named_tuple_assignment_refcounting(self):
60+
class C(Class):
61+
x = Member(int)
62+
63+
NT = NamedTuple(c=C)
64+
65+
@Compiled
66+
def f(x: NT):
67+
y = x
68+
return y.c
69+
70+
c = C(x=20)
71+
res = f(NT(c=c))
72+
73+
self.assertEqual(res.x, 20)
74+
self.assertEqual(_types.refcount(res), 2)
75+
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Copyright 2018 Braxton Mckee
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from nativepython.type_wrappers.wrapper import Wrapper
16+
from nativepython.type_wrappers.refcounted_wrapper import RefcountedWrapper
17+
from nativepython.typed_expression import TypedExpression
18+
from nativepython.type_wrappers.exceptions import generateThrowException
19+
import nativepython.type_wrappers.runtime_functions as runtime_functions
20+
21+
from typed_python import NoneType, Int64, _types
22+
23+
import nativepython.native_ast as native_ast
24+
import nativepython
25+
26+
27+
typeWrapper = lambda x: nativepython.python_object_representation.typedPythonTypeToTypeWrapper(x)
28+
29+
def makeAlternativeWrapper(t):
30+
if t.__typed_python_category__ == "ConcreteAlternative":
31+
return ConcreteAlternativeWrapper(t)
32+
33+
if _types.all_alternatives_empty(t):
34+
return SimpleAlternativeWrapper(t)
35+
else:
36+
return AlternativeWrapper(t)
37+
38+
class SimpleAlternativeWrapper(Wrapper):
39+
"""Wrapper around alternatives with all empty arguments."""
40+
is_pod = True
41+
is_empty = False
42+
is_pass_by_ref = False
43+
44+
def __init__(self, t):
45+
super().__init__(t)
46+
47+
self.layoutType = native_ast.UInt8
48+
49+
def getNativeLayoutType(self):
50+
return self.layoutType
51+
52+
def convert_default_initialize(self, context, target):
53+
return self.convert_copy_initialize(
54+
context,
55+
target,
56+
nativepython.python_object_representation.pythonObjectRepresentation(context, self.typeRepresentation())
57+
)
58+
59+
def convert_destroy(self, context, target):
60+
pass
61+
62+
def convert_assign(self, context, target, toStore):
63+
assert target.isReference
64+
context.pushEffect(
65+
target.expr.store(toStore.nonref_expr)
66+
)
67+
68+
def convert_copy_initialize(self, context, target, toStore):
69+
assert target.isReference
70+
context.pushEffect(
71+
target.expr.store(toStore.nonref_expr)
72+
)
73+
74+
class AlternativeWrapper(RefcountedWrapper):
75+
is_empty = False
76+
is_pod = False
77+
is_pass_by_ref = True
78+
79+
def __init__(self, t):
80+
super().__init__(t)
81+
82+
element_types = [('refcount', native_ast.Int64), ('which', native_ast.Int64), ('data',native_ast.UInt8)]
83+
84+
self.alternativeType = t
85+
self.layoutType = native_ast.Type.Struct(element_types=element_types,name=t.__qualname__+"Layout").pointer()
86+
self._alternatives = None
87+
88+
@property
89+
def alternatives(self):
90+
"""Return a list of type wrappers for our alternative bodies.
91+
92+
This function has to be deferred until after the object is created if we have recursive alternatives.
93+
"""
94+
if self._alternatives is None:
95+
self._alternatives = [typeWrapper(x.ElementType) for x in self.typeRepresentation.__typed_python_alternatives__]
96+
return self._alternatives
97+
98+
def getNativeLayoutType(self):
99+
return self.layoutType
100+
101+
def on_refcount_zero(self, context, instance):
102+
return (
103+
context.converter.defineNativeFunction(
104+
"destructor_" + str(self.typeRepresentation),
105+
('destructor', self),
106+
[self],
107+
typeWrapper(NoneType()),
108+
self.generateNativeDestructorFunction
109+
)
110+
.call(instance)
111+
)
112+
113+
def refAs(self, context, instance, whichIx):
114+
return context.pushReference(
115+
self.alternatives[whichIx].typeRepresentation,
116+
instance.nonref_expr.ElementPtrIntegers(0,2).cast(self.alternatives[whichIx].getNativeLayoutType().pointer())
117+
)
118+
119+
def generateNativeDestructorFunction(self, context, out, instance):
120+
with context.switch(instance.nonref_expr.ElementPtrIntegers(0,1).load(), range(len(self.alternatives)), False) as indicesAndContexts:
121+
for ix, subcontext in indicesAndContexts:
122+
with subcontext:
123+
self.refAs(context, instance, ix).convert_destroy()
124+
125+
context.pushEffect(runtime_functions.free.call(instance.nonref_expr.cast(native_ast.UInt8Ptr)))
126+
127+
def convert_attribute(self, context, instance, attribute, nocheck=False):
128+
pass
129+
130+
def generateConstructor(self, context, out, *args):
131+
pass
132+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright 2018 Braxton Mckee
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from nativepython.type_wrappers.wrapper import Wrapper
16+
from nativepython.typed_expression import TypedExpression
17+
from nativepython.type_wrappers.exceptions import generateThrowException
18+
import nativepython.type_wrappers.runtime_functions as runtime_functions
19+
20+
from typed_python import NoneType, Int64, _types
21+
22+
import nativepython.native_ast as native_ast
23+
import nativepython
24+
25+
typeWrapper = lambda x: nativepython.python_object_representation.typedPythonTypeToTypeWrapper(x)
26+
27+
class BoundMethodWrapper(Wrapper):
28+
def __init__(self, t):
29+
super().__init__(t)
30+
31+
self.firstArgType = typeWrapper(self.typeRepresentation.FirstArgType)
32+
33+
def convert_assign(self, context, target, toStore):
34+
return self.firstArgType.convert_assign(
35+
context,
36+
target.changeType(self.firstArgType),
37+
toStore.changeType(self.firstArgType)
38+
)
39+
40+
def convert_copy_initialize(self, context, target, toStore):
41+
return self.firstArgType.convert_copy_initialize(
42+
context,
43+
target.changeType(self.firstArgType),
44+
toStore.changeType(self.firstArgType)
45+
)
46+
47+
def convert_destroy(self, context, instance):
48+
return self.firstArgType.convert_destroy(
49+
context,
50+
target.changeType(self.firstArgType),
51+
toStore.changeType(self.firstArgType)
52+
)
53+
54+
def convert_call(self, context, left, args):
55+
clsType = typeWrapper(self.typeRepresentation.FirstArgType)
56+
funcType = typeWrapper(self.typeRepresentation.Function)
57+
58+
return funcType.convert_call(
59+
context,
60+
context.pushPod(funcType, native_ast.nullExpr),
61+
(left.changeType(clsType),) + tuple(args)
62+
)
63+
64+
65+

0 commit comments

Comments
 (0)