X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FParse.hh;h=892c5222e9bf002a23345a5fff23939929563d34;hb=fa5eaa97c8593e3587c87f25adb14f7f91f31f37;hp=295f4a66b9e8230e2671662f7d6e8a4e7500c228;hpb=63c40810b93b4d8f3d6dad5f987adc5f2bf5b5ed;p=senf.git diff --git a/Console/Parse.hh b/Console/Parse.hh index 295f4a6..892c522 100644 --- a/Console/Parse.hh +++ b/Console/Parse.hh @@ -194,7 +194,9 @@ #include #include #include +#include #include +#include "../Utils/safe_bool.hh" //#include "Parse.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -214,14 +216,54 @@ namespace console { class ArgumentToken { public: + enum TokenType { + PathSeparator = 0x0001, + ArgumentGroupOpen = 0x0002, + ArgumentGroupClose = 0x0004, + DirectoryGroupOpen = 0x0008, + DirectoryGroupClose = 0x0010, + CommandTerminator = 0x0020, + OtherPunctuation = 0x0040, + BasicString = 0x0080, + HexString = 0x0100, + Word = 0x0200 + }; + + enum TokenGroup { + ArgumentGrouper = ArgumentGroupOpen + | ArgumentGroupClose, + + DirectoryGrouper = DirectoryGroupOpen + | DirectoryGroupClose, + + Punctuation = DirectoryGroupOpen + | DirectoryGroupClose + | PathSeparator + | CommandTerminator + | OtherPunctuation, + + String = BasicString + | HexString, + + SimpleArgument = Word + | BasicString + | HexString + }; + std::string const & value() const; ///< String value of token /**< This value is properly unquoted */ + TokenType type() const; ///< Token type + + bool is(unsigned tokens) const; ///< Check, whether tokens type matches \a tokens + /**< \a tokens is a bit-mask of token types to check. */ + protected: private: - explicit ArgumentToken(std::string token); + ArgumentToken(TokenType type, std::string token); + TokenType type_; std::string token_; friend class detail::ParserAccess; @@ -244,19 +286,14 @@ namespace console { { typedef std::vector Tokens; typedef std::vector CommandPath; - + public: + class ArgumentIterator; + typedef CommandPath::const_iterator path_iterator; typedef Tokens::const_iterator token_iterator; - typedef boost::iterator_range argument_value_type; - - - private: - typedef std::vector Arguments; - - public: - typedef Arguments::const_iterator argument_iterator; - typedef Arguments::size_type size_type; + typedef ArgumentIterator argument_iterator; + typedef Tokens::size_type size_type; typedef boost::iterator_range CommandPathRange; typedef boost::iterator_range ArgumentsRange; @@ -292,26 +329,174 @@ namespace console { void init(); void setBuiltin(BuiltinCommand builtin); void setCommand(std::vector & commandPath); - void startArgument(); - void endArgument(); void addToken(ArgumentToken const & token); - void finalize(); struct MakeRange; std::vector commandPath_; - - typedef std::pair TempArgumentRange; - typedef std::vector TempArguments; - BuiltinCommand builtin_; Tokens tokens_; - Arguments arguments_; - TempArguments tempArguments_; friend class detail::ParserAccess; }; + /** \brief Iterator parsing argument groups + + This special iterator parses a token range returned by the parser into argument ranges. An + argument range is either a single token or it is a range of tokens enclosed in matching + parenthesis. The ParseCommandInfo::arguments() uses this iterator type. To recursively parse + complex arguments, you can however use this iterator to divide a multi-token argument into + further argument groups (e.g. to parse a list or vector of items). + + This iterator is a bidirectional iterator \e not a random access iterator. + */ + class ParseCommandInfo::ArgumentIterator + : public boost::iterator_facade< ParseCommandInfo::ArgumentIterator, + ParseCommandInfo::TokensRange, + boost::bidirectional_traversal_tag, + ParseCommandInfo::TokensRange > + { + public: + ArgumentIterator(); + explicit ArgumentIterator(ParseCommandInfo::TokensRange::iterator i); + + private: + reference dereference() const; + bool equal(ArgumentIterator const & other) const; + void increment(); + void decrement(); + + mutable ParseCommandInfo::TokensRange::iterator b_; + mutable ParseCommandInfo::TokensRange::iterator e_; + + void setRange() const; + + friend class boost::iterator_core_access; + friend class ParseCommandInfo; + }; + + /** \brief Syntax error parsing command arguments exception + + All errors while parsing the arguments of a command must be signaled by throwing an instance + of SyntaxErrorException. This is important, so command overloading works. + */ + struct SyntaxErrorException : public std::exception + { + explicit SyntaxErrorException(std::string const & msg = ""); + virtual ~SyntaxErrorException() throw(); + + virtual char const * what() const throw(); + std::string const & message() const; + + private: + std::string message_; + }; + + /** \brief Wrapper checking argument iterator access for validity + + CheckedArgumentIteratorWrapper is a wrapper around a range of arguments parsed using the + ParseCommandInfo::ArgumentIterator. It is used to parse arguments either in a command + (registered with manual argument parsing) or when defining a custom parser. + \code + void fn(std::ostream & out, senf::console::ParseCommandInfo command) + { + std:;string arg1; + unsigned arg2 (0); + + { + senf::console::CheckedArgumentIteratorWrapper arg (command.arguments()); + senf::console::parse( *(arg++), arg1 ); + senf::console::parse( *(arg++), arg2 ); + } + + // ... + } + \endcode + + To use the wrapper, you must ensure that: + \li You increment the iterator \e past all arguments you parse. The iterator must point to + the end of the range when parsing is complete. + \li The iterator wrapper is destroyed after parsing but before executing the command itself + begins. + + Accessing a non-existent argument or failing to parse all arguments will raise a + senf::console::SyntaxErrorException. + + \see \link console_arg_custom Example customer parser \endlink + */ + class CheckedArgumentIteratorWrapper + : boost::noncopyable, + public boost::iterator_facade< CheckedArgumentIteratorWrapper, + ParseCommandInfo::TokensRange, + boost::forward_traversal_tag, + ParseCommandInfo::TokensRange >, + public senf::safe_bool + + { + typedef boost::iterator_facade< CheckedArgumentIteratorWrapper, + ParseCommandInfo::TokensRange, + boost::forward_traversal_tag, + ParseCommandInfo::TokensRange > IteratorFacade; + + public: + explicit CheckedArgumentIteratorWrapper( + ParseCommandInfo::ArgumentsRange const & range, + std::string const & msg = "invalid number of arguments"); + ///< Make wrapper from ArgumentsRange + /**< This constructs a wrapper from a + ParseCommandInfo::ArgumentsRange. + \param[in] range Range of arguments to parse + \param[in] msg Error message */ + explicit CheckedArgumentIteratorWrapper( + ParseCommandInfo::TokensRange const & range, + std::string const & msg = "invalid number of arguments"); + ///< Make wrapper from TokensRange + /**< This constructs a wrapper from a + ParseCommandInfo::TokensRange. The TokensRange is first + converted into an ParseCommandInfo::ArgumentsRange + which is then wrapped. + \param[in] range Range of tokens to parse + \param[in] msg Error message */ + + ~CheckedArgumentIteratorWrapper(); ///< Check, if all arguments are parsed + /**< The destructor validates, that all arguments are parsed + correctly when leaving the scope, in which the wrapper + is instantiated normally (not by an exception). + + \warning This destructor will throw a + SyntaxErrorException, if not all arguments are parsed + and when no other exception is in progress. */ + + operator ParseCommandInfo::ArgumentIterator(); + ///< Use wrapper as ParseCommandInfo::ArgumentIterator + + bool boolean_test() const; ///< \c true, if more arguments are available + bool done() const; ///< \c true, if all arguments are parsed + + void clear(); ///< Set range empty + /**< This call will point the current iterator to the end of + the tokens range. + \post done() == \c true; */ + + bool operator==(ParseCommandInfo::ArgumentIterator const & other) const; + ///< Compare wrapper against ArgumentIterator + bool operator!=(ParseCommandInfo::ArgumentIterator const & other) const; + ///< Compare wrapper against ArgumentIterator + + using IteratorFacade::operator++; + ParseCommandInfo::ArgumentIterator operator++(int); + + private: + reference dereference() const; + void increment(); + + ParseCommandInfo::ArgumentIterator i_; + ParseCommandInfo::ArgumentIterator e_; + std::string msg_; + + friend class boost::iterator_core_access; + }; + /**< \brief Output ParseCommandInfo instance \related ParseCommandInfo */