harec

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

scope.c (3150B)


      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 	}
     54 
     55 	return scope;
     56 }
     57 
     58 void
     59 scope_free(struct scope *scope)
     60 {
     61 	if (!scope) {
     62 		return;
     63 	}
     64 
     65 	struct scope_object *obj = scope->objects;
     66 	while (obj) {
     67 		struct scope_object *next = obj->lnext;
     68 		free(obj);
     69 		obj = next;
     70 	}
     71 
     72 	free(scope);
     73 }
     74 
     75 void
     76 scope_free_all(struct scopes *scopes)
     77 {
     78 	while (scopes) {
     79 		struct scopes *next = scopes->next;
     80 		scope_free(scopes->scope);
     81 		free(scopes);
     82 		scopes = next;
     83 	}
     84 }
     85 
     86 void
     87 scope_object_init(struct scope_object *object, enum object_type otype,
     88 	const struct identifier *ident, const struct identifier *name,
     89 	const struct type *type, struct expression *value)
     90 {
     91 	identifier_dup(&object->ident, ident);
     92 	identifier_dup(&object->name, name);
     93 	object->otype = otype;
     94 	object->type = type;
     95 	object->value = value;
     96 	if (value) {
     97 		assert(otype == O_CONST);
     98 		assert(value->type == EXPR_CONSTANT);
     99 	}
    100 	const_refer(type, &object->type);
    101 }
    102 
    103 void
    104 scope_insert_from_object(struct scope *scope, struct scope_object *object)
    105 {
    106 	// Linked list
    107 	*scope->next = object;
    108 	scope->next = &object->lnext;
    109 
    110 	// Hash map
    111 	uint32_t hash = name_hash(FNV1A_INIT, &object->name);
    112 	struct scope_object **bucket = &scope->buckets[hash % SCOPE_BUCKETS];
    113 	if (*bucket) {
    114 		object->mnext = *bucket;
    115 	}
    116 	*bucket = object;
    117 }
    118 
    119 const struct scope_object *
    120 scope_insert(struct scope *scope, enum object_type otype,
    121 	const struct identifier *ident, const struct identifier *name,
    122 	const struct type *type, struct expression *value)
    123 {
    124 	struct scope_object *o = xcalloc(1, sizeof(struct scope_object));
    125 	scope_object_init(o, otype, ident, name, type, value);
    126 	scope_insert_from_object(scope, o);
    127 	return o;
    128 }
    129 
    130 const struct scope_object *
    131 scope_lookup(struct scope *scope, const struct identifier *ident)
    132 {
    133 	uint32_t hash = name_hash(FNV1A_INIT, ident);
    134 	struct scope_object *bucket = scope->buckets[hash % SCOPE_BUCKETS];
    135 	while (bucket) {
    136 		if (identifier_eq(&bucket->name, ident)) {
    137 			return bucket;
    138 		}
    139 		bucket = bucket->mnext;
    140 	}
    141 	if (scope->parent) {
    142 		return scope_lookup(scope->parent, ident);
    143 	}
    144 	return NULL;
    145 }