// Copyright 2017 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_DECLARABLE_H_
#define V8_TORQUE_DECLARABLE_H_
#include <cassert>
#include <string>
#include "src/base/functional.h"
#include "src/base/logging.h"
#include "src/torque/ast.h"
#include "src/torque/types.h"
#include "src/torque/utils.h"
namespace v8 {
namespace internal {
namespace torque {
class Scope;
class ScopeChain;
class Generic;
class Declarable {
public:
virtual ~Declarable() {}
enum Kind {
kVariable,
kParameter,
kMacro,
kMacroList,
kBuiltin,
kRuntimeFunction,
kGeneric,
kGenericList,
kTypeAlias,
kLabel,
kExternConstant,
kModuleConstant
};
Kind kind() const { return kind_; }
bool IsMacro() const { return kind() == kMacro; }
bool IsBuiltin() const { return kind() == kBuiltin; }
bool IsRuntimeFunction() const { return kind() == kRuntimeFunction; }
bool IsGeneric() const { return kind() == kGeneric; }
bool IsTypeAlias() const { return kind() == kTypeAlias; }
bool IsParameter() const { return kind() == kParameter; }
bool IsLabel() const { return kind() == kLabel; }
bool IsVariable() const { return kind() == kVariable; }
bool IsMacroList() const { return kind() == kMacroList; }
bool IsGenericList() const { return kind() == kGenericList; }
bool IsExternConstant() const { return kind() == kExternConstant; }
bool IsModuleConstant() const { return kind() == kModuleConstant; }
bool IsValue() const {
return IsVariable() || IsExternConstant() || IsParameter() ||
IsModuleConstant();
}
virtual const char* type_name() const { return "<<unknown>>"; }
protected:
explicit Declarable(Kind kind) : kind_(kind) {}
private:
const Kind kind_;
};
#define DECLARE_DECLARABLE_BOILERPLATE(x, y) \
static x* cast(Declarable* declarable) { \
DCHECK(declarable->Is##x()); \
return static_cast<x*>(declarable); \
} \
static const x* cast(const Declarable* declarable) { \
DCHECK(declarable->Is##x()); \
return static_cast<const x*>(declarable); \
} \
const char* type_name() const override { return #y; } \
static x* DynamicCast(Declarable* declarable) { \
if (!declarable) return nullptr; \
if (!declarable->Is##x()) return nullptr; \
return static_cast<x*>(declarable); \
} \
static const x* DynamicCast(const Declarable* declarable) { \
if (!declarable) return nullptr; \
if (!declarable->Is##x()) return nullptr; \
return static_cast<const x*>(declarable); \
}
class Value : public Declarable {
public:
const std::string& name() const { return name_; }
virtual bool IsConst() const { return true; }
virtual std::string value() const = 0;
virtual std::string RValue() const { return value(); }
DECLARE_DECLARABLE_BOILERPLATE(Value, value);
const Type* type() const { return type_; }
protected:
Value(Kind kind, const Type* type, const std::string& name)
: Declarable(kind), type_(type), name_(name) {}
private:
const Type* type_;
std::string name_;
};
class Parameter : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(Parameter, parameter);
std::string value() const override { return var_name_; }
private:
friend class Declarations;
Parameter(const std::string& name, const Type* type,
const std::string& var_name)
: Value(Declarable::kParameter, type, name), var_name_(var_name) {}
std::string var_name_;
};
class ModuleConstant : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(ModuleConstant, constant);
std::string value() const override { UNREACHABLE(); }
std::string RValue() const override { return name() + "()"; }
private:
friend class Declarations;
explicit ModuleConstant(const std::string& name, const Type* type)
: Value(Declarable::kModuleConstant, type, name) {}
};
class Variable : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(Variable, variable);
bool IsConst() const override { return const_; }
std::string value() const override { return value_; }
std::string RValue() const override;
void Define() {
if (defined_ && IsConst()) {
ReportError("Cannot re-define a const-bound variable.");
}
defined_ = true;
}
bool IsDefined() const { return defined_; }
private:
friend class Declarations;
Variable(const std::string& name, const std::string& value, const Type* type,
bool is_const)
: Value(Declarable::kVariable, type, name),
value_(value),
defined_(false),
const_(is_const) {
DCHECK_IMPLIES(type->IsConstexpr(), IsConst());
}
std::string value_;
bool defined_;
bool const_;
};
class Label : public Declarable {
public:
void AddVariable(Variable* var) { parameters_.push_back(var); }
std::string name() const { return name_; }
std::string generated() const { return generated_; }
Variable* GetParameter(size_t i) const { return parameters_[i]; }
size_t GetParameterCount() const { return parameters_.size(); }
const std::vector<Variable*>& GetParameters() const { return parameters_; }
DECLARE_DECLARABLE_BOILERPLATE(Label, label);
void MarkUsed() { used_ = true; }
bool IsUsed() const { return used_; }
private:
friend class Declarations;
explicit Label(const std::string& name)
: Declarable(Declarable::kLabel),
name_(name),
generated_("label_" + name + "_" + std::to_string(next_id_++)),
used_(false) {}
std::string name_;
std::string generated_;
std::vector<Variable*> parameters_;
static size_t next_id_;
bool used_;
};
class ExternConstant : public Value {
public:
DECLARE_DECLARABLE_BOILERPLATE(ExternConstant, constant);
std::string value() const override { return value_; }
private:
friend class Declarations;
explicit ExternConstant(const std::string& name, const Type* type,
const std::string& value)
: Value(Declarable::kExternConstant, type, name), value_(value) {}
std::string value_;
};
class Callable : public Declarable {
public:
static Callable* cast(Declarable* declarable) {
assert(declarable->IsMacro() || declarable->IsBuiltin() ||
declarable->IsRuntimeFunction());
return static_cast<Callable*>(declarable);
}
static const Callable* cast(const Declarable* declarable) {
assert(declarable->IsMacro() || declarable->IsBuiltin() ||
declarable->IsRuntimeFunction());
return static_cast<const Callable*>(declarable);
}
const std::string& name() const { return name_; }
const Signature& signature() const { return signature_; }
const NameVector& parameter_names() const {
return signature_.parameter_names;
}
bool HasReturnValue() const {
return !signature_.return_type->IsVoidOrNever();
}
void IncrementReturns() { ++returns_; }
bool HasReturns() const { return returns_; }
base::Optional<Generic*> generic() const { return generic_; }
protected:
Callable(Declarable::Kind kind, const std::string& name,
const Signature& signature, base::Optional<Generic*> generic)
: Declarable(kind),
name_(name),
signature_(signature),
returns_(0),
generic_(generic) {}
private:
std::string name_;
Signature signature_;
size_t returns_;
base::Optional<Generic*> generic_;
};
class Macro : public Callable {
public:
DECLARE_DECLARABLE_BOILERPLATE(Macro, macro);
private:
friend class Declarations;
Macro(const std::string& name, const Signature& signature,
base::Optional<Generic*> generic)
: Callable(Declarable::kMacro, name, signature, generic) {
if (signature.parameter_types.var_args) {
ReportError("Varargs are not supported for macros.");
}
}
};
class MacroList : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(MacroList, macro_list);
const std::vector<Macro*>& list() { return list_; }
Macro* AddMacro(Macro* macro) {
list_.emplace_back(macro);
return macro;
}
private:
friend class Declarations;
MacroList() : Declarable(Declarable::kMacroList) {}
std::vector<Macro*> list_;
};
class Builtin : public Callable {
public:
enum Kind { kStub, kFixedArgsJavaScript, kVarArgsJavaScript };
DECLARE_DECLARABLE_BOILERPLATE(Builtin, builtin);
Kind kind() const { return kind_; }
bool IsStub() const { return kind_ == kStub; }
bool IsVarArgsJavaScript() const { return kind_ == kVarArgsJavaScript; }
bool IsFixedArgsJavaScript() const { return kind_ == kFixedArgsJavaScript; }
bool IsExternal() const { return external_; }
private:
friend class Declarations;
Builtin(const std::string& name, Builtin::Kind kind, bool external,
const Signature& signature, base::Optional<Generic*> generic)
: Callable(Declarable::kBuiltin, name, signature, generic),
kind_(kind),
external_(external) {}
Kind kind_;
bool external_;
};
class RuntimeFunction : public Callable {
public:
DECLARE_DECLARABLE_BOILERPLATE(RuntimeFunction, runtime);
private:
friend class Declarations;
RuntimeFunction(const std::string& name, const Signature& signature,
base::Optional<Generic*> generic)
: Callable(Declarable::kRuntimeFunction, name, signature, generic) {}
};
class Generic : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(Generic, generic);
GenericDeclaration* declaration() const { return declaration_; }
const std::string& name() const { return name_; }
Module* module() const { return module_; }
private:
friend class Declarations;
Generic(const std::string& name, Module* module,
GenericDeclaration* declaration)
: Declarable(Declarable::kGeneric),
name_(name),
module_(module),
declaration_(declaration) {}
std::string name_;
Module* module_;
GenericDeclaration* declaration_;
};
class GenericList : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericList, generic_list);
const std::vector<Generic*>& list() { return list_; }
Generic* AddGeneric(Generic* generic) {
list_.push_back(generic);
return generic;
}
private:
friend class Declarations;
GenericList() : Declarable(Declarable::kGenericList) {}
std::vector<Generic*> list_;
};
typedef std::pair<Generic*, TypeVector> SpecializationKey;
class TypeAlias : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(TypeAlias, type_alias);
const Type* type() const { return type_; }
private:
friend class Declarations;
explicit TypeAlias(const Type* type)
: Declarable(Declarable::kTypeAlias), type_(type) {}
const Type* type_;
};
void PrintLabel(std::ostream& os, const Label& l, bool with_names);
std::ostream& operator<<(std::ostream& os, const Callable& m);
std::ostream& operator<<(std::ostream& os, const Variable& v);
std::ostream& operator<<(std::ostream& os, const Builtin& b);
std::ostream& operator<<(std::ostream& os, const Label& l);
std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b);
std::ostream& operator<<(std::ostream& os, const Generic& g);
#undef DECLARE_DECLARABLE_BOILERPLATE
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_DECLARABLE_H_