Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

759 lines
32 KiB
C++

// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
#pragma once
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <hilti/ast/builder/node-factory.h>
namespace hilti {
struct Options;
/**
* Builder wrapping an AST context to provide convenience factory methods for
* AST nodes.
*
* There are two types of factory methods:
*
* 1. All `create()` methods of any Node-derived class gets a corresponding
* method inside the builder that simply forwards all arguments, just adding
* the builder's AST context. This allows the caller to use an existing builder
* without needing to worry about the context parameter that all the
* `create()` method need. All the forwarding methods are defined in the
* auto-generated `builder::NodeFactory` base class.
*
* 2. Additional convenience methods constructing nodes that don't have a
* direct 1-to-1 equivalent in any `create()` method, including creating entire
* subtrees of nodes at once. These methods are defined directly in the
* `Builder` class.
*/
class Builder : public builder::NodeFactory {
public:
virtual ~Builder() = default;
/** Constructs a builder that will use a given context. */
Builder(ASTContext* ctx) : NodeFactory(ctx) { _static_state.block = statement::Block::create(ctx, {}, {}); }
/** Construct a builder that adds any flow-level nodes to a given pre-existing block. */
Builder(ASTContext* context, statement::Block* block) : NodeFactory(context) { _static_state.block = block; }
/**
* Returns the current block associated with the builder for creating
* flow-level nodes, or null if none.
*/
const auto& block() const { return _state->block; }
/** Shortcut to retrieve compiler options from the AST context. */
const Options& options() const;
/**
* Expresses the coercion of an expression into a target type. Note that
* the coercion will not be immediately performed, but just recorded to
* perform later during AST resolving. This version associated the source
* expressions meta data with the coercion.
*/
auto coerceTo(Expression* e, QualifiedType* t) { return expressionPendingCoerced(e, t, e->meta()); }
/**
* Expresses the coercion of an expression into a target type. Note that
* the coercion will not be immediately performed, but just recorded to
* perform later during AST resolving. This version associated custom meta
* data with the coercion.
*/
auto coerceTo(Expression* e, QualifiedType* t, const Meta& m) { return expressionPendingCoerced(e, t, m); }
//////// Helpers for operators
/** Constructs a node representing the main node for constructor call operator. */
auto ctorType(UnqualifiedType* t) { return typeType(qualifiedType(t, Constness::Const)); }
//////// Declarations
auto import(const std::string& module, const Meta& m = Meta()) {
return declarationImportedModule(hilti::ID(module), std::string(".hlt"), m);
}
auto import(const std::string& module, const std::string& parse_extension, const Meta& m = Meta()) {
return declarationImportedModule(hilti::ID(module), parse_extension, m);
}
auto import(const std::string& module, const std::string& parse_extension, ID search_scope,
const Meta& m = Meta()) {
return declarationImportedModule(hilti::ID(module), parse_extension, std::move(search_scope), m);
}
auto local(ID id_, QualifiedType* t, Meta m = Meta()) {
return statementDeclaration(declarationLocalVariable(std::move(id_), t, {}, std::move(m)));
}
auto local(ID id_, Expression* init, const Meta& m = Meta()) {
return statementDeclaration(declarationLocalVariable(std::move(id_), init, m));
}
auto local(ID id_, QualifiedType* t, Expression* init, Meta m = Meta()) {
return statementDeclaration(declarationLocalVariable(std::move(id_), t, init, std::move(m)));
}
auto local(ID id_, QualifiedType* t, Expressions args, Meta m = Meta()) {
return statementDeclaration(declarationLocalVariable(std::move(id_), t, std::move(args), {}, std::move(m)));
}
auto global(ID id_, QualifiedType* t, declaration::Linkage linkage = declaration::Linkage::Private,
Meta m = Meta()) {
return declarationGlobalVariable(std::move(id_), t, {}, linkage, std::move(m));
}
auto global(ID id_, Expression* init, declaration::Linkage linkage = declaration::Linkage::Private,
const Meta& m = Meta()) {
return declarationGlobalVariable(std::move(id_), init, linkage, m);
}
auto global(ID id_, QualifiedType* t, Expression* init,
declaration::Linkage linkage = declaration::Linkage::Private, Meta m = Meta()) {
return declarationGlobalVariable(std::move(id_), t, init, linkage, std::move(m));
}
auto global(ID id_, QualifiedType* t, Expressions args,
declaration::Linkage linkage = declaration::Linkage::Private, Meta m = Meta()) {
return declarationGlobalVariable(std::move(id_), t, std::move(args), {}, linkage, std::move(m));
}
auto type(ID id, QualifiedType* type, declaration::Linkage linkage = declaration::Linkage::Private,
Meta m = Meta()) {
return declarationType(std::move(id), type, linkage, std::move(m));
}
auto type(ID id, QualifiedType* type, AttributeSet* attrs,
declaration::Linkage linkage = declaration::Linkage::Private, Meta m = Meta()) {
return declarationType(std::move(id), type, attrs, linkage, std::move(m));
}
auto constant(ID id_, Expression* init, declaration::Linkage linkage = declaration::Linkage::Private,
Meta m = Meta()) {
return declarationConstant(std::move(id_), init, linkage, std::move(m));
}
auto parameter(ID id, UnqualifiedType* type, parameter::Kind kind = parameter::Kind::In, Meta m = Meta()) {
return declarationParameter(std::move(id), type, kind, {}, {}, std::move(m));
}
auto parameter(ID id, UnqualifiedType* type, Expression* default_, parameter::Kind kind = parameter::Kind::In,
Meta m = Meta()) {
return declarationParameter(std::move(id), type, kind, default_, {}, std::move(m));
}
template<typename... Params>
static auto parameters(Params&&... params) {
return std::vector<hilti::type::function::Parameter*>{std::forward<Params>(params)...};
}
using NodeFactory::function;
auto function(const ID& id, QualifiedType* result, const declaration::Parameters& params,
type::function::Flavor flavor = type::function::Flavor::Standard,
declaration::Linkage linkage = declaration::Linkage::Private,
function::CallingConvention cc = function::CallingConvention::Standard, AttributeSet* attrs = {},
const Meta& m = Meta()) {
auto ft = typeFunction(result, params, flavor, m);
auto f = function(id, ft, {}, cc, attrs, m);
return declarationFunction(f, linkage, m);
}
auto function(const ID& id, QualifiedType* result, const declaration::Parameters& params, Statement* body,
type::function::Flavor flavor = type::function::Flavor::Standard,
declaration::Linkage linkage = declaration::Linkage::Private,
function::CallingConvention cc = function::CallingConvention::Standard, AttributeSet* attrs = {},
const Meta& m = Meta()) {
auto ft = typeFunction(result, params, flavor, m);
auto f = function(id, ft, body, cc, attrs, m);
return declarationFunction(f, linkage, m);
}
auto function(const ID& id, type::Function* ftype, Statement* body,
declaration::Linkage linkage = declaration::Linkage::Private,
function::CallingConvention cc = function::CallingConvention::Standard, AttributeSet* attrs = {},
const Meta& m = Meta()) {
auto f = function(id, ftype, body, cc, attrs, m);
return declarationFunction(f, linkage, m);
}
//////// Types
auto typeTypeInfo(const Meta& m = Meta()) { return typeLibrary(Constness::Const, "hilti::rt::TypeInfo*", m); }
//////// Expressions
// Constructors.
auto id(const ID& id_, const Meta& m = Meta()) { return expressionName(id_, m); }
auto stringMutable(std::string_view s, const Meta& m = Meta()) {
return expressionCtor(ctorString({s.data(), s.size()}, false, m), m);
}
auto stringLiteral(std::string_view s, const Meta& m = Meta()) {
// String literals have no location.
return expressionCtor(ctorString({s.data(), s.size()}, true));
}
auto bool_(bool b, const Meta& m = Meta()) { return expressionCtor(ctorBool(b, m), m); }
auto bytes(std::string s, const Meta& m = Meta()) { return expressionCtor(ctorBytes(std::move(s), m), m); }
auto default_(UnqualifiedType* t, const Meta& m = Meta()) { return expressionCtor(ctorDefault(t, m), m); }
auto default_(UnqualifiedType* t, Expressions type_args, const Meta& m = Meta()) {
return expressionCtor(ctorDefault(t, std::move(type_args), m), m);
}
auto exception(UnqualifiedType* t, const std::string& msg, const Meta& m = Meta()) {
return expressionCtor(ctorException(t, stringLiteral(msg), m), m);
}
auto exception(UnqualifiedType* t, Expression* msg, const Meta& m = Meta()) {
return expressionCtor(ctorException(t, msg, m), m);
}
auto exception(UnqualifiedType* t, Expression* what, Expression* where, const Meta& m = Meta()) {
return expressionCtor(ctorException(t, what, where, m), m);
}
auto integer(int i, const Meta& m = Meta()) {
return expressionCtor(ctorSignedInteger(static_cast<int64_t>(i), 64, m), m);
}
auto integer(int64_t i, const Meta& m = Meta()) { return expressionCtor(ctorSignedInteger(i, 64, m), m); }
auto integer(unsigned int i, const Meta& m = Meta()) { return expressionCtor(ctorUnsignedInteger(i, 64, m), m); }
auto integer(uint64_t i, const Meta& m = Meta()) { return expressionCtor(ctorUnsignedInteger(i, 64, m), m); }
auto null(const Meta& m = Meta()) { return expressionCtor(ctorNull(m), m); }
auto optional(Expression* e, const Meta& m = Meta()) { return expressionCtor(ctorOptional(e, m), m); }
auto optional(QualifiedType* t, const Meta& m = Meta()) { return expressionCtor(ctorOptional(t, m), m); }
auto port(hilti::rt::Port p, const Meta& m = Meta()) { return expressionCtor(ctorPort(p, m), m); }
auto regexp(std::string p, AttributeSet* attrs = {}, const Meta& m = Meta()) {
return expressionCtor(ctorRegExp({std::move(p)}, attrs, m), m);
}
auto regexp(hilti::ctor::regexp::Patterns p, AttributeSet* attrs = {}, const Meta& m = Meta()) {
return expressionCtor(ctorRegExp(std::move(p), attrs, m), m);
}
auto stream(std::string s, const Meta& m = Meta()) { return expressionCtor(ctorStream(std::move(s), m), m); }
auto struct_(ctor::struct_::Fields f, const Meta& m = Meta()) {
return expressionCtor(ctorStruct(std::move(f), m), m);
}
auto struct_(ctor::struct_::Fields f, QualifiedType* t, const Meta& m = Meta()) {
return expressionCtor(ctorStruct(std::move(f), t, m), m);
}
auto tuple(const Expressions& v, const Meta& m = Meta()) { return expressionCtor(ctorTuple(v, m), m); }
auto vector(const Expressions& v, const Meta& m = Meta()) { return expressionCtor(ctorVector(v, m), m); }
auto vector(QualifiedType* t, Expressions v, const Meta& m = Meta()) {
return expressionCtor(ctorVector(t, std::move(v), m), m);
}
auto vector(QualifiedType* t, const Meta& m = Meta()) { return expressionCtor(ctorVector(t, {}, m), m); }
auto void_(const Meta& m = Meta()) { return expressionVoid(m); }
auto strongReference(QualifiedType* t, const Meta& m = Meta()) {
return expressionCtor(ctorStrongReference(t, m), m);
}
auto weakReference(QualifiedType* t, const Meta& m = Meta()) { return expressionCtor(ctorWeakReference(t, m), m); }
auto valueReference(Expression* e, const Meta& m = Meta()) { return expressionCtor(ctorValueReference(e, m), m); }
// Operator expressions
auto add(Expression* target, Expression* index, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Add, {target, index}, m);
}
auto and_(Expression* op0, Expression* op1, const Meta& m = Meta()) { return expressionLogicalAnd(op0, op1, m); }
auto or_(Expression* op0, Expression* op1, const Meta& m = Meta()) { return expressionLogicalOr(op0, op1, m); }
auto begin(Expression* e, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Begin, {e}, m);
}
auto cast(Expression* e, QualifiedType* dst, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Cast, {e, expressionType(dst)}, m);
}
auto delete_(Expression* self, const ID& field, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Delete, {self, expressionMember(field)}, m);
}
auto deref(Expression* e, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Deref, {e}, m);
}
auto end(Expression* e, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::End, {e}, m);
}
auto call(const ID& id_, const Expressions& v, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Call, {id(id_, m), tuple(v, m)}, m);
}
auto index(Expression* value, unsigned int index, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Index, {value, integer(index, m)}, m);
}
auto size(Expression* op, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Size, {op}, m);
}
auto modulo(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Modulo, {op1, op2}, m);
}
auto lowerEqual(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::LowerEqual, {op1, op2}, m);
}
auto greaterEqual(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::GreaterEqual, {op1, op2}, m);
}
auto lower(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Lower, {op1, op2}, m);
}
auto greater(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Greater, {op1, op2}, m);
}
auto equal(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Equal, {op1, op2}, m);
}
auto unequal(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Unequal, {op1, op2}, m);
}
auto member(Expression* self, const std::string& id_, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Member, {self, expressionMember(ID(id_), m)}, m);
}
auto hasMember(Expression* self, const std::string& id_, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::HasMember, {self, expressionMember(ID(id_), m)}, m);
}
auto tryMember(Expression* self, const std::string& id_, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::TryMember, {self, expressionMember(ID(id_), m)}, m);
}
auto memberCall(Expression* self, const std::string& id_, const Expressions& args = {}, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::MemberCall,
{self, expressionMember(ID(id_), m), tuple(args, m)}, m);
}
auto memberCall(Expression* self, const std::string& id_, ctor::Tuple* args, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::MemberCall,
{self, expressionMember(ID(id_), m), expressionCtor(args)}, m);
}
auto pack(QualifiedType* type, const Expressions& args, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Pack, {expressionType(type, m), tuple(args, m)}, m);
}
auto unpack(QualifiedType* type, const Expressions& args, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Unpack,
{expressionType(type, m), tuple(args, m), expressionCtor(ctorBool(false))},
m);
}
auto unset(Expression* self, const ID& field, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Unset, {self, expressionMember(field)}, m);
}
auto sumAssign(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::SumAssign, {op1, op2}, m);
}
auto differenceAssign(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::DifferenceAssign, {op1, op2}, m);
}
auto sum(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Sum, {op1, op2}, m);
}
auto difference(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Difference, {op1, op2}, m);
}
auto decrementPostfix(Expression* op, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::DecrPostfix, {op}, m);
}
auto decrementPrefix(Expression* op, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::DecrPrefix, {op}, m);
}
auto incrementPostfix(Expression* op, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::IncrPostfix, {op}, m);
}
auto incrementPrefix(Expression* op, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::IncrPrefix, {op}, m);
}
auto new_(UnqualifiedType* t, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::New,
{expressionType(qualifiedType(t, hilti::Constness::Const), m),
expressionCtor(ctorTuple({}, m))},
m);
}
auto new_(UnqualifiedType* t, const Expressions& args, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::New,
{expressionType(qualifiedType(t, hilti::Constness::Const), m),
expressionCtor(ctorTuple(args, m))},
m);
}
auto division(Expression* op1, Expression* op2, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Division, {op1, op2}, m);
}
// Other expressions
auto expression(Ctor* c, const Meta& m = Meta()) { return expressionCtor(c, m); }
auto expression(const Location& l) { return stringLiteral(std::string(l)); }
auto expression(const Meta& m) { return expression(m.location()); }
auto grouping(Expression* e, const Meta& m = Meta()) { return expressionGrouping(e, m); }
auto move(Expression* e, const Meta& m = Meta()) { return expressionMove(e, m); }
auto typeinfo(QualifiedType* t, const Meta& m = Meta()) { return expressionTypeInfo(expressionType(t, m), m); }
auto typeinfo(Expression* e, const Meta& m = Meta()) { return expressionTypeInfo(e, m); }
auto assign(Expression* target, Expression* src, const Meta& m = Meta()) {
return expressionAssign(target, src, m);
}
auto not_(Expression* e, const Meta& m = Meta()) { return expressionLogicalNot(e, m); }
auto ternary(Expression* cond, Expression* true_, Expression* false_, const Meta& m = Meta()) {
return expressionTernary(cond, true_, false_, m);
}
auto conditionTest(Expression* value, Expression* error, const Meta& m = Meta()) {
return expressionConditionTest(value, error, m);
}
auto min(Expression* e1, Expression* e2, const Meta& m = Meta()) {
return ternary(lowerEqual(e1, e2, m), e1, e2, m);
}
auto max(Expression* e1, Expression* e2, const Meta& m = Meta()) {
return ternary(lowerEqual(e1, e2, m), e2, e1, m);
}
auto namedCtor(const std::string& name, const Expressions& args, const Meta& m = Meta()) {
return expressionUnresolvedOperator(operator_::Kind::Call,
{expressionMember(ID(name)), expressionCtor(ctorTuple(args))}, m);
}
auto scope(const Meta& m = Meta()) { return expressionKeyword(hilti::expression::keyword::Kind::Scope, m); }
//////////// Variables and statements
Expression* addTmp(const std::string& prefix, Expression* init);
Expression* addTmp(const std::string& prefix, QualifiedType* t, const Expressions& args = {});
Expression* addTmp(const std::string& prefix, QualifiedType* t, Expression* init);
Expression* addTmp(const std::string& prefix, UnqualifiedType* t, const Expressions& args = {}) {
return addTmp(prefix, qualifiedType(t, Constness::Mutable), args);
}
Expression* addTmp(const std::string& prefix, UnqualifiedType* t, Expression* init) {
return addTmp(prefix, qualifiedType(t, Constness::Mutable), init);
}
void addLocal(ID id, QualifiedType* t, Meta m = Meta()) {
block()->_add(context(), local(std::move(id), t, std::move(m)));
}
void addLocal(ID id, Expression* init, const Meta& m = Meta()) {
block()->_add(context(), local(std::move(id), init, m));
}
void addLocal(ID id, QualifiedType* t, Expression* init, Meta m = Meta()) {
block()->_add(context(), local(std::move(id), t, init, std::move(m)));
}
void addLocal(ID id, QualifiedType* t, std::vector<hilti::Expression*> args, Meta m = Meta()) {
block()->_add(context(), local(std::move(id), t, std::move(args), std::move(m)));
}
void addExpression(Expression* expr) { block()->_add(context(), statementExpression(expr, expr->meta())); }
void addAssert(Expression* cond, std::string_view msg, Meta m = Meta()) {
block()->_add(context(), statementAssert(cond, stringMutable(msg), std::move(m)));
}
void addAssign(Expression* dst, Expression* src, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(assign(dst, src, m), m));
}
void addSumAssign(Expression* dst, Expression* src, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(sumAssign(dst, src, m), m));
}
void addAssign(const ID& dst, Expression* src, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(assign(id(dst), src, m), m));
}
void addBreak(Meta m = Meta()) { block()->_add(context(), statementBreak(std::move(m))); }
void addContinue(Meta m = Meta()) { block()->_add(context(), statementContinue(std::move(m))); }
void addSumAssign(const ID& dst, Expression* src, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(sumAssign(id(dst), src, m), m));
}
void addCall(const ID& id, const Expressions& v, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(call(id, v, m), m));
}
void addMemberCall(Expression* self, const ID& id, const Expressions& v, const Meta& m = Meta()) {
block()->_add(context(), statementExpression(memberCall(self, id, v, m), m));
}
void addComment(std::string comment,
hilti::statement::comment::Separator separator = hilti::statement::comment::Separator::Before,
const Meta& m = Meta()) {
comment = util::replace(comment, "\n", "");
block()->_add(context(), statementComment(std::move(comment), separator, m));
}
void addReturn(Expression* e, Meta m = Meta()) { block()->_add(context(), statementReturn(e, std::move(m))); }
void addReturn(Ctor* c, const Meta& m = Meta()) {
block()->_add(context(), statementReturn(expressionCtor(c, m), m));
}
void addReturn(Meta m = Meta()) { block()->_add(context(), statementReturn(std::move(m))); }
void addThrow(Expression* excpt, Meta m = Meta()) { block()->_add(context(), statementThrow(excpt, std::move(m))); }
void addRethrow(Meta m = Meta()) { block()->_add(context(), statementThrow(std::move(m))); }
void addDebugMsg(std::string_view stream, std::string_view fmt, Expressions args = {});
void addDebugIndent(std::string_view stream);
void addDebugDedent(std::string_view stream);
void addPrint(const Expressions& exprs) { addCall("hilti::print", exprs); }
void addPrint(Expression* expr) { addCall("hilti::print", {expr}); }
void setLocation(const Location& l);
bool empty() const { return block()->statements().empty() && _tmps().empty(); }
Expression* startProfiler(std::string_view name, Expression* size = nullptr);
void stopProfiler(Expression* profiler, Expression* size = nullptr);
protected:
Builder(Builder* parent) : NodeFactory(parent->context()), _state(parent->_state) {}
private:
struct State {
statement::Block* block = nullptr;
std::map<std::string, int> tmps;
};
std::map<std::string, int>& _tmps() const { return _state->tmps; }
State _static_state;
State* _state = &_static_state;
};
// Extended version of the `Builder` including any methods that depend on the
// builder's type. We don't use these inside the HILTI infrastructure, but
// it's helpful for external users constructing ASTs. They should derive their
// own `Builder` class from this template and then use that for constructing
// ASTs, potentially adding more methods of their own as needed as well.
template<typename Builder>
class ExtendedBuilderTemplate : public Builder {
public:
using Builder::Builder;
auto addWhile(statement::Declaration* init, Expression* cond, const Meta& m = Meta()) {
auto body = Builder::statementBlock();
Builder::block()->_add(Builder::context(), Builder::statementWhile(init->declaration(), cond, body, {}, m));
return _newBuilder(body);
}
auto addWhile(Expression* cond, const Meta& m = Meta()) {
auto body = Builder::statementBlock();
Builder::block()->_add(Builder::context(), Builder::statementWhile(cond, body, {}, m));
return _newBuilder(body);
}
auto addWhileElse(statement::Declaration* init, Expression* cond, const Meta& m = Meta()) {
auto body = Builder::statementBlock();
auto else_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), statementWhile(init->declaration(), cond, body, else_, m));
return std::make_pair(_newBuilder(body), _newBuilder(else_));
}
auto addWhileElse(Expression* cond, const Meta& m = Meta()) {
auto body = Builder::statementBlock();
auto else_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), statementWhile(cond, body, else_, m));
return std::make_pair(_newBuilder(body), _newBuilder(else_));
}
auto addIf(statement::Declaration* init, Expression* cond, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(),
Builder::statementIf(init->declaration(), cond, true_, {}, std::move(m)));
return _newBuilder(true_);
}
auto addIf(statement::Declaration* init, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), statementIf(init->declaration(), {}, true_, {}, std::move(m)));
return _newBuilder(true_);
}
auto addIf(Expression* cond, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), Builder::statementIf(cond, true_, {}, std::move(m)));
return _newBuilder(true_);
}
auto addIfElse(statement::Declaration* init, Expression* cond, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
auto false_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(),
Builder::statementIf(init->declaration(), cond, true_, false_, std::move(m)));
return std::make_pair(_newBuilder(true_), _newBuilder(false_));
}
auto addIfElse(statement::Declaration* init, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
auto false_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), statementIf(init->declaration(), {}, true_, false_, std::move(m)));
return std::make_pair(_newBuilder(true_), _newBuilder(false_));
}
auto addIfElse(Expression* cond, Meta m = Meta()) {
auto true_ = Builder::statementBlock();
auto false_ = Builder::statementBlock();
Builder::block()->_add(Builder::context(), Builder::statementIf(cond, true_, false_, std::move(m)));
return std::make_pair(_newBuilder(true_), _newBuilder(false_));
}
auto newBlock(const Meta& m = Meta()) {
auto body = Builder::statementBlock(m);
return _newBuilder(body);
}
auto addBlock(const Meta& m = Meta()) {
auto body = Builder::statementBlock(m);
Builder::block()->_add(Builder::context(), body);
return _newBuilder(body);
}
class SwitchProxy {
public:
SwitchProxy(ExtendedBuilderTemplate* b, statement::Switch* s) : _builder(b), _switch(s) {}
auto addCase(Expression* expr, const Meta& m = Meta()) { return _addCase({expr}, m); }
auto addCase(const Expressions& exprs, const Meta& m = Meta()) { return _addCase(exprs, m); }
auto addDefault(const Meta& m = Meta()) { return _addCase({}, m); }
private:
std::shared_ptr<ExtendedBuilderTemplate> _addCase(const Expressions& exprs, const Meta& m = Meta()) {
auto body = _builder->statementBlock(m);
_switch->addCase(_builder->context(), _builder->statementSwitchCase(exprs, body, m));
return _builder->_newBuilder(body);
}
ExtendedBuilderTemplate* _builder;
statement::Switch* _switch = nullptr;
};
auto addSwitch(Expression* cond, Meta m = Meta()) {
auto switch_ = Builder::statementSwitch(cond, {}, std::move(m));
Builder::block()->_add(Builder::context(), switch_);
return SwitchProxy(this, switch_);
}
auto addSwitch(statement::Declaration* cond, Meta m = Meta()) {
auto switch_ = Builder::statementSwitch(cond->declaration(), {}, std::move(m));
Builder::block()->_add(Builder::context(), switch_);
return SwitchProxy(this, switch_);
}
class TryProxy {
public:
TryProxy(ExtendedBuilderTemplate* b, statement::Try* s) : _builder(b), _try(s) {}
auto addCatch(declaration::Parameter* p, const Meta& m = Meta()) {
auto body = _builder->statementBlock(m);
_try->addCatch(_builder->context(), _builder->statementTryCatch(p, body, m));
return _builder->_newBuilder(body);
}
auto addCatch(const Meta& m = Meta()) {
auto body = _builder->statementBlock(m);
_try->addCatch(_builder->context(), _builder->statementTryCatch(body, m));
return _builder->_newBuilder(body);
}
TryProxy(const TryProxy&) = default;
TryProxy(TryProxy&&) noexcept = default;
TryProxy() = delete;
~TryProxy() = default;
TryProxy& operator=(const TryProxy&) = default;
TryProxy& operator=(TryProxy&&) noexcept = default;
private:
ExtendedBuilderTemplate* _builder;
statement::Try* _try = nullptr;
};
auto addTry(Meta m = Meta()) {
auto body = Builder::statementBlock();
auto try_ = Builder::statementTry(body, {}, std::move(m));
Builder::block()->_add(Builder::context(), try_);
return std::make_pair(_newBuilder(body), TryProxy(this, try_));
}
private:
std::shared_ptr<ExtendedBuilderTemplate> _newBuilder(statement::Block* block) {
return std::make_shared<ExtendedBuilderTemplate>(Builder::context(), block);
}
};
using BuilderPtr = std::shared_ptr<Builder>;
} // namespace hilti