harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

scope.c (3189B)


      1 #include <assert.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include "expr.h"
      5 #include "identifier.h"
      6 #include "scope.h"
      7 #include "util.h"
      8 
      9 static uint32_t
     10 name_hash(uint32_t init, const struct identifier *ident)
     11 {
     12 	return fnv1a_s(init, ident->name);
     13 }
     14 
     15 struct scope *
     16 scope_push(struct scope **stack, enum scope_class class)
     17 {
     18 	struct scope *new = xcalloc(1, sizeof(struct scope));
     19 	new->class = class;
     20 	new->next = &new->objects;
     21 	new->parent = *stack;
     22 	*stack = new;
     23 	return new;
     24 }
     25 
     26 struct scope *
     27 scope_pop(struct scope **stack)
     28 {
     29 	struct scope *prev = *stack;
     30 	assert(prev);
     31 	*stack = prev->parent;
     32 	return prev;
     33 }
     34 
     35 struct scope *
     36 scope_lookup_ancestor(struct scope *scope,
     37 	enum scope_class class, const char *label)
     38 {
     39 	// Implements the algorithm described by "Control statements" item 2, or
     40 	// 6.6.48.2 at the time of writing
     41 	while (scope) {
     42 		if (label && scope->label && strcmp(scope->label, label) == 0) {
     43 			break;
     44 		} else if (!label && scope->class == class) {
     45 			break;
     46 		}
     47 		scope = scope->parent;
     48 	}
     49 
     50 	if (scope && class != scope->class) {
     51 		assert(scope->class == SCOPE_COMPOUND);
     52 		scope = scope->parent;
     53 		if (scope->class != class) {
     54 			return NULL;
     55 		}
     56 	}
     57 
     58 	return scope;
     59 }
     60 
     61 void
     62 scope_free(struct scope *scope)
     63 {
     64 	if (!scope) {
     65 		return;
     66 	}
     67 
     68 	struct scope_object *obj = scope->objects;
     69 	while (obj) {
     70 		struct scope_object *next = obj->lnext;
     71 		free(obj);
     72 		obj = next;
     73 	}
     74 
     75 	free(scope);
     76 }
     77 
     78 void
     79 scope_free_all(struct scopes *scopes)
     80 {
     81 	while (scopes) {
     82 		struct scopes *next = scopes->next;
     83 		scope_free(scopes->scope);
     84 		free(scopes);
     85 		scopes = next;
     86 	}
     87 }
     88 
     89 void
     90 scope_object_init(struct scope_object *object, enum object_type otype,
     91 	const struct identifier *ident, const struct identifier *name,
     92 	const struct type *type, struct expression *value)
     93 {
     94 	identifier_dup(&object->ident, ident);
     95 	identifier_dup(&object->name, name);
     96 	object->otype = otype;
     97 	object->type = type;
     98 	object->value = value;
     99 	if (value) {
    100 		assert(otype == O_CONST);
    101 		assert(value->type == EXPR_CONSTANT);
    102 	}
    103 	const_refer(type, &object->type);
    104 }
    105 
    106 void
    107 scope_insert_from_object(struct scope *scope, struct scope_object *object)
    108 {
    109 	// Linked list
    110 	*scope->next = object;
    111 	scope->next = &object->lnext;
    112 
    113 	// Hash map
    114 	uint32_t hash = name_hash(FNV1A_INIT, &object->name);
    115 	struct scope_object **bucket = &scope->buckets[hash % SCOPE_BUCKETS];
    116 	if (*bucket) {
    117 		object->mnext = *bucket;
    118 	}
    119 	*bucket = object;
    120 }
    121 
    122 struct scope_object *
    123 scope_insert(struct scope *scope, enum object_type otype,
    124 	const struct identifier *ident, const struct identifier *name,
    125 	const struct type *type, struct expression *value)
    126 {
    127 	struct scope_object *o = xcalloc(1, sizeof(struct scope_object));
    128 	scope_object_init(o, otype, ident, name, type, value);
    129 	scope_insert_from_object(scope, o);
    130 	return o;
    131 }
    132 
    133 struct scope_object *
    134 scope_lookup(struct scope *scope, const struct identifier *ident)
    135 {
    136 	uint32_t hash = name_hash(FNV1A_INIT, ident);
    137 	struct scope_object *bucket = scope->buckets[hash % SCOPE_BUCKETS];
    138 	while (bucket) {
    139 		if (identifier_eq(&bucket->name, ident)) {
    140 			return bucket;
    141 		}
    142 		bucket = bucket->mnext;
    143 	}
    144 	if (scope->parent) {
    145 		return scope_lookup(scope->parent, ident);
    146 	}
    147 	return NULL;
    148 }