#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