#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