diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/StringLiteralBranchNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/StringLiteralBranchNode.java index ce8e052f7f65..eec5ca70c194 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/StringLiteralBranchNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/controlflow/caseexpr/StringLiteralBranchNode.java @@ -1,16 +1,19 @@ package org.enso.interpreter.node.controlflow.caseexpr; -import com.ibm.icu.text.Normalizer; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.CountingConditionProfile; import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode; import org.enso.interpreter.runtime.data.text.Text; +import org.enso.polyglot.common_utils.Core_Text_Utils; @NodeInfo(shortName = "StringLiteralMatch", description = "Allows matching on String literals") public abstract class StringLiteralBranchNode extends BranchNode { @@ -39,9 +42,26 @@ void doText( } } + @Specialization( + guards = {"targetInterop.isString(target)"}, + limit = "3") + void doInteropString( + VirtualFrame frame, + Object state, + Object target, + @CachedLibrary("target") InteropLibrary targetInterop) { + try { + if (textProfile.profile(equalStrings(literal, targetInterop.asString(target)))) { + accept(frame, state, new Object[0]); + } + } catch (UnsupportedMessageException e) { + throw CompilerDirectives.shouldNotReachHere(e); + } + } + @CompilerDirectives.TruffleBoundary private boolean equalStrings(String s1, String s2) { - return Normalizer.compare(s1, s2, Normalizer.FOLD_CASE_DEFAULT) == 0; + return Core_Text_Utils.equals(s1, s2); } @Fallback diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java index 76fdc55715d9..c59b2e90e8f6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/syntax/HostValueToEnsoNode.java @@ -7,10 +7,14 @@ import com.oracle.truffle.api.dsl.ReportPolymorphism; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; -import org.enso.interpreter.node.expression.foreign.CoerceNothing; +import com.oracle.truffle.api.profiles.CountingConditionProfile; +import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.data.text.Text; +import org.enso.interpreter.runtime.error.WarningsLibrary; +import org.enso.interpreter.runtime.error.WithWarnings; /** * Converts a value returned by a polyglot call back to a value that can be further used within Enso @@ -66,12 +70,23 @@ Text doString(String txt) { return Text.create(txt); } - @Specialization(guards = {"o != null", "iop.isNull(o)"}) + @Specialization(guards = {"value != null", "iop.isNull(value)"}) Object doNull( - Object o, + Object value, @CachedLibrary(limit = "3") InteropLibrary iop, - @Cached CoerceNothing coerceNothing) { - return coerceNothing.execute(o); + @CachedLibrary(limit = "3") WarningsLibrary warningsLibrary, + @Cached CountingConditionProfile nullWarningProfile) { + var ctx = EnsoContext.get(this); + var nothing = ctx.getBuiltins().nothing(); + if (nothing != value && nullWarningProfile.profile(warningsLibrary.hasWarnings(value))) { + try { + var attachedWarnings = warningsLibrary.getWarnings(value, null, false); + return WithWarnings.wrap(ctx, nothing, attachedWarnings); + } catch (UnsupportedMessageException e) { + return nothing; + } + } + return nothing; } @Fallback diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java deleted file mode 100644 index fe003aeb65c9..000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/CoerceNothing.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.enso.interpreter.node.expression.foreign; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.GenerateUncached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.CountingConditionProfile; -import org.enso.interpreter.runtime.EnsoContext; -import org.enso.interpreter.runtime.error.Warning; -import org.enso.interpreter.runtime.error.WarningsLibrary; -import org.enso.interpreter.runtime.error.WithWarnings; - -@GenerateUncached -public abstract class CoerceNothing extends Node { - public static CoerceNothing build() { - return CoerceNothingNodeGen.create(); - } - - /** - * Converts a null polyglot representation into an equivalent Nothing representation in Enso - * context. - * - * @param value the polyglot value to perform coercion on - * @return {@code value} coerced to an Enso primitive where applicable - */ - public abstract Object execute(Object value); - - @Specialization(guards = "interop.isNull(value)") - public Object doNothing( - Object value, - @CachedLibrary(limit = "1") InteropLibrary interop, - @CachedLibrary(limit = "3") WarningsLibrary warningsLibrary, - @Cached CountingConditionProfile nullWarningProfile) { - var ctx = EnsoContext.get(this); - var nothing = ctx.getBuiltins().nothing(); - if (nullWarningProfile.profile(warningsLibrary.hasWarnings(value))) { - try { - Warning[] attachedWarnings = warningsLibrary.getWarnings(value, null, false); - return WithWarnings.wrap(ctx, nothing, attachedWarnings); - } catch (UnsupportedMessageException e) { - return nothing; - } - } - - return nothing; - } - - @Fallback - public Object doOther(Object value) { - return value; - } -} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java index 048c1452064e..c1a34913ad65 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/foreign/ForeignMethodCallNode.java @@ -6,19 +6,20 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.node.ExpressionNode; +import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; import org.enso.interpreter.runtime.error.DataflowError; /** Performs a call into a given foreign call target. */ public class ForeignMethodCallNode extends ExpressionNode { private @Children ExpressionNode[] arguments; private @Child DirectCallNode callNode; - private @Child CoerceNothing coerceNothingNode; + private @Child HostValueToEnsoNode coerceNode; private final BranchProfile[] errorProfiles; ForeignMethodCallNode(ExpressionNode[] arguments, CallTarget foreignCt) { this.arguments = arguments; this.callNode = DirectCallNode.create(foreignCt); - this.coerceNothingNode = CoerceNothing.build(); + this.coerceNode = HostValueToEnsoNode.build(); this.errorProfiles = new BranchProfile[arguments.length]; for (int i = 0; i < arguments.length; i++) { @@ -48,6 +49,6 @@ public Object executeGeneric(VirtualFrame frame) { return args[i]; } } - return coerceNothingNode.execute(callNode.call(args)); + return coerceNode.execute(callNode.call(args)); } } diff --git a/test/Base_Tests/src/Semantic/Case_Spec.enso b/test/Base_Tests/src/Semantic/Case_Spec.enso index 3b17bcb0725e..485544f462b5 100644 --- a/test/Base_Tests/src/Semantic/Case_Spec.enso +++ b/test/Base_Tests/src/Semantic/Case_Spec.enso @@ -6,6 +6,7 @@ import Standard.Base.Data.Vector as Vector_Module polyglot java import java.lang.Class polyglot java import java.lang.Long as Java_Long polyglot java import java.lang.Object as Java_Object +polyglot java import java.lang.StringBuilder as Java_StringBuilder polyglot java import java.util.Random as Java_Random polyglot java import java.util.AbstractList polyglot java import java.util.ArrayList @@ -301,6 +302,25 @@ add_specs suite_builder = suite_builder.group "Pattern Matches" group_builder-> u = v.map foo u.should_equal ["text", "array", "array"] + group_builder.specify "should correctly pattern match strings from JS" <| + json = """ + {"x": "foo"} + js_txt = json.parse_json.get "x" + r = case js_txt of + "foo" -> "OK" + other -> "not ok: "+other.to_text + r.should_equal "OK" + + group_builder.specify "should correctly pattern match strings from Java" <| + sb = Java_StringBuilder.new + sb.append "b" + sb.append "ar" + java_txt = sb.toString + r = case java_txt of + "bar" -> "OK" + other -> "not ok: "+other.to_text + r.should_equal "OK" + group_builder.specify "should correctly pattern match on supertype" <| case 1 of _ : Any -> Nothing @@ -331,4 +351,3 @@ main filter=Nothing = suite = Test.build suite_builder-> add_specs suite_builder suite.run_with_filter filter -