WONKY



LOG | FILES | OVERVIEW


#ifndef WONKY_LINKAGE_C
#define WONKY_LINKAGE_C WONKY_LINKAGE_C
#include <linkage.h>





struct Linkage* get_linkage()
{
	struct Linkage *ret;
	ret=wonky_malloc(sizeof(struct Linkage));
	ret->ids=wonky_malloc(sizeof(struct Map));

	Map_Init(ret->ids);

	return ret;
}

/*denoted things are deleted here and left alone when deleting scopes*/
void delete_linkage(struct Linkage *linkage)
{
	Map_Destroy(linkage->ids);
	wonky_free(linkage);
}


/*TODO optimise when you know what should happen here*/

void account_for_upper_linkage_on_object(struct Scope *scope,struct Translation_Data *translation_data,struct Denoted_Object *denoted_object)
{
	struct Denoted_Object *hold_object;
	hold_object=check_ordinary(scope,denoted_object->id);
	if(hold_object!=NULL && hold_object->denotation==DT_Object && types_are_identical(denoted_object->object->type,hold_object->object->type))
	{
		if(hold_object->linkage!=LINKAGE_NONE)
		{
			denoted_object->linkage=hold_object->linkage;
		}else
		{
			denoted_object->linkage=LINKAGE_EXTERNAL;
		}
	}else
	{
		denoted_object->linkage=LINKAGE_EXTERNAL;
	}
}
void account_for_upper_linkage_on_function(struct Scope *scope,struct Translation_Data *translation_data,struct Denoted_Function *denoted_function)
{
	struct Denoted_Function *hold_function;
	hold_function=check_ordinary(scope,denoted_function->id);
	if(hold_function!=NULL)
	{
		if(hold_function->denotation==DT_Function && types_are_identical(denoted_function->type,hold_function->type))
		{
			denoted_function->linkage=( (hold_function->linkage==LINKAGE_NONE) ? LINKAGE_EXTERNAL : hold_function->linkage);
		}else
		{
			push_translation_error("mismtatching types for %t",translation_data,denoted_function->id);
			push_translation_note("first it was declared with type %T",translation_data,hold_function->type);
			push_translation_note("now it's declared with type %T",translation_data,denoted_function->type);
			return;
		}
	}else
	{
		denoted_function->linkage=LINKAGE_EXTERNAL;
	}
}
void resolve_object_linkage(struct Scope *scope,struct Translation_Data *translation_data,struct Denoted_Object *denoted_object)
{
	if(scope->type==FILE_SCOPE)
	{
		if(denoted_object->object->storage_class==SCS_NONE || denoted_object->object->storage_class==SCS_EXTERN)
		{
			denoted_object->linkage=LINKAGE_EXTERNAL;
			denoted_object->object->storage_class=SCS_STATIC;
			account_for_upper_linkage_on_object(scope,translation_data,denoted_object);

		}else if(denoted_object->object->storage_class==SCS_STATIC) 
		{
			denoted_object->linkage=LINKAGE_INTERNAL;
			denoted_object->object->storage_class=SCS_STATIC;
		}else
		{
			wonky_assert(SHOULD_NOT_REACH_HERE);
		}
	}else if(scope->type==FUNCTION_PROTOTYPE_SCOPE)
	{
		denoted_object->linkage=LINKAGE_NONE;
		denoted_object->object->storage_class=SCS_NONE;
		if(denoted_object->object->storage_class!=SCS_NONE && denoted_object->object->storage_class!=SCS_REGISTER)
		{
			push_translation_error("storage class specifier other than register in function prototype scope",translation_data);
			return ;
		}
	}else if(scope->type==BLOCK_SCOPE)
	{
		denoted_object->linkage=LINKAGE_NONE;
		/*here comes the spooky part*/
		if(denoted_object->object->storage_class==SCS_EXTERN)
			account_for_upper_linkage_on_object(scope,translation_data,denoted_object);
	}else
	{
		wonky_assert(SHOULD_NOT_REACH_HERE);
	}

	/*check if id is linked oppositely*/
	if(denoted_object->linkage==LINKAGE_EXTERNAL &&
		Map_Check(translation_data->internal_linkage->ids,denoted_object->id->data,denoted_object->id->size)!=NULL)
	{
		push_translation_error("linking id both internally and externally",translation_data);
	}else if(denoted_object->linkage==LINKAGE_INTERNAL && 
		Map_Check(translation_data->program->external_linkage->ids,denoted_object->id->data,denoted_object->id->size)!=NULL)
	{
		push_translation_error("linking id both internally and externally",translation_data);
	}
}
void resolve_function_linkage(struct Scope *scope,struct Translation_Data *translation_data,struct Denoted_Function *denoted_function)
{
	if(scope->type==BLOCK_SCOPE)
	{
		if(denoted_function->linkage==LINKAGE_INTERNAL)
		{
			push_translation_error("static storage class specifier on function declaration in block scope",translation_data);
			return;
		}else
		{
			denoted_function->linkage=LINKAGE_EXTERNAL;
			account_for_upper_linkage_on_function(scope,translation_data,denoted_function);

		}
	}else if(scope->type==FILE_SCOPE)
	{
		if(denoted_function->linkage==LINKAGE_NONE)
			denoted_function->linkage=LINKAGE_EXTERNAL;
		/*falltrough*/

		if(denoted_function->linkage==LINKAGE_EXTERNAL)
			account_for_upper_linkage_on_function(scope,translation_data,denoted_function);

	}else
	{
		wonky_assert(SHOULD_NOT_REACH_HERE);
	}

	/*check if id is linked oppositely*/
	if(denoted_function->linkage==LINKAGE_EXTERNAL &&
		Map_Check(translation_data->internal_linkage->ids,denoted_function->id->data,denoted_function->id->size)!=NULL)
	{
		push_translation_error("linking id both internally and externally",translation_data);
	}else if(denoted_function->linkage==LINKAGE_INTERNAL &&
		Map_Check(translation_data->program->external_linkage->ids,denoted_function->id->data,denoted_function->id->size)!=NULL)
	{
		push_translation_error("linking id both internally and externally",translation_data);
	}
}
void push_object_into_linkage(struct Translation_Data *translation_data,struct AST_Object_Declaration *object)
{
	struct AST_Object_Declaration *possible_declaration;

	wonky_assert(is_valid_ast((struct AST*)object));
	possible_declaration=Map_Check(translation_data->program->external_linkage->ids,object->object->id->data,object->object->id->size);

	if(possible_declaration==NULL)
	{
		if(object->object->linkage==LINKAGE_EXTERNAL)
			Map_Push(translation_data->program->external_linkage->ids,object->object->id->data,object->object->id->size,object);
		else if(object->object->linkage==LINKAGE_INTERNAL)
			Map_Push(translation_data->internal_linkage->ids,object->object->id->data,object->object->id->size,object);
	}else
	{
		if(object->initializer!=NULL && possible_declaration->initializer!=NULL)
			push_translation_error("reinitialisation of %t",translation_data,object->object->id);
	}


}
void push_function_into_linkage(struct Translation_Data *translation_data,struct AST *function)
{
	wonky_assert(is_valid_ast(function) && function->type==ST_FUNCTION_DEFINITION || function->type==ST_FUNCTION_DECLARATION);

	if(function->type==ST_FUNCTION_DECLARATION)
		push_function_declaration_into_linkage(translation_data,(struct AST_Function_Declaration*)function);
	else
		push_function_definition_into_linkage(translation_data,(struct AST_Function_Definition*)function);
}
void push_function_definition_into_linkage(struct Translation_Data *translation_data,struct AST_Function_Definition *function)
{
	struct AST *possible_declaration;

	possible_declaration=Map_Check(translation_data->program->external_linkage->ids,function->function->id->data,function->function->id->size);

	if(function->function->linkage==LINKAGE_EXTERNAL)
		Map_Push(translation_data->program->external_linkage->ids,function->function->id->data,function->function->id->size,function);
	else
		Map_Push(translation_data->internal_linkage->ids,function->function->id->data,function->function->id->size,function);

	if(possible_declaration!=NULL)
	{
		if(possible_declaration->type==ST_FUNCTION_DEFINITION)
			push_translation_error("redefinition of function %t",translation_data,function->function->id);
	}
}
void push_function_declaration_into_linkage(struct Translation_Data *translation_data,struct AST_Function_Declaration *function)
{
	struct AST *possible_definition;
	possible_definition=Map_Check(translation_data->program->external_linkage->ids,function->function->id->data,function->function->id->size);

	if(possible_definition==NULL)
	{
		if(function->function->linkage==LINKAGE_EXTERNAL)
			Map_Push(translation_data->program->external_linkage->ids,function->function->id->data,function->function->id->size,function);
		else
			Map_Push(translation_data->internal_linkage->ids,function->function->id->data,function->function->id->size,function);
	}
}
#endif