Skip to content

Commit

Permalink
Merge pull request #4111 from roccomao/fix-function-parse
Browse files Browse the repository at this point in the history
Verilog: Fix function parse when return type contains `::`
  • Loading branch information
hirooih authored Nov 16, 2024
2 parents f63e6ae + 68ef8d6 commit 748a0e1
Show file tree
Hide file tree
Showing 5 changed files with 391 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--sort=no
92 changes: 92 additions & 0 deletions Units/parser-verilog.r/systemverilog-github4109.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
new_test_case input.sv /^package new_test_case; \/\/ for better readability$/;" K
test_func_A input.sv /^ function signed test_func_A();$/;" f package:new_test_case
test_task_A input.sv /^ task test_task_A; endtask$/;" t package:new_test_case
test_func_B input.sv /^ function not_care_class test_func_B();$/;" f package:new_test_case
test_func_C input.sv /^ function not_care_class#(int) test_func_C ();$/;" f package:new_test_case
test_func_D input.sv /^ function not_care_class #(int) test_func_D ( );$/;" f package:new_test_case
test_func_E input.sv /^ function not_care_class #( .T(int) ) test_func_E();$/;" f package:new_test_case
test_func_F input.sv /^ function unsigned [7:0] class_scope::test_func_F();$/;" f class:new_test_case.class_scope
test_func_G input.sv /^ function not_care_class class_scope::test_func_G();$/;" f class:new_test_case.class_scope
test_func_H input.sv /^ function not_care_class#(IF) class_scope::test_func_H();$/;" f class:new_test_case.class_scope
test_func_I input.sv /^ function not_care_class #(IF) class_scope::test_func_I;$/;" f class:new_test_case.class_scope
test_func_J input.sv /^ function not_care_class#(.T(real), .size(4)) class_scope::test_func_J;$/;" f class:new_test_case.class_scope
new input.sv /^ function class_scope::new;$/;" f class:new_test_case.class_scope
test_task_B input.sv /^ task class_scope::test_task_B () ;$/;" t class:new_test_case.class_scope
test_func_K input.sv /^ function not_care_class::TYPE test_func_K ();$/;" f package:new_test_case
test_func_L input.sv /^ function automatic bit signed [15:0] test_func_L();$/;" f package:new_test_case
test_func_M input.sv /^ function not_care_class#(bit [2:0]) :: TYPE test_func_M;$/;" f package:new_test_case
test_func_N input.sv /^ function not_care_class #(.T(bit [2:0]))::TYPE test_func_N;$/;" f package:new_test_case
test_func_O input.sv /^ function not_care_class # (100) ::TYPE test_func_O () ;$/;" f package:new_test_case
test_var_A input.sv /^ int test_var_A = 100;$/;" r package:new_test_case
test_func_P input.sv /^ function static bit test_func_P; endfunction$/;" f package:new_test_case
new input.sv /^ function new; endfunction$/;" f package:new_test_case
test_task_C input.sv /^ task test_task_C; endtask$/;" t package:new_test_case
test_func_Q input.sv /^ function not_care_class :: TYPE scope::test_func_Q;$/;" f class:new_test_case.scope
test_func_R input.sv /^ function void test_func_R ();$/;" f package:new_test_case
test_func_S input.sv /^ function not_care_class#(shortint)::TYPE scope::test_func_S ( );$/;" f class:new_test_case.scope
test_func_T input.sv /^ function not_care_class # ( .IF( IF ) )::TYPE scope:: test_func_T;$/;" f class:new_test_case.scope
test_var_B input.sv /^ longint test_var_B = 1024;$/;" r package:new_test_case
test_task_D input.sv /^ task test_task_D ( );$/;" t package:new_test_case
test_func_U input.sv /^ function void test_func_U; endfunction$/;" f package:new_test_case
new input.sv /^ function scope::new ();$/;" f class:new_test_case.scope
test_task_E input.sv /^ task scope:: test_task_E;$/;" t class:new_test_case.scope
LOW input.sv /^ localparam LOW = 8;$/;" c package:new_test_case
HIGH input.sv /^ localparam HIGH = 15;$/;" c package:new_test_case
test_func_V input.sv /^ function automatic logic [ LOW : HIGH ] test_func_V ();$/;" f package:new_test_case
test_func_W input.sv /^ function automatic int signed [LOW-1:HIGH-1] test_func_W;$/;" f package:new_test_case
test_func_EA input.sv /^ function automatic A:: B#(IF) ::TYPE test_func_EA ();$/;" f package:new_test_case
test_func_EB input.sv /^ function automatic unsigned [ LOW -1: HIGH -1] scope:: test_func_EB;$/;" f class:new_test_case.scope
test_wrong_task input.sv /^ task static A :: B :: C # (.T (int)) :: test_wrong_task ();$/;" t class:new_test_case.A.B.C
test_wrong_function input.sv /^ function static A::B::TYPE scope # ( .T (IF) ) :: test_wrong_function;$/;" f class:new_test_case.scope
test_specifier_A input.sv /^ function :initial void test_specifier_A (); endfunction$/;" f package:new_test_case
test_specifier_B input.sv /^ function :extends void test_specifier_B (); endfunction$/;" f package:new_test_case
test_specifier_C input.sv /^ function :final void test_specifier_C (); endfunction$/;" f package:new_test_case
test_specifier_D input.sv /^ function : initial : final void test_specifier_D (); endfunction$/;" f package:new_test_case
test_specifier_E input.sv /^ function : extends : final void test_specifier_E (); endfunction$/;" f package:new_test_case
test_specifier_F input.sv /^ function : final : initial void test_specifier_F (); endfunction$/;" f package:new_test_case
test_specifier_G input.sv /^ function : final : extends void test_specifier_G (); endfunction$/;" f package:new_test_case
test_specifier_H input.sv /^ virtual function : initial A :: B :: TYPE test_specifier_H ();$/;" f package:new_test_case
test_specifier_I input.sv /^ virtual function :extends :final A::B::C A::B::test_specifier_I;$/;" f class:new_test_case.A.B
test_specifier_J input.sv /^ task :initial :final A :: B :: test_specifier_J ;$/;" t class:new_test_case.A.B
test_specifier_K input.sv /^ task :final : extends A #(IF)::B ::test_specifier_K () ;$/;" t class:new_test_case.A.B
new input.sv /^ function corner_A::corner_B :: new ( );$/;" f class:new_test_case.corner_A.corner_B
test_func_XA input.sv /^ function A::B::C::D #(int) corner_A:: test_func_XA();$/;" f class:new_test_case.corner_A
test_func_XB input.sv /^ function void corner_A # ( .T(real) ) :: test_func_XB;$/;" f class:new_test_case.corner_A
test_func_XC input.sv /^ function A # ( IF ) :: B :: C corner_A :: test_func_XC ();$/;" f class:new_test_case.corner_A
test_func_XD input.sv /^ function A :: B # ( 100 )::C::D#(int) test_func_XD;$/;" f package:new_test_case
test_task_F input.sv /^ task A::B::C::test_task_F ;$/;" t class:new_test_case.A.B.C
test_func_Y input.sv /^ function void test_func_Y ( int Y_in_A, int Y_in_B );$/;" f package:new_test_case
Y_in_A input.sv /^ function void test_func_Y ( int Y_in_A, int Y_in_B );$/;" p function:new_test_case.test_func_Y
Y_in_B input.sv /^ function void test_func_Y ( int Y_in_A, int Y_in_B );$/;" p function:new_test_case.test_func_Y
test_task_G input.sv /^ task A #(real):: B#(IF)::C#( .size(64) ) :: D :: test_task_G ();$/;" t class:new_test_case.A.B.C.D
test_var_C input.sv /^ int test_var_C = 1024;$/;" r package:new_test_case
test_func_Z input.sv /^ function logic [LOW:HIGH] test_func_Z ();$/;" f package:new_test_case
test_class input.sv /^ class test_class;$/;" C package:new_test_case
test_func_EC input.sv /^ static function A::B::C::D test_func_EC () ;$/;" f class:new_test_case.test_class
test_task_EB input.sv /^ static task test_class::test_task_EB ; endtask$/;" t class:new_test_case.test_class
test_func_ED input.sv /^ static function A:: B ::C::D test_class :: test_func_ED;$/;" f class:new_test_case.test_class
uvm_component input.sv /^virtual class uvm_component extends uvm_report_object;$/;" C
config_mode_t input.sv /^ typedef bit [1:0] config_mode_t;$/;" T class:uvm_component
test_ok input.sv /^function void uvm_component::test_ok();$/;" f class:uvm_component
return_scope_res input.sv /^function uvm_component::config_mode_t uvm_component::return_scope_res();$/;" f class:uvm_component
test_scope_variable input.sv /^int test_scope_variable;$/;" r
m_set_cl_msg_args input.sv /^function void uvm_component::m_set_cl_msg_args();$/;" f class:uvm_component
m_set_cl_verb input.sv /^function void uvm_component::m_set_cl_verb; return; endfunction$/;" f class:uvm_component
m_set_cl_action input.sv /^function void uvm_component::m_set_cl_action; return; endfunction$/;" f class:uvm_component
m_set_cl_sev input.sv /^function void uvm_component::m_set_cl_sev; return; endfunction$/;" f class:uvm_component
test_case_A input.sv /^package test_case_A;$/;" K
test_ok input.sv /^ function void test_ok;$/;" f package:test_case_A
oops input.sv /^ function extern_class::data_type oops();$/;" f package:test_case_A
OOPS input.sv /^ function extern_class#(int)::data_type OOPS();$/;" f package:test_case_A
still_ok input.sv /^ function void still_ok();$/;" f package:test_case_A
test_case_B input.sv /^package test_case_B;$/;" K
foo input.sv /^ function void foo; \/\/ OK$/;" f package:test_case_B
test_ok input.sv /^ function uvm_queue#(uvm_callback) test_ok(uvm_object obj);$/;" f package:test_case_B
obj input.sv /^ function uvm_queue#(uvm_callback) test_ok(uvm_object obj);$/;" p function:test_case_B.test_ok
TEST_OK input.sv /^ function uvm_queue #(uvm_callback) TEST_OK(uvm_object obj);$/;" f package:test_case_B
obj input.sv /^ function uvm_queue #(uvm_callback) TEST_OK(uvm_object obj);$/;" p function:test_case_B.TEST_OK
bar input.sv /^ function void bar(); \/\/ OK$/;" f package:test_case_B
oops input.sv /^ function uvm_queue #(uvm_callback)::data_type oops(uvm_object obj);$/;" f package:test_case_B
obj input.sv /^ function uvm_queue #(uvm_callback)::data_type oops(uvm_object obj);$/;" p function:test_case_B.oops
test_scope_var input.sv /^ int test_scope_var = 1;$/;" r function:test_case_B.oops
still_ok input.sv /^ function void still_ok();$/;" f package:test_case_B
241 changes: 241 additions & 0 deletions Units/parser-verilog.r/systemverilog-github4109.d/input.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@

// ---------------------------------------------------------------------------
// TEST CASE for `processFunction()` to parse `function` and `task` body
// ---------------------------------------------------------------------------

package new_test_case; // for better readability

// 1. Normal function.
// -----------------------------------------------------------------
function signed test_func_A();
endfunction
task test_task_A; endtask

// 2. Normal function return class type.
// -----------------------------------------------------------------
// 2.1 return Normal class.
function not_care_class test_func_B();
endfunction
// 2.2 return parameterized class without space.
function not_care_class#(int) test_func_C ();
endfunction
// 2.3 return parameterized class with space.
function not_care_class #(int) test_func_D ( );
endfunction
// 2.4 return parameterized class with parameter.
function not_care_class #( .T(int) ) test_func_E();
endfunction

// 3. The prototype of the class is declared in another file,
// and the specific implementation is here.
// -----------------------------------------------------------------
// 3.1 Normal function.
function unsigned [7:0] class_scope::test_func_F();
endfunction
// 3.2 return Normal class.
function not_care_class class_scope::test_func_G();
endfunction
// 3.3 return parameterized class without space.
function not_care_class#(IF) class_scope::test_func_H();
endfunction
// 3.4 return parameterized class with space.
function not_care_class #(IF) class_scope::test_func_I;
endfunction
// 3.5 return parameterized class with parameter.
function not_care_class#(.T(real), .size(4)) class_scope::test_func_J;
endfunction
// 3.6 task or new function
function class_scope::new;
endfunction
task class_scope::test_task_B () ;
endtask

// 4. Normal function: return type from a class ( with `::` ).
// -----------------------------------------------------------------
// 4.1 from a Normal class
function not_care_class::TYPE test_func_K ();
endfunction
// Subsequent parsing is not affected.
function automatic bit signed [15:0] test_func_L();
endfunction
// 4.2 from a parameterized class
function not_care_class#(bit [2:0]) :: TYPE test_func_M;
endfunction
function not_care_class #(.T(bit [2:0]))::TYPE test_func_N;
endfunction
function not_care_class # (100) ::TYPE test_func_O () ;
endfunction
// Subsequent parsing is not affected.
int test_var_A = 100;
function static bit test_func_P; endfunction
// 4.3 task or new function
function new; endfunction
task test_task_C; endtask

// 5. function with class_scope && return type with class_scope
// -----------------------------------------------------------------
// 5.1 from a Normal class
function not_care_class :: TYPE scope::test_func_Q;
endfunction
// Subsequent parsing is not affected
function void test_func_R ();
endfunction
// 5.2 from a parameterized class
function not_care_class#(shortint)::TYPE scope::test_func_S ( );
endfunction
function not_care_class # ( .IF( IF ) )::TYPE scope:: test_func_T;
endfunction
// Subsequent parsing is not affected
longint test_var_B = 1024;
task test_task_D ( );
endtask
function void test_func_U; endfunction
// 5.3 task or new function
function scope::new ();
endfunction
task scope:: test_task_E;
endtask

// 6. Corner TEST
// -----------------------------------------------------------------
localparam LOW = 8;
localparam HIGH = 15;
function automatic logic [ LOW : HIGH ] test_func_V ();
endfunction
function automatic int signed [LOW-1:HIGH-1] test_func_W;
endfunction
function automatic A:: B#(IF) ::TYPE test_func_EA ();
endfunction
function automatic unsigned [ LOW -1: HIGH -1] scope:: test_func_EB;
endfunction
task static A :: B :: C # (.T (int)) :: test_wrong_task ();
endtask
function static A::B::TYPE scope # ( .T (IF) ) :: test_wrong_function;
endfunction
function :initial void test_specifier_A (); endfunction
function :extends void test_specifier_B (); endfunction
function :final void test_specifier_C (); endfunction
function : initial : final void test_specifier_D (); endfunction
function : extends : final void test_specifier_E (); endfunction
function : final : initial void test_specifier_F (); endfunction
function : final : extends void test_specifier_G (); endfunction
virtual function : initial A :: B :: TYPE test_specifier_H ();
endfunction
virtual function :extends :final A::B::C A::B::test_specifier_I;
endfunction
task :initial :final A :: B :: test_specifier_J ;
endtask
task :final : extends A #(IF)::B ::test_specifier_K () ;
endtask
function corner_A::corner_B :: new ( );
endfunction
function A::B::C::D #(int) corner_A:: test_func_XA();
endfunction
function void corner_A # ( .T(real) ) :: test_func_XB;
endfunction
function A # ( IF ) :: B :: C corner_A :: test_func_XC ();
endfunction
function A :: B # ( 100 )::C::D#(int) test_func_XD;
endfunction
task A::B::C::test_task_F ;
endtask
function void test_func_Y ( int Y_in_A, int Y_in_B );
endfunction
task A #(real):: B#(IF)::C#( .size(64) ) :: D :: test_task_G ();
endtask
int test_var_C = 1024;
function logic [LOW:HIGH] test_func_Z ();
endfunction
class test_class;
static function A::B::C::D test_func_EC () ;
endfunction
extern static task test_task_EB ();
extern static function A :: B :: C :: D test_func_ED ();
endclass
static task test_class::test_task_EB ; endtask
static function A:: B ::C::D test_class :: test_func_ED;
endfunction

endpackage : new_test_case

// ---------------------------------------------------------------------------
// REF : https://github.com/universal-ctags/ctags/issues/4109
// ---------------------------------------------------------------------------

virtual class uvm_component extends uvm_report_object;
typedef bit [1:0] config_mode_t;
extern virtual function void test_ok();
// ------------------------------------------------------
extern virtual function config_mode_t return_scope_res();
// ------------------------------------------------------
extern function void m_set_cl_msg_args();
extern function void m_set_cl_verb;
extern function void m_set_cl_action;
extern function void m_set_cl_sev;
endclass

function void uvm_component::test_ok();
// function body, this function is parsed OK
endfunction

// ---------------------------------------------------------------------
function uvm_component::config_mode_t uvm_component::return_scope_res();
return 2'b00;
endfunction
// ---------------------------------------------------------------------

int test_scope_variable;

function void uvm_component::m_set_cl_msg_args();
endfunction
function void uvm_component::m_set_cl_verb; return; endfunction
function void uvm_component::m_set_cl_action; return; endfunction
function void uvm_component::m_set_cl_sev; return; endfunction

package test_case_A;
typedef class extern_class;

function void test_ok;
endfunction

function extern_class::data_type oops();
endfunction

function extern_class#(int)::data_type OOPS();
endfunction

function void still_ok();
endfunction
endpackage

package test_case_B;
function void foo; // OK
// something
endfunction

// return type is a parameterized class, OK
function uvm_queue#(uvm_callback) test_ok(uvm_object obj);
return null;
endfunction

// OK, even if there is a space between `uvm_queue` and `#(`
function uvm_queue #(uvm_callback) TEST_OK(uvm_object obj);
return null;
endfunction

// Subsequent parsing is not affected
function void bar(); // OK
// something
endfunction

// ----------------------------------------------------------------
function uvm_queue #(uvm_callback)::data_type oops(uvm_object obj);
int test_scope_var = 1;
return null;
endfunction
// ----------------------------------------------------------------

function void still_ok();
// function body
endfunction
endpackage
16 changes: 8 additions & 8 deletions Units/parser-verilog.r/systemverilog-parameter.d/expected.tags
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ x input.sv /^ int x = C::p; \/\/ C::p disambiguates p$/;" r task:C.t
C input.sv /^class C #($/;" C
p input.sv /^ int p = 1,$/;" c class:C parameter:
T input.sv /^ type T = int$/;" c class:C parameter:
f input.sv /^function C::T C::f();$/;" f class:C.C
C input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" C class:C
DECODE_W input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" c class:C.C parameter:
ENCODE_W input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" c class:C.C parameter:
ENCODER_f input.sv /^ static function logic [ENCODE_W-1:0] ENCODER_f$/;" f class:C.C
DecodeIn input.sv /^ (input logic [DECODE_W-1:0] DecodeIn);$/;" p function:C.C.ENCODER_f
DECODER_f input.sv /^ static function logic [DECODE_W-1:0] DECODER_f$/;" f class:C.C
EncodeIn input.sv /^ (input logic [ENCODE_W-1:0] EncodeIn);$/;" p function:C.C.DECODER_f
f input.sv /^function C::T C::f();$/;" f class:C
C input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" C
DECODE_W input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" c class:C parameter:
ENCODE_W input.sv /^virtual class C#(parameter DECODE_W, parameter ENCODE_W = $clog2(DECODE_W));$/;" c class:C parameter:
ENCODER_f input.sv /^ static function logic [ENCODE_W-1:0] ENCODER_f$/;" f class:C
DecodeIn input.sv /^ (input logic [DECODE_W-1:0] DecodeIn);$/;" p function:C.ENCODER_f
DECODER_f input.sv /^ static function logic [DECODE_W-1:0] DECODER_f$/;" f class:C
EncodeIn input.sv /^ (input logic [ENCODE_W-1:0] EncodeIn);$/;" p function:C.DECODER_f
PutImp input.sv /^interface class PutImp #(type PUT_T = logic);$/;" l
PUT_T input.sv /^interface class PutImp #(type PUT_T = logic);$/;" c ifclass:PutImp parameter:
GetImp input.sv /^interface class GetImp #(type GET_T = logic);$/;" l
Expand Down
Loading

0 comments on commit 748a0e1

Please sign in to comment.