#!./perl -w # Verify that all files generated by perl scripts are up to date. BEGIN { if (-f "./TestInit.pm") { push @INC, "."; } elsif (-f '../TestInit.pm') { push @INC, ".."; } } use TestInit qw(T A); # T is chdir to the top level, A makes paths absolute use strict; # this tests the functions in HeaderParser.pm which we use for make regen. require './t/test.pl'; require './regen/HeaderParser.pm'; skip_all_if_miniperl("needs Data::Dumper"); require Data::Dumper; sub show_text { my ($as_text)= @_; print STDERR $as_text=~s/^/" " x 8/mger; } my $hp= HeaderParser->new(); $hp->parse_text(<<~'EOF'); #ifdef A #ifdef B #define AB content 1 #endif content 2 #define A #endif /*comment line */ #define C /* this is a hidden line continuation */ D EOF my $normal= $hp->lines_as_str(); my $lines= $hp->lines(); my $lines_as_str= Data::Dumper->new([$lines])->Sortkeys(1)->Useqq(1)->Indent(1)->Dump(); is($lines_as_str,<<~'DUMP_EOF', "Simple data structure as expected") or show_text($lines_as_str); $VAR1 = [ bless( { "cond" => [ [ "defined(A)" ] ], "flat" => "#if defined(A)", "level" => 0, "line" => "#if defined(A)\n", "n_lines" => 1, "raw" => "#ifdef A\n", "source" => "(buffer)", "start_line_num" => 1, "sub_type" => "#if", "type" => "cond" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ], [ "defined(B)" ] ], "flat" => "#if defined(B)", "level" => 1, "line" => "# if defined(B)\n", "n_lines" => 1, "raw" => "#ifdef B\n", "source" => "(buffer)", "start_line_num" => 2, "sub_type" => "#if", "type" => "cond" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ], [ "defined(B)" ] ], "flat" => "#define AB", "level" => 2, "line" => "# define AB\n", "n_lines" => 1, "raw" => "#define AB\n", "source" => "(buffer)", "start_line_num" => 3, "sub_type" => "#define", "type" => "content" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ], [ "defined(B)" ] ], "flat" => "content 1", "level" => 2, "line" => "content 1\n", "n_lines" => 1, "raw" => "content 1\n", "source" => "(buffer)", "start_line_num" => 4, "sub_type" => "text", "type" => "content" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ], [ "defined(B)" ] ], "flat" => "#endif", "inner_lines" => 3, "level" => 1, "line" => "# endif\n", "n_lines" => 1, "raw" => "#endif\n", "source" => "(buffer)", "start_line_num" => 5, "sub_type" => "#endif", "type" => "cond" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ] ], "flat" => "content 2", "level" => 1, "line" => "content 2\n", "n_lines" => 1, "raw" => "content 2\n", "source" => "(buffer)", "start_line_num" => 6, "sub_type" => "text", "type" => "content" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ] ], "flat" => "#define A", "level" => 1, "line" => "# define A\n", "n_lines" => 1, "raw" => "#define A\n", "source" => "(buffer)", "start_line_num" => 7, "sub_type" => "#define", "type" => "content" }, 'HeaderLine' ), bless( { "cond" => [ [ "defined(A)" ] ], "flat" => "#endif", "inner_lines" => 7, "level" => 0, "line" => "#endif\n", "n_lines" => 1, "raw" => "#endif\n", "source" => "(buffer)", "start_line_num" => 8, "sub_type" => "#endif", "type" => "cond" }, 'HeaderLine' ), bless( { "cond" => [], "flat" => "", "level" => 0, "line" => "/*comment\n line */\n", "n_lines" => 2, "raw" => "/*comment\n line */\n", "source" => "(buffer)", "start_line_num" => 9, "sub_type" => "text", "type" => "content" }, 'HeaderLine' ), bless( { "cond" => [], "flat" => "#define C D", "level" => 0, "line" => "#define C /* this is\n a hidden line continuation */ D\n", "n_lines" => 2, "raw" => "#define C /* this is\n a hidden line continuation */ D\n", "source" => "(buffer)", "start_line_num" => 11, "sub_type" => "#define", "type" => "content" }, 'HeaderLine' ) ]; DUMP_EOF is($normal,<<~'EOF',"Normalized text as expected"); #if defined(A) # if defined(B) # define AB content 1 # endif content 2 # define A #endif /*comment line */ #define C /* this is a hidden line continuation */ D EOF { my @warn; local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] }; my $ok= eval { HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1 #ifdef A #ifdef B #endif EOF }; my $err= !$ok ? $@ : ""; ok(!$ok,"Should throw an error"); like($err,qr/Unterminated conditional block starting line 1 with last conditional operation at line 3/, "Got expected error message"); } { my @warn; local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] }; my $ok= eval { HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1 #ifdef A #ifdef B #elif C EOF }; my $err= !$ok ? $@ : ""; ok(!$ok,"Should throw an error"); like($err,qr/Unterminated conditional block starting line 3/, "Unterminated block detected"); } { my @warn; local $SIG{__WARN__}= sub { push @warn, $_[0]; warn $_[0] }; my $ok= eval { HeaderParser->new(add_commented_expr_after=>0)->parse_text(<<~'EOF'); 1 #if 1 * * 10 > 5 #elifdef C EOF }; my $err= !$ok ? $@ : ""; ok(!$ok,"Should throw an error"); is($err, "Error at line 1\n" . "Line 1: #if 1 * * 10 > 5\n" . "Error in multiplication expression: " . "Unexpected token '*', expecting literal, unary, or expression.\n", "Expected token error") or warn $err; } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #ifdef A # ifdef B # define P # else # define Q # endif # if !defined B # define R # else # define S # endif #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"inverted simple clauses get merged properly") or show_text($as_text); #if defined(A) # if defined(B) # define P # define S # else /* if !defined(B) */ # define Q # define R # endif /* !defined(B) */ #endif /* defined(A) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) && defined(B) # if (defined(C) && defined(D)) # define P # else # define Q # endif # if !(defined C && defined D) # define R # else # define S # endif #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"inverted complex clauses get merged properly") or show_text($as_text); #if defined(A) && defined(B) # if defined(C) && defined(D) # define P # define S # else /* if !( defined(C) && defined(D) ) */ # define Q # define R # endif /* !( defined(C) && defined(D) ) */ #endif /* defined(A) && defined(B) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) #define HAS_A #elif defined(B) #define HAS_B #elif defined(C) #define HAS_C #else #define HAS_D #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"test nested elif round trip") or show_text($as_text); #if defined(A) # define HAS_A #elif defined(B) /* && !defined(A) */ # define HAS_B #elif defined(C) /* && !defined(A) && !defined(B) */ # define HAS_C #else /* if !defined(A) && !defined(B) && !defined(C) */ # define HAS_D #endif /* !defined(A) && !defined(B) && !defined(C) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) #define HAS_A #endif #if !defined(A) && defined(B) #define HAS_B #endif #if defined(C) #if !defined(A) #if !defined(B) #define HAS_C #endif #endif #endif #if !defined(B) && !defined(A) && !defined(C) #define HAS_D #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"test elif composition from disparate statements") or show_text($as_text); #if defined(A) # define HAS_A #elif defined(B) /* && !defined(A) */ # define HAS_B #elif defined(C) /* && !defined(A) && !defined(B) */ # define HAS_C #else /* if !defined(A) && !defined(B) && !defined(C) */ # define HAS_D #endif /* !defined(A) && !defined(B) && !defined(C) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) #define HAS_A #endif #if !defined(A) #define HAS_NOT_A #if !defined(C) #define HAS_A_NOT_C #endif #endif #if defined(C) #define HAS_C #if defined(A) #define HAS_A_C #endif #else #if defined(A) #define HAS_NOT_C_A #endif #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"test else composition") or show_text($as_text); #if defined(A) # define HAS_A # if defined(C) # define HAS_A_C # else /* if !defined(C) */ # define HAS_NOT_C_A # endif /* !defined(C) */ #else /* if !defined(A) */ # define HAS_NOT_A # if !defined(C) # define HAS_A_NOT_C # endif /* !defined(C) */ #endif /* !defined(A) */ #if defined(C) # define HAS_C #endif /* defined(C) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if !defined(A) #define NOT_A1 #else #define A1 #endif #if !!!!defined(A) #define A2 #else #define NOT_A2 #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"normalization into if/else") or show_text($as_text); #if defined(A) # define A1 # define A2 #else /* if !defined(A) */ # define NOT_A1 # define NOT_A2 #endif /* !defined(A) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if !!!(defined(A) && defined(B)) #define NOT_A_AND_B #endif #if defined(A) #if defined(B) #define A_AND_B #endif #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"normalization with complex else") or show_text($as_text); #if defined(A) && defined(B) # define A_AND_B #else /* if !( defined(A) && defined(B) ) */ # define NOT_A_AND_B #endif /* !( defined(A) && defined(B) ) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) && !!defined(A) && !!!!defined(A) #define HAS_A #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"simplification") or show_text($as_text); #if defined(A) # define HAS_A #endif /* defined(A) */ EOF } { local $::TODO; $::TODO= "Absorbtion not implemented yet"; # currently we don't handle absorbtion: (A && (A || B || C ...)) == A my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(X) && (defined(X) || defined(Y)) #define HAS_X #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"simplification by absorbtion"); # or show_text($as_text); #if defined(X) # define HAS_X #endif /* defined(X) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(A) && (defined(B) && defined(C)) #define HAS_A #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"expression flattening") or show_text($as_text); #if defined(A) && defined(B) && defined(C) # define HAS_A #endif /* defined(A) && defined(B) && defined(C) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>3); $hp->parse_text(<<~'EOF'); #if defined(A) #define HAS_A1 #define HAS_A2 #define HAS_A3 #endif #if defined(B) #define HAS_B1 #else #define HAS_B1e #define HAS_B2e #define HAS_B3e #endif #if defined(C) #if defined(D) #define HAS_D1 #endif #elif defined(CC) #define HAS_CC1 #define HAS_CC2 #define HAS_CC3 #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"auto-comments") or show_text($as_text); #if defined(A) # define HAS_A1 # define HAS_A2 # define HAS_A3 #endif /* defined(A) */ #if defined(B) # define HAS_B1 #else # define HAS_B1e # define HAS_B2e # define HAS_B3e #endif /* !defined(B) */ #if defined(C) # if defined(D) # define HAS_D1 # endif #elif defined(CC) /* && !defined(C) */ # define HAS_CC1 # define HAS_CC2 # define HAS_CC3 #endif /* !defined(C) && defined(CC) */ EOF } { my $hp= HeaderParser->new(debug=>0,add_commented_expr_after=>0); $hp->parse_text(<<~'EOF'); #if defined(DEBUGGING) \ || (defined(USE_LOCALE) && ( defined(USE_THREADS) \ || defined(HAS_IGNORED_LOCALE_CATEGORIES)\ || defined(USE_POSIX_2008_LOCALE) \ || ! defined(LC_ALL))) # define X #endif EOF my $grouped= $hp->group_content(); my $as_text= $hp->lines_as_str($grouped); is($as_text,<<~'EOF',"Karls example") or show_text($as_text); #if defined(DEBUGGING) || \ ( defined(USE_LOCALE) && \ ( defined(HAS_IGNORED_LOCALE_CATEGORIES) || !defined(LC_ALL) || \ defined(USE_POSIX_2008_LOCALE) || defined(USE_THREADS) ) ) # define X #endif /* defined(DEBUGGING) || ( defined(USE_LOCALE) && ( defined(HAS_IGNORED_LOCALE_CATEGORIES) || !defined(LC_ALL) || defined(USE_POSIX_2008_LOCALE) || defined(USE_THREADS) ) ) */ EOF } done_testing();