// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details. #pragma once #include #include #include #include #include #include #include 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 static auto parameters(Params&&... params) { return std::vector{std::forward(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(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 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 tmps; }; std::map& _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 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 _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 _newBuilder(statement::Block* block) { return std::make_shared(Builder::context(), block); } }; using BuilderPtr = std::shared_ptr; } // namespace hilti