WONKY



LOG | FILES | OVERVIEW


#ifndef WONKY_SCOPE_C
#define WONKY_SCOPE_C WONKY_SCOPE_C
#include <scope.h>


struct Scope* get_normal_scope(struct Scope *parent,enum Scope_Type type)
{
	struct Normal_Scope *ret;
	
	wonky_assert(type==BLOCK_SCOPE || type==FILE_SCOPE || type==FUNCTION_PROTOTYPE_SCOPE);

	ret=wonky_malloc(sizeof(struct Normal_Scope));
	ret->type=type;
	ret->tags=wonky_malloc(sizeof(struct Map));
	ret->ordinary=wonky_malloc(sizeof(struct Map));

	wonky_assert((type!=FILE_SCOPE) || parent==NULL);
	ret->parent=parent;

	Map_Init(ret->tags);
	Map_Init(ret->ordinary);




	ret->object_order=wonky_malloc(sizeof(struct Queue));


	Queue_Init(ret->object_order);

	wonky_assert(is_valid_normal_scope(ret));
	return (struct Scope*)ret;

}
struct Scope* get_partial_normal_scope(struct Normal_Scope *scope)
{
	struct Normal_Scope *ret;
	ret=wonky_malloc(sizeof(struct Normal_Scope));
	ret->object_order=wonky_malloc(sizeof(struct Queue));
	*ret->object_order=*scope->object_order;

	ret->type=scope->type;
	ret->parent=scope->parent;
	ret->tags=scope->tags;
	ret->ordinary=scope->ordinary;

	return (struct Scope*)ret;
}
struct Scope* get_function_scope(struct Scope *parent,struct Denoted_Function *function)
{
	struct Function_Scope *ret;
	wonky_assert(parent!=NULL && parent->type==FILE_SCOPE);

	ret=wonky_malloc(sizeof(struct Function_Scope));
	ret->type=FUNCTION_SCOPE;
	ret->parent=parent;
	ret->function=function;
	ret->labels=wonky_malloc(sizeof(struct Map));

	Map_Init(ret->labels);

	ret->label_order=wonky_malloc(sizeof(struct Queue));
	Queue_Init(ret->label_order);

	wonky_assert(is_valid_function_scope(ret));
	return (struct Scope*)ret;
}
void delete_normal_scope(struct Normal_Scope *scope)
{
	Map_Map(scope->tags,delete_denoted_wrapper);
	Map_Destroy(scope->tags);
	Map_Map(scope->ordinary,delete_denoted_with_no_linkage_wrapper);
	Map_Destroy(scope->ordinary);
	while(scope->object_order->size>0)
		Queue_Pop(scope->object_order);
	wonky_free(scope->object_order);
	wonky_free(scope);
}

void delete_function_scope(struct Function_Scope *scope)
{
	Map_Map(scope->labels,delete_denoted_wrapper);
	Map_Destroy(scope->labels);
	while(scope->label_order->size>0)
		Queue_Pop(scope->label_order);
	wonky_free(scope->label_order);
	wonky_free(scope);
}

void delete_scope(struct Scope *scope)
{
	switch(scope->type)
	{
		case BLOCK_SCOPE:
		case FILE_SCOPE:
		case FUNCTION_PROTOTYPE_SCOPE:
			delete_normal_scope((struct Normal_Scope*)scope);
			break;
		case FUNCTION_SCOPE:
			delete_function_scope((struct Function_Scope*)scope);
		default:
			wonky_assert(SHOULD_NOT_REACH_HERE);
	}
}


struct Denoted_Statement* check_label(struct Scope *current,struct identifier *id)
{
	struct Denoted_Statement *hold=NULL;
	struct Function_Scope *function_scope;

	function_scope=get_enclosing_function_scope(current);

	if(function_scope!=NULL)
		hold=Map_Check(function_scope->labels,id->data,id->size);

	return hold;
}

struct Denoted* check_tag(struct Scope *current,struct identifier *id)
{
	void *hold;
	hold=NULL;
	while(current!=NULL && hold==NULL)
	{
		switch(current->type)
		{
			case FILE_SCOPE:
			case BLOCK_SCOPE:
			case FUNCTION_PROTOTYPE_SCOPE:
				hold=Map_Check(((struct Normal_Scope*)current)->tags,id->data,id->size);

		}
		current=current->parent;
	}
	return hold;
}
void* check_ordinary(struct Scope *current,struct identifier *id)
{
	void *hold;
	hold=NULL;
	while(current!=NULL && hold==NULL)
	{
		switch(current->type)
		{
			case FILE_SCOPE:
			case BLOCK_SCOPE:
			case FUNCTION_PROTOTYPE_SCOPE:
				hold=Map_Check(((struct Normal_Scope*)current)->ordinary,id->data,id->size);

		}
		current=current->parent;
	}
	return hold;
}

void* check_struct_union_member(struct Normal_Scope *inner,struct identifier *id)
{
	return Map_Check(inner->ordinary,id->data,id->size);
}
void Scope_Push(struct Scope *scope,struct Denoted *declarator,struct Translation_Data *translation_data)
{

	switch(declarator->denotation)
	{
		case DT_Statement:
			/*perhaps lables should be denoted*/
			wonky_assert(SHOULD_NOT_REACH_HERE);
		case DT_Function:
			push_function(scope,translation_data,AS_DENOTED_FUNCTION(declarator));
			break;
		case DT_Object:
			push_object(scope,translation_data,AS_DENOTED_OBJECT_PTR(declarator));
			break;
		case DT_Typedef:
			push_typedef(scope,translation_data,AS_DENOTED_TYPEDEF(declarator));
			break;
		case DT_Enum_Constant:
			push_denoted_enum_constant(scope,translation_data,AS_DENOTED_ENUM_CONST(declarator));
			break;
		case DT_Struct_Union_Member:
			wonky_assert(SHOULD_NOT_REACH_HERE);
			break;
		case DT_Enum:
			push_denoted_enum_tag(scope,translation_data,AS_DENOTED_ENUM(declarator));
			break;
		case DT_Struct_Union_Tag:
			push_denoted_struct_union_tag(scope,translation_data,AS_DENOTED_STRUCT_UNION(declarator));
			break;
	}


}
struct Function_Scope* get_enclosing_function_scope(struct Scope *scope)
{
	struct Scope *current;
	current=scope;
	while(current->type!=FUNCTION_SCOPE && current!=NULL)
	{
		wonky_assert(current->type!=FILE_SCOPE);
		current=current->parent;
	}
	return (struct Function_Scope*)current;
}
struct Denoted_Object* get_last_known_denoted_object(struct Normal_Scope *scope)
{
	if(scope->object_order->last==NULL) 
		return NULL;
	else
		return (struct Denoted_Object*)scope->object_order->last->data;
}
struct Denoted_Function* get_enclosing_function(struct Scope *scope)
{
	struct Function_Scope *function_scope;

	function_scope=get_enclosing_function_scope(scope);

	if(function_scope==NULL)
		return NULL;/*TODO maybe return a denoted_error*/

	return function_scope->function;
}
_Bool check_if_typedefed(struct Scope* scope,struct identifier *id)
{
	struct Denoted *hold;
	hold=check_ordinary(scope,id);
	if(hold==NULL || hold->denotation!=DT_Typedef)
		return 0;
	else
		return 1;

}
struct Denoted* push_label(struct Scope *current,struct identifier *label,struct AST *statement,struct Translation_Data *translation_data)
{
	struct Denoted_Statement *hold_statement;
	struct Function_Scope *current_function_scope;

	current_function_scope=get_enclosing_function_scope(current);

	hold_statement=(struct Denoted_Statement*)Map_Check(current_function_scope->labels,label->data,label->size);

	if(hold_statement!=NULL)
	{
		wonky_assert(hold_statement->denotation==DT_Statement);

		if(hold_statement->statement!=NULL)
		{
			push_translation_error("Redeclaration of label id %t",translation_data,label);

			return get_denoted_error((struct Denoted*)hold_statement);
		}else
		{
			wonky_assert(hold_statement->label!=NULL);
			wonky_assert(hold_statement->gotos_jumping_to_this_statement->size>0);
			wonky_assert(hold_statement->previous_denoted_object==NULL);

			hold_statement->label=label;
			hold_statement->statement=statement;

			/*note the use of the current scope instead of the function scope*/
			hold_statement->previous_denoted_object=get_last_known_denoted_object((struct Normal_Scope*)current);

			wonky_assert(hold_statement->previous_denoted_object==NULL || hold_statement->previous_denoted_object->denotation==DT_Object);

			return (struct Denoted*)hold_statement;
		}
	}else
	{

		hold_statement=(struct Denoted_Statement*)get_denoted_statement(label,statement,get_last_known_denoted_object((struct Normal_Scope*)current));
		Map_Push(current_function_scope->labels,label->data,label->size,hold_statement);
		Queue_Push(current_function_scope->label_order,hold_statement);


		return (struct Denoted*)hold_statement;
	}

	wonky_assert(SHOULD_NOT_REACH_HERE);
}


void push_object(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Object *denoted_object)
{
	struct Denoted *hold_previous;

	wonky_assert(current->type!=FUNCTION_SCOPE);


	

	hold_previous=check_and_push_id(denoted_object,AS_NORMAL_SCOPE(current)->ordinary,denoted_object->id,translation_data);
	Queue_Push(AS_NORMAL_SCOPE(current)->object_order,denoted_object);


	if(has_new_errors(translation_data) || !constraint_check_object_linkage(denoted_object,hold_previous,current,translation_data) )
	{
		translation_data->program->number_of_errors_when_last_checked--; /*TODO make a new function for this for gods sake*/
		//delete_denoted_object(denoted_object);
	}

}
void push_function(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Function *denoted_function)
{
	struct Denoted *hold_previous;

	wonky_assert(current->type!=FUNCTION_SCOPE);



	hold_previous=check_and_push_id(denoted_function,AS_NORMAL_SCOPE(current)->ordinary,denoted_function->id,translation_data);

	if(has_new_errors(translation_data) || !constraint_check_function_linkage(denoted_function,hold_previous,current,translation_data))
	{
		//delete_denoted_function(denoted_function);
		translation_data->program->number_of_errors_when_last_checked--;
	}
}
#define CHECK_AND_PUSH(thing,scope) Map_Check_And_Push(scope,thing->id->data,thing->id->size,thing)
void push_typedef(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Type *denoted_typedef)
{
	struct Denoted *hold_denotated;
	hold_denotated=CHECK_AND_PUSH(denoted_typedef,AS_NORMAL_SCOPE(current)->ordinary);
	if(hold_denotated)
	{
		delete_denoted_typedef(denoted_typedef);
		push_translation_error("redefinition of identifier",translation_data);
	}
}
void push_denoted_enum_tag(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Enum *denoted_enum)
{
	struct Denoted *hold_denotated;
	hold_denotated=Map_Check_And_Push(AS_NORMAL_SCOPE(current)->tags,denoted_enum->enumeration->id->data,denoted_enum->enumeration->id->size,denoted_enum);
	if(hold_denotated)
	{
		delete_denoted_enum(denoted_enum);
		push_translation_error("redefinition of tag",translation_data);
	}
}

void push_denoted_enum_constant(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Enum_Const *denoted_enum_constant)
{
	struct Denoted *hold_denotated;
	hold_denotated=CHECK_AND_PUSH(denoted_enum_constant,AS_NORMAL_SCOPE(current)->ordinary);
	if(hold_denotated)
	{
		delete_denoted_enum_constant(denoted_enum_constant);
		push_translation_error("redefinition of identifier",translation_data);
	}
}
void push_denoted_struct_union_tag(struct Scope *current,struct Translation_Data *translation_data,struct Denoted_Struct_Union *denoted_struct_union)
{
	struct Denoted *hold_denotated;
	hold_denotated=Map_Check_And_Push(AS_NORMAL_SCOPE(current)->tags,denoted_struct_union->struct_union->id->data,denoted_struct_union->struct_union->id->size,denoted_struct_union);
	if(hold_denotated)
	{
		delete_denoted_struct_union(denoted_struct_union);
		push_translation_error("redefinition of tag",translation_data);
	}
}
void* check_and_push_id(void *data,struct Map *scope_map,struct identifier *id,struct Translation_Data *translation_data)
{
	return Map_Check_And_Push(scope_map,id->data,id->size,data);
}
#endif