Elementa v8.0.0
Minimalistic library for any C++ application (C++11 and up)
Loading...
Searching...
No Matches
expressions.h
Go to the documentation of this file.
1
3#include "elementa/license.inc"
4#include "elementa/checks.inc"
5
6#ifndef ELEMENTA_PARSING_EXPRESSIONS_H
7#define ELEMENTA_PARSING_EXPRESSIONS_H
8
9#include <limits>
10#include <vector>
11#include <list>
12#include <map>
13#include <memory>
14#include <string>
15#include <utility>
16#include <functional>
17#include "elementa/base/enums.h"
19
20namespace elementa
21{
22
23namespace parsing
24{
25
47/* ***************************************************************************
48
49 Abstract base classes: ExprElement, ExprOperElement
50 Concrete classes: ExprSimpleGroupOpen, ExprSimpleGroupClose, ExprOperNop
51
52*******************************************************************************/
53
55
61{
62 public:
63
68 using Ptr = std::shared_ptr<ExprElement>;
69
71
73 class PList: public std::list<Ptr>
74 {
75 public:
76
78 using Base = std::list<Ptr>;
79
81 using Base::Base;
82
84 virtual std::string to_string(void) const;
85 };
86
89 kDatum,
90 kGroupOpen,
91 kGroupClose,
92 kArgsOpen,
93 kArgsClose,
94 kArgsSep,
95 kOperation
96 );
97
105 virtual ~ExprElement(void) = default;
106
114 bool isDatum(void) const noexcept { return(kind() == Kind::kDatum); }
115
117 bool isOperation(void) const noexcept { return(kind() == Kind::kOperation);}
118
120 bool isOpeningGrouping(void) const noexcept
121 { return(kind() == Kind::kGroupOpen); }
122
124 bool isClosingGrouping(void) const noexcept
125 { return(kind() == Kind::kGroupClose); }
126
128 bool isGrouping(void) const noexcept
129 { return(isOpeningGrouping() || isClosingGrouping()); }
130
132 bool isOpeningArgs(void) const noexcept
133 { return(kind() == Kind::kArgsOpen); }
134
136 bool isClosingArgs(void) const noexcept
137 { return(kind() == Kind::kArgsClose); }
138
140 bool isGroupingArgs(void) const noexcept
141 { return(isOpeningArgs() || isClosingArgs()); }
142
144 bool isSepArgs(void) const noexcept
145 { return(kind() == Kind::kArgsSep); }
146
148 bool isDatumTypedAs(int ty) const noexcept
149 { return(isDatum() && (type() == ty)); }
150
152 virtual Kind kind(void) const = 0;
153
155
157 virtual int type(void) const { return(-1); }
158
159 // Can be overriden to return a more specific text version of the element.
160 virtual std::string to_string(void) const
161 { return(KindEnum::IdName(kind())); }
162
165};
166
167
170{
171 public:
172
173 Kind kind(void) const { return(Kind::kGroupOpen); }
174};
175
176
179{
180 public:
181
182 Kind kind(void) const { return(Kind::kGroupClose); }
183};
184
187{
188 public:
189
190 Kind kind(void) const { return(Kind::kArgsOpen); }
191};
192
195{
196 public:
197
198 Kind kind(void) const { return(Kind::kArgsClose); }
199};
200
203{
204 public:
205
206 Kind kind(void) const { return(Kind::kArgsSep); }
207};
208
210
217{
218 public:
219
224 ELE_CLASS_ENUM(ArgsGroupOmitting,
225 CanOmit,
226 MustOmit,
227 CannotOmit);
228
230
234 class ParamSpec: public std::vector<int>
235 {
236 public:
237
238 using Base = std::vector<int>;
239
240 using Base::Base;
241
242 std::string to_string(void) const;
243 };
244
246
247 using VectorOfParamSpecs = std::vector<ParamSpec>;
248
256 Kind kind(void) const { return(Kind::kOperation); }
257
259
262 unsigned char arity(void) const
263 { ParamSpec::size_type ps{prototype().size()};
264 if (ps == 0) return(0);
265 if (ps > static_cast<ParamSpec::size_type>(
266 std::numeric_limits<unsigned char>::max()))
268 "Operator with too many parameters (" + std::to_string(ps) +
269 ", prototype " + prototype().to_string() +
270 ") in its specification");
271 return(static_cast<unsigned char>(withResult() ? ps-1 : ps)); }
272
274
277 virtual bool inFixed(void) const { return(true); }
278
280
283 virtual ArgsGroupOmitting argGroupingsOmit(void) const
284 { return(ArgsGroupOmitting::CannotOmit); }
285
287 virtual ExprElement::Ptr argsOpening(void) const
288 { return(ExprElement::Ptr{new ExprSimpleArgsOpen{}}); }
289
291 virtual ExprElement::Ptr argsClosing(void) const
292 { return(ExprElement::Ptr{new ExprSimpleArgsClose{}}); }
293
295 virtual ExprElement::Ptr argsSeparating(void) const
296 { return(ExprElement::Ptr{new ExprSimpleArgsSep{}}); }
297
305
308 virtual const ParamSpec & prototype(void) const = 0;
309
311
316 virtual unsigned precedence(void) const = 0;
317
319
321 virtual bool withResult(void) const { return(true); }
322
325};
326
327
330{
331 public:
332
333 const ParamSpec & prototype(void) const
334 {const static ParamSpec nopps; return(nopps); }
335 unsigned precedence(void) const { return(0); } // ignored
336 bool withResult(void) const override { return(false); }
337
338 ArgsGroupOmitting argGroupingsOmit(void) const override
339 { return(ArgsGroupOmitting::MustOmit); }
340
341 std::string to_string(void) const override { return("NOP"); }
342
343};
344
345
346/* ***************************************************************************
347
348 Class: Expression
349
350*******************************************************************************/
351
353
355{
356 public:
357
363
365 using Length = Base::size_type;
366
368
375 kPostfix,
376 kInfix
377 );
378
380
394 using Evaluator =
395 std::function< ExprElement::Ptr(const ExprElement::Ptr &,
396 const ExprElement::PList &) >;
397
399
407 std::function< bool(const ExprOperElement &,
408 const ExprElement::Ptr &,
409 ExprOperElement::ParamSpec::Base::size_type,
410 int,int) >;
411
413
421 std::function< int(ExprOperElement &,
423 int) >;
424
426
428 const ExprOperElement & oper,
429 const ExprElement::Ptr &,
430 ExprOperElement::ParamSpec::Base::size_type apos,
431 int tparm, int targ)
432 { return(tparm == targ); }
433
436 ExprOperElement & oper,
437 const ExprOperElement::ParamSpec & actualproto,
438 int proposed)
439 { return(proposed); }
440
442
444 {
445 public:
446
447 EvalError(const std::string & explanation):
449 std::string{"Expression evaluation error. "} +
450 explanation} {}
451
453 };
454
456 class EmptyExpr: public EvalError
457 {
458 public:
459
460 EmptyExpr(const std::string & details):
462 "Empty expression",details)}
463 {}
464
466 };
467
469 class UnexpEnd: public EvalError
470 {
471 public:
472
473 UnexpEnd(const std::string & details):
475 "Unexpected end of expression",details)}
476 {}
477
479 };
480
483 {
484 public:
485
486 GroupingError(const std::string & details):
488 "Grouping error",details)}
489 {}
490
492 };
493
496 {
497 public:
498
499 MisusedElement(const std::string & details):
501 "Misused element",details)}
502 {}
503
505 };
506
508 class InvArgs: public EvalError
509 {
510 public:
511
512 InvArgs(const std::string & details):
514 "Invalid arguments",details)}
515 {}
516
518 };
519
521 class InvResult: public EvalError
522 {
523 public:
524
525 InvResult(const std::string & details):
527 "Invalid number of results",details)}
528 {}
529
531 };
532
534
540 {
541 public:
542
543 char what;
545 struct {
546 ExprElement::Ptr poper;
547 ExprElement::PList operands;
549
550
552 ExprElement::Kind kind(void) const
553 { return(ExprElement::Kind::kDatum); }
554
556 std::string to_string(void) const;
557 };
558
566
568 Expression(Order order = Order::kInfix,
569 const ExprElement::Ptr & groupopening =
571 const ExprElement::Ptr & groupclosing =
573 Base{},
574 groupopen_{groupopening},
575 groupclose_{groupclosing},
576 order_{order} {}
577
579
580 Expression(Order order, Base && elems,
581 const ExprElement::Ptr & groupopening =
583 const ExprElement::Ptr & groupclosing =
585 Base{std::move(elems)},
586 groupopen_{groupopening},
587 groupclose_{groupclosing},
588 order_{order} {}
589
590 Expression(const Expression & oth) { copyFrom(oth); }
591 Expression(Expression && oth) { moveFrom(std::move(oth)); }
592 Expression & operator=(const Expression & oth)
593 { if (this != &oth) copyFrom(oth); return(*this); }
594 Expression & operator=(Expression && oth)
595 { if (this != &oth) moveFrom(std::move(oth)); return(*this); }
596
604 Order order(void) const { return(order_); }
605
607
610
618
626 long checkGrouping(void) const;
627
629 long checkArgGrouping(void) const;
630
632
647 int checkType(Base::const_iterator & errloc,
649 const TypeConfirming & tcf = defaultTypeConfirming) const;
650
652
661 ExprElement::Ptr evaluate(Base::const_iterator & errloc,
662 Evaluator & evaluator) const;
663
665
671 bool reduce(Evaluator & evaluator);
672
680
704 void changeOrder(Order neword, bool forcegrouping = false);
705
707
708 void deleteNOPs(void);
709
711
715 void changeElements(const std::function< std::pair<bool,ExprElement::Ptr>
716 (ExprElement::Ptr &) > & pred);
717
719
720 void deleteElements(const std::function< bool(ExprElement::Ptr &) > & pred);
721
725 private:
726
727 using ConvIndex = std::pair<Order,Order>;
728 using MapOfConversions = std::map < ConvIndex ,
729 void (Expression::*)(bool) >;
730
731 static const MapOfConversions mapofconvs_;
732
733 ExprElement::Ptr groupopen_, groupclose_;
734 Order order_;
735
736 void copyFrom(const Expression & oth);
737 void moveFrom(Expression && oth);
738
739 void errorInvInPostfix(const std::string & context) const;
740 long checkGeneralGrouping(ExprElement::Kind kopen,
741 ExprElement::Kind kclose) const;
742 void infixToPostfix(bool forcegrouping);
743 void postfixToInfix(bool forcegrouping);
744};
745
746 // Expressions
748
749} // End parsing namespace
750
751} // End elementa namespace
752
753
754#endif
A list of elements constitutes an expression.
Definition: expressions.h:74
virtual std::string to_string(void) const
Build a text with the sequence of elements.
std::list< Ptr > Base
Shortcut.
Definition: expressions.h:78
Specification of the parameters of an operation.
Definition: expressions.h:235
Base class for all errors that can be thrown during the execution.
Definition: expressions.h:444
Error: Invalid arguments of operation.
Definition: expressions.h:509
Error: Invalid result of expression.
Definition: expressions.h:522
Error: element used badly in expression.
Definition: expressions.h:496
A class to wrap any expression datum or complete operation as a datum.
Definition: expressions.h:540
struct elementa::parsing::Expression::OpDatumWrapper::@2 oper
All operation data in original expression if 'o'.
std::string to_string(void) const
Return a one-line text representing the node.
ExprElement::Ptr pdatum
Datum in original expression if 'd'.
Definition: expressions.h:544
ExprElement::Kind kind(void) const
Return datum since in a tree everything is dealt with as a datum.
Definition: expressions.h:552
char what
'd' -> datum from postfix, 'o' -> scanned operation
Definition: expressions.h:543
Error: unexpected end of expression.
Definition: expressions.h:470
const char * explanation(void) const noexcept
Return the explanation only. It will live as long as this exception.
Definition: exceptions.h:164
Base class for all errors / exceptions in Elementa. Just derive from it.
Definition: exceptions.h:113
#define ELE_CLASS_EXCOVERRIDE(C)
Shortening macro that must be used inside classes derived from Exc.
Definition: exceptions.h:64
#define ELE_CODE_INVSTATE(expl)
To throw an invalid-state exception with an explanation.
Definition: exceptions.h:306
std::function< ExprElement::Ptr(const ExprElement::Ptr &, const ExprElement::PList &) > Evaluator
An evaluator function of a given operation or datum.
Definition: expressions.h:396
ExprElement::PList Base
Shortcut.
Definition: expressions.h:362
bool isClosingGrouping(void) const noexcept
Return TRUE if the element is a closing grouping.
Definition: expressions.h:124
virtual unsigned precedence(void) const =0
Must return a number that indicates the precedence of the operation.
void deleteNOPs(void)
Delete all NOP operations.
virtual ArgsGroupOmitting argGroupingsOmit(void) const
Return how the args grouping are allowed to be in 0/1 arity ops.
Definition: expressions.h:283
virtual ExprElement::Ptr argsClosing(void) const
Return the closing argument element for this operation.
Definition: expressions.h:291
unsigned char arity(void) const
Return the arity -number of arguments- of the operation (from 0 on).
Definition: expressions.h:262
virtual bool inFixed(void) const
Return whether the op. must be in infix form if arity == 2 when in InFix.
Definition: expressions.h:277
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
Definition: expressions.h:206
bool isOpeningGrouping(void) const noexcept
Return TRUE if the element is an opening grouping.
Definition: expressions.h:120
bool isOpeningArgs(void) const noexcept
Return TRUE if the element is an opening args.
Definition: expressions.h:132
Order order(void) const
Return the current order of the expression.
Definition: expressions.h:604
Expression(Order order=Order::kInfix, const ExprElement::Ptr &groupopening=ExprElement::Ptr{new ExprSimpleGroupOpen{}}, const ExprElement::Ptr &groupclosing=ExprElement::Ptr{new ExprSimpleGroupClose{}})
Default constructor: empty expression in InFix.
Definition: expressions.h:568
Base::size_type Length
Shortcut.
Definition: expressions.h:365
static bool defaultTypeCompatChecker(const ExprOperElement &oper, const ExprElement::Ptr &, ExprOperElement::ParamSpec::Base::size_type apos, int tparm, int targ)
Default compatibility checker.
Definition: expressions.h:427
std::shared_ptr< ExprElement > Ptr
A safe, polymorphic pointer to an element for container use.
Definition: expressions.h:68
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
Definition: expressions.h:190
static int defaultTypeConfirming(ExprOperElement &oper, const ExprOperElement::ParamSpec &actualproto, int proposed)
Default confirming routine that just return the proposed type.
Definition: expressions.h:435
Expression(Order order, Base &&elems, const ExprElement::Ptr &groupopening=ExprElement::Ptr{new ExprSimpleGroupOpen{}}, const ExprElement::Ptr &groupclosing=ExprElement::Ptr{new ExprSimpleGroupClose{}})
Constructor from a list of elements assumed to be in the given order.
Definition: expressions.h:580
virtual ExprElement::Ptr argsOpening(void) const
Return the opening argument element for this operation.
Definition: expressions.h:287
ArgsGroupOmitting argGroupingsOmit(void) const override
Return how the args grouping are allowed to be in 0/1 arity ops.
Definition: expressions.h:338
ELE_CLASS_ENUM(ArgsGroupOmitting, CanOmit, MustOmit, CannotOmit)
Mode of omitting args groupings for operations of arity 0 or 1.
bool isSepArgs(void) const noexcept
Return TRUE if the element is a sep args.
Definition: expressions.h:144
std::function< int(ExprOperElement &, const ExprOperElement::ParamSpec &, int) > TypeConfirming
An op result type confirming routine used when checking types.
Definition: expressions.h:423
bool isGroupingArgs(void) const noexcept
Return TRUE if the element is an args grouping.
Definition: expressions.h:140
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
Definition: expressions.h:198
ExprElement::Ptr evaluate(Base::const_iterator &errloc, Evaluator &evaluator) const
Evaluate the expression using the given evaluator; only if postfix.
bool isDatumTypedAs(int ty) const noexcept
Return TRUE if the element is a datum of a given type.
Definition: expressions.h:148
long checkGrouping(void) const
Check grouping validity in the expression (not args-grouping).
void changeElements(const std::function< std::pair< bool, ExprElement::Ptr >(ExprElement::Ptr &) > &pred)
Change all elements in the expression that satisfy a predicate.
long checkArgGrouping(void) const
The same as checkGrouping but for the args-open and -close elements.
unsigned precedence(void) const
Must return a number that indicates the precedence of the operation.
Definition: expressions.h:335
ELE_CLASS_ENUM(Kind, kDatum, kGroupOpen, kGroupClose, kArgsOpen, kArgsClose, kArgsSep, kOperation)
Kind ot the elements.
void changeOrder(Order neword, bool forcegrouping=false)
Change the order of operations to NEWORD, if possible.
virtual ~ExprElement(void)=default
Just for polymorphic deletions.
int checkType(Base::const_iterator &errloc, const TypeCompatChecker &tcc=defaultTypeCompatChecker, const TypeConfirming &tcf=defaultTypeConfirming) const
Evaluate the type of the expression, returning the resulting type.
std::vector< ParamSpec > VectorOfParamSpecs
A number of specifications.
Definition: expressions.h:247
bool isDatum(void) const noexcept
Return TRUE if the element is a datum (not a grouping).
Definition: expressions.h:114
bool withResult(void) const override
Can be overriden to return whether the operation produces a result.
Definition: expressions.h:336
std::function< bool(const ExprOperElement &, const ExprElement::Ptr &, ExprOperElement::ParamSpec::Base::size_type, int, int) > TypeCompatChecker
An op arg type compatibility checker used when checking types.
Definition: expressions.h:410
Kind kind(void) const
Return the kind of the element: an operation.
Definition: expressions.h:256
virtual const ParamSpec & prototype(void) const =0
Must return a const reference to the specification of parms and return.
const ParamSpec & prototype(void) const
Must return a const reference to the specification of parms and return.
Definition: expressions.h:333
virtual Kind kind(void) const =0
Must return the kind of the element: datum, grouping or operation.
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
Definition: expressions.h:182
virtual bool withResult(void) const
Can be overriden to return whether the operation produces a result.
Definition: expressions.h:321
void deleteElements(const std::function< bool(ExprElement::Ptr &) > &pred)
Delete all elements in the expression that satisfy a predicate.
ExprElement::Ptr buildTree(void) const
Build a tree from the expression and return the root node.
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
Definition: expressions.h:173
bool reduce(Evaluator &evaluator)
Reduce the expression partial or totally.
virtual ExprElement::Ptr argsSeparating(void) const
Return the separating argument element for this operation.
Definition: expressions.h:295
ELE_CLASS_ENUM(Order, kPostfix, kInfix)
Kind of ordering in the expression.
bool isGrouping(void) const noexcept
Return TRUE if the element is a grouping.
Definition: expressions.h:128
bool isOperation(void) const noexcept
Return TRUE if the element is an operation.
Definition: expressions.h:117
bool isClosingArgs(void) const noexcept
Return TRUE if the element is a closing args.
Definition: expressions.h:136
virtual int type(void) const
Can be overriden to return the type of the element (an int value).
Definition: expressions.h:157
An element within an expression. Elements are data, operations or groupings.
Definition: expressions.h:61
An element within an expression that is an operation with a fixed arity.
Definition: expressions.h:217
An operation that takes no arguments and does nothing.
Definition: expressions.h:330
A simple args-close expression element.
Definition: expressions.h:195
A simple args-open expression element.
Definition: expressions.h:187
A simple args-separator expression element.
Definition: expressions.h:203
A simple group-close expression element.
Definition: expressions.h:179
A simple group-open expression element.
Definition: expressions.h:170
A general expression composed of a number of elements of type Element.
Definition: expressions.h:355
std::string concatWithMiddle(const std::string &s1, const std::string &s2, const std::string &m=". ")
Concatenate two strings putting a middle one only if the second is not empty.