tclquadcode

Check-in [89030dcc42]
Login

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

Overview
Comment:Enough partial implementation for expandtest::test1-test3
Timelines: family | ancestors | descendants | both | notworking | kbk-refactor-callframe
Files: files | file ages | folders
SHA3-256:89030dcc42c7523a6bc13f9e09d66bd66ceee9ea14809733ec05185d53bb0766
User & Date: kbk 2019-01-21 22:33:03
Context
2019-01-22
02:35
Bug fixes to make all the 'expandtest' cases work check-in: 4f7b3a4d01 user: kbk tags: notworking, kbk-refactor-callframe
2019-01-21
22:33
Enough partial implementation for expandtest::test1-test3 check-in: 89030dcc42 user: kbk tags: notworking, kbk-refactor-callframe
19:45
Fix mislinking of phi operations on the error branch of 'invoke' check-in: 407e1ef055 user: kbk tags: notworking, kbk-refactor-callframe
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to quadcode/varargs.tcl.

191
192
193
194
195
196
197














































198
199
200
201
202
203
204
...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329

330

331





332
333
334
335
336
337
338


339
340
341
342
343
344
345
...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
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
728
729
730
731
732
733
734
735


736
737
738
739
740
741
742
743
744
745

746
747
748
749
750
751




752
753
754
755
756
757
758
759


760
761

762
763
764


765

766
767
768


769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
...
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
...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016

1017
1018
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
1052
1053
1054
1055
1056
    if {[lindex $cmd 0] ne "literal"
        || [catch {info args [lindex $cmd 1]} arginfo]} {
        return {0 {}}
    } else {
        return [list 1 $arginfo]
    }
}














































 
# quadcode::transformer method va_PrepareArgs --
#
#	Emits code to prepare the arguments for an 'invoke' or
#	'invokeExpanded' command, up to the point where the actual
#	'invoke' is issued.
#
................................................................................
    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 {}
        set i $firstOptional

        while {$i < $nPlainParams} {

            info default $callee [lindex $arginfo $i] defaultVal





            lassign [my va_UnpackOptional tempIndex b bb \
                         $finishB $compTemp $listLoc $lenLoc $j] \
                fromBlock argLoc
            lappend optInfo [list $fromBlock $defaultVal $argLoc]
            incr i
            incr j
        }



        # Close out the last basic block, switch to the 'finish' block
        # and emit 'phi' instructions to get the correct parameter set
        my va_FinishOptional b bb newq $finishB $optInfo

    }

................................................................................
    } else {
        error  "NOT DONE - varargs needs to check for excess args"
        my va_CheckTooMany b bb $lenLoc $compTemp $j $notokb
    }

    return $newq
}
 
# quadcode::transformer method va_UnlinkTail --
#
#	Removes the invocation sequence from a basic block in preparation
#	for rewriting it.
#
# Parameters:
#	b - Number of the basic block
#	pc - Program counter of the first instruction being deleted
#
# Results:
#	Returns the partial basic block that remains.
#
# Side effects:
#	Variable defs and uses in the invocation sequence are removed
#	from ud- and du-chains. The basic block is unlinked from its
#	successors. 

oo::define quadcode::transformer method va_UnlinkTail {b pc} {

    set bb [lindex $bbcontent $b]
    lset bbcontent $b {}
    my debug-varargs {
        puts "varargs: Split basic block $b:"
        puts "   $b:$pc: [lindex $bb $pc]"
    }

    set tail [lrange $bb $pc end]
    set bb [lreplace $bb[set bb {}] $pc end]
    lset bbcontent $b $bb
    foreach q $tail {
        if {[lindex $q 1 0] in {"temp" "var"}} {
            dict unset udchain [lindex $q 1]
        }
        foreach arg [lrange $q 2 end] {
            if {[lindex $arg 0] in {"temp" "var"}} {
                my removeUse $arg $b
            }
        }
    }
    foreach b2 [my bbsucc $b] {
        my removePred $b2 $b
    }

    return [lreplace $tail[set tail {}] 0 0]
}
 
# quadcode::transformer method va_NonExpandedArgument --
#
#	Transfer a leading non-expanded argument into a quad
#	under construction when rewriting 'invokeExpanded'
#
# Parameters:
................................................................................
            $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} {

    # 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 log-last
    }
    $B emit [list jump [list bb $nextb]]
    my debug-varargs {
        $B log-last
    }

    # Make an intermediate block that jumps to the error block
    $B buildin $intb
    $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 gettemp error]
    $B updatephi $errorb $errorInPhi $val

    # Now continue building in the normal exit
    $B buildin $nextb
}
 
# quadcode::transformer method va_MakeErrorBlock --
#
#	Makes the block to which all the error paths in an invocation
#	sequence jump.
#
# Parameters:
#	B - Builder that is emitting code
#
# Results:
#	Returns the number of the block.
#
# Side effects:
#	Creates the block, and adds a vacuous 'phi' operation to it that
#	will hold the FAIL value from the error. The block and the result
#	of the 'phi' are both named 'error' in the builder.

oo::define quadcode::transformer method va_MakeErrorBlock {B} {

    my debug-varargs {
        puts "varargs: Create a block for error exits."
    }
    set currentb [$B curblock]
    set errorb [$B makeblock error]

    $B buildin $errorb
    set errortemp [$B maketemp error]
    $B emit [list phi $errortemp]
    my debug-varargs {
        $B log-last
    }

    $B buildin $currentb
    return
}
 
# quadcode::transformer method va_UnpackMandatory --
#
#	Unpacks the mandatory args to a proc from the list created
#	by argument expansion
#
# Parameters;
#	tempIdxVar - Variable in caller's scope containing the last
#	             allocated temporary
#	bbVar - Variable in caller's scope containing basic block content
#	newqVar - Variable in caller's scope containing the new 'invoke'
#	          quad being constructed.
#	b - Basic block number under construction
#	listLoc - Variable or temp holding the list being unpacked


#	nMandatory - Number of parameters to unpack
#
# Results:
#	None.
#
# 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

        set argTemp [list temp [incr tempIdx]]
        set argLoc [my newVarInstance $argTemp]
        my va_EmitAndTrack $b bb \
            [list listIndex $argLoc $listLoc [list literal $i]]



        # Emit the 'extractMaybe' to get the arg from the Maybe

        # result of 'listIndex'
        set argLoc2 [my newVarInstance $argTemp]
        my va_EmitAndTrack $b bb [list extractMaybe $argLoc2 $argLoc]




        # Put the extracted arg on the 'invoke' instruction
        lappend newq $argLoc2
    }


}
 
# quadcode::transformer method va_UnpackOptional --
#
#	Emits code to unpack one optional parameter in an invokeExpanded
#
# Parameters:
#	tempIdxVar - Variable holding the index of the last used temporary
#	bVar - Variable holding the current basic block number
#	bbVar - Variable holding the content of the basic block under
#	        construction
#	finishB - Basic block number of the finishing block
#	compTemp - Temporary to use for list comparisons
#	listLoc - Location where the arg list is found
#	lenLoc - Location where the list length is found
#	j - Index in the arg list of the current parameter
#
# Results:
#	Returns a two-element list giving the block number that jumps
#	to the finish if the parameter is not supplied and the
#	location of a temporary holding the unpacked value if it is.
#
# Side effects:
................................................................................
#	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]
................................................................................
    }

    # 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
#
................................................................................
    lset bbcontent $b $bb

    set b $newb
    set bb {}

}
 
# 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} {
            append sbval " ?arg ...?"
        } elseif {[info default [lindex $cmd 1] $a -]} {
            lappend sbval ?$a?
        } else {
            lappend sbval $a
        }
    }

    set msgval "wrong # args: should be \"$sbval\""
    set intres [my newVarInstance $result]


    set q [list initException $intres [list literal $msgval] \
               {literal {-errorcode {TCL WRONGARGS}}} \
               {literal 1} \
               {literal 0}]
    lappend burst $q





    set q [list extractFail $result $intres]
    lappend burst $q












    return $burst



























































































}
 
# oo::transformer method va_ConvergeErrorPath --
#
#	Converges the code for the error and normal paths after an 'invoke'.
#
# Parameters:







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







 







|


|







<
<


<
<
<
<

>

>

>
>
>
>
>
|
<
|




>
>







 







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







 








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






<
<
<
<
<
<
<
>
>



|




|
<
>
|
<
<
<


>
>
>
>




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

|

>
>







|
|
|
<
<
<
<
<
<







 







<







 







|





|
|



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







 







|




|
|
<
<


<
>


<
>
>

|

>
|
>
|
>
>
>
|

|




|







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







191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366


367
368




369
370
371
372
373
374
375
376
377
378
379

380
381
382
383
384
385
386
387
388
389
390
391
392
393
...
398
399
400
401
402
403
404














































405
406
407
408
409
410
411
...
571
572
573
574
575
576
577
578


















































































































































579
580
581
582
583
584







585
586
587
588
589
590
591
592
593
594
595

596
597



598
599
600
601
602
603
604
605
606
607
608


609
610
611
612

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
...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
...
896
897
898
899
900
901
902
903
904
905
906
907
908
909


910
911

912
913
914

915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
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
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
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
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
    if {[lindex $cmd 0] ne "literal"
        || [catch {info args [lindex $cmd 1]} arginfo]} {
        return {0 {}}
    } else {
        return [list 1 $arginfo]
    }
}
 
# quadcode::transformer method va_UnlinkTail --
#
#	Removes the invocation sequence from a basic block in preparation
#	for rewriting it.
#
# Parameters:
#	b - Number of the basic block
#	pc - Program counter of the first instruction being deleted
#
# Results:
#	Returns the partial basic block that remains.
#
# Side effects:
#	Variable defs and uses in the invocation sequence are removed
#	from ud- and du-chains. The basic block is unlinked from its
#	successors. 

oo::define quadcode::transformer method va_UnlinkTail {b pc} {

    set bb [lindex $bbcontent $b]
    lset bbcontent $b {}
    my debug-varargs {
        puts "varargs: Split basic block $b:"
        puts "   $b:$pc: [lindex $bb $pc]"
    }

    set tail [lrange $bb $pc end]
    set bb [lreplace $bb[set bb {}] $pc end]
    lset bbcontent $b $bb
    foreach q $tail {
        if {[lindex $q 1 0] in {"temp" "var"}} {
            dict unset udchain [lindex $q 1]
        }
        foreach arg [lrange $q 2 end] {
            if {[lindex $arg 0] in {"temp" "var"}} {
                my removeUse $arg $b
            }
         }
    }
    foreach b2 [my bbsucc $b] {
        my removePred $b2 $b
    }

    return [lreplace $tail[set tail {}] 0 0]
}
 
# quadcode::transformer method va_PrepareArgs --
#
#	Emits code to prepare the arguments for an 'invoke' or
#	'invokeExpanded' command, up to the point where the actual
#	'invoke' is issued.
#
................................................................................
    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 $callee $nMandatory

        # Make code to transfer mandatory args
        set newq [my va_UnpackMandatory $B $newq $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 i $firstOptional

        while {$i < $nPlainParams} {
        
            info default $callee [lindex $arginfo $i] defaultVal

            my debug-varargs {
                puts "Emit length check and extraction for optional param \
                      $i: [lindex $arginfo $i] (default=$defaultVal)"
            }
            lassign [my va_UnpackOptional $B $newq $j] \

                newq fromBlock argLoc
            lappend optInfo [list $fromBlock $defaultVal $argLoc]
            incr i
            incr j
        }

        error "NOT FINISHED - Close out the optional params."

        # Close out the last basic block, switch to the 'finish' block
        # and emit 'phi' instructions to get the correct parameter set
        my va_FinishOptional b bb newq $finishB $optInfo

    }

................................................................................
    } else {
        error  "NOT DONE - varargs needs to check for excess args"
        my va_CheckTooMany b bb $lenLoc $compTemp $j $notokb
    }

    return $newq
}














































 
# quadcode::transformer method va_NonExpandedArgument --
#
#	Transfer a leading non-expanded argument into a quad
#	under construction when rewriting 'invokeExpanded'
#
# Parameters:
................................................................................
            $B log-last
        }
    }

    return $mightThrow

}
 


















































































































































# quadcode::transformer method va_UnpackMandatory --
#
#	Unpacks the mandatory args to a proc from the list created
#	by argument expansion
#
# Parameters;







#	B - Builder that is emitting quadcode
#	newq - 'invoke' instruction under construction
#	nMandatory - Number of parameters to unpack
#
# Results:
#	Returns the 'invoke' instruction with the mandatory parameters added.
#
# Side effects:
#	Emits code to unpack the mandatory parameters

oo::define quadcode::transformer method va_UnpackMandatory {B newq nMandatory} {


    set arglist [$B gettemp arglist]




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

        my debug-varargs {
            puts "varargs: transfer mandatory argument $i"
        }

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

        set argtemp [$B maketemp arg$i]


        $B emit [list listIndex $argtemp $arglist [list literal $i]]
        my debug-varargs {
            $B log-last
        }


        set argloc [$B maketemp arg$i]

        $B emit [list extractMaybe $argloc $argtemp]
        my debug-varargs {
            $B log-last
        }

        # Put the extracted arg on the 'invoke' instruction
        lappend newq $argloc
    }

    return $newq
}
 
# quadcode::transformer method va_UnpackOptional --
#
#	Emits code to unpack one optional parameter in an invokeExpanded
#
# Parameters:
#	B - Builder that is emitting the invocation sequence
#	newq - 'invoke' instruction under construction
#	j - Position of the parameter being unpacked






#
# Results:
#	Returns a two-element list giving the block number that jumps
#	to the finish if the parameter is not supplied and the
#	location of a temporary holding the unpacked value if it is.
#
# Side effects:
................................................................................
#	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]
................................................................................
    }

    # 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 emit [list listRange $argsLoc1 $listLoc \
                      [list literal $i] {literal end}]
        my debug-varargs {
            $B log-last
        }

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

}
 
# 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
#	callee - Name of the invoked command
#	minLength - Minumum length of the arglist
#
# Results:
#	None.
#
# Side effects:
#	Emits the check, the 'wrong # args' error if needed, and generates
#	the error block if needed
#
# The assumption is made that the 'arglen' temporary in $B has the
# length of the 

oo::define quadcode::transformer method va_CheckEnough {B callee minLength} {

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

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

    # jump to a 'wrong # args' error if wrong
    set errb [my va_MakeWrongArgs $B $callee]
    $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
    }

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

}
 
# quadcode::transformer method va_CheckTooMany --
#
#	Emits a codeburst to check whether an 'invokeExpanded' has
#	too many args
#
................................................................................
    lset bbcontent $b $bb

    set b $newb
    set bb {}

}
 
# quadcode::transformer method va_MakeWrongArgs --
#
#	Generates code to throw the 'wrong # args' error when needed
#
# Parameters:
#	B - Builder that is generating quadcode
#	callee - Name of the called procedure


#
# Results:

#	Returns the basic block number of the generated block
#
# Side effects:

#	Generates a block that creates an exception and jumps to the
#	error handler.

oo::define quadcode::transformer method va_MakeWrongArgs {B callee} {

    set wrongb [$B getblock "wrongargs"]
    if {$wrongb >= 0} {
        return $wrongb
    }
    set wrongb [$B makeblock "wrongargs"]
    set currentb [$B curblock]

    set argl [info args $callee]
    set left [llength $argl]
    set sbval [list $callee]
    foreach a $argl {
        incr left -1
        if {$a eq "args" && $left == 0} {
            append sbval " ?arg ...?"
        } elseif {[info default $callee $a -]} {
            lappend sbval ?$a?
        } else {
            lappend sbval $a
        }
    }

    set msgval "wrong # args: should be \"$sbval\""
    set intres [$B maketemp wrongargs]

    $B buildin $wrongb
    $B emit [list initException $intres [list literal $msgval] \
                 {literal {-errorcode {TCL WRONGARGS}}} \
                 {literal 1} \
                 {literal 0}]

    my debug-varargs {
        $B log-last
    }
    
    set excloc [$B maketemp wrongargs]
    $B emit [list extractFail $excloc $intres]

    my debug-varargs {
        $B log-last
    }

    set errorb [my va_MakeErrorBlock $B]
    $B emit [list jump [list bb $errorb]]

    # Add phis for the error result ant the callframe to the error block
    set errorInPhi [$B gettemp error]
    $B updatephi $errorb $errorInPhi $excloc
    
    $B buildin $currentb
    return $wrongb
    
}
 
# 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} {

    # 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 log-last
    }
    $B emit [list jump [list bb $nextb]]
    my debug-varargs {
        $B log-last
    }

    # Make an intermediate block that jumps to the error block
    $B buildin $intb
    $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 gettemp error]
    $B updatephi $errorb $errorInPhi $val

    # Now continue building in the normal exit
    $B buildin $nextb
}
 
# quadcode::transformer method va_MakeErrorBlock --
#
#	Makes the block to which all the error paths in an invocation
#	sequence jump.
#
# Parameters:
#	B - Builder that is emitting code
#
# Results:
#	Returns the number of the block.
#
# Side effects:
#	Creates the block, and adds a vacuous 'phi' operation to it that
#	will hold the FAIL value from the error. The block and the result
#	of the 'phi' are both named 'error' in the builder.

oo::define quadcode::transformer method va_MakeErrorBlock {B} {

    my debug-varargs {
        puts "varargs: Create a block for error exits."
    }
    set errorb [$B getblock error]
    if {$errorb >= 0} {
        return $errorb
    }
    
    set currentb [$B curblock]
    set errorb [$B makeblock error]

    $B buildin $errorb
    set errortemp [$B maketemp error]
    $B emit [list phi $errortemp]
    my debug-varargs {
        $B log-last
    }

    $B buildin $currentb
    return
}
 
# oo::transformer method va_ConvergeErrorPath --
#
#	Converges the code for the error and normal paths after an 'invoke'.
#
# Parameters: