#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTSTMT_H
#include "ResourceScriptToken.h"
#include "ResourceVisitor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringSet.h"
namespace llvm {
namespace rc {
class RCInt {
uint32_t Val;
bool Long;
public:
RCInt(const RCToken &Token)
: Val(Token.intValue()), Long(Token.isLongInt()) {}
RCInt(uint32_t Value) : Val(Value), Long(false) {}
RCInt(uint32_t Value, bool IsLong) : Val(Value), Long(IsLong) {}
operator uint32_t() const { return Val; }
bool isLong() const { return Long; }
RCInt &operator+=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val + Rhs.Val, Long | Rhs.Long);
return *this;
}
RCInt &operator-=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val - Rhs.Val, Long | Rhs.Long);
return *this;
}
RCInt &operator|=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
return *this;
}
RCInt &operator&=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val & Rhs.Val, Long | Rhs.Long);
return *this;
}
RCInt operator-() const { return {-Val, Long}; }
RCInt operator~() const { return {~Val, Long}; }
friend raw_ostream &operator<<(raw_ostream &OS, const RCInt &Int) {
return OS << Int.Val << (Int.Long ? "L" : "");
}
};
class IntWithNotMask {
private:
RCInt Value;
int32_t NotMask;
public:
IntWithNotMask() : IntWithNotMask(RCInt(0)) {}
IntWithNotMask(RCInt Value, int32_t NotMask = 0) : Value(Value), NotMask(NotMask) {}
RCInt getValue() const {
return Value;
}
uint32_t getNotMask() const {
return NotMask;
}
IntWithNotMask &operator+=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value += Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}
IntWithNotMask &operator-=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value -= Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}
IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value |= Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}
IntWithNotMask &operator&=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value &= Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}
IntWithNotMask operator-() const { return {-Value, NotMask}; }
IntWithNotMask operator~() const { return {~Value, 0}; }
friend raw_ostream &operator<<(raw_ostream &OS, const IntWithNotMask &Int) {
return OS << Int.Value;
}
};
class IntOrString {
private:
union Data {
RCInt Int;
StringRef String;
Data(RCInt Value) : Int(Value) {}
Data(const StringRef Value) : String(Value) {}
Data(const RCToken &Token) {
if (Token.kind() == RCToken::Kind::Int)
Int = RCInt(Token);
else
String = Token.value();
}
} Data;
bool IsInt;
public:
IntOrString() : IntOrString(RCInt(0)) {}
IntOrString(uint32_t Value) : Data(Value), IsInt(true) {}
IntOrString(RCInt Value) : Data(Value), IsInt(true) {}
IntOrString(StringRef Value) : Data(Value), IsInt(false) {}
IntOrString(const RCToken &Token)
: Data(Token), IsInt(Token.kind() == RCToken::Kind::Int) {}
bool equalsLower(const char *Str) {
return !IsInt && Data.String.equals_insensitive(Str);
}
bool isInt() const { return IsInt; }
RCInt getInt() const {
assert(IsInt);
return Data.Int;
}
const StringRef &getString() const {
assert(!IsInt);
return Data.String;
}
operator Twine() const {
return isInt() ? Twine(getInt()) : Twine(getString());
}
friend raw_ostream &operator<<(raw_ostream &, const IntOrString &);
};
enum ResourceKind {
RkNull = 0,
RkSingleCursor = 1,
RkBitmap = 2,
RkSingleIcon = 3,
RkMenu = 4,
RkDialog = 5,
RkStringTableBundle = 6,
RkAccelerators = 9,
RkRcData = 10,
RkCursorGroup = 12,
RkIconGroup = 14,
RkVersionInfo = 16,
RkHTML = 23,
RkInvalid = 256,
RkBase,
RkCursor,
RkIcon,
RkStringTable,
RkUser,
RkSingleCursorOrIconRes,
RkCursorOrIconGroupRes,
};
enum MemoryFlags {
MfMoveable = 0x10,
MfPure = 0x20,
MfPreload = 0x40,
MfDiscardable = 0x1000
};
class RCResource {
public:
IntOrString ResName;
uint16_t MemoryFlags = getDefaultMemoryFlags();
void setName(const IntOrString &Name) { ResName = Name; }
virtual raw_ostream &log(raw_ostream &OS) const {
return OS << "Base statement\n";
};
RCResource() {}
RCResource(uint16_t Flags) : MemoryFlags(Flags) {}
virtual ~RCResource() {}
virtual Error visit(Visitor *) const {
llvm_unreachable("This is unable to call methods from Visitor base");
}
virtual Error applyStmts(Visitor *) const { return Error::success(); }
static uint16_t getDefaultMemoryFlags() {
return MfDiscardable | MfPure | MfMoveable;
}
virtual ResourceKind getKind() const { return RkBase; }
static bool classof(const RCResource *Res) { return true; }
virtual IntOrString getResourceType() const {
llvm_unreachable("This cannot be called on objects without types.");
}
virtual Twine getResourceTypeName() const {
llvm_unreachable("This cannot be called on objects without types.");
};
};
class NullResource : public RCResource {
public:
NullResource() : RCResource(0) {}
raw_ostream &log(raw_ostream &OS) const override {
return OS << "Null resource\n";
}
Error visit(Visitor *V) const override { return V->visitNullResource(this); }
IntOrString getResourceType() const override { return 0; }
Twine getResourceTypeName() const override { return "(NULL)"; }
};
class OptionalStmt : public RCResource {};
class OptionalStmtList : public OptionalStmt {
std::vector<std::unique_ptr<OptionalStmt>> Statements;
public:
OptionalStmtList() {}
raw_ostream &log(raw_ostream &OS) const override;
void addStmt(std::unique_ptr<OptionalStmt> Stmt) {
Statements.push_back(std::move(Stmt));
}
Error visit(Visitor *V) const override {
for (auto &StmtPtr : Statements)
if (auto Err = StmtPtr->visit(V))
return Err;
return Error::success();
}
};
class OptStatementsRCResource : public RCResource {
public:
std::unique_ptr<OptionalStmtList> OptStatements;
OptStatementsRCResource(OptionalStmtList &&Stmts,
uint16_t Flags = RCResource::getDefaultMemoryFlags())
: RCResource(Flags),
OptStatements(std::make_unique<OptionalStmtList>(std::move(Stmts))) {}
Error applyStmts(Visitor *V) const override {
return OptStatements->visit(V);
}
};
class LanguageResource : public OptionalStmt {
public:
uint32_t Lang, SubLang;
LanguageResource(uint32_t LangId, uint32_t SubLangId)
: Lang(LangId), SubLang(SubLangId) {}
raw_ostream &log(raw_ostream &) const override;
Error visit(Visitor *V) const override { return V->visitLanguageStmt(this); }
Twine getResourceTypeName() const override { return "LANGUAGE"; }
};
class AcceleratorsResource : public OptStatementsRCResource {
public:
class Accelerator {
public:
IntOrString Event;
uint32_t Id;
uint16_t Flags;
enum Options {
ASCII = 0x8000,
VIRTKEY = 0x0001,
NOINVERT = 0x0002,
ALT = 0x0010,
SHIFT = 0x0004,
CONTROL = 0x0008
};
static constexpr size_t NumFlags = 6;
static StringRef OptionsStr[NumFlags];
static uint32_t OptionsFlags[NumFlags];
};
AcceleratorsResource(OptionalStmtList &&List, uint16_t Flags)
: OptStatementsRCResource(std::move(List), Flags) {}
std::vector<Accelerator> Accelerators;
void addAccelerator(IntOrString Event, uint32_t Id, uint16_t Flags) {
Accelerators.push_back(Accelerator{Event, Id, Flags});
}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkAccelerators; }
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Twine getResourceTypeName() const override { return "ACCELERATORS"; }
Error visit(Visitor *V) const override {
return V->visitAcceleratorsResource(this);
}
ResourceKind getKind() const override { return RkAccelerators; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkAccelerators;
}
};
class BitmapResource : public RCResource {
public:
StringRef BitmapLoc;
BitmapResource(StringRef Location, uint16_t Flags)
: RCResource(Flags), BitmapLoc(Location) {}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkBitmap; }
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Twine getResourceTypeName() const override { return "BITMAP"; }
Error visit(Visitor *V) const override {
return V->visitBitmapResource(this);
}
ResourceKind getKind() const override { return RkBitmap; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkBitmap;
}
};
class CursorResource : public RCResource {
public:
StringRef CursorLoc;
CursorResource(StringRef Location, uint16_t Flags)
: RCResource(Flags), CursorLoc(Location) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "CURSOR"; }
static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
Error visit(Visitor *V) const override {
return V->visitCursorResource(this);
}
ResourceKind getKind() const override { return RkCursor; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkCursor;
}
};
class IconResource : public RCResource {
public:
StringRef IconLoc;
IconResource(StringRef Location, uint16_t Flags)
: RCResource(Flags), IconLoc(Location) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "ICON"; }
static uint16_t getDefaultMemoryFlags() { return MfDiscardable | MfMoveable; }
Error visit(Visitor *V) const override { return V->visitIconResource(this); }
ResourceKind getKind() const override { return RkIcon; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkIcon;
}
};
class HTMLResource : public RCResource {
public:
StringRef HTMLLoc;
HTMLResource(StringRef Location, uint16_t Flags)
: RCResource(Flags), HTMLLoc(Location) {}
raw_ostream &log(raw_ostream &) const override;
Error visit(Visitor *V) const override { return V->visitHTMLResource(this); }
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
IntOrString getResourceType() const override { return RkHTML; }
Twine getResourceTypeName() const override { return "HTML"; }
ResourceKind getKind() const override { return RkHTML; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkHTML;
}
};
class MenuDefinition {
public:
enum Options {
CHECKED = 0x0008,
GRAYED = 0x0001,
HELP = 0x4000,
INACTIVE = 0x0002,
MENUBARBREAK = 0x0020,
MENUBREAK = 0x0040
};
enum MenuDefKind { MkBase, MkSeparator, MkMenuItem, MkPopup };
static constexpr size_t NumFlags = 6;
static StringRef OptionsStr[NumFlags];
static uint32_t OptionsFlags[NumFlags];
static raw_ostream &logFlags(raw_ostream &, uint16_t Flags);
virtual raw_ostream &log(raw_ostream &OS) const {
return OS << "Base menu definition\n";
}
virtual ~MenuDefinition() {}
virtual uint16_t getResFlags() const { return 0; }
virtual MenuDefKind getKind() const { return MkBase; }
};
class MenuDefinitionList : public MenuDefinition {
public:
std::vector<std::unique_ptr<MenuDefinition>> Definitions;
void addDefinition(std::unique_ptr<MenuDefinition> Def) {
Definitions.push_back(std::move(Def));
}
raw_ostream &log(raw_ostream &) const override;
};
class MenuSeparator : public MenuDefinition {
public:
raw_ostream &log(raw_ostream &) const override;
MenuDefKind getKind() const override { return MkSeparator; }
static bool classof(const MenuDefinition *D) {
return D->getKind() == MkSeparator;
}
};
class MenuItem : public MenuDefinition {
public:
StringRef Name;
uint32_t Id;
uint16_t Flags;
MenuItem(StringRef Caption, uint32_t ItemId, uint16_t ItemFlags)
: Name(Caption), Id(ItemId), Flags(ItemFlags) {}
raw_ostream &log(raw_ostream &) const override;
uint16_t getResFlags() const override { return Flags; }
MenuDefKind getKind() const override { return MkMenuItem; }
static bool classof(const MenuDefinition *D) {
return D->getKind() == MkMenuItem;
}
};
class PopupItem : public MenuDefinition {
public:
StringRef Name;
uint16_t Flags;
MenuDefinitionList SubItems;
PopupItem(StringRef Caption, uint16_t ItemFlags,
MenuDefinitionList &&SubItemsList)
: Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
raw_ostream &log(raw_ostream &) const override;
uint16_t getResFlags() const override { return Flags | 0x10; }
MenuDefKind getKind() const override { return MkPopup; }
static bool classof(const MenuDefinition *D) {
return D->getKind() == MkPopup;
}
};
class MenuResource : public OptStatementsRCResource {
public:
MenuDefinitionList Elements;
MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items,
uint16_t Flags)
: OptStatementsRCResource(std::move(OptStmts), Flags),
Elements(std::move(Items)) {}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkMenu; }
Twine getResourceTypeName() const override { return "MENU"; }
Error visit(Visitor *V) const override { return V->visitMenuResource(this); }
ResourceKind getKind() const override { return RkMenu; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkMenu;
}
};
class StringTableResource : public OptStatementsRCResource {
public:
std::vector<std::pair<uint32_t, std::vector<StringRef>>> Table;
StringTableResource(OptionalStmtList &&List, uint16_t Flags)
: OptStatementsRCResource(std::move(List), Flags) {}
void addStrings(uint32_t ID, std::vector<StringRef> &&Strings) {
Table.emplace_back(ID, Strings);
}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "STRINGTABLE"; }
Error visit(Visitor *V) const override {
return V->visitStringTableResource(this);
}
};
class Control {
public:
StringRef Type;
IntOrString Title;
uint32_t ID, X, Y, Width, Height;
Optional<IntWithNotMask> Style;
Optional<uint32_t> ExtStyle, HelpID;
IntOrString Class;
enum CtlClasses {
ClsButton = 0x80,
ClsEdit = 0x81,
ClsStatic = 0x82,
ClsListBox = 0x83,
ClsScrollBar = 0x84,
ClsComboBox = 0x85
};
struct CtlInfo {
uint32_t Style;
uint16_t CtlClass;
bool HasTitle;
};
Control(StringRef CtlType, IntOrString CtlTitle, uint32_t CtlID,
uint32_t PosX, uint32_t PosY, uint32_t ItemWidth, uint32_t ItemHeight,
Optional<IntWithNotMask> ItemStyle, Optional<uint32_t> ExtItemStyle,
Optional<uint32_t> CtlHelpID, IntOrString CtlClass)
: Type(CtlType), Title(CtlTitle), ID(CtlID), X(PosX), Y(PosY),
Width(ItemWidth), Height(ItemHeight), Style(ItemStyle),
ExtStyle(ExtItemStyle), HelpID(CtlHelpID), Class(CtlClass) {}
static const StringMap<CtlInfo> SupportedCtls;
raw_ostream &log(raw_ostream &) const;
};
class DialogResource : public OptStatementsRCResource {
public:
uint32_t X, Y, Width, Height, HelpID;
std::vector<Control> Controls;
bool IsExtended;
DialogResource(uint32_t PosX, uint32_t PosY, uint32_t DlgWidth,
uint32_t DlgHeight, uint32_t DlgHelpID,
OptionalStmtList &&OptStmts, bool IsDialogEx, uint16_t Flags)
: OptStatementsRCResource(std::move(OptStmts), Flags), X(PosX), Y(PosY),
Width(DlgWidth), Height(DlgHeight), HelpID(DlgHelpID),
IsExtended(IsDialogEx) {}
void addControl(Control &&Ctl) { Controls.push_back(std::move(Ctl)); }
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkDialog; }
Twine getResourceTypeName() const override {
return "DIALOG" + Twine(IsExtended ? "EX" : "");
}
Error visit(Visitor *V) const override {
return V->visitDialogResource(this);
}
ResourceKind getKind() const override { return RkDialog; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkDialog;
}
};
class UserDefinedResource : public RCResource {
public:
IntOrString Type;
StringRef FileLoc;
std::vector<IntOrString> Contents;
bool IsFileResource;
UserDefinedResource(IntOrString ResourceType, StringRef FileLocation,
uint16_t Flags)
: RCResource(Flags), Type(ResourceType), FileLoc(FileLocation),
IsFileResource(true) {}
UserDefinedResource(IntOrString ResourceType, std::vector<IntOrString> &&Data,
uint16_t Flags)
: RCResource(Flags), Type(ResourceType), Contents(std::move(Data)),
IsFileResource(false) {}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return Type; }
Twine getResourceTypeName() const override { return Type; }
static uint16_t getDefaultMemoryFlags() { return MfPure | MfMoveable; }
Error visit(Visitor *V) const override {
return V->visitUserDefinedResource(this);
}
ResourceKind getKind() const override { return RkUser; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkUser;
}
};
class VersionInfoStmt {
public:
enum StmtKind { StBase = 0, StBlock = 1, StValue = 2 };
virtual raw_ostream &log(raw_ostream &OS) const { return OS << "VI stmt\n"; }
virtual ~VersionInfoStmt() {}
virtual StmtKind getKind() const { return StBase; }
static bool classof(const VersionInfoStmt *S) {
return S->getKind() == StBase;
}
};
class VersionInfoBlock : public VersionInfoStmt {
public:
std::vector<std::unique_ptr<VersionInfoStmt>> Stmts;
StringRef Name;
VersionInfoBlock(StringRef BlockName) : Name(BlockName) {}
void addStmt(std::unique_ptr<VersionInfoStmt> Stmt) {
Stmts.push_back(std::move(Stmt));
}
raw_ostream &log(raw_ostream &) const override;
StmtKind getKind() const override { return StBlock; }
static bool classof(const VersionInfoStmt *S) {
return S->getKind() == StBlock;
}
};
class VersionInfoValue : public VersionInfoStmt {
public:
StringRef Key;
std::vector<IntOrString> Values;
BitVector HasPrecedingComma;
VersionInfoValue(StringRef InfoKey, std::vector<IntOrString> &&Vals,
BitVector &&CommasBeforeVals)
: Key(InfoKey), Values(std::move(Vals)),
HasPrecedingComma(std::move(CommasBeforeVals)) {}
raw_ostream &log(raw_ostream &) const override;
StmtKind getKind() const override { return StValue; }
static bool classof(const VersionInfoStmt *S) {
return S->getKind() == StValue;
}
};
class VersionInfoResource : public RCResource {
public:
class VersionInfoFixed {
public:
enum VersionInfoFixedType {
FtUnknown,
FtFileVersion,
FtProductVersion,
FtFileFlagsMask,
FtFileFlags,
FtFileOS,
FtFileType,
FtFileSubtype,
FtNumTypes
};
private:
static const StringMap<VersionInfoFixedType> FixedFieldsInfoMap;
static const StringRef FixedFieldsNames[FtNumTypes];
public:
SmallVector<uint32_t, 4> FixedInfo[FtNumTypes];
SmallVector<bool, FtNumTypes> IsTypePresent;
static VersionInfoFixedType getFixedType(StringRef Type);
static bool isTypeSupported(VersionInfoFixedType Type);
static bool isVersionType(VersionInfoFixedType Type);
VersionInfoFixed() : IsTypePresent(FtNumTypes, false) {}
void setValue(VersionInfoFixedType Type, ArrayRef<uint32_t> Value) {
FixedInfo[Type] = SmallVector<uint32_t, 4>(Value.begin(), Value.end());
IsTypePresent[Type] = true;
}
raw_ostream &log(raw_ostream &) const;
};
VersionInfoBlock MainBlock;
VersionInfoFixed FixedData;
VersionInfoResource(VersionInfoBlock &&TopLevelBlock,
VersionInfoFixed &&FixedInfo, uint16_t Flags)
: RCResource(Flags), MainBlock(std::move(TopLevelBlock)),
FixedData(std::move(FixedInfo)) {}
raw_ostream &log(raw_ostream &) const override;
IntOrString getResourceType() const override { return RkVersionInfo; }
static uint16_t getDefaultMemoryFlags() { return MfMoveable | MfPure; }
Twine getResourceTypeName() const override { return "VERSIONINFO"; }
Error visit(Visitor *V) const override {
return V->visitVersionInfoResource(this);
}
ResourceKind getKind() const override { return RkVersionInfo; }
static bool classof(const RCResource *Res) {
return Res->getKind() == RkVersionInfo;
}
};
class CharacteristicsStmt : public OptionalStmt {
public:
uint32_t Value;
CharacteristicsStmt(uint32_t Characteristic) : Value(Characteristic) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "CHARACTERISTICS"; }
Error visit(Visitor *V) const override {
return V->visitCharacteristicsStmt(this);
}
};
class VersionStmt : public OptionalStmt {
public:
uint32_t Value;
VersionStmt(uint32_t Version) : Value(Version) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "VERSION"; }
Error visit(Visitor *V) const override { return V->visitVersionStmt(this); }
};
class CaptionStmt : public OptionalStmt {
public:
StringRef Value;
CaptionStmt(StringRef Caption) : Value(Caption) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "CAPTION"; }
Error visit(Visitor *V) const override { return V->visitCaptionStmt(this); }
};
class FontStmt : public OptionalStmt {
public:
uint32_t Size, Weight, Charset;
StringRef Name;
bool Italic;
FontStmt(uint32_t FontSize, StringRef FontName, uint32_t FontWeight,
bool FontItalic, uint32_t FontCharset)
: Size(FontSize), Weight(FontWeight), Charset(FontCharset),
Name(FontName), Italic(FontItalic) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "FONT"; }
Error visit(Visitor *V) const override { return V->visitFontStmt(this); }
};
class StyleStmt : public OptionalStmt {
public:
uint32_t Value;
StyleStmt(uint32_t Style) : Value(Style) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "STYLE"; }
Error visit(Visitor *V) const override { return V->visitStyleStmt(this); }
};
class ExStyleStmt : public OptionalStmt {
public:
uint32_t Value;
ExStyleStmt(uint32_t ExStyle) : Value(ExStyle) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "EXSTYLE"; }
Error visit(Visitor *V) const override { return V->visitExStyleStmt(this); }
};
class ClassStmt : public OptionalStmt {
public:
IntOrString Value;
ClassStmt(IntOrString Class) : Value(Class) {}
raw_ostream &log(raw_ostream &) const override;
Twine getResourceTypeName() const override { return "CLASS"; }
Error visit(Visitor *V) const override { return V->visitClassStmt(this); }
};
} }
#endif