mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 00:20:51 +00:00
Added mixins for classes.
This commit is contained in:
parent
4c7c1138aa
commit
e63b6d494a
7 changed files with 206 additions and 0 deletions
|
@ -179,6 +179,7 @@ translation_unit(X) ::= translation_unit(X) EOF.
|
||||||
translation_unit(X) ::= error. { X = NULL; }
|
translation_unit(X) ::= error. { X = NULL; }
|
||||||
|
|
||||||
%type external_declaration {ZCC_TreeNode *}
|
%type external_declaration {ZCC_TreeNode *}
|
||||||
|
external_declaration(X) ::= mixin_definition(A). { X = A; /*X-overwrites-A*/ }
|
||||||
external_declaration(X) ::= class_definition(A). { X = A; /*X-overwrites-A*/ }
|
external_declaration(X) ::= class_definition(A). { X = A; /*X-overwrites-A*/ }
|
||||||
external_declaration(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
external_declaration(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
external_declaration(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
external_declaration(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
@ -312,6 +313,7 @@ class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; /*X-overwrites-A*/ }
|
||||||
class_innards(X) ::= . { X = NULL; }
|
class_innards(X) ::= . { X = NULL; }
|
||||||
class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); }
|
class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); }
|
||||||
|
|
||||||
|
%type mixin_statement{ZCC_MixinStmt *}
|
||||||
%type property_def{ZCC_Property *}
|
%type property_def{ZCC_Property *}
|
||||||
%type flag_def{ZCC_FlagDef *}
|
%type flag_def{ZCC_FlagDef *}
|
||||||
%type struct_def{ZCC_Struct *}
|
%type struct_def{ZCC_Struct *}
|
||||||
|
@ -320,6 +322,7 @@ class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); }
|
||||||
%type const_def {ZCC_ConstantDef *}
|
%type const_def {ZCC_ConstantDef *}
|
||||||
|
|
||||||
class_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
class_member(X) ::= mixin_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
@ -330,6 +333,14 @@ class_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
|
|
||||||
|
/*----- Mixin statement -----*/
|
||||||
|
mixin_statement(X) ::= MIXIN(T) IDENTIFIER(A) SEMICOLON.
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(MixinStmt,stmt,T);
|
||||||
|
stmt->MixinName = A.Name();
|
||||||
|
X = stmt;
|
||||||
|
}
|
||||||
|
|
||||||
/*----- Struct Definition -----*/
|
/*----- Struct Definition -----*/
|
||||||
/* Structs can define variables and enums. */
|
/* Structs can define variables and enums. */
|
||||||
|
|
||||||
|
@ -510,6 +521,51 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */
|
||||||
X = node;
|
X = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************ Mixin Definition ************/
|
||||||
|
/* Can only occur at global scope. */
|
||||||
|
|
||||||
|
%type mixin_definition{ZCC_MixinDef *}
|
||||||
|
%type mixin_class_definition{ZCC_MixinDef *}
|
||||||
|
|
||||||
|
mixin_definition(X) ::= mixin_class_definition(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
|
/*------ Mixin Class Definition ------*/
|
||||||
|
%type mixin_class_body{ZCC_TreeNode *}
|
||||||
|
%type mixin_class_member{ZCC_TreeNode *}
|
||||||
|
|
||||||
|
mixin_class_definition(X) ::= MIXIN(T) CLASS IDENTIFIER(A) LBRACE mixin_class_body(B) RBRACE.
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(MixinDef,def,T);
|
||||||
|
def->Body = B;
|
||||||
|
def->NodeName = A.Name();
|
||||||
|
def->MixinType = ZCC_Mixin_Class;
|
||||||
|
def->Symbol = nullptr;
|
||||||
|
X = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------ Mixin Class Body ------*/
|
||||||
|
// Body is a list of:
|
||||||
|
// * variable definitions
|
||||||
|
// * function definitions
|
||||||
|
// * enum definitions
|
||||||
|
// * struct definitions
|
||||||
|
// * state definitions
|
||||||
|
// * constants
|
||||||
|
// * defaults
|
||||||
|
|
||||||
|
mixin_class_body(X) ::= . { X = NULL; }
|
||||||
|
mixin_class_body(X) ::= mixin_class_body(X) mixin_class_member(B). { SAFE_APPEND(X,B); }
|
||||||
|
|
||||||
|
mixin_class_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= default_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= property_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
mixin_class_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
/************ States ************/
|
/************ States ************/
|
||||||
|
|
||||||
%type states_body {ZCC_StatePart *}
|
%type states_body {ZCC_StatePart *}
|
||||||
|
|
|
@ -132,6 +132,8 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = cnode->Body;
|
auto node = cnode->Body;
|
||||||
|
auto origNextNode = cnode->Body;
|
||||||
|
ZCC_MixinDef *mixinDef = nullptr;
|
||||||
PSymbolTreeNode *childnode;
|
PSymbolTreeNode *childnode;
|
||||||
ZCC_Enum *enumType = nullptr;
|
ZCC_Enum *enumType = nullptr;
|
||||||
|
|
||||||
|
@ -140,6 +142,34 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
||||||
{
|
{
|
||||||
switch (node->NodeType)
|
switch (node->NodeType)
|
||||||
{
|
{
|
||||||
|
case AST_MixinStmt:
|
||||||
|
{
|
||||||
|
auto mixinStmt = static_cast<ZCC_MixinStmt *>(node);
|
||||||
|
for (auto mx : Mixins)
|
||||||
|
{
|
||||||
|
if (mx->mixin->NodeName == mixinStmt->MixinName)
|
||||||
|
{
|
||||||
|
if (mx->mixin->MixinType != ZCC_Mixin_Class)
|
||||||
|
{
|
||||||
|
Error(node, "Mixin %s is not a class mixin.", FName(mixinStmt->MixinName).GetChars());
|
||||||
|
}
|
||||||
|
|
||||||
|
mixinDef = mx->mixin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mixinDef == nullptr)
|
||||||
|
{
|
||||||
|
Error(node, "Mixin %s does not exist.", FName(mixinStmt->MixinName).GetChars());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
origNextNode = node->SiblingNext;
|
||||||
|
node = mixinDef->Body;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_Struct:
|
case AST_Struct:
|
||||||
case AST_ConstantDef:
|
case AST_ConstantDef:
|
||||||
case AST_Enum:
|
case AST_Enum:
|
||||||
|
@ -211,11 +241,62 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
||||||
assert(0 && "Unhandled AST node type");
|
assert(0 && "Unhandled AST node type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = node->SiblingNext;
|
node = node->SiblingNext;
|
||||||
|
|
||||||
|
if (mixinDef != nullptr && node == mixinDef->Body)
|
||||||
|
{
|
||||||
|
node = origNextNode;
|
||||||
|
mixinDef = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (node != cnode->Body);
|
while (node != cnode->Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ZCCCompiler :: ProcessMixin
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ZCCCompiler::ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode)
|
||||||
|
{
|
||||||
|
ZCC_MixinWork *cls = new ZCC_MixinWork(cnode, treenode);
|
||||||
|
|
||||||
|
Mixins.Push(cls);
|
||||||
|
|
||||||
|
auto node = cnode->Body;
|
||||||
|
|
||||||
|
// Need to check if the class actually has a body.
|
||||||
|
if (node != nullptr) do
|
||||||
|
{
|
||||||
|
if (cnode->MixinType == ZCC_Mixin_Class)
|
||||||
|
{
|
||||||
|
switch (node->NodeType)
|
||||||
|
{
|
||||||
|
case AST_Struct:
|
||||||
|
case AST_ConstantDef:
|
||||||
|
case AST_Enum:
|
||||||
|
case AST_Property:
|
||||||
|
case AST_FlagDef:
|
||||||
|
case AST_VarDeclarator:
|
||||||
|
case AST_EnumTerminator:
|
||||||
|
case AST_States:
|
||||||
|
case AST_FuncDeclarator:
|
||||||
|
case AST_Default:
|
||||||
|
case AST_StaticArrayStatement:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "Unhandled AST node type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = node->SiblingNext;
|
||||||
|
} while (node != cnode->Body);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ZCCCompiler :: ProcessStruct
|
// ZCCCompiler :: ProcessStruct
|
||||||
|
@ -301,6 +382,28 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols,
|
||||||
{
|
{
|
||||||
ZCC_TreeNode *node = ast.TopNode;
|
ZCC_TreeNode *node = ast.TopNode;
|
||||||
PSymbolTreeNode *tnode;
|
PSymbolTreeNode *tnode;
|
||||||
|
|
||||||
|
// [pbeta] Mixins must be processed before everything else.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
switch (node->NodeType)
|
||||||
|
{
|
||||||
|
case AST_MixinDef:
|
||||||
|
if ((tnode = AddTreeNode(static_cast<ZCC_NamedNode *>(node)->NodeName, node, GlobalTreeNodes)))
|
||||||
|
{
|
||||||
|
switch (node->NodeType)
|
||||||
|
{
|
||||||
|
case AST_MixinDef:
|
||||||
|
ProcessMixin(static_cast<ZCC_MixinDef *>(node), tnode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = node->SiblingNext;
|
||||||
|
} while (node != ast.TopNode);
|
||||||
|
|
||||||
|
node = ast.TopNode;
|
||||||
PType *enumType = nullptr;
|
PType *enumType = nullptr;
|
||||||
ZCC_Enum *zenumType = nullptr;
|
ZCC_Enum *zenumType = nullptr;
|
||||||
|
|
||||||
|
@ -308,6 +411,10 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols,
|
||||||
{
|
{
|
||||||
switch (node->NodeType)
|
switch (node->NodeType)
|
||||||
{
|
{
|
||||||
|
case AST_MixinDef:
|
||||||
|
// [pbeta] We already processed mixins, ignore them here.
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_Class:
|
case AST_Class:
|
||||||
// a class extension should not check the tree node symbols.
|
// a class extension should not check the tree node symbols.
|
||||||
if (static_cast<ZCC_Class *>(node)->Flags == ZCC_Extension)
|
if (static_cast<ZCC_Class *>(node)->Flags == ZCC_Extension)
|
||||||
|
|
|
@ -71,6 +71,23 @@ struct ZCC_ClassWork : public ZCC_StructWork
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_MixinWork
|
||||||
|
{
|
||||||
|
PSymbolTable TreeNodes;
|
||||||
|
ZCC_MixinDef *mixin;
|
||||||
|
PSymbolTreeNode *node;
|
||||||
|
|
||||||
|
ZCC_MixinWork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ZCC_MixinWork(ZCC_MixinDef *m, PSymbolTreeNode *n)
|
||||||
|
{
|
||||||
|
mixin = m;
|
||||||
|
node = n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_PropertyWork
|
struct ZCC_PropertyWork
|
||||||
{
|
{
|
||||||
ZCC_Property *prop;
|
ZCC_Property *prop;
|
||||||
|
@ -99,6 +116,7 @@ private:
|
||||||
FString StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls);
|
FString StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls);
|
||||||
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
|
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
|
||||||
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
|
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
|
||||||
|
void ProcessMixin(ZCC_MixinDef *cnode, PSymbolTreeNode *treenode);
|
||||||
void CreateStructTypes();
|
void CreateStructTypes();
|
||||||
void CreateClassTypes();
|
void CreateClassTypes();
|
||||||
void CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PContainerType *cls, PSymbolTable *ot);
|
void CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PContainerType *cls, PSymbolTable *ot);
|
||||||
|
@ -131,6 +149,7 @@ private:
|
||||||
TArray<ZCC_ConstantDef *> Constants;
|
TArray<ZCC_ConstantDef *> Constants;
|
||||||
TArray<ZCC_StructWork *> Structs;
|
TArray<ZCC_StructWork *> Structs;
|
||||||
TArray<ZCC_ClassWork *> Classes;
|
TArray<ZCC_ClassWork *> Classes;
|
||||||
|
TArray<ZCC_MixinWork *> Mixins;
|
||||||
TArray<ZCC_PropertyWork *> Properties;
|
TArray<ZCC_PropertyWork *> Properties;
|
||||||
VersionInfo mVersion;
|
VersionInfo mVersion;
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ static void InitTokenMap()
|
||||||
TOKENDEF (TK_Struct, ZCC_STRUCT);
|
TOKENDEF (TK_Struct, ZCC_STRUCT);
|
||||||
TOKENDEF (TK_Property, ZCC_PROPERTY);
|
TOKENDEF (TK_Property, ZCC_PROPERTY);
|
||||||
TOKENDEF (TK_FlagDef, ZCC_FLAGDEF);
|
TOKENDEF (TK_FlagDef, ZCC_FLAGDEF);
|
||||||
|
TOKENDEF (TK_Mixin, ZCC_MIXIN);
|
||||||
TOKENDEF (TK_Transient, ZCC_TRANSIENT);
|
TOKENDEF (TK_Transient, ZCC_TRANSIENT);
|
||||||
TOKENDEF (TK_Enum, ZCC_ENUM);
|
TOKENDEF (TK_Enum, ZCC_ENUM);
|
||||||
TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte);
|
TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte);
|
||||||
|
|
|
@ -135,6 +135,8 @@ enum EZCCTreeNodeType
|
||||||
AST_StaticArrayStatement,
|
AST_StaticArrayStatement,
|
||||||
AST_Property,
|
AST_Property,
|
||||||
AST_FlagDef,
|
AST_FlagDef,
|
||||||
|
AST_MixinDef,
|
||||||
|
AST_MixinStmt,
|
||||||
|
|
||||||
NUM_AST_NODE_TYPES
|
NUM_AST_NODE_TYPES
|
||||||
};
|
};
|
||||||
|
@ -168,6 +170,13 @@ enum EZCCBuiltinType
|
||||||
ZCC_NUM_BUILT_IN_TYPES
|
ZCC_NUM_BUILT_IN_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum EZCCMixinType
|
||||||
|
{
|
||||||
|
ZCC_Mixin_Class,
|
||||||
|
|
||||||
|
ZCC_NUM_MIXIN_TYPES
|
||||||
|
};
|
||||||
|
|
||||||
enum EZCCExprType
|
enum EZCCExprType
|
||||||
{
|
{
|
||||||
#define xx(a,z) PEX_##a,
|
#define xx(a,z) PEX_##a,
|
||||||
|
@ -241,6 +250,13 @@ struct ZCC_Class : ZCC_Struct
|
||||||
PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
|
PClass *CType() { return static_cast<PClassType *>(Type)->Descriptor; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_MixinDef : ZCC_NamedNode
|
||||||
|
{
|
||||||
|
ZCC_TreeNode *Body;
|
||||||
|
|
||||||
|
EZCCMixinType MixinType;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_Enum : ZCC_NamedNode
|
struct ZCC_Enum : ZCC_NamedNode
|
||||||
{
|
{
|
||||||
EZCCBuiltinType EnumType;
|
EZCCBuiltinType EnumType;
|
||||||
|
@ -568,6 +584,11 @@ struct ZCC_FlagStmt : ZCC_Statement
|
||||||
bool set;
|
bool set;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_MixinStmt : ZCC_Statement
|
||||||
|
{
|
||||||
|
ENamedName MixinName;
|
||||||
|
};
|
||||||
|
|
||||||
FString ZCC_PrintAST(ZCC_TreeNode *root);
|
FString ZCC_PrintAST(ZCC_TreeNode *root);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,7 @@ std2:
|
||||||
'void' { RET(TK_Void); }
|
'void' { RET(TK_Void); }
|
||||||
'struct' { RET(TK_Struct); }
|
'struct' { RET(TK_Struct); }
|
||||||
'class' { RET(TK_Class); }
|
'class' { RET(TK_Class); }
|
||||||
|
'mixin' { RET(TK_Mixin); }
|
||||||
'enum' { RET(TK_Enum); }
|
'enum' { RET(TK_Enum); }
|
||||||
'name' { RET(TK_Name); }
|
'name' { RET(TK_Name); }
|
||||||
'string' { RET(TK_String); }
|
'string' { RET(TK_String); }
|
||||||
|
|
|
@ -70,6 +70,7 @@ xx(TK_Struct, "'struct'")
|
||||||
xx(TK_FlagDef, "'flagdef'")
|
xx(TK_FlagDef, "'flagdef'")
|
||||||
xx(TK_Property, "'property'")
|
xx(TK_Property, "'property'")
|
||||||
xx(TK_Class, "'class'")
|
xx(TK_Class, "'class'")
|
||||||
|
xx(TK_Mixin, "'mixin'")
|
||||||
xx(TK_Enum, "'enum'")
|
xx(TK_Enum, "'enum'")
|
||||||
xx(TK_Name, "'name'")
|
xx(TK_Name, "'name'")
|
||||||
xx(TK_String, "'string'")
|
xx(TK_String, "'string'")
|
||||||
|
|
Loading…
Reference in a new issue