Skip to content

Commit caf774b

Browse files
committed
Implement type checking for else-less if
1 parent 80c3be9 commit caf774b

File tree

1 file changed

+66
-35
lines changed

1 file changed

+66
-35
lines changed

porth.py

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,20 @@ def compiler_error_(place: Union[Token, Loc], message: str):
398398
def 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

404412
def 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

Comments
 (0)