@@ -398,11 +398,20 @@ def compiler_error_(place: Union[Token, Loc], message: str):
398398def compiler_note_ (place : Union [Token , Loc ], message : str ):
399399 compiler_diagnostic (place , 'NOTE' , message )
400400
401- def not_enough_arguments_for_intrinsic_ (place : Union [Token , Loc ], intr : Intrinsic ):
402- compiler_error_ (place , "not enough arguments for the `%s` intrinsic" % INTRINSIC_NAMES [intr ])
401+ def not_enough_arguments (op : Op ):
402+ if op .typ == OpType .INTRINSIC :
403+ assert isinstance (op .operand , Intrinsic )
404+ compiler_error_ (op .token , "not enough arguments for the `%s` intrinsic" % INTRINSIC_NAMES [op .operand ])
405+ elif op .typ == OpType .IF :
406+ compiler_error_ (op .token , "not enough arguments for the if-block" )
407+ else :
408+ assert False , "unsupported type of operation"
409+
410+ DataStack = List [Tuple [DataType , Token ]]
403411
404412def type_check_program (program : Program ):
405- stack : List [Tuple [DataType , Token ]] = []
413+ stack : DataStack = []
414+ block_stack : List [Tuple [DataStack , OpType ]] = []
406415 for ip in range (len (program )):
407416 op = program [ip ]
408417 assert len (OpType ) == 8 , "Exhaustive ops handling in type_check_program()"
@@ -417,7 +426,7 @@ def type_check_program(program: Program):
417426 if op .operand == Intrinsic .PLUS :
418427 assert len (DataType ) == 3 , "Exhaustive type handling in PLUS intrinsic"
419428 if len (stack ) < 2 :
420- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
429+ not_enough_arguments (op )
421430 exit (1 )
422431 a_type , a_loc = stack .pop ()
423432 b_type , b_loc = stack .pop ()
@@ -434,7 +443,7 @@ def type_check_program(program: Program):
434443 elif op .operand == Intrinsic .MINUS :
435444 assert len (DataType ) == 3 , "Exhaustive type handling in MINUS intrinsic"
436445 if len (stack ) < 2 :
437- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
446+ not_enough_arguments (op )
438447 exit (1 )
439448 a_type , a_loc = stack .pop ()
440449 b_type , b_loc = stack .pop ()
@@ -447,7 +456,7 @@ def type_check_program(program: Program):
447456 elif op .operand == Intrinsic .MUL :
448457 assert len (DataType ) == 3 , "Exhaustive type handling in MUL intrinsic"
449458 if len (stack ) < 2 :
450- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
459+ not_enough_arguments (op )
451460 exit (1 )
452461 a_type , a_loc = stack .pop ()
453462 b_type , b_loc = stack .pop ()
@@ -460,7 +469,7 @@ def type_check_program(program: Program):
460469 elif op .operand == Intrinsic .DIVMOD :
461470 assert len (DataType ) == 3 , "Exhaustive type handling in DIVMOD intrinsic"
462471 if len (stack ) < 2 :
463- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
472+ not_enough_arguments (op )
464473 exit (1 )
465474 a_type , a_loc = stack .pop ()
466475 b_type , b_loc = stack .pop ()
@@ -474,7 +483,7 @@ def type_check_program(program: Program):
474483 elif op .operand == Intrinsic .EQ :
475484 assert len (DataType ) == 3 , "Exhaustive type handling in EQ intrinsic"
476485 if len (stack ) < 2 :
477- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
486+ not_enough_arguments (op )
478487 exit (1 )
479488 a_type , a_loc = stack .pop ()
480489 b_type , b_loc = stack .pop ()
@@ -487,7 +496,7 @@ def type_check_program(program: Program):
487496 elif op .operand == Intrinsic .GT :
488497 assert len (DataType ) == 3 , "Exhaustive type handling in GT intrinsic"
489498 if len (stack ) < 2 :
490- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
499+ not_enough_arguments (op )
491500 exit (1 )
492501
493502 a_type , a_loc = stack .pop ()
@@ -501,7 +510,7 @@ def type_check_program(program: Program):
501510 elif op .operand == Intrinsic .LT :
502511 assert len (DataType ) == 3 , "Exhaustive type handling in LT intrinsic"
503512 if len (stack ) < 2 :
504- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
513+ not_enough_arguments (op )
505514 exit (1 )
506515
507516 a_type , a_loc = stack .pop ()
@@ -515,7 +524,7 @@ def type_check_program(program: Program):
515524 elif op .operand == Intrinsic .GE :
516525 assert len (DataType ) == 3 , "Exhaustive type handling in GE intrinsic"
517526 if len (stack ) < 2 :
518- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
527+ not_enough_arguments (op )
519528 exit (1 )
520529
521530 a_type , a_loc = stack .pop ()
@@ -529,7 +538,7 @@ def type_check_program(program: Program):
529538 elif op .operand == Intrinsic .LE :
530539 assert len (DataType ) == 3 , "Exhaustive type handling in LE intrinsic"
531540 if len (stack ) < 2 :
532- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
541+ not_enough_arguments (op )
533542 exit (1 )
534543
535544 a_type , a_loc = stack .pop ()
@@ -543,7 +552,7 @@ def type_check_program(program: Program):
543552 elif op .operand == Intrinsic .NE :
544553 assert len (DataType ) == 3 , "Exhaustive type handling in NE intrinsic"
545554 if len (stack ) < 2 :
546- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
555+ not_enough_arguments (op )
547556 exit (1 )
548557
549558 a_type , a_loc = stack .pop ()
@@ -557,7 +566,7 @@ def type_check_program(program: Program):
557566 elif op .operand == Intrinsic .SHR :
558567 assert len (DataType ) == 3 , "Exhaustive type handling in SHR intrinsic"
559568 if len (stack ) < 2 :
560- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
569+ not_enough_arguments (op )
561570 exit (1 )
562571
563572 a_type , a_loc = stack .pop ()
@@ -571,7 +580,7 @@ def type_check_program(program: Program):
571580 elif op .operand == Intrinsic .SHL :
572581 assert len (DataType ) == 3 , "Exhaustive type handling in SHL intrinsic"
573582 if len (stack ) < 2 :
574- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
583+ not_enough_arguments (op )
575584 exit (1 )
576585
577586 a_type , a_loc = stack .pop ()
@@ -585,7 +594,7 @@ def type_check_program(program: Program):
585594 elif op .operand == Intrinsic .BOR :
586595 assert len (DataType ) == 3 , "Exhaustive type handling in BOR intrinsic"
587596 if len (stack ) < 2 :
588- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
597+ not_enough_arguments (op )
589598 exit (1 )
590599
591600 a_type , a_loc = stack .pop ()
@@ -599,7 +608,7 @@ def type_check_program(program: Program):
599608 elif op .operand == Intrinsic .BAND :
600609 assert len (DataType ) == 3 , "Exhaustive type handling in BAND intrinsic"
601610 if len (stack ) < 2 :
602- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
611+ not_enough_arguments (op )
603612 exit (1 )
604613
605614 a_type , a_loc = stack .pop ()
@@ -612,32 +621,32 @@ def type_check_program(program: Program):
612621 exit (1 )
613622 elif op .operand == Intrinsic .PRINT :
614623 if len (stack ) < 1 :
615- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
624+ not_enough_arguments (op )
616625 exit (1 )
617626 stack .pop ()
618627 elif op .operand == Intrinsic .DUP :
619628 if len (stack ) < 1 :
620- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
629+ not_enough_arguments (op )
621630 exit (1 )
622631 a = stack .pop ()
623632 stack .append (a )
624633 stack .append (a )
625634 elif op .operand == Intrinsic .SWAP :
626635 if len (stack ) < 2 :
627- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
636+ not_enough_arguments (op )
628637 exit (1 )
629638 a = stack .pop ()
630639 b = stack .pop ()
631640 stack .append (a )
632641 stack .append (b )
633642 elif op .operand == Intrinsic .DROP :
634643 if len (stack ) < 1 :
635- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
644+ not_enough_arguments (op )
636645 exit (1 )
637646 stack .pop ()
638647 elif op .operand == Intrinsic .OVER :
639648 if len (stack ) < 2 :
640- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
649+ not_enough_arguments (op )
641650 exit (1 )
642651 a = stack .pop ()
643652 b = stack .pop ()
@@ -649,7 +658,7 @@ def type_check_program(program: Program):
649658 elif op .operand == Intrinsic .LOAD :
650659 assert len (DataType ) == 3 , "Exhaustive type handling in LOAD intrinsic"
651660 if len (stack ) < 1 :
652- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
661+ not_enough_arguments (op )
653662 exit (1 )
654663 a_type , a_loc = stack .pop ()
655664
@@ -661,7 +670,7 @@ def type_check_program(program: Program):
661670 elif op .operand == Intrinsic .STORE :
662671 assert len (DataType ) == 3 , "Exhaustive type handling in STORE intrinsic"
663672 if len (stack ) < 2 :
664- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
673+ not_enough_arguments (op )
665674 exit (1 )
666675
667676 a_type , a_loc = stack .pop ()
@@ -675,7 +684,7 @@ def type_check_program(program: Program):
675684 elif op .operand == Intrinsic .LOAD64 :
676685 assert len (DataType ) == 3 , "Exhaustive type handling in LOAD64 intrinsic"
677686 if len (stack ) < 1 :
678- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
687+ not_enough_arguments (op )
679688 exit (1 )
680689 a_type , a_loc = stack .pop ()
681690
@@ -687,7 +696,7 @@ def type_check_program(program: Program):
687696 elif op .operand == Intrinsic .STORE64 :
688697 assert len (DataType ) == 3 , "Exhaustive type handling in STORE64 intrinsic"
689698 if len (stack ) < 2 :
690- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
699+ not_enough_arguments (op )
691700 exit (1 )
692701
693702 a_type , a_loc = stack .pop ()
@@ -705,59 +714,81 @@ def type_check_program(program: Program):
705714 # TODO: figure out how to type check syscall arguments and return types
706715 elif op .operand == Intrinsic .SYSCALL0 :
707716 if len (stack ) < 1 :
708- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
717+ not_enough_arguments (op )
709718 exit (1 )
710719 for i in range (1 ):
711720 stack .pop ()
712721 stack .append ((DataType .INT , op .token ))
713722 elif op .operand == Intrinsic .SYSCALL1 :
714723 if len (stack ) < 2 :
715- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
724+ not_enough_arguments (op )
716725 exit (1 )
717726 for i in range (2 ):
718727 stack .pop ()
719728 stack .append ((DataType .INT , op .token ))
720729 elif op .operand == Intrinsic .SYSCALL2 :
721730 if len (stack ) < 3 :
722- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
731+ not_enough_arguments (op )
723732 exit (1 )
724733 for i in range (3 ):
725734 stack .pop ()
726735 stack .append ((DataType .INT , op .token ))
727736 elif op .operand == Intrinsic .SYSCALL3 :
728737 if len (stack ) < 4 :
729- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
738+ not_enough_arguments (op )
730739 exit (1 )
731740 for i in range (4 ):
732741 stack .pop ()
733742 stack .append ((DataType .INT , op .token ))
734743 elif op .operand == Intrinsic .SYSCALL4 :
735744 if len (stack ) < 5 :
736- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
745+ not_enough_arguments (op )
737746 exit (1 )
738747 for i in range (5 ):
739748 stack .pop ()
740749 stack .append ((DataType .INT , op .token ))
741750 elif op .operand == Intrinsic .SYSCALL5 :
742751 if len (stack ) < 6 :
743- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
752+ not_enough_arguments (op )
744753 exit (1 )
745754 for i in range (6 ):
746755 stack .pop ()
747756 stack .append ((DataType .INT , op .token ))
748757 elif op .operand == Intrinsic .SYSCALL6 :
749758 if len (stack ) < 7 :
750- not_enough_arguments_for_intrinsic_ (op . token , op . operand )
759+ not_enough_arguments (op )
751760 exit (1 )
752761 for i in range (7 ):
753762 stack .pop ()
754763 stack .append ((DataType .INT , op .token ))
755764 else :
756765 assert False , "unreachable"
757766 elif op .typ == OpType .IF :
758- assert False , "not implemented"
767+ if len (stack ) < 1 :
768+ not_enough_arguments (op )
769+ exit (1 )
770+ a_type , a_token = stack .pop ()
771+ if a_type != DataType .BOOL :
772+ compiler_error_ (op .token , "Invalid argument for the if-block condition. Expected BOOL." )
773+ exit (1 )
774+ block_stack .append ((copy (stack ), op .typ ))
759775 elif op .typ == OpType .END :
760- assert False , "not implemented"
776+ expected_stack , block_type = block_stack .pop ()
777+ assert len (OpType ) == 8 , "Exhaustive handling of op types"
778+ if block_type == OpType .IF :
779+ expected_types = list (map (lambda x : x [0 ], expected_stack ))
780+ actual_types = list (map (lambda x : x [0 ], stack ))
781+ if expected_types != actual_types :
782+ compiler_error_ (op .token , 'else-less if block is not allowed to alter the types of the arguments on the data stack' )
783+ compiler_note_ (op .token , 'Expected types: %s' % expected_types )
784+ compiler_note_ (op .token , 'Actual types: %s' % actual_types )
785+ exit (1 )
786+ elif block_type == OpType .ELSE :
787+ assert False , "not implemented"
788+ elif block_type == OpType .DO :
789+ assert False , "not implemented"
790+ else :
791+ assert "unreachable"
761792 elif op .typ == OpType .ELSE :
762793 assert False , "not implemented"
763794 elif op .typ == OpType .WHILE :
0 commit comments