75
75
import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
76
76
import com .oracle .graal .python .lib .PyObjectIsTrueNode ;
77
77
import com .oracle .graal .python .lib .PyObjectSizeNode ;
78
+ import com .oracle .graal .python .lib .PySequenceCheckNode ;
78
79
import com .oracle .graal .python .nodes .ErrorMessages ;
79
80
import com .oracle .graal .python .nodes .PGuards ;
81
+ import com .oracle .graal .python .nodes .builtins .TupleNodes ;
80
82
import com .oracle .graal .python .nodes .classes .IsSubtypeNode ;
81
83
import com .oracle .graal .python .nodes .object .GetClassNode ;
82
84
import com .oracle .graal .python .nodes .object .IsBuiltinClassProfile ;
@@ -139,6 +141,7 @@ public abstract class CExtParseArgumentsNode {
139
141
static final char FORMAT_LOWER_W = 'w' ;
140
142
static final char FORMAT_LOWER_P = 'p' ;
141
143
static final char FORMAT_PAR_OPEN = '(' ;
144
+ static final char FORMAT_PAR_CLOSE = ')' ;
142
145
143
146
@ GenerateUncached
144
147
@ ImportStatic (PGuards .class )
@@ -241,15 +244,8 @@ private static ParserState convertArg(ParserState state, Object kwds, char[] for
241
244
case FORMAT_LOWER_W :
242
245
case FORMAT_LOWER_P :
243
246
case FORMAT_PAR_OPEN :
247
+ case FORMAT_PAR_CLOSE :
244
248
return convertArgNode .execute (state , kwds , c , format , format_idx , kwdnames , varargs );
245
- case ')' :
246
- if (state .v .prev == null ) {
247
- CompilerDirectives .transferToInterpreter ();
248
- raiseNode .raiseIntWithoutFrame (0 , PythonBuiltinClassType .SystemError , ErrorMessages .LEFT_BRACKET_WO_RIGHT_BRACKET_IN_ARG );
249
- throw ParseArgumentsException .raise ();
250
- } else {
251
- return state .close ();
252
- }
253
249
case '|' :
254
250
if (state .restOptional ) {
255
251
raiseNode .raiseIntWithoutFrame (0 , SystemError , "Invalid format string (| specified twice)" , c );
@@ -1039,8 +1035,10 @@ static ParserState doPredicate(ParserState state, Object kwds, @SuppressWarnings
1039
1035
}
1040
1036
1041
1037
@ Specialization (guards = "c == FORMAT_PAR_OPEN" )
1042
- static ParserState doPredicate (ParserState state , Object kwds , @ SuppressWarnings ("unused" ) char c , @ SuppressWarnings ("unused" ) char [] format , @ SuppressWarnings ("unused" ) int format_idx ,
1038
+ static ParserState doParOpen (ParserState state , Object kwds , @ SuppressWarnings ("unused" ) char c , @ SuppressWarnings ("unused" ) char [] format , @ SuppressWarnings ("unused" ) int format_idx ,
1043
1039
Object kwdnames , @ SuppressWarnings ("unused" ) Object varargs ,
1040
+ @ Cached PySequenceCheckNode sequenceCheckNode ,
1041
+ @ Cached TupleNodes .ConstructTupleNode constructTupleNode ,
1044
1042
@ Cached PythonObjectFactory factory ,
1045
1043
@ Shared ("getArgNode" ) @ Cached GetArgNode getArgNode ,
1046
1044
@ Shared ("raiseNode" ) @ Cached PRaiseNativeNode raiseNode ) throws InteropException , ParseArgumentsException {
@@ -1049,14 +1047,33 @@ static ParserState doPredicate(ParserState state, Object kwds, @SuppressWarnings
1049
1047
if (skipOptionalArg (arg , state .restOptional )) {
1050
1048
return state .open (new PositionalArgStack (factory .createEmptyTuple (), state .v ));
1051
1049
} else {
1052
- // n.b.: there is a small gap in this check: In theory, there could be
1053
- // native subclass of tuple. But since we do not support this anyway, the
1054
- // instanceof test is just the most efficient way to do it.
1055
- if (!(arg instanceof PTuple )) {
1050
+ if (!sequenceCheckNode .execute (arg )) {
1056
1051
throw raise (raiseNode , TypeError , ErrorMessages .EXPECTED_S_GOT_P , "tuple" , arg );
1057
1052
}
1058
- return state .open (new PositionalArgStack ((PTuple ) arg , state .v ));
1053
+ try {
1054
+ return state .open (new PositionalArgStack (constructTupleNode .execute (null , arg ), state .v ));
1055
+ } catch (PException e ) {
1056
+ throw raise (raiseNode , TypeError , "failed to convert sequence" );
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ @ Specialization (guards = "c == FORMAT_PAR_CLOSE" )
1062
+ static ParserState doParClose (ParserState state , @ SuppressWarnings ("unused" ) Object kwds , @ SuppressWarnings ("unused" ) char c , @ SuppressWarnings ("unused" ) char [] format ,
1063
+ @ SuppressWarnings ("unused" ) int format_idx ,
1064
+ @ SuppressWarnings ("unused" ) Object kwdnames , @ SuppressWarnings ("unused" ) Object varargs ,
1065
+ @ Cached SequenceStorageNodes .LenNode lenNode ,
1066
+ @ Shared ("raiseNode" ) @ Cached PRaiseNativeNode raiseNode ) throws ParseArgumentsException {
1067
+ if (state .v .prev == null ) {
1068
+ CompilerDirectives .transferToInterpreter ();
1069
+ raiseNode .raiseIntWithoutFrame (0 , PythonBuiltinClassType .SystemError , ErrorMessages .LEFT_BRACKET_WO_RIGHT_BRACKET_IN_ARG );
1070
+ throw ParseArgumentsException .raise ();
1071
+ }
1072
+ int len = lenNode .execute (state .v .argv .getSequenceStorage ());
1073
+ if (len != state .v .argnum ) {
1074
+ throw raise (raiseNode , TypeError , "must be sequence of length %d, not %d" , state .v .argnum , len );
1059
1075
}
1076
+ return state .close ();
1060
1077
}
1061
1078
1062
1079
private static ParseArgumentsException raise (PRaiseNativeNode raiseNode , PythonBuiltinClassType errType , String format , Object ... arguments ) {
0 commit comments