summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-05-10 17:54:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-05-10 17:54:18 +0200
commit443293aaf09eca7c3b88d621d056c4effee2c248 (patch)
treea35c7b2354295b5b73462c0806e04e2deef58171 /cli
parent4f9022f24c4591391637121c7274d9855b37bd93 (diff)
Implement option class inheritance
For now multiple, non-virtual inheritance is supported. An option class can now also be declared abstract using the class c = 0 {...}; syntax. New option, --exclude-base, controls whether base class information is present in usage and documentation.
Diffstat (limited to 'cli')
-rw-r--r--cli/header.cxx150
-rw-r--r--cli/html.cxx10
-rw-r--r--cli/lexer.cxx3
-rw-r--r--cli/man.cxx10
-rw-r--r--cli/options.cli5
-rw-r--r--cli/options.cxx138
-rw-r--r--cli/options.hxx52
-rw-r--r--cli/options.ixx41
-rw-r--r--cli/parser.cxx184
-rw-r--r--cli/parser.hxx19
-rw-r--r--cli/runtime-header.cxx4
-rw-r--r--cli/semantics/class.cxx18
-rw-r--r--cli/semantics/class.hxx86
-rw-r--r--cli/semantics/elements.cxx13
-rw-r--r--cli/semantics/elements.hxx9
-rw-r--r--cli/source.cxx452
-rw-r--r--cli/token.hxx1
-rw-r--r--cli/traversal/class.cxx23
-rw-r--r--cli/traversal/class.hxx15
19 files changed, 994 insertions, 239 deletions
diff --git a/cli/header.cxx b/cli/header.cxx
index fb714ed..e16b592 100644
--- a/cli/header.cxx
+++ b/cli/header.cxx
@@ -65,6 +65,31 @@ namespace
//
//
+ struct base: traversal::class_, context
+ {
+ base (context& c): context (c), first_ (true) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ if (first_)
+ {
+ os << ": ";
+ first_ = false;
+ }
+ else
+ os << "," << endl
+ << " ";
+
+ os << "public " << fq_name (c);
+ }
+
+ private:
+ bool first_;
+ };
+
+ //
+ //
struct class_: traversal::class_, context
{
class_ (context& c)
@@ -79,59 +104,67 @@ namespace
virtual void
traverse (type& c)
{
+ bool abst (c.abstract ());
string name (escape (c.name ()));
+ string um (cli + "::unknown_mode");
- os << "class " << name
- << "{"
- << "public:" << endl
- << endl;
+ os << "class " << name;
+
+ {
+ base b (*this);
+ traversal::inherits i (b);
+ inherits (c, i);
+ }
+
+ os << "{"
+ << "public:" << endl;
// c-tors
//
- string um (cli + "::unknown_mode");
-
- os << name << " (int& argc," << endl
- << "char** argv," << endl
- << "bool erase = false," << endl
- << um << " option = " << um << "::fail," << endl
- << um << " argument = " << um << "::stop);"
- << endl;
+ if (!abst)
+ {
+ os << name << " (int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase = false," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
- os << name << " (int start," << endl
- << "int& argc," << endl
- << "char** argv," << endl
- << "bool erase = false," << endl
- << um << " option = " << um << "::fail," << endl
- << um << " argument = " << um << "::stop);"
- << endl;
+ os << name << " (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase = false," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
- os << name << " (int& argc," << endl
- << "char** argv," << endl
- << "int& end," << endl
- << "bool erase = false," << endl
- << um << " option = " << um << "::fail," << endl
- << um << " argument = " << um << "::stop);"
- << endl;
+ os << name << " (int& argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << "bool erase = false," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
- os << name << " (int start," << endl
- << "int& argc," << endl
- << "char** argv," << endl
- << "int& end," << endl
- << "bool erase = false," << endl
- << um << " option = " << um << "::fail," << endl
- << um << " argument = " << um << "::stop);"
- << endl;
+ os << name << " (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << "bool erase = false," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
- os << name << " (" << cli << "::scanner&," << endl
- << um << " option = " << um << "::fail," << endl
- << um << " argument = " << um << "::stop);"
- << endl;
+ os << name << " (" << cli << "::scanner&," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+ }
//
//
os << "// Option accessors" << (modifier ? " and modifiers." : ".") << endl
- << "//" << endl
- << endl;
+ << "//" << endl;
names (c, names_option_);
@@ -157,15 +190,40 @@ namespace
<< endl;
}
- // _parse()
+ os << "// Implementation details." << endl
+ << "//" << endl
+ << "protected:" << endl;
+
+ // default c-tor
+ //
+ os << name << " ();"
+ << endl;
+
+ // fill ()
+ //
+ if (options.generate_description ())
+ os << "friend struct _cli_" + name + "_desc_init;"
+ << endl
+ << "static void" << endl
+ << "fill (" << cli << "::options&);"
+ << endl;
+
+ // _parse ()
//
- os << "private:" << endl
- << "void" << endl
- << "_parse (" << cli << "::scanner&," << endl
- << um << " option," << endl
- << um << " argument);"
+ os << "bool" << endl
+ << "_parse (const char*, " << cli << "::scanner&);"
<< endl;
+ // _parse ()
+ //
+ if (!abst)
+ os << "private:" << endl
+ << "void" << endl
+ << "_parse (" << cli << "::scanner&," << endl
+ << um << " option," << endl
+ << um << " argument);"
+ << endl;
+
// Data members.
//
os << "public:" << endl; //@@ tmp
diff --git a/cli/html.cxx b/cli/html.cxx
index c440854..8a9e97d 100644
--- a/cli/html.cxx
+++ b/cli/html.cxx
@@ -160,6 +160,9 @@ namespace
class_ (context& c)
: context (c), option_ (c)
{
+ *this >> inherits_base_ >> base_ >> inherits_base_;
+ base_ >> names_option_;
+
names_option_ >> option_;
}
@@ -179,15 +182,20 @@ namespace
os << "<dl class=\"options\">" << endl;
+ if (!options.exclude_base ())
+ inherits (c, inherits_base_);
+
names (c, names_option_);
os << "</dl>" << endl;
}
private:
- bool generated_;
option option_;
traversal::names names_option_;
+
+ traversal::class_ base_;
+ traversal::inherits inherits_base_;
};
}
diff --git a/cli/lexer.cxx b/cli/lexer.cxx
index baa8423..bf16ce5 100644
--- a/cli/lexer.cxx
+++ b/cli/lexer.cxx
@@ -155,7 +155,8 @@ next ()
get ();
return token (token::p_dcolon, c.line (), c.column ());
}
- break;
+
+ return token (token::p_colon, c.line (), c.column ());
}
case '{':
{
diff --git a/cli/man.cxx b/cli/man.cxx
index 93c6920..ac5d9b1 100644
--- a/cli/man.cxx
+++ b/cli/man.cxx
@@ -120,6 +120,9 @@ namespace
class_ (context& c)
: context (c), option_ (c)
{
+ *this >> inherits_base_ >> base_ >> inherits_base_;
+ base_ >> names_option_;
+
names_option_ >> option_;
}
@@ -137,13 +140,18 @@ namespace
return;
}
+ if (!options.exclude_base ())
+ inherits (c, inherits_base_);
+
names (c, names_option_);
}
private:
- bool generated_;
option option_;
traversal::names names_option_;
+
+ traversal::class_ base_;
+ traversal::inherits inherits_base_;
};
}
diff --git a/cli/options.cli b/cli/options.cli
index d21efa7..1462385 100644
--- a/cli/options.cli
+++ b/cli/options.cli
@@ -78,6 +78,11 @@ class options
files, and would like their usage to have the same indentation level."
};
+ bool --exclude-base
+ {
+ "Exclude base class information from usage and documentation."
+ };
+
std::string --cli-namespace = "::cli"
{
"<ns>",
diff --git a/cli/options.cxx b/cli/options.cxx
index eaef875..2d45b05 100644
--- a/cli/options.cxx
+++ b/cli/options.cxx
@@ -214,15 +214,24 @@ namespace cli
// See if the next argument is the file option.
//
const char* a (base::peek ());
+ const option_info* oi;
- if (!skip_ && a == option_)
+ if (!skip_ && (oi = find (a)))
{
base::next ();
if (!base::more ())
- throw missing_value (option_);
+ throw missing_value (oi->option);
- load (base::next ());
+ if (oi->search_func != 0)
+ {
+ std::string f (oi->search_func (base::next (), oi->arg));
+
+ if (!f.empty ())
+ load (f);
+ }
+ else
+ load (base::next ());
if (!args_.empty ())
return true;
@@ -276,12 +285,22 @@ namespace cli
args_.pop_front ();
}
+ const argv_file_scanner::option_info* argv_file_scanner::
+ find (const char* a) const
+ {
+ for (std::size_t i (0); i < options_count_; ++i)
+ if (std::strcmp (a, options_[i].option) == 0)
+ return &options_[i];
+
+ return 0;
+ }
+
void argv_file_scanner::
- load (const char* file)
+ load (const std::string& file)
{
using namespace std;
- ifstream is (file);
+ ifstream is (file.c_str ());
if (!is.is_open ())
throw file_io_failure (file);
@@ -361,8 +380,22 @@ namespace cli
s2 = string (s2, 1, n - 2);
}
- if (!skip_ && s1 == option_)
- load (s2.c_str ());
+ const option_info* oi;
+ if (!skip_ && (oi = find (s1.c_str ())))
+ {
+ if (s2.empty ())
+ throw missing_value (oi->option);
+
+ if (oi->search_func != 0)
+ {
+ std::string f (oi->search_func (s2.c_str (), oi->arg));
+
+ if (!f.empty ())
+ load (f);
+ }
+ else
+ load (s2);
+ }
else
{
args_.push_back (s1);
@@ -378,11 +411,11 @@ namespace cli
static void
parse (X& x, scanner& s)
{
- const char* o (s.next ());
+ std::string o (s.next ());
if (s.more ())
{
- const char* v (s.next ());
+ std::string v (s.next ());
std::istringstream is (v);
if (!(is >> x && is.eof ()))
throw invalid_value (o, v);
@@ -425,8 +458,7 @@ namespace cli
parse (std::vector<X>& c, scanner& s)
{
X x;
- bool dummy;
- parser<X>::parse (x, dummy, s);
+ parser<X>::parse (x, s);
c.push_back (x);
}
};
@@ -438,8 +470,7 @@ namespace cli
parse (std::set<X>& c, scanner& s)
{
X x;
- bool dummy;
- parser<X>::parse (x, dummy, s);
+ parser<X>::parse (x, s);
c.insert (x);
}
};
@@ -450,7 +481,7 @@ namespace cli
static void
parse (std::map<K, V>& m, scanner& s)
{
- const char* o (s.next ());
+ std::string o (s.next ());
if (s.more ())
{
@@ -517,6 +548,46 @@ namespace cli
//
options::
+options ()
+: help_ (),
+ version_ (),
+ output_dir_ (),
+ generate_modifier_ (),
+ generate_specifier_ (),
+ generate_description_ (),
+ generate_file_scanner_ (),
+ suppress_inline_ (),
+ suppress_undocumented_ (),
+ suppress_usage_ (),
+ long_usage_ (),
+ option_length_ (0),
+ exclude_base_ (),
+ cli_namespace_ ("::cli"),
+ generate_cxx_ (),
+ generate_man_ (),
+ generate_html_ (),
+ man_prologue_ (),
+ man_epilogue_ (),
+ html_prologue_ (),
+ html_epilogue_ (),
+ class__ (),
+ stdout__ (),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ man_suffix_ (".1"),
+ html_suffix_ (".html"),
+ option_prefix_ ("-"),
+ option_separator_ ("--"),
+ include_with_brackets_ (),
+ include_prefix_ (),
+ guard_prefix_ (),
+ reserved_name_ (),
+ options_file_ ()
+{
+}
+
+options::
options (int& argc,
char** argv,
bool erase,
@@ -534,6 +605,7 @@ options (int& argc,
suppress_usage_ (),
long_usage_ (),
option_length_ (0),
+ exclude_base_ (),
cli_namespace_ ("::cli"),
generate_cxx_ (),
generate_man_ (),
@@ -580,6 +652,7 @@ options (int start,
suppress_usage_ (),
long_usage_ (),
option_length_ (0),
+ exclude_base_ (),
cli_namespace_ ("::cli"),
generate_cxx_ (),
generate_man_ (),
@@ -626,6 +699,7 @@ options (int& argc,
suppress_usage_ (),
long_usage_ (),
option_length_ (0),
+ exclude_base_ (),
cli_namespace_ ("::cli"),
generate_cxx_ (),
generate_man_ (),
@@ -674,6 +748,7 @@ options (int start,
suppress_usage_ (),
long_usage_ (),
option_length_ (0),
+ exclude_base_ (),
cli_namespace_ ("::cli"),
generate_cxx_ (),
generate_man_ (),
@@ -718,6 +793,7 @@ options (::cli::scanner& s,
suppress_usage_ (),
long_usage_ (),
option_length_ (0),
+ exclude_base_ (),
cli_namespace_ ("::cli"),
generate_cxx_ (),
generate_man_ (),
@@ -770,7 +846,8 @@ print_usage (::std::ostream& os)
os << "--suppress-undocumented Suppress the generation of documentation entries" << ::std::endl
<< " for undocumented options." << ::std::endl;
- os << "--suppress-usage Suppress the generation of the usage printing code." << ::std::endl;
+ os << "--suppress-usage Suppress the generation of the usage printing" << ::std::endl
+ << " code." << ::std::endl;
os << "--long-usage If no short documentation string is provided, use" << ::std::endl
<< " the complete long documentation string in usage." << ::std::endl;
@@ -778,6 +855,9 @@ print_usage (::std::ostream& os)
os << "--option-length <len> Indent option descriptions <len> characters when" << ::std::endl
<< " printing usage." << ::std::endl;
+ os << "--exclude-base Exclude base class information from usage and" << ::std::endl
+ << " documentation." << ::std::endl;
+
os << "--cli-namespace <ns> Generate the CLI support types in the <ns>" << ::std::endl
<< " namespace ('cli' by default)." << ::std::endl;
@@ -796,8 +876,8 @@ print_usage (::std::ostream& os)
os << "--html-prologue <file> Insert the content of <file> at the beginning of" << ::std::endl
<< " the HTML file." << ::std::endl;
- os << "--html-epilogue <file> Insert the content of <file> at the end of the HTML" << ::std::endl
- << " file." << ::std::endl;
+ os << "--html-epilogue <file> Insert the content of <file> at the end of the" << ::std::endl
+ << " HTML file." << ::std::endl;
os << "--class <fq-name> Generate the man page or HTML documentation only" << ::std::endl
<< " for the <fq-name> options class." << ::std::endl;
@@ -879,6 +959,8 @@ struct _cli_options_map_init
&::cli::thunk< options, bool, &options::long_usage_ >;
_cli_options_map_["--option-length"] =
&::cli::thunk< options, std::size_t, &options::option_length_ >;
+ _cli_options_map_["--exclude-base"] =
+ &::cli::thunk< options, bool, &options::exclude_base_ >;
_cli_options_map_["--cli-namespace"] =
&::cli::thunk< options, std::string, &options::cli_namespace_ >;
_cli_options_map_["--generate-cxx"] =
@@ -928,6 +1010,20 @@ struct _cli_options_map_init
static _cli_options_map_init _cli_options_map_init_;
+bool options::
+_parse (const char* o, ::cli::scanner& s)
+{
+ _cli_options_map::const_iterator i (_cli_options_map_.find (o));
+
+ if (i != _cli_options_map_.end ())
+ {
+ (*(i->second)) (*this, s);
+ return true;
+ }
+
+ return false;
+}
+
void options::
_parse (::cli::scanner& s,
::cli::unknown_mode opt_mode,
@@ -946,13 +1042,7 @@ _parse (::cli::scanner& s,
continue;
}
- _cli_options_map::const_iterator i (
- opt ? _cli_options_map_.find (o) : _cli_options_map_.end ());
-
- if (i != _cli_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- }
+ if (opt && _parse (o, s));
else if (opt && std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
{
switch (opt_mode)
diff --git a/cli/options.hxx b/cli/options.hxx
index a7a7094..8042669 100644
--- a/cli/options.hxx
+++ b/cli/options.hxx
@@ -8,6 +8,7 @@
#include <deque>
#include <iosfwd>
#include <string>
+#include <cstddef>
#include <exception>
namespace cli
@@ -239,13 +240,37 @@ namespace cli
public:
argv_file_scanner (int& argc,
char** argv,
- const std::string& file_option,
+ const std::string& option,
+ bool erase = false);
+
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const std::string& option,
bool erase = false);
+ struct option_info
+ {
+ // If search_func is not NULL, it is called, with the arg
+ // value as the second argument, to locate the options file.
+ // If it returns an empty string, then the file is ignored.
+ //
+ const char* option;
+ std::string (*search_func) (const char*, void* arg);
+ void* arg;
+ };
+
+ argv_file_scanner (int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase = false);
+
argv_file_scanner (int start,
int& argc,
char** argv,
- const std::string& file_option,
+ const option_info* options,
+ std::size_t options_count,
bool erase = false);
virtual bool
@@ -261,12 +286,19 @@ namespace cli
skip ();
private:
+ const option_info*
+ find (const char*) const;
+
void
- load (const char* file);
+ load (const std::string& file);
typedef argv_scanner base;
const std::string option_;
+ option_info option_info_;
+ const option_info* options_;
+ std::size_t options_count_;
+
std::string hold_;
std::deque<std::string> args_;
bool skip_;
@@ -284,7 +316,6 @@ namespace cli
class options
{
public:
-
options (int& argc,
char** argv,
bool erase = false,
@@ -319,7 +350,6 @@ class options
// Option accessors.
//
-
const bool&
help () const;
@@ -356,6 +386,9 @@ class options
const std::size_t&
option_length () const;
+ const bool&
+ exclude_base () const;
+
const std::string&
cli_namespace () const;
@@ -427,6 +460,14 @@ class options
static void
print_usage (::std::ostream&);
+ // Implementation details.
+ //
+ protected:
+ options ();
+
+ bool
+ _parse (const char*, ::cli::scanner&);
+
private:
void
_parse (::cli::scanner&,
@@ -446,6 +487,7 @@ class options
bool suppress_usage_;
bool long_usage_;
std::size_t option_length_;
+ bool exclude_base_;
std::string cli_namespace_;
bool generate_cxx_;
bool generate_man_;
diff --git a/cli/options.ixx b/cli/options.ixx
index f2072fe..05c9f9a 100644
--- a/cli/options.ixx
+++ b/cli/options.ixx
@@ -141,8 +141,12 @@ namespace cli
bool erase)
: argv_scanner (argc, argv, erase),
option_ (option),
+ options_ (&option_info_),
+ options_count_ (1),
skip_ (false)
{
+ option_info_.option = option_.c_str ();
+ option_info_.search_func = 0;
}
inline argv_file_scanner::
@@ -153,6 +157,37 @@ namespace cli
bool erase)
: argv_scanner (start, argc, argv, erase),
option_ (option),
+ options_ (&option_info_),
+ options_count_ (1),
+ skip_ (false)
+ {
+ option_info_.option = option_.c_str ();
+ option_info_.search_func = 0;
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase)
+ : argv_scanner (argc, argv, erase),
+ options_ (options),
+ options_count_ (options_count),
+ skip_ (false)
+ {
+ }
+
+ inline argv_file_scanner::
+ argv_file_scanner (int start,
+ int& argc,
+ char** argv,
+ const option_info* options,
+ std::size_t options_count,
+ bool erase)
+ : argv_scanner (start, argc, argv, erase),
+ options_ (options),
+ options_count_ (options_count),
skip_ (false)
{
}
@@ -233,6 +268,12 @@ option_length () const
return this->option_length_;
}
+inline const bool& options::
+exclude_base () const
+{
+ return this->exclude_base_;
+}
+
inline const std::string& options::
cli_namespace () const
{
diff --git a/cli/parser.cxx b/cli/parser.cxx
index 9cefdbc..00803f2 100644
--- a/cli/parser.cxx
+++ b/cli/parser.cxx
@@ -32,7 +32,8 @@ const char* keywords[] =
"double"
};
-const char* punctuation[] = {";", ",", "::", "{", "}", /*"(", ")",*/ "=", "|"};
+const char* punctuation[] = {
+ ";", ",", ":", "::", "{", "}", /*"(", ")",*/ "=", "|"};
// Output the token type and value in a format suitable for diagnostics.
//
@@ -412,17 +413,75 @@ class_def ()
throw error ();
}
- auto_restore<scope> new_scope (scope_);
-
+ class_* n (0);
if (valid_)
{
- class_& n (root_->new_node<class_> (*path_, t.line (), t.column ()));
- root_->new_edge<names> (*scope_, n, t.identifier ());
- new_scope.set (&n);
+ n = &root_->new_node<class_> (*path_, t.line (), t.column ());
+ root_->new_edge<names> (*scope_, *n, t.identifier ());
}
t = lexer_->next ();
+ // inheritance-spec
+ //
+ if (t.punctuation () == token::p_colon)
+ {
+ for (;;)
+ {
+ t = lexer_->next ();
+ size_t line (t.line ()), col (t.column ());
+
+ string name;
+ if (!qualified_name (t, name))
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
+ << "expected qualified name instead of " << t << endl;
+ throw error ();
+ }
+
+ string ns;
+
+ // If it is a fully-qualifed name, then start from the global namespace.
+ // Otherwise, from the current scope.
+ //
+ if (name[0] == ':')
+ name = string (name, 2, string::npos);
+ else
+ ns = scope_->fq_name ();
+
+ if (class_* b = lookup<class_> (ns, name))
+ root_->new_edge<inherits> (*n, *b);
+ else
+ {
+ cerr << *path_ << ':' << line << ':' << col << ": error: "
+ << "unable to resolve base class '" << name << "'" << endl;
+ valid_ = false;
+ }
+
+ if (t.punctuation () != token::p_comma)
+ break;
+ }
+ }
+
+ // abstract-spec
+ //
+ if (t.punctuation () == token::p_eq)
+ {
+ t = lexer_->next ();
+
+ if (t.type () != token::t_int_lit || t.literal () != "0")
+ {
+ cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
+ << "expected '0' instead of " << t << endl;
+ throw error ();
+ }
+
+ if (n != 0)
+ n->abstract (true);
+
+ t = lexer_->next ();
+ }
+
if (t.punctuation () != token::p_lcbrace)
{
cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: "
@@ -430,11 +489,13 @@ class_def ()
throw error ();
}
+ auto_restore<scope> new_scope (scope_, n);
+
// decl-seq
//
t = lexer_->next ();
- while (true)
+ for (;;)
{
try
{
@@ -494,7 +555,7 @@ option_def (token& t)
// option-name-seq
//
names::name_list nl;
- while (true)
+ for (;;)
{
switch (t.type ())
{
@@ -780,7 +841,7 @@ qualified_name (token& t, string& r)
t = lexer_->next ();
}
- while (true)
+ for (;;)
{
if (t.type () != token::t_identifier)
{
@@ -1189,3 +1250,108 @@ fundamental_type (token& t, string& r)
return true;
}
+
+template <typename T>
+T* parser::
+lookup (string const& ss, string const& name, cli_unit* unit, bool outer)
+{
+ if (unit == 0)
+ unit = cur_;
+
+ // Resolve the starting scope in this unit, if any.
+ //
+ string::size_type b (0), e;
+ scope* s (0);
+
+ do
+ {
+ e = ss.find ("::", b);
+ string n (ss, b, e == string::npos ? e : e - b);
+
+ if (n.empty ())
+ s = unit;
+ else
+ {
+ scope::names_iterator_pair ip (s->find (n));
+
+ for (s = 0; ip.first != ip.second; ++ip.first)
+ if (s = dynamic_cast<scope*> (&ip.first->named ()))
+ break;
+
+ if (s == 0)
+ break; // No such scope in this unit.
+ }
+
+ b = e;
+
+ if (b == string::npos)
+ break;
+
+ b += 2;
+ } while (true);
+
+ // If we have the starting scope, then try to resolve the name in it.
+ //
+ if (s != 0)
+ {
+ b = 0;
+
+ do
+ {
+ e = name.find ("::", b);
+ string n (name, b, e == string::npos ? e : e - b);
+
+ scope::names_iterator_pair ip (s->find (n));
+
+ // If this is the last name, then see if we have the desired type.
+ //
+ if (e == string::npos)
+ {
+ for (; ip.first != ip.second; ++ip.first)
+ if (T* r = dynamic_cast<T*> (&ip.first->named ()))
+ return r;
+ }
+ // Otherwise, this should be a scope.
+ //
+ else
+ {
+ for (s = 0; ip.first != ip.second; ++ip.first)
+ if (s = dynamic_cast<scope*> (&ip.first->named ()))
+ break;
+
+ if (s == 0)
+ break; // No such inner scope.
+ }
+
+ b = e;
+
+ if (b == string::npos)
+ break;
+
+ b += 2;
+ } while (true);
+ }
+
+ // If we are here, then that means the lookup didn't find anything in
+ // this unit. The next step is to examine all the included units.
+ //
+ for (cli_unit::includes_iterator i (unit->includes_begin ());
+ i != unit->includes_end ();
+ ++i)
+ {
+ if (cli_includes* ci = dynamic_cast<cli_includes*> (&*i))
+ if (T* r = lookup<T> (ss, name, &ci->includee (), false))
+ return r;
+ }
+
+ // If we still haven't found anything, then the next step is to search
+ // one-outer scope, unless it is the global namespace.
+ //
+ if (outer && !ss.empty ())
+ {
+ string n (ss, 0, ss.rfind ("::"));
+ return lookup<T> (n, name, unit, false);
+ }
+
+ return 0;
+}
diff --git a/cli/parser.hxx b/cli/parser.hxx
index c93b9a0..34d3450 100644
--- a/cli/parser.hxx
+++ b/cli/parser.hxx
@@ -56,6 +56,25 @@ private:
void
recover (token& t);
+ // Lookup a name in the specified starting scope. Empty scope denotes
+ // the global namespace. Starting scope should be a fully-qualified
+ // name while name can be qualified but should not be fully-qualified
+ // (to lookup a fully-qualified name use the global namespace as the
+ // starting scope).
+ //
+ // If starting unit is not specified, the lookup is performed in the
+ // current unit. It then continues in all the units that the starting
+ // unit includes, transitively.
+ //
+ // The outer flag specifies whether to search the outer scopes.
+ //
+ template <typename T>
+ T*
+ lookup (std::string const& scope,
+ std::string const& name,
+ semantics::cli_unit* unit = 0,
+ bool outer = true);
+
private:
bool valid_;
semantics::path const* path_;
diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx
index a1cf114..f0b3cc1 100644
--- a/cli/runtime-header.cxx
+++ b/cli/runtime-header.cxx
@@ -364,7 +364,7 @@ generate_runtime_header (context& ctx)
<< "bool flag," << endl
<< "const std::string& default_value);"
<< endl
- << "private:"
+ << "private:" << endl
<< "std::string name_;"
<< "option_names aliases_;"
<< "bool flag_;"
@@ -381,7 +381,7 @@ generate_runtime_header (context& ctx)
<< endl
<< "void" << endl
<< "push_back (const option&);"
- << "private:"
+ << "private:" << endl
<< "typedef std::map<std::string, container_type::size_type> map_type;"
<< "map_type map_;"
<< "};";
diff --git a/cli/semantics/class.cxx b/cli/semantics/class.cxx
index 1af31dc..9a6fc85 100644
--- a/cli/semantics/class.cxx
+++ b/cli/semantics/class.cxx
@@ -19,9 +19,21 @@ namespace semantics
{
using compiler::type_info;
- type_info ti (typeid (class_));
- ti.add_base (typeid (scope));
- insert (ti);
+ // inherits
+ //
+ {
+ type_info ti (typeid (inherits));
+ ti.add_base (typeid (edge));
+ insert (ti);
+ }
+
+ // class_
+ //
+ {
+ type_info ti (typeid (class_));
+ ti.add_base (typeid (scope));
+ insert (ti);
+ }
}
} init_;
}
diff --git a/cli/semantics/class.hxx b/cli/semantics/class.hxx
index be0b9f9..f5f12c8 100644
--- a/cli/semantics/class.hxx
+++ b/cli/semantics/class.hxx
@@ -6,17 +6,101 @@
#ifndef CLI_SEMANTICS_CLASS_HXX
#define CLI_SEMANTICS_CLASS_HXX
+#include <vector>
+
#include <semantics/elements.hxx>
namespace semantics
{
+ class class_;
+
+ class inherits: public edge
+ {
+ public:
+ class_&
+ base () const
+ {
+ return *base_;
+ }
+
+ class_&
+ derived () const
+ {
+ return *derived_;
+ }
+
+ public:
+ void
+ set_left_node (class_& n)
+ {
+ derived_ = &n;
+ }
+
+ void
+ set_right_node (class_& n)
+ {
+ base_ = &n;
+ }
+
+ protected:
+ class_* base_;
+ class_* derived_;
+ };
+
class class_: public scope
{
+ private:
+ typedef std::vector<inherits*> inherits_list;
+
+ public:
+ bool
+ abstract () const
+ {
+ return abstract_;
+ }
+
+ void
+ abstract (bool a)
+ {
+ abstract_ = a;
+ }
+
+ public:
+ typedef pointer_iterator<inherits_list::const_iterator> inherits_iterator;
+
+ inherits_iterator
+ inherits_begin () const
+ {
+ return inherits_.begin ();
+ }
+
+ inherits_iterator
+ inherits_end () const
+ {
+ return inherits_.end ();
+ }
+
public:
class_ (path const& file, size_t line, size_t column)
- : node (file, line, column)
+ : node (file, line, column), abstract_ (false)
+ {
+ }
+
+ void
+ add_edge_left (inherits& e)
{
+ inherits_.push_back (&e);
}
+
+ void
+ add_edge_right (inherits&) {}
+
+ using scope::add_edge_left;
+ using scope::add_edge_right;
+
+ private:
+ bool abstract_;
+ inherits_list inherits_;
};
}
diff --git a/cli/semantics/elements.cxx b/cli/semantics/elements.cxx
index 04d6e03..3e87248 100644
--- a/cli/semantics/elements.cxx
+++ b/cli/semantics/elements.cxx
@@ -9,6 +9,19 @@
namespace semantics
{
+ // nameable
+ //
+ string nameable::
+ fq_name () const
+ {
+ string const& n (name ());
+
+ if (n.empty ())
+ return n;
+ else
+ return scope ().fq_name () + "::" + n;
+ }
+
// scope
//
diff --git a/cli/semantics/elements.hxx b/cli/semantics/elements.hxx
index 6dd6f78..e650f37 100644
--- a/cli/semantics/elements.hxx
+++ b/cli/semantics/elements.hxx
@@ -254,12 +254,21 @@ namespace semantics
return named_->name ();
}
+ string
+ fq_name () const;
+
scope_type&
scope ()
{
return named_->scope ();
}
+ scope_type const&
+ scope () const
+ {
+ return named_->scope ();
+ }
+
names&
named ()
{
diff --git a/cli/source.cxx b/cli/source.cxx
index 1d1726e..d49caf8 100644
--- a/cli/source.cxx
+++ b/cli/source.cxx
@@ -279,7 +279,7 @@ namespace
// If we have both the long and the short descriptions, use
// the short one. Otherwise, use the first sentence from the
- // long one ubless --long-usage was specified.
+ // long one unless --long-usage was specified.
//
string d;
@@ -429,11 +429,66 @@ namespace
//
//
+ struct base_parse: traversal::class_, context
+ {
+ base_parse (context& c): context (c) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << escape (c.name ()) << " base" << endl
+ << "//" << endl
+ << "if (" << fq_name (c) << "::_parse (o, s))" << endl
+ << "return true;"
+ << endl;
+ }
+ };
+
+ //
+ //
+ struct base_desc: traversal::class_, context
+ {
+ base_desc (context& c): context (c) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << escape (c.name ()) << " base" << endl
+ << "//" << endl
+ << fq_name (c) << "::fill (os);"
+ << endl;
+ }
+ };
+
+ struct base_usage: traversal::class_, context
+ {
+ base_usage (context& c): context (c) {}
+
+ virtual void
+ traverse (type& c)
+ {
+ os << "// " << escape (c.name ()) << " base" << endl
+ << "//" << endl
+ << fq_name (c) << "::print_usage (os);"
+ << endl;
+ }
+ };
+
+ //
+ //
struct class_: traversal::class_, context
{
class_ (context& c)
- : context (c), option_map_ (c), option_desc_ (c)
+ : context (c),
+ base_parse_ (c),
+ base_desc_ (c),
+ base_usage_ (c),
+ option_map_ (c),
+ option_desc_ (c)
{
+ inherits_base_parse_ >> base_parse_;
+ inherits_base_desc_ >> base_desc_;
+ inherits_base_usage_ >> base_usage_;
names_option_map_ >> option_map_;
names_option_desc_ >> option_desc_;
}
@@ -442,7 +497,10 @@ namespace
traverse (type& c)
{
string name (escape (c.name ()));
+
+ bool abst (c.abstract ());
bool ho (has<semantics::option> (c));
+ bool hb (c.inherits_begin () != c.inherits_end ());
os << "// " << name << endl
<< "//" << endl
@@ -453,94 +511,109 @@ namespace
string um (cli + "::unknown_mode");
os << name << "::" << endl
- << name << " (int& argc," << endl
- << "char** argv," << endl
- << "bool erase," << endl
- << um << " opt," << endl
- << um << " arg)";
+ << name << " ()";
{
option_init init (*this);
traversal::names names_init (init);
names (c, names_init);
}
os << "{"
- << cli << "::argv_scanner s (argc, argv, erase);"
- << "_parse (s, opt, arg);"
<< "}";
- os << name << "::" << endl
- << name << " (int start," << endl
- << "int& argc," << endl
- << "char** argv," << endl
- << "bool erase," << endl
- << um << " opt," << endl
- << um << " arg)";
+ if (!abst)
{
- option_init init (*this);
- traversal::names names_init (init);
- names (c, names_init);
- }
- os << "{"
- << cli << "::argv_scanner s (start, argc, argv, erase);"
- << "_parse (s, opt, arg);"
- << "}";
+ os << name << "::" << endl
+ << name << " (int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << cli << "::argv_scanner s (argc, argv, erase);"
+ << "_parse (s, opt, arg);"
+ << "}";
- os << name << "::" << endl
- << name << " (int& argc," << endl
- << "char** argv," << endl
- << "int& end," << endl
- << "bool erase," << endl
- << um << " opt," << endl
- << um << " arg)";
- {
- option_init init (*this);
- traversal::names names_init (init);
- names (c, names_init);
- }
- os << "{"
- << cli << "::argv_scanner s (argc, argv, erase);"
- << "_parse (s, opt, arg);"
- << "end = s.end ();"
- << "}";
+ os << name << "::" << endl
+ << name << " (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "bool erase," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << cli << "::argv_scanner s (start, argc, argv, erase);"
+ << "_parse (s, opt, arg);"
+ << "}";
- os << name << "::" << endl
- << name << " (int start," << endl
- << "int& argc," << endl
- << "char** argv," << endl
- << "int& end," << endl
- << "bool erase," << endl
- << um << " opt," << endl
- << um << " arg)";
- {
- option_init init (*this);
- traversal::names names_init (init);
- names (c, names_init);
- }
- os << "{"
- << cli << "::argv_scanner s (start, argc, argv, erase);"
- << "_parse (s, opt, arg);"
- << "end = s.end ();"
- << "}";
+ os << name << "::" << endl
+ << name << " (int& argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << "bool erase," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << cli << "::argv_scanner s (argc, argv, erase);"
+ << "_parse (s, opt, arg);"
+ << "end = s.end ();"
+ << "}";
- os << name << "::" << endl
- << name << " (" << cli << "::scanner& s," << endl
- << um << " opt," << endl
- << um << " arg)";
- {
- option_init init (*this);
- traversal::names names_init (init);
- names (c, names_init);
+ os << name << "::" << endl
+ << name << " (int start," << endl
+ << "int& argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << "bool erase," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << cli << "::argv_scanner s (start, argc, argv, erase);"
+ << "_parse (s, opt, arg);"
+ << "end = s.end ();"
+ << "}";
+
+ os << name << "::" << endl
+ << name << " (" << cli << "::scanner& s," << endl
+ << um << " opt," << endl
+ << um << " arg)";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "_parse (s, opt, arg);"
+ << "}";
}
- os << "{"
- << "_parse (s, opt, arg);"
- << "}";
// Usage.
//
if (usage)
{
+ bool b (hb && !options.exclude_base ());
+
os << "void " << name << "::" << endl
- << "print_usage (::std::ostream&" << (ho ? " os" : "") << ")"
+ << "print_usage (::std::ostream&" << (ho || b ? " os" : "") << ")"
<< "{";
// Calculate option length.
@@ -548,12 +621,61 @@ namespace
size_t len (0);
{
semantics::option* o (0);
- option_length t (*this, len, o);
- traversal::names n (t);
- names (c, n);
-
size_t max (options.option_length ());
+ // We need to go into our bases unless --exclude-base was
+ // specified.
+ //
+ {
+ traversal::class_ ct;
+ option_length olt (*this, len, o);
+ traversal::inherits i;
+ traversal::names n;
+
+ if (b)
+ ct >> i >> ct;
+
+ ct >> n >> olt;
+ ct.traverse (c);
+
+ // Now do the same for each base and issue a warning if any
+ // base has shorter option length than derived.
+ //
+ if (b && max == 0)
+ {
+ size_t d_len (len);
+ semantics::option* d_o (o);
+
+ for (type::inherits_iterator i (c.inherits_begin ());
+ i != c.inherits_end (); ++i)
+ {
+ type& b (i->base ());
+
+ len = 0;
+ ct.traverse (b);
+
+ if (len == d_len)
+ continue;
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " warning: derived class option length is greater "
+ << "than that of a base class '" << b.name () << "'"
+ << endl;
+
+ cerr << b.file () << ":" << b.line () << ":" << b.column ()
+ << " note: class '" << b.name () << "' is defined here"
+ << endl;
+
+ cerr << c.file () << ":" << c.line () << ":" << c.column ()
+ << " note: use --option-length to specify uniform length"
+ << endl;
+ }
+
+ len = d_len;
+ o = d_o;
+ }
+ }
+
if (max != 0)
{
if (len > max)
@@ -568,6 +690,11 @@ namespace
}
}
+ // Call our bases.
+ //
+ if (b)
+ inherits (c, inherits_base_usage_);
+
// Print option usage.
//
{
@@ -591,15 +718,26 @@ namespace
os << "struct " << desc << "_init"
<< "{"
<< desc << "_init (" << cli << "::options& os)"
+ << "{"
+ << name << "::fill (os);"
+ << "}"
+ << "};";
+
+ os << "static " << desc << "_init " << desc << "_init_ (" <<
+ desc << "_);"
+ << endl;
+
+ os << "void " << name << "::" << endl
+ << "fill (" << cli << "::options& " << (ho || hb ? " os)" : ")")
<< "{";
+ // Add the entries from our bases first so that our entires
+ // override any conflicts.
+ //
+ inherits (c, inherits_base_desc_);
names (c, names_option_desc_);
- os << "}"
- << "};"
- << "static " << desc << "_init " << desc << "_init_ (" <<
- desc << "_);"
- << endl;
+ os << "}";
os << "const " << cli << "::options& " << name << "::" << endl
<< "description ()"
@@ -608,7 +746,7 @@ namespace
<< "};";
}
- // _parse()
+ // _parse ()
//
string map ("_cli_" + name + "_map");
@@ -632,57 +770,93 @@ namespace
<< "static " << map << "_init " << map << "_init_;"
<< endl;
- bool pfx (!opt_prefix.empty ());
- bool sep (!opt_sep.empty ());
-
- os << "void " << name << "::" << endl
- << "_parse (" << cli << "::scanner& s," << endl
- << um << " opt_mode," << endl
- << um << " arg_mode)"
- << "{";
-
- if (sep)
- os << "bool opt = true;" // Still recognizing options.
- << endl;
-
- os << "while (s.more ())"
+ os << "bool " << name << "::" << endl
+ << "_parse (const char* o, " << cli << "::scanner& s)"
<< "{"
- << "const char* o = s.peek ();";
-
- if (sep)
- os << endl
- << "if (std::strcmp (o, \"" << opt_sep << "\") == 0)"
- << "{"
- << "s.skip ();" // We don't want to remove the separator.
- << "opt = false;"
- << "continue;"
- << "}"
- << map << "::const_iterator i (" << endl
- << "opt ? " << map << "_.find (o) : " << map << "_.end ());";
- else
- os << map << "::const_iterator i (" << map << "_.find (o));";
-
- os << endl
+ << map << "::const_iterator i (" << map << "_.find (o));"
+ << endl
<< "if (i != " << map << "_.end ())"
<< "{"
<< "(*(i->second)) (*this, s);"
+ << "return true;"
<< "}";
- // Unknown option.
+ // Try our bases, from left-to-right.
//
- if (pfx)
+ inherits (c, inherits_base_parse_);
+
+ os << "return false;"
+ << "}";
+
+ if (!abst)
{
- size_t n (opt_prefix.size ());
+ bool pfx (!opt_prefix.empty ());
+ bool sep (!opt_sep.empty ());
- os << "else if (";
+ os << "void " << name << "::" << endl
+ << "_parse (" << cli << "::scanner& s," << endl
+ << um << " opt_mode," << endl
+ << um << " arg_mode)"
+ << "{";
if (sep)
- os << "opt && ";
+ os << "bool opt = true;" // Still recognizing options.
+ << endl;
- os << "std::strncmp (o, \"" << opt_prefix << "\", " <<
- n << ") == 0 && o[" << n << "] != '\\0')"
+ os << "while (s.more ())"
<< "{"
- << "switch (opt_mode)"
+ << "const char* o = s.peek ();";
+
+ if (sep)
+ os << endl
+ << "if (std::strcmp (o, \"" << opt_sep << "\") == 0)"
+ << "{"
+ << "s.skip ();" // We don't want to remove the separator.
+ << "opt = false;"
+ << "continue;"
+ << "}";
+
+ os << "if (" << (sep ? "opt && " : "") << "_parse (o, s));";
+
+ // Unknown option.
+ //
+ if (pfx)
+ {
+ size_t n (opt_prefix.size ());
+
+ os << "else if (";
+
+ if (sep)
+ os << "opt && ";
+
+ os << "std::strncmp (o, \"" << opt_prefix << "\", " <<
+ n << ") == 0 && o[" << n << "] != '\\0')"
+ << "{"
+ << "switch (opt_mode)"
+ << "{"
+ << "case " << cli << "::unknown_mode::skip:" << endl
+ << "{"
+ << "s.skip ();"
+ << "continue;"
+ << "}"
+ << "case " << cli << "::unknown_mode::stop:" << endl
+ << "{"
+ << "break;"
+ << "}"
+ << "case " << cli << "::unknown_mode::fail:" << endl
+ << "{"
+ << "throw " << cli << "::unknown_option (o);"
+ << "}"
+ << "}" // switch
+ << "break;" // The stop case.
+ << "}";
+ }
+
+ // Unknown argument.
+ //
+ os << "else"
+ << "{"
+ << "switch (arg_mode)"
<< "{"
<< "case " << cli << "::unknown_mode::skip:" << endl
<< "{"
@@ -695,41 +869,27 @@ namespace
<< "}"
<< "case " << cli << "::unknown_mode::fail:" << endl
<< "{"
- << "throw " << cli << "::unknown_option (o);"
+ << "throw " << cli << "::unknown_argument (o);"
<< "}"
<< "}" // switch
<< "break;" // The stop case.
+ << "}"
+
+ << "}" // for
<< "}";
}
-
- // Unknown argument.
- //
- os << "else"
- << "{"
- << "switch (arg_mode)"
- << "{"
- << "case " << cli << "::unknown_mode::skip:" << endl
- << "{"
- << "s.skip ();"
- << "continue;"
- << "}"
- << "case " << cli << "::unknown_mode::stop:" << endl
- << "{"
- << "break;"
- << "}"
- << "case " << cli << "::unknown_mode::fail:" << endl
- << "{"
- << "throw " << cli << "::unknown_argument (o);"
- << "}"
- << "}" // switch
- << "break;" // The stop case.
- << "}"
-
- << "}" // for
- << "}";
}
private:
+ base_parse base_parse_;
+ traversal::inherits inherits_base_parse_;
+
+ base_desc base_desc_;
+ traversal::inherits inherits_base_desc_;
+
+ base_usage base_usage_;
+ traversal::inherits inherits_base_usage_;
+
option_map option_map_;
traversal::names names_option_map_;
diff --git a/cli/token.hxx b/cli/token.hxx
index cfa3afd..22679d3 100644
--- a/cli/token.hxx
+++ b/cli/token.hxx
@@ -77,6 +77,7 @@ public:
{
p_semi,
p_comma,
+ p_colon,
p_dcolon,
p_lcbrace,
p_rcbrace,
diff --git a/cli/traversal/class.cxx b/cli/traversal/class.cxx
index 8262e5d..3f178b6 100644
--- a/cli/traversal/class.cxx
+++ b/cli/traversal/class.cxx
@@ -7,15 +7,38 @@
namespace traversal
{
+ // inherits
+ //
+ void inherits::
+ traverse (type& i)
+ {
+ dispatch (i.base ());
+ }
+
+ // class_
+ //
void class_::
traverse (type& c)
{
pre (c);
+ inherits (c);
names (c);
post (c);
}
void class_::
+ inherits (type& c)
+ {
+ inherits (c, *this);
+ }
+
+ void class_::
+ inherits (type& c, edge_dispatcher& d)
+ {
+ iterate_and_dispatch (c.inherits_begin (), c.inherits_end (), d);
+ }
+
+ void class_::
pre (type&)
{
}
diff --git a/cli/traversal/class.hxx b/cli/traversal/class.hxx
index ef4433e..37f5f64 100644
--- a/cli/traversal/class.hxx
+++ b/cli/traversal/class.hxx
@@ -11,6 +11,15 @@
namespace traversal
{
+ struct inherits: edge<semantics::inherits>
+ {
+ inherits () {}
+ inherits (node_dispatcher& n) {node_traverser (n);}
+
+ virtual void
+ traverse (type&);
+ };
+
struct class_: scope_template<semantics::class_>
{
virtual void
@@ -20,6 +29,12 @@ namespace traversal
pre (type&);
virtual void
+ inherits (type&);
+
+ virtual void
+ inherits (type&, edge_dispatcher&);
+
+ virtual void
post (type&);
};
}