Check-in [76b943ad4a]
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:More argument preparation code in 'varargs'
Timelines: family | ancestors | descendants | both | notworking | kbk-refactor-callframe
Files: files | file ages | folders
SHA3-256: 76b943ad4a8bf322aaa2c4ca5f1bbf70bbb01f5b3a243db67d461e35cb9274c3
User & Date: kbk 2019-01-16 02:30:51
Context
2019-01-18
04:22
Add the final processing in 'varargs' - next, emit the error path. check-in: 305328fa6b user: kbk tags: notworking, kbk-refactor-callframe
2019-01-16
02:30
More argument preparation code in 'varargs' check-in: 76b943ad4a user: kbk tags: notworking, kbk-refactor-callframe
2019-01-14
03:46
Further development of varargs. Note that the invocation sequence is much, much simpler than it used to be, so 'invoke.tcl' is no more. check-in: 90e908dae3 user: kbk tags: notworking, kbk-refactor-callframe
Changes

Changes to quadcode/builder.tcl.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
..
69
70
71
72
73
74
75



















76
77
78
79
80
81
82
    set xfmr $xfmr_
    set b $b_
    set bb $bb_
    set bbindex {}
    set varindex {}
}
 
# quadcode::builder maketemp --
#
#	Makes a temporary variable.
#
# Parameters:
#	name - Base name for the temporary.
#
# Results:
................................................................................
#	Stores the name as the most recent instance of the temporary.

oo::define quadcode::builder method maketemp {name} {
    set ssaname [$xfmr newVarInstance [list temp @$name]]
    dict set varindex $name $ssaname
    return $ssaname
}



















 
# quadcode::builder method emit --
#
#	Emits an instruction into the basic block under construction.
#
# Parameters:
#	q - Quadcode instruction to emit






|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
..
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    set xfmr $xfmr_
    set b $b_
    set bb $bb_
    set bbindex {}
    set varindex {}
}
 
# quadcode::builder method maketemp --
#
#	Makes a temporary variable.
#
# Parameters:
#	name - Base name for the temporary.
#
# Results:
................................................................................
#	Stores the name as the most recent instance of the temporary.

oo::define quadcode::builder method maketemp {name} {
    set ssaname [$xfmr newVarInstance [list temp @$name]]
    dict set varindex $name $ssaname
    return $ssaname
}
 
# quadcode::builder method gettemp --
#
#	Gets the last instance of a temporary variable
#
# Parameters:
#	name - Base name of the temporary
#
# Results:
#	Returns the SSA name of the lastest instance of the temporary,
#	or "" if there is no instance.

oo::define quadcode::builder method gettemp {name} {
    if {[dict exists $varindex $name]} {
        return [dict get $varindex $name]
    } else {
        return {}
    }
}
 
# quadcode::builder method emit --
#
#	Emits an instruction into the basic block under construction.
#
# Parameters:
#	q - Quadcode instruction to emit

Changes to quadcode/varargs.tcl.

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276


277
278
279
280
281
282
283
...
297
298
299
300
301
302
303
304
305

306
307








308
309
310
311
312
313
314
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640





























































641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660


661
662
663
664

665
666
667
668
669
670
671
...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
...
764
765
766
767
768
769
770

771
772
773
774
775
776
777
...
814
815
816
817
818
819
820

821
822
823
824
825
826
827
...
888
889
890
891
892
893
894

895
896
897
898
899
900
901
...
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952

953



954
955
956

957
958
959
960
961
962
963




964
965
966
967

968
969
970
971
972
973
974
....
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
    set bb [my va_UnlinkTail $b $pc]
    set B [quadcode::builder new [self] $b $bb]

    # Prepare parameters for the 'invoke' (or 'invokeExpanded') call, and
    # add the call to the instruction sequence under construction.
    my va_PrepareArgs $B $b $pc $q $arginfo
 
    puts "NOT FINISHED."
    exit
    $B destroy
    $call destroy
    return
}
 
# quadcode::transformer method va_GetArgInfo --
#
................................................................................

    my debug-varargs {
        puts "varargs: $b:$pc: matched $pos out of $nPlainParams\
              leading non-expanded arg(s)."
    }

    # Generate code to make the rest of the args into a list
    lassign [my va_MakeArgList $B $argl $pos $cfin] mightThrow listLoc

    # We are going to need the length of the list, so
    # extract that now. (If it turns out somehow that we
    # don't use it, 'deadvars' will get rid of this, anyway.)
    set lenLoc1 [my newVarInstance {temp @arglen}]
    set lenLoc [my newVarInstance {temp @arglen}]
    $B emit [list listLength $lenLoc1 $listLoc]
    
    my debug-varargs {
        $B log-last
    }
    $B emit [list extractMaybe $lenLoc $lenLoc1]
    my debug-varargs {
        $B log-last
    }
................................................................................
        incr pos
    }
    my debug-varargs {
        puts "varargs: first optional arg is at position $pos"
    }
    set firstOptional $pos


    puts "NOT DONE - varargs built the arglist in $listLoc"
    exit 1

}


if 0 {

    set compTemp [list temp [incr $tempIndex]]

    set nMandatory 0
    if {$firstOptional > $firstMandatory} {

        # Make code to check length of arg list, starting a
        # new basic block
        set nMandatory [expr {$firstOptional - $firstMandatory}]
        set b [my va_CheckEnough $b $bb $lenLoc $compTemp \
                   $nMandatory $notokb]
        set bb {}

        # Make code to transfer mandatory args
        my va_UnpackMandatory tempIndex bb newq $b $listLoc $nMandatory
    }

    # Now we have the parameters that have default values.

    set j $nMandatory
    if {$nPlainParams > $firstOptional} {



        # Emit a code burst for each optional parameter to
        # check the list length and extract the parameter
        set optInfo {}
        set finishB [llength $bbcontent]
        lappend bbcontent {}
        lappend bbpred {}
................................................................................
        my va_FinishOptional b bb newq $finishB $optInfo

    }

    # If the procedure has 'args', then fill it in with the remainder of the
    # arg list.
    if {$haveargs} {
        my va_DoArgs tempIndex $b bb newq $listLoc $j
    } else {

        my va_CheckTooMany b bb $lenLoc $compTemp $j $notokb
    }









    # Create the normal invocation sequence.
    # 1. Create moveToCallFrame

    set cfin [$call cfin]
    set invars [$call invars]
    if {[$call pc0] < $pc} {
................................................................................
        dict set errorphis $outval [list bb $err1b] $notokval
    }        

    # 6. Make the terminal jumps
    my va_EmitAndTrack $b bb [list jumpMaybe [list bb $err0b] $okresult]
    my va_EmitAndTrack $b bb [list jump [list bb $norm0b]]

    # Emit the final basic block rewrite

    lset bbcontent $b $bb

    # toRepair will have the variables that have to be fixed up by
    # repairSSAVariable after this stuff runs
    set toRepair {}

................................................................................
#	B - quadcode::builder that is rewriting the invocation sequence.
#	argl - Argument list being analyzed
#	pos - Position in the argument list
#	cfin - Callframe input to the 'invoke' instruction.
#
# Results:
#
#	Returns a two-element list. The first element is 1 if it is possible
#	that the argument list is a non-list, and 0 otherwise.  The second
#	element is the name of a variable, temporary or literal that holds the
#	expanded list.

oo::define quadcode::transformer method va_MakeArgList {B argl pos cfin} {

    my debug-varargs {
        puts "varargs: make arg list for [list $argl] from position $pos"
    }

................................................................................
        $B emit [list $op $nloc $listLoc $arg]
        my debug-varargs {
            $B log-last
        }

        # If the concatenation might have failed, emit the error check
        if {$mightThrow} {
            my va_MakeErrorCheck $B $cfin $nloc
            set mightThrow 0
        }

        # On normal exit from list construction, extract the result from the
        # 'maybe' returned by listAppend or listConcat
        set listLoc [$B maketemp arglist]
        $B emit [list extractMaybe $listLoc $nloc]
        my debug-varargs {
            $B log-last
        }
    }

    set retval [list $mightThrow $listLoc]
    return $retval






























































}
 
# quadcode::transformer method va_MakeErrorCheck --
#
#	Emits code to jump to an error block if a given value is FAIL.
#
# Parameters:
#	B - Builder that is emitting code
#	cf - Callframe that is active at the time of the check
#	val - Value that might be FAIL
#
# Results:
#	None.
#
# Side effects:
#	Emits the necessary jumpMaybe, and adds callframe and FAIL value
#	to the phi operations at the head of the error block.

oo::define quadcode::transformer method va_makeErrorCheck {B cf val} {



    # Emit any required error checking when building the variable
    # argument list.
    my va_MakeErrorBlock $B

    set intb [$B makeblock]
    set nextb [$B makeblock]

    # Close out the current block with jumpMaybe to an intermediate
    # block and jump to the normal return
    $B emit [list jumpMaybe [list bb $intb] $val]
    my debug-varargs {
................................................................................
    $B emit [list jump [list bb $errorb]]
    my debug-varargs {
        $B log-last
    }

    # Add phis for the error result ant the callframe to the error block
    set errorInPhi [$B get-or-make-temp error]
    set callframeInPhi [$B get-or-make-temp error-callframe]
    $B phi $errorb $errorInPhi $val
    $B phi $errorb $callframeInPhi $cf

    # Now continue building in the normal exit
    $B buildin $nextb
}
 
# quadcode::transformer method va_CheckEnough --
#
#	Emits code to check for too few args passed to invokeExpanded
#
# Parameters:
#	b - Basic block number under construction
#	bb - Instructions in the block
#	lenLoc - Location holding the length of the arg list
#	compTemp - Temporary variable name to use for comparison
#	nMandatory - Number of mandatory args still unpaired
#	errorB - Basic block to jump to if too few args
#
# Results:
#	Returns the new basic block number; this method ends the block.

oo::define quadcode::transformer method va_CheckEnough {b bb lenLoc compTemp
                                                            nMandatory errorB} {
    # Emit {$nMandatory > $lenLoc}
    set compLoc [my newVarInstance $compTemp]
    my va_EmitAndTrack $b bb \
        [list gt $compLoc [list literal $nMandatory] $lenLoc]

    # Emit jumpTrue to the error block. This has to go through an
    # intermediate block because it will be a critical edge otherwise.
    # Emit jump to the following block
    set intb [llength $bbcontent]
    lappend bbcontent {}
    lappend bbpred {}
    set newb [llength $bbcontent]
    lappend bbcontent {}
    lappend bbpred {}

    my va_EmitAndTrack $b bb [list jumpTrue [list bb $intb] $compLoc]
    my va_EmitAndTrack $b bb [list jump [list bb $newb]]

    lset bbcontent $b $bb
    set bb {}

    # Emit the intermediate jump
    my va_EmitAndTrack $intb bb [list jump [list bb $errorB]]
    lset bbcontent $intb $bb
    set bb {}

    return $newb
}
 
# quadcode::transformer method va_UnpackMandatory --
#
#	Unpacks the mandatory args to a proc from the list created
#	by argument expansion
#
# Parameters;
................................................................................
# Side effects:
#	Emits code to unpack the mandatory parameters

oo::define quadcode::transformer method va_UnpackMandatory {tempIdxVar
                                                                bbVar newqVar
                                                                b listLoc
                                                                nMandatory} {

    upvar 1 $tempIdxVar tempIdx $bbVar bb $newqVar newq

    for {set i 0} {$i < $nMandatory} {incr i} {

        # Emit the 'listIndex' instruction for one arg. It can't fail
        # because we know we have a list

................................................................................
#	Emits code to unpack one value, or jump to the finish block if
#	there is nothing to unpack.

oo::define quadcode::transformer method va_UnpackOptional {tempIdxVar bVar
                                                               bbVar finishB
                                                               compTemp listLoc
                                                               lenLoc j} {

    upvar 1 $tempIdxVar tempIndex $bVar b $bbVar bb

    set pos [list literal $j]
    set compLoc [my newVarInstance $compTemp]
    set argTemp [list temp [incr tempIndex]]
    set argLoc1 [my newVarInstance $argTemp]
    set argLoc2 [my newVarInstance $argTemp]
................................................................................
#	outputs of the phi instructions to the 'invoke' instruction
#	under construction.

oo::define quadcode::transformer method va_FinishOptional {bVar bbVar
                                                               newqVar finishB
                                                               optInfo} {


    upvar 1 $bVar b $bbVar bb $newqVar newq

    # Finish the current block and start building into 'finishB'

    my va_EmitAndTrack $b bb [list jump [list bb $finishB]]
    lset bbcontent $b $bb
    set bb {}
................................................................................

# quadcode::transformer method va_DoArgs --
#
#	Emits code to extract the parameter sequence needed to fill '$args'
#	from the parameter list.
#
# Parameters:
#	tempIdxVar - Variable containing the last temporary index used
#	b - basic block number under construction
#	bbVar - Variable containing the code of the basic block
#	newqVar - Variable containing the 'invoke' instruction under
#                 construction
#	listLoc - LLVM location holding the argument list
#	i - Index in the arg list at which 'args' starts
#
# Results:
#	None.
#
# Side effects:
#	Emits any code necessary to fill in 'args', and adds the resulting
#	variable onto the end of the new instruction.

oo::define quadcode::transformer method va_DoArgs {tempIdxVar b bbVar

                                                       newqVar listLoc i} {




    upvar 1 $tempIdxVar tempIndex $bbVar bb $newqVar newq


    if {$i == 0} {
        lappend newq $listLoc
    } else {
        set argsTemp [list temp [incr tempIndex]]
        set argsLoc1 [my newVarInstance $argsTemp]
        my va_EmitAndTrack $b bb [list listRange $argsLoc1 $listLoc \
                                   [list literal $i] [list literal end]]




        set argsLoc2 [my newVarInstance $argsTemp]
        my va_EmitAndTrack $b bb [list extractMaybe $argsLoc2 $argsLoc1]
        lappend newq $argsLoc2
    }

}
 
# quadcode::transformer method va_CheckTooMany --
#
#	Emits a codeburst to check whether an 'invokeExpanded' has
#	too many args
#
................................................................................
 
# quadcode::transformer method va_EmitWrongArgs --
#
#	Generates code to throw the 'wrong # args' error when needed
#
# Parameters:
#	result - Quadcode value that will hold the command result
#	cfout - Quadcode value that will hold the result callframe,
#	        or {} if no callframe need be produced
#	cfin - Quadcode value that holds the pre-invoke callframe,
#	       or Nothing if no callframe need be produced
#	cmd - Quadcode literal with the name of the command being invoked
#
# Results:
#	None.
#
# Side effects:
#	Returns a codeburst that throws the exception

oo::define quadcode::transformer method va_EmitWrongArgs {result cfout 
                                                              cfin cmd} {

    set burst {}
    if {$cfin ne "Nothing"} {
        lappend burst [list copy $cfout $cfin]
    }

    set argl [info args [lindex $cmd 1]]
    set left [llength $argl]
    set sbval [list [lindex $cmd 1]]
    foreach a $argl {
        incr left -1
        if {$a eq "args" && $left == 0} {






|
|







 







|





|
|
<







 







<
<
<
<
<
<
<
<
<
<
<



|
<

|
<
<


|






>
>







 







|

>


>
>
>
>
>
>
>
>







 







|







 







|
|
<
<







 







|












<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









<






|
|

|
>
>




>







 







<

<




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>







 







>







 







>







 







|
|
<
|
<
<
|








|
>
|
>
>
>
|
<

>



<
|
|
|
>
>
>
>
|
|


>







 







<
<










|
<


<
<
<







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
...
240
241
242
243
244
245
246











247
248
249
250

251
252


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
...
510
511
512
513
514
515
516
517
518


519
520
521
522
523
524
525
...
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703

704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
...
741
742
743
744
745
746
747

748

749
750
751
752














































753
754
755
756
757
758
759
...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
...
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
...
941
942
943
944
945
946
947
948
949

950


951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966

967
968
969
970
971

972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
....
1035
1036
1037
1038
1039
1040
1041


1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052

1053
1054



1055
1056
1057
1058
1059
1060
1061
    set bb [my va_UnlinkTail $b $pc]
    set B [quadcode::builder new [self] $b $bb]

    # Prepare parameters for the 'invoke' (or 'invokeExpanded') call, and
    # add the call to the instruction sequence under construction.
    my va_PrepareArgs $B $b $pc $q $arginfo
 
    error "NOT FINISHED - rewriting invoke instruction"

    $B destroy
    $call destroy
    return
}
 
# quadcode::transformer method va_GetArgInfo --
#
................................................................................

    my debug-varargs {
        puts "varargs: $b:$pc: matched $pos out of $nPlainParams\
              leading non-expanded arg(s)."
    }

    # Generate code to make the rest of the args into a list
    set mightThrow [my va_MakeArgList $B $argl $pos $cfin]

    # We are going to need the length of the list, so
    # extract that now. (If it turns out somehow that we
    # don't use it, 'deadvars' will get rid of this, anyway.)
    set lenLoc1 [my newVarInstance {temp @arglen}]
    set lenLoc [$B maketemp arglen]
    $B emit [list listLength $lenLoc1 [$B gettemp arglist]]

    my debug-varargs {
        $B log-last
    }
    $B emit [list extractMaybe $lenLoc $lenLoc1]
    my debug-varargs {
        $B log-last
    }
................................................................................
        incr pos
    }
    my debug-varargs {
        puts "varargs: first optional arg is at position $pos"
    }
    set firstOptional $pos












    set nMandatory 0
    if {$firstOptional > $firstMandatory} {

        # Make code to check length of arg list

        set nMandatory [expr {$firstOptional - $firstMandatory}]
        my va_CheckEnough $B $nMandatory



        # Make code to transfer mandatory args
        my va_UnpackMandatory $B newq $nMandatory
    }

    # Now we have the parameters that have default values.

    set j $nMandatory
    if {$nPlainParams > $firstOptional} {

        error "NOT DONE - varargs doing optional arg(s)"

        # Emit a code burst for each optional parameter to
        # check the list length and extract the parameter
        set optInfo {}
        set finishB [llength $bbcontent]
        lappend bbcontent {}
        lappend bbpred {}
................................................................................
        my va_FinishOptional b bb newq $finishB $optInfo

    }

    # If the procedure has 'args', then fill it in with the remainder of the
    # arg list.
    if {$haveargs} {
        my va_DoArgs $B newq $j
    } else {
        error  "NOT DONE - varargs needs to check for excess args"
        my va_CheckTooMany b bb $lenLoc $compTemp $j $notokb
    }

    error "NOT DONE - varargs needs to emit call:\n    $newq"
}


if 0 {



    # Create the normal invocation sequence.
    # 1. Create moveToCallFrame

    set cfin [$call cfin]
    set invars [$call invars]
    if {[$call pc0] < $pc} {
................................................................................
        dict set errorphis $outval [list bb $err1b] $notokval
    }        

    # 6. Make the terminal jumps
    my va_EmitAndTrack $b bb [list jumpMaybe [list bb $err0b] $okresult]
    my va_EmitAndTrack $b bb [list jump [list bb $norm0b]]

q    # Emit the final basic block rewrite

    lset bbcontent $b $bb

    # toRepair will have the variables that have to be fixed up by
    # repairSSAVariable after this stuff runs
    set toRepair {}

................................................................................
#	B - quadcode::builder that is rewriting the invocation sequence.
#	argl - Argument list being analyzed
#	pos - Position in the argument list
#	cfin - Callframe input to the 'invoke' instruction.
#
# Results:
#
#	Returns 1 if it is possible that the argument list is a non-list,
#	and 0 otherwise.



oo::define quadcode::transformer method va_MakeArgList {B argl pos cfin} {

    my debug-varargs {
        puts "varargs: make arg list for [list $argl] from position $pos"
    }

................................................................................
        $B emit [list $op $nloc $listLoc $arg]
        my debug-varargs {
            $B log-last
        }

        # If the concatenation might have failed, emit the error check
        if {$mightThrow} {
            my va_MakeErrorCheck $B $nloc
            set mightThrow 0
        }

        # On normal exit from list construction, extract the result from the
        # 'maybe' returned by listAppend or listConcat
        set listLoc [$B maketemp arglist]
        $B emit [list extractMaybe $listLoc $nloc]
        my debug-varargs {
            $B log-last
        }
    }


    return $mightThrow

}
 
# quadcode::transformer method va_CheckEnough --
#
#	Emits code to check for too few args passed to invokeExpanded
#
# Parameters:
#	B - Builder that is managing code for this invocation
#	result - Return value from the call
#	cfin - Input call frame to the call
#	cmd - Name of the command being invoked
#	nMandatory - Number of non-defaulted args that must be provided
#
# Results:
#	None.
#
# Side effects:
#	Emits the check, the 'wrong # args' error if needed, and generates
#	the error block if needed

oo::define quadcode::transformer method va_CheckEnough {B result cfin cmd
                                                        nMandatory} {

    error "va_CheckEnough: Not yet reached in testing"

    set compLoc [my newVarInstance {temp @toofew}]
    set lenLoc [$B gettemp arglen]

    # compare args provided to args needed
    $B emit [list gt $compLoc [list literal $nMandatory] $lenLoc]
    my debug-varargs {
        $B log-last
    }

    # jump to errb if wrong
    set errb [$B makeblock]
    $B emit [list jumpTrue [list bb $errb] $compLoc]
    my debug-varargs {
        $B log-last
    }

    # jump to okb if right
    set okb [$B makeblock]
    $B emit [list jump [list bb $okb]]
    my debug-varargs {
        $B log-last
    }

    # make code to emit 'wrong # args' error
    set wrongb [my va_EmitWrongArgs $result $cfin $cmd]

    # jump from errb to code that throws error
    $B buildin $errb
    $B emit [list jump [list bb $wrongb]]
    my debug-varargs {
        $B log-last
    }

    # return to the 'no failure' branch
    $B buildin $okb

}
 
# quadcode::transformer method va_MakeErrorCheck --
#
#	Emits code to jump to an error block if a given value is FAIL.
#
# Parameters:
#	B - Builder that is emitting code

#	val - Value that might be FAIL
#
# Results:
#	None.
#
# Side effects:
#	Emits the necessary jumpMaybe, and adds FAIL value
#	to the phi operation at the head of the error block.

oo::define quadcode::transformer method va_makeErrorCheck {B val} {

    error "va_MakeErrorCheck: Not yet reached in testing"

    # Emit any required error checking when building the variable
    # argument list.
    my va_MakeErrorBlock $B
    set errorb [$B getblock error]
    set intb [$B makeblock]
    set nextb [$B makeblock]

    # Close out the current block with jumpMaybe to an intermediate
    # block and jump to the normal return
    $B emit [list jumpMaybe [list bb $intb] $val]
    my debug-varargs {
................................................................................
    $B emit [list jump [list bb $errorb]]
    my debug-varargs {
        $B log-last
    }

    # Add phis for the error result ant the callframe to the error block
    set errorInPhi [$B get-or-make-temp error]

    $B phi $errorb $errorInPhi $val


    # Now continue building in the normal exit
    $B buildin $nextb
}














































 
# quadcode::transformer method va_UnpackMandatory --
#
#	Unpacks the mandatory args to a proc from the list created
#	by argument expansion
#
# Parameters;
................................................................................
# Side effects:
#	Emits code to unpack the mandatory parameters

oo::define quadcode::transformer method va_UnpackMandatory {tempIdxVar
                                                                bbVar newqVar
                                                                b listLoc
                                                                nMandatory} {
    error "va_UnpackMandatory: Not yet refactored or reached in testing"
    upvar 1 $tempIdxVar tempIdx $bbVar bb $newqVar newq

    for {set i 0} {$i < $nMandatory} {incr i} {

        # Emit the 'listIndex' instruction for one arg. It can't fail
        # because we know we have a list

................................................................................
#	Emits code to unpack one value, or jump to the finish block if
#	there is nothing to unpack.

oo::define quadcode::transformer method va_UnpackOptional {tempIdxVar bVar
                                                               bbVar finishB
                                                               compTemp listLoc
                                                               lenLoc j} {
    error "va_UnpackOptional: Not yet refactored or reached in testing"
    upvar 1 $tempIdxVar tempIndex $bVar b $bbVar bb

    set pos [list literal $j]
    set compLoc [my newVarInstance $compTemp]
    set argTemp [list temp [incr tempIndex]]
    set argLoc1 [my newVarInstance $argTemp]
    set argLoc2 [my newVarInstance $argTemp]
................................................................................
#	outputs of the phi instructions to the 'invoke' instruction
#	under construction.

oo::define quadcode::transformer method va_FinishOptional {bVar bbVar
                                                               newqVar finishB
                                                               optInfo} {

    error "va_FinishOptional: not refactored or tested yet"
    upvar 1 $bVar b $bbVar bb $newqVar newq

    # Finish the current block and start building into 'finishB'

    my va_EmitAndTrack $b bb [list jump [list bb $finishB]]
    lset bbcontent $b $bb
    set bb {}
................................................................................

# quadcode::transformer method va_DoArgs --
#
#	Emits code to extract the parameter sequence needed to fill '$args'
#	from the parameter list.
#
# Parameters:
#	B - Builder that is emitting the code sequence
#	newqVar - Variable in caller's scope containing the quadcode

#	          'invoke' instruction under construction


#	i - Position in the argument list at which 'args' starts.
#
# Results:
#	None.
#
# Side effects:
#	Emits any code necessary to fill in 'args', and adds the resulting
#	variable onto the end of the new instruction.

oo::define quadcode::transformer method va_DoArgs {B newqVar i} {

    upvar 1 $newqVar newq
    set listLoc [$B gettemp arglist]
    my debug-varargs {
        puts "varargs: args will come from positions $i-end in $listLoc"
    }


    # If args is the whole list, just concatenate it onto the invoke
    if {$i == 0} {
        lappend newq $listLoc
    } else {

        set argsLoc1 [$B maketemp \$args]
        $B build [list listRange $argsLoc1 $listLoc \
                      [list literal $i] {literal end}]
        my debug-varargs {
            $B log-last
        }

        set argsLoc2 [B maketemp \$args]
        $B build [list extractMaybe $argsLoc2 $argsLoc1]
        lappend newq $argsLoc2
    }

}
 
# quadcode::transformer method va_CheckTooMany --
#
#	Emits a codeburst to check whether an 'invokeExpanded' has
#	too many args
#
................................................................................
 
# quadcode::transformer method va_EmitWrongArgs --
#
#	Generates code to throw the 'wrong # args' error when needed
#
# Parameters:
#	result - Quadcode value that will hold the command result


#	cfin - Quadcode value that holds the pre-invoke callframe,
#	       or Nothing if no callframe need be produced
#	cmd - Quadcode literal with the name of the command being invoked
#
# Results:
#	None.
#
# Side effects:
#	Returns a codeburst that throws the exception

oo::define quadcode::transformer method va_EmitWrongArgs {result cfin cmd} {


    set burst {}




    set argl [info args [lindex $cmd 1]]
    set left [llength $argl]
    set sbval [list [lindex $cmd 1]]
    foreach a $argl {
        incr left -1
        if {$a eq "args" && $left == 0} {