/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     To provide a simplified framework
//              for series of source code parsers 
//              complying to generic interface
// Author:      Aleksandras Gluchovas
// Modified by: AG on 28/12/98
// Created:     22/09/98
// RCS-ID:      $Id: parserbase.h,v 1.4 2001/04/19 10:12:08 georgetasker Exp $
// Copyright:   (c) Aleskandars Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifndef __SRCPARSER_G__
#define __SRCPARSER_G__

#include "wx/string.h"
#include "wx/dynarray.h"
#include "wx/list.h"
#include "wx/txtstrm.h"

#include "wx/pmf/markup.h" // markup tags used in spOperator::GetFullName()

// context class hierarchy

class spContext;
	class spParameter;
	class spAttribute;
	class spOperation;
	class spEnumeration;
	class spTypeDef;
	class spPreprocessorLine;
	class spClass;
	class spNameSpace;
	class spFile;

class spComment;

// source context visibilities
enum SRC_VISIBLITY_TYPES
{
	SP_VIS_PUBLIC,
	SP_VIS_PROTECTED,
	SP_VIS_PRIVATE
};

// class types
enum SP_CLASS_TYPES
{
	SP_CLTYPE_CLASS,
	SP_CLTYPE_TEMPLATE_CLASS,
	SP_CLTYPE_STRUCTURE,
	SP_CLTYPE_UNION,
	SP_CLTYPE_INTERFACE
};

// inheritance types
enum SP_INHERITANCE_TYPES
{
	SP_INHERIT_VIRTUAL,
	SP_INHERIT_PUBLIC,
	SP_INHERIT_PRIVATE
};

// proprocessor definitions types (specific to C++ code)

enum SP_PREP_DEFINITION_TYPES
{
	SP_PREP_DEF_DEFINE_SYMBOL,
	SP_PREP_DEF_REDEFINE_SYMBOL,
	SP_PREP_DEF_INCLUDE_FILE,
	SP_PREP_DEF_OTHER
};

// common context types

enum SP_CONTEXT_TYPE
{
	SP_CTX_UNKNOWN = 100,
	SP_CTX_FILE,
	SP_CTX_NAMESPACE,
	SP_CTX_CLASS,
	SP_CTX_TYPEDEF,
	SP_CTX_PREPROCESSOR,
	SP_CTX_ENUMERATION,
	SP_CTX_ATTRIBUTE,
	SP_CTX_OPERATION,
	SP_CTX_PARAMETER
};

// other (custom) context codes may be defined elsewere, however they should
// not clash with above codes for common type and also should not
// exceed 16-bits of in value 

// masks all context types (up to 32 custom context can be defined)

#define SP_CTX_ANY           0xFFFFFFFF

// misc. modifiers (can be ORed with context type)

// TODO:: replace bool's with "int flags" to reduce memory consumption

#define SP_FLAG_VIS_PUBLIC       0x01
#define SP_FLAG_VIS_PRIVATE      0x02
#define SP_FLAG_VIS_PROTECTED    0x04
#define SP_FLAG_IS_DEFINITION    0x08
#define SP_FLAG_IS_STATIC        0x10
#define SP_FLAG_IS_CONSTANT      0x20
#define SP_FLAG_IS_VIRTUAL       0x40
#define SP_FLAG_IS_PURE_VIRTUAL  0x80

WX_DEFINE_ARRAY( spContext*,   MMemberListT );
WX_DEFINE_ARRAY( spComment*,   MCommentListT );
WX_DEFINE_ARRAY( spParameter*, MParamListT );

// base class for all visitors of source code contents

class spVisitor 
{
protected:
	bool mSiblingSkipped;
	bool mChildSkipped;
	int  mContextMask;

	spContext* mpCurCxt;

public:
	// methods invoked by context

	// method invoked from user's controling code
	// to visit all nodes staring at the given context.
	// Content is sorted if requrired, see comments 
	// spClass on sorting the class members

	void VisitAll( spContext& atContext,
				   bool sortContent = TRUE
				 );

	// methods invoked by visitor

	// goes to the next context in the outter scope
	// NOTE:: should not be invoked more than once while
	//        visiting certain context

	void SkipSiblings();

	// prevents going down into the contexts contained by
	// the current context
	// NOTE:: the same as above

	void SkipChildren();

	// can be called only in from visiting procedure
	void RemoveCurrentContext();

	// method enables fast filtered traversal
	// of source content, e.g. collecting only classes,
	// or only global functions

	// arg. context - can contain combination of contexts concatinated
	//           with bitwise OR, e.g. SP_CTX_CLASS | SP_CTX_NAMESPACE
	//
	// method can be invoked from the user's controling as well as
	// from within the visting procedure

	void SetFilter( int contextMask );

	// methods should be implemneted by specific visitor:

	// NOTE:: Do not confuse visiting with parsing, first
	//        the source is parsed, and than can be visited
	//        multiple times by variouse visitors (there can
	//        be more the one visitor visiting content at a time)

	virtual void VisitFile( spFile& fl ) {}

	virtual void VisitNameSpace( spNameSpace& ns ) {}   

	virtual void VisitClass( spClass& cl ) {}

	virtual void VisitEnumeration( spEnumeration& en ) {}

	virtual void VisitTypeDef( spTypeDef& td ) {}

	virtual void VisitPreprocessorLine( spPreprocessorLine& pd ) {}

	virtual void VisitAttribute( spAttribute& attr ) {}

	virtual void VisitOperation( spOperation& op ) {}

	virtual void VisitParameter( spParameter& param ) {}

	virtual void VisitCustomContext( spContext& ctx ) {}
};

// stores one section of comments,
// multiple sections can be put to geather
// and attached to some context

class spComment	: public wxObject
{
public:
	wxString mText;
	bool   mIsMultiline; // multiline comments ar those with /**/'s

	// TRUE, if these was an empty empty
	// line above single line comment

	bool   mStartsPar;   
	                     
public:

	bool    IsMultiline() const;
	bool    StartsParagraph() const;

	wxString& GetText();

	// contstant version of GetText()
	wxString  GetText() const;
};

// abstract base class for common (to most languages) code 
// contexts (constructs), e.g file, namespace, class, operation, 
// etc

class spContext : public wxObject
{
public:
	// "linked" list of comments belonging to this context
	MCommentListT mComments;
	
	// NULL, if this is file context
	MMemberListT   mMembers;

	// NULL, if this is top-most context
	spContext*    mpParent;	

	int			 mFlags;

	// points to context object, where the this context
	// was originally declared, meaning that this object
	// is redeclaration (or if in the case of operation
	// this context object most probably referres to the
	// implemnetation in .cpp file for example)

	// is NULL, if this object referres to the first occurence
	// of the context

	spContext*    mpFirstOccurence;

	// used, to avoid excessive sorting of context's agreggates
	bool          mAlreadySorted;

public:

	// source line number, (-1) if unknown
	int           mSrcLineNo;

	// offset of context in the source file, (-1) if unknown
	int           mSrcOffset;

	// lentgh of the context in characters, (-1) if unknown
	int           mContextLength;

	// e.g. can be used by documentation generator to store
	// reference to section object
	void*        mpUserData;

public:
	// universal identifier of the context (e.g. class name)
	wxString        mName;    

public:
	// default constructor
	spContext();

	// automatically destorys all aggregated contexts
	// (thus, it's enought to call destructor of root-context)
	virtual ~spContext();

	// see mpUererData member;
	void* GetUserData()  { return mpUserData; }

	void SetUserData( void* pUserData );

	int  GetFlags() { return mFlags; }
	void SetFlags( int flags ) { mFlags = flags; }

	// removes refernce to user data (if any), without actually
	// destroying the refered object

	void DetachUserData();

	// searches the whole context tree for the cotnexts
	// which match given masks, pust results into lst array
	void GetContextList( MMemberListT& lst, int contextMask );

	size_t CountMembers( int type );

	// used by default visitor's implementation

	/*** forward/reverse ingineering fecilities ***/

	bool PositionIsKnown();

	// TRUE, if there is at least one entry
	// in the comment list of this context
	bool HasComments();
	inline MCommentListT& GetCommentList()
		{ return mComments; }

	// should be overriden, if the context supports sorting
	// of it's members
	virtual void SortMembers() {}

	// returns identifier of this context
	inline wxString& GetName() { return mName; }

	inline void SetName( const wxString& name ) { mName = name; }

	// returns -1, if souce line # is unknow
	inline int GetSourceLineNo() { return mSrcLineNo; }

	// see comments on mpFirstOccurence member variable
	bool IsFirstOccurence();
	spContext* GetFirstOccurence();

	// returns not-NULL value if this context
	// is aggregated by another cotnext
	spContext* GetOutterContext();

	// perhaps more intuitive alias for `GetOutterContext()'
	inline spContext* GetParent() { return mpParent; }

	bool HasOutterContext();

	// add one aggregate (or child) into this context
	void AddMember ( spContext* pMember );
	MMemberListT& GetMembers();

	// append comment to the comment list decribing
	// this context
	void AddComment( spComment* pComment );

	// returns NULL, if the context with the given
	// name and type is not contained by this context
	// and it's children. Children's children are not
	// searched recursivelly if searchSubMembers is FALSE

	spContext* FindContext( const wxString& identifier,
		                    int   contextType      = SP_CTX_ANY,
							bool  searchSubMembers = TRUE
		                  );

	// removes this context from it's parent
	// (NOTE:: context should have an outter cotnext
	//  to when this method is called, otherwise removal
	//  will result assertion failure)
	void RemoveThisContext();

	// returns TRUE, if this object is aggregated in the file
	bool IsInFile();

	// TRUE, if outter context is a namespace
	bool IsInNameSpace();

	// TRUE, if outter context is a class
	bool IsInClass();

	// TRUE, if outter cotext is an operation (TRUE for "spParameter"s)
	bool IsInOperation();

	// NOTE:: method returns not the type of this object
	//		  but the file/namespace/class/operation or file in which this
	//		  attribute is contained. First, check for the type of
	//        context using the above method. 
	
	//		  Requiering container which does not exist, will result
	//        in assertion failure

	spClass&     GetClass(); 
	spFile&      GetFile();
	spNameSpace& GetNameSpace();
	spOperation& GetOperation();

	/*** overridables ***/

	// each new context should override this method
	// to return it's specific type 
	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_UNKNOWN; }

	// perhaps more intuitive short-cut
	inline int GetType() { return GetContextType(); }

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );

	// derived classes override this to invoke VisitXXX method
	// which corresponds to the class of specific context,
	// - this is what the "Visitor" pattern told us ^)

	// if method is not overriden, then it's probably user-defined
	// custom context

	virtual void AcceptVisitor( spVisitor& visitor )
	
		{ visitor.VisitCustomContext( *this );	};

	// called by visitors, to remove given subcontext 
	// of this context object
	virtual void RemoveChild( spContext* pChild );

	virtual void RemoveChildren();

	virtual spContext* GetEnclosingContext( int mask = SP_CTX_ANY );

	virtual wxString StripTypeModifiers( const wxString& type );
};

// stores information about single argument of operation

class spParameter : public wxObject
{
public:
	wxString mName;

	// type of argument (parameter)
	wxString mType;

	// "stringified" initial value
	wxString mInitVal;
};


// stores information about member(or global) variable

class spAttribute : public spContext
{
public:
	// type of the attribute
	wxString mType;

	// it's initial value
	wxString mInitVal;

	// constantness
	bool   mIsConstant;
public:

	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_ATTRIBUTE; }

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitAttribute( *this ); }

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

class spOperation : public spContext
{
public:
	// type of return value
	wxString      mRetType;

	// argument list
	MParamListT mParams;

	// scope if any (e.g. MyClass::MyFunction(), scope stirng is "MyClass" )
	// usually found along with implementation of the method, which is now skipped

	wxString      mScope;
	wxString      mArgsDigest; // argument types concatinated into single wxString

public:
	spOperation();
	~spOperation();

	// returns full declaration of the operations
	// (ret val., identifier, arg. list),

	// arguments are marked up with italic,
	// default values marked up with bold-italic,
	// all the rest is marked as bold

	// NOTE:: this method may be overriden by class
	//        specific to concrete parser, to provide
	//        language-dependent reperesnetation of
	//        operation and it's argumetn list
	//
	// the default implementation outputs name in
	// C++/Java syntax

	virtual wxString GetFullName(MarkupTagsT tags);

	wxString FormatSignature( bool withArgNames      = TRUE,
							  bool withInitialValues = TRUE,
							  bool withReturnValue   = TRUE,
							  bool spaceArguments    = FALSE,
							  bool spaceBrackets     = TRUE  );


	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_OPERATION; }

	virtual wxString GetArgListDigest();

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitOperation( *this ); }

	virtual MParamListT& GetParams();

	virtual void AddParameter( spParameter* param );

	// overriden method of spContext

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

// stores infromation about preprocessor directive

class spPreprocessorLine : public spContext 
{

public:

	// prepocessor statement including '#' and
	// attached multiple lines with '\' character
	wxString mLine;               

	int    mDefType; // see SP_PREP_DEFINITION_TYPES enumeration 

public:

	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_PREPROCESSOR; }

	virtual int GetStatementType() { return mDefType; }

	wxString CPP_GetIncludedFileNeme();

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitPreprocessorLine( *this ); }

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

// stores information about the class 

class spClass : public spContext
{
public:
	// list of superclasses/interfaces
	wxStringList mSuperClassNames;

	// see SP_CLASS_TYPES enumeration
	int          mClassSubType;    

	// see SP_INHERITANCE_TYPES enumeration
	int          mInheritanceType;

	// valid if mClassSubType is SP_CLTYPE_TEMPLATE_CLASS
	wxString       mTemplateTypes;

	// TRUE, if it's and interface of abstract base class
	bool         mIsAbstract;

public:

	// sorts class members in the following order:
	// 
	// (by "privacy level" - first private, than protected, public)
	//
	//     within above set
	//
	//       (by member type - attributes first, than methods, nested classes)
	//
	//          within above set
	//
	//             (by identifier of the member)
	
	virtual void SortMembers();

	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_CLASS; }

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitClass( *this ); }

	// overriden member of spContext

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

// stores information about enum statement

class spEnumeration  : public spContext
{
public:
	wxString mEnumContent; // full-text content of enumeration

public:
	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_ENUMERATION; }

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitEnumeration( *this ); }
};

class spTypeDef  : public spContext
{
public:
	// the original type which is redefined
	// by this type definition
	wxString mOriginalType;

public:
	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_TYPEDEF; }

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitTypeDef( *this ); }

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

// NOTE:: files context may be put to other
//        file context, resulting in a collection
//        of parsed file contexts, with a virtual "superfile"

class spFile : public spContext
{
public:
	// since file name cannot be determined from
	// source code, filling in this field is optional
	wxString mFileName; 

public:
	virtual SP_CONTEXT_TYPE GetContextType() { return SP_CTX_FILE; }

	virtual void AcceptVisitor( spVisitor& visitor ) 
		{ visitor.VisitFile( *this ); }

	virtual void Dump( wxTextOutputStream& stm, const wxString& indent );
};

//TODO:: comments.

class SourceParserPlugin
{
public:
	virtual bool CanUnderstandContext( char* cur, char* end, spContext* pOuttterCtx ) = 0;
	virtual void ParseContext( char* start, char*& cur, char* end, spContext* pOuttterCtx ) = 0;
};

// abstract interface for source parsers
// which can output parsing results in the
// form of context-tree, where each node
// should be derivative of spContext, (see
// above classes)

class SourceParserBase
{
private:
	// auto-resizing file buffer, created in ParseFile()
	// to reuse large heap block for multiple parsings
	
	char* mpFileBuf; 
	int   mFileBufSz;

protected:
	SourceParserPlugin* mpPlugin;
	         
protected:
	// value is set in the derived parser classes
	int mParserStatus;
	spFile* FindFile( const wxString& fname );

	void ResolveLineNumbersRecursive( spContext* pCtx, 
									  char* start,
									  char*& cur, 
									  char* end, size_t& curLine );

public:
	SourceParserBase();
	virtual ~SourceParserBase();

	// loads entier source file(as text) into memory,
	// and passes it's contents to ParseAll() method,
	// memory occupied by source text is released after
	// parsing is done
	//
	// (NOTE:: this is the default implementation),

	virtual spFile* ParseFile( const char* fname, bool resolveLineNumbers = TRUE );

	// should return the root-node of the created context tree
	// (user is responsible for releasing it from the heep)
	// "end" should point to the (last character + 1) of the 
	// source text area

	virtual spFile* Parse( char* start, char* end,
						   bool resolveLineNumbers = TRUE
		                 ) = 0;

	// should return indentifiers and their types found in the 
	// given region of funciton-definition

	virtual void AnalyzeFunctionBody( char* start, char* end,
									  wxStringList& types, wxStringList& identifiers ) = 0;

	// returns parser "status word" (specific to concrete parser)
	int GetParserStatus() { return mParserStatus; }

	void SetPlugin( SourceParserPlugin* pPlugin );

	void ResolveLineNumbers( spFile* pFile, char* start, char* end );
};

#endif