@@ -27,10 +27,14 @@ namespace pyston {
27
27
// The logic is already complex, and the function also deals with rewriting
28
28
// the logic for ICs, so it gets pretty hairy.
29
29
30
- enum class KeywordDest {
30
+ enum class KeywordDestType {
31
31
POSITIONAL,
32
32
KWARGS,
33
33
};
34
+ struct KeywordDest {
35
+ KeywordDestType type;
36
+ int param_idx;
37
+ };
34
38
static KeywordDest placeKeyword (const ParamNames* param_names, llvm::SmallVector<bool , 8 >& params_filled,
35
39
BoxedString* kw_name, Box* kw_val, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** oargs,
36
40
BoxedDict* okwargs, const char * func_name) {
@@ -49,7 +53,7 @@ static KeywordDest placeKeyword(const ParamNames* param_names, llvm::SmallVector
49
53
getArg (j, oarg1, oarg2, oarg3, oargs) = kw_val;
50
54
params_filled[j] = true ;
51
55
52
- return KeywordDest ::POSITIONAL;
56
+ return { KeywordDestType ::POSITIONAL, j } ;
53
57
}
54
58
}
55
59
@@ -60,7 +64,7 @@ static KeywordDest placeKeyword(const ParamNames* param_names, llvm::SmallVector
60
64
kw_name->c_str ());
61
65
}
62
66
v = kw_val;
63
- return KeywordDest ::KWARGS;
67
+ return { KeywordDestType ::KWARGS, 0 } ;
64
68
} else {
65
69
raiseExcHelper (TypeError, " %.200s() got an unexpected keyword argument '%s'" , func_name, kw_name->c_str ());
66
70
}
@@ -146,6 +150,10 @@ extern "C" BoxedTuple* makeVarArgsFromArgsAndStarArgs(Box* arg1, Box* arg2, Box*
146
150
return starParam;
147
151
}
148
152
153
+ extern " C" void insertInDict (BoxedDict* d, Box* key, Box* val) {
154
+ d->d .insert (std::make_pair (key, val));
155
+ }
156
+
149
157
void rearrangeArguments (ParamReceiveSpec paramspec, const ParamNames* param_names, const char * func_name,
150
158
Box** defaults, CallRewriteArgs* rewrite_args, bool & rewrite_success, ArgPassSpec argspec,
151
159
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
240
248
}
241
249
242
250
llvm::SmallVector<bool , 8 > params_filled (num_output_args);
251
+ llvm::SmallVector<KeywordDest, 8 > kw_arg_idx_to_param_idx (argspec.num_keywords );
252
+
243
253
for (int i = 0 ; i < positional_to_positional + varargs_to_positional; i++) {
244
254
params_filled[i] = true ;
245
255
}
@@ -286,11 +296,14 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
286
296
if (!param_names || !param_names->takes_param_names ) {
287
297
assert (okwargs);
288
298
okwargs->d [(*keyword_names)[i]] = kw_val;
299
+
300
+ kw_arg_idx_to_param_idx[i] = { KeywordDestType::KWARGS, 0 };
289
301
continue ;
290
302
}
291
303
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;
294
307
}
295
308
296
309
if (argspec.has_kwargs ) {
@@ -361,10 +374,15 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
361
374
// If we need to make modifications, we have to copy it first.
362
375
363
376
// Right now we don't handle either of these
364
- if (argspec.has_kwargs || argspec. num_keywords )
377
+ if (argspec.has_kwargs )
365
378
return ;
366
379
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 ) {
368
386
assert (!argspec.has_kwargs );
369
387
assert (!argspec.num_keywords );
370
388
// 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
468
486
}
469
487
470
488
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
+
471
497
// We might have trouble if we have more output args than input args,
472
498
// such as if we need more space to pass defaults.
473
499
bool did_copy = false ;
@@ -543,40 +569,112 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
543
569
}
544
570
}
545
571
572
+ RewriterVar* r_output_kwargs = NULL ;
546
573
if (paramspec.takes_kwargs ) {
547
- assert (!argspec.num_keywords && !argspec. has_kwargs );
574
+ assert (!argspec.has_kwargs );
548
575
549
576
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);
551
578
552
579
if (kwargs_idx == 0 )
553
- rewrite_args->arg1 = r_kwargs ;
580
+ rewrite_args->arg1 = r_output_kwargs ;
554
581
if (kwargs_idx == 1 )
555
- rewrite_args->arg2 = r_kwargs ;
582
+ rewrite_args->arg2 = r_output_kwargs ;
556
583
if (kwargs_idx == 2 )
557
- rewrite_args->arg3 = r_kwargs ;
584
+ rewrite_args->arg3 = r_output_kwargs ;
558
585
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);
561
597
}
562
598
}
563
599
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 );
565
604
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
+ }
567
629
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;
569
637
638
+ RewriterVar* r_arg;
570
639
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 ;
572
641
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 ;
574
643
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);
580
678
}
581
679
}
582
680
0 commit comments