7575import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
7676import com .oracle .graal .python .lib .PyObjectIsTrueNode ;
7777import com .oracle .graal .python .lib .PyObjectSizeNode ;
78+ import com .oracle .graal .python .lib .PySequenceCheckNode ;
7879import com .oracle .graal .python .nodes .ErrorMessages ;
7980import com .oracle .graal .python .nodes .PGuards ;
81+ import com .oracle .graal .python .nodes .builtins .TupleNodes ;
8082import com .oracle .graal .python .nodes .classes .IsSubtypeNode ;
8183import com .oracle .graal .python .nodes .object .GetClassNode ;
8284import com .oracle .graal .python .nodes .object .IsBuiltinClassProfile ;
@@ -139,6 +141,7 @@ public abstract class CExtParseArgumentsNode {
139141 static final char FORMAT_LOWER_W = 'w' ;
140142 static final char FORMAT_LOWER_P = 'p' ;
141143 static final char FORMAT_PAR_OPEN = '(' ;
144+ static final char FORMAT_PAR_CLOSE = ')' ;
142145
143146 @ GenerateUncached
144147 @ ImportStatic (PGuards .class )
@@ -241,15 +244,8 @@ private static ParserState convertArg(ParserState state, Object kwds, char[] for
241244 case FORMAT_LOWER_W :
242245 case FORMAT_LOWER_P :
243246 case FORMAT_PAR_OPEN :
247+ case FORMAT_PAR_CLOSE :
244248 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- }
253249 case '|' :
254250 if (state .restOptional ) {
255251 raiseNode .raiseIntWithoutFrame (0 , SystemError , "Invalid format string (| specified twice)" , c );
@@ -1039,8 +1035,10 @@ static ParserState doPredicate(ParserState state, Object kwds, @SuppressWarnings
10391035 }
10401036
10411037 @ 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 ,
10431039 Object kwdnames , @ SuppressWarnings ("unused" ) Object varargs ,
1040+ @ Cached PySequenceCheckNode sequenceCheckNode ,
1041+ @ Cached TupleNodes .ConstructTupleNode constructTupleNode ,
10441042 @ Cached PythonObjectFactory factory ,
10451043 @ Shared ("getArgNode" ) @ Cached GetArgNode getArgNode ,
10461044 @ Shared ("raiseNode" ) @ Cached PRaiseNativeNode raiseNode ) throws InteropException , ParseArgumentsException {
@@ -1049,14 +1047,33 @@ static ParserState doPredicate(ParserState state, Object kwds, @SuppressWarnings
10491047 if (skipOptionalArg (arg , state .restOptional )) {
10501048 return state .open (new PositionalArgStack (factory .createEmptyTuple (), state .v ));
10511049 } 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 )) {
10561051 throw raise (raiseNode , TypeError , ErrorMessages .EXPECTED_S_GOT_P , "tuple" , arg );
10571052 }
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 );
10591075 }
1076+ return state .close ();
10601077 }
10611078
10621079 private static ParseArgumentsException raise (PRaiseNativeNode raiseNode , PythonBuiltinClassType errType , String format , Object ... arguments ) {
0 commit comments