Skip to content

Commit 2607d6a

Browse files
author
Michal Medvecky
committed
mapping pattern
1 parent 3e8e7a2 commit 2607d6a

File tree

2 files changed

+166
-111
lines changed

2 files changed

+166
-111
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java

Lines changed: 154 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3706,57 +3706,38 @@ private static int lengthOrZero(Object[] p) {
37063706
return p == null ? 0 : p.length;
37073707
}
37083708

3709-
private void doVisitPattern(PatternTy.MatchMapping node, PatternContext pc) {
3710-
ExprTy[] keys = node.keys;
3711-
PatternTy[] patterns = node.patterns;
3712-
3713-
int key_len = lengthOrZero(keys);
3714-
int pat_len = lengthOrZero(patterns);
3715-
3716-
if (key_len != pat_len) {
3717-
ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "keys (%d) / patterns (%d) length mismatch in mapping pattern", key_len, pat_len);
3718-
}
3719-
3720-
String starTarget = node.rest;
3721-
if (key_len == 0 && starTarget == null) {
3722-
b.emitLoadConstant(false);
3723-
return;
3724-
}
3725-
if (Integer.MAX_VALUE < key_len - 1) {
3726-
ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "too many sub-patterns in mapping pattern");
3727-
}
3728-
3729-
b.beginPrimitiveBoolAnd(); // AND for sanity checks (length matching, etc.)
3730-
3731-
if (key_len > 0) {
3732-
// If the pattern has any keys in it, perform a length check:
3733-
b.beginGe();
3734-
b.beginGetLen();
3735-
b.emitLoadLocal(pc.subject);
3736-
b.endGetLen();
3737-
b.emitLoadConstant(key_len);
3738-
b.endGe();
3739-
}
3740-
3741-
b.beginBlock();
3742-
3743-
// save pc.subject
3744-
BytecodeLocal pc_save = b.createLocal();
3745-
b.beginStoreLocal(pc_save);
3746-
b.emitLoadLocal(pc.subject);
3747-
b.endStoreLocal();
3748-
3749-
// check that type matches
3750-
b.beginCheckTypeFlags(TypeFlags.MAPPING);
3709+
/**
3710+
* Checks if keys in pattern are, if present, longer than keys in subject. If yes, pattern should fail,
3711+
* otherwise, we should continue with evaluation.
3712+
*
3713+
* Generates result of the comparison (boolean).
3714+
*
3715+
* @param keyLen Number of keys in pattern.
3716+
* @param pc Pattern context.
3717+
*/
3718+
private void checkPatternKeysLength(int keyLen, PatternContext pc) {
3719+
b.beginGe();
3720+
b.beginGetLen();
37513721
b.emitLoadLocal(pc.subject);
3752-
b.endCheckTypeFlags();
3722+
b.endGetLen();
3723+
b.emitLoadConstant(keyLen);
3724+
b.endGe();
3725+
}
37533726

3754-
// match keys and get array of values
3755-
BytecodeLocal keys_local = b.createLocal();
3756-
b.beginStoreLocal(keys_local);
3757-
b.beginCollectToObjectArray();
3727+
/**
3728+
* Will process pattern keys: Attributes evaluation and constant folding. Checks for duplicate keys and
3729+
* that only literals and attributes lookups are being matched.
3730+
*
3731+
* Generates array.
3732+
*
3733+
* @param keys Pattern keys.
3734+
* @param keyLen Length of pattern keys.
3735+
* @param node Pattern matching node, for source range in errors.
3736+
*/
3737+
private void processPatternKeys(ExprTy[] keys, int keyLen, PatternTy.MatchMapping node) {
3738+
b.beginCollectToObjectArray(); // keys (from pattern)
37583739
List<Object> seen = new ArrayList<>();
3759-
for (int i = 0; i < key_len; i++) {
3740+
for (int i = 0; i < keyLen; i++) {
37603741
ExprTy key = keys[i];
37613742
if (key instanceof ExprTy.Attribute) {
37623743
key.accept(this);
@@ -3782,75 +3763,149 @@ private void doVisitPattern(PatternTy.MatchMapping node, PatternContext pc) {
37823763
}
37833764
}
37843765
b.endCollectToObjectArray();
3785-
b.endStoreLocal();
3786-
3787-
// save match result AND values
3788-
BytecodeLocal key_match_and_values = b.createLocal();
3789-
b.beginStoreLocal(key_match_and_values);
3790-
b.beginMatchKeys();
3791-
b.emitLoadLocal(pc.subject);
3792-
b.emitLoadLocal(keys_local);
3793-
b.endMatchKeys();
3794-
b.endStoreLocal();
3795-
3796-
BytecodeLocal temp = b.createLocal();
3797-
b.beginStoreLocal(temp);
3798-
3799-
b.beginPrimitiveBoolAnd(); // AND keys and values
3766+
}
38003767

3801-
// emit if everything matched
3802-
b.beginArrayIndex(0);
3803-
b.emitLoadLocal(key_match_and_values);
3804-
b.endArrayIndex();
3768+
/**
3769+
* Visit all sub-patterns for mapping in pattern (not subject).
3770+
*
3771+
* Generates boolean value (AND of result of all sub-patterns).
3772+
*
3773+
* @param patterns Sub-patterns to iterate through.
3774+
* @param values Patterns from subject to set as subject for evaluated sub-patterns.
3775+
* @param pc Pattern context.
3776+
*/
3777+
private void mappingVisitSubpatterns(PatternTy[] patterns, BytecodeLocal values, PatternContext pc) {
3778+
int patLen = patterns.length;
38053779

38063780
b.beginBlock();
3781+
// unpack values from pc.subject
3782+
BytecodeLocal valuesUnpacked = b.createLocal();
3783+
b.beginStoreLocal(valuesUnpacked);
3784+
b.beginUnpackSequence(patLen);
3785+
b.emitLoadLocal(values);
3786+
b.endUnpackSequence();
3787+
b.endStoreLocal();
38073788

3808-
// unpack values from pc.subject
3809-
BytecodeLocal values_unpacked = b.createLocal();
3810-
b.beginStoreLocal(values_unpacked);
3811-
b.beginUnpackSequence(pat_len);
3812-
b.beginArrayIndex(1);
3813-
b.emitLoadLocal(key_match_and_values);
3814-
b.endArrayIndex();
3815-
b.endUnpackSequence();
3816-
b.endStoreLocal();
3817-
3818-
b.beginPrimitiveBoolAnd(); // AND for sub-pats
3789+
// backup pc.subject, it will get replaced for sub-patterns
3790+
BytecodeLocal pcSave = b.createLocal();
3791+
b.beginStoreLocal(pcSave);
3792+
b.emitLoadLocal(pc.subject);
3793+
b.endStoreLocal();
38193794

3820-
for (int i = 0; i < pat_len; i++) {
3821-
b.beginBlock();
3795+
BytecodeLocal temp = b.createLocal();
3796+
b.beginStoreLocal(temp);
3797+
b.beginPrimitiveBoolAnd();
3798+
boolean hadNonWildcardPattern = false;
3799+
for (int i = 0; i < patLen; i++) {
3800+
if (wildcardCheck(patterns[i])) {
3801+
continue;
3802+
}
3803+
hadNonWildcardPattern = true;
3804+
b.beginBlock();
3805+
b.beginStoreLocal(pc.subject);
3806+
b.beginArrayIndex(i);
3807+
b.emitLoadLocal(valuesUnpacked);
3808+
b.endArrayIndex();
3809+
b.endStoreLocal();
3810+
3811+
visitSubpattern(patterns[i], pc);
3812+
b.endBlock();
3813+
}
3814+
if (!hadNonWildcardPattern) {
3815+
b.emitLoadConstant(true);
3816+
}
3817+
b.endPrimitiveBoolAnd();
3818+
b.endStoreLocal();
38223819

38233820
b.beginStoreLocal(pc.subject);
3824-
b.beginArrayIndex(i);
3825-
b.emitLoadLocal(values_unpacked);
3826-
b.endArrayIndex();
3821+
b.emitLoadLocal(pcSave);
38273822
b.endStoreLocal();
38283823

3829-
visitSubpattern(patterns[i], pc);
3830-
3831-
b.endBlock();
3832-
}
3824+
b.emitLoadLocal(temp);
3825+
b.endBlock();
3826+
}
38333827

3834-
b.emitLoadConstant(true);
3828+
private void doVisitPattern(PatternTy.MatchMapping node, PatternContext pc) {
3829+
/**
3830+
* Mapping pattern match will take the keys and check, whether the keys in the pattern are
3831+
* present in the subject. This is good enough, since the pattern needs only to be a subset of the subject.
3832+
* Keys aren't evaluated as subpatterns.
3833+
*
3834+
* After the key check, the values of the pattern are patterns as well and are evaluated as sub-patterns
3835+
* with values in the subject used as separate respective subjects.
3836+
*/
3837+
ExprTy[] keys = node.keys;
3838+
PatternTy[] patterns = node.patterns;
38353839

3836-
b.endPrimitiveBoolAnd(); // AND for sub-pats
3840+
int keyLen = lengthOrZero(keys);
3841+
int patLen = lengthOrZero(patterns);
38373842

3838-
b.endBlock();
3843+
if (keyLen != patLen) {
3844+
ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "keys (%d) / patterns (%d) length mismatch in mapping pattern", keyLen, patLen);
3845+
}
3846+
// @formatter:off
38393847

3840-
b.endPrimitiveBoolAnd(); // AND keys and values
3848+
b.beginPrimitiveBoolAnd(); // AND for type, trivial and key length matching
3849+
// check that type matches
3850+
b.beginCheckTypeFlags(TypeFlags.MAPPING);
3851+
b.emitLoadLocal(pc.subject);
3852+
b.endCheckTypeFlags();
38413853

3842-
b.endStoreLocal(); // temp
3854+
String starTarget = node.rest;
3855+
if (keyLen == 0 && starTarget == null) {
3856+
b.emitLoadConstant(true);
3857+
b.endPrimitiveBoolAnd();
3858+
return;
3859+
}
3860+
if (Integer.MAX_VALUE < keyLen - 1) {
3861+
ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "too many sub-patterns in mapping pattern");
3862+
}
38433863

3844-
// restore saved pc.subject
3845-
b.beginStoreLocal(pc.subject);
3846-
b.emitLoadLocal(pc_save);
3847-
b.endStoreLocal();
3864+
// If the pattern has any keys in it, perform a length check:
3865+
if (keyLen > 0) {
3866+
checkPatternKeysLength(keyLen, pc);
3867+
}
38483868

3849-
b.emitLoadLocal(temp);
3869+
b.beginBlock();
3870+
BytecodeLocal subjectPatterns = b.createLocal();
3871+
BytecodeLocal temp = b.createLocal();
3872+
BytecodeLocal keysChecked = b.createLocal();
3873+
3874+
b.beginStoreLocal(temp);
3875+
b.beginPrimitiveBoolAnd(); // AND process keys and sub-patterns
3876+
b.beginBlock();
3877+
b.beginStoreLocal(keysChecked);
3878+
processPatternKeys(keys, keyLen, node);
3879+
b.endStoreLocal();
3880+
3881+
// save match result together with values
3882+
b.beginMatchKeys(subjectPatterns);
3883+
b.emitLoadLocal(pc.subject);
3884+
b.emitLoadLocal(keysChecked);
3885+
b.endMatchKeys();
3886+
b.endBlock();
3887+
3888+
if (patLen > 0) {
3889+
mappingVisitSubpatterns(patterns, subjectPatterns, pc);
3890+
}
3891+
b.endPrimitiveBoolAnd(); // AND process keys and sub-patterns
3892+
b.endStoreLocal(); // temp
3893+
3894+
if (starTarget != null) {
3895+
BytecodeLocal starVariable = pc.allocateBindVariable(starTarget);
3896+
b.beginStoreLocal(starVariable);
3897+
b.beginCopyDictWithoutKeys();
3898+
b.emitLoadLocal(pc.subject);
3899+
b.emitLoadLocal(keysChecked);
3900+
b.endCopyDictWithoutKeys();
3901+
b.endStoreLocal();
3902+
}
38503903

3851-
b.endBlock();
3904+
b.emitLoadLocal(temp);
3905+
b.endBlock();
3906+
b.endPrimitiveBoolAnd(); // AND for key length matching
38523907

3853-
b.endPrimitiveBoolAnd(); // AND for sanity checks (length matching, etc.)
3908+
// @formatter:on
38543909
}
38553910

38563911
private void checkAlternativePatternDifferentNames(Set<String> control, Map<String, BytecodeLocal> bindVariables) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
import com.oracle.graal.python.nodes.argument.keywords.SameDictKeyException;
163163
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetFixedAttributeNode;
164164
import com.oracle.graal.python.nodes.builtins.ListNodes;
165+
import com.oracle.graal.python.nodes.bytecode.CopyDictWithoutKeysNode;
165166
import com.oracle.graal.python.nodes.bytecode.GetSendValueNode;
166167
import com.oracle.graal.python.nodes.bytecode.GetTPFlagsNode;
167168
import com.oracle.graal.python.nodes.bytecode.GetYieldFromIterNode;
@@ -1124,23 +1125,22 @@ public static void perform(VirtualFrame frame, Object object,
11241125
}
11251126

11261127
@Operation
1128+
@ConstantOperand(type = LocalAccessor.class)
11271129
public static final class MatchKeys {
11281130
@Specialization
1129-
public static Object perform(VirtualFrame frame, Object map, Object[] keys, @Cached MatchKeysNode node) {
1130-
Object[] rv = new Object[2];
1131-
rv[0] = node.execute(frame, map, keys) != PNone.NONE;
1132-
rv[1] = node.execute(frame, map, keys);
1133-
return rv;
1131+
public static boolean perform(VirtualFrame frame, LocalAccessor values, Object map, Object[] keys, @Bind BytecodeNode bytecodeNode, @Cached MatchKeysNode node) {
1132+
values.setObject(bytecodeNode, frame, node.execute(frame, map, keys));
1133+
return node.execute(frame, map, keys) != PNone.NONE;
11341134
}
11351135
}
11361136

1137-
// @Operation
1138-
// public static final class CheckNone {
1139-
// @Specialization
1140-
// public static boolean perform(VirtualFrame frame, Object o) {
1141-
// return o != PNone.NONE;
1142-
// }
1143-
// }
1137+
@Operation
1138+
public static final class CopyDictWithoutKeys {
1139+
@Specialization
1140+
public static PDict perform(VirtualFrame frame, Object map, Object[] keys, @Cached CopyDictWithoutKeysNode node) {
1141+
return node.execute(frame, map, keys);
1142+
}
1143+
}
11441144

11451145
@Operation
11461146
@ConstantOperand(type = TruffleString.class, name = "name")

0 commit comments

Comments
 (0)