Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Improvements and refactoring of ut_annotation_parser #522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/core/annotations/ut_annotation_manager.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ create or replace package body ut_annotation_manager as
where s.type = :a_object_type
and s.owner = :a_object_owner
and s.name
in (select /*+ cardinality( x ]'||l_card||q'[ )*/
in (select /*+ cardinality( t ]'||l_card||q'[ )*/
x.name
from table(:a_objects_to_refresh) t
join ]'||l_sources_view||q'[ x
Expand Down
101 changes: 52 additions & 49 deletions source/core/annotations/ut_annotation_parser.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,43 @@ create or replace package body ut_annotation_parser as
,modifier => 'n');
end;

procedure add_annotation(
a_annotations in out nocopy ut_annotations,
a_position positiven,
a_comment varchar2,
a_subobject_name varchar2 := null
) is
l_annotation_str varchar2(32767);
l_annotation_text varchar2(32767);
l_annotation_name varchar2(1000);
begin
-- strip everything except the annotation itself (spaces and others)
l_annotation_str := regexp_substr(a_comment, c_annotation_pattern, 1, 1, modifier => 'i');
if l_annotation_str is not null then

-- get the annotation name and it's parameters if present
l_annotation_name := lower(regexp_substr(l_annotation_str
,'%(' || c_regexp_identifier || ')'
,modifier => 'i'
,subexpression => 1));
l_annotation_text := trim(regexp_substr(l_annotation_str, '\((.*?)\)\s*$', subexpression => 1));

a_annotations.extend;
a_annotations( a_annotations.last) :=
ut_annotation(a_position, l_annotation_name, l_annotation_text, a_subobject_name);
end if;
end;

procedure delete_processed_comments( a_comments in out nocopy tt_comment_list, a_annotations ut_annotations ) is
l_loop_index pls_integer := 1;
begin
l_loop_index := a_annotations.first;
while l_loop_index is not null loop
a_comments.delete( a_annotations(l_loop_index).position );
l_loop_index := a_annotations.next( l_loop_index );
end loop;
end;

procedure add_annotations(
a_annotations in out nocopy ut_annotations,
a_source varchar2,
Expand All @@ -47,10 +84,6 @@ create or replace package body ut_annotation_parser as
) is
l_loop_index pls_integer := 1;
l_annotation_index pls_integer;
l_comment varchar2(32767);
l_annotation_str varchar2(32767);
l_annotation_text varchar2(32767);
l_annotation_name varchar2(1000);
begin
-- loop while there are unprocessed comment blocks
while 0 != nvl(regexp_instr(srcstr => a_source
Expand All @@ -60,49 +93,14 @@ create or replace package body ut_annotation_parser as
,0) loop

-- define index of the comment block and get it's content from cache
l_annotation_index := to_number(regexp_substr(a_source
,c_comment_replacer_regex_ptrn
,1
,l_loop_index
,subexpression => 1));

l_comment := a_comments( l_annotation_index );

-- strip everything except the annotation itself (spaces and others)
l_annotation_str := regexp_substr(l_comment, c_annotation_pattern, 1, 1, modifier => 'i');
if l_annotation_str is not null then

-- get the annotation name and it's parameters if present
l_annotation_name := lower(regexp_substr(l_annotation_str
,'%(' || c_regexp_identifier || ')'
,modifier => 'i'
,subexpression => 1));
l_annotation_text := trim(regexp_substr(l_annotation_str, '\((.*?)\)\s*$', subexpression => 1));

a_annotations.extend;
a_annotations( a_annotations.last) :=
ut_annotation(l_annotation_index, l_annotation_name, l_annotation_text, a_subobject_name);
end if;
l_annotation_index := regexp_substr( a_source ,c_comment_replacer_regex_ptrn ,1 ,l_loop_index ,subexpression => 1);
add_annotation( a_annotations, l_annotation_index, a_comments( l_annotation_index ), a_subobject_name );
l_loop_index := l_loop_index + 1;
end loop;

end add_annotations;

procedure add_package_annotations(a_annotations in out nocopy ut_annotations, a_source clob, a_comments tt_comment_list) is
l_package_comments varchar2(32767);
begin
l_package_comments := regexp_substr(srcstr => a_source
,pattern => '^\s*(CREATE\s+(OR\s+REPLACE)?(\s+(NON)?EDITIONABLE)?\s+)?PACKAGE\s[^;]*?(\s+(AS|IS)\s+)((.*?{COMMENT#\d+}\s?)+)'
,modifier => 'i'
,subexpression => 7);

-- parsing for package annotations
if l_package_comments is not null then
add_annotations(a_annotations, l_package_comments, a_comments);
end if;
end add_package_annotations;

procedure add_procedure_annotations(a_annotations in out nocopy ut_annotations, a_source clob, a_comments tt_comment_list) is
procedure add_procedure_annotations(a_annotations in out nocopy ut_annotations, a_source clob, a_comments in out nocopy tt_comment_list) is
l_proc_comments varchar2(32767);
l_proc_name varchar2(250);
l_annot_proc_ind number;
Expand All @@ -119,7 +117,7 @@ create or replace package body ut_annotation_parser as
,position => l_annot_proc_ind);
exit when l_annot_proc_ind = 0;

--get the annotataions with procedure name
--get the annotations with procedure name
l_annot_proc_block := regexp_substr(srcstr => a_source
,pattern => c_annotation_block_pattern
,position => l_annot_proc_ind
Expand All @@ -140,7 +138,6 @@ create or replace package body ut_annotation_parser as
-- parse the comment block for the syntactically correct annotations and store them as an array
add_annotations(a_annotations, l_proc_comments, a_comments, l_proc_name);

--l_annot_proc_ind := l_annot_proc_ind + length(l_annot_proc_block);
l_annot_proc_ind := regexp_instr(srcstr => a_source
,pattern => ';'
,occurrence => 1
Expand Down Expand Up @@ -203,6 +200,7 @@ create or replace package body ut_annotation_parser as
l_comments tt_comment_list;
l_annotations ut_annotations := ut_annotations();
l_result ut_annotations;
l_comment_index positive;
begin

l_source := delete_multiline_comments(l_source);
Expand All @@ -211,15 +209,20 @@ create or replace package body ut_annotation_parser as
-- this call modifies l_source
l_comments := extract_and_replace_comments(l_source);

add_package_annotations(l_annotations, l_source, l_comments);
add_procedure_annotations(l_annotations, l_source, l_comments);

delete_processed_comments(l_comments, l_annotations);

--at this point, only the comments not related to procedures are left, so we process them all as top-level
l_comment_index := l_comments.first;
while l_comment_index is not null loop
add_annotation( l_annotations, l_comment_index, l_comments( l_comment_index ) );
l_comment_index := l_comments.next(l_comment_index);
end loop;

dbms_lob.freetemporary(l_source);
select value(x)
bulk collect into l_result
from table(l_annotations) x
order by x.position;

select value(x) bulk collect into l_result from table(l_annotations) x order by x.position;

-- printing out parsed structure for debugging
$if $$ut_trace $then
Expand Down
7 changes: 6 additions & 1 deletion test/ut_annotation_parser/test_annotation_parser.pkb
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ create or replace package body test_annotation_parser is
ut3.ut_annotation(1,'suite',null, null),
ut3.ut_annotation(2,'displayname','Name of suite',null),
ut3.ut_annotation(3,'suitepath','all.globaltests',null),
ut3.ut_annotation(4,'ann1','Name of suite',null),
ut3.ut_annotation(5,'ann2','some_value','foo')
);

ut.expect(anydata.convertCollection(l_actual)).to_equal(anydata.convertCollection(l_expected));
end;

procedure ignore_floating_annotations is
procedure include_floating_annotations is
l_source clob;
l_actual ut3.ut_annotations;
l_expected ut3.ut_annotations;
Expand Down Expand Up @@ -63,7 +64,11 @@ create or replace package body test_annotation_parser is
ut3.ut_annotation( 1, 'suite', null, null ),
ut3.ut_annotation( 2, 'displayname', 'Name of suite', null ),
ut3.ut_annotation( 3, 'suitepath', 'all.globaltests', null ),
ut3.ut_annotation( 4, 'ann1', 'Name of suite', null ),
ut3.ut_annotation( 5, 'ann2', 'all.globaltests', null ),
ut3.ut_annotation( 6, 'test', null, 'foo'),
ut3.ut_annotation( 7, 'ann3', 'Name of suite', null ),
ut3.ut_annotation( 8, 'ann4', 'all.globaltests', null ),
ut3.ut_annotation( 9, 'test', null, 'bar')
);

Expand Down
6 changes: 3 additions & 3 deletions test/ut_annotation_parser/test_annotation_parser.pks
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ create or replace package test_annotation_parser is
--%suite(ut_annotation_parser)
--%suitepath(utplsql.core)

--%test(Ignores procedure level annotations if mixed with comments)
--%test(Treats procedure level annotations as package level, if mixed with comments)
procedure test_proc_comments;
--%test(Ignores floating annotations between procedures and package)
procedure ignore_floating_annotations;
--%test(Includes floating annotations between procedures and package)
procedure include_floating_annotations;
--%test(Parses complex annotations on procedures and functions)
procedure parse_complex_with_functions;
--%test(Parses package annotations without any procedure annotations)
Expand Down