<commit_before>#pragma once
#include <windows.h>
#include <string>
#include <tchar.h>
#include "RegistryUtil.h"
#include "LogOperation.h"

static CRITICAL_SECTION LogFileCS;
static HANDLE hLogFile;
static LONG LogFileCsInitialized;

BOOL LogOperation::OpenLogFile( std::string &log_filename )
{
	EnterCriticalSection( &LogFileCS );
	// Create the new file to write the upper-case version to.
	if( hLogFile == INVALID_HANDLE_VALUE )
	{
		hLogFile = CreateFile((LPTSTR) log_filename.c_str(),// file name
				GENERIC_READ | GENERIC_WRITE,// open r-w
				FILE_SHARE_READ,
				NULL,				// default security
				OPEN_ALWAYS,		// overwrite existing
				FILE_ATTRIBUTE_NORMAL,// normal file
				NULL);				// no template
		if( hLogFile == INVALID_HANDLE_VALUE )
		{
			printf("CreateFile failed for [%s] with error %u.\r\n", log_filename.c_str(), GetLastError());
			LeaveCriticalSection( &LogFileCS );
			return FALSE;
		}
		SetFilePointer(hLogFile,0,0,FILE_END);
	}
	LeaveCriticalSection( &LogFileCS );
	return TRUE;
}

void LogOperation::CloseLogFile( )
{
	EnterCriticalSection( &LogFileCS );
	if( hLogFile != INVALID_HANDLE_VALUE )
	{
		CloseHandle( hLogFile );
		hLogFile = INVALID_HANDLE_VALUE;
	}
	LeaveCriticalSection( &LogFileCS );
}

void LogOperation::_Log(const CHAR *log_message)
{
	std::string full_log_message;
	if( OutputType & LogToFile )
	{
		if( hLogFile != INVALID_HANDLE_VALUE )
		{
			EnterCriticalSection( &LogFileCS );
			DWORD bytes_written;

			SYSTEMTIME lt;
			GetLocalTime(&lt);
			char time_buffer[50];
			_snprintf(time_buffer, sizeof(time_buffer), "[%02d/%02d/%04d %02d:%02d:%02d] ",
				lt.wMonth,
				lt.wDay,
				lt.wYear,
				lt.wHour,
				lt.wMinute,
				lt.wSecond);

			full_log_message = time_buffer;
			full_log_message += " [";
			full_log_message += CategoryName.c_str();
			full_log_message += "] ";
			full_log_message += log_message;

			DWORD ret = WriteFile( hLogFile,
				full_log_message.c_str(),
				full_log_message.length(),
				&bytes_written,
				NULL);
			if( !ret )
			{
				printf("WriteFile failed with error %u.\r\n",GetLastError());
			}
			LeaveCriticalSection( &LogFileCS );
		}
		else
		{
			printf("%s", log_message);
		}
	}

	if( (OutputType & LogToDbgview) || (OutputType & LogToIDAMessageBox) || (OutputType & LogToStdout) )
	{
		full_log_message = "[";
		full_log_message += CategoryName.c_str();
		full_log_message += "] ";
		full_log_message += log_message;
	}

	if( OutputType & LogToDbgview )
		OutputDebugStringA( full_log_message.c_str() );

	if( OutputType & LogToIDAMessageBox )
	{
#ifdef IDA_PLUGIN
		msg("%s", full_log_message.c_str() );
#endif
	}

	if( OutputType & LogToStdout )
		printf("%s", full_log_message.c_str() );
}

void LogOperation::_Log(const WCHAR *log_message)
{
	CHAR log_message_a[1024];
	_snprintf(log_message_a, sizeof(log_message_a)-1, "%ws", log_message );
	_Log( log_message_a );
}

LogOperation::LogOperation( int output_type ): OutputType(output_type), DebugLevel(5)
{
	if( !GetConsoleWindow() )
		OutputType = LogToDbgview;
}

LogOperation::LogOperation( const char *category_name ): OutputType(LogToFile)
{
	SetCategory( category_name );
}

void LogOperation::InitLog()
{
	InitializeCriticalSection( &LogFileCS );
	hLogFile = INVALID_HANDLE_VALUE;
	//InterlockedExchange( &LogFileCsInitialized, 1 );
}

void LogOperation::FiniLog()
{
	//if( InterlockedExchange( &LogFileCsInitialized, 0 ) == 1 )
	{
		//CloseLogFile();
		DeleteCriticalSection( &LogFileCS );
	}
}

void LogOperation::RetrieveLogInfoFromRegistry()
{
	std::string key_name = "HKEY_LOCAL_MACHINE\\Software\\";
	key_name += CompanyName;
	key_name += "\\";
	key_name += ProductName;
	key_name += "\\Logging\\";

	std::string category_key_name = key_name;
	category_key_name += CategoryName;

	char *type = GetRegValueString( category_key_name.c_str(), "Type" );
	if( type )
	{
		if( !_stricmp( type, "stdout" ) )
		{
			OutputType = LogToStdout;
		}
		else if( !_stricmp( type, "dbgview" ) )
		{
			OutputType = LogToDbgview;
		}
		else if( !_stricmp( type, "file" ) )
		{
			OutputType = LogToFile;
		}
#ifdef IDA_PLUGIN
		else if( !_stricmp( type, "ida" ) )
		{
			OutputType = LogToIDAMessageBox;
		}
#endif
		free( type );
	}

	if( OutputType == LogToFile && hLogFile == INVALID_HANDLE_VALUE )
	{
		char *log_filename_str = GetRegValueString( key_name.c_str(), "LogFileName" );
		if( log_filename_str )
		{
			std::string log_filename = log_filename_str;
			free( log_filename_str );

			char *image_filename;
			char image_full_filename[MAX_PATH+1];
			GetModuleFileNameA( NULL, image_full_filename, MAX_PATH );
			image_filename = image_full_filename;
			for( int i = strlen( image_full_filename ) - 1; i >=0 ; i-- )
			{
				if( image_full_filename[i] == '\\' )
				{
					image_filename = image_full_filename + i + 1;
					break;
				}
			}

			log_filename += "-";
			log_filename += image_filename;

			DWORD pid = GetCurrentProcessId();
			char pid_buffer[11];

			_snprintf( pid_buffer, sizeof(pid_buffer) -1, "%d", pid );
			log_filename += "-";
			log_filename += pid_buffer;

			log_filename += ".log";
			OpenLogFile( log_filename );
		}
	}

	GetRegValueInteger( key_name.c_str(), "Level", DebugLevel );
}

void LogOperation::SetCompanyName( const char *company_name )
{
	CompanyName = company_name;
}

void LogOperation::SetProductName( const char *product_name )
{
	ProductName = product_name;
}

void LogOperation::SetCategory( const char *category_name )
{
	CategoryName = category_name;
	DebugLevel = 0;
	OutputType = LogToDbgview;
	if( CategoryName == "IEAutomator" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentMain" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "Agent" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogByLogServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentC" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorker" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorkerInBHO" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogMessage" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ApplicationServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorkerProcessor" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "HookOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProtocolTransport" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LocalCommunicator" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SocketConnection" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SocketOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "WorkQueueManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SandBoxRuleManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "Controller" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentManager::WorkOnItem" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentController" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogServer::LogServerThreadCallback" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}

	RetrieveLogInfoFromRegistry();
}

LogOperation::~LogOperation()
{
}

void LogOperation::SetOutputType( int output_type )
{
	OutputType = output_type;
}

void LogOperation::SetDebugLevel( DWORD newDebugLevel )
{
	DebugLevel = newDebugLevel;
}

void LogOperation::SetLogFilename( const char *filename )
{
	LogFilename = filename;

	CloseLogFile();
	OpenLogFile( LogFilename );
}

void LogOperation::Log( DWORD MessageDebugLevel, const CHAR *format, ... )
{
	if( MessageDebugLevel < DebugLevel  )
	{
		va_list args;
		va_start(args,format);
		CHAR log_message[1024]={0,};
		_vsnprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
		va_end(args);

		_Log(log_message);
	}
}

void LogOperation::Log( const CHAR *format, ... )
{
	va_list args;
	va_start(args,format);
	CHAR log_message[1024]={0,};
	_vsnprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
	va_end(args);
	_Log(log_message);
}

void LogOperation::Log( DWORD MessageDebugLevel, const WCHAR *format, ... )
{
	if( MessageDebugLevel < DebugLevel  )
	{
		va_list args;
		va_start(args,format);
		WCHAR log_message[1024]={0,};
		_vsnwprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
		va_end(args);

		_Log(log_message);
	}
}

void LogOperation::Log( const WCHAR *format, ... )
{
	va_list args;
	va_start(args,format);
	WCHAR log_message[1024]={0,};
	_vsnwprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
	va_end(args);
	_Log(log_message);
}

void LogOperation::DumpHex( TCHAR *Prefix, unsigned char *Buffer, int BufferLen )
{
	TCHAR LineBuffer[256];
	memset(LineBuffer,' ',50);
	LineBuffer[50]=0;
	int cursor=0;
	TCHAR ascii[17];
	int start_i=0;
	int i;
	ascii[16]=0;

	for(i=0;i<BufferLen;i++)
	{
		_tprintf( LineBuffer+(i%16)*3,"%0.2X ",Buffer[i]);
		if(isprint(Buffer[i]))
			ascii[i%16]=Buffer[i];
		else
			ascii[i%16]='.';

		if(i%16==15)
		{
			_tprintf(LineBuffer+48,TEXT("  %s"),ascii);
			Log( TEXT("%s%.8x: %s\r\n"),Prefix,start_i,LineBuffer);
			start_i=i+1;
		}
	}

	if(i%16!=0)
	{
		memset(LineBuffer+(i%16)*3,' ',(16-(i%16))*3);
		ascii[i%16]=0;
		_tprintf( LineBuffer+48, TEXT("  %s"),ascii);
		Log(TEXT("%s%.8x: %s\r\n"),Prefix,start_i,LineBuffer);
	}
}

void LogOperation::DumpHex( DWORD MessageDebugLevel, TCHAR *Prefix, unsigned char *Buffer, int BufferLen )
{
	if(MessageDebugLevel < DebugLevel)
	{
		DumpHex( Prefix, Buffer, BufferLen );
	}
}
<commit_msg>Don't try to open a log file when the log file name size is 0<commit_after>#pragma once
#include <windows.h>
#include <string>
#include <tchar.h>
#include "RegistryUtil.h"
#include "LogOperation.h"

static CRITICAL_SECTION LogFileCS;
static HANDLE hLogFile;
static LONG LogFileCsInitialized;

BOOL LogOperation::OpenLogFile( std::string &log_filename )
{
	EnterCriticalSection( &LogFileCS );
	// Create the new file to write the upper-case version to.
	if (hLogFile == INVALID_HANDLE_VALUE && log_filename.size()>0)
	{
		hLogFile = CreateFile((LPTSTR) log_filename.c_str(),// file name
				GENERIC_READ | GENERIC_WRITE,// open r-w
				FILE_SHARE_READ,
				NULL,				// default security
				OPEN_ALWAYS,		// overwrite existing
				FILE_ATTRIBUTE_NORMAL,// normal file
				NULL);				// no template
		if( hLogFile == INVALID_HANDLE_VALUE )
		{
			printf("CreateFile failed for [%s] with error %u.\r\n", log_filename.c_str(), GetLastError());
			LeaveCriticalSection( &LogFileCS );
			return FALSE;
		}
		SetFilePointer(hLogFile,0,0,FILE_END);
	}
	LeaveCriticalSection( &LogFileCS );
	return TRUE;
}

void LogOperation::CloseLogFile( )
{
	EnterCriticalSection( &LogFileCS );
	if( hLogFile != INVALID_HANDLE_VALUE )
	{
		CloseHandle( hLogFile );
		hLogFile = INVALID_HANDLE_VALUE;
	}
	LeaveCriticalSection( &LogFileCS );
}

void LogOperation::_Log(const CHAR *log_message)
{
	std::string full_log_message;
	if( OutputType & LogToFile )
	{
		if( hLogFile != INVALID_HANDLE_VALUE )
		{
			EnterCriticalSection( &LogFileCS );
			DWORD bytes_written;

			SYSTEMTIME lt;
			GetLocalTime(&lt);
			char time_buffer[50];
			_snprintf(time_buffer, sizeof(time_buffer), "[%02d/%02d/%04d %02d:%02d:%02d] ",
				lt.wMonth,
				lt.wDay,
				lt.wYear,
				lt.wHour,
				lt.wMinute,
				lt.wSecond);

			full_log_message = time_buffer;
			full_log_message += " [";
			full_log_message += CategoryName.c_str();
			full_log_message += "] ";
			full_log_message += log_message;

			DWORD ret = WriteFile( hLogFile,
				full_log_message.c_str(),
				full_log_message.length(),
				&bytes_written,
				NULL);
			if( !ret )
			{
				printf("WriteFile failed with error %u.\r\n",GetLastError());
			}
			LeaveCriticalSection( &LogFileCS );
		}
		else
		{
			printf("%s", log_message);
		}
	}

	if( (OutputType & LogToDbgview) || (OutputType & LogToIDAMessageBox) || (OutputType & LogToStdout) )
	{
		full_log_message = "[";
		full_log_message += CategoryName.c_str();
		full_log_message += "] ";
		full_log_message += log_message;
	}

	if( OutputType & LogToDbgview )
		OutputDebugStringA( full_log_message.c_str() );

	if( OutputType & LogToIDAMessageBox )
	{
#ifdef IDA_PLUGIN
		msg("%s", full_log_message.c_str() );
#endif
	}

	if( OutputType & LogToStdout )
		printf("%s", full_log_message.c_str() );
}

void LogOperation::_Log(const WCHAR *log_message)
{
	CHAR log_message_a[1024];
	_snprintf(log_message_a, sizeof(log_message_a)-1, "%ws", log_message );
	_Log( log_message_a );
}

LogOperation::LogOperation( int output_type ): OutputType(output_type), DebugLevel(5)
{
	if( !GetConsoleWindow() )
		OutputType = LogToDbgview;
}

LogOperation::LogOperation( const char *category_name ): OutputType(LogToFile)
{
	SetCategory( category_name );
}

void LogOperation::InitLog()
{
	InitializeCriticalSection( &LogFileCS );
	hLogFile = INVALID_HANDLE_VALUE;
	//InterlockedExchange( &LogFileCsInitialized, 1 );
}

void LogOperation::FiniLog()
{
	//if( InterlockedExchange( &LogFileCsInitialized, 0 ) == 1 )
	{
		//CloseLogFile();
		DeleteCriticalSection( &LogFileCS );
	}
}

void LogOperation::RetrieveLogInfoFromRegistry()
{
	std::string key_name = "HKEY_LOCAL_MACHINE\\Software\\";
	key_name += CompanyName;
	key_name += "\\";
	key_name += ProductName;
	key_name += "\\Logging\\";

	std::string category_key_name = key_name;
	category_key_name += CategoryName;

	char *type = GetRegValueString( category_key_name.c_str(), "Type" );
	if( type )
	{
		if( !_stricmp( type, "stdout" ) )
		{
			OutputType = LogToStdout;
		}
		else if( !_stricmp( type, "dbgview" ) )
		{
			OutputType = LogToDbgview;
		}
		else if( !_stricmp( type, "file" ) )
		{
			OutputType = LogToFile;
		}
#ifdef IDA_PLUGIN
		else if( !_stricmp( type, "ida" ) )
		{
			OutputType = LogToIDAMessageBox;
		}
#endif
		free( type );
	}

	if( OutputType == LogToFile && hLogFile == INVALID_HANDLE_VALUE )
	{
		char *log_filename_str = GetRegValueString( key_name.c_str(), "LogFileName" );
		if( log_filename_str )
		{
			std::string log_filename = log_filename_str;
			free( log_filename_str );

			char *image_filename;
			char image_full_filename[MAX_PATH+1];
			GetModuleFileNameA( NULL, image_full_filename, MAX_PATH );
			image_filename = image_full_filename;
			for( int i = strlen( image_full_filename ) - 1; i >=0 ; i-- )
			{
				if( image_full_filename[i] == '\\' )
				{
					image_filename = image_full_filename + i + 1;
					break;
				}
			}

			log_filename += "-";
			log_filename += image_filename;

			DWORD pid = GetCurrentProcessId();
			char pid_buffer[11];

			_snprintf( pid_buffer, sizeof(pid_buffer) -1, "%d", pid );
			log_filename += "-";
			log_filename += pid_buffer;

			log_filename += ".log";
			OpenLogFile( log_filename );
		}
	}

	GetRegValueInteger( key_name.c_str(), "Level", DebugLevel );
}

void LogOperation::SetCompanyName( const char *company_name )
{
	CompanyName = company_name;
}

void LogOperation::SetProductName( const char *product_name )
{
	ProductName = product_name;
}

void LogOperation::SetCategory( const char *category_name )
{
	CategoryName = category_name;
	DebugLevel = 0;
	OutputType = LogToDbgview;
	if( CategoryName == "IEAutomator" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentMain" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "Agent" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogByLogServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentC" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorker" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorkerInBHO" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogMessage" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ApplicationServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessWorkerProcessor" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "HookOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProcessOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "ProtocolTransport" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LocalCommunicator" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SocketConnection" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SocketOperation" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "WorkQueueManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "SandBoxRuleManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "Controller" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentManager::WorkOnItem" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentManager" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "AgentController" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogServer::LogServerThreadCallback" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}
	else if( CategoryName == "LogServer" )
	{
		DebugLevel = 0;
		OutputType = LogToDbgview;
	}

	RetrieveLogInfoFromRegistry();
}

LogOperation::~LogOperation()
{
}

void LogOperation::SetOutputType( int output_type )
{
	OutputType = output_type;
}

void LogOperation::SetDebugLevel( DWORD newDebugLevel )
{
	DebugLevel = newDebugLevel;
}

void LogOperation::SetLogFilename( const char *filename )
{
	LogFilename = filename;

	CloseLogFile();
	OpenLogFile( LogFilename );
}

void LogOperation::Log( DWORD MessageDebugLevel, const CHAR *format, ... )
{
	if( MessageDebugLevel < DebugLevel  )
	{
		va_list args;
		va_start(args,format);
		CHAR log_message[1024]={0,};
		_vsnprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
		va_end(args);

		_Log(log_message);
	}
}

void LogOperation::Log( const CHAR *format, ... )
{
	va_list args;
	va_start(args,format);
	CHAR log_message[1024]={0,};
	_vsnprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
	va_end(args);
	_Log(log_message);
}

void LogOperation::Log( DWORD MessageDebugLevel, const WCHAR *format, ... )
{
	if( MessageDebugLevel < DebugLevel  )
	{
		va_list args;
		va_start(args,format);
		WCHAR log_message[1024]={0,};
		_vsnwprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
		va_end(args);

		_Log(log_message);
	}
}

void LogOperation::Log( const WCHAR *format, ... )
{
	va_list args;
	va_start(args,format);
	WCHAR log_message[1024]={0,};
	_vsnwprintf(log_message,sizeof(log_message)/sizeof(char),format,args);
	va_end(args);
	_Log(log_message);
}

void LogOperation::DumpHex( TCHAR *Prefix, unsigned char *Buffer, int BufferLen )
{
	TCHAR LineBuffer[256];
	memset(LineBuffer,' ',50);
	LineBuffer[50]=0;
	int cursor=0;
	TCHAR ascii[17];
	int start_i=0;
	int i;
	ascii[16]=0;

	for(i=0;i<BufferLen;i++)
	{
		_tprintf( LineBuffer+(i%16)*3,"%0.2X ",Buffer[i]);
		if(isprint(Buffer[i]))
			ascii[i%16]=Buffer[i];
		else
			ascii[i%16]='.';

		if(i%16==15)
		{
			_tprintf(LineBuffer+48,TEXT("  %s"),ascii);
			Log( TEXT("%s%.8x: %s\r\n"),Prefix,start_i,LineBuffer);
			start_i=i+1;
		}
	}

	if(i%16!=0)
	{
		memset(LineBuffer+(i%16)*3,' ',(16-(i%16))*3);
		ascii[i%16]=0;
		_tprintf( LineBuffer+48, TEXT("  %s"),ascii);
		Log(TEXT("%s%.8x: %s\r\n"),Prefix,start_i,LineBuffer);
	}
}

void LogOperation::DumpHex( DWORD MessageDebugLevel, TCHAR *Prefix, unsigned char *Buffer, int BufferLen )
{
	if(MessageDebugLevel < DebugLevel)
	{
		DumpHex( Prefix, Buffer, BufferLen );
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include "memory_tracker.h"

/**
 * THIS FILE SHOULD NEVER ACTUALLY BE RUN. IT IS JUST USED TO GET SOME OF OUR
 * TESTS TO COMPILE.
 */

extern "C" {
    static bool mock_add_new_hook(void (*)(const void* ptr, size_t size)) {
        return false;
    }

    static bool mock_remove_new_hook(void (*)(const void* ptr, size_t size)) {
        return false;
    }

    static bool mock_add_delete_hook(void (*)(const void* ptr)) {
        return false;
    }

    static bool mock_remove_delete_hook(void (*)(const void* ptr)) {
        return false;
    }

    static int mock_get_extra_stats_size() {
        return 0;
    }

    static void mock_get_allocator_stats(allocator_stats*) {
        // Empty
    }

    static size_t mock_get_allocation_size(void*) {
        return 0;
    }
}

ALLOCATOR_HOOKS_API* getHooksApi(void) {
    static ALLOCATOR_HOOKS_API hooksApi;
    hooksApi.add_new_hook = mock_add_new_hook;
    hooksApi.remove_new_hook = mock_remove_new_hook;
    hooksApi.add_delete_hook = mock_add_delete_hook;
    hooksApi.remove_delete_hook = mock_remove_delete_hook;
    hooksApi.get_extra_stats_size = mock_get_extra_stats_size;
    hooksApi.get_allocator_stats = mock_get_allocator_stats;
    hooksApi.get_allocation_size = mock_get_allocation_size;
    return &hooksApi;
}

bool MemoryTracker::tracking = false;
MemoryTracker *MemoryTracker::instance = 0;

MemoryTracker *MemoryTracker::getInstance() {
    if (!instance) {
        instance = new MemoryTracker();
    }
    return instance;
}

MemoryTracker::MemoryTracker() {
    // Do nothing
}

MemoryTracker::~MemoryTracker() {
    // Do nothing
}

void MemoryTracker::getAllocatorStats(std::map<std::string, size_t> &allocator_stats) {
    (void) allocator_stats;
    // Do nothing
}

bool MemoryTracker::trackingMemoryAllocations() {
    // This should ALWAYS return false
    return tracking;
}

size_t MemoryTracker::getFragmentation() {
    return 0;
}

size_t MemoryTracker::getTotalBytesAllocated() {
    return 0;
}

size_t MemoryTracker::getTotalHeapBytes() {
    return 0;
}

<commit_msg>Get allocation size should be const<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include "memory_tracker.h"

/**
 * THIS FILE SHOULD NEVER ACTUALLY BE RUN. IT IS JUST USED TO GET SOME OF OUR
 * TESTS TO COMPILE.
 */

extern "C" {
    static bool mock_add_new_hook(void (*)(const void* ptr, size_t size)) {
        return false;
    }

    static bool mock_remove_new_hook(void (*)(const void* ptr, size_t size)) {
        return false;
    }

    static bool mock_add_delete_hook(void (*)(const void* ptr)) {
        return false;
    }

    static bool mock_remove_delete_hook(void (*)(const void* ptr)) {
        return false;
    }

    static int mock_get_extra_stats_size() {
        return 0;
    }

    static void mock_get_allocator_stats(allocator_stats*) {
        // Empty
    }

    static size_t mock_get_allocation_size(const void*) {
        return 0;
    }
}

ALLOCATOR_HOOKS_API* getHooksApi(void) {
    static ALLOCATOR_HOOKS_API hooksApi;
    hooksApi.add_new_hook = mock_add_new_hook;
    hooksApi.remove_new_hook = mock_remove_new_hook;
    hooksApi.add_delete_hook = mock_add_delete_hook;
    hooksApi.remove_delete_hook = mock_remove_delete_hook;
    hooksApi.get_extra_stats_size = mock_get_extra_stats_size;
    hooksApi.get_allocator_stats = mock_get_allocator_stats;
    hooksApi.get_allocation_size = mock_get_allocation_size;
    return &hooksApi;
}

bool MemoryTracker::tracking = false;
MemoryTracker *MemoryTracker::instance = 0;

MemoryTracker *MemoryTracker::getInstance() {
    if (!instance) {
        instance = new MemoryTracker();
    }
    return instance;
}

MemoryTracker::MemoryTracker() {
    // Do nothing
}

MemoryTracker::~MemoryTracker() {
    // Do nothing
}

void MemoryTracker::getAllocatorStats(std::map<std::string, size_t> &allocator_stats) {
    (void) allocator_stats;
    // Do nothing
}

bool MemoryTracker::trackingMemoryAllocations() {
    // This should ALWAYS return false
    return tracking;
}

size_t MemoryTracker::getFragmentation() {
    return 0;
}

size_t MemoryTracker::getTotalBytesAllocated() {
    return 0;
}

size_t MemoryTracker::getTotalHeapBytes() {
    return 0;
}

<|endoftext|>


<commit_before>// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "log-utils.h"
#include "string-stream.h"

namespace v8 {
namespace internal {

const char* Log::kLogToTemporaryFile = "&";

Log::Log(Logger* logger)
  : is_stopped_(false),
    output_handle_(NULL),
    ll_output_handle_(NULL),
    mutex_(NULL),
    message_buffer_(NULL),
    logger_(logger) {
}

static void AddIsolateIdIfNeeded(StringStream* stream) {
  Isolate* isolate = Isolate::Current();
  if (isolate->IsDefaultIsolate()) return;
  stream->Add("isolate-%p-", isolate);
}

void Log::Initialize() {
  mutex_ = OS::CreateMutex();
  message_buffer_ = NewArray<char>(kMessageBufferSize);

  // --log-all enables all the log flags.
  if (FLAG_log_all) {
    FLAG_log_runtime = true;
    FLAG_log_api = true;
    FLAG_log_code = true;
    FLAG_log_gc = true;
    FLAG_log_suspect = true;
    FLAG_log_handles = true;
    FLAG_log_regexp = true;
  }

  // --prof implies --log-code.
  if (FLAG_prof) FLAG_log_code = true;

  // --prof_lazy controls --log-code, implies --noprof_auto.
  if (FLAG_prof_lazy) {
    FLAG_log_code = false;
    FLAG_prof_auto = false;
  }

  bool open_log_file = FLAG_log || FLAG_log_runtime || FLAG_log_api
      || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
      || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;

  // If we're logging anything, we need to open the log file.
  if (open_log_file) {
    if (strcmp(FLAG_logfile, "-") == 0) {
      OpenStdout();
    } else if (strcmp(FLAG_logfile, "*") == 0) {
      // Does nothing for now. Will be removed.
    } else if (strcmp(FLAG_logfile, kLogToTemporaryFile) == 0) {
      OpenTemporaryFile();
    } else {
      if (strchr(FLAG_logfile, '%') != NULL ||
          !Isolate::Current()->IsDefaultIsolate()) {
        // If there's a '%' in the log file name we have to expand
        // placeholders.
        HeapStringAllocator allocator;
        StringStream stream(&allocator);
        AddIsolateIdIfNeeded(&stream);
        for (const char* p = FLAG_logfile; *p; p++) {
          if (*p == '%') {
            p++;
            switch (*p) {
              case '\0':
                // If there's a % at the end of the string we back up
                // one character so we can escape the loop properly.
                p--;
                break;
              case 't': {
                // %t expands to the current time in milliseconds.
                double time = OS::TimeCurrentMillis();
                stream.Add("%.0f", FmtElm(time));
                break;
              }
              case '%':
                // %% expands (contracts really) to %.
                stream.Put('%');
                break;
              default:
                // All other %'s expand to themselves.
                stream.Put('%');
                stream.Put(*p);
                break;
            }
          } else {
            stream.Put(*p);
          }
        }
        SmartPointer<const char> expanded = stream.ToCString();
        OpenFile(*expanded);
      } else {
        OpenFile(FLAG_logfile);
      }
    }
  }
}

void Log::OpenStdout() {
  ASSERT(!IsEnabled());
  output_handle_ = stdout;
}

void Log::OpenTemporaryFile() {
  ASSERT(!IsEnabled());
  output_handle_ = i::OS::OpenTemporaryFile();
}

// Extension added to V8 log file name to get the low-level log name.
static const char kLowLevelLogExt[] = ".ll";

// File buffer size of the low-level log. We don't use the default to
// minimize the associated overhead.
static const int kLowLevelLogBufferSize = 2 * MB;

void Log::OpenFile(const char* name) {
  ASSERT(!IsEnabled());
  output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
  if (FLAG_ll_prof) {
    // Open the low-level log file.
    size_t len = strlen(name);
    ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
    memcpy(ll_name.start(), name, len);
    memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
    ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
    setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
  }
}

FILE* Log::Close() {
  FILE* result = NULL;
  if (output_handle_ != NULL) {
    if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
      fclose(output_handle_);
    } else {
      result = output_handle_;
    }
  }
  output_handle_ = NULL;
  if (ll_output_handle_ != NULL) fclose(ll_output_handle_);
  ll_output_handle_ = NULL;

  DeleteArray(message_buffer_);
  message_buffer_ = NULL;

  delete mutex_;
  mutex_ = NULL;

  is_stopped_ = false;
  return result;
}

LogMessageBuilder::LogMessageBuilder(Logger* logger)
  : log_(logger->log_),
    sl(log_->mutex_),
    pos_(0) {
  ASSERT(log_->message_buffer_ != NULL);
}

void LogMessageBuilder::Append(const char* format, ...) {
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  va_list args;
  va_start(args, format);
  AppendVA(format, args);
  va_end(args);
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::AppendVA(const char* format, va_list args) {
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  int result = v8::internal::OS::VSNPrintF(buf, format, args);

  // Result is -1 if output was truncated.
  if (result >= 0) {
    pos_ += result;
  } else {
    pos_ = Log::kMessageBufferSize;
  }
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::Append(const char c) {
  if (pos_ < Log::kMessageBufferSize) {
    log_->message_buffer_[pos_++] = c;
  }
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::Append(String* str) {
  AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
  int length = str->length();
  for (int i = 0; i < length; i++) {
    Append(static_cast<char>(str->Get(i)));
  }
}

void LogMessageBuilder::AppendAddress(Address addr) {
  Append("0x%" V8PRIxPTR, addr);
}

void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
  if (str == NULL) return;
  AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
  int len = str->length();
  if (len > 0x1000)
    len = 0x1000;
  if (show_impl_info) {
    Append(str->IsAsciiRepresentation() ? 'a' : '2');
    if (StringShape(str).IsExternal())
      Append('e');
    if (StringShape(str).IsSymbol())
      Append('#');
    Append(":%i:", str->length());
  }
  for (int i = 0; i < len; i++) {
    uc32 c = str->Get(i);
    if (c > 0xff) {
      Append("\\u%04x", c);
    } else if (c < 32 || c > 126) {
      Append("\\x%02x", c);
    } else if (c == ',') {
      Append("\\,");
    } else if (c == '\\') {
      Append("\\\\");
    } else if (c == '\"') {
      Append("\"\"");
    } else {
      Append("%lc", c);
    }
  }
}

void LogMessageBuilder::AppendStringPart(const char* str, int len) {
  if (pos_ + len > Log::kMessageBufferSize) {
    len = Log::kMessageBufferSize - pos_;
    ASSERT(len >= 0);
    if (len == 0) return;
  }
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  OS::StrNCpy(buf, str, len);
  pos_ += len;
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::WriteToLogFile() {
  ASSERT(pos_ <= Log::kMessageBufferSize);
  const int written = log_->WriteToFile(log_->message_buffer_, pos_);
  if (written != pos_) {
    log_->stop();
    log_->logger_->LogFailure();
  }
}

} }  // namespace v8::internal
<commit_msg>Finally, remove logging to memory support.<commit_after>// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "log-utils.h"
#include "string-stream.h"

namespace v8 {
namespace internal {

const char* Log::kLogToTemporaryFile = "&";

Log::Log(Logger* logger)
  : is_stopped_(false),
    output_handle_(NULL),
    ll_output_handle_(NULL),
    mutex_(NULL),
    message_buffer_(NULL),
    logger_(logger) {
}

static void AddIsolateIdIfNeeded(StringStream* stream) {
  Isolate* isolate = Isolate::Current();
  if (isolate->IsDefaultIsolate()) return;
  stream->Add("isolate-%p-", isolate);
}

void Log::Initialize() {
  mutex_ = OS::CreateMutex();
  message_buffer_ = NewArray<char>(kMessageBufferSize);

  // --log-all enables all the log flags.
  if (FLAG_log_all) {
    FLAG_log_runtime = true;
    FLAG_log_api = true;
    FLAG_log_code = true;
    FLAG_log_gc = true;
    FLAG_log_suspect = true;
    FLAG_log_handles = true;
    FLAG_log_regexp = true;
  }

  // --prof implies --log-code.
  if (FLAG_prof) FLAG_log_code = true;

  // --prof_lazy controls --log-code, implies --noprof_auto.
  if (FLAG_prof_lazy) {
    FLAG_log_code = false;
    FLAG_prof_auto = false;
  }

  bool open_log_file = FLAG_log || FLAG_log_runtime || FLAG_log_api
      || FLAG_log_code || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect
      || FLAG_log_regexp || FLAG_log_state_changes || FLAG_ll_prof;

  // If we're logging anything, we need to open the log file.
  if (open_log_file) {
    if (strcmp(FLAG_logfile, "-") == 0) {
      OpenStdout();
    } else if (strcmp(FLAG_logfile, kLogToTemporaryFile) == 0) {
      OpenTemporaryFile();
    } else {
      if (strchr(FLAG_logfile, '%') != NULL ||
          !Isolate::Current()->IsDefaultIsolate()) {
        // If there's a '%' in the log file name we have to expand
        // placeholders.
        HeapStringAllocator allocator;
        StringStream stream(&allocator);
        AddIsolateIdIfNeeded(&stream);
        for (const char* p = FLAG_logfile; *p; p++) {
          if (*p == '%') {
            p++;
            switch (*p) {
              case '\0':
                // If there's a % at the end of the string we back up
                // one character so we can escape the loop properly.
                p--;
                break;
              case 't': {
                // %t expands to the current time in milliseconds.
                double time = OS::TimeCurrentMillis();
                stream.Add("%.0f", FmtElm(time));
                break;
              }
              case '%':
                // %% expands (contracts really) to %.
                stream.Put('%');
                break;
              default:
                // All other %'s expand to themselves.
                stream.Put('%');
                stream.Put(*p);
                break;
            }
          } else {
            stream.Put(*p);
          }
        }
        SmartPointer<const char> expanded = stream.ToCString();
        OpenFile(*expanded);
      } else {
        OpenFile(FLAG_logfile);
      }
    }
  }
}

void Log::OpenStdout() {
  ASSERT(!IsEnabled());
  output_handle_ = stdout;
}

void Log::OpenTemporaryFile() {
  ASSERT(!IsEnabled());
  output_handle_ = i::OS::OpenTemporaryFile();
}

// Extension added to V8 log file name to get the low-level log name.
static const char kLowLevelLogExt[] = ".ll";

// File buffer size of the low-level log. We don't use the default to
// minimize the associated overhead.
static const int kLowLevelLogBufferSize = 2 * MB;

void Log::OpenFile(const char* name) {
  ASSERT(!IsEnabled());
  output_handle_ = OS::FOpen(name, OS::LogFileOpenMode);
  if (FLAG_ll_prof) {
    // Open the low-level log file.
    size_t len = strlen(name);
    ScopedVector<char> ll_name(static_cast<int>(len + sizeof(kLowLevelLogExt)));
    memcpy(ll_name.start(), name, len);
    memcpy(ll_name.start() + len, kLowLevelLogExt, sizeof(kLowLevelLogExt));
    ll_output_handle_ = OS::FOpen(ll_name.start(), OS::LogFileOpenMode);
    setvbuf(ll_output_handle_, NULL, _IOFBF, kLowLevelLogBufferSize);
  }
}

FILE* Log::Close() {
  FILE* result = NULL;
  if (output_handle_ != NULL) {
    if (strcmp(FLAG_logfile, kLogToTemporaryFile) != 0) {
      fclose(output_handle_);
    } else {
      result = output_handle_;
    }
  }
  output_handle_ = NULL;
  if (ll_output_handle_ != NULL) fclose(ll_output_handle_);
  ll_output_handle_ = NULL;

  DeleteArray(message_buffer_);
  message_buffer_ = NULL;

  delete mutex_;
  mutex_ = NULL;

  is_stopped_ = false;
  return result;
}

LogMessageBuilder::LogMessageBuilder(Logger* logger)
  : log_(logger->log_),
    sl(log_->mutex_),
    pos_(0) {
  ASSERT(log_->message_buffer_ != NULL);
}

void LogMessageBuilder::Append(const char* format, ...) {
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  va_list args;
  va_start(args, format);
  AppendVA(format, args);
  va_end(args);
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::AppendVA(const char* format, va_list args) {
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  int result = v8::internal::OS::VSNPrintF(buf, format, args);

  // Result is -1 if output was truncated.
  if (result >= 0) {
    pos_ += result;
  } else {
    pos_ = Log::kMessageBufferSize;
  }
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::Append(const char c) {
  if (pos_ < Log::kMessageBufferSize) {
    log_->message_buffer_[pos_++] = c;
  }
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::Append(String* str) {
  AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
  int length = str->length();
  for (int i = 0; i < length; i++) {
    Append(static_cast<char>(str->Get(i)));
  }
}

void LogMessageBuilder::AppendAddress(Address addr) {
  Append("0x%" V8PRIxPTR, addr);
}

void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
  if (str == NULL) return;
  AssertNoAllocation no_heap_allocation;  // Ensure string stay valid.
  int len = str->length();
  if (len > 0x1000)
    len = 0x1000;
  if (show_impl_info) {
    Append(str->IsAsciiRepresentation() ? 'a' : '2');
    if (StringShape(str).IsExternal())
      Append('e');
    if (StringShape(str).IsSymbol())
      Append('#');
    Append(":%i:", str->length());
  }
  for (int i = 0; i < len; i++) {
    uc32 c = str->Get(i);
    if (c > 0xff) {
      Append("\\u%04x", c);
    } else if (c < 32 || c > 126) {
      Append("\\x%02x", c);
    } else if (c == ',') {
      Append("\\,");
    } else if (c == '\\') {
      Append("\\\\");
    } else if (c == '\"') {
      Append("\"\"");
    } else {
      Append("%lc", c);
    }
  }
}

void LogMessageBuilder::AppendStringPart(const char* str, int len) {
  if (pos_ + len > Log::kMessageBufferSize) {
    len = Log::kMessageBufferSize - pos_;
    ASSERT(len >= 0);
    if (len == 0) return;
  }
  Vector<char> buf(log_->message_buffer_ + pos_,
                   Log::kMessageBufferSize - pos_);
  OS::StrNCpy(buf, str, len);
  pos_ += len;
  ASSERT(pos_ <= Log::kMessageBufferSize);
}

void LogMessageBuilder::WriteToLogFile() {
  ASSERT(pos_ <= Log::kMessageBufferSize);
  const int written = log_->WriteToFile(log_->message_buffer_, pos_);
  if (written != pos_) {
    log_->stop();
    log_->logger_->LogFailure();
  }
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>#include <reflection/reflection.h>
#include <smartref/smartref.h>

// #include <vector>
#include <cassert>

namespace tests_containers {

template<typename T>
struct Ref : smartref::using_<T>
{
  T ref;

  static auto &counter()
  {
    static auto count = 0;
    return count;
  }

  operator T &()
  {
    ++counter();
    return ref;
  }

  Ref(T arg) : ref{arg} {}

  using smartref::using_<T>::operator=;

  Ref() = default;

  Ref(const Ref &) = default;
  Ref &operator=(const Ref &) = default;
  Ref(Ref &&) = default;
  Ref &operator=(Ref &&) = default;
};

template<typename T, typename Delegate>
auto test = []{
  //! Uninitialized construction
  T a;

  //! Default construction
  T b{};
  T c = {};

  //! Copy construction
  T d{a};
  T e = a;
  T f = {a};
  auto g{a};
  auto h = a;
  auto i = {a};

  //! Move construction
  T j{std::move(a)};
  T k = std::move(a);
  T l = {std::move(a)};
  auto m{T{}};
  auto n = T{};
  auto o = {T{}};

  //! Delegate type copy construction
  auto delegate = Delegate{};
  T p{delegate};
  T q = delegate;
  T r = {delegate};
  auto s{T{delegate}};
  auto t = T{delegate};
  auto u = {T{delegate}};

  //! Delegate type move construction
  T v{std::move(delegate)};
  T w = std::move(delegate);
  T x = {std::move(delegate)};
  auto y{T{std::move(delegate)}};
  auto z = T{std::move(delegate)};
  auto A = {T{std::move(delegate)}};

  // TODO: Check whether semantics are right (e.g. (a = b)++ changes a, instead of a copy).
  //! Copy assignment
  a = b;
  a = b = c;
  a = (b = c);
  (a = b) = c;
  (a = b) = delegate; // TODO: also add similar checks for other tests.

  //! Move assignment
  a = std::move(b);
  a = b = std::move(c);
  a = (b = std::move(c));
  (a = b) = std::move(c);

  //! Delegate type copy assignment
  a = delegate;
  a = b = delegate;
  a = (b = delegate);
  (a = b) = delegate;

  //! Delegate type move assignment
  a = std::move(delegate);
  a = b = std::move(delegate);
  a = (b = std::move(delegate));
  (a = b) = std::move(delegate);

  return 0;
};

auto test_int = test<int, int>();

auto test_ref = []{
  Ref<int>::counter() = 0;
  test<Ref<int>, int>();
  printf("counter: %d\n", Ref<int>::counter());
  assert(Ref<int>::counter() == 34);

  Ref<float>::counter() = 0;
  test<Ref<float>, float>();
  assert(Ref<float>::counter() == 34);

  Ref<bool>::counter() = 0;
  test<Ref<bool>, bool>();
  assert(Ref<bool>::counter() == 34);

  return 0;
}();

// using T = int;
// using T = std::vector<int>;

// using reflection::reflect;

// //! Member-types
// constexpr auto is_valid = [](auto expression)
// {
//   // auto expected = reflect<decltype(expression(std::declval<    T >(), std::declval<    T >()))>;
//   auto actual   = reflect<decltype(expression(std::declval<Ref<T>>(), std::declval<    T >()))>;

//   return true;
//   // return actual == expected;
// };

// #define IS_VALID(expression) is_valid([](auto &&_, auto &&__) {return expression;})

// TODO:
// - constructing a smartref (e.g. Ref<int> x;)

// static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
// static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
// static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
// static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
// static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
// static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
// static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
// static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
// static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
// static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
// static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
// static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

// //! Member functions
// // TODO: Test all overloads
// // TODO: (constructor)
// // TODO: Why does operator= work? What does it do?
// // static_assert(IS_VALID(_.operator=(_)));
// // static_assert(IS_VALID(_.operator=(__)));
// static_assert(IS_VALID(_ = __));
// static_assert(IS_VALID(_.assign(0, 0)));
// static_assert(IS_VALID(_.assign(begin(_), end(_))));
// static_assert(IS_VALID(_.get_allocator()));
// //! Element access
// static_assert(IS_VALID(_.at(T::size_type{})));
// static_assert(IS_VALID(_.operator[](0)));
// static_assert(IS_VALID(_[0]));
// static_assert(IS_VALID(_.front()));
// static_assert(IS_VALID(_.back()));
// static_assert(IS_VALID(_.data()));

// //! Iterators
// static_assert(IS_VALID(_.begin()));
// static_assert(IS_VALID(_.cbegin()));
// static_assert(IS_VALID(_.end()));
// static_assert(IS_VALID(_.cend()));
// static_assert(IS_VALID(_.rbegin()));
// static_assert(IS_VALID(_.crbegin()));
// static_assert(IS_VALID(_.rend()));
// static_assert(IS_VALID(_.crend()));

// //! Capacity
// static_assert(IS_VALID(_.empty()));
// static_assert(IS_VALID(_.size()));
// static_assert(IS_VALID(_.max_size()));
// static_assert(IS_VALID(_.reserve(T::size_type{})));
// static_assert(IS_VALID(_.capacity()));
// static_assert(IS_VALID(_.shrink_to_fit()));

// //! Modifiers
// static_assert(IS_VALID(_.clear()));
// static_assert(IS_VALID(_.insert(begin(_), 0)));
// static_assert(IS_VALID(_.emplace(begin(_), 0)));
// static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
// static_assert(IS_VALID(_.erase(begin(_))));
// static_assert(IS_VALID(_.push_back(0)));
// static_assert(IS_VALID(_.emplace_back(0)));
// static_assert(IS_VALID(_.template emplace_back<int>(0)));
// static_assert(IS_VALID(_.pop_back()));
// static_assert(IS_VALID(_.resize(T::size_type{})));
// static_assert(IS_VALID(_.swap(_)));

// //! Non-member functions
// // static_assert(IS_VALID(_ == _);
// // TODO: operator!=
// // TODO: operator<
// // TODO: operator<=
// // TODO: operator>
// // TODO: operator>=
// // TODO: std::swap

// // TODO: Deduction guides

} // namespace tests_containers
<commit_msg>Added assignment operator unit test for std::string.<commit_after>#include <reflection/reflection.h>
#include <smartref/smartref.h>

// #include <vector>
#include <cassert>
#include <string>

namespace tests_containers {

template<typename T>
struct Ref : smartref::using_<T>
{
  T ref;

  static auto &counter()
  {
    static auto count = 0;
    return count;
  }

  operator T &()
  {
    ++counter();
    return ref;
  }

  Ref(T arg) : ref{arg} {}

  using smartref::using_<T>::operator=;

  Ref() = default;

  Ref(const Ref &) = default;
  Ref &operator=(const Ref &) = default;
  Ref(Ref &&) = default;
  Ref &operator=(Ref &&) = default;
};

template<typename T, typename Delegate>
auto test = []{
  //! Uninitialized construction
  T a;

  //! Default construction
  T b{};
  T c = {};

  //! Copy construction
  T d{a};
  T e = a;
  T f = {a};
  auto g{a};
  auto h = a;
  auto i = {a};

  //! Move construction
  T j{std::move(a)};
  T k = std::move(a);
  T l = {std::move(a)};
  auto m{T{}};
  auto n = T{};
  auto o = {T{}};

  //! Delegate type copy construction
  auto delegate = Delegate{};
  T p{delegate};
  T q = delegate;
  T r = {delegate};
  auto s{T{delegate}};
  auto t = T{delegate};
  auto u = {T{delegate}};

  //! Delegate type move construction
  T v{std::move(delegate)};
  T w = std::move(delegate);
  T x = {std::move(delegate)};
  auto y{T{std::move(delegate)}};
  auto z = T{std::move(delegate)};
  auto A = {T{std::move(delegate)}};

  // TODO: Check whether semantics are right (e.g. (a = b)++ changes a, instead of a copy).
  //! Copy assignment
  a = b;
  a = b = c;
  a = (b = c);
  (a = b) = c;
  (a = b) = delegate; // TODO: also add similar checks for other tests.

  //! Move assignment
  a = std::move(b);
  a = b = std::move(c);
  a = (b = std::move(c));
  (a = b) = std::move(c);

  //! Delegate type copy assignment
  a = delegate;
  a = b = delegate;
  a = (b = delegate);
  (a = b) = delegate;

  //! Delegate type move assignment
  a = std::move(delegate);
  a = b = std::move(delegate);
  a = (b = std::move(delegate));
  (a = b) = std::move(delegate);

  return 0;
};

auto test_int = test<int, int>();

auto test_ref = []{
  Ref<int>::counter() = 0;
  test<Ref<int>, int>();
  printf("counter: %d\n", Ref<int>::counter());
  assert(Ref<int>::counter() == 34);

  Ref<float>::counter() = 0;
  test<Ref<float>, float>();
  assert(Ref<float>::counter() == 34);

  Ref<bool>::counter() = 0;
  test<Ref<bool>, bool>();
  assert(Ref<bool>::counter() == 34);

  Ref<std::string>::counter() = 0;
  test<Ref<std::string>, std::string>();
  assert(Ref<std::string>::counter() == 34);

  return 0;
}();

// using T = int;
// using T = std::vector<int>;

// using reflection::reflect;

// //! Member-types
// constexpr auto is_valid = [](auto expression)
// {
//   // auto expected = reflect<decltype(expression(std::declval<    T >(), std::declval<    T >()))>;
//   auto actual   = reflect<decltype(expression(std::declval<Ref<T>>(), std::declval<    T >()))>;

//   return true;
//   // return actual == expected;
// };

// #define IS_VALID(expression) is_valid([](auto &&_, auto &&__) {return expression;})

// TODO:
// - constructing a smartref (e.g. Ref<int> x;)

// static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
// static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
// static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
// static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
// static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
// static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
// static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
// static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
// static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
// static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
// static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
// static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

// //! Member functions
// // TODO: Test all overloads
// // TODO: (constructor)
// // TODO: Why does operator= work? What does it do?
// // static_assert(IS_VALID(_.operator=(_)));
// // static_assert(IS_VALID(_.operator=(__)));
// static_assert(IS_VALID(_ = __));
// static_assert(IS_VALID(_.assign(0, 0)));
// static_assert(IS_VALID(_.assign(begin(_), end(_))));
// static_assert(IS_VALID(_.get_allocator()));
// //! Element access
// static_assert(IS_VALID(_.at(T::size_type{})));
// static_assert(IS_VALID(_.operator[](0)));
// static_assert(IS_VALID(_[0]));
// static_assert(IS_VALID(_.front()));
// static_assert(IS_VALID(_.back()));
// static_assert(IS_VALID(_.data()));

// //! Iterators
// static_assert(IS_VALID(_.begin()));
// static_assert(IS_VALID(_.cbegin()));
// static_assert(IS_VALID(_.end()));
// static_assert(IS_VALID(_.cend()));
// static_assert(IS_VALID(_.rbegin()));
// static_assert(IS_VALID(_.crbegin()));
// static_assert(IS_VALID(_.rend()));
// static_assert(IS_VALID(_.crend()));

// //! Capacity
// static_assert(IS_VALID(_.empty()));
// static_assert(IS_VALID(_.size()));
// static_assert(IS_VALID(_.max_size()));
// static_assert(IS_VALID(_.reserve(T::size_type{})));
// static_assert(IS_VALID(_.capacity()));
// static_assert(IS_VALID(_.shrink_to_fit()));

// //! Modifiers
// static_assert(IS_VALID(_.clear()));
// static_assert(IS_VALID(_.insert(begin(_), 0)));
// static_assert(IS_VALID(_.emplace(begin(_), 0)));
// static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
// static_assert(IS_VALID(_.erase(begin(_))));
// static_assert(IS_VALID(_.push_back(0)));
// static_assert(IS_VALID(_.emplace_back(0)));
// static_assert(IS_VALID(_.template emplace_back<int>(0)));
// static_assert(IS_VALID(_.pop_back()));
// static_assert(IS_VALID(_.resize(T::size_type{})));
// static_assert(IS_VALID(_.swap(_)));

// //! Non-member functions
// // static_assert(IS_VALID(_ == _);
// // TODO: operator!=
// // TODO: operator<
// // TODO: operator<=
// // TODO: operator>
// // TODO: operator>=
// // TODO: std::swap

// // TODO: Deduction guides

} // namespace tests_containers
<|endoftext|>


<commit_before>#include <reflection/reflection.h>
#include <smartref/smartref.h>

#include <vector>

namespace tests_containers {

template<typename T>
struct Ref : smartref::using_<T>
{
  T ref;

  operator T &()
  {
    return ref;
  }
};

using T = std::vector<int>;

using reflection::reflect;

//! Member-types
constexpr auto is_valid = [](auto expression)
{
  auto expected = reflect<decltype(expression(std::declval<    T >()))>;
  auto actual   = reflect<decltype(expression(std::declval<Ref<T>>()))>;

  return actual == expected;
};

#define IS_VALID(expression) is_valid([](auto &&_) {expression;})

static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

//! Member functions
// TODO: Test all overloads
// TODO: (constructor)
// TODO: operator=
// static_assert(IS_VALID(_.operator=(_)));
// static_assert(IS_VALID(_ = _));
static_assert(IS_VALID(_.assign(0, 0)));
static_assert(IS_VALID(_.assign(begin(_), end(_))));
static_assert(IS_VALID(_.get_allocator()));

//! Element access
static_assert(IS_VALID(_.at(T::size_type{})));
static_assert(IS_VALID(_.operator[](0)));
static_assert(IS_VALID(_[0]));
static_assert(IS_VALID(_.front()));
static_assert(IS_VALID(_.back()));
static_assert(IS_VALID(_.data()));

//! Iterators
static_assert(IS_VALID(_.begin()));
static_assert(IS_VALID(_.cbegin()));
static_assert(IS_VALID(_.end()));
static_assert(IS_VALID(_.cend()));
static_assert(IS_VALID(_.rbegin()));
static_assert(IS_VALID(_.crbegin()));
static_assert(IS_VALID(_.rend()));
static_assert(IS_VALID(_.crend()));

//! Capacity
static_assert(IS_VALID(_.empty()));
static_assert(IS_VALID(_.size()));
static_assert(IS_VALID(_.max_size()));
static_assert(IS_VALID(_.reserve(T::size_type{})));
static_assert(IS_VALID(_.capacity()));
static_assert(IS_VALID(_.shrink_to_fit()));

//! Modifiers
static_assert(IS_VALID(_.clear()));
static_assert(IS_VALID(_.insert(begin(_), 0)));
static_assert(IS_VALID(_.emplace(begin(_), 0)));
static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
static_assert(IS_VALID(_.erase(begin(_))));
static_assert(IS_VALID(_.push_back(0)));
static_assert(IS_VALID(_.emplace_back(0)));
static_assert(IS_VALID(_.template emplace_back<int>(0)));
static_assert(IS_VALID(_.pop_back()));
static_assert(IS_VALID(_.resize(T::size_type{})));
static_assert(IS_VALID(_.swap(_)));

//! Non-member functions
// TODO: operator==
// TODO: operator!=
// TODO: operator<
// TODO: operator<=
// TODO: operator>
// TODO: operator>=
// TODO: std::swap

// TODO: Deduction guides

} // namespace tests_containers
<commit_msg>Apparently, operator= works out of the box.<commit_after>#include <reflection/reflection.h>
#include <smartref/smartref.h>

#include <vector>

namespace tests_containers {

template<typename T>
struct Ref : smartref::using_<T>
{
  T ref;

  operator T &()
  {
    return ref;
  }
};

using T = std::vector<int>;

using reflection::reflect;

//! Member-types
constexpr auto is_valid = [](auto expression)
{
  auto expected = reflect<decltype(expression(std::declval<    T >()))>;
  auto actual   = reflect<decltype(expression(std::declval<Ref<T>>()))>;

  return actual == expected;
};

#define IS_VALID(expression) is_valid([](auto &&_) {expression;})

static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

//! Member functions
// TODO: Test all overloads
// TODO: (constructor)
// TODO: Why does operator= work? What does it do?
static_assert(IS_VALID(_.operator=(_)));
static_assert(IS_VALID(_ = _));
static_assert(IS_VALID(_.assign(0, 0)));
static_assert(IS_VALID(_.assign(begin(_), end(_))));
static_assert(IS_VALID(_.get_allocator()));

//! Element access
static_assert(IS_VALID(_.at(T::size_type{})));
static_assert(IS_VALID(_.operator[](0)));
static_assert(IS_VALID(_[0]));
static_assert(IS_VALID(_.front()));
static_assert(IS_VALID(_.back()));
static_assert(IS_VALID(_.data()));

//! Iterators
static_assert(IS_VALID(_.begin()));
static_assert(IS_VALID(_.cbegin()));
static_assert(IS_VALID(_.end()));
static_assert(IS_VALID(_.cend()));
static_assert(IS_VALID(_.rbegin()));
static_assert(IS_VALID(_.crbegin()));
static_assert(IS_VALID(_.rend()));
static_assert(IS_VALID(_.crend()));

//! Capacity
static_assert(IS_VALID(_.empty()));
static_assert(IS_VALID(_.size()));
static_assert(IS_VALID(_.max_size()));
static_assert(IS_VALID(_.reserve(T::size_type{})));
static_assert(IS_VALID(_.capacity()));
static_assert(IS_VALID(_.shrink_to_fit()));

//! Modifiers
static_assert(IS_VALID(_.clear()));
static_assert(IS_VALID(_.insert(begin(_), 0)));
static_assert(IS_VALID(_.emplace(begin(_), 0)));
static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
static_assert(IS_VALID(_.erase(begin(_))));
static_assert(IS_VALID(_.push_back(0)));
static_assert(IS_VALID(_.emplace_back(0)));
static_assert(IS_VALID(_.template emplace_back<int>(0)));
static_assert(IS_VALID(_.pop_back()));
static_assert(IS_VALID(_.resize(T::size_type{})));
static_assert(IS_VALID(_.swap(_)));

//! Non-member functions
// TODO: operator==
// TODO: operator!=
// TODO: operator<
// TODO: operator<=
// TODO: operator>
// TODO: operator>=
// TODO: std::swap

// TODO: Deduction guides

} // namespace tests_containers
<|endoftext|>


<commit_before>#include <reflection/reflection.h>
#include <smartref/smartref.h>

// #include <vector>

namespace tests_containers {

// template <typename F>
// class reflect_member_function : public reflection::reflect_base<reflection::reflected_kind::member_function> {
// private:
//     template <typename... ExplicitArgs, typename... Args>
//     decltype(auto) indirect(Args&&... args)
//     {
//         auto f = [](auto& obj, auto&&... args) { if constexpr (sizeof...(ExplicitArgs) == 0) return obj.operator=(std::forward<Args>(args)...); else if constexpr (utils::always_true<Args...>) return obj.template operator=<ExplicitArgs...>( std::forward<Args>(args)...); };
//         return F{}(*this, f, std::forward<Args>(args)...);
//     }
// public:
//     template <typename... ExplicitArgs, typename... Args>
//     auto operator=(Args&&... args) -> decltype(indirect<ExplicitArgs...>(std::forward<Args>(args)...)) { return indirect<ExplicitArgs...>(std::forward<Args>(args)...); }
// };
// template<typename T>
struct Ref : smartref::reflect_member_function<Ref>
// struct Ref : smartref::using_<T>
{
  int ref;

  operator int &()
  {
    return ref;
  }

  // Ref() = default;
  // Ref(const Ref &) = default;
  Ref(int arg) : ref{arg} {}

  // using Base = smartref::reflect_member_function<Ref>;
  // using Base::operator=;

  // int &operator=(int arg)
  // {
  //   return ref = arg;
  // }

  // using smartref::using_<T>::using_;
  // using smartref::using_<T>::operator=;

  Ref() = default;

  // Ref(const Ref &) = default;
  // Ref &operator=(const Ref &) = default;
  // Ref(Ref &&) = default;
  // Ref &operator=(Ref &&) = default;

  Ref(const Ref &) = delete;
  Ref(Ref &&) = delete;
  Ref &operator=(const Ref &) = delete;
  Ref &operator=(Ref &&) = delete;
};

// struct uiop {
//   auto operator=(int) {}
// };
// struct qwerty : uiop {
//   using uiop::operator=;
// };
template<typename T>
auto test = []{
  T a;
  T b{};
  T c = {};
  T d = 0;
  // T e = {0};
  // T f = a;
  // T g = {a};
  // auto h = T{};
  // auto i = a;
  // auto j = {a};
  // auto k{T{}};
  // auto l{a};

  // a = 0;
  // a = b;
  // a = b = 0;
  // a = b = c;
  // a = (b = 0);
  // a = (b = c);
  // (a = b) = 0;
  // (a = b) = c;
};

auto test_int = test<int>;
auto test_ref = test<Ref>;

// using T = int;
// using T = std::vector<int>;

// using reflection::reflect;

// //! Member-types
// constexpr auto is_valid = [](auto expression)
// {
//   // auto expected = reflect<decltype(expression(std::declval<    T >(), std::declval<    T >()))>;
//   auto actual   = reflect<decltype(expression(std::declval<Ref<T>>(), std::declval<    T >()))>;

//   return true;
//   // return actual == expected;
// };

// #define IS_VALID(expression) is_valid([](auto &&_, auto &&__) {return expression;})

// TODO:
// - constructing a smartref (e.g. Ref<int> x;)

// static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
// static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
// static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
// static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
// static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
// static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
// static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
// static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
// static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
// static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
// static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
// static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

// //! Member functions
// // TODO: Test all overloads
// // TODO: (constructor)
// // TODO: Why does operator= work? What does it do?
// // static_assert(IS_VALID(_.operator=(_)));
// // static_assert(IS_VALID(_.operator=(__)));
// static_assert(IS_VALID(_ = __));
// static_assert(IS_VALID(_.assign(0, 0)));
// static_assert(IS_VALID(_.assign(begin(_), end(_))));
// static_assert(IS_VALID(_.get_allocator()));
// //! Element access
// static_assert(IS_VALID(_.at(T::size_type{})));
// static_assert(IS_VALID(_.operator[](0)));
// static_assert(IS_VALID(_[0]));
// static_assert(IS_VALID(_.front()));
// static_assert(IS_VALID(_.back()));
// static_assert(IS_VALID(_.data()));

// //! Iterators
// static_assert(IS_VALID(_.begin()));
// static_assert(IS_VALID(_.cbegin()));
// static_assert(IS_VALID(_.end()));
// static_assert(IS_VALID(_.cend()));
// static_assert(IS_VALID(_.rbegin()));
// static_assert(IS_VALID(_.crbegin()));
// static_assert(IS_VALID(_.rend()));
// static_assert(IS_VALID(_.crend()));

// //! Capacity
// static_assert(IS_VALID(_.empty()));
// static_assert(IS_VALID(_.size()));
// static_assert(IS_VALID(_.max_size()));
// static_assert(IS_VALID(_.reserve(T::size_type{})));
// static_assert(IS_VALID(_.capacity()));
// static_assert(IS_VALID(_.shrink_to_fit()));

// //! Modifiers
// static_assert(IS_VALID(_.clear()));
// static_assert(IS_VALID(_.insert(begin(_), 0)));
// static_assert(IS_VALID(_.emplace(begin(_), 0)));
// static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
// static_assert(IS_VALID(_.erase(begin(_))));
// static_assert(IS_VALID(_.push_back(0)));
// static_assert(IS_VALID(_.emplace_back(0)));
// static_assert(IS_VALID(_.template emplace_back<int>(0)));
// static_assert(IS_VALID(_.pop_back()));
// static_assert(IS_VALID(_.resize(T::size_type{})));
// static_assert(IS_VALID(_.swap(_)));

// //! Non-member functions
// // static_assert(IS_VALID(_ == _);
// // TODO: operator!=
// // TODO: operator<
// // TODO: operator<=
// // TODO: operator>
// // TODO: operator>=
// // TODO: std::swap

// // TODO: Deduction guides

} // namespace tests_containers
<commit_msg>Re-enabled some more tests.<commit_after>#include <reflection/reflection.h>
#include <smartref/smartref.h>

// #include <vector>

namespace tests_containers {

// template <typename F>
// class reflect_member_function : public reflection::reflect_base<reflection::reflected_kind::member_function> {
// private:
//     template <typename... ExplicitArgs, typename... Args>
//     decltype(auto) indirect(Args&&... args)
//     {
//         auto f = [](auto& obj, auto&&... args) { if constexpr (sizeof...(ExplicitArgs) == 0) return obj.operator=(std::forward<Args>(args)...); else if constexpr (utils::always_true<Args...>) return obj.template operator=<ExplicitArgs...>( std::forward<Args>(args)...); };
//         return F{}(*this, f, std::forward<Args>(args)...);
//     }
// public:
//     template <typename... ExplicitArgs, typename... Args>
//     auto operator=(Args&&... args) -> decltype(indirect<ExplicitArgs...>(std::forward<Args>(args)...)) { return indirect<ExplicitArgs...>(std::forward<Args>(args)...); }
// };
// template<typename T>
struct Ref : smartref::reflect_member_function<Ref>
// struct Ref : smartref::using_<T>
{
  int ref;

  operator int &()
  {
    return ref;
  }

  // Ref() = default;
  // Ref(const Ref &) = default;
  Ref(int arg) : ref{arg} {}

  // using Base = smartref::reflect_member_function<Ref>;
  // using Base::operator=;

  // int &operator=(int arg)
  // {
  //   return ref = arg;
  // }

  // using smartref::using_<T>::using_;
  // using smartref::using_<T>::operator=;

  Ref() = default;

  // Ref(const Ref &) = default;
  // Ref &operator=(const Ref &) = default;
  // Ref(Ref &&) = default;
  // Ref &operator=(Ref &&) = default;

  Ref(const Ref &) = delete;
  Ref(Ref &&) = delete;
  Ref &operator=(const Ref &) = delete;
  Ref &operator=(Ref &&) = delete;
};

// struct uiop {
//   auto operator=(int) {}
// };
// struct qwerty : uiop {
//   using uiop::operator=;
// };
template<typename T>
auto test = []{
  T a;
  T b{};
  T c = {};
  T d = 0;
  T e = {0};
  // T f = a;
  // T g = {a};
  // auto h = T{};
  // auto i = a;
  // auto j = {a};
  // auto k{T{}};
  // auto l{a};

  // a = 0;
  // a = b;
  // a = b = 0;
  // a = b = c;
  // a = (b = 0);
  // a = (b = c);
  // (a = b) = 0;
  // (a = b) = c;
};

auto test_int = test<int>;
auto test_ref = test<Ref>;

// using T = int;
// using T = std::vector<int>;

// using reflection::reflect;

// //! Member-types
// constexpr auto is_valid = [](auto expression)
// {
//   // auto expected = reflect<decltype(expression(std::declval<    T >(), std::declval<    T >()))>;
//   auto actual   = reflect<decltype(expression(std::declval<Ref<T>>(), std::declval<    T >()))>;

//   return true;
//   // return actual == expected;
// };

// #define IS_VALID(expression) is_valid([](auto &&_, auto &&__) {return expression;})

// TODO:
// - constructing a smartref (e.g. Ref<int> x;)

// static_assert(reflect<Ref<T>::value_type>             == reflect<T::value_type>);
// static_assert(reflect<Ref<T>::allocator_type>         == reflect<T::allocator_type>);
// static_assert(reflect<Ref<T>::size_type>              == reflect<T::size_type>);
// static_assert(reflect<Ref<T>::difference_type>        == reflect<T::difference_type>);
// static_assert(reflect<Ref<T>::reference>              == reflect<T::reference>);
// static_assert(reflect<Ref<T>::const_reference>        == reflect<T::const_reference>);
// static_assert(reflect<Ref<T>::pointer>                == reflect<T::pointer>);
// static_assert(reflect<Ref<T>::const_pointer>          == reflect<T::const_pointer>);
// static_assert(reflect<Ref<T>::iterator>               == reflect<T::iterator>);
// static_assert(reflect<Ref<T>::const_iterator>         == reflect<T::const_iterator>);
// static_assert(reflect<Ref<T>::reverse_iterator>       == reflect<T::reverse_iterator>);
// static_assert(reflect<Ref<T>::const_reverse_iterator> == reflect<T::const_reverse_iterator>);

// //! Member functions
// // TODO: Test all overloads
// // TODO: (constructor)
// // TODO: Why does operator= work? What does it do?
// // static_assert(IS_VALID(_.operator=(_)));
// // static_assert(IS_VALID(_.operator=(__)));
// static_assert(IS_VALID(_ = __));
// static_assert(IS_VALID(_.assign(0, 0)));
// static_assert(IS_VALID(_.assign(begin(_), end(_))));
// static_assert(IS_VALID(_.get_allocator()));
// //! Element access
// static_assert(IS_VALID(_.at(T::size_type{})));
// static_assert(IS_VALID(_.operator[](0)));
// static_assert(IS_VALID(_[0]));
// static_assert(IS_VALID(_.front()));
// static_assert(IS_VALID(_.back()));
// static_assert(IS_VALID(_.data()));

// //! Iterators
// static_assert(IS_VALID(_.begin()));
// static_assert(IS_VALID(_.cbegin()));
// static_assert(IS_VALID(_.end()));
// static_assert(IS_VALID(_.cend()));
// static_assert(IS_VALID(_.rbegin()));
// static_assert(IS_VALID(_.crbegin()));
// static_assert(IS_VALID(_.rend()));
// static_assert(IS_VALID(_.crend()));

// //! Capacity
// static_assert(IS_VALID(_.empty()));
// static_assert(IS_VALID(_.size()));
// static_assert(IS_VALID(_.max_size()));
// static_assert(IS_VALID(_.reserve(T::size_type{})));
// static_assert(IS_VALID(_.capacity()));
// static_assert(IS_VALID(_.shrink_to_fit()));

// //! Modifiers
// static_assert(IS_VALID(_.clear()));
// static_assert(IS_VALID(_.insert(begin(_), 0)));
// static_assert(IS_VALID(_.emplace(begin(_), 0)));
// static_assert(IS_VALID(_.template emplace<int>(begin(_), 0)));
// static_assert(IS_VALID(_.erase(begin(_))));
// static_assert(IS_VALID(_.push_back(0)));
// static_assert(IS_VALID(_.emplace_back(0)));
// static_assert(IS_VALID(_.template emplace_back<int>(0)));
// static_assert(IS_VALID(_.pop_back()));
// static_assert(IS_VALID(_.resize(T::size_type{})));
// static_assert(IS_VALID(_.swap(_)));

// //! Non-member functions
// // static_assert(IS_VALID(_ == _);
// // TODO: operator!=
// // TODO: operator<
// // TODO: operator<=
// // TODO: operator>
// // TODO: operator>=
// // TODO: std::swap

// // TODO: Deduction guides

} // namespace tests_containers
<|endoftext|>


<commit_before>#include "../ParserTestsBase.h"

class ParserTests_FunctionCalls : public ParserTestsBase {
};

TEST_F(ParserTests_FunctionCalls, FunctionCallOperator) {
    ASTNode* node = this->parseSingleFunction("def test()\n"
                                              "  test()\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ("Function Variable", fnCall->receiver()->nodeName());
    ASSERT_EQ(0, fnCall->childCount());

    ASSERT_EQ(NewDataType::Void, fnCall->dataType().kind());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallOperatorWithArgument) {
    ASTNode* node = this->parseSingleFunction("def test(Int a)\n"
                                              "  test(a)\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ(1, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallOperatorWithTwoArguments) {
    ASTNode* node = this->parseSingleFunction("def test(Int a)\n"
                                              "  test(a, a)\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ(2, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(0)->nodeName());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(1)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeClosureParameter) {
    Three::ASTNode* node = this->parseSingleFunction("def test({Int} closure)\n"
                                                     "  closure(1)\n"
                                                     "end\n");

    node = node->childAtIndex(0);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ(1, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->receiver()->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeClosurePointerParameter) {
    Three::ASTNode* node = this->parseSingleFunction("def test(*{Int} closure)\n"
                                                     "  (*closure)(1)\n"
                                                     "end\n");

    node = node->childAtIndex(0);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ(1, fnCall->childCount());

    node = fnCall->receiver();
    ASSERT_EQ("Dereference Operator", node->nodeName());
    ASSERT_EQ("Local Variable", node->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, MethodInvocation) {
    Three::ASTNode* node = this->parseNodeWithBodies("def Int.test(Int b)\n"
                                                     "end\n"
                                                     "def invoke(*Int a)\n"
                                                     "  a.test(5)\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    ASSERT_EQ("Function Definition", node->childAtIndex(0)->nodeName());
    ASSERT_EQ(NewDataType::Kind::Integer, dynamic_cast<Three::FunctionDefinitionNode*>(node->childAtIndex(0))->methodOnType().kind());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Definition", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Method Call Operator", node->nodeName());

    Three::MethodCallOperatorNode* method = dynamic_cast<Three::MethodCallOperatorNode*>(node);

    ASSERT_EQ("test", method->name());
    ASSERT_EQ("Local Variable", method->receiver()->nodeName());
    ASSERT_EQ("a", dynamic_cast<Three::VariableNode*>(method->receiver())->name());
    ASSERT_EQ(1, method->childCount());
    EXPECT_EQ("Integer Literal", method->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeVariableAsFunction) {
    Three::ASTNode* node = this->parseSingleFunction("def test()\n"
                                                     "  (Int) func\n"
                                                     "  func(1)\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    EXPECT_EQ("Variable Declaration", node->childAtIndex(0)->nodeName());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ("Local Variable", fnCall->receiver()->nodeName());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallDereference) {
    Three::ASTNode* node = this->parseNodeWithBodies("def foo(;*Int)\n"
                                                     "  return null\n"
                                                     "end\n"
                                                     "def test()\n"
                                                     "  *foo() = 1\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    ASSERT_EQ("Function Definition", node->childAtIndex(0)->nodeName());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Definition", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Assign Operator", node->nodeName());

    node = node->childAtIndex(0);
    ASSERT_EQ("Dereference Operator", node->nodeName());
    ASSERT_EQ("Function Call Operator", node->childAtIndex(0)->nodeName());
}
<commit_msg>Add test for multiple namespaces with methods<commit_after>#include "../ParserTestsBase.h"

class ParserTests_FunctionCalls : public ParserTestsBase {
};

TEST_F(ParserTests_FunctionCalls, FunctionCallOperator) {
    ASTNode* node = this->parseSingleFunction("def test()\n"
                                              "  test()\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ("Function Variable", fnCall->receiver()->nodeName());
    ASSERT_EQ(0, fnCall->childCount());

    ASSERT_EQ(NewDataType::Void, fnCall->dataType().kind());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallOperatorWithArgument) {
    ASTNode* node = this->parseSingleFunction("def test(Int a)\n"
                                              "  test(a)\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ(1, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallOperatorWithTwoArguments) {
    ASTNode* node = this->parseSingleFunction("def test(Int a)\n"
                                              "  test(a, a)\n"
                                              "end\n");

    FunctionCallOperatorNode* fnCall = dynamic_cast<FunctionCallOperatorNode*>(node->childAtIndex(0));

    ASSERT_EQ("Function Call Operator", fnCall->nodeName());
    ASSERT_EQ(2, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(0)->nodeName());
    ASSERT_EQ("Local Variable", fnCall->childAtIndex(1)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeClosureParameter) {
    Three::ASTNode* node = this->parseSingleFunction("def test({Int} closure)\n"
                                                     "  closure(1)\n"
                                                     "end\n");

    node = node->childAtIndex(0);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ(1, fnCall->childCount());
    ASSERT_EQ("Local Variable", fnCall->receiver()->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeClosurePointerParameter) {
    Three::ASTNode* node = this->parseSingleFunction("def test(*{Int} closure)\n"
                                                     "  (*closure)(1)\n"
                                                     "end\n");

    node = node->childAtIndex(0);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ(1, fnCall->childCount());

    node = fnCall->receiver();
    ASSERT_EQ("Dereference Operator", node->nodeName());
    ASSERT_EQ("Local Variable", node->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, MethodInvocation) {
    Three::ASTNode* node = this->parseNodeWithBodies("def Int.test(Int b)\n"
                                                     "end\n"
                                                     "def invoke(*Int a)\n"
                                                     "  a.test(5)\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    ASSERT_EQ("Function Definition", node->childAtIndex(0)->nodeName());
    ASSERT_EQ(NewDataType::Kind::Integer, dynamic_cast<Three::FunctionDefinitionNode*>(node->childAtIndex(0))->methodOnType().kind());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Definition", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Method Call Operator", node->nodeName());

    Three::MethodCallOperatorNode* method = dynamic_cast<Three::MethodCallOperatorNode*>(node);

    ASSERT_EQ("test", method->name());
    ASSERT_EQ("Local Variable", method->receiver()->nodeName());
    ASSERT_EQ("a", dynamic_cast<Three::VariableNode*>(method->receiver())->name());
    ASSERT_EQ(1, method->childCount());
    EXPECT_EQ("Integer Literal", method->childAtIndex(0)->nodeName());
}

TEST_F(ParserTests_FunctionCalls, InvokeMethodDefinedInPreviousNamespace) {
    Three::ASTNode* node = this->parseNodeWithBodies("namespace Foo\n"
                                                     "  def Int.something()\n"
                                                     "  end\n"
                                                     "end\n"
                                                     "namespace Foo\n"
                                                     "  def test(*Int a)\n"
                                                     "    a.something()\n"
                                                     "  end\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());

    node = node->childAtIndex(1);
    ASSERT_EQ("Namespace", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Function Definition", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Method Call Operator", node->nodeName());
    auto method = dynamic_cast<MethodCallOperatorNode*>(node);

    ASSERT_EQ("something", method->name());
}

TEST_F(ParserTests_FunctionCalls, InvokeVariableAsFunction) {
    Three::ASTNode* node = this->parseSingleFunction("def test()\n"
                                                     "  (Int) func\n"
                                                     "  func(1)\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    EXPECT_EQ("Variable Declaration", node->childAtIndex(0)->nodeName());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Call Operator", node->nodeName());

    Three::FunctionCallOperatorNode* fnCall = dynamic_cast<Three::FunctionCallOperatorNode*>(node);

    ASSERT_EQ("Local Variable", fnCall->receiver()->nodeName());
}

TEST_F(ParserTests_FunctionCalls, FunctionCallDereference) {
    Three::ASTNode* node = this->parseNodeWithBodies("def foo(;*Int)\n"
                                                     "  return null\n"
                                                     "end\n"
                                                     "def test()\n"
                                                     "  *foo() = 1\n"
                                                     "end\n");

    ASSERT_EQ(2, node->childCount());
    ASSERT_EQ("Function Definition", node->childAtIndex(0)->nodeName());

    node = node->childAtIndex(1);
    ASSERT_EQ("Function Definition", node->nodeName());
    ASSERT_EQ(1, node->childCount());

    node = node->childAtIndex(0);
    ASSERT_EQ("Assign Operator", node->nodeName());

    node = node->childAtIndex(0);
    ASSERT_EQ("Dereference Operator", node->nodeName());
    ASSERT_EQ("Function Call Operator", node->childAtIndex(0)->nodeName());
}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "token.h"
#include "token_exception.h"
#include "tokenreader.h"

using namespace std;

TokenReader::TokenReader( const char * file ){
	ifile.open( file );
	myfile = string( file );
	ifile >> noskipws;
	// cout<<"Opened "<<file<<endl;
}

TokenReader::TokenReader( const string & file ){
	ifile.open( file.c_str() );
	myfile = file;
	ifile >> noskipws;
}

TokenReader::~TokenReader(){
	ifile.close();

	/* tokenreader giveth, and tokenreader taketh */
	for ( vector< Token * >::iterator it = my_tokens.begin(); it != my_tokens.end(); it++ ){
		delete *it;
	}
}

Token * TokenReader::readToken() throw( TokenException ){

	if ( !ifile ){
            throw TokenException( string("Could not open ") + myfile );
        }
	// Token * t;

	// string token_string;

	char open_paren = 'x';
	int parens = 1;
	while ( ifile.good() && open_paren != '(' ){
		ifile >> open_paren;
	}
	// token_string += '(';

	Token * cur_token = new Token();
	cur_token->setFile( myfile );
	my_tokens.push_back( cur_token );
	Token * first = cur_token;
	vector< Token * > token_stack;
	token_stack.push_back( cur_token );

	char n;
	string cur_string = "";
	// while ( parens != 0 ){

	/* in_quote is true if a " is read and before another " is read */
	bool in_quote = false;

	/* escaped unconditionally adds the next character to the string */
	bool escaped = false;
	while ( !token_stack.empty() ){
		if ( !ifile ){
			cout<<__FILE__<<": "<<myfile<<" is bad. Open parens "<<parens<<endl;
			// cout<<"Dump: "<< token_string << "Last token = [" << n << "]" << (int)n << endl;
			first->print( " " );
			throw TokenException("Wrong number of parentheses");
		}
		// char n;
		// slow as we go
		ifile >> n;

		const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!";
		const char * nonalpha = " ;()#\"";
		// cout<<"Alpha char: "<<n<<endl;

		if ( escaped ){
			cur_string += n;
			escaped = false;
			continue;
		}

		if ( n == '\\' ){
			escaped = true;
			continue;
		}

		if ( in_quote ){
			if ( n == '"' ){
				in_quote = false;

				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";

			} else
				cur_string += n;

		} else {
			if ( n == '"' )
				in_quote = true;

			if ( strchr( alpha, n ) != NULL ){
				cur_string += n;
			} else if ( cur_string != "" && strchr( nonalpha, n ) != NULL ){
				// cout<<"Made new token "<<cur_string<<endl;
				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";
			}
		}

		if ( n == '#' || n == ';' ){
			while ( n != '\n' && !ifile.eof() ){
				ifile >> n;
			}
			continue;
		} else if ( n == '(' ){
			Token * another = new Token();
			another->setParent( cur_token );
			cur_token->addToken( another );
			cur_token = another;
			token_stack.push_back( cur_token );
			/*
			parens++;
			cout<<"Inc Parens is "<<parens<<endl;
			*/
		} else if ( n == ')' ){

			if ( token_stack.empty() ){
				cout<<"Stack is empty"<<endl;
				throw TokenException("Stack is empty");
			}
			token_stack.pop_back();
			if ( ! token_stack.empty() ){
				cur_token = token_stack.back();
			}
		}
	}

	// first->print("");
	first->finalize();
	return first;

}

<commit_msg>add a comment<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "token.h"
#include "token_exception.h"
#include "tokenreader.h"

using namespace std;

/* tokenreader reads a file formatted with s-expressions. examples:
 * (hello)
 * (hello world)
 * (hello "world")
 * (hello (world))
 * (hello (world hi))
 */
TokenReader::TokenReader( const char * file ){
	ifile.open( file );
	myfile = string( file );
	ifile >> noskipws;
	// cout<<"Opened "<<file<<endl;
}

TokenReader::TokenReader( const string & file ){
	ifile.open( file.c_str() );
	myfile = file;
	ifile >> noskipws;
}

TokenReader::~TokenReader(){
	ifile.close();

	/* tokenreader giveth, and tokenreader taketh */
	for ( vector< Token * >::iterator it = my_tokens.begin(); it != my_tokens.end(); it++ ){
		delete *it;
	}
}

Token * TokenReader::readToken() throw( TokenException ){

	if ( !ifile ){
            throw TokenException( string("Could not open ") + myfile );
        }
	// Token * t;

	// string token_string;

	char open_paren = 'x';
	int parens = 1;
	while ( ifile.good() && open_paren != '(' ){
		ifile >> open_paren;
	}
	// token_string += '(';

	Token * cur_token = new Token();
	cur_token->setFile( myfile );
	my_tokens.push_back( cur_token );
	Token * first = cur_token;
	vector< Token * > token_stack;
	token_stack.push_back( cur_token );

	char n;
	string cur_string = "";
	// while ( parens != 0 ){

	/* in_quote is true if a " is read and before another " is read */
	bool in_quote = false;

	/* escaped unconditionally adds the next character to the string */
	bool escaped = false;
	while ( !token_stack.empty() ){
		if ( !ifile ){
			cout<<__FILE__<<": "<<myfile<<" is bad. Open parens "<<parens<<endl;
			// cout<<"Dump: "<< token_string << "Last token = [" << n << "]" << (int)n << endl;
			first->print( " " );
			throw TokenException("Wrong number of parentheses");
		}
		// char n;
		// slow as we go
		ifile >> n;

		const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!";
		const char * nonalpha = " ;()#\"";
		// cout<<"Alpha char: "<<n<<endl;

		if ( escaped ){
			cur_string += n;
			escaped = false;
			continue;
		}

		if ( n == '\\' ){
			escaped = true;
			continue;
		}

		if ( in_quote ){
			if ( n == '"' ){
				in_quote = false;

				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";

			} else
				cur_string += n;

		} else {
			if ( n == '"' )
				in_quote = true;

			if ( strchr( alpha, n ) != NULL ){
				cur_string += n;
			} else if ( cur_string != "" && strchr( nonalpha, n ) != NULL ){
				// cout<<"Made new token "<<cur_string<<endl;
				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";
			}
		}

		if ( n == '#' || n == ';' ){
			while ( n != '\n' && !ifile.eof() ){
				ifile >> n;
			}
			continue;
		} else if ( n == '(' ){
			Token * another = new Token();
			another->setParent( cur_token );
			cur_token->addToken( another );
			cur_token = another;
			token_stack.push_back( cur_token );
			/*
			parens++;
			cout<<"Inc Parens is "<<parens<<endl;
			*/
		} else if ( n == ')' ){

			if ( token_stack.empty() ){
				cout<<"Stack is empty"<<endl;
				throw TokenException("Stack is empty");
			}
			token_stack.pop_back();
			if ( ! token_stack.empty() ){
				cur_token = token_stack.back();
			}
		}
	}

	// first->print("");
	first->finalize();
	return first;

}

<|endoftext|>