Added mixins for classes.

This commit is contained in:
Chronos Ouroboros 2019-11-01 18:33:15 -03:00
parent 4c7c1138aa
commit e63b6d494a
7 changed files with 206 additions and 0 deletions

View file

@ -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 *}

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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); }

View file

@ -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'")