Skip to content

Commit 130c251

Browse files
committed
add PyObjectSetAttr
1 parent 156ccdb commit 130c251

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.lib;
42+
43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
44+
import static com.oracle.graal.python.nodes.ErrorMessages.P_HAS_NO_ATTRS_S_TO_ASSIGN;
45+
import static com.oracle.graal.python.nodes.ErrorMessages.P_HAS_NO_ATTRS_S_TO_DELETE;
46+
import static com.oracle.graal.python.nodes.ErrorMessages.P_HAS_RO_ATTRS_S_TO_ASSIGN;
47+
import static com.oracle.graal.python.nodes.ErrorMessages.P_HAS_RO_ATTRS_S_TO_DELETE;
48+
49+
import com.oracle.graal.python.builtins.objects.PNone;
50+
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
51+
import com.oracle.graal.python.nodes.PRaiseNode;
52+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
53+
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
54+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodSlotNode;
55+
import com.oracle.graal.python.nodes.object.GetClassNode;
56+
import com.oracle.truffle.api.dsl.Cached.Shared;
57+
import com.oracle.truffle.api.dsl.Cached;
58+
import com.oracle.truffle.api.dsl.GenerateUncached;
59+
import com.oracle.truffle.api.dsl.ImportStatic;
60+
import com.oracle.truffle.api.dsl.Specialization;
61+
import com.oracle.truffle.api.frame.Frame;
62+
import com.oracle.truffle.api.nodes.Node;
63+
64+
/**
65+
* Equivalent PyObject_SetAttr*. Like Python, this method raises when the attribute doesn't exist.
66+
*/
67+
@GenerateUncached
68+
@ImportStatic(SpecialMethodSlot.class)
69+
public abstract class PyObjectSetAttr extends Node {
70+
public abstract void execute(Frame frame, Object receiver, Object name, Object value);
71+
72+
public final void delete(Frame frame, Object receiver, Object name) {
73+
execute(frame, receiver, name, null);
74+
}
75+
76+
@Specialization(guards = {"name == cachedName", "value != null"}, limit = "1")
77+
static void setFixedAttr(Frame frame, Object self, @SuppressWarnings("unused") String name, Object value,
78+
@SuppressWarnings("unused") @Cached("name") String cachedName,
79+
@Shared("getClass") @Cached GetClassNode getClass,
80+
@Shared("lookup") @Cached(parameters = "SetAttr") LookupSpecialMethodSlotNode lookupSetattr,
81+
@Shared("lookupGet") @Cached(parameters = "GetAttribute") LookupSpecialMethodSlotNode lookupGetattr,
82+
@Shared("raise") @Cached PRaiseNode raise,
83+
@Shared("call") @Cached CallTernaryMethodNode callSetattr) {
84+
Object type = getClass.execute(self);
85+
Object setattr = lookupSetattr.execute(frame, type, self);
86+
if (setattr == PNone.NO_VALUE) {
87+
if (lookupGetattr.execute(frame, type, self) == PNone.NO_VALUE) {
88+
throw raise.raise(TypeError, P_HAS_NO_ATTRS_S_TO_ASSIGN, self, name);
89+
} else {
90+
throw raise.raise(TypeError, P_HAS_RO_ATTRS_S_TO_ASSIGN, self, name);
91+
}
92+
}
93+
callSetattr.execute(frame, setattr, self, name, value);
94+
}
95+
96+
@Specialization(guards = {"name == cachedName", "value == null"}, limit = "1")
97+
static void delFixedAttr(Frame frame, Object self, @SuppressWarnings("unused") String name, @SuppressWarnings("unused") Object value,
98+
@SuppressWarnings("unused") @Cached("name") String cachedName,
99+
@Shared("getClass") @Cached GetClassNode getClass,
100+
@Shared("lookupDel") @Cached(parameters = "DelAttr") LookupSpecialMethodSlotNode lookupDelattr,
101+
@Shared("lookupGet") @Cached(parameters = "GetAttribute") LookupSpecialMethodSlotNode lookupGetattr,
102+
@Shared("raise") @Cached PRaiseNode raise,
103+
@Shared("callDel") @Cached CallBinaryMethodNode callDelattr) {
104+
Object type = getClass.execute(self);
105+
Object delattr = lookupDelattr.execute(frame, type, self);
106+
if (delattr == PNone.NO_VALUE) {
107+
if (lookupGetattr.execute(frame, type, self) == PNone.NO_VALUE) {
108+
throw raise.raise(TypeError, P_HAS_NO_ATTRS_S_TO_DELETE, self, name);
109+
} else {
110+
throw raise.raise(TypeError, P_HAS_RO_ATTRS_S_TO_DELETE, self, name);
111+
}
112+
}
113+
callDelattr.executeObject(frame, delattr, self, name);
114+
}
115+
116+
@Specialization(replaces = {"setFixedAttr", "delFixedAttr"})
117+
static void doDynamicAttr(Frame frame, Object self, String name, Object value,
118+
@Shared("getClass") @Cached GetClassNode getClass,
119+
@Shared("lookup") @Cached(parameters = "SetAttr") LookupSpecialMethodSlotNode lookupSetattr,
120+
@Shared("lookupDel") @Cached(parameters = "DelAttr") LookupSpecialMethodSlotNode lookupDelattr,
121+
@Shared("lookupGet") @Cached(parameters = "GetAttribute") LookupSpecialMethodSlotNode lookupGetattr,
122+
@Shared("raise") @Cached PRaiseNode raise,
123+
@Shared("call") @Cached CallTernaryMethodNode callSetattr,
124+
@Shared("callDel") @Cached CallBinaryMethodNode callDelattr) {
125+
if (value == null) {
126+
delFixedAttr(frame, self, name, value, name, getClass, lookupDelattr, lookupGetattr, raise, callDelattr);
127+
} else {
128+
setFixedAttr(frame, self, name, value, name, getClass, lookupSetattr, lookupGetattr, raise, callSetattr);
129+
}
130+
}
131+
132+
public static PyObjectSetAttr create() {
133+
return PyObjectSetAttrNodeGen.create();
134+
}
135+
136+
public static PyObjectSetAttr getUncached() {
137+
return PyObjectSetAttrNodeGen.getUncached();
138+
}
139+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ public abstract class ErrorMessages {
286286
public static final String GOT_UNEXPECTED_KEYWORD_ARG = "%s() got an unexpected keyword argument '%s'";
287287
public static final String HANDLER_MUST_BE_CALLABLE = "handler must be callable";
288288
public static final String HAS_NO_ATTR = "%s has no attribute %s";
289+
public static final String P_HAS_NO_ATTRS_S_TO_ASSIGN = "'%p' object has no attributes (assign to .%s)";
290+
public static final String P_HAS_NO_ATTRS_S_TO_DELETE = "'%p' object has no attributes (del .%s)";
291+
public static final String P_HAS_RO_ATTRS_S_TO_ASSIGN = "'%p' object has only read-only attributes (assign to .%s)";
292+
public static final String P_HAS_RO_ATTRS_S_TO_DELETE = "'%p' object has only read-only attributes (del .%s)";
289293
public static final String HASH_SHOULD_RETURN_INTEGER = "__hash__ method should return an integer";
290294
public static final String HEX_VALUE_TOO_LARGE_AS_FLOAT = "hexadecimal value too large to represent as a float";
291295
public static final String HOST_ACCESS_NOT_ALLOWED = "host access is not allowed";

0 commit comments

Comments
 (0)