// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_TORQUE_CPP_BUILDER_H_ #define V8_TORQUE_CPP_BUILDER_H_ #include <stack> #include "src/torque/ast.h" #include "src/torque/types.h" namespace v8 { namespace internal { namespace torque { namespace cpp { struct TemplateParameter { explicit TemplateParameter(std::string name) : name(std::move(name)) {} TemplateParameter(std::string type, std::string name) : name(std::move(name)), type(std::move(type)) {} std::string name; std::string type; }; class Class { public: explicit Class(std::string name) : name_(std::move(name)) {} Class(std::vector<TemplateParameter> template_parameters, std::string name) : template_parameters_(std::move(template_parameters)), name_(std::move(name)) {} std::string GetName() const { return name_; } std::vector<TemplateParameter> GetTemplateParameters() const { return template_parameters_; } private: std::vector<TemplateParameter> template_parameters_; std::string name_; }; #define FUNCTION_FLAG_LIST(V) \ V(Inline, 0x01) \ V(V8Inline, 0x03) \ V(Const, 0x04) \ V(Constexpr, 0x08) \ V(Export, 0x10) \ V(Static, 0x20) \ V(Override, 0x40) class Function { public: enum FunctionFlag { #define ENTRY(name, value) k##name = value, FUNCTION_FLAG_LIST(ENTRY) #undef ENTRY }; struct Parameter { std::string type; std::string name; std::string default_value; Parameter(std::string type, std::string name, std::string default_value = {}) : type(std::move(type)), name(std::move(name)), default_value(std::move(default_value)) {} }; explicit Function(std::string name) : pos_(CurrentSourcePosition::Get()), owning_class_(nullptr), name_(std::move(name)) {} Function(Class* owning_class, std::string name) : pos_(CurrentSourcePosition::Get()), owning_class_(owning_class), name_(std::move(name)) {} ~Function() = default; static Function DefaultGetter(std::string return_type, Class* owner, std::string name) { Function getter(owner, std::move(name)); getter.SetReturnType(std::move(return_type)); getter.SetInline(); getter.SetConst(); return getter; } static Function DefaultSetter(Class* owner, std::string name, std::string parameter_type, std::string parameter_name) { Function setter(owner, std::move(name)); setter.SetReturnType("void"); setter.AddParameter(std::move(parameter_type), std::move(parameter_name)); setter.SetInline(); return setter; } void SetFlag(FunctionFlag flag, bool value = true) { if (value) { flags_ = flags_ | flag; } else { flags_ = flags_.without(flag); } } void SetFlags(base::Flags<FunctionFlag> flags, bool value = true) { if (value) { flags_ |= flags; } else { flags_ &= ~flags; } } bool HasFlag(FunctionFlag flag) const { return (flags_ & flag) == flag; } #define ACCESSOR(name, value) \ void Set##name(bool v = true) { SetFlag(k##name, v); } \ bool Is##name() const { return HasFlag(k##name); } FUNCTION_FLAG_LIST(ACCESSOR) #undef ACCESSOR void SetDescription(std::string description) { description_ = std::move(description); } void SetName(std::string name) { name_ = std::move(name); } void SetReturnType(std::string return_type) { return_type_ = std::move(return_type); } void AddParameter(std::string type, std::string name = {}, std::string default_value = {}) { parameters_.emplace_back(std::move(type), std::move(name), std::move(default_value)); } void InsertParameter(int index, std::string type, std::string name = {}, std::string default_value = {}) { DCHECK_GE(index, 0); DCHECK_LE(index, parameters_.size()); parameters_.insert( parameters_.begin() + index, Parameter(std::move(type), std::move(name), std::move(default_value))); } std::vector<Parameter> GetParameters() const { return parameters_; } std::vector<std::string> GetParameterNames() const { std::vector<std::string> names; std::transform(parameters_.begin(), parameters_.end(), std::back_inserter(names), [](const Parameter& p) { return p.name; }); return names; } static constexpr int kAutomaticIndentation = -1; void PrintDeclaration(std::ostream& stream, int indentation = kAutomaticIndentation) const; void PrintDefinition(std::ostream& stream, const std::function<void(std::ostream&)>& builder, int indentation = 0) const; void PrintInlineDefinition(std::ostream& stream, const std::function<void(std::ostream&)>& builder, int indentation = 2) const; void PrintBeginDefinition(std::ostream& stream, int indentation = 0) const; void PrintEndDefinition(std::ostream& stream, int indentation = 0) const; protected: void PrintDeclarationHeader(std::ostream& stream, int indentation) const; private: SourcePosition pos_; Class* owning_class_; std::string description_; std::string name_; std::string return_type_; std::vector<Parameter> parameters_; base::Flags<FunctionFlag> flags_; }; DEFINE_OPERATORS_FOR_FLAGS(base::Flags<Function::FunctionFlag>) #undef FUNCTION_FLAG_LIST class File { public: explicit File(std::ostream& stream) : stream_(&stream) {} void BeginIncludeGuard(const std::string& name); void EndIncludeGuard(const std::string& name); void BeginNamespace(std::string name); void BeginNamespace(std::string name0, std::string name1); void EndNamespace(const std::string& name); void EndNamespace(const std::string& name0, const std::string& name1); void AddInclude(std::string include) { includes_.insert(std::move(include)); } template <typename T> File& operator<<(const T& value) { s() << value; return *this; } protected: std::ostream& s() { return *stream_; } private: std::ostream* stream_; std::set<std::string> includes_; std::stack<std::string> namespaces_; }; class IncludeGuardScope { public: explicit IncludeGuardScope(File* file, std::string name) : file_(file), name_(std::move(name)) { file_->BeginIncludeGuard(name_); } IncludeGuardScope(const IncludeGuardScope&) = delete; IncludeGuardScope(IncludeGuardScope&& other) V8_NOEXCEPT : file_(nullptr), name_() { std::swap(file_, other.file_); std::swap(name_, other.name_); } ~IncludeGuardScope() { if (file_) { file_->EndIncludeGuard(name_); } } IncludeGuardScope& operator=(const IncludeGuardScope&) = delete; IncludeGuardScope& operator=(IncludeGuardScope&& other) V8_NOEXCEPT { if (this != &other) { DCHECK_NULL(file_); DCHECK(name_.empty()); std::swap(file_, other.file_); std::swap(name_, other.name_); } return *this; } private: File* file_; std::string name_; }; } // namespace cpp } // namespace torque } // namespace internal } // namespace v8 #endif // V8_TORQUE_CPP_BUILDER_H_