From ef1d105bfbaa43cf55cd9aaaa70805b12a75c266 Mon Sep 17 00:00:00 2001 From: dbankieris Date: Wed, 8 May 2019 08:41:50 -0500 Subject: [PATCH] Improve parsing of base-clauses in S_define A base-clause is the stuff in an inheritance list after the colon in a class declaration. https://en.cppreference.com/w/cpp/language/derived_class Closes #723 Closes #733 --- libexec/trick/pm/parse_s_define.pm | 41 +++- test/SIM_parse_s_define/S_define | 207 +++++++++++++++++++++ test/SIM_parse_s_define/S_overrides.mk | 2 + test/SIM_parse_s_define/models/Classes.cpp | 1 + test/SIM_parse_s_define/models/Classes.hh | 22 +++ test/makefile | 1 + 6 files changed, 266 insertions(+), 8 deletions(-) create mode 100644 test/SIM_parse_s_define/S_define create mode 100644 test/SIM_parse_s_define/S_overrides.mk create mode 100644 test/SIM_parse_s_define/models/Classes.cpp create mode 100644 test/SIM_parse_s_define/models/Classes.hh diff --git a/libexec/trick/pm/parse_s_define.pm b/libexec/trick/pm/parse_s_define.pm index 8c2dfe92..214179d8 100644 --- a/libexec/trick/pm/parse_s_define.pm +++ b/libexec/trick/pm/parse_s_define.pm @@ -504,7 +504,7 @@ sub handle_sim_class ($$$$) { my ($s, $file_contents, $sim_ref, $comments_ref) = @_; my ($full_template_args, $template_args) ; my ($class_contents , $constructor_contents) ; - my ($class_name , $inherit_class, $inherit_constructor) ; + my ($class_name , $base_clause) ; my $final_contents ; my $int_call_functions ; my $double_call_functions ; @@ -518,7 +518,7 @@ sub handle_sim_class ($$$$) { $s =~ s/ZZZYYYXXX(\d+)ZZZYYYXXX//esg ; # grab the class name and the name of the class we are inheriting from - ($full_template_args, $class_name, $inherit_class) = $s =~ /(?:\s*template\s*<\s*([^>]+?)\s*>)?\s*class\s+(\w+)\s*(?::\s*public\s+(.+?)\s*)?$/ ; + ($full_template_args, $class_name, $base_clause) = $s =~ /(?:\s*template\s*<\s*([^>]+?)\s*>)?\s*class\s+(\w+)\s*(?::\s*(.+?)\s*)?$/ ; $template_args = $full_template_args ; $template_args =~ s/class|typename//g ; @@ -535,10 +535,35 @@ sub handle_sim_class ($$$$) { #final_contents contains the processed class. Start if off with the incoming class name $final_contents = $s ; - my ($unparameterized_name) = $inherit_class =~ /([^<]+)/ ; + # remove all whitespace from the base-clause to simplify regex patterns + $base_clause =~ s/\s//g; + + # This is the full regex for matching (I hope) any valid string following the ':' in a class + # declaration. (?1) is the syntax for recursive matching, which handles arbitrarily deeply + # nested template brackets. There are only two capture groups (the other groups are non- + # capturing). Because a class can inherit from any number of parents, the second group is + # repeated wth the * operator. Unfortunately, only the final capture is retained (until + # Perl 6), so we can't actually use this regex to capture all the parents. We could use it + # to validate the string, but the compiler is going to do that anyway. + #my @parents = $base_clause =~ /^(?:private|protected|public|virtual)*([\w:]+(?:<(?:[^<>]|(?1))*>)?)(?:,(?:private|protected|public)?((?1)))*$/; + + # This regex is less strict and will accept some invalid strings, but it will capture all + # of the parents. Since the compiler will eventually flag any syntax errors, I think it's + # ok if we let them pass here. + my @parents = $base_clause =~ /\G,?(?:private|protected|public|virtual)*([\w:]+(?:<(?:[^<>]|(?1))*>)?)/g; + + my $sim_object_parent; + foreach (@parents) { + # remove template arguments + ($_) = $_ =~ /([^<]+)/; + if (exists $$sim_ref{sim_class_index}{$_}) { + $sim_object_parent = $_; + last; + } + } # if this class is not a SimObject pass it whole to S_Source.cpp - if ( $inherit_class eq "" or !exists $$sim_ref{sim_class_index}{$unparameterized_name} ) { + if ( !$sim_object_parent ) { $class_contents =~ s/ZZZYYYXXX(\d+)ZZZYYYXXX/@$comments_ref[$1]/g ; $final_contents .= "$class_contents ;\n\n" ; $$sim_ref{sim_class_code} .= $final_contents ; @@ -564,7 +589,7 @@ sub handle_sim_class ($$$$) { $double_call_functions .= " if ( curr_job->disabled ) return (trick_ret) ;\n\n" ; $double_call_functions .= " switch ( curr_job->id ) {\n" ; - $$sim_ref{sim_class_index}{$class_name} = $$sim_ref{sim_class_index}{$unparameterized_name} ; + $$sim_ref{sim_class_index}{$class_name} = $$sim_ref{sim_class_index}{$sim_object_parent} ; # look for constructor while ( $class_contents =~ /^(.*?)$class_name\s*\([^;]*{/s ) { @@ -633,12 +658,12 @@ sub handle_sim_class ($$$$) { if ( $constructor_found == 1 ) { # if there is an inherited base class then the job id may reside in the base class - if ( $inherit_class eq "Trick::SimObject" or $inherit_class eq "SimObject" ) { + if ( $sim_object_parent eq "Trick::SimObject" or $sim_object_parent eq "SimObject" ) { $int_call_functions .= " default:\n trick_ret = -1 ;\n break ;\n" ; $double_call_functions .= " default:\n trick_ret = 0.0 ;\n break ;\n" ; } else { - $int_call_functions .= " default:\n trick_ret = ${inherit_class}::call_function( curr_job ) ;\n break ;\n" ; - $double_call_functions .= " default:\n trick_ret = ${inherit_class}::call_function_double( curr_job ) ;\n break ;\n" ; + $int_call_functions .= " default:\n trick_ret = ${sim_object_parent}::call_function( curr_job ) ;\n break ;\n" ; + $double_call_functions .= " default:\n trick_ret = ${sim_object_parent}::call_function_double( curr_job ) ;\n break ;\n" ; } $int_call_functions .= " }\n\n return(trick_ret) ;\n}\n\n" ; diff --git a/test/SIM_parse_s_define/S_define b/test/SIM_parse_s_define/S_define new file mode 100644 index 00000000..b8a6c2b5 --- /dev/null +++ b/test/SIM_parse_s_define/S_define @@ -0,0 +1,207 @@ +#include "sim_objects/default_trick_sys.sm" +##include "Classes.hh" + +// not sim objects, no namespace +class A : public Normal { +}; +class B : public Template1 {}; +class C : public Template2 > {}; + +// no namespace, sim object last +class D : public Normal, public Trick::SimObject { + public: + D() { + ("initialization") foo(); + } +}; +class DerivedFromD : public D { + public: + DerivedFromD() { + ("initialization") foo(); + } +}; +class E : public Template1, public Trick::SimObject { + public: + E() { + ("initialization") foo(); + } +}; +class DerivedFromE : public E { + public: + DerivedFromE() { + ("initialization") foo(); + } +}; +class F : public Template2 >, public Trick::SimObject { + public: + F() { + ("initialization") foo(); + } +}; +class DerivedFromF : public F { + public: + DerivedFromF() { + ("initialization") foo(); + } +}; + +// no namespace, sim object first +class G : public Trick::SimObject, public Normal { + public: + G() { + ("initialization") foo(); + } +}; +class DerivedFromG : public G { + public: + DerivedFromG() { + ("initialization") foo(); + } +}; +class H : public Trick::SimObject, public Template1 { + public: + H() { + ("initialization") foo(); + } +}; +class DerivedFromH : public H { + public: + DerivedFromH() { + ("initialization") foo(); + } +}; +class I : public Trick::SimObject, public Template2 > { + public: + I() { + ("initialization") foo(); + } +}; +class DerivedFromI : public I { + public: + DerivedFromI() { + ("initialization") foo(); + } +}; + +// not sim objects, namespace +class J : public Foo::FooNormal {}; +class K : public Foo::FooTemplate1 {}; +class L : public Foo::FooTemplate2 > {}; + +// namespace, sim object last +class M : public Foo::FooNormal, public Trick::SimObject { + public: + M() { + ("initialization") foo(); + } +}; +class DerivedFromM : public M { + public: + DerivedFromM() { + ("initialization") foo(); + } +}; +class N : public Foo::FooTemplate1, public Trick::SimObject { + public: + N() { + ("initialization") foo(); + } +}; +class DerivedFromN : public N { + public: + DerivedFromN() { + ("initialization") foo(); + } +}; +class O : public Foo::FooTemplate2 >, public Trick::SimObject { + public: + O() { + ("initialization") foo(); + } +}; +class DerivedFromO : public O { + public: + DerivedFromO() { + ("initialization") foo(); + } +}; + +// namespace, sim object first +class P : public Trick::SimObject, public Foo::FooNormal { + public: + P() { + ("initialization") foo(); + } +}; +class DerivedFromP : public P { + public: + DerivedFromP() { + ("initialization") foo(); + } +}; +class Q : public Trick::SimObject, public Foo::FooTemplate1 { + public: + Q() { + ("initialization") foo(); + } +}; +class DerivedFromQ : public Q { + public: + DerivedFromQ() { + ("initialization") foo(); + } +}; +class R : public Trick::SimObject, public Foo::FooTemplate2 > { + public: + R() { + ("initialization") foo(); + } +}; +class DerivedFromR : public R { + public: + DerivedFromR() { + ("initialization") foo(); + } +}; + +// SimObject templates! +template +class S : public Trick::SimObject { + public: + S() { + ("initialization") foo(); + } +}; +class DerivedFromS : public S { + public: + DerivedFromS() { + ("initialization") foo(); + } +}; +template +class T : public S { + public: + T() { + ("initialization") foo(); + } +}; +class DerivedFromT : public T > { + public: + DerivedFromT() { + ("initialization") foo(); + } +}; + +// crazy stuff +class Crazy1 : Foo::FooNormal, virtual Normal, private Template1, protected virtual Template2 >, public Trick::SimObject, virtual public Foo::FooTemplate1 { + public: + Crazy1() { + ("initialization") foo(); + } +}; +class DerivedFromCrazy1 : public Crazy1 { + public: + DerivedFromCrazy1() { + ("initialization") foo(); + } +}; diff --git a/test/SIM_parse_s_define/S_overrides.mk b/test/SIM_parse_s_define/S_overrides.mk new file mode 100644 index 00000000..e1f6cccd --- /dev/null +++ b/test/SIM_parse_s_define/S_overrides.mk @@ -0,0 +1,2 @@ +TRICK_CFLAGS += -Imodels +TRICK_CXXFLAGS += -Imodels diff --git a/test/SIM_parse_s_define/models/Classes.cpp b/test/SIM_parse_s_define/models/Classes.cpp new file mode 100644 index 00000000..f1dbbb82 --- /dev/null +++ b/test/SIM_parse_s_define/models/Classes.cpp @@ -0,0 +1 @@ +void foo() {}; diff --git a/test/SIM_parse_s_define/models/Classes.hh b/test/SIM_parse_s_define/models/Classes.hh new file mode 100644 index 00000000..7cafc6db --- /dev/null +++ b/test/SIM_parse_s_define/models/Classes.hh @@ -0,0 +1,22 @@ +//@trick_link_dependency{Classes.cpp} + +#ifndef CLASSES_HH +#define CLASSES_HH + +#include "trick/SimObject.hh" + +void foo(); + +class Normal {}; +template class Template1 {}; +template struct Template2 {}; + +namespace Foo { + +class FooNormal {}; +template class FooTemplate1 {}; +template struct FooTemplate2 {}; + +}; + +#endif diff --git a/test/makefile b/test/makefile index c110a529..d4ef47ba 100644 --- a/test/makefile +++ b/test/makefile @@ -20,6 +20,7 @@ SIMS_NEEDING_TEST = \ SIM_alloc_test \ SIM_demo_inputfile \ SIM_measurement_units \ + SIM_parse_s_define \ SIM_test_abstract \ SIM_test_inherit \ SIM_test_ip2 \