<commit_before>/**
 * Zillians MMO
 * Copyright (C) 2007-2011 Zillians.com, Inc.
 * For more information see http://www.zillians.com
 *
 * Zillians MMO is the library and runtime for massive multiplayer online game
 * development in utility computing model, which runs as a service for every
 * developer to build their virtual world running on our GPU-assisted machines.
 *
 * This is a close source library intended to be used solely within Zillians.com
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef ZILLIANS_LANGUAGE_STAGE_VISITOR_RESTRUCTURESTAGEVISITOR_H_
#define ZILLIANS_LANGUAGE_STAGE_VISITOR_RESTRUCTURESTAGEVISITOR_H_

#include "core/Prerequisite.h"
#include "language/tree/ASTNodeHelper.h"
#include "language/context/TransformerContext.h"
#include "language/tree/visitor/GenericDoubleVisitor.h"
#include "language/tree/visitor/NameManglingVisitor.h"
#include "language/stage/transformer/context/ManglingStageContext.h"

using namespace zillians::language::tree;
using zillians::language::tree::visitor::GenericDoubleVisitor;
using zillians::language::tree::visitor::NameManglingVisitor;

namespace zillians { namespace language { namespace stage { namespace visitor {

/**
 * RestructureStageVisitor is the visitation helper for RestructureStage
 *
 * @see RestructureStage
 */
struct RestructureStageVisitor : GenericDoubleVisitor
{
	CREATE_INVOKER(restructInvoker, restruct)

	RestructureStageVisitor()
	{
		REGISTER_ALL_VISITABLE_ASTNODE(restructInvoker)
	}

	void restruct(ASTNode& node)
	{
		revisit(node);
	}

	void restruct(ClassDecl& node)
	{
		revisit(node);

		// check if there's no default constructor,
		bool has_default_constructor = false;
		foreach(i, node.member_functions)
		{
			if((*i)->name->toString() == L"new")
			{
				if( (*i)->parameters.size() == 0 || ( (*i)->parameters.size() == 1 && (*i)->parameters[0]->name->toString() == L"this" ) )
				{
					has_default_constructor = true;
					break;
				}
			}
		}

		// if there's none, create a new one for it
		if(!has_default_constructor)
		{
			transforms.push_back([&](){
				SimpleIdentifier* name = new SimpleIdentifier(L"new");
				TypeSpecifier* type = getParserContext().program->internal->getPrimitiveTy(PrimitiveType::VOID);
				Block* block = new Block();

				FunctionDecl* default_constructor = new FunctionDecl(
						name,
						type,
						true, false,
						Declaration::VisibilitySpecifier::DEFAULT,
						block);

				node.addFunction(default_constructor);

				ASTNodeHelper::propogateSourceInfo(*name, node);
				ASTNodeHelper::propogateSourceInfo(*block, node);
				ASTNodeHelper::propogateSourceInfo(*default_constructor, node);
			});
		}
	}

	void restruct(FunctionDecl& node)
	{
		revisit(node);

		// for all class member function
		bool need_to_prepend_this_argument = false;
		ClassDecl* owner_class = ASTNodeHelper::getOwner<ClassDecl>(&node);
		if(owner_class && node.is_member && !node.is_static)
		{
			if(node.parameters.size() == 0)
			{
				// if member function has zero argument, which means we've never prepended "this" argument to it
				need_to_prepend_this_argument = true;
			}
			else
			{
				// otherwise, check the very first argument's name and type
				if(node.parameters[0]->name->toString() != L"this")
				{
					need_to_prepend_this_argument = true;
				}
			}
		}

		// prepend "this" argument to the function declaration if we haven't done so
		if(need_to_prepend_this_argument)
		{
			transforms.push_back([&, owner_class](){
				SimpleIdentifier* name = new SimpleIdentifier(L"this");
				Identifier* type_name = cast<Identifier>(owner_class->name->clone());
				TypeSpecifier* type_specifier = new TypeSpecifier(type_name);

				VariableDecl* this_parameter = new VariableDecl(
						name,
						type_specifier,
						true, false, false,
						Declaration::VisibilitySpecifier::DEFAULT);

				node.prependParameter(this_parameter);

				ASTNodeHelper::propogateSourceInfo(*name, node);
				ASTNodeHelper::propogateSourceInfo(*type_name, node);
				ASTNodeHelper::propogateSourceInfo(*type_specifier, node);
				ASTNodeHelper::propogateSourceInfo(*this_parameter, node);
			});
		}
	}

	void restruct(VariableDecl& node)
	{
		revisit(node);

		if(node.initializer)
		{
			// transform all initializer into a separate assignment binary expression
			// for example (var a = ...):
			//
			//       block
			//      /  |  \
			//     ......  var_decl
			//            /        \
			//           a         (initializer)
			//
			// will be transformed into:
			//
			//       block------------------+
			//      /  |  \                  \
			//     ......  var_decl           =
			//            /        \         / \
			//           a         (null)	a   (initializer)
			//
			// note that we skip parameters in FunctionDecl, which shouldn't be transformed
			//
			if(ASTNodeHelper::hasOwner<FunctionDecl>(&node) && ASTNodeHelper::hasOwner<Block>(&node))
			{
				transforms.push_back([&](){
					DeclarativeStmt* anchor = cast<DeclarativeStmt>(node.parent);
					Block* parent = (anchor && anchor->parent) ? cast<Block>(anchor->parent) : NULL;
					SimpleIdentifier* name = cast<SimpleIdentifier>(node.name);
					BOOST_ASSERT(parent != NULL && name != NULL && anchor != NULL && "variable declaration has incorrect hierarchy");
					if(parent && name && anchor)
					{
						Identifier*     new_identifier      = cast<Identifier>(node.name->clone());
						PrimaryExpr*    new_primary_expr    = new PrimaryExpr(new_identifier);
						BinaryExpr*     new_assignment_expr = new BinaryExpr(BinaryExpr::OpCode::ASSIGN, new_primary_expr, node.initializer);
						ExpressionStmt* new_expr_stmt       = new ExpressionStmt(new_assignment_expr);

						SplitReferenceContext::set(new_identifier, anchor);
						SplitReferenceContext::set(new_primary_expr, anchor);
						SplitReferenceContext::set(new_assignment_expr, anchor);
						SplitReferenceContext::set(new_expr_stmt, anchor);
<commit_msg>make the comment for variable decl restructure clearer<commit_after>/**
 * Zillians MMO
 * Copyright (C) 2007-2011 Zillians.com, Inc.
 * For more information see http://www.zillians.com
 *
 * Zillians MMO is the library and runtime for massive multiplayer online game
 * development in utility computing model, which runs as a service for every
 * developer to build their virtual world running on our GPU-assisted machines.
 *
 * This is a close source library intended to be used solely within Zillians.com
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef ZILLIANS_LANGUAGE_STAGE_VISITOR_RESTRUCTURESTAGEVISITOR_H_
#define ZILLIANS_LANGUAGE_STAGE_VISITOR_RESTRUCTURESTAGEVISITOR_H_

#include "core/Prerequisite.h"
#include "language/tree/ASTNodeHelper.h"
#include "language/context/TransformerContext.h"
#include "language/tree/visitor/GenericDoubleVisitor.h"
#include "language/tree/visitor/NameManglingVisitor.h"
#include "language/stage/transformer/context/ManglingStageContext.h"

using namespace zillians::language::tree;
using zillians::language::tree::visitor::GenericDoubleVisitor;
using zillians::language::tree::visitor::NameManglingVisitor;

namespace zillians { namespace language { namespace stage { namespace visitor {

/**
 * RestructureStageVisitor is the visitation helper for RestructureStage
 *
 * @see RestructureStage
 */
struct RestructureStageVisitor : GenericDoubleVisitor
{
	CREATE_INVOKER(restructInvoker, restruct)

	RestructureStageVisitor()
	{
		REGISTER_ALL_VISITABLE_ASTNODE(restructInvoker)
	}

	void restruct(ASTNode& node)
	{
		revisit(node);
	}

	void restruct(ClassDecl& node)
	{
		revisit(node);

		// check if there's no default constructor,
		bool has_default_constructor = false;
		foreach(i, node.member_functions)
		{
			if((*i)->name->toString() == L"new")
			{
				if( (*i)->parameters.size() == 0 || ( (*i)->parameters.size() == 1 && (*i)->parameters[0]->name->toString() == L"this" ) )
				{
					has_default_constructor = true;
					break;
				}
			}
		}

		// if there's none, create a new one for it
		if(!has_default_constructor)
		{
			transforms.push_back([&](){
				SimpleIdentifier* name = new SimpleIdentifier(L"new");
				TypeSpecifier* type = getParserContext().program->internal->getPrimitiveTy(PrimitiveType::VOID);
				Block* block = new Block();

				FunctionDecl* default_constructor = new FunctionDecl(
						name,
						type,
						true, false,
						Declaration::VisibilitySpecifier::DEFAULT,
						block);

				node.addFunction(default_constructor);

				ASTNodeHelper::propogateSourceInfo(*name, node);
				ASTNodeHelper::propogateSourceInfo(*block, node);
				ASTNodeHelper::propogateSourceInfo(*default_constructor, node);
			});
		}
	}

	void restruct(FunctionDecl& node)
	{
		revisit(node);

		// for all class member function
		bool need_to_prepend_this_argument = false;
		ClassDecl* owner_class = ASTNodeHelper::getOwner<ClassDecl>(&node);
		if(owner_class && node.is_member && !node.is_static)
		{
			if(node.parameters.size() == 0)
			{
				// if member function has zero argument, which means we've never prepended "this" argument to it
				need_to_prepend_this_argument = true;
			}
			else
			{
				// otherwise, check the very first argument's name and type
				if(node.parameters[0]->name->toString() != L"this")
				{
					need_to_prepend_this_argument = true;
				}
			}
		}

		// prepend "this" argument to the function declaration if we haven't done so
		if(need_to_prepend_this_argument)
		{
			transforms.push_back([&, owner_class](){
				SimpleIdentifier* name = new SimpleIdentifier(L"this");
				Identifier* type_name = cast<Identifier>(owner_class->name->clone());
				TypeSpecifier* type_specifier = new TypeSpecifier(type_name);

				VariableDecl* this_parameter = new VariableDecl(
						name,
						type_specifier,
						true, false, false,
						Declaration::VisibilitySpecifier::DEFAULT);

				node.prependParameter(this_parameter);

				ASTNodeHelper::propogateSourceInfo(*name, node);
				ASTNodeHelper::propogateSourceInfo(*type_name, node);
				ASTNodeHelper::propogateSourceInfo(*type_specifier, node);
				ASTNodeHelper::propogateSourceInfo(*this_parameter, node);
			});
		}
	}

	void restruct(VariableDecl& node)
	{
		revisit(node);

		if(node.initializer)
		{
			// transform all initializer into a separate assignment binary expression
			// for example (var a = ...):
			//
			//       block
			//      /  |  \
			//     ......  decl_stmt
			//                 |
			//              var_decl
			//             /        \
			//            a         (initializer)
			//
			// will be transformed into:
			//
			//       block---------------+
			//      /  |  \               \
			//     ......  decl_stmt       expr_stmt
			//                 |               |
			//              var_decl     binary_expr(=)
			//             /        \         / \
			//            a         (null)	a   (initializer)
			//
			// note that we skip parameters in FunctionDecl, which shouldn't be transformed
			//
			if(ASTNodeHelper::hasOwner<FunctionDecl>(&node) && ASTNodeHelper::hasOwner<Block>(&node))
			{
				transforms.push_back([&](){
					DeclarativeStmt* anchor = cast<DeclarativeStmt>(node.parent);
					Block* parent = (anchor && anchor->parent) ? cast<Block>(anchor->parent) : NULL;
					SimpleIdentifier* name = cast<SimpleIdentifier>(node.name);
					BOOST_ASSERT(parent != NULL && name != NULL && anchor != NULL && "variable declaration has incorrect hierarchy");
					if(parent && name && anchor)
					{
						Identifier*     new_identifier      = cast<Identifier>(node.name->clone());
						PrimaryExpr*    new_primary_expr    = new PrimaryExpr(new_identifier);
						BinaryExpr*     new_assignment_expr = new BinaryExpr(BinaryExpr::OpCode::ASSIGN, new_primary_expr, node.initializer);
						ExpressionStmt* new_expr_stmt       = new ExpressionStmt(new_assignment_expr);

						SplitReferenceContext::set(new_identifier, anchor);
						SplitReferenceContext::set(new_primary_expr, anchor);
						SplitReferenceContext::set(new_assignment_expr, anchor);
						SplitReferenceContext::set(new_expr_stmt, anchor);

{'fraction_non_alphanumeric': 0.11558099953581928, 'fraction_numerical': 0.0020114497911186756, 'mean_word_length': 3.4545141281874567, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3020885', 'n_tokens_mistral': 4510, 'n_tokens_neox': 3787, 'n_words': 901}