3#include "elementa/license.inc"
4#include "elementa/checks.inc"
6#ifndef ELEMENTA_PARSING_EXPRESSIONS_H
7#define ELEMENTA_PARSING_EXPRESSIONS_H
68 using Ptr = std::shared_ptr<ExprElement>;
73 class PList:
public std::list<Ptr>
78 using Base = std::list<Ptr>;
114 bool isDatum(
void)
const noexcept {
return(
kind() == Kind::kDatum); }
121 {
return(
kind() == Kind::kGroupOpen); }
125 {
return(
kind() == Kind::kGroupClose); }
133 {
return(
kind() == Kind::kArgsOpen); }
137 {
return(
kind() == Kind::kArgsClose); }
145 {
return(
kind() == Kind::kArgsSep); }
152 virtual Kind
kind(
void)
const = 0;
157 virtual int type(
void)
const {
return(-1); }
160 virtual std::string to_string(
void)
const
161 {
return(KindEnum::IdName(
kind())); }
173 Kind
kind(
void)
const {
return(Kind::kGroupOpen); }
182 Kind
kind(
void)
const {
return(Kind::kGroupClose); }
190 Kind
kind(
void)
const {
return(Kind::kArgsOpen); }
198 Kind
kind(
void)
const {
return(Kind::kArgsClose); }
206 Kind
kind(
void)
const {
return(Kind::kArgsSep); }
238 using Base = std::vector<int>;
242 std::string to_string(
void)
const;
256 Kind
kind(
void)
const {
return(Kind::kOperation); }
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)); }
277 virtual bool inFixed(
void)
const {
return(
true); }
284 {
return(ArgsGroupOmitting::CannotOmit); }
334 {
const static ParamSpec nopps;
return(nopps); }
339 {
return(ArgsGroupOmitting::MustOmit); }
341 std::string to_string(
void)
const override {
return(
"NOP"); }
409 ExprOperElement::ParamSpec::Base::size_type,
430 ExprOperElement::ParamSpec::Base::size_type apos,
432 {
return(tparm == targ); }
439 {
return(proposed); }
449 std::string{
"Expression evaluation error. "} +
462 "Empty expression",details)}
473 UnexpEnd(
const std::string & details):
475 "Unexpected end of expression",details)}
488 "Grouping error",details)}
501 "Misused element",details)}
512 InvArgs(
const std::string & details):
514 "Invalid arguments",details)}
527 "Invalid number of results",details)}
552 ExprElement::Kind
kind(
void)
const
553 {
return(ExprElement::Kind::kDatum); }
574 groupopen_{groupopening},
575 groupclose_{groupclosing},
585 Base{std::move(elems)},
586 groupopen_{groupopening},
587 groupclose_{groupclosing},
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); }
595 {
if (
this != &oth) moveFrom(std::move(oth));
return(*
this); }
604 Order
order(
void)
const {
return(order_); }
727 using ConvIndex = std::pair<Order,Order>;
728 using MapOfConversions = std::map < ConvIndex ,
731 static const MapOfConversions mapofconvs_;
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);
A list of elements constitutes an expression.
virtual std::string to_string(void) const
Build a text with the sequence of elements.
std::list< Ptr > Base
Shortcut.
Specification of the parameters of an operation.
Base class for all errors that can be thrown during the execution.
Error: Invalid arguments of operation.
Error: Invalid result of expression.
Error: element used badly in expression.
A class to wrap any expression datum or complete operation as a datum.
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'.
ExprElement::Kind kind(void) const
Return datum since in a tree everything is dealt with as a datum.
char what
'd' -> datum from postfix, 'o' -> scanned operation
Error: unexpected end of expression.
const char * explanation(void) const noexcept
Return the explanation only. It will live as long as this exception.
Base class for all errors / exceptions in Elementa. Just derive from it.
#define ELE_CLASS_EXCOVERRIDE(C)
Shortening macro that must be used inside classes derived from Exc.
#define ELE_CODE_INVSTATE(expl)
To throw an invalid-state exception with an explanation.
std::function< ExprElement::Ptr(const ExprElement::Ptr &, const ExprElement::PList &) > Evaluator
An evaluator function of a given operation or datum.
ExprElement::PList Base
Shortcut.
bool isClosingGrouping(void) const noexcept
Return TRUE if the element is a closing grouping.
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.
virtual ExprElement::Ptr argsClosing(void) const
Return the closing argument element for this operation.
unsigned char arity(void) const
Return the arity -number of arguments- of the operation (from 0 on).
virtual bool inFixed(void) const
Return whether the op. must be in infix form if arity == 2 when in InFix.
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
bool isOpeningGrouping(void) const noexcept
Return TRUE if the element is an opening grouping.
bool isOpeningArgs(void) const noexcept
Return TRUE if the element is an opening args.
Order order(void) const
Return the current order of the expression.
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.
Base::size_type Length
Shortcut.
static bool defaultTypeCompatChecker(const ExprOperElement &oper, const ExprElement::Ptr &, ExprOperElement::ParamSpec::Base::size_type apos, int tparm, int targ)
Default compatibility checker.
std::shared_ptr< ExprElement > Ptr
A safe, polymorphic pointer to an element for container use.
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
static int defaultTypeConfirming(ExprOperElement &oper, const ExprOperElement::ParamSpec &actualproto, int proposed)
Default confirming routine that just return the proposed type.
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.
virtual ExprElement::Ptr argsOpening(void) const
Return the opening argument element for this operation.
ArgsGroupOmitting argGroupingsOmit(void) const override
Return how the args grouping are allowed to be in 0/1 arity ops.
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.
std::function< int(ExprOperElement &, const ExprOperElement::ParamSpec &, int) > TypeConfirming
An op result type confirming routine used when checking types.
bool isGroupingArgs(void) const noexcept
Return TRUE if the element is an args grouping.
Kind kind(void) const
Must return the kind of the element: datum, grouping or operation.
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.
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.
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.
bool isDatum(void) const noexcept
Return TRUE if the element is a datum (not a grouping).
bool withResult(void) const override
Can be overriden to return whether the operation produces a result.
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.
Kind kind(void) const
Return the kind of the element: an operation.
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.
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.
virtual bool withResult(void) const
Can be overriden to return whether the operation produces a result.
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.
bool reduce(Evaluator &evaluator)
Reduce the expression partial or totally.
virtual ExprElement::Ptr argsSeparating(void) const
Return the separating argument element for this operation.
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.
bool isOperation(void) const noexcept
Return TRUE if the element is an operation.
bool isClosingArgs(void) const noexcept
Return TRUE if the element is a closing args.
virtual int type(void) const
Can be overriden to return the type of the element (an int value).
An element within an expression. Elements are data, operations or groupings.
An element within an expression that is an operation with a fixed arity.
An operation that takes no arguments and does nothing.
A simple args-close expression element.
A simple args-open expression element.
A simple args-separator expression element.
A simple group-close expression element.
A simple group-open expression element.
A general expression composed of a number of elements of type Element.
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.