@@ -27,10 +27,14 @@ namespace pyston {
2727// The logic is already complex, and the function also deals with rewriting
2828// the logic for ICs, so it gets pretty hairy.
2929
30- enum class KeywordDest {
30+ enum class KeywordDestType {
3131 POSITIONAL,
3232 KWARGS,
3333};
34+ struct KeywordDest {
35+ KeywordDestType type;
36+ int param_idx;
37+ };
3438static KeywordDest placeKeyword (const ParamNames* param_names, llvm::SmallVector<bool , 8 >& params_filled,
3539 BoxedString* kw_name, Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs,
3640 BoxedDict* okwargs, const char * func_name) {
@@ -49,7 +53,7 @@ static KeywordDest placeKeyword(const ParamNames* param_names, llvm::SmallVector
4953 getArg (j, oarg1, oarg2, oarg3, oargs) = kw_val;
5054 params_filled[j] = true ;
5155
52- return KeywordDest ::POSITIONAL;
56+ return { KeywordDestType ::POSITIONAL, j } ;
5357 }
5458 }
5559
@@ -60,7 +64,7 @@ static KeywordDest placeKeyword(const ParamNames* param_names, llvm::SmallVector
6064 kw_name->c_str ());
6165 }
6266 v = kw_val;
63- return KeywordDest ::KWARGS;
67+ return { KeywordDestType ::KWARGS, 0 } ;
6468 } else {
6569 raiseExcHelper (TypeError, " %.200s() got an unexpected keyword argument '%s'" , func_name, kw_name->c_str ());
6670 }
@@ -146,6 +150,10 @@ extern "C" BoxedTuple* makeVarArgsFromArgsAndStarArgs(Box* arg1, Box* arg2, Box*
146150 return starParam;
147151}
148152
153+ extern " C" void insertInDict (BoxedDict* d, Box* key, Box* val) {
154+ d->d .insert (std::make_pair (key, val));
155+ }
156+
149157void rearrangeArguments (ParamReceiveSpec paramspec, const ParamNames* param_names, const char * func_name,
150158 Box** defaults, CallRewriteArgs* rewrite_args, bool & rewrite_success, ArgPassSpec argspec,
151159 Box* arg1, Box* arg2, Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names,
@@ -240,6 +248,8 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
240248 }
241249
242250 llvm::SmallVector<bool , 8 > params_filled (num_output_args);
251+ llvm::SmallVector<KeywordDest, 8 > kw_arg_idx_to_param_idx (argspec.num_keywords );
252+
243253 for (int i = 0 ; i < positional_to_positional + varargs_to_positional; i++) {
244254 params_filled[i] = true ;
245255 }
@@ -286,11 +296,14 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
286296 if (!param_names || !param_names->takes_param_names ) {
287297 assert (okwargs);
288298 okwargs->d [(*keyword_names)[i]] = kw_val;
299+
300+ kw_arg_idx_to_param_idx[i] = { KeywordDestType::KWARGS, 0 };
289301 continue ;
290302 }
291303
292- auto dest = placeKeyword (param_names, params_filled, (*keyword_names)[i], kw_val, oarg1, oarg2, oarg3, oargs,
293- okwargs, func_name);
304+ KeywordDest dest = placeKeyword (param_names, params_filled, (*keyword_names)[i], kw_val, oarg1, oarg2, oarg3,
305+ oargs, okwargs, func_name);
306+ kw_arg_idx_to_param_idx[i] = dest;
294307 }
295308
296309 if (argspec.has_kwargs ) {
@@ -361,10 +374,15 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
361374 // If we need to make modifications, we have to copy it first.
362375
363376 // Right now we don't handle either of these
364- if (argspec.has_kwargs || argspec. num_keywords )
377+ if (argspec.has_kwargs )
365378 return ;
366379
367- if (argspec.has_starargs && !paramspec.num_defaults ) {
380+ RewriterVar* r_original_arg1 = rewrite_args->arg1 ;
381+ RewriterVar* r_original_arg2 = rewrite_args->arg2 ;
382+ RewriterVar* r_original_arg3 = rewrite_args->arg3 ;
383+ RewriterVar* r_original_args = rewrite_args->args ;
384+
385+ if (argspec.has_starargs && !paramspec.num_defaults && !argspec.num_keywords ) {
368386 assert (!argspec.has_kwargs );
369387 assert (!argspec.num_keywords );
370388 // We just dispatch to a helper function to copy the args and call pyElements
@@ -468,6 +486,14 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
468486 }
469487
470488 if (!(paramspec.takes_varargs && argspec.num_args > paramspec.num_args + 3 ) && !argspec.has_starargs ) {
489+ // Most general case handled here is
490+ // def f(a, b, c, d=default, e=default, *args, **kwargs):
491+ //
492+ // f(1,2,...,keyword=blah,...)
493+ // (i.e. no starargs or kwargs passed in)
494+ assert (!argspec.has_starargs );
495+ assert (!argspec.has_kwargs );
496+
471497 // We might have trouble if we have more output args than input args,
472498 // such as if we need more space to pass defaults.
473499 bool did_copy = false ;
@@ -543,40 +569,112 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
543569 }
544570 }
545571
572+ RewriterVar* r_output_kwargs = NULL ;
546573 if (paramspec.takes_kwargs ) {
547- assert (!argspec.num_keywords && !argspec. has_kwargs );
574+ assert (!argspec.has_kwargs );
548575
549576 int kwargs_idx = paramspec.num_args + (paramspec.takes_varargs ? 1 : 0 );
550- RewriterVar* r_kwargs = rewrite_args->rewriter ->call (true , (void *)createDict);
577+ r_output_kwargs = rewrite_args->rewriter ->call (true , (void *)createDict);
551578
552579 if (kwargs_idx == 0 )
553- rewrite_args->arg1 = r_kwargs ;
580+ rewrite_args->arg1 = r_output_kwargs ;
554581 if (kwargs_idx == 1 )
555- rewrite_args->arg2 = r_kwargs ;
582+ rewrite_args->arg2 = r_output_kwargs ;
556583 if (kwargs_idx == 2 )
557- rewrite_args->arg3 = r_kwargs ;
584+ rewrite_args->arg3 = r_output_kwargs ;
558585 if (kwargs_idx >= 3 ) {
559- assert (did_copy);
560- rewrite_args->args ->setAttr ((kwargs_idx - 3 ) * sizeof (Box*), r_kwargs);
586+ if (!did_copy) {
587+ if (num_passed_args <= 3 ) {
588+ // we weren't passed args
589+ rewrite_args->args = rewrite_args->rewriter ->allocate (num_output_args - 3 );
590+ } else {
591+ rewrite_args->args
592+ = rewrite_args->rewriter ->allocateAndCopy (rewrite_args->args , num_output_args - 3 );
593+ }
594+ did_copy = true ;
595+ }
596+ rewrite_args->args ->setAttr ((kwargs_idx - 3 ) * sizeof (Box*), r_output_kwargs);
561597 }
562598 }
563599
564- for (int arg_idx = std::max ((int )(paramspec.num_args - paramspec.num_defaults ), (int )argspec.num_args );
600+ // Here we loop through all the positional parameters which are past the last positional arg.
601+ // In each case, we check if we can fill it with either a given keyword arg (done below).
602+ // If not, we fill it with the default.
603+ for (int arg_idx = std::max ((int )argspec.num_args , paramspec.num_args - paramspec.num_defaults );
565604 arg_idx < paramspec.num_args ; arg_idx++) {
566- int default_idx = arg_idx + paramspec.num_defaults - paramspec.num_args ;
605+ // Do we have a keyword for this?
606+ if (!params_filled[arg_idx]) {
607+ // No keyword arg, use the default
608+ int default_idx = arg_idx + paramspec.num_defaults - paramspec.num_args ;
609+ Box* default_obj = defaults[default_idx];
610+ RewriterVar* r_default = rewrite_args->rewriter ->loadConst ((intptr_t )default_obj);
611+
612+ if (arg_idx == 0 )
613+ rewrite_args->arg1 = r_default;
614+ else if (arg_idx == 1 )
615+ rewrite_args->arg2 = r_default;
616+ else if (arg_idx == 2 )
617+ rewrite_args->arg3 = r_default;
618+ else {
619+ if (!did_copy) {
620+ if (num_passed_args <= 3 ) {
621+ // we weren't passed args
622+ rewrite_args->args = rewrite_args->rewriter ->allocate (num_output_args - 3 );
623+ } else {
624+ rewrite_args->args
625+ = rewrite_args->rewriter ->allocateAndCopy (rewrite_args->args , num_output_args - 3 );
626+ }
627+ did_copy = true ;
628+ }
567629
568- Box* default_obj = defaults[default_idx];
630+ rewrite_args->args ->setAttr ((arg_idx - 3 ) * sizeof (Box*), r_default);
631+ }
632+ }
633+ }
634+
635+ for (int i = 0 ; i < argspec.num_keywords ; i++) {
636+ int arg_idx = argspec.num_args + i;
569637
638+ RewriterVar* r_arg;
570639 if (arg_idx == 0 )
571- rewrite_args-> arg1 = rewrite_args-> rewriter -> loadConst (( intptr_t )default_obj, Location::forArg ( 0 )) ;
640+ r_arg = r_original_arg1 ;
572641 else if (arg_idx == 1 )
573- rewrite_args-> arg2 = rewrite_args-> rewriter -> loadConst (( intptr_t )default_obj, Location::forArg ( 1 )) ;
642+ r_arg = r_original_arg2 ;
574643 else if (arg_idx == 2 )
575- rewrite_args->arg3 = rewrite_args->rewriter ->loadConst ((intptr_t )default_obj, Location::forArg (2 ));
576- else {
577- assert (did_copy);
578- rewrite_args->args ->setAttr ((arg_idx - 3 ) * sizeof (Box*),
579- rewrite_args->rewriter ->loadConst ((intptr_t )default_obj));
644+ r_arg = r_original_arg3;
645+ else
646+ r_arg = r_original_args->getAttr (sizeof (Box*) * (arg_idx - 3 ));
647+
648+ KeywordDest dest = kw_arg_idx_to_param_idx[i];
649+ if (dest.type == KeywordDestType::POSITIONAL) {
650+ // Move keyword arg into its keyword position
651+ if (dest.param_idx == 0 )
652+ rewrite_args->arg1 = r_arg;
653+ else if (dest.param_idx == 1 )
654+ rewrite_args->arg2 = r_arg;
655+ else if (dest.param_idx == 2 )
656+ rewrite_args->arg3 = r_arg;
657+ else {
658+ if (!did_copy) {
659+ if (num_passed_args <= 3 ) {
660+ // we weren't passed args
661+ rewrite_args->args = rewrite_args->rewriter ->allocate (num_output_args - 3 );
662+ } else {
663+ rewrite_args->args
664+ = rewrite_args->rewriter ->allocateAndCopy (rewrite_args->args , num_output_args - 3 );
665+ }
666+ did_copy = true ;
667+ }
668+
669+ rewrite_args->args ->setAttr ((dest.param_idx - 3 ) * sizeof (Box*), r_arg);
670+ }
671+ } else {
672+ // TODO we should be able to inline a lot more of the dict creation
673+ // (e.g. just have a "template" dict object and copy all the attributes into the
674+ // right offsets)
675+ assert (r_output_kwargs != NULL );
676+ rewrite_args->rewriter ->call (false , (void *)insertInDict, r_output_kwargs,
677+ rewrite_args->rewriter ->loadConst ((int64_t )(*keyword_names)[i]), r_arg);
580678 }
581679 }
582680
0 commit comments