]> git.donarmstrong.com Git - perltidy.git/commitdiff
add --use-feature=class, part 2
authorSteve Hancock <perltidy@users.sourceforge.net>
Mon, 2 Jan 2023 23:41:56 +0000 (15:41 -0800)
committerSteve Hancock <perltidy@users.sourceforge.net>
Mon, 2 Jan 2023 23:41:56 +0000 (15:41 -0800)
Updates have been made to allow the default setting of --use-feature
to be --use-feature=class.  This can be turned off with --use-feature=' '.

CHANGES.md
dev-bin/perltidy_random_setup.pl
lib/Perl/Tidy.pm
lib/Perl/Tidy/Tokenizer.pm
t/snippets/expect/rt145706.def [new file with mode: 0644]
t/snippets/expect/sal.def
t/snippets/packing_list.txt
t/snippets/rt145706.in [new file with mode: 0644]
t/snippets15.t
t/snippets27.t

index 9bcdf999a5cb6a5bbaddad6e2fe517a5e221743a..1f0e0d75d021c76e159d422785700771716d830d 100644 (file)
@@ -2,6 +2,14 @@
 
 ## 2022 11 12.02
 
+    - Added option --use-feature=class, or -uf=class, for issue rt #145706.
+      This adds keywords 'class', 'method', 'field', and 'ADJUST' in support of
+      this feature which is being tested for future inclusion in Perl.
+      An effort has been made to avoid conflicts with past uses of these
+      words, especially 'method' and 'class'. The default setting
+      is --use-feature=class. If this causes a conflict, this option can
+      be turned off by entering -uf=' '.
+
     - Added option -bfvt=n, or --brace-follower-vertical-tightness=n,
       for part of issue git #110.  For n=2, this option looks for lines
       which would otherwise be, by default,
index 9b46493a128362556274341a1cb28f813d58fd83..3f1517b2f2f4d3b7ecb02e1da80bd7969a5db456 100755 (executable)
@@ -1163,6 +1163,8 @@ EOM
 
             'want-trailing-commas' => [ '0', '*', 'm', 'b', 'h', 'i', ' ' ],
 
+            'use-feature' => [ 'class', ' ', 'xyzzy' ],
+
             # Arbitrary limits to keep things readable
             'blank-lines-after-opening-block'  => [ 0, 4 ],
             'blank-lines-before-closing-block' => [ 0, 3 ],
index 534e8a564f22edee0c69479826cd793129fd10a1..35e7d552786ae890a345cb82e9a4746f60b47a61 100644 (file)
@@ -3577,6 +3577,7 @@ sub generate_options {
       noweld-nested-containers
       recombine
       nouse-unicode-gcstring
+      use-feature=class
       valign-code
       valign-block-comments
       valign-side-comments
@@ -4208,7 +4209,7 @@ sub cleanup_word_list {
 
     # Given:
     #   $rOpts - the global option hash
-    #   $option_name - hash key of this iption
+    #   $option_name - hash key of this option
     #   $rforced_words - ref to list of any words to be added
 
     # Returns:
index f1c2fafcf75f59cee4646a1c4d0b903ab33c248b..820a36435eed58e53fac8f740e05f44cafd969c0 100644 (file)
@@ -2195,6 +2195,137 @@ EOM
         return;
     } ## end sub scan_simple_identifier
 
+    sub method_ok_here {
+
+        # Return:
+        #   false if this is definitely an invalid method declaration
+        #   true otherwise (even if not sure)
+
+        # We are trying to avoid problems with old uses of 'method'
+        # when --use-feature=class is set (rt145706).
+        # For example, this should cause a return of 'false':
+
+        #  method paint => sub {
+        #    return;
+        #  };
+
+        # from do_scan_sub:
+        my $i_beg   = $i + 1;
+        my $pos_beg = $rtoken_map->[$i_beg];
+        pos($input_line) = $pos_beg;
+
+        # TEST 1: look a valid sub NAME
+        if (
+            $input_line =~ m/\G\s*
+        ((?:\w*(?:'|::))*)  # package - something that ends in :: or '
+        (\w+)               # NAME    - required
+        /gcx
+          )
+        {
+            my $subname = $2;
+            my $package = $1 ? $1 : EMPTY_STRING;
+        }
+        else {
+            return;
+        }
+
+        # TEST 2: look for invalid characters after name, such as here:
+        #    method paint => sub {
+        #     ...
+        #    }
+
+        if ( $input_line =~ m/\s*(\S)/gcx ) {
+            my $char = $1;
+
+            # Possibly valid next token types:
+            # '(' could start prototype or signature
+            # ':' could start ATTRIBUTE
+            # '{' cold start BLOCK
+            # ';' or '}' could end a statement
+            if ( $char =~ /^[\(\:\{\;\}]/ ) { return 1 }
+
+            # stop at a side comment - assume ok for now
+            if ( $char eq '#' ) { return 1 }
+
+            # nothing else is valid (in particular '#' and '"')
+            return;
+        }
+
+        # TBD: Still uncertain; may be at end of line
+        # We could continue will stop here and assume ok.
+        return 1;
+    }
+
+    sub class_ok_here {
+
+        # Return:
+        #   false if this is definitely an invalid class declaration
+        #   true otherwise (even if not sure)
+
+        # We are trying to avoid problems with old uses of 'class'
+        # when --use-feature=class is set (rt145706).
+
+        # Valid class declarations look like
+        #   class NAME ATTRS VERSION BLOCK
+        # where ATTRS VERSION and BLOCK are optional
+
+        # For example, this should cause a return of 'false':
+        #
+        #   class ExtendsBasicAttributes is BasicAttributes{
+
+        # TEST 1: class stmt can only go where a new statment can start
+        if ( !new_statement_ok() ) { return }
+
+        my $i_beg   = $i + 1;
+        my $pos_beg = $rtoken_map->[$i_beg];
+        pos($input_line) = $pos_beg;
+
+        # TEST 2: look for a valid NAME
+        if (
+            $input_line =~ m/\G\s*
+        ((?:\w*(?:'|::))*)  # package - something that ends in :: or '
+        (\w+)               # NAME    - required
+        /gcx
+          )
+        {
+            my $subname = $2;
+            my $package = $1 ? $1 : EMPTY_STRING;
+        }
+        else {
+            return;
+        }
+
+        # TEST 3: look for invalid characters after NAME
+        if ( $input_line =~ m/\s*(\S)/gcx ) {
+
+            my $char = $1;
+
+            # Must see one of: ATTRIBUTE, VERSION, BLOCK, or end stmt
+
+            # Possibly valid next token types:
+            # ':' could start ATTRIBUTE
+            # '\d' could start VERSION
+            # '{' cold start BLOCK
+            # ';' could end a statement
+            # '}' could end statement but would be strange
+            if ( $char =~ /^[\:\d\{\;\}]/ ) { return 1 }
+
+            # stop at a side comment - assume ok for now
+            if ( $char eq '#' ) { return 1 }
+
+            # Nothing else should be okay
+            return;
+
+            # non-dight letter - not ok
+            # ( this must be checked after \d )
+            ##OLD: if ( $tok =~ /^\w/) { return }
+        }
+
+        # TBD: Still uncertain; may be at end of line.
+        # We could continue will stop here and assume ok.
+        return 1;
+    }
+
     sub scan_id {
         ( $i, $tok, $type, $id_scan_state ) =
           scan_id_do( $input_line, $i, $tok, $rtokens, $rtoken_map,
@@ -2804,8 +2935,15 @@ EOM
             }
         }
 
-        $brace_type[ ++$brace_depth ]        = $block_type;
-        $brace_package[$brace_depth]         = $current_package;
+        $brace_type[ ++$brace_depth ] = $block_type;
+
+        # Patch for CLASS BLOCK definitions: do not update the package for the
+        # current depth if this is a BLOCK type definition.
+        # TODO: should make 'class' separate from 'package' and only do
+        # this for 'class'
+        $brace_package[$brace_depth] = $current_package
+          if ( substr( $block_type, 0, 8 ) ne 'package ' );
+
         $brace_structural_type[$brace_depth] = $type;
         $brace_context[$brace_depth]         = $context;
         ( $type_sequence, $indent_flag ) =
@@ -4090,11 +4228,15 @@ EOM
 
             if ( $tok_kw eq 'method' ) {
                 if (   $expecting == OPERATOR
-                    || $next_nonblank_token !~ /^(\w|\:)/ )
+                    || $next_nonblank_token !~ /^(\w|\:)/
+                    || !method_ok_here() )
                 {
                     do_UNKNOWN_BAREWORD($next_nonblank_token);
                 }
-                else { scan_id() }
+                else {
+                    initialize_subname();
+                    scan_id();
+                }
             }
             else {
                 error_if_expecting_OPERATOR()
@@ -4114,8 +4256,8 @@ EOM
             #   package($x) - error
             if ( $tok_kw eq 'class' ) {
                 if (   $expecting == OPERATOR
-                    || !new_statement_ok()
-                    || $next_nonblank_token !~ /^(\w|\:)/ )
+                    || $next_nonblank_token !~ /^(\w|\:)/
+                    || !class_ok_here() )
                 {
                     do_UNKNOWN_BAREWORD($next_nonblank_token);
                 }
@@ -8624,10 +8766,24 @@ EOM
                 }
             }
             elsif ($next_nonblank_token) {    # EOF technically ok
-                $subname = EMPTY_STRING unless defined($subname);
-                warning(
+
+                if ( $rinput_hash->{tok} eq 'method' && $call_type == SUB_CALL )
+                {
+                    # For a method call, silently ignore this error (rt145706)
+                    # to avoid needless warnings. Example which can produce it:
+                    #     test(method Pack (), "method");
+
+                    # TODO: scan for use feature 'class' and:
+                    # - if we saw 'use feature 'class' then issue the warning.
+                    # - if we did not see use feature 'class' then issue the
+                    #   warning and suggest turning off --use-feature=class
+                }
+                else {
+                    $subname = EMPTY_STRING unless defined($subname);
+                    warning(
 "expecting ':' or ';' or '{' after definition or declaration of sub '$subname' but saw '$next_nonblank_token'\n"
-                );
+                    );
+                }
             }
             check_prototype( $proto, $package, $subname );
         }
diff --git a/t/snippets/expect/rt145706.def b/t/snippets/expect/rt145706.def
new file mode 100644 (file)
index 0000000..64f81ef
--- /dev/null
@@ -0,0 +1,30 @@
+# some tests for default setting --use-feature=class, rt145706
+class Example::Subclass1 : isa(Example::Base) { ... }
+class Example::Subclass2 : isa(Example::Base 2.345) { ... }
+class Example::Subclass3 : isa(Example::Base) 1.345 { ... }
+field $y : param(the_y_value);
+class Pointer 2.0 {
+    field $x : param;
+    field $y : param;
+
+    method to_string() {
+        return "($x, $y)";
+    }
+}
+
+ADJUST {
+    $x = 0;
+}
+
+# these should not produce errors
+method paint => sub {
+    ...;
+};
+is( ( method Pack "a", "b", "c" ), "method,a,b,c" );
+class ExtendsBasicAttributes is BasicAttributes {
+    ...
+}
+class +Night with +Bad {
+    public nine { return 'crazy' }
+};
+my $x = field(50);
index f7584da2ce2d993630f5b980e32f5bfff97f5da5..124fac14ac9615f432ca5dbf9fd848c74c9bad5a 100644 (file)
@@ -2,7 +2,7 @@ sub get_val () {
 
 }
 
-method get_value() {
+method get_value () {
 
 }
 
index 6307b9a1ce6b555e027b2cd50c43ab2852bdacf7..c8caa6447adc00ca3740fcf8082dc108ea91e3f7 100644 (file)
 ../snippets27.t        wtc.wtc7
 ../snippets27.t        rt144979.def
 ../snippets27.t        rt144979.rt144979
+../snippets27.t        bfvt.bfvt0
+../snippets27.t        bfvt.bfvt2
+../snippets27.t        bfvt.def
+../snippets27.t        cpb.cpb
+../snippets27.t        cpb.def
 ../snippets3.t ce_wn1.ce_wn
 ../snippets3.t ce_wn1.def
 ../snippets3.t colin.colin
 ../snippets9.t rt98902.def
 ../snippets9.t rt98902.rt98902
 ../snippets9.t rt99961.def
-../snippets27.t        bfvt.bfvt0
-../snippets27.t        bfvt.bfvt2
-../snippets27.t        bfvt.def
-../snippets27.t        cpb.cpb
-../snippets27.t        cpb.def
+../snippets27.t        rt145706.def
diff --git a/t/snippets/rt145706.in b/t/snippets/rt145706.in
new file mode 100644 (file)
index 0000000..542280f
--- /dev/null
@@ -0,0 +1,30 @@
+# some tests for default setting --use-feature=class, rt145706
+class Example::Subclass1 : isa(Example::Base) { ... }
+class Example::Subclass2 : isa(Example::Base 2.345) { ... }
+class Example::Subclass3 : isa(Example::Base) 1.345 { ... }
+field $y : param(the_y_value);
+class Pointer 2.0 {
+    field $x : param;
+    field $y : param;
+
+    method to_string() {
+        return "($x, $y)";
+    }
+}
+
+ADJUST {
+    $x = 0;
+}
+
+# these should not produce errors
+method paint => sub {
+    ...;
+};
+is( ( method Pack "a", "b", "c" ), "method,a,b,c" );
+class ExtendsBasicAttributes is BasicAttributes{
+ ...
+}
+class +Night with +Bad {
+    public nine { return 'crazy' }
+};
+my $x = field(50);
index b51c0c5fc7f3e85d78378c8d9c6b5cb631ae17f4..eac77b011d4a3aaff6674b0d057f3566f4dbee39 100644 (file)
@@ -435,7 +435,7 @@ sub get_val () {
 
 }
 
-method get_value() {
+method get_value () {
 
 }
 
index 01ed0e433f50c3105307b3dbf88620e1fabe3f04..c266b5fd6a8f51dfe4da69f6f5c37adc2f6f8bcd 100644 (file)
@@ -17,6 +17,7 @@
 #14 bfvt.def
 #15 cpb.cpb
 #16 cpb.def
+#17 rt145706.def
 
 # To locate test #13 you can search for its name or the string '#13'
 
@@ -153,6 +154,39 @@ GetOptions(
             }
 }}}
 
+----------
+
+        'rt145706' => <<'----------',
+# some tests for default setting --use-feature=class, rt145706
+class Example::Subclass1 : isa(Example::Base) { ... }
+class Example::Subclass2 : isa(Example::Base 2.345) { ... }
+class Example::Subclass3 : isa(Example::Base) 1.345 { ... }
+field $y : param(the_y_value);
+class Pointer 2.0 {
+    field $x : param;
+    field $y : param;
+
+    method to_string() {
+        return "($x, $y)";
+    }
+}
+
+ADJUST {
+    $x = 0;
+}
+
+# these should not produce errors
+method paint => sub {
+    ...;
+};
+is( ( method Pack "a", "b", "c" ), "method,a,b,c" );
+class ExtendsBasicAttributes is BasicAttributes{
+ ...
+}
+class +Night with +Bad {
+    public nine { return 'crazy' }
+};
+my $x = field(50);
 ----------
 
         'wtc' => <<'----------',
@@ -852,6 +886,43 @@ foreach my $dir (
 
 #16...........
         },
+
+        'rt145706.def' => {
+            source => "rt145706",
+            params => "def",
+            expect => <<'#17...........',
+# some tests for default setting --use-feature=class, rt145706
+class Example::Subclass1 : isa(Example::Base) { ... }
+class Example::Subclass2 : isa(Example::Base 2.345) { ... }
+class Example::Subclass3 : isa(Example::Base) 1.345 { ... }
+field $y : param(the_y_value);
+class Pointer 2.0 {
+    field $x : param;
+    field $y : param;
+
+    method to_string() {
+        return "($x, $y)";
+    }
+}
+
+ADJUST {
+    $x = 0;
+}
+
+# these should not produce errors
+method paint => sub {
+    ...;
+};
+is( ( method Pack "a", "b", "c" ), "method,a,b,c" );
+class ExtendsBasicAttributes is BasicAttributes {
+    ...
+}
+class +Night with +Bad {
+    public nine { return 'crazy' }
+};
+my $x = field(50);
+#17...........
+        },
     };
 
     my $ntests = 0 + keys %{$rtests};