/* This file is part of KDevelop
    Copyright 2002-2005 Roberto Raggi <roberto@kdevelop.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef AST_H
#define AST_H

#include "memorypool.h"
#include "listnode.h"

#define DECLARE_AST_NODE(k) \
    enum { __node_kind = Kind_##k };

class ParseSession;
struct AccessSpecifierAST;
struct AsmDefinitionAST;
struct BaseClauseAST;
struct BaseSpecifierAST;
struct BinaryExpressionAST;
struct CastExpressionAST;
struct ClassMemberAccessAST;
struct ClassSpecifierAST;
struct CompoundStatementAST;
struct ConditionAST;
struct ConditionalExpressionAST;
struct CppCastExpressionAST;
struct CtorInitializerAST;
struct DeclarationAST;
struct DeclarationStatementAST;
struct DeclaratorAST;
struct DeleteExpressionAST;
struct DoStatementAST;
struct Elaborated;
struct EnumSpecifierAST;
struct EnumeratorAST;
struct ExceptionSpecificationAST;
struct ExpressionAST;
struct ExpressionOrDeclarationStatementAST;
struct ExpressionStatementAST;
struct ForStatementAST;
struct FunctionCallAST;
struct FunctionDefinitionAST;
struct IfStatementAST;
struct IncrDecrExpressionAST;
struct InitDeclaratorAST;
struct InitializerAST;
struct InitializerClauseAST;
struct LabeledStatementAST;
struct LinkageBodyAST;
struct LinkageSpecificationAST;
struct MemInitializerAST;
struct NameAST;
struct NamespaceAST;
struct NamespaceAliasDefinitionAST;
struct NewDeclaratorAST;
struct NewExpressionAST;
struct NewInitializerAST;
struct NewTypeIdAST;
struct OperatorAST;
struct OperatorFunctionIdAST;
struct ParameterDeclarationAST;
struct ParameterDeclarationClauseAST;
struct PostfixExpressionAST;
struct PrimaryExpressionAST;
struct PtrOperatorAST;
struct PtrToMemberAST;
struct ReturnStatementAST;
struct SimpleDeclarationAST;
struct SimpleTypeSpecifierAST;
struct SizeofExpressionAST;
struct StatementAST;
struct StringLiteralAST;
struct SubscriptExpressionAST;
struct SwitchStatementAST;
struct TemplateArgumentAST;
struct TemplateDeclarationAST;
struct TemplateParameterAST;
struct ThrowExpressionAST;
struct TranslationUnitAST;
struct TryBlockStatementAST;
struct CatchStatementAST;
struct TypeIdAST;
struct TypeIdentificationAST;
struct TypeParameterAST;
struct TypeSpecifierAST;
struct TypedefAST;
struct UnaryExpressionAST;
struct UnqualifiedNameAST;
struct UsingAST;
struct UsingDirectiveAST;
struct WhileStatementAST;
struct WinDeclSpecAST;

struct AST
{///@warning When adding new nodes here, also modify the names[] array in dumptree.cpp
  enum NODE_KIND
    {
      Kind_UNKNOWN = 0,

      Kind_AccessSpecifier,                     // 1
      Kind_AsmDefinition,                       // 2
      Kind_BaseClause,                          // 3
      Kind_BaseSpecifier,                       // 4
      Kind_BinaryExpression,                    // 5
      Kind_CastExpression,                      // 6
      Kind_ClassMemberAccess,                   // 7
      Kind_ClassSpecifier,                      // 8
      Kind_CompoundStatement,                   // 9
      Kind_Condition,                           // 10
      Kind_ConditionalExpression,               // 11
      Kind_CppCastExpression,                   // 12
      Kind_CtorInitializer,                     // 13
      Kind_DeclarationStatement,                // 14
      Kind_Declarator,                          // 15
      Kind_DeleteExpression,                    // 16
      Kind_DoStatement,                         // 17
      Kind_ElaboratedTypeSpecifier,             // 18
      Kind_EnumSpecifier,                       // 19
      Kind_Enumerator,                          // 20
      Kind_ExceptionSpecification,              // 21
      Kind_ExpressionOrDeclarationStatement,    // 22
      Kind_ExpressionStatement,                 // 23
      Kind_ForStatement,                        // 24
      Kind_FunctionCall,                        // 25
      Kind_FunctionDefinition,                  // 26
      Kind_IfStatement,                         // 27
      Kind_IncrDecrExpression,                  // 28
      Kind_InitDeclarator,                      // 29
      Kind_Initializer,                         // 30
      Kind_InitializerClause,                   // 31
      Kind_LabeledStatement,                    // 32
      Kind_LinkageBody,                         // 33
      Kind_LinkageSpecification,                // 34
      Kind_MemInitializer,                      // 35
      Kind_Name,                                // 36
      Kind_Namespace,                           // 37
      Kind_NamespaceAliasDefinition,            // 38
      Kind_NewDeclarator,                       // 39
      Kind_NewExpression,                       // 40
      Kind_NewInitializer,                      // 41
      Kind_NewTypeId,                           // 42
      Kind_Operator,                            // 43
      Kind_OperatorFunctionId,                  // 44
      Kind_ParameterDeclaration,                // 45
      Kind_ParameterDeclarationClause,          // 46
      Kind_PostfixExpression,                   // 47
      Kind_PrimaryExpression,                   // 48
      Kind_PtrOperator,                         // 49
      Kind_PtrToMember,                         // 50
      Kind_ReturnStatement,                     // 51
      Kind_SimpleDeclaration,                   // 52
      Kind_SimpleTypeSpecifier,                 // 53
      Kind_SizeofExpression,                    // 54
      Kind_StringLiteral,                       // 55
      Kind_SubscriptExpression,                 // 56
      Kind_SwitchStatement,                     // 57
      Kind_TemplateArgument,                    // 58
      Kind_TemplateDeclaration,                 // 59
      Kind_TemplateParameter,                   // 60
      Kind_ThrowExpression,                     // 61
      Kind_TranslationUnit,                     // 62
      Kind_TryBlockStatement,                   // 63
      Kind_CatchStatement,                      // 64
      Kind_TypeId,                              // 65
      Kind_TypeIdentification,                  // 66
      Kind_TypeParameter,                       // 67
      Kind_Typedef,                             // 68
      Kind_UnaryExpression,                     // 69
      Kind_UnqualifiedName,                     // 70
      Kind_Using,                               // 71
      Kind_UsingDirective,                      // 72
      Kind_WhileStatement,                      // 73
      Kind_WinDeclSpec,                         // 74
      Kind_Comment,                             // 75
      Kind_JumpStatement,                       // 76
      Kind_SignalSlotExpression,                     // 77
      NODE_KIND_COUNT
    };

  int kind;

  std::size_t start_token;
  std::size_t end_token;
};

struct CommentAST {
  const ListNode<std::size_t> *comments; //A list of comment-tokens
};

struct TypeSpecifierAST: public AST
{
  const ListNode<std::size_t> *cv; // const or volatile tokens
};

struct StatementAST: public AST
{
};

struct ExpressionAST: public AST
{
};

struct DeclarationAST: public AST, public CommentAST
{
};

struct AccessSpecifierAST: public DeclarationAST
{
  DECLARE_AST_NODE(AccessSpecifier)

  const ListNode<std::size_t> *specs;
};

struct AsmDefinitionAST: public DeclarationAST
{
  DECLARE_AST_NODE(AsmDefinition)

  const ListNode<std::size_t> *cv;
};

struct BaseClauseAST: public AST // ### kill me
{
  DECLARE_AST_NODE(BaseClause)

  const ListNode<BaseSpecifierAST*> *base_specifiers;
};

struct BaseSpecifierAST: public AST
{
  DECLARE_AST_NODE(BaseSpecifier)

  std::size_t virt;
  std::size_t access_specifier;
  NameAST *name;
};

struct BinaryExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(BinaryExpression)

  std::size_t op; //Index of the token that describes the operator
  ExpressionAST *left_expression;
  ExpressionAST *right_expression;
};

///An expression used to do more detailed processing of SIGNAL(..) and SLOT(..) specifications
struct SignalSlotExpressionAST : public ExpressionAST {
  DECLARE_AST_NODE(SignalSlotExpression)
  //The unqualified name also contains the argument types in its template-arguments
  UnqualifiedNameAST *name;
};

struct CastExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(CastExpression)

  TypeIdAST *type_id;
  ExpressionAST *expression;
};

struct ClassMemberAccessAST: public ExpressionAST
{
  DECLARE_AST_NODE(ClassMemberAccess)

  std::size_t op; //Index of the token that describes the operator
  NameAST *name;
};

struct ClassSpecifierAST: public TypeSpecifierAST
{
  DECLARE_AST_NODE(ClassSpecifier)

  WinDeclSpecAST *win_decl_specifiers;
  std::size_t class_key;
  NameAST *name;
  BaseClauseAST *base_clause;
  const ListNode<DeclarationAST*> *member_specs;
};

struct CompoundStatementAST: public StatementAST
{
  DECLARE_AST_NODE(CompoundStatement)

  const ListNode<StatementAST*> *statements;
};

struct ConditionAST: public AST
{
  DECLARE_AST_NODE(Condition)

  TypeSpecifierAST *type_specifier;
  DeclaratorAST *declarator;
  ExpressionAST *expression;
};

struct ConditionalExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(ConditionalExpression)

  ExpressionAST *condition;
  ExpressionAST *left_expression;
  ExpressionAST *right_expression;
};

/**
 * type_id is the type that should be casted to
 * expression is the expression casted from
 * sub_expressions is a list of post-fix expressions, see PostfixExpressionAST
 */
struct CppCastExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(CppCastExpression)

  std::size_t op; //Index of the token that describes the operator
  TypeIdAST *type_id;
  ExpressionAST *expression;
  const ListNode<ExpressionAST*> *sub_expressions;
};

struct CtorInitializerAST: public AST
{
  DECLARE_AST_NODE(CtorInitializer)

  std::size_t colon;
  const ListNode<MemInitializerAST*> *member_initializers;
};

struct DeclarationStatementAST: public StatementAST
{
  DECLARE_AST_NODE(DeclarationStatement)

  DeclarationAST *declaration;
};

struct DeclaratorAST: public AST
{
  DECLARE_AST_NODE(Declarator)

  const ListNode<PtrOperatorAST*> *ptr_ops;
  DeclaratorAST *sub_declarator;
  NameAST *id;
  ExpressionAST *bit_expression;
  const ListNode<ExpressionAST*> *array_dimensions;
  
  bool parameter_is_initializer; //Used by the declaration-builder to mark a parameter-declaration clause as a mis-parsed initializer
  ParameterDeclarationClauseAST *parameter_declaration_clause;
  const ListNode<std::size_t> *fun_cv;
  ExceptionSpecificationAST *exception_spec;
};

struct DeleteExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(DeleteExpression)

  std::size_t scope_token;
  std::size_t delete_token;
  std::size_t lbracket_token;
  std::size_t rbracket_token;
  ExpressionAST *expression;
};

struct DoStatementAST: public StatementAST
{
  DECLARE_AST_NODE(DoStatement)

  StatementAST *statement;
  ExpressionAST *expression;
};

struct ElaboratedTypeSpecifierAST: public TypeSpecifierAST
{
  DECLARE_AST_NODE(ElaboratedTypeSpecifier)

  std::size_t type;
  NameAST *name;
};

struct EnumSpecifierAST: public TypeSpecifierAST
{
  DECLARE_AST_NODE(EnumSpecifier)

  NameAST *name;
  const ListNode<EnumeratorAST*> *enumerators;
};

struct EnumeratorAST: public AST, public  CommentAST
{
  DECLARE_AST_NODE(Enumerator)

  std::size_t id;
  ExpressionAST *expression;
};

struct ExceptionSpecificationAST: public AST
{
  DECLARE_AST_NODE(ExceptionSpecification)

  std::size_t ellipsis;
  const ListNode<TypeIdAST*> *type_ids;
};

struct ExpressionOrDeclarationStatementAST: public StatementAST
{
  DECLARE_AST_NODE(ExpressionOrDeclarationStatement)

  StatementAST *expression;
  StatementAST *declaration;

  // This was not originally part of the AST - added by the context visitor
  bool expressionChosen;
};

///An expression terminated by a semicolon or similar
struct ExpressionStatementAST: public StatementAST
{
  DECLARE_AST_NODE(ExpressionStatement)

  ExpressionAST *expression;
};

struct FunctionCallAST: public ExpressionAST
{
  DECLARE_AST_NODE(FunctionCall)

  ExpressionAST *arguments;
};

struct FunctionDefinitionAST: public DeclarationAST
{
  DECLARE_AST_NODE(FunctionDefinition)

  const ListNode<std::size_t> *storage_specifiers;
  const ListNode<std::size_t> *function_specifiers;
  TypeSpecifierAST *type_specifier;
  InitDeclaratorAST *init_declarator;
  StatementAST *function_body;
  WinDeclSpecAST *win_decl_specifiers;
  CtorInitializerAST *constructor_initializers;
};

struct ForStatementAST: public StatementAST
{
  DECLARE_AST_NODE(ForStatement)

  StatementAST *init_statement;
  ConditionAST *condition;
  ExpressionAST *expression;
  StatementAST *statement;
};

struct IfStatementAST: public StatementAST
{
  DECLARE_AST_NODE(IfStatement)

  ConditionAST *condition;
  StatementAST *statement;
  StatementAST *else_statement;
};

struct IncrDecrExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(IncrDecrExpression)

  std::size_t op; //Index of the token that describes the operator
};

struct InitDeclaratorAST: public AST
{
  DECLARE_AST_NODE(InitDeclarator)

  DeclaratorAST *declarator;
  InitializerAST *initializer;
};

struct InitializerAST: public AST
{
  DECLARE_AST_NODE(Initializer)

  InitializerClauseAST *initializer_clause;
  ExpressionAST *expression;
};

struct InitializerClauseAST: public AST
{
  DECLARE_AST_NODE(InitializerClause)

  // either 'expression' or 'initializer_list' or neither are used.
  // neither are used when the clause represents the empty initializer "{}"

  // assignment expression
  ExpressionAST *expression;
  const ListNode<InitializerClauseAST*> *initializer_list;
};

struct LabeledStatementAST: public StatementAST
{
  DECLARE_AST_NODE(LabeledStatement)

  std::size_t label;
  //The constant label expression
  ExpressionAST *expression;
  StatementAST* statement;
};

struct LinkageBodyAST: public AST
{
  DECLARE_AST_NODE(LinkageBody)

  const ListNode<DeclarationAST*> *declarations;
};

struct LinkageSpecificationAST: public DeclarationAST
{
  DECLARE_AST_NODE(LinkageSpecification)

  std::size_t extern_type;
  LinkageBodyAST *linkage_body;
  DeclarationAST *declaration;
};

struct MemInitializerAST: public AST
{
  DECLARE_AST_NODE(MemInitializer)

  NameAST *initializer_id;
  ExpressionAST *expression;
};

struct NameAST: public AST
{
  DECLARE_AST_NODE(Name)

  bool global;
  const ListNode<UnqualifiedNameAST*> *qualified_names;
  UnqualifiedNameAST *unqualified_name;
};

struct NamespaceAST: public DeclarationAST
{
  DECLARE_AST_NODE(Namespace)

  std::size_t namespace_name;
  LinkageBodyAST *linkage_body;
};

struct NamespaceAliasDefinitionAST: public DeclarationAST
{
  DECLARE_AST_NODE(NamespaceAliasDefinition)

  std::size_t namespace_name;
  NameAST *alias_name;
};

struct NewDeclaratorAST: public AST
{
  DECLARE_AST_NODE(NewDeclarator)

  PtrOperatorAST *ptr_op;
  NewDeclaratorAST *sub_declarator;
  const ListNode<ExpressionAST*> *expressions;
};

struct NewExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(NewExpression)

  std::size_t scope_token;
  std::size_t new_token;
  ExpressionAST *expression;
  TypeIdAST *type_id;
  NewTypeIdAST *new_type_id;
  NewInitializerAST *new_initializer;
};

struct NewInitializerAST: public AST
{
  DECLARE_AST_NODE(NewInitializer)

  ExpressionAST *expression;
};

struct NewTypeIdAST: public AST
{
  DECLARE_AST_NODE(NewTypeId)

  TypeSpecifierAST *type_specifier;
  NewInitializerAST *new_initializer;
  NewDeclaratorAST *new_declarator;
};

struct OperatorAST: public AST
{
  DECLARE_AST_NODE(Operator)

  std::size_t op; //Index of the token that describes the operator
  std::size_t open;
  std::size_t close;
};

struct OperatorFunctionIdAST: public AST
{
  DECLARE_AST_NODE(OperatorFunctionId)

  OperatorAST *op;
  TypeSpecifierAST *type_specifier;
  const ListNode<PtrOperatorAST*> *ptr_ops;
};

struct ParameterDeclarationAST: public AST
{
  DECLARE_AST_NODE(ParameterDeclaration)

  TypeSpecifierAST *type_specifier;
  DeclaratorAST *declarator;
  ExpressionAST *expression;
};

struct ParameterDeclarationClauseAST: public AST
{
  DECLARE_AST_NODE(ParameterDeclarationClause)

  const ListNode<ParameterDeclarationAST*> *parameter_declarations;
  std::size_t ellipsis;
};

/**
 * A post-fix expression is an expression that consists of one primary expression and multiple sub-expressions that are evaluated from
 * left to right, each  sub-expression based on the previous expression.
 *
 *
 * Examples:
 * "a->b"  : "a" is the primary expression, "->b" is a sub-expression
 * "a->b(5,3)" : "a" is the primary expression, "->b" is a sub-expression, and "(5,3)" is a sub-expression
 **/
struct PostfixExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(PostfixExpression)

  TypeSpecifierAST *type_specifier;
  ExpressionAST *expression;
  const ListNode<ExpressionAST*> *sub_expressions;
};

struct PrimaryExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(PrimaryExpression)

  StringLiteralAST *literal;
  std::size_t token;
  StatementAST *expression_statement;
  ExpressionAST *sub_expression;
  NameAST *name;
};

struct PtrOperatorAST: public AST
{
  DECLARE_AST_NODE(PtrOperator)

  const ListNode<std::size_t> *cv;
  std::size_t op; //Index of the token that describes the operator. Is zero when mem_ptr is non-zero.
  PtrToMemberAST *mem_ptr;
};

struct PtrToMemberAST: public AST
{
  DECLARE_AST_NODE(PtrToMember)
};

struct JumpStatementAST : public StatementAST
{
  DECLARE_AST_NODE(JumpStatement)

  // index of operator token which describes the jump, one of
  // 'break', 'continue' or 'goto.  Return statements are handled by
  // ReturnStatementAST
  std::size_t op;
  // identifier for 'goto' statements
  std::size_t identifier;
};

struct ReturnStatementAST: public StatementAST
{
  DECLARE_AST_NODE(ReturnStatement)

  ExpressionAST *expression;
};

struct SimpleDeclarationAST: public DeclarationAST
{
  DECLARE_AST_NODE(SimpleDeclaration)

  const ListNode<std::size_t> *storage_specifiers;
  const ListNode<std::size_t> *function_specifiers;
  TypeSpecifierAST *type_specifier;
  const ListNode<InitDeclaratorAST*> *init_declarators;
  WinDeclSpecAST *win_decl_specifiers;
};

struct SimpleTypeSpecifierAST: public TypeSpecifierAST
{
  DECLARE_AST_NODE(SimpleTypeSpecifier)

  const ListNode<std::size_t> *integrals;
  std::size_t type_of;
  TypeIdAST *type_id;
  ExpressionAST *expression;
  NameAST *name;
};

struct SizeofExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(SizeofExpression)

  std::size_t sizeof_token;
  TypeIdAST *type_id;
  ExpressionAST *expression;
};

struct StringLiteralAST: public AST
{
  DECLARE_AST_NODE(StringLiteral)

  const ListNode<std::size_t> *literals;
};

/// operator []
struct SubscriptExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(SubscriptExpression)

  ExpressionAST *subscript;
};

struct SwitchStatementAST: public StatementAST
{
  DECLARE_AST_NODE(SwitchStatement)

  ConditionAST *condition;
  StatementAST *statement;
};

struct TemplateArgumentAST: public AST
{
  DECLARE_AST_NODE(TemplateArgument)

  TypeIdAST *type_id;
  ExpressionAST *expression;
};

struct TemplateDeclarationAST: public DeclarationAST
{
  DECLARE_AST_NODE(TemplateDeclaration)

  std::size_t exported;
  const ListNode<TemplateParameterAST*> *template_parameters;
  DeclarationAST* declaration;
};

struct TemplateParameterAST: public AST
{
  DECLARE_AST_NODE(TemplateParameter)

  TypeParameterAST *type_parameter; //This is used if this is a template-parameter like "class A"
  ParameterDeclarationAST *parameter_declaration; //This is used if this is a template-parameter like "int a"
};

struct ThrowExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(ThrowExpression)

  std::size_t throw_token;
  ExpressionAST *expression;
};

struct TranslationUnitAST: public AST, public CommentAST
{
  DECLARE_AST_NODE(TranslationUnit)

  const ListNode<DeclarationAST*> *declarations;

  ///true if either a '}' was missing at the end, or there was a '}' too much.
  ///This indicates a temporary state where the user is typing, and the document is completely invalid.
  bool hadMissingCompoundTokens;
  
  // Note: non AST related, saves parsing session...
  ParseSession* session;
};

struct TryBlockStatementAST: public StatementAST
{
  DECLARE_AST_NODE(TryBlockStatement)

  StatementAST* try_block;
  const ListNode<CatchStatementAST*> *catch_blocks;
};

struct CatchStatementAST: public StatementAST
{
  DECLARE_AST_NODE(CatchStatement)

  ConditionAST* condition;
  StatementAST* statement;
};

struct TypeIdAST: public AST
{
  DECLARE_AST_NODE(TypeId)

  TypeSpecifierAST *type_specifier;
  DeclaratorAST *declarator;
};

///"typename"
struct TypeIdentificationAST: public ExpressionAST
{
  DECLARE_AST_NODE(TypeIdentification)

  std::size_t typename_token;
  NameAST *name;
  ExpressionAST *expression;
};

struct TypeParameterAST: public AST
{
  DECLARE_AST_NODE(TypeParameter)

  std::size_t type;
  NameAST *name;
  TypeIdAST *type_id;
  const ListNode<TemplateParameterAST*> *template_parameters;
  NameAST *template_name;
};

struct TypedefAST: public DeclarationAST
{
  DECLARE_AST_NODE(Typedef)

  TypeSpecifierAST *type_specifier;
  const ListNode<InitDeclaratorAST*> *init_declarators;
};

struct UnaryExpressionAST: public ExpressionAST
{
  DECLARE_AST_NODE(UnaryExpression)

  std::size_t op; //Index of the token that describes the operator
  ExpressionAST *expression;
};

struct UnqualifiedNameAST: public AST
{
  DECLARE_AST_NODE(UnqualifiedName)

  std::size_t tilde;
  std::size_t id;
  OperatorFunctionIdAST *operator_id;
  const ListNode<TemplateArgumentAST*> *template_arguments;
};

struct UsingAST: public DeclarationAST
{
  DECLARE_AST_NODE(Using)

  std::size_t type_name;
  NameAST *name;
};

struct UsingDirectiveAST: public DeclarationAST
{
  DECLARE_AST_NODE(UsingDirective)

  NameAST *name;
};

struct WhileStatementAST: public StatementAST
{
  DECLARE_AST_NODE(WhileStatement)

  ConditionAST *condition;
  StatementAST *statement;
};

struct WinDeclSpecAST: public AST
{
  DECLARE_AST_NODE(WinDeclSpec)

  std::size_t specifier;
  std::size_t modifier;
};

template <class _Tp>
_Tp *CreateNode(pool *memory_pool)
{
  _Tp *node = reinterpret_cast<_Tp*>(memory_pool->allocate(sizeof(_Tp)));
  node->kind = _Tp::__node_kind;
  return node;
}

template <class _Tp>
_Tp ast_cast(AST *item)
{
  if (item && static_cast<_Tp>(0)->__node_kind == item->kind)
    return static_cast<_Tp>(item);

  return 0;
}

#endif // AST_H

