Skip to content

Commit 5911c4e

Browse files
committed
Refactor polyglot.eval
1 parent 1fc772e commit 5911c4e

File tree

3 files changed

+54
-83
lines changed

3 files changed

+54
-83
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,8 @@ def test_host_lookup():
286286
def test_internal_languages_dont_eval():
287287
try:
288288
polyglot.eval(language="nfi", string="default")
289-
except NotImplementedError as e:
290-
assert "No language for id nfi found" in str(e)
289+
except ValueError as e:
290+
assert str(e) == "polyglot language 'nfi' not found"
291291

292292
assert polyglot.eval(language="python", string="21 * 2") == 42
293293

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

Lines changed: 48 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@
6161
import static com.oracle.graal.python.nodes.StringLiterals.T_READABLE;
6262
import static com.oracle.graal.python.nodes.StringLiterals.T_WRITABLE;
6363
import static com.oracle.graal.python.nodes.truffle.TruffleStringMigrationHelpers.isJavaString;
64-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.NotImplementedError;
6564
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OSError;
65+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.RuntimeError;
66+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
6667
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
6768
import static com.oracle.graal.python.util.PythonUtils.EMPTY_BYTE_ARRAY;
6869
import static com.oracle.graal.python.util.PythonUtils.EMPTY_OBJECT_ARRAY;
@@ -111,6 +112,7 @@
111112
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
112113
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
113114
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
115+
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
114116
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
115117
import com.oracle.graal.python.nodes.interop.InteropBehavior;
116118
import com.oracle.graal.python.nodes.interop.InteropBehaviorMethod;
@@ -138,11 +140,11 @@
138140
import com.oracle.truffle.api.TruffleLogger;
139141
import com.oracle.truffle.api.dsl.Bind;
140142
import com.oracle.truffle.api.dsl.Cached;
141-
import com.oracle.truffle.api.dsl.Cached.Shared;
142143
import com.oracle.truffle.api.dsl.Fallback;
143144
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
144145
import com.oracle.truffle.api.dsl.Specialization;
145146
import com.oracle.truffle.api.dsl.TypeSystemReference;
147+
import com.oracle.truffle.api.exception.AbstractTruffleException;
146148
import com.oracle.truffle.api.frame.VirtualFrame;
147149
import com.oracle.truffle.api.interop.ArityException;
148150
import com.oracle.truffle.api.interop.InteropLibrary;
@@ -154,7 +156,6 @@
154156
import com.oracle.truffle.api.nodes.LanguageInfo;
155157
import com.oracle.truffle.api.nodes.Node;
156158
import com.oracle.truffle.api.source.Source;
157-
import com.oracle.truffle.api.source.Source.LiteralBuilder;
158159
import com.oracle.truffle.api.source.Source.SourceBuilder;
159160
import com.oracle.truffle.api.strings.TruffleString;
160161

@@ -213,99 +214,68 @@ Object importSymbol(TruffleString name,
213214

214215
@Builtin(name = "eval", minNumOfPositionalArgs = 0, parameterNames = {"path", "string", "language"})
215216
@GenerateNodeFactory
216-
abstract static class EvalInteropNode extends PythonBuiltinNode {
217+
abstract static class EvalInteropNode extends PythonTernaryBuiltinNode {
217218
@TruffleBoundary
218219
@Specialization
219-
Object evalString(@SuppressWarnings("unused") PNone path, TruffleString tvalue, TruffleString tlangOrMimeType,
220-
@Shared @Cached PForeignToPTypeNode convert) {
220+
Object eval(Object pathObj, Object stringObj, Object languageObj) {
221+
if (languageObj instanceof PNone) {
222+
throw PRaiseNode.raiseUncached(this, ValueError, ErrorMessages.POLYGLOT_EVAL_MUST_PASS_LANG);
223+
}
224+
boolean hasString = !(stringObj instanceof PNone);
225+
boolean hasPath = !(pathObj instanceof PNone);
226+
if (!hasString && !hasPath || hasString && hasPath) {
227+
throw PRaiseNode.raiseUncached(this, ValueError, ErrorMessages.POLYGLOT_EVAL_MUST_PASS_STRING_OR_PATH);
228+
}
229+
String languageName = toJavaString(languageObj, "language");
230+
String string = hasString ? toJavaString(stringObj, "string") : null;
231+
String path = hasPath ? toJavaString(pathObj, "path") : null;
221232
Env env = getContext().getEnv();
222-
if (!env.isPolyglotEvalAllowed()) {
223-
throw PRaiseNode.raiseUncached(this, PythonErrorType.NotImplementedError, ErrorMessages.POLYGLOT_ACCESS_NOT_ALLOWED);
233+
if (!env.isPolyglotEvalAllowed(null)) {
234+
throw PRaiseNode.raiseUncached(this, RuntimeError, ErrorMessages.POLYGLOT_ACCESS_NOT_ALLOWED);
224235
}
225-
try {
226-
String value = tvalue.toJavaStringUncached();
227-
String langOrMimeType = tlangOrMimeType.toJavaStringUncached();
228-
boolean mimeType = isMimeType(langOrMimeType);
229-
String lang = mimeType ? findLanguageByMimeType(env, langOrMimeType) : langOrMimeType;
230-
raiseIfInternal(env, lang);
231-
LiteralBuilder newBuilder = Source.newBuilder(lang, value, value);
232-
if (mimeType) {
233-
newBuilder = newBuilder.mimeType(langOrMimeType);
234-
}
235-
return convert.executeConvert(env.parsePublic(newBuilder.build()).call());
236-
} catch (RuntimeException e) {
237-
throw PRaiseNode.raiseUncached(this, NotImplementedError, e);
236+
Map<String, LanguageInfo> languages = env.getPublicLanguages();
237+
String mimeType = null;
238+
if (isMimeType(languageName)) {
239+
mimeType = languageName;
240+
languageName = findLanguageByMimeType(languages, languageName);
238241
}
239-
}
240-
241-
private void raiseIfInternal(Env env, String lang) {
242-
LanguageInfo languageInfo = env.getPublicLanguages().get(lang);
243-
if (languageInfo != null && languageInfo.isInternal()) {
244-
throw PRaiseNode.raiseUncached(this, NotImplementedError, ErrorMessages.ACCESS_TO_INTERNAL_LANG_NOT_PERMITTED, lang);
242+
LanguageInfo language = languages.get(languageName);
243+
if (language == null) {
244+
throw PRaiseNode.raiseUncached(this, ValueError, ErrorMessages.POLYGLOT_LANGUAGE_S_NOT_FOUND, languageName);
245245
}
246-
}
247-
248-
@TruffleBoundary
249-
@Specialization
250-
Object evalFile(TruffleString tpath, @SuppressWarnings("unused") PNone string, TruffleString tlangOrMimeType,
251-
@Shared @Cached PForeignToPTypeNode convert) {
252-
Env env = getContext().getEnv();
253-
if (!env.isPolyglotEvalAllowed()) {
254-
throw PRaiseNode.raiseUncached(this, PythonErrorType.NotImplementedError, ErrorMessages.POLYGLOT_ACCESS_NOT_ALLOWED);
246+
if (!env.isPolyglotEvalAllowed(language)) {
247+
throw PRaiseNode.raiseUncached(this, RuntimeError, ErrorMessages.POLYGLOT_ACCESS_NOT_ALLOWED_FOR_LANGUAGE_S, languageName);
255248
}
256249
try {
257-
String path = tpath.toJavaStringUncached();
258-
String langOrMimeType = tlangOrMimeType.toJavaStringUncached();
259-
boolean mimeType = isMimeType(langOrMimeType);
260-
String lang = mimeType ? findLanguageByMimeType(env, langOrMimeType) : langOrMimeType;
261-
raiseIfInternal(env, lang);
262-
SourceBuilder newBuilder = Source.newBuilder(lang, env.getPublicTruffleFile(path));
263-
if (mimeType) {
264-
newBuilder = newBuilder.mimeType(langOrMimeType);
250+
SourceBuilder builder;
251+
if (hasString) {
252+
builder = Source.newBuilder(languageName, string, string);
253+
} else {
254+
builder = Source.newBuilder(languageName, env.getPublicTruffleFile(path)).name(path);
255+
}
256+
if (mimeType != null) {
257+
builder = builder.mimeType(mimeType);
265258
}
266-
return convert.executeConvert(getContext().getEnv().parsePublic(newBuilder.name(path).build()).call());
259+
Object result = env.parsePublic(builder.build()).call();
260+
return PForeignToPTypeNode.getUncached().executeConvert(result);
261+
} catch (AbstractTruffleException e) {
262+
throw e;
267263
} catch (IOException e) {
268264
throw PRaiseNode.raiseUncached(this, OSError, ErrorMessages.S, e);
269265
} catch (RuntimeException e) {
270-
throw PRaiseNode.raiseUncached(this, NotImplementedError, e);
266+
throw PRaiseNode.raiseUncached(this, RuntimeError, e);
271267
}
272268
}
273269

274-
@TruffleBoundary
275-
@Specialization
276-
Object evalFile(TruffleString tpath, @SuppressWarnings("unused") PNone string, @SuppressWarnings("unused") PNone lang,
277-
@Shared @Cached PForeignToPTypeNode convert) {
278-
Env env = getContext().getEnv();
279-
if (!env.isPolyglotEvalAllowed()) {
280-
throw PRaiseNode.raiseUncached(this, PythonErrorType.NotImplementedError, ErrorMessages.POLYGLOT_ACCESS_NOT_ALLOWED);
281-
}
270+
private String toJavaString(Object object, String parameterName) {
282271
try {
283-
String path = tpath.toJavaStringUncached();
284-
return convert.executeConvert(getContext().getEnv().parsePublic(Source.newBuilder(PythonLanguage.ID, env.getPublicTruffleFile(path)).name(path).build()).call());
285-
} catch (IOException e) {
286-
throw PRaiseNode.raiseUncached(this, OSError, ErrorMessages.S, e);
287-
} catch (RuntimeException e) {
288-
throw PRaiseNode.raiseUncached(this, NotImplementedError, e);
272+
return CastToJavaStringNode.getUncached().execute(object);
273+
} catch (CannotCastException e) {
274+
throw PRaiseNode.raiseUncached(this, TypeError, ErrorMessages.S_BRACKETS_ARG_S_MUST_BE_S_NOT_P, "polyglot.eval", parameterName, "str", object);
289275
}
290276
}
291277

292-
@SuppressWarnings("unused")
293-
@Specialization
294-
static Object evalStringWithoutLang(PNone path, TruffleString string, PNone lang,
295-
@Shared @Cached PRaiseNode raiseNode) {
296-
throw raiseNode.raise(ValueError, ErrorMessages.POLYGLOT_EVAL_WITH_STRING_MUST_PASS_LANG);
297-
}
298-
299-
@SuppressWarnings("unused")
300-
@Fallback
301-
static Object evalWithoutContent(Object path, Object string, Object lang,
302-
@Shared @Cached PRaiseNode raiseNode) {
303-
throw raiseNode.raise(ValueError, ErrorMessages.POLYGLOT_EVAL_MUST_PASS_STRINGS);
304-
}
305-
306-
@TruffleBoundary(transferToInterpreterOnException = false)
307-
private static String findLanguageByMimeType(Env env, String mimeType) {
308-
Map<String, LanguageInfo> languages = env.getPublicLanguages();
278+
private static String findLanguageByMimeType(Map<String, LanguageInfo> languages, String mimeType) {
309279
for (String language : languages.keySet()) {
310280
for (String registeredMimeType : languages.get(language).getMimeTypes()) {
311281
if (mimeType.equals(registeredMimeType)) {
@@ -316,7 +286,7 @@ private static String findLanguageByMimeType(Env env, String mimeType) {
316286
return null;
317287
}
318288

319-
protected boolean isMimeType(String lang) {
289+
private static boolean isMimeType(String lang) {
320290
return lang.contains("/");
321291
}
322292
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,9 @@ public abstract class ErrorMessages {
586586
public static final TruffleString PACKED_IP_WRONG_LENGTH = tsLiteral("packed IP wrong length for %s");
587587
public static final TruffleString PATTERNS_MAY_ONLY_MATCH_LITERALS_AND_ATTRIBUTE_LOOKUPS = tsLiteral("patterns may only match literals and attribute lookups");
588588
public static final TruffleString POLYGLOT_ACCESS_NOT_ALLOWED = tsLiteral("polyglot access is not allowed");
589-
public static final TruffleString POLYGLOT_EVAL_MUST_PASS_STRINGS = tsLiteral("polyglot.eval must pass strings as either 'path' or a 'string' keyword");
590-
public static final TruffleString POLYGLOT_EVAL_WITH_STRING_MUST_PASS_LANG = tsLiteral("polyglot.eval with a string argument must pass a language or mime-type");
589+
public static final TruffleString POLYGLOT_ACCESS_NOT_ALLOWED_FOR_LANGUAGE_S = tsLiteral("polyglot access is not allowed for language '%s'");
590+
public static final TruffleString POLYGLOT_EVAL_MUST_PASS_STRING_OR_PATH = tsLiteral("polyglot.eval() must pass either 'path' or 'string' keyword argument");
591+
public static final TruffleString POLYGLOT_EVAL_MUST_PASS_LANG = tsLiteral("polyglot.eval() must pass 'language' keyword argument");
591592
public static final TruffleString POP_FROM_EMPTY_SET = tsLiteral("pop from an emtpy set");
592593
public static final TruffleString POP_INDEX_OUT_OF_RANGE = tsLiteral("pop index out of range");
593594
public static final TruffleString POSITION_D_FROM_ERROR_HANDLER_OUT_OF_BOUNDS = tsLiteral("position %d from error handler out of bounds");
@@ -782,7 +783,7 @@ public abstract class ErrorMessages {
782783
public static final TruffleString X_NOT_IN_TUPLE = tsLiteral("tuple.index(x): x not in tuple");
783784
public static final TruffleString S_IS_AN_INVALID_ARG_FOR_S = tsLiteral("'%s' is an invalid keyword argument for %s");
784785
public static final TruffleString YOU_MAY_SPECIFY_EITHER_OR_BUT_NOT_BOTH = tsLiteral("%s: you may specify either '%s' or '%s' but not both");
785-
public static final TruffleString ACCESS_TO_INTERNAL_LANG_NOT_PERMITTED = tsLiteral("access to internal language %s is not permitted");
786+
public static final TruffleString POLYGLOT_LANGUAGE_S_NOT_FOUND = tsLiteral("polyglot language '%s' not found");
786787
public static final TruffleString POW_BASE_NOT_INVERTIBLE = tsLiteral("base is not invertible for the given modulus");
787788
public static final TruffleString POW_ZERO_CANNOT_RAISE_TO_NEGATIVE_POWER = tsLiteral("0.0 cannot be raised to a negative power");
788789
public static final TruffleString S_ALIGNMENT_FLAG_NOT_ALLOWED_FOR_COMPLEX_FMT = tsLiteral("'%c' alignment flag is not allowed in complex format specifier");

0 commit comments

Comments
 (0)