comparison libinterp/parse-tree/oct-parse.yy @ 28511:59dfd9ed72a3 stable

capture comments for classdef classes, properties, events, and enumerations * parse.h, oct-parse.yy: Refactor parser rules for collecting comments and docstrings for classdef parse tree elements. * pt-classdef.h, pt-classdef.cc (tree_classdef_property, tree_classdef_event, tree_classdef_enum): Store comments and docstrings and provide access to them. (tree_classdef_body): Store docstring for classdef object. (tree_classdef): Provide access to classdef docstring from classdef body object.
author John W. Eaton <jwe@octave.org>
date Thu, 28 May 2020 13:48:37 -0400
parents 06bc2f0bf760
children 70d155283f33 3dae50cf0bc5
comparison
equal deleted inserted replaced
28510:a3ea758870dc 28511:59dfd9ed72a3
1729 1729
1730 classdef : classdef_beg stash_comment attr_list identifier opt_sep superclass_list class_body END 1730 classdef : classdef_beg stash_comment attr_list identifier opt_sep superclass_list class_body END
1731 { 1731 {
1732 YYUSE ($5); 1732 YYUSE ($5);
1733 1733
1734 octave::comment_list *lc = $2;
1735 octave::comment_list *tc = lexer.get_comment ();
1736
1734 lexer.m_parsing_classdef = false; 1737 lexer.m_parsing_classdef = false;
1735 1738
1736 if (! ($$ = parser.make_classdef ($1, $3, $4, $6, $7, $8, $2))) 1739 if (! ($$ = parser.make_classdef ($1, $3, $4, $6, $7, $8,
1740 lc, tc)))
1737 { 1741 {
1738 // make_classdef deleted $3, $4, $6, and $7. 1742 // make_classdef deleted $3, $4, $6, $7, LC, and
1743 // TC.
1739 YYABORT; 1744 YYABORT;
1740 } 1745 }
1741 } 1746 }
1742 ; 1747 ;
1743 1748
1866 $$ = $1; 1871 $$ = $1;
1867 } 1872 }
1868 ; 1873 ;
1869 1874
1870 properties_block 1875 properties_block
1871 : PROPERTIES opt_sep stash_comment attr_list property_list END 1876 : PROPERTIES stash_comment opt_sep attr_list property_list END
1872 { 1877 {
1873 YYUSE ($2); 1878 YYUSE ($3);
1879
1880 octave::comment_list *lc = $2;
1881 octave::comment_list *tc = lexer.get_comment ();
1874 1882
1875 if (! ($$ = parser.make_classdef_properties_block 1883 if (! ($$ = parser.make_classdef_properties_block
1876 ($1, $4, $5, $6, $3))) 1884 ($1, $4, $5, $6, lc, tc)))
1877 { 1885 {
1878 // make_classdef_properties_block deleted $4 and $5. 1886 // make_classdef_properties_block deleted $4,
1887 // $5, LC, and TC.
1879 YYABORT; 1888 YYABORT;
1880 } 1889 }
1881 } 1890 }
1882 ; 1891 ;
1883 1892
1896 { $$ = new octave::tree_classdef_property_list ($1); } 1905 { $$ = new octave::tree_classdef_property_list ($1); }
1897 | property_list1 sep class_property 1906 | property_list1 sep class_property
1898 { 1907 {
1899 YYUSE ($2); 1908 YYUSE ($2);
1900 1909
1910 // We don't look ahead to grab end-of-line comments.
1911 // Instead, they are grabbed when we see the
1912 // identifier that becomes the next element in the
1913 // list. If the element at the end of the list
1914 // doesn't have a doc string, see whether the
1915 // element we are adding is stroing an end-of-line
1916 // comment for us to use.
1917
1918 octave::tree_classdef_property *last_elt = $1->back ();
1919
1920 if (! last_elt->have_doc_string ())
1921 {
1922 octave::comment_list *cl = $3->comments ();
1923
1924 if (cl)
1925 {
1926 octave::comment_elt elt = cl->front ();
1927
1928 if (elt.is_end_of_line ())
1929 last_elt->doc_string (elt.text ());
1930 }
1931 }
1932
1901 $1->append ($3); 1933 $1->append ($3);
1902 $$ = $1; 1934 $$ = $1;
1903 } 1935 }
1904 ; 1936 ;
1905 1937
1906 class_property : identifier 1938 class_property : stash_comment identifier
1907 { $$ = new octave::tree_classdef_property ($1); } 1939 {
1908 | identifier '=' decl_param_init expression 1940 $$ = new octave::tree_classdef_property ($2, $1);
1909 { 1941 }
1910 YYUSE ($2); 1942 | stash_comment identifier '=' decl_param_init expression
1943 {
1944 YYUSE ($3);
1911 1945
1912 lexer.m_looking_at_initializer_expression = false; 1946 lexer.m_looking_at_initializer_expression = false;
1913 $$ = new octave::tree_classdef_property ($1, $4); 1947
1914 } 1948 $$ = new octave::tree_classdef_property ($2, $5, $1);
1915 ; 1949 }
1916 1950 ;
1917 methods_block : METHODS opt_sep stash_comment attr_list methods_list END 1951
1918 { 1952 methods_block : METHODS stash_comment opt_sep attr_list methods_list END
1919 YYUSE ($2); 1953 {
1954 YYUSE ($3);
1955
1956 octave::comment_list *lc = $2;
1957 octave::comment_list *tc = lexer.get_comment ();
1920 1958
1921 if (! ($$ = parser.make_classdef_methods_block 1959 if (! ($$ = parser.make_classdef_methods_block
1922 ($1, $4, $5, $6, $3))) 1960 ($1, $4, $5, $6, lc, tc)))
1923 { 1961 {
1924 // make_classdef_methods_block deleted $4 and $5. 1962 // make_classdef_methods_block deleted $4, $5,
1963 // LC, and TC.
1925 YYABORT; 1964 YYABORT;
1926 } 1965 }
1927 } 1966 }
1928 ; 1967 ;
1929 1968
1950 } 1989 }
1951 method_decl1 1990 method_decl1
1952 { 1991 {
1953 lexer.m_defining_func--; 1992 lexer.m_defining_func--;
1954 lexer.m_parsed_function_name.pop (); 1993 lexer.m_parsed_function_name.pop ();
1994
1955 $$ = parser.finish_classdef_external_method ($5, $2, $1); 1995 $$ = parser.finish_classdef_external_method ($5, $2, $1);
1956 } 1996 }
1957 ; 1997 ;
1958 1998
1959 method : method_decl 1999 method : method_decl
1992 $1->append (fcn); 2032 $1->append (fcn);
1993 $$ = $1; 2033 $$ = $1;
1994 } 2034 }
1995 ; 2035 ;
1996 2036
1997 events_block : EVENTS opt_sep stash_comment attr_list events_list END 2037 events_block : EVENTS stash_comment opt_sep attr_list events_list END
1998 { 2038 {
1999 YYUSE ($2); 2039 YYUSE ($3);
2040
2041 octave::comment_list *lc = $2;
2042 octave::comment_list *tc = lexer.get_comment ();
2000 2043
2001 if (! ($$ = parser.make_classdef_events_block 2044 if (! ($$ = parser.make_classdef_events_block
2002 ($1, $4, $5, $6, $3))) 2045 ($1, $4, $5, $6, lc, tc)))
2003 { 2046 {
2004 // make_classdef_events_block deleted $4 and $5. 2047 // make_classdef_events_block deleted $4, $5,
2048 // LC, and TC.
2005 YYABORT; 2049 YYABORT;
2006 } 2050 }
2007 } 2051 }
2008 ; 2052 ;
2009 2053
2026 $1->append ($3); 2070 $1->append ($3);
2027 $$ = $1; 2071 $$ = $1;
2028 } 2072 }
2029 ; 2073 ;
2030 2074
2031 class_event : identifier 2075 class_event : stash_comment identifier
2032 { $$ = new octave::tree_classdef_event ($1); } 2076 { $$ = new octave::tree_classdef_event ($2, $1); }
2033 ; 2077 ;
2034 2078
2035 enum_block : ENUMERATION opt_sep stash_comment attr_list enum_list END 2079 enum_block : ENUMERATION stash_comment opt_sep attr_list enum_list END
2036 { 2080 {
2037 YYUSE ($2); 2081 YYUSE ($3);
2082
2083 octave::comment_list *lc = $2;
2084 octave::comment_list *tc = lexer.get_comment ();
2038 2085
2039 if (! ($$ = parser.make_classdef_enum_block 2086 if (! ($$ = parser.make_classdef_enum_block
2040 ($1, $4, $5, $6, $3))) 2087 ($1, $4, $5, $6, lc, tc)))
2041 { 2088 {
2042 // make_classdef_enum_block deleted $3 and $4. 2089 // make_classdef_enum_block deleted $4, $5, LC,
2090 // and TC.
2043 YYABORT; 2091 YYABORT;
2044 } 2092 }
2045 } 2093 }
2046 ; 2094 ;
2047 2095
2064 $1->append ($3); 2112 $1->append ($3);
2065 $$ = $1; 2113 $$ = $1;
2066 } 2114 }
2067 ; 2115 ;
2068 2116
2069 class_enum : identifier '(' expression ')' 2117 class_enum : stash_comment identifier '(' expression ')'
2070 { 2118 {
2071 YYUSE ($2); 2119 YYUSE ($3);
2072 YYUSE ($4); 2120 YYUSE ($5);
2073 2121
2074 $$ = new octave::tree_classdef_enum ($1, $3); 2122 $$ = new octave::tree_classdef_enum ($2, $4, $1);
2075 } 2123 }
2076 ; 2124 ;
2077 2125
2078 // ============= 2126 // =============
2079 // Miscellaneous 2127 // Miscellaneous
3785 // methods, but it is not an executable command. Parsing the block 3833 // methods, but it is not an executable command. Parsing the block
3786 // makes some changes in the symbol table (inserting the constructor 3834 // makes some changes in the symbol table (inserting the constructor
3787 // and methods, and adding to the list of known objects) and creates 3835 // and methods, and adding to the list of known objects) and creates
3788 // a parse tree containing meta information about the class. 3836 // a parse tree containing meta information about the class.
3789 3837
3838 // LC contains comments appearing before the classdef keyword.
3839 // TC contains comments appearing between the classdef elements
3840 // and the final end token for the classdef block.
3841
3790 tree_classdef * 3842 tree_classdef *
3791 base_parser::make_classdef (token *tok_val, 3843 base_parser::make_classdef (token *tok_val,
3792 tree_classdef_attribute_list *a, 3844 tree_classdef_attribute_list *a,
3793 tree_identifier *id, 3845 tree_identifier *id,
3794 tree_classdef_superclass_list *sc, 3846 tree_classdef_superclass_list *sc,
3795 tree_classdef_body *body, token *end_tok, 3847 tree_classdef_body *body, token *end_tok,
3796 comment_list *lc) 3848 comment_list *lc, comment_list *tc)
3797 { 3849 {
3798 tree_classdef *retval = nullptr; 3850 tree_classdef *retval = nullptr;
3799 3851
3800 m_lexer.m_symtab_context.pop (); 3852 m_lexer.m_symtab_context.pop ();
3801 3853
3815 3867
3816 delete a; 3868 delete a;
3817 delete id; 3869 delete id;
3818 delete sc; 3870 delete sc;
3819 delete body; 3871 delete body;
3872 delete lc;
3873 delete tc;
3820 3874
3821 bison_error ("invalid classdef definition, the class name must match the filename", l, c); 3875 bison_error ("invalid classdef definition, the class name must match the filename", l, c);
3822 3876
3823 } 3877 }
3824 else 3878 else
3825 { 3879 {
3826 if (end_token_ok (end_tok, token::classdef_end)) 3880 if (end_token_ok (end_tok, token::classdef_end))
3827 { 3881 {
3828 comment_list *tc = m_lexer.m_comment_buf.get_comment ();
3829
3830 int l = tok_val->line (); 3882 int l = tok_val->line ();
3831 int c = tok_val->column (); 3883 int c = tok_val->column ();
3832 3884
3833 if (! body) 3885 if (! body)
3834 body = new tree_classdef_body (); 3886 body = new tree_classdef_body ();
3841 { 3893 {
3842 delete a; 3894 delete a;
3843 delete id; 3895 delete id;
3844 delete sc; 3896 delete sc;
3845 delete body; 3897 delete body;
3898 delete lc;
3899 delete tc;
3846 3900
3847 end_token_error (end_tok, token::switch_end); 3901 end_token_error (end_tok, token::switch_end);
3848 } 3902 }
3849 } 3903 }
3850 3904
3851 return retval; 3905 return retval;
3852 } 3906 }
3907
3908 // LC contains comments appearing before the properties keyword.
3909 // If this properties block appears first in the list of classdef
3910 // elements, this comment list will be used for the help text for the
3911 // classdef block.
3912
3913 // TC contains comments appearing between the list of properties
3914 // and the final end token for the properties block and may be used to
3915 // find the doc string for the final property in the list.
3853 3916
3854 tree_classdef_properties_block * 3917 tree_classdef_properties_block *
3855 base_parser::make_classdef_properties_block (token *tok_val, 3918 base_parser::make_classdef_properties_block (token *tok_val,
3856 tree_classdef_attribute_list *a, 3919 tree_classdef_attribute_list *a,
3857 tree_classdef_property_list *plist, 3920 tree_classdef_property_list *plist,
3858 token *end_tok, 3921 token *end_tok,
3859 comment_list *lc) 3922 comment_list *lc,
3923 comment_list *tc)
3860 { 3924 {
3861 tree_classdef_properties_block *retval = nullptr; 3925 tree_classdef_properties_block *retval = nullptr;
3862 3926
3863 if (end_token_ok (end_tok, token::properties_end)) 3927 if (end_token_ok (end_tok, token::properties_end))
3864 { 3928 {
3865 comment_list *tc = m_lexer.m_comment_buf.get_comment ();
3866
3867 int l = tok_val->line (); 3929 int l = tok_val->line ();
3868 int c = tok_val->column (); 3930 int c = tok_val->column ();
3869 3931
3870 if (! plist) 3932 if (plist)
3933 {
3934 // If the element at the end of the list doesn't have a doc
3935 // string, see whether the first element of TC is an
3936 // end-of-line comment for us to use.
3937
3938 if (tc)
3939 {
3940 tree_classdef_property *last_elt = plist->back ();
3941
3942 if (! last_elt->have_doc_string ())
3943 {
3944 comment_elt first_comment_elt = tc->front ();
3945
3946 if (first_comment_elt.is_end_of_line ())
3947 {
3948 std::string eol_comment = first_comment_elt.text ();
3949
3950 last_elt->doc_string (eol_comment);
3951 }
3952 }
3953 }
3954 }
3955 else
3871 plist = new tree_classdef_property_list (); 3956 plist = new tree_classdef_property_list ();
3872 3957
3873 retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); 3958 retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c);
3874 } 3959 }
3875 else 3960 else
3876 { 3961 {
3877 delete a; 3962 delete a;
3878 delete plist; 3963 delete plist;
3964 delete lc;
3965 delete tc;
3879 3966
3880 end_token_error (end_tok, token::properties_end); 3967 end_token_error (end_tok, token::properties_end);
3881 } 3968 }
3882 3969
3883 return retval; 3970 return retval;
3884 } 3971 }
3972
3973 // LC contains comments appearing before the methods keyword.
3974 // If this methods block appears first in the list of classdef
3975 // elements, this comment list will be used for the help text for the
3976 // classdef block.
3885 3977
3886 tree_classdef_methods_block * 3978 tree_classdef_methods_block *
3887 base_parser::make_classdef_methods_block (token *tok_val, 3979 base_parser::make_classdef_methods_block (token *tok_val,
3888 tree_classdef_attribute_list *a, 3980 tree_classdef_attribute_list *a,
3889 tree_classdef_methods_list *mlist, 3981 tree_classdef_methods_list *mlist,
3890 token *end_tok, 3982 token *end_tok, comment_list *lc,
3891 comment_list *lc) 3983 comment_list *tc)
3892 { 3984 {
3893 tree_classdef_methods_block *retval = nullptr; 3985 tree_classdef_methods_block *retval = nullptr;
3894 3986
3895 if (end_token_ok (end_tok, token::methods_end)) 3987 if (end_token_ok (end_tok, token::methods_end))
3896 { 3988 {
3897 comment_list *tc = m_lexer.m_comment_buf.get_comment ();
3898
3899 int l = tok_val->line (); 3989 int l = tok_val->line ();
3900 int c = tok_val->column (); 3990 int c = tok_val->column ();
3901 3991
3902 if (! mlist) 3992 if (! mlist)
3903 mlist = new tree_classdef_methods_list (); 3993 mlist = new tree_classdef_methods_list ();
3906 } 3996 }
3907 else 3997 else
3908 { 3998 {
3909 delete a; 3999 delete a;
3910 delete mlist; 4000 delete mlist;
4001 delete lc;
4002 delete tc;
3911 4003
3912 end_token_error (end_tok, token::methods_end); 4004 end_token_error (end_tok, token::methods_end);
3913 } 4005 }
3914 4006
3915 return retval; 4007 return retval;
3916 } 4008 }
4009
4010 // LC contains comments appearing before the events keyword.
4011 // If this events block appears first in the list of classdef
4012 // elements, this comment list will be used for the help text for the
4013 // classdef block.
4014
4015 // TC contains comments appearing between the list of events and
4016 // the final end token for the events block and may be used to find
4017 // the doc string for the final event in the list.
3917 4018
3918 tree_classdef_events_block * 4019 tree_classdef_events_block *
3919 base_parser::make_classdef_events_block (token *tok_val, 4020 base_parser::make_classdef_events_block (token *tok_val,
3920 tree_classdef_attribute_list *a, 4021 tree_classdef_attribute_list *a,
3921 tree_classdef_events_list *elist, 4022 tree_classdef_events_list *elist,
3922 token *end_tok, 4023 token *end_tok,
3923 comment_list *lc) 4024 comment_list *lc,
4025 comment_list *tc)
3924 { 4026 {
3925 tree_classdef_events_block *retval = nullptr; 4027 tree_classdef_events_block *retval = nullptr;
3926 4028
3927 if (end_token_ok (end_tok, token::events_end)) 4029 if (end_token_ok (end_tok, token::events_end))
3928 { 4030 {
3929 comment_list *tc = m_lexer.m_comment_buf.get_comment ();
3930
3931 int l = tok_val->line (); 4031 int l = tok_val->line ();
3932 int c = tok_val->column (); 4032 int c = tok_val->column ();
3933 4033
3934 if (! elist) 4034 if (! elist)
3935 elist = new tree_classdef_events_list (); 4035 elist = new tree_classdef_events_list ();
3938 } 4038 }
3939 else 4039 else
3940 { 4040 {
3941 delete a; 4041 delete a;
3942 delete elist; 4042 delete elist;
4043 delete lc;
4044 delete tc;
3943 4045
3944 end_token_error (end_tok, token::events_end); 4046 end_token_error (end_tok, token::events_end);
3945 } 4047 }
3946 4048
3947 return retval; 4049 return retval;
3948 } 4050 }
4051
4052 // LC contains comments appearing before the enumeration keyword.
4053 // If this enumeration block appears first in the list of classdef
4054 // elements, this comment list will be used for the help text for the
4055 // classdef block.
4056
4057 // TC contains comments appearing between the list of
4058 // enumerations and the final end token for the enumeration block and
4059 // may be used to find the doc string for the final enumeration in the
4060 // list.
3949 4061
3950 tree_classdef_enum_block * 4062 tree_classdef_enum_block *
3951 base_parser::make_classdef_enum_block (token *tok_val, 4063 base_parser::make_classdef_enum_block (token *tok_val,
3952 tree_classdef_attribute_list *a, 4064 tree_classdef_attribute_list *a,
3953 tree_classdef_enum_list *elist, 4065 tree_classdef_enum_list *elist,
3954 token *end_tok, 4066 token *end_tok,
3955 comment_list *lc) 4067 comment_list *lc,
4068 comment_list *tc)
3956 { 4069 {
3957 tree_classdef_enum_block *retval = nullptr; 4070 tree_classdef_enum_block *retval = nullptr;
3958 4071
3959 if (end_token_ok (end_tok, token::enumeration_end)) 4072 if (end_token_ok (end_tok, token::enumeration_end))
3960 { 4073 {
3961 comment_list *tc = m_lexer.m_comment_buf.get_comment ();
3962
3963 int l = tok_val->line (); 4074 int l = tok_val->line ();
3964 int c = tok_val->column (); 4075 int c = tok_val->column ();
3965 4076
3966 if (! elist) 4077 if (! elist)
3967 elist = new tree_classdef_enum_list (); 4078 elist = new tree_classdef_enum_list ();
3970 } 4081 }
3971 else 4082 else
3972 { 4083 {
3973 delete a; 4084 delete a;
3974 delete elist; 4085 delete elist;
4086 delete lc;
4087 delete tc;
3975 4088
3976 end_token_error (end_tok, token::enumeration_end); 4089 end_token_error (end_tok, token::enumeration_end);
3977 } 4090 }
3978 4091
3979 return retval; 4092 return retval;