@@ -131,7 +131,7 @@ bool ps_ast_test_delete_interpreter(ps_interpreter *interpreter, ps_ast_block *b
131131
132132/**
133133 * @brief Test minimal Pascal program
134- * L/C 12345678901234567890
134+ * L/C 123456789012345678901234567890123456789012345678901234567890
135135 * 1 Program Minimal;
136136 * 2 Begin
137137 * 3 End.
@@ -508,6 +508,112 @@ bool ps_ast_test_while_do()
508508 return true;
509509}
510510
511+ /**
512+ * @brief Test Repeat-Until Pascal program
513+ * L/C 123456789012345678901234567890123456789012345678901234567890
514+ * 1 Program RepeatUntil;
515+ * 2 Var I: Integer;
516+ * 3 Begin
517+ * 4 I := 5;
518+ * 5 Repeat
519+ * 6 I := I - 1;
520+ * 7 Until I = 0;
521+ * 8 End.
522+ */
523+ bool ps_ast_test_repeat_until ()
524+ {
525+ bool result ;
526+
527+ ps_ast_block * block_program = ps_ast_test_create_block_program ("REPEATUNTIL" );
528+ ASSERT_RETURN_FALSE (block_program != NULL );
529+
530+ ps_interpreter * interpreter = ps_ast_test_create_interpreter (block_program );
531+ ASSERT_RETURN_FALSE (interpreter != NULL );
532+
533+ ps_ast_debug_line (0 , "Create variable symbol I of type Integer and add it to the symbol tables" );
534+ ps_value value_i = {.allocated = false, .type = & ps_system_integer , .data .i = 0 };
535+ ps_symbol * symbol_i = ps_symbol_alloc (PS_SYMBOL_KIND_VARIABLE , "I" , & value_i );
536+ result = ps_interpreter_add_symbol (interpreter , symbol_i );
537+ ASSERT_RETURN_FALSE (result );
538+ ps_symbol_table_error error = ps_symbol_table_add (block_program -> symbols , symbol_i );
539+ ASSERT_RETURN_FALSE (error == PS_SYMBOL_TABLE_ERROR_NONE );
540+ block_program -> n_vars = 1 ;
541+
542+ ps_ast_debug_line (0 , "Create a statement list with 2 statements (I := 5; Repeat loop)" );
543+ block_program -> statement_list = ps_ast_create_statement_list (4 , 5 , 2 );
544+ ASSERT_RETURN_FALSE (block_program -> statement_list != NULL );
545+
546+ ps_ast_debug_line (0 , "Create the first assignment statement I := 5;" );
547+ ps_ast_variable_simple * variable_i_init = ps_ast_create_variable_simple (4 , 5 , PS_AST_LVALUE_SIMPLE , symbol_i );
548+ ASSERT_RETURN_FALSE (variable_i_init != NULL );
549+ ps_value value_i_5 = {.allocated = false, .type = & ps_system_integer , .data .i = 5 };
550+ ps_ast_value * rvalue_i_5 = ps_ast_create_rvalue_const (4 , 10 , value_i_5 );
551+ ASSERT_RETURN_FALSE (rvalue_i_5 != NULL );
552+ ps_ast_assignment * assignment_i_init =
553+ ps_ast_create_assignment (4 , 5 , (ps_ast_node * )variable_i_init , (ps_ast_node * )rvalue_i_5 );
554+ ASSERT_RETURN_FALSE (assignment_i_init != NULL );
555+ block_program -> statement_list -> statements [0 ] = (ps_ast_node * )assignment_i_init ;
556+
557+ ps_ast_debug_line (0 , "Create the REPEAT loop body: I := I - 1" );
558+ ps_ast_statement_list * repeat_body = ps_ast_create_statement_list (6 , 9 , 1 );
559+ ASSERT_RETURN_FALSE (repeat_body != NULL );
560+ ps_ast_variable_simple * variable_i_body = ps_ast_create_variable_simple (6 , 9 , PS_AST_LVALUE_SIMPLE , symbol_i );
561+ ASSERT_RETURN_FALSE (variable_i_body != NULL );
562+ ps_ast_variable_simple * rvalue_i_body = ps_ast_create_variable_simple (6 , 19 , PS_AST_RVALUE_SIMPLE , symbol_i );
563+ ASSERT_RETURN_FALSE (rvalue_i_body != NULL );
564+ ps_value value_i_1 = {.allocated = false, .type = & ps_system_integer , .data .i = 1 };
565+ ps_ast_value * rvalue_i_1 = ps_ast_create_rvalue_const (6 , 23 , value_i_1 );
566+ ASSERT_RETURN_FALSE (rvalue_i_1 != NULL );
567+ ps_ast_binary_operation * i_minus_1 =
568+ ps_ast_create_binary_operation (6 , 21 , PS_OP_SUB , (ps_ast_node * )rvalue_i_body , (ps_ast_node * )rvalue_i_1 );
569+ ASSERT_RETURN_FALSE (i_minus_1 != NULL );
570+ ps_ast_assignment * assignment_i_body =
571+ ps_ast_create_assignment (6 , 9 , (ps_ast_node * )variable_i_body , (ps_ast_node * )i_minus_1 );
572+ ASSERT_RETURN_FALSE (assignment_i_body != NULL );
573+ repeat_body -> statements [0 ] = (ps_ast_node * )assignment_i_body ;
574+
575+ ps_ast_debug_line (0 , "Create the REPEAT condition I = 0" );
576+ ps_ast_variable_simple * rvalue_i_cond = ps_ast_create_variable_simple (7 , 10 , PS_AST_RVALUE_SIMPLE , symbol_i );
577+ ASSERT_RETURN_FALSE (rvalue_i_cond != NULL );
578+ ps_value value_i_0 = {.allocated = false, .type = & ps_system_integer , .data .i = 0 };
579+ ps_ast_value * rvalue_i_0 = ps_ast_create_rvalue_const (7 , 14 , value_i_0 );
580+ ASSERT_RETURN_FALSE (rvalue_i_0 != NULL );
581+ ps_ast_binary_operation * repeat_condition =
582+ ps_ast_create_binary_operation (7 , 12 , PS_OP_EQ , (ps_ast_node * )rvalue_i_cond , (ps_ast_node * )rvalue_i_0 );
583+ ASSERT_RETURN_FALSE (repeat_condition != NULL );
584+
585+ ps_ast_debug_line (0 , "Create the REPEAT statement" );
586+ ps_ast_repeat * repeat_statement = ps_ast_create_repeat (5 , 5 , repeat_body , (ps_ast_node * )repeat_condition );
587+ ASSERT_RETURN_FALSE (repeat_statement != NULL );
588+ block_program -> statement_list -> statements [1 ] = (ps_ast_node * )repeat_statement ;
589+
590+ ps_ast_debug_line (0 , "Debug print the program" );
591+ ps_ast_debug = true;
592+ ps_ast_debug_line (0 , "================================================================" );
593+ ps_ast_debug_node (0 , (ps_ast_node * )block_program );
594+ ps_ast_debug_line (0 , "================================================================" );
595+
596+ ps_ast_debug_line (0 , "Run the program and check that it returns true" );
597+ result = ps_ast_run_program (interpreter , block_program );
598+ ps_ast_debug_line (0 , "Interpreter error: %s" , ps_error_get_message (interpreter -> error ));
599+ ps_ast_debug_line (0 , "Interpreter message: %s" , interpreter -> message );
600+ ASSERT_RETURN_FALSE (result );
601+
602+ ps_ast_debug_line (0 , "Check that variable I has the expected value 0 (loop condition became true)" );
603+ ASSERT_RETURN_FALSE (symbol_i -> value != NULL );
604+ ASSERT_RETURN_FALSE (symbol_i -> value -> type == & ps_system_integer );
605+ ps_ast_debug_line (0 , "Variable I value: %d" , symbol_i -> value -> data .i );
606+ ASSERT_RETURN_FALSE (symbol_i -> value -> data .i == 0 );
607+
608+ ps_symbol_table_dump (stderr , NULL , block_program -> symbols );
609+
610+ ps_ast_test_delete_interpreter (interpreter , block_program );
611+
612+ ps_ast_test_delete_block_program (block_program );
613+
614+ return true;
615+ }
616+
511617/**
512618 * @brief Test For-Do Pascal program
513619 * L/C 123456789012345678901234567890123456789012345678901234567890
@@ -629,7 +735,7 @@ bool ps_ast_test_for_do()
629735/**
630736 * @brief Test Hello Pascal program
631737 * 0 1 2 3
632- * L/C 123456789012345678901234567890
738+ * L/C 123456789012345678901234567890123456789012345678901234567890
633739 * 1 Program Hello;
634740 * 2 Begin
635741 * 3 WriteLn('Hello, World!');
@@ -718,6 +824,8 @@ bool ps_ast_test()
718824 ps_ast_debug_line (0 , "****************************************************************" );
719825 result &= ps_ast_test_while_do ();
720826 ps_ast_debug_line (0 , "****************************************************************" );
827+ result &= ps_ast_test_repeat_until ();
828+ ps_ast_debug_line (0 , "****************************************************************" );
721829 result &= ps_ast_test_for_do ();
722830 ps_ast_debug_line (0 , "****************************************************************" );
723831 result &= ps_ast_test_hello ();
0 commit comments