Minor doku updates
[senf.git] / Console / Parse.hh
index 892c522..1c11053 100644 (file)
 #include <boost/iterator/iterator_facade.hpp>
 #include <boost/function.hpp>
 #include "../Utils/safe_bool.hh"
+#include "../Utils/Exception.hh"
 
 //#include "Parse.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -209,20 +210,21 @@ namespace console {
     /** \brief Single argument token
 
         All command arguments are split into tokens by the parser. Each token is returned as an
-        ArgumentToken instance. 
+        Token instance. 
 
         \ingroup console_parser
       */
-    class ArgumentToken
+    class Token
     {
     public:
         enum TokenType { 
-            PathSeparator       = 0x0001,
-            ArgumentGroupOpen   = 0x0002,
-            ArgumentGroupClose  = 0x0004,
-            DirectoryGroupOpen  = 0x0008,
-            DirectoryGroupClose = 0x0010,
-            CommandTerminator   = 0x0020,
+            None                = 0,
+            PathSeparator       = 0x0001, // '/'
+            ArgumentGroupOpen   = 0x0002, // '('
+            ArgumentGroupClose  = 0x0004, // ')'
+            DirectoryGroupOpen  = 0x0008, // '{'
+            DirectoryGroupClose = 0x0010, // '}'
+            CommandTerminator   = 0x0020, // ';'
             OtherPunctuation    = 0x0040,
             BasicString         = 0x0080,
             HexString           = 0x0100,
@@ -250,6 +252,10 @@ namespace console {
                                 | HexString
         };
         
+        Token();                        ///< Create empty token
+        Token(TokenType type, std::string token); ///< Create token with given type and value
+
+
         std::string const & value() const; ///< String value of token
                                         /**< This value is properly unquoted */
 
@@ -258,33 +264,78 @@ namespace console {
         bool is(unsigned tokens) const; ///< Check, whether tokens type matches \a tokens
                                         /**< \a tokens is a bit-mask of token types to check. */
 
+        bool operator==(Token const & other) const;
+        bool operator!=(Token const & other) const;
+
     protected:
 
     private:
-        ArgumentToken(TokenType type, std::string token);
-
         TokenType type_;
         std::string token_;
-
-        friend class detail::ParserAccess;
     };
 
+    std::ostream & operator<<(std::ostream & os, Token const & token);
+
+    /** \brief Create a \c None token
+        \related Token */
+    Token NoneToken();
+
+    /** \brief Create a \c PathSeparator ['/'] token
+        \related Token */
+    Token PathSeparatorToken();
+
+    /** \brief Create an \c ArgumentGroupOpen ['('] token
+        \related Token */
+    Token ArgumentGroupOpenToken();
+
+    /** \brief Create a \c ArgumentGroupClose [')'] token
+        \related Token */
+    Token ArgumentGroupCloseToken();
+
+    /** \brief Create a \c DirectoryGroupOpen ['{'] token
+        \related Token */
+    Token DirectoryGroupOpenToken();
+
+    /** \brief Create a \c DirectoryGroupClose ['}'] token
+        \related Token */
+    Token DirectoryGroupCloseToken();
+
+    /** \brief Create a \c CommandTerminator [';'] token
+        \related Token */
+    Token CommandTerminatorToken();
+
+    /** \brief Create a \c OtherPunctuation ['=', ','] token with the given \a value
+        \related Token */
+    Token OtherPunctuationToken(std::string const & value);
+
+    /** \brief Create a \c BasicString token with the given \a value
+        \related Token */
+    Token BasicStringToken(std::string const & value);
+
+    /** \brief Create a \c HexString token with the given \a value
+        \related Token */
+    Token HexStringToken(std::string const & value);
+
+    /** \brief Create a \c Word token with the given \a value
+        \related Token */
+    Token WordToken(std::string const & value);
+
     /** \brief Single parsed console command
 
         Every command parsed is returned in a ParseCommandInfo instance. This information is purely
         taken from the parser, no semantic information is attached at this point, the config/console
-        node tree is not involved in any why. ParseCommandInfo consist of
+        node tree is not involved in any way. ParseCommandInfo consist of
         
         \li the type of command: built-in or normal command represented by a possibly relative path
             into the command tree.
         \li the command
-        \li the arguments. Every argument consists of a range of ArgumentToken instances.
+        \li the arguments. Every argument consists of a range of Token instances.
 
         \ingroup console_parser
       */
     class ParseCommandInfo
     {
-        typedef std::vector<ArgumentToken> Tokens;
+        typedef std::vector<Token> Tokens;
         typedef std::vector<std::string> CommandPath;
 
     public:
@@ -307,10 +358,12 @@ namespace console {
                               BuiltinEXIT,
                               BuiltinHELP };
 
+        ParseCommandInfo();
+
         BuiltinCommand builtin() const; ///< Command type
                                         /**< \returns \c NoBuiltin, if the command is an ordinary
                                              command, otherwise the id of the built-in command */
-        CommandPathRange commandPath() const; ///< Command path
+        TokensRange commandPath() const; ///< Command path
                                         /**< This is the path to the command if it is not a built-in
                                              command. Every element of the returned range
                                              constitutes one path element. If the first element is
@@ -323,21 +376,27 @@ namespace console {
         TokensRange tokens() const;     ///< All argument tokens
                                         /**< The returned range contains \e all argument tokens in a
                                              single range not divided into separate arguments. */
+
+        void clear();                   ///< Clear all data members
+        bool empty();                   ///< \c true, if the data is empty
+
+        void builtin(BuiltinCommand builtin); ///< Assign builtin command 
+        void command(std::vector<Token> & commandPath); ///< Assign non-builtin command
+
+        void addToken(Token const & token); ///< Add argument token
+                                        /**< You \e must ensure, that the resulting argument tokens
+                                             are properly nested regarding '()' groups, otherwise
+                                             interpreting arguments using the arguments() call will
+                                             crash the program. */
+
     protected:
 
     private:
-        void init();
-        void setBuiltin(BuiltinCommand builtin);
-        void setCommand(std::vector<std::string> & commandPath);
-        void addToken(ArgumentToken const & token);
-
         struct MakeRange;
 
-        std::vector<std::string> commandPath_;
+        std::vector<Token> commandPath_;
         BuiltinCommand builtin_;
         Tokens tokens_;
-
-        friend class detail::ParserAccess;
     };
 
     /** \brief Iterator parsing argument groups
@@ -380,17 +439,9 @@ namespace console {
         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_;
-    };
+    struct SyntaxErrorException : public senf::Exception
+    { explicit SyntaxErrorException(std::string const & msg = "syntax error") 
+          : senf::Exception(msg) {} };
 
     /** \brief Wrapper checking argument iterator access for validity
         
@@ -485,7 +536,7 @@ namespace console {
         
         using IteratorFacade::operator++;
         ParseCommandInfo::ArgumentIterator operator++(int);
-        
+
     private:
         reference dereference() const;
         void increment();
@@ -515,8 +566,6 @@ namespace console {
             some special iterator adaptors from Boost.Spirit. However, the amount of backtracking
             needs to be analyzed before this is viable.
 
-        \todo Implement more detailed error reporting and error recovery.
-
         \ingroup console_parser
       */
     class CommandParser
@@ -538,17 +587,45 @@ namespace console {
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        bool parse(std::string command, Callback cb); ///< Parse string
-        bool parseFile(std::string filename, Callback cb); ///< Parse file
+        void parse(std::string const & command, Callback cb); ///< Parse string
+        void parseFile(std::string const & filename, Callback cb); ///< Parse file
                                         /**< \throws SystemException if the file cannot be
                                              read. */
 
+        void parseArguments(std::string const & arguments, ParseCommandInfo & info);
+                                        ///< Parse \a arguments
+                                        /**< parseArguments() parses the string \a arguments which
+                                             contains arbitrary command arguments (without the name
+                                             of the command). The argument tokens are written into
+                                             \a info. */
+
+        std::string::size_type parseIncremental(std::string const & commands, Callback cb);
+                                        ///< Incremental parse
+                                        /**< An incremental parse will parse all complete statements
+                                             in \a commands. parseIncremental() will return the
+                                             number of characters successfully parsed from \a
+                                             commands. 
+                                             
+                                             \note The incremental parser \e requires all statements
+                                                 to be terminated explicitly. This means, that the
+                                                 last ';' is \e not optional in this case. */
+
+        /** \brief Exception thrown when the parser detects an error */
+        struct ParserErrorException : public SyntaxErrorException
+        { explicit ParserErrorException(std::string const & msg) : SyntaxErrorException(msg) {} };
+
     private:
         struct Impl;
+        struct SetIncremental;
+
+        template <class Iterator>
+        Iterator parseLoop(Iterator b, Iterator e, std::string const & source, Callback cb);
 
         Impl & impl();
 
         boost::scoped_ptr<Impl> impl_;
+
+        friend class SetIncremental;
     };
 
 }}