Skip to content

Commit 7228ada

Browse files
committed
intrinsify classmethod and staticmethod
1 parent 17ba95e commit 7228ada

File tree

12 files changed

+321
-105
lines changed

12 files changed

+321
-105
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@
125125
import com.oracle.graal.python.builtins.objects.memoryview.MemoryviewBuiltins;
126126
import com.oracle.graal.python.builtins.objects.method.AbstractMethodBuiltins;
127127
import com.oracle.graal.python.builtins.objects.method.BuiltinMethodBuiltins;
128+
import com.oracle.graal.python.builtins.objects.method.ClassmethodBuiltins;
129+
import com.oracle.graal.python.builtins.objects.method.DecoratedMethodBuiltins;
128130
import com.oracle.graal.python.builtins.objects.method.MethodBuiltins;
131+
import com.oracle.graal.python.builtins.objects.method.StaticmethodBuiltins;
129132
import com.oracle.graal.python.builtins.objects.module.PythonModule;
130133
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
131134
import com.oracle.graal.python.builtins.objects.object.PythonObject;
@@ -224,6 +227,9 @@ private static final PythonBuiltins[] initializeBuiltins() {
224227
List<PythonBuiltins> builtins = new ArrayList<>(Arrays.asList(
225228
new BuiltinConstructors(),
226229
new BuiltinFunctions(),
230+
new DecoratedMethodBuiltins(),
231+
new ClassmethodBuiltins(),
232+
new StaticmethodBuiltins(),
227233
new InteropModuleBuiltins(),
228234
new ObjectBuiltins(),
229235
new CellBuiltins(),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public enum PythonBuiltinClassType implements LazyPythonClass {
9191
PLock("LockType", "_thread"),
9292
PRLock("RLock", "_thread"),
9393
PSocket("socket", "_socket"),
94+
PStaticmethod("staticmethod", "builtins"),
95+
PClassmethod("classmethod", "builtins"),
9496

9597
// Errors and exceptions:
9698

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static com.oracle.graal.python.nodes.BuiltinNames.BOOL;
3030
import static com.oracle.graal.python.nodes.BuiltinNames.BYTEARRAY;
3131
import static com.oracle.graal.python.nodes.BuiltinNames.BYTES;
32+
import static com.oracle.graal.python.nodes.BuiltinNames.CLASSMETHOD;
3233
import static com.oracle.graal.python.nodes.BuiltinNames.COMPLEX;
3334
import static com.oracle.graal.python.nodes.BuiltinNames.DICT;
3435
import static com.oracle.graal.python.nodes.BuiltinNames.ENUMERATE;
@@ -42,6 +43,7 @@
4243
import static com.oracle.graal.python.nodes.BuiltinNames.RANGE;
4344
import static com.oracle.graal.python.nodes.BuiltinNames.REVERSED;
4445
import static com.oracle.graal.python.nodes.BuiltinNames.SET;
46+
import static com.oracle.graal.python.nodes.BuiltinNames.STATICMETHOD;
4547
import static com.oracle.graal.python.nodes.BuiltinNames.STR;
4648
import static com.oracle.graal.python.nodes.BuiltinNames.SUPER;
4749
import static com.oracle.graal.python.nodes.BuiltinNames.TUPLE;
@@ -106,6 +108,7 @@
106108
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
107109
import com.oracle.graal.python.builtins.objects.type.PythonClass;
108110
import com.oracle.graal.python.nodes.PGuards;
111+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
109112
import com.oracle.graal.python.nodes.argument.CreateArgumentsNode;
110113
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
111114
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
@@ -2137,4 +2140,41 @@ Object doObjectIndirect(PythonClass self, @SuppressWarnings("unused") Object typ
21372140
return factory().createSuperObject(self);
21382141
}
21392142
}
2143+
2144+
@Builtin(name = CLASSMETHOD, fixedNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PClassmethod, doc = "classmethod(function) -> method\n" +
2145+
"\n" +
2146+
"Convert a function to be a class method.\n" +
2147+
"\n" +
2148+
"A class method receives the class as implicit first argument,\n" +
2149+
"just like an instance method receives the instance.\n" +
2150+
"To declare a class method, use this idiom:\n" +
2151+
"\n" +
2152+
" class C:\n" +
2153+
" @classmethod\n" +
2154+
" def f(cls, arg1, arg2, ...):\n" +
2155+
" ...\n" +
2156+
"\n" +
2157+
"It can be called either on the class (e.g. C.f()) or on an instance\n" +
2158+
"(e.g. C().f()). The instance is ignored except for its class.\n" +
2159+
"If a class method is called for a derived class, the derived class\n" +
2160+
"object is passed as the implied first argument.\n" +
2161+
"\n" +
2162+
"Class methods are different than C++ or Java static methods.\n" +
2163+
"If you want those, see the staticmethod builtin.")
2164+
@GenerateNodeFactory
2165+
public abstract static class ClassmethodNode extends PythonBinaryBuiltinNode {
2166+
@Specialization
2167+
Object doObjectIndirect(PythonClass self, @SuppressWarnings("unused") Object callable) {
2168+
return factory().createClassmethod(self);
2169+
}
2170+
}
2171+
2172+
@Builtin(name = STATICMETHOD, fixedNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PStaticmethod)
2173+
@GenerateNodeFactory
2174+
public abstract static class StaticmethodNode extends PythonBinaryBuiltinNode {
2175+
@Specialization
2176+
Object doObjectIndirect(PythonClass self, @SuppressWarnings("unused") Object callable) {
2177+
return factory().createStaticmethod(self);
2178+
}
2179+
}
21402180
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package com.oracle.graal.python.builtins.objects.method;
28+
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GET__;
30+
31+
import java.util.List;
32+
33+
import com.oracle.graal.python.builtins.Builtin;
34+
import com.oracle.graal.python.builtins.CoreFunctions;
35+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
36+
import com.oracle.graal.python.builtins.PythonBuiltins;
37+
import com.oracle.graal.python.builtins.objects.function.PFunction;
38+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
39+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
40+
import com.oracle.graal.python.nodes.object.GetClassNode;
41+
import com.oracle.truffle.api.dsl.Cached;
42+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
43+
import com.oracle.truffle.api.dsl.NodeFactory;
44+
import com.oracle.truffle.api.dsl.Specialization;
45+
import com.oracle.truffle.api.profiles.BranchProfile;
46+
47+
@CoreFunctions(extendClasses = {PythonBuiltinClassType.PClassmethod})
48+
public class ClassmethodBuiltins extends PythonBuiltins {
49+
50+
@Override
51+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
52+
return ClassmethodBuiltinsFactory.getFactories();
53+
}
54+
55+
@Builtin(name = __GET__, minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 4)
56+
@GenerateNodeFactory
57+
abstract static class CallNode extends PythonBuiltinNode {
58+
@Specialization(guards = {"isNoValue(type)"})
59+
protected Object get(PDecoratedMethod self, Object obj, @SuppressWarnings("unused") Object type,
60+
@Cached("create()") GetClassNode getClass,
61+
@Cached("create()") BranchProfile uninitialized,
62+
@Cached("create()") BranchProfile genericCallable) {
63+
return doGet(self, getClass.execute(obj), uninitialized, genericCallable);
64+
}
65+
66+
@Specialization(guards = "!isNoValue(type)")
67+
protected Object doIt(PDecoratedMethod self, @SuppressWarnings("unused") Object obj, Object type,
68+
@Cached("create()") BranchProfile uninitialized,
69+
@Cached("create()") BranchProfile genericCallable) {
70+
return doGet(self, type, uninitialized, genericCallable);
71+
}
72+
73+
private PMethod doGet(PDecoratedMethod self, Object type, BranchProfile uninitialized, BranchProfile genericCallable) {
74+
Object callable = self.getCallable();
75+
if (callable == null) {
76+
uninitialized.enter();
77+
throw raise(PythonBuiltinClassType.RuntimeError, "uninitialized classmethod object");
78+
}
79+
if (callable instanceof PFunction) {
80+
return factory().createMethod(type, (PFunction) callable);
81+
}
82+
genericCallable.enter();
83+
throw raise(PythonBuiltinClassType.NotImplementedError, "classmethods with non-function callables");
84+
}
85+
}
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package com.oracle.graal.python.builtins.objects.method;
28+
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
30+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__FUNC__;
31+
32+
import java.util.List;
33+
34+
import com.oracle.graal.python.builtins.Builtin;
35+
import com.oracle.graal.python.builtins.CoreFunctions;
36+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
37+
import com.oracle.graal.python.builtins.PythonBuiltins;
38+
import com.oracle.graal.python.builtins.objects.PNone;
39+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
40+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
41+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
42+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
43+
import com.oracle.truffle.api.dsl.NodeFactory;
44+
import com.oracle.truffle.api.dsl.Specialization;
45+
46+
@CoreFunctions(extendClasses = {PythonBuiltinClassType.PStaticmethod, PythonBuiltinClassType.PClassmethod})
47+
public class DecoratedMethodBuiltins extends PythonBuiltins {
48+
49+
@Override
50+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
51+
return DecoratedMethodBuiltinsFactory.getFactories();
52+
}
53+
54+
@Builtin(name = __INIT__, fixedNumOfPositionalArgs = 2)
55+
@GenerateNodeFactory
56+
abstract static class InitNode extends PythonBinaryBuiltinNode {
57+
@Specialization
58+
protected PNone init(PDecoratedMethod self, Object callable) {
59+
self.setCallable(callable);
60+
return PNone.NONE;
61+
}
62+
}
63+
64+
@Builtin(name = __FUNC__, fixedNumOfPositionalArgs = 1, isGetter = true)
65+
@GenerateNodeFactory
66+
abstract static class FuncNode extends PythonUnaryBuiltinNode {
67+
@Specialization
68+
protected Object func(PDecoratedMethod self) {
69+
return self.getCallable();
70+
}
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.oracle.graal.python.builtins.objects.method;
2+
3+
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
4+
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
5+
6+
/**
7+
* Storage for both classmethods and staticmethods
8+
*/
9+
public class PDecoratedMethod extends PythonBuiltinObject {
10+
private Object callable;
11+
12+
public PDecoratedMethod(LazyPythonClass cls) {
13+
super(cls);
14+
}
15+
16+
public PDecoratedMethod(LazyPythonClass cls, Object callable) {
17+
this(cls);
18+
this.callable = callable;
19+
}
20+
21+
public Object getCallable() {
22+
return callable;
23+
}
24+
25+
public void setCallable(Object callable) {
26+
this.callable = callable;
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package com.oracle.graal.python.builtins.objects.method;
28+
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GET__;
30+
31+
import java.util.List;
32+
33+
import com.oracle.graal.python.builtins.Builtin;
34+
import com.oracle.graal.python.builtins.CoreFunctions;
35+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
36+
import com.oracle.graal.python.builtins.PythonBuiltins;
37+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
38+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
39+
import com.oracle.truffle.api.dsl.Cached;
40+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
41+
import com.oracle.truffle.api.dsl.NodeFactory;
42+
import com.oracle.truffle.api.dsl.Specialization;
43+
import com.oracle.truffle.api.profiles.BranchProfile;
44+
45+
@CoreFunctions(extendClasses = {PythonBuiltinClassType.PStaticmethod})
46+
public class StaticmethodBuiltins extends PythonBuiltins {
47+
48+
@Override
49+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
50+
return StaticmethodBuiltinsFactory.getFactories();
51+
}
52+
53+
@Builtin(name = __GET__, minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 4)
54+
@GenerateNodeFactory
55+
abstract static class GetNode extends PythonBuiltinNode {
56+
@Specialization
57+
protected Object get(PDecoratedMethod self, @SuppressWarnings("unused") Object obj, @SuppressWarnings("unused") Object type,
58+
@Cached("create()") BranchProfile uninitialized) {
59+
Object callable = self.getCallable();
60+
if (callable == null) {
61+
uninitialized.enter();
62+
throw raise(PythonBuiltinClassType.RuntimeError, "uninitialized staticmethod object");
63+
}
64+
return callable;
65+
}
66+
}
67+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PythonObjectFactory.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import com.oracle.graal.python.builtins.objects.memoryview.PBuffer;
8383
import com.oracle.graal.python.builtins.objects.memoryview.PMemoryView;
8484
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
85+
import com.oracle.graal.python.builtins.objects.method.PDecoratedMethod;
8586
import com.oracle.graal.python.builtins.objects.method.PMethod;
8687
import com.oracle.graal.python.builtins.objects.module.PythonModule;
8788
import com.oracle.graal.python.builtins.objects.object.PythonObject;
@@ -393,6 +394,22 @@ public GetSetDescriptor createGetSetDescriptor(PythonCallable get, PythonCallabl
393394
return trace(new GetSetDescriptor(PythonBuiltinClassType.GetSetDescriptor, get, set, name, type));
394395
}
395396

397+
public PDecoratedMethod createClassmethod(LazyPythonClass cls) {
398+
return trace(new PDecoratedMethod(cls));
399+
}
400+
401+
public Object createClassmethod(Object callable) {
402+
return trace(new PDecoratedMethod(PythonBuiltinClassType.PClassmethod, callable));
403+
}
404+
405+
public PDecoratedMethod createStaticmethod(LazyPythonClass cls) {
406+
return trace(new PDecoratedMethod(cls));
407+
}
408+
409+
public Object createStaticmethod(Object callable) {
410+
return trace(new PDecoratedMethod(PythonBuiltinClassType.PStaticmethod, callable));
411+
}
412+
396413
/*
397414
* Lists, sets and dicts
398415
*/

graalpython/lib-graalpython/builtins.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ def __import__(filename, module_name):
5656

5757

5858
__import__("%s/functions.py", "builtins")
59-
__import__("%s/staticmethod.py", "builtins")
60-
__import__("%s/classmethod.py", "builtins")
6159
__import__("%s/exceptions.py", "builtins")
6260
__import__("%s/super.py", "builtins")
6361
__import__("%s/property.py", "builtins")

0 commit comments

Comments
 (0)