Skip to content

Commit 4b2092b

Browse files
committed
AST validator
1 parent 9bb885e commit 4b2092b

File tree

5 files changed

+971
-23
lines changed

5 files changed

+971
-23
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstModuleBuiltins.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ public static Object sst2Obj(PythonContext context, ModTy mod) {
147147

148148
@TruffleBoundary
149149
public static ModTy obj2sst(PythonContext context, Object obj) {
150-
return new Obj2Sst(getAstState(context)).obj2ModTy(obj);
150+
// TODO PyAST_obj2mod
151+
ModTy mod = new Obj2Sst(getAstState(context)).obj2ModTy(obj);
152+
Validator.validateMod(mod);
153+
return mod;
151154
}
152155

153156
@TruffleBoundary

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/Obj2SstBase.java

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules.ast;
4242

43+
import static com.oracle.graal.python.builtins.modules.ast.AstState.T_C_CONSTANT;
44+
import static com.oracle.graal.python.builtins.modules.ast.AstState.T_F_VALUE;
45+
import static com.oracle.graal.python.nodes.ErrorMessages.AST_IDENTIFIER_MUST_BE_OF_TYPE_STR;
4346
import static com.oracle.graal.python.nodes.ErrorMessages.EXPECTED_SOME_SORT_OF_S_BUT_GOT_S;
47+
import static com.oracle.graal.python.nodes.ErrorMessages.FIELD_S_IS_REQUIRED_FOR_S;
48+
import static com.oracle.graal.python.nodes.ErrorMessages.INVALID_INTEGER_VALUE;
4449
import static com.oracle.graal.python.nodes.ErrorMessages.REQUIRED_FIELD_S_MISSING_FROM_S;
4550
import static com.oracle.graal.python.nodes.ErrorMessages.S_FIELD_S_CHANGED_SIZE_DURING_ITERATION;
4651
import static com.oracle.graal.python.nodes.ErrorMessages.S_FIELD_S_MUST_BE_A_LIST_NOT_P;
@@ -52,11 +57,13 @@
5257
import com.oracle.graal.python.builtins.objects.list.PList;
5358
import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass;
5459
import com.oracle.graal.python.lib.PyLongAsIntNode;
60+
import com.oracle.graal.python.lib.PyLongCheckNode;
5561
import com.oracle.graal.python.lib.PyObjectLookupAttr;
5662
import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode;
5763
import com.oracle.graal.python.nodes.PRaiseNode;
5864
import com.oracle.graal.python.nodes.SpecialMethodNames;
5965
import com.oracle.graal.python.nodes.call.CallNode;
66+
import com.oracle.graal.python.nodes.util.CannotCastException;
6067
import com.oracle.graal.python.nodes.util.CastToJavaBooleanNode;
6168
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
6269
import com.oracle.graal.python.pegparser.sst.ConstantValue;
@@ -78,50 +85,64 @@ interface Conversion<T> {
7885
}
7986

8087
<T> T lookupAndConvert(Object obj, TruffleString attrName, TruffleString nodeName, Conversion<T> conversion, boolean required) {
81-
Object tmp = PyObjectLookupAttr.getUncached().execute(null, obj, attrName);
88+
Object tmp = lookupAttr(obj, attrName);
8289
if (tmp instanceof PNone) {
83-
if (required) {
84-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
90+
if (!required) {
91+
return null;
92+
}
93+
if (tmp == PNone.NO_VALUE) {
94+
throw raiseTypeError(REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
95+
}
96+
// In CPython, None values for required attributes are not checked here, but converted
97+
// to C NULL and later checked in _PyAST_* constructor. This is not convenient for us,
98+
// since our SST nodes are in the pegparser project which does not have access to Python
99+
// exceptions. So we handle PNone.NONE here, but there is one exception - None is a
100+
// valid value for the required field ExprTy.Constant.value.
101+
if (!(nodeName == T_C_CONSTANT && attrName == T_F_VALUE)) {
102+
throw raiseValueError(FIELD_S_IS_REQUIRED_FOR_S, attrName, nodeName);
85103
}
86-
return null;
87104
}
88105
// Py_EnterRecursiveCall(" while traversing '%s' node")
89106
return conversion.convert(tmp);
90107
}
91108

92109
int lookupAndConvertInt(Object obj, TruffleString attrName, TruffleString nodeName, boolean required) {
93-
Object tmp = PyObjectLookupAttr.getUncached().execute(null, obj, attrName);
110+
Object tmp = lookupAttr(obj, attrName);
94111
if (tmp instanceof PNone) {
95-
if (required) {
96-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
97-
} else {
112+
if (!required) {
98113
return 0;
99114
}
115+
if (tmp == PNone.NO_VALUE) {
116+
throw raiseTypeError(REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
117+
}
118+
// PNone.NONE is handled by obj2int() (produces a different error message)
100119
}
101120
// Py_EnterRecursiveCall(" while traversing '%s' node")
102121
return obj2int(tmp);
103122
}
104123

105124
boolean lookupAndConvertBoolean(Object obj, TruffleString attrName, TruffleString nodeName, boolean required) {
106-
Object tmp = PyObjectLookupAttr.getUncached().execute(null, obj, attrName);
125+
Object tmp = lookupAttr(obj, attrName);
107126
if (tmp instanceof PNone) {
108-
if (required) {
109-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
110-
} else {
127+
if (!required) {
111128
return false;
112129
}
130+
if (tmp == PNone.NO_VALUE) {
131+
throw raiseTypeError(REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
132+
}
133+
// PNone.NONE is handled by obj2boolean() (produces a different error message)
113134
}
114135
// Py_EnterRecursiveCall(" while traversing '%s' node")
115136
return obj2boolean(tmp);
116137
}
117138

118139
<T> T[] lookupAndConvertSequence(Object obj, TruffleString attrName, TruffleString nodeName, Conversion<T> conversion, IntFunction<T[]> arrayFactory) {
119-
Object tmp = PyObjectLookupAttr.getUncached().execute(null, obj, attrName);
140+
Object tmp = lookupAttr(obj, attrName);
120141
if (tmp instanceof PNone) {
121-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
142+
throw raiseTypeError(REQUIRED_FIELD_S_MISSING_FROM_S, attrName, nodeName);
122143
}
123144
if (!(tmp instanceof PList)) {
124-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, S_FIELD_S_MUST_BE_A_LIST_NOT_P, nodeName, attrName, tmp);
145+
throw raiseTypeError(S_FIELD_S_MUST_BE_A_LIST_NOT_P, nodeName, attrName, tmp);
125146
}
126147
SequenceStorage seq = ((PList) tmp).getSequenceStorage();
127148
T[] result = arrayFactory.apply(seq.length());
@@ -130,20 +151,22 @@ <T> T[] lookupAndConvertSequence(Object obj, TruffleString attrName, TruffleStri
130151
// Py_EnterRecursiveCall(" while traversing '%s' node")
131152
result[i] = conversion.convert(tmp);
132153
if (result.length != seq.length()) {
133-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, S_FIELD_S_CHANGED_SIZE_DURING_ITERATION, nodeName, attrName);
154+
throw raiseTypeError(S_FIELD_S_CHANGED_SIZE_DURING_ITERATION, nodeName, attrName);
134155
}
135156
}
136157
return result;
137158
}
138159

139160
static boolean isInstanceOf(Object o, PythonAbstractClass cls) {
140-
Object check = PyObjectLookupAttr.getUncached().execute(null, cls, SpecialMethodNames.T___INSTANCECHECK__);
161+
Object check = lookupAttr(cls, SpecialMethodNames.T___INSTANCECHECK__);
141162
Object result = CallNode.getUncached().execute(check, o);
142163
return CastToJavaBooleanNode.getUncached().execute(result);
143164
}
144165

145166
int obj2int(Object o) {
146-
// TODO PyLong_Check
167+
if (!PyLongCheckNode.getUncached().execute(o)) {
168+
throw raiseValueError(INVALID_INTEGER_VALUE, repr(o));
169+
}
147170
return PyLongAsIntNode.getUncached().execute(null, o);
148171
}
149172

@@ -160,11 +183,14 @@ String obj2String(Object obj) { // TODO support str and bytes
160183
}
161184

162185
String obj2identifier(Object obj) {
163-
// TODO if (!PyUnicode_CheckExact(obj) && obj != Py_None) {
164186
if (obj == PNone.NONE) {
165187
return null;
166188
}
167-
return CastToJavaStringNode.getUncached().execute(obj);
189+
try {
190+
return CastToJavaStringNode.getUncached().execute(obj);
191+
} catch (CannotCastException e) {
192+
throw raiseTypeError(AST_IDENTIFIER_MUST_BE_OF_TYPE_STR);
193+
}
168194
}
169195

170196
ConstantValue obj2ConstantValue(Object obj) {
@@ -173,7 +199,26 @@ ConstantValue obj2ConstantValue(Object obj) {
173199
}
174200

175201
static PException unexpectedNodeType(TruffleString expected, Object obj) {
176-
TruffleString repr = PyObjectReprAsTruffleStringNode.getUncached().execute(null, obj);
177-
throw PRaiseNode.getUncached().raise(PythonBuiltinClassType.TypeError, EXPECTED_SOME_SORT_OF_S_BUT_GOT_S, expected, repr);
202+
throw raiseTypeError(EXPECTED_SOME_SORT_OF_S_BUT_GOT_S, expected, repr(obj));
203+
}
204+
205+
private static Object lookupAttr(Object o, TruffleString attrName) {
206+
return PyObjectLookupAttr.getUncached().execute(null, o, attrName);
207+
}
208+
209+
private static TruffleString repr(Object o) {
210+
return PyObjectReprAsTruffleStringNode.getUncached().execute(null, o);
211+
}
212+
213+
private static PException raise(PythonBuiltinClassType type, TruffleString format, Object... arguments) {
214+
throw PRaiseNode.getUncached().raise(type, format, arguments);
215+
}
216+
217+
private static PException raiseTypeError(TruffleString format, Object... arguments) {
218+
throw raise(PythonBuiltinClassType.TypeError, format, arguments);
219+
}
220+
221+
private static PException raiseValueError(TruffleString format, Object... arguments) {
222+
throw raise(PythonBuiltinClassType.ValueError, format, arguments);
178223
}
179224
}

0 commit comments

Comments
 (0)