pianod2
multisource multiuser scriptable networked music player
parsnip_command.h
Go to the documentation of this file.
1 
10 #pragma once
11 
12 #include <string>
13 #include <memory>
14 #include <vector>
15 #include <unordered_map>
16 #include <exception>
17 #include <functional>
18 
19 #include "parsnip.h"
20 
21 namespace Parsnip {
23  class NumberOutOfRange : public Exception {
24  public:
25  inline NumberOutOfRange() : Exception ("Value out of range"){};
26  inline NumberOutOfRange (const std::string &value) : Exception ("Value out of range", value){};
27  };
28 
30  class NotNumeric : public Exception {
31  public:
32  inline NotNumeric() : Exception ("Not a number"){};
33  inline NotNumeric (const std::string &value) : Exception ("Not a number", value){};
34  };
35 
37  class InvalidValue : public Exception {
38  public:
39  inline InvalidValue() : Exception ("Invalid value"){};
40  inline InvalidValue (const std::string &value) : Exception ("Invalid value", value){};
41  };
42 
44  class IncompleteCommand : public Exception {
45  public:
46  inline IncompleteCommand() : Exception ("Incomplete command"){};
47  inline IncompleteCommand (const std::string &value) : Exception ("Incomplete command", value){};
48  };
49 
51  class RunOnCommand : public Exception {
52  public:
53  inline RunOnCommand() : Exception ("Run-on command"){};
54  inline RunOnCommand (const std::string &value) : Exception ("Run-on command", value){};
55  };
56 
58  class DuplicateOption : public Exception {
59  public:
60  inline DuplicateOption() : Exception ("Option respecified: "){};
61  inline DuplicateOption (const std::string &value) : Exception ("Option respecified", value){};
62  };
63 
65  class NoSchemaDefined : public Exception {
66  public:
67  inline NoSchemaDefined() : Exception ("No Schema defined: "){};
68  inline NoSchemaDefined (std::string command) : Exception ("No schema defined", command){};
69  inline NoSchemaDefined (const int command) : Exception ("No schema defined", std::to_string (command)){};
70  };
71 
72  extern const std::string EmptyString;
73 
77  void operator() (class Evaluator *free_me);
78  };
79  using EvaluatorRef = std::unique_ptr<class Evaluator, EvaluatorDeleter>;
80 
82  class OptionParser {
83  friend class OptionEvaluator;
84  friend class Schema;
85  public:
87 
88  public:
89  // Structure for defining new option patterns.
90  using Definitions = std::vector<const char *>;
91 
92  OptionParser() = default;
93  OptionParser (const Definitions &defs, class Parser * = nullptr);
94  void addOptions (const Definitions &defs, class Parser * = nullptr);
95  bool operator== (const OptionParser &) const;
96  };
97  using OptionParserRef = std::shared_ptr<OptionParser>;
98 
100  class Parser {
101  friend class OptionEvaluator;
102  friend class SchemaSet;
103  private:
105  using OptionParsers = std::unordered_map<std::string, OptionParserRef>;
107 
108  public:
109  using CommandId = int;
110  using StringType = std::string;
111 
112  // Structure for defining new parser patterns.
113  struct Definition {
115  const char *statement;
116  };
117  using Definitions = std::vector<Definition>;
118 
119  // Structure for evaluation results.
120  struct Result {
125  };
126 
127  Parser() = default;
128  Parser (const Definitions &defs);
129  virtual ~Parser() = default;
130  void addOptionParser (const std::string &name, const OptionParserRef &add);
131  void addStatements (const Definitions &defs);
132  Result evaluate (const StringType &command) const;
133  bool operator== (const Parser &) const;
134  inline bool operator!= (const Parser &other) const {
135  return !(*this == other);
136  }
137  };
138  using ParserRef = std::shared_ptr<Parser>;
139 
140  template <typename ReturnType, typename ContextType>
141  class Interpreter {
142  public:
143  virtual ReturnType interpret (Parser::CommandId command_id, const Parsnip::Data &parameters, ContextType context) = 0;
144  };
145 
146  // A parser that includes dispatching capabilities.
147  template <typename DispatchReturnType, typename DispatchContextType>
148  class Dispatcher {
149  protected:
151  public:
152  using ReturnType = DispatchReturnType;
153  using ContextType = DispatchContextType;
155  private:
156  std::unordered_map <Parser::CommandId, ExecutorType> handlers;
157 #ifndef NDEBUG
158  int parser_number = 0;
159  std::unordered_map <Parser::CommandId, int> mapping_check;
160 #endif
161  public:
163  void addHandler (const Parser::Definitions &defs, const ExecutorType &handler);
165  void addStatements (const Parser::Definitions &defs, ExecutorType handler);
166  ReturnType operator () (Parser::CommandId command_id, const Parsnip::Data &parameters, DispatchContextType context) const;
168  };
169 
171  class SchemaSet {
172  public:
173  using CommandId = int;
174  using CommandSchemas = std::unordered_map <CommandId, SchemaBaseRef>;
177  private:
180  void integrateSchema (const int, const class DictionarySchema &);
182  const SchemaBaseRef &getSchemaForCommand (CommandId command_id) const;
183 
184  public:
187  public:
188  SchemaSet (const class Parser &from);
189  void validate (const CommandId, const Data &) const;
190  std::ostream &dump (const std::string &intro, const CommandId command_id, std::ostream &target = std::clog) const;
191 
192  void addMember (const CommandId, const char *name, const SchemaBase &schema, bool mandatory = false,
193  const Dependencies &dependencies = Schema::NoDependencies);
194  void addMember (const char *name, const SchemaBase &schema, bool mandatory = false,
195  const Dependencies &dependencies = Schema::NoDependencies);
196  void replaceMember (const CommandId, const char *name, const SchemaBase &schema);
197  void removeMember (const CommandId, const char *name);
198  };
199  using SchemaSetRef = std::shared_ptr <SchemaSet>;
200 
201 
202  /*
203  *
204  * TEMPLATE IMPLEMENTATIONS
205  *
206  */
207 
208  /*
209  * Dispatcher
210  */
211 
214  template <typename DispatchReturnType, typename DispatchContextType>
216  : parser (par) {
217  }
218 
224  template <typename DispatchReturnType, typename DispatchContextType>
226 #ifndef NDEBUG
227  parser_number++;
228 #endif
229  for (auto &it : defs) {
230 #ifndef NDEBUG
231  if (mapping_check [it.command_id]) {
232  assert (mapping_check [it.command_id] == parser_number);
233  } else {
234  mapping_check [it.command_id] = parser_number;
235  }
236 #endif
237  handlers [it.command_id] = handler;
238  }
239  }
240 
241 
246  template <typename DispatchReturnType, typename DispatchContextType>
250  interpreter, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) };
251  addHandler (defs, handler);
252  }
253 
257  template <typename DispatchReturnType, typename DispatchContextType>
259  parser->addStatements (defs);
260  addHandler (defs, handler);
261  }
262 
268  template <typename DispatchReturnType, typename DispatchContextType>
270  const Parsnip::Data &parameters,
271  ContextType context) const {
272  return handlers.at (command_id) (command_id, parameters, context);
273  }
274 
279  template <typename DispatchReturnType, typename DispatchContextType>
281  ContextType context) const {
282  Parser::Result result = parser->evaluate (command);
283  return (*this) (result.command_id, result.parameters, context);
284  }
285 
286 } // namespace Parsnip
Generic data type.
Definition: parsnip.h:81
static const struct Parsnip::Data::dictionary_t Dictionary
Dictionary flag type/value.
Schema component for validating dictionaries.
Definition: parsnip_schema.h:307
Definition: parsnip_command.h:148
void addStatements(const Parser::Definitions &defs, ExecutorType handler)
Add statements to the parser and register their related handler.
Definition: parsnip_command.h:258
void addHandler(const Parser::Definitions &defs, const ExecutorType &handler)
Register handlers with the dispatcher.
Definition: parsnip_command.h:225
ReturnType operator()(Parser::CommandId command_id, const Parsnip::Data &parameters, DispatchContextType context) const
Dispatch a command to the executor/handler function.
Definition: parsnip_command.h:269
DispatchContextType ContextType
Definition: parsnip_command.h:153
int parser_number
Definition: parsnip_command.h:158
DispatchReturnType ReturnType
Definition: parsnip_command.h:152
std::unordered_map< Parser::CommandId, int > mapping_check
Definition: parsnip_command.h:159
Dispatcher(const ParserRef &parser)
Construct a dispatcher.
Definition: parsnip_command.h:215
std::unordered_map< Parser::CommandId, ExecutorType > handlers
Definition: parsnip_command.h:156
const ParserRef parser
Definition: parsnip_command.h:150
void addHandler(const Parser::Definitions &defs, Interpreter< DispatchReturnType, DispatchContextType > *interpreter)
Register handlers with the dispatcher.
Definition: parsnip_command.h:247
std::function< ReturnType(Parser::CommandId, const Parsnip::Data &, ContextType)> ExecutorType
Definition: parsnip_command.h:154
An option was supplied twice to an iterating option parser.
Definition: parsnip_command.h:58
DuplicateOption()
Definition: parsnip_command.h:60
DuplicateOption(const std::string &value)
Definition: parsnip_command.h:61
Evaluator base class.
Definition: parsnip_evaluate.h:30
Class representing issues related to serialization & parsing.
Definition: parsnip.h:41
More tokens were expected.
Definition: parsnip_command.h:44
IncompleteCommand()
Definition: parsnip_command.h:46
IncompleteCommand(const std::string &value)
Definition: parsnip_command.h:47
Definition: parsnip_command.h:141
virtual ReturnType interpret(Parser::CommandId command_id, const Parsnip::Data &parameters, ContextType context)=0
A token encountered was not one of the expected keywords.
Definition: parsnip_command.h:37
InvalidValue()
Definition: parsnip_command.h:39
InvalidValue(const std::string &value)
Definition: parsnip_command.h:40
A schema is not defined for a certain command ID.
Definition: parsnip_command.h:65
NoSchemaDefined(std::string command)
Definition: parsnip_command.h:68
NoSchemaDefined(const int command)
Definition: parsnip_command.h:69
NoSchemaDefined()
Definition: parsnip_command.h:67
Not numeric: A command pattern specified a number, but the token was not valid number.
Definition: parsnip_command.h:30
NotNumeric()
Definition: parsnip_command.h:32
NotNumeric(const std::string &value)
Definition: parsnip_command.h:33
NumberOutOfRange: The number was outside the range defined in the command pattern.
Definition: parsnip_command.h:23
NumberOutOfRange()
Definition: parsnip_command.h:25
NumberOutOfRange(const std::string &value)
Definition: parsnip_command.h:26
Evaluate remainder with a different parser.
Definition: parsnip_evaluate.h:315
A class for parsing command line options (name-value pairs, for instance).
Definition: parsnip_command.h:82
void addOptions(const Definitions &defs, class Parser *=nullptr)
Register new option patterns.
Definition: parsnip_command.cpp:454
bool operator==(const OptionParser &) const
Definition: parsnip_command.cpp:468
EvaluatorRef evaluator
Definition: parsnip_command.h:86
std::vector< const char * > Definitions
Definition: parsnip_command.h:90
A class for parsing command lines.
Definition: parsnip_command.h:100
std::string StringType
Definition: parsnip_command.h:110
OptionParsers option_parsers
Definition: parsnip_command.h:106
std::vector< Definition > Definitions
Definition: parsnip_command.h:117
bool operator!=(const Parser &other) const
Definition: parsnip_command.h:134
std::unordered_map< std::string, OptionParserRef > OptionParsers
Definition: parsnip_command.h:105
Result evaluate(const StringType &command) const
Evaluate a command.
Definition: parsnip_command.cpp:424
void addStatements(const Definitions &defs)
Add statements to the parser.
Definition: parsnip_command.cpp:399
Parser()=default
bool operator==(const Parser &) const
Check if a parser is identical to another parser.
Definition: parsnip_command.cpp:435
EvaluatorRef evaluator
Definition: parsnip_command.h:104
int CommandId
Definition: parsnip_command.h:109
virtual ~Parser()=default
void addOptionParser(const std::string &name, const OptionParserRef &add)
Register an options parser for use.
Definition: parsnip_command.cpp:415
There were extra tokens at the end of the command pattern.
Definition: parsnip_command.h:51
RunOnCommand(const std::string &value)
Definition: parsnip_command.h:54
RunOnCommand()
Definition: parsnip_command.h:53
Definition: parsnip_schema.h:28
Smart pointer for schemas, with unusual ability to be copied.
Definition: parsnip.h:601
Schema for one JSON object.
Definition: parsnip.h:612
static const Dependencies NoDependencies
Definition: parsnip.h:617
std::set< std::string > Dependencies
Definition: parsnip.h:616
std::unordered_map< class OptionParser *, SchemaRef > OptionSchemas
Definition: parsnip.h:615
A schema built to validate JSON messages based on command line patterns.
Definition: parsnip_command.h:171
SchemaBaseRef & getSchemaForCommand(CommandId command_id)
Get a schema by ID.
Definition: parsnip_schema.cpp:1263
void addMember(const CommandId, const char *name, const SchemaBase &schema, bool mandatory=false, const Dependencies &dependencies=Schema::NoDependencies)
Modify a schema by adding a new dictionary member.
Definition: parsnip_schema.cpp:1319
SchemaSet(const class Parser &from)
Construct schemas from a parser.
Definition: parsnip_schema.cpp:1226
void integrateSchema(const int, const class DictionarySchema &)
Callback function, invoked when generating schemas from a Parser.
Definition: parsnip_schema.cpp:1285
Schema::OptionSchemas OptionSchemas
Definition: parsnip_command.h:175
Schema::Dependencies Dependencies
Definition: parsnip_command.h:176
std::ostream & dump(const std::string &intro, const CommandId command_id, std::ostream &target=std::clog) const
Dump the schema in human-readable format.
Definition: parsnip_schema.cpp:1305
void removeMember(const CommandId, const char *name)
Modify a schema by removing a dictionary member.
Definition: parsnip_schema.cpp:1354
void validate(const CommandId, const Data &) const
Validate data against a command's schema.
Definition: parsnip_schema.cpp:1297
OptionSchemas option_schemas
Schemas for each of the option parsers.
Definition: parsnip_command.h:186
void replaceMember(const CommandId, const char *name, const SchemaBase &schema)
Modify a schema by replacing dictionary member.
Definition: parsnip_schema.cpp:1347
int CommandId
Definition: parsnip_command.h:173
std::unordered_map< CommandId, SchemaBaseRef > CommandSchemas
Definition: parsnip_command.h:174
CommandSchemas schemas
Schemas for each unique command ID.
Definition: parsnip_command.h:179
Connection to a pianod client, along with context and state of that connection.
Definition: connection.h:54
A response collector/aggregator.
Definition: response.h:197
uint32_t value
Definition: audiooutput.cpp:68
Serialization and parsing library.
Definition: mediaunit.h:26
std::shared_ptr< OptionParser > OptionParserRef
Definition: parsnip_command.h:97
const std::string EmptyString
Definition: parsnip_command.cpp:128
std::unique_ptr< class Evaluator, EvaluatorDeleter > EvaluatorRef
Definition: parsnip_command.h:79
std::shared_ptr< SchemaSet > SchemaSetRef
Definition: parsnip_command.h:199
std::shared_ptr< Parser > ParserRef
Definition: parsnip_command.h:138
Parsnip serialization.
This does what std::default_delete would do, but is required since we haven't defined Evaluator yet.
Definition: parsnip_command.h:76
void operator()(class Evaluator *free_me)
Definition: parsnip_evaluate.cpp:31
Definition: parsnip_command.h:113
CommandId command_id
Definition: parsnip_command.h:114
const char * statement
Definition: parsnip_command.h:115
Definition: parsnip_command.h:120
CommandId command_id
< ID of command pattern that was matched.
Definition: parsnip_command.h:122
Parsnip::Data parameters
Parameters collected from the command line.
Definition: parsnip_command.h:124