Sélectionner une révision Git
IrElement.hh 6,54 Kio
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <type_traits>
#include "Lib/Utils.hh"
#include "Lib/Script/FrontEnd/Token.hh"
#include "Lib/Script/FrontEnd/Tokens.hh"
#include "Lib/Script/FrontEnd/Location.hh"
namespace Vivy::Script
{
/* Structural And Declarative Objects */
class IrRoot; // A root, with all the needed modules, etc
class IrModule; // A module (single vvs file)
class IrAttribute; // Attribute placed on the module, function, etc
class IrImport; // An import statement
class IrOption; // An option to pass to jobs (no global vars)
/* Types */
class IrType;
class IrTAss; // Ass types, SYLLABE, LINE, etc
class IrTOption; // An option type, need to have the same shape
class IrTPrimitive; // Primitive types
/* Jobs */
class IrJob;
class IrImportedJob; // An imported job
/* Functions */
class IrFunction;
class IrImportedFunction; // A utility to hide the imported functions
/* Variables */
class IrVariable;
class IrVPrimitive; // A simple base variable
class IrVTable; // A variable with fields (a struct)
/* Instructions */
class IrInstruction;
class IrILoop; // Any loop
class IrIAffectation; // Variable affectation
class IrIReturn; // Return statement
class IrIDeclaration; // Variable declaration
class IrIConditional; // If/Else/Elif statements
/* Expression */
class IrExpression;
class IrEConstExpr; // A constant expression, known at compile time
class IrECall; // A function call
class IrECompOp; // A comparaison (!=, <=, ...)
class IrEArithmeticOp; // Simple operations (+, *, ...)
class IrELogicOp; // A logic operation (and, or, ...)
class IrEVariableRef; // Reference to a variable, local or argument
/* A signature for a callable element */
class IrCallableSignature;
/* Base class forward declaration needed for concepts */
class IrElement;
/*
** Base concept for an IR element class.
*/
template <typename T>
concept IrElementObject = std::is_base_of<IrElement, T>::value;
template <typename... T>
concept IrElementObjects = std::conjunction<std::is_base_of<IrElement, T>...>::value;
/*
** IrElementConstructible object. Used to create an element from
** the passed arguments (`typename... Args`).
*/
template <typename T, typename... Args>
concept IrElementConstructible = IrElementObject<T> && requires(T irElem, Args &&...args)
{
T(std::forward<Args>(args)...);
};
/*
** IrElementDefaultConstructible object. Used to create an element
** from nothing.
*/
template <typename T>
concept IrElementDefaultConstructible =
std::is_base_of<IrElement, T>::value && has_any_default_constructor<T>::value;
/*
** IrElementParsable object. Used for the create with the pointer
** to the tokens passed. Also removes the
** `virtual void parse(std::vector<Token>*)` abstract method.
*/
template <typename T>
concept IrElementParsable = std::is_base_of<IrElement, T>::value && requires(T irElem)
{
irElem.parse(new std::vector<Token>);
};
/* Base class definition: IrElement */
class IrElement {
IrElement *parentElement = nullptr;
IrAttribute *elementAttributes = nullptr;
std::vector<IrElement *> childElements;
protected:
IrElement() noexcept = default;
IrElement(IrElement *p) noexcept;
void detachElementFromParent() noexcept;
void addChild(IrElement *) noexcept;
void throwUnexpectedToken(const Token &tok) const;
public:
virtual ~IrElement() noexcept;
virtual const IrElement *parent() const noexcept;
virtual IrElement *parent() noexcept;
void setParent(IrElement *p) noexcept;
void setAttribute(IrAttribute *a) noexcept;
virtual std::string toString() const noexcept = 0;
/*
** Get attributes for an element!
*/
std::vector<StrV> attribute(const std::string &name) const noexcept;
std::vector<StrV> attribute(StrV name) const noexcept;
/*
** Create an IrElement by parsing a token stream representing the file.
** May throw an exception because parse is not noexcept. Always return a
** non null pointer, will throw an exception on failure.
**
** TODO: Use concepts IrElementParsable and IrElementConstructible.
*/
template <typename T>
requires IrElementParsable<T> && IrElementDefaultConstructible<T>
static T *create(IrElement *p, std::vector<Token> *tokens)
{
using DeleteCall = decltype(&IrElement::destroy<T>);
std::unique_ptr<T, DeleteCall> ret(new T, IrElement::destroy<T>);
ret->setParent(p != nullptr ? p : ret.get());
ret->parse(tokens);
return ret.release();
}
template <typename T, typename... Args>
requires IrElementConstructible<T, Args...> && IrElementParsable<T>
static T *create(IrElement *p, std::vector<Token> *tokens, Args &&...args)
{
using DeleteCall = decltype(&IrElement::destroy<T>);
std::unique_ptr<T, DeleteCall> ret(new T(std::forward<Args>(args)...),
IrElement::destroy<T>);
ret->setParent(p != nullptr ? p : ret.get());
ret->parse(tokens);
return ret.release();
}
template <typename T>
requires IrElementParsable<T>
static T *create(IrElement *p)
{
using DeleteCall = decltype(&IrElement::destroy<T>);
std::unique_ptr<T, DeleteCall> ret(new T, IrElement::destroy<T>);
ret->setParent(p != nullptr ? p : ret.get());
return ret.release();
}
template <typename T, typename... Args>
requires IrElementConstructible<T, Args...>
static T *create(IrElement *p, Args &&...args)
{
using DeleteCall = decltype(&IrElement::destroy<T>);
std::unique_ptr<T, DeleteCall> ret(new T(std::forward<Args>(args)...),
IrElement::destroy<T>);
ret->setParent(p != nullptr ? p : ret.get());
return ret.release();
}
/* A safer call to delete, to also remove the children from its parent */
template <typename T>
requires IrElementObject<T>
static void destroy(T *const e) noexcept
{
if (e != nullptr) {
e->detachElementFromParent();
delete e;
}
}
};
/*
** Define an IrElement sub-class. Sets the correct visibility for the
** constructors and add IrElement as a friend for the create static
** method.
*/
#define VIVY_IR_ELEMENT(clazz) \
protected: \
friend class IrElement; \
template <typename... T> friend struct HasAnyConstructor; \
\
private:
}