-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Hash pattern matching and the rest of pattern matching
- Loading branch information
Showing
21 changed files
with
636 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,10 @@ | ||
fails:Pattern matching variable pattern supports using any name with _ at the beginning in a pattern several times | ||
fails:Pattern matching alternative pattern matches if any of patterns matches | ||
fails:Pattern matching alternative pattern does not support variable binding | ||
fails:Pattern matching alternative pattern support underscore prefixed variables in alternation | ||
fails:Pattern matching AS pattern binds a variable to a value if pattern matches | ||
fails:Pattern matching AS pattern can be used as a nested pattern | ||
fails:Pattern matching Hash pattern supports form id: pat, id: pat, ... | ||
fails:Pattern matching Hash pattern supports a: which means a: a | ||
fails:Pattern matching Hash pattern can mix key (a:) and key-value (a: b) declarations | ||
fails:Pattern matching Hash pattern does not match object if Constant === object returns false | ||
fails:Pattern matching Hash pattern does not match object without #deconstruct_keys method | ||
fails:Pattern matching Hash pattern does not match object if #deconstruct_keys method does not return Hash | ||
fails:Pattern matching Hash pattern does not match object if #deconstruct_keys method returns Hash with non-symbol keys | ||
fails:Pattern matching Hash pattern does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern | ||
fails:Pattern matching Hash pattern passes keys specified in pattern as arguments to #deconstruct_keys method | ||
fails:Pattern matching Hash pattern passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator ** | ||
fails:Pattern matching Hash pattern passes nil to #deconstruct_keys method if pattern contains double splat operator **rest | ||
fails:Pattern matching Hash pattern binds variables | ||
fails:Pattern matching Hash pattern supports double splat operator **rest | ||
fails:Pattern matching Hash pattern treats **nil like there should not be any other keys in a matched Hash | ||
fails:Pattern matching Hash pattern matches anything with ** | ||
fails:Pattern matching refinements are used for #deconstruct_keys | ||
fails:Pattern matching Array pattern accepts a subclass of Array from #deconstruct | ||
fails:Pattern matching Array pattern calls #deconstruct once for multiple patterns, caching the result | ||
fails:Pattern matching find pattern captures both preceding and following elements to the pattern | ||
fails:Pattern matching warning when one-line form warns about pattern matching is experimental feature | ||
fails:Pattern matching alternative pattern can be used as a nested pattern | ||
fails:Pattern matching Array pattern can be used as a nested pattern | ||
fails:Pattern matching Hash pattern can be used as a nested pattern | ||
fails:Pattern matching find pattern can be nested | ||
fails:Pattern matching find pattern can be nested with an array pattern | ||
fails:Pattern matching find pattern can be nested within a hash pattern | ||
fails:Pattern matching find pattern can nest hash and array patterns | ||
fails:Pattern matching can omit parentheses in one line pattern matching | ||
fails:Pattern matching Hash pattern supports form Constant(id: pat, id: pat, ...) | ||
fails:Pattern matching Hash pattern supports form Constant[id: pat, id: pat, ...] | ||
fails:Pattern matching Hash pattern supports form {id: pat, id: pat, ...} | ||
fails:Pattern matching Hash pattern supports 'string': key literal | ||
fails:Pattern matching Hash pattern matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern | ||
fails:Pattern matching Hash pattern calls #deconstruct_keys per pattern | ||
fails:Pattern matching Hash pattern can match partially | ||
fails:Pattern matching Hash pattern matches {} with {} | ||
fails:Pattern matching refinements are used for #deconstruct | ||
fails:Pattern matching variable pattern does not support using variable name (except _) several times | ||
fails:Pattern matching Hash pattern does not support non-symbol keys | ||
fails:Pattern matching Hash pattern does not support string interpolation in keys | ||
fails:Pattern matching Hash pattern raise SyntaxError when keys duplicate in pattern | ||
fails:Pattern matching supports pinning expressions in hash pattern |
60 changes: 60 additions & 0 deletions
60
src/main/java/org/truffleruby/core/array/ArrayDeconstructNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. This | ||
* code is released under a tri EPL/GPL/LGPL license. You can use it, | ||
* redistribute it and/or modify it under the terms of the: | ||
* | ||
* Eclipse Public License version 2.0, or | ||
* GNU General Public License version 2, or | ||
* GNU Lesser General Public License version 2.1. | ||
*/ | ||
package org.truffleruby.core.array; | ||
|
||
import com.oracle.truffle.api.dsl.Cached; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import com.oracle.truffle.api.profiles.InlinedBranchProfile; | ||
import com.oracle.truffle.api.profiles.InlinedConditionProfile; | ||
import org.truffleruby.core.cast.BooleanCastNode; | ||
import org.truffleruby.language.RubyContextSourceNode; | ||
import org.truffleruby.language.RubyNode; | ||
|
||
import com.oracle.truffle.api.dsl.NodeChild; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import org.truffleruby.language.control.RaiseException; | ||
import org.truffleruby.language.dispatch.DispatchNode; | ||
|
||
import static org.truffleruby.language.dispatch.DispatchConfiguration.PUBLIC; | ||
|
||
// Implemented in Java because the call to #deconstruct needs to honor refinements | ||
@NodeChild(value = "valueNode", type = RubyNode.class) | ||
public abstract class ArrayDeconstructNode extends RubyContextSourceNode { | ||
|
||
abstract RubyNode getValueNode(); | ||
|
||
@Specialization | ||
Object deconstruct(VirtualFrame frame, Object toMatch, | ||
@Cached DispatchNode respondToNode, | ||
@Cached BooleanCastNode booleanCastNode, | ||
@Cached DispatchNode deconstructNode, | ||
@Cached InlinedConditionProfile hasDeconstructProfile, | ||
@Cached InlinedBranchProfile errorProfile) { | ||
if (hasDeconstructProfile.profile(this, booleanCastNode.execute(this, | ||
respondToNode.callWithFrame(PUBLIC, frame, toMatch, "respond_to?", coreSymbols().DECONSTRUCT)))) { | ||
Object deconstructed = deconstructNode.callWithFrame(PUBLIC, frame, toMatch, "deconstruct"); | ||
if (deconstructed instanceof RubyArray) { | ||
return deconstructed; | ||
} else { | ||
errorProfile.enter(this); | ||
throw new RaiseException(getContext(), | ||
coreExceptions().typeError("deconstruct must return Array", this)); | ||
} | ||
} else { | ||
return nil; | ||
} | ||
} | ||
|
||
@Override | ||
public RubyNode cloneUninitialized() { | ||
return ArrayDeconstructNodeGen.create(getValueNode().cloneUninitialized()).copyFlags(this); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/main/java/org/truffleruby/core/array/ArrayStaticLiteralNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. This | ||
* code is released under a tri EPL/GPL/LGPL license. You can use it, | ||
* redistribute it and/or modify it under the terms of the: | ||
* | ||
* Eclipse Public License version 2.0, or | ||
* GNU General Public License version 2, or | ||
* GNU Lesser General Public License version 2.1. | ||
*/ | ||
package org.truffleruby.core.array; | ||
|
||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import org.truffleruby.language.RubyContextSourceNode; | ||
import org.truffleruby.language.RubyGuards; | ||
import org.truffleruby.language.RubyNode; | ||
|
||
public final class ArrayStaticLiteralNode extends RubyContextSourceNode { | ||
|
||
@CompilationFinal(dimensions = 1) private final Object[] values; | ||
|
||
public ArrayStaticLiteralNode(Object[] values) { | ||
assert allValuesArePrimitiveOrImmutable(values); | ||
this.values = values; | ||
} | ||
|
||
private static boolean allValuesArePrimitiveOrImmutable(Object[] values) { | ||
for (Object value : values) { | ||
assert RubyGuards.isPrimitiveOrImmutable(value); | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public RubyArray execute(VirtualFrame frame) { | ||
// Copying here is the simplest since we need to return a mutable Array. | ||
// An alternative would be to use COW via DelegatedArrayStorage. | ||
return createArray(ArrayUtils.copy(values)); | ||
} | ||
|
||
@Override | ||
public RubyNode cloneUninitialized() { | ||
return new ArrayStaticLiteralNode(values); | ||
} | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
src/main/java/org/truffleruby/core/hash/HashDeconstructKeysNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. This | ||
* code is released under a tri EPL/GPL/LGPL license. You can use it, | ||
* redistribute it and/or modify it under the terms of the: | ||
* | ||
* Eclipse Public License version 2.0, or | ||
* GNU General Public License version 2, or | ||
* GNU Lesser General Public License version 2.1. | ||
*/ | ||
package org.truffleruby.core.hash; | ||
|
||
import static org.truffleruby.language.dispatch.DispatchConfiguration.PUBLIC; | ||
|
||
import org.truffleruby.core.cast.BooleanCastNode; | ||
import org.truffleruby.language.RubyContextSourceNode; | ||
import org.truffleruby.language.RubyNode; | ||
import org.truffleruby.language.control.RaiseException; | ||
import org.truffleruby.language.dispatch.DispatchNode; | ||
|
||
import com.oracle.truffle.api.dsl.Cached; | ||
import com.oracle.truffle.api.dsl.NodeChild; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.frame.VirtualFrame; | ||
import com.oracle.truffle.api.profiles.InlinedBranchProfile; | ||
import com.oracle.truffle.api.profiles.InlinedConditionProfile; | ||
|
||
// Implemented in Java because the call to #deconstruct_keys needs to honor refinements | ||
@NodeChild(value = "valueNode", type = RubyNode.class) | ||
@NodeChild(value = "keysNode", type = RubyNode.class) | ||
public abstract class HashDeconstructKeysNode extends RubyContextSourceNode { | ||
|
||
abstract RubyNode getValueNode(); | ||
|
||
abstract RubyNode getKeysNode(); | ||
|
||
@Specialization | ||
Object deconstructKeys(VirtualFrame frame, Object toMatch, Object keys, | ||
@Cached DispatchNode respondToNode, | ||
@Cached BooleanCastNode booleanCastNode, | ||
@Cached DispatchNode deconstructKeysNode, | ||
@Cached InlinedConditionProfile hasDeconstructKeysProfile, | ||
@Cached InlinedBranchProfile errorProfile) { | ||
if (hasDeconstructKeysProfile.profile(this, booleanCastNode.execute(this, | ||
respondToNode.callWithFrame(PUBLIC, frame, toMatch, "respond_to?", coreSymbols().DECONSTRUCT_KEYS)))) { | ||
Object deconstructed = deconstructKeysNode.callWithFrame(PUBLIC, frame, toMatch, "deconstruct_keys", keys); | ||
if (deconstructed instanceof RubyHash) { | ||
return deconstructed; | ||
} else { | ||
errorProfile.enter(this); | ||
throw new RaiseException(getContext(), | ||
coreExceptions().typeError("deconstruct_keys must return Hash", this)); | ||
} | ||
} else { | ||
return nil; | ||
} | ||
} | ||
|
||
@Override | ||
public RubyNode cloneUninitialized() { | ||
return HashDeconstructKeysNodeGen | ||
.create(getValueNode().cloneUninitialized(), getKeysNode().cloneUninitialized()).copyFlags(this); | ||
} | ||
|
||
} |
54 changes: 54 additions & 0 deletions
54
src/main/java/org/truffleruby/core/hash/HashGetOrUndefinedNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. This | ||
* code is released under a tri EPL/GPL/LGPL license. You can use it, | ||
* redistribute it and/or modify it under the terms of the: | ||
* | ||
* Eclipse Public License version 2.0, or | ||
* GNU General Public License version 2, or | ||
* GNU Lesser General Public License version 2.1. | ||
*/ | ||
package org.truffleruby.core.hash; | ||
|
||
import com.oracle.truffle.api.dsl.ImportStatic; | ||
import com.oracle.truffle.api.dsl.NodeChild; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.frame.Frame; | ||
import com.oracle.truffle.api.library.CachedLibrary; | ||
import org.truffleruby.collections.PEBiFunction; | ||
import org.truffleruby.core.hash.library.HashStoreLibrary; | ||
import org.truffleruby.core.symbol.RubySymbol; | ||
import org.truffleruby.language.NotProvided; | ||
import org.truffleruby.language.RubyContextSourceNode; | ||
import org.truffleruby.language.RubyNode; | ||
|
||
/** The same as {@link HashNodes.GetOrUndefinedNode} but with a static key. */ | ||
@ImportStatic(HashGuards.class) | ||
@NodeChild(value = "hashNode", type = RubyNode.class) | ||
public abstract class HashGetOrUndefinedNode extends RubyContextSourceNode implements PEBiFunction { | ||
|
||
private final RubySymbol key; | ||
|
||
public HashGetOrUndefinedNode(RubySymbol key) { | ||
this.key = key; | ||
} | ||
|
||
abstract RubyNode getHashNode(); | ||
|
||
@Specialization(limit = "hashStrategyLimit()") | ||
Object get(RubyHash hash, | ||
@CachedLibrary("hash.store") HashStoreLibrary hashes) { | ||
return hashes.lookupOrDefault(hash.store, null, hash, key, this); | ||
} | ||
|
||
@Override | ||
public Object accept(Frame frame, Object hash, Object key) { | ||
return NotProvided.INSTANCE; | ||
} | ||
|
||
@Override | ||
public RubyNode cloneUninitialized() { | ||
var copy = HashGetOrUndefinedNodeGen.create(key, getHashNode().cloneUninitialized()); | ||
return copy.copyFlags(this); | ||
} | ||
|
||
} |
Oops, something went wrong.