hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

scope.ha (2475B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use hare::ast;
      5 use hare::types;
      6 use hash;
      7 use hash::fnv;
      8 use strings;
      9 
     10 // What sort of [[object]] is represented.
     11 export type object_kind = enum {
     12 	BIND,
     13 	CONST,
     14 	DECL,
     15 	TYPE,
     16 };
     17 
     18 // An object is a named object in a scope, such as a binding, type, or
     19 // declaration.
     20 export type object = struct {
     21 	kind: object_kind,
     22 	hash: u64,
     23 
     24 	// The fully qualified identifier
     25 	ident: ast::ident,
     26 	// Local name, if different from the fully qualified identifier
     27 	name: ast::ident,
     28 
     29 	_type: const *types::_type,
     30 	// TODO: store value for constants
     31 };
     32 
     33 export def SCOPE_BUCKETS: size = 4096;
     34 
     35 // What kind of [[scope]] is represented.
     36 export type scope_class = enum {
     37 	COMPOUND,
     38 	ENUM,
     39 	FUNC,
     40 	LOOP,
     41 	MATCH,
     42 	SUBUNIT,
     43 	UNIT,
     44 };
     45 
     46 // A scope is a member of a hierarchy of storage containers which hold named
     47 // [[object]]s, such as variables or function parameters.
     48 export type scope = struct {
     49 	class: scope_class,
     50 	parent: nullable *scope,
     51 	objects: []object,
     52 	hashmap: [SCOPE_BUCKETS][]*object,
     53 };
     54 
     55 fn scope_push(ctx: *context, class: scope_class) *scope = {
     56 	let new = alloc(scope {
     57 		class = class,
     58 		parent = ctx.scope,
     59 		...
     60 	});
     61 	ctx.scope = new;
     62 	return new;
     63 };
     64 
     65 fn scope_pop(ctx: *context) *scope = {
     66 	const top_scope = ctx.scope;
     67 	ctx.scope = ctx.scope.parent: *scope; // TODO: as *scope
     68 	return top_scope;
     69 };
     70 
     71 fn ident_hash(ident: ast::ident) u64 = {
     72 	let hash = fnv::fnv64a();
     73 	const zerobuf = [0u8];
     74 	for (let i = len(ident); i > 0; i -= 1) {
     75 		hash::write(&hash, strings::toutf8(ident[i - 1]));
     76 		hash::write(&hash, zerobuf[..]);
     77 	};
     78 	return fnv::sum64(&hash);
     79 };
     80 
     81 fn scope_insert(ctx: *context, obj: object) *object = {
     82 	const scope = ctx.scope;
     83 	append(scope.objects, obj);
     84 	let obj = &scope.objects[len(scope.objects) - 1];
     85 	const hash = ident_hash(obj.ident);
     86 	obj.hash = hash;
     87 	append(scope.hashmap[hash: size % SCOPE_BUCKETS], obj);
     88 	return obj;
     89 };
     90 
     91 fn ctx_lookup(ctx: *context, ident: ast::ident) nullable *object =
     92 	scope_lookup(ctx.scope, ident);
     93 
     94 fn scope_lookup(scp: *scope, ident: ast::ident) nullable *object = {
     95 	const hash = ident_hash(ident);
     96 	const bucket = scp.hashmap[hash: size % SCOPE_BUCKETS];
     97 	for (let i = 0z; i < len(bucket); i += 1) {
     98 		if (ast::ident_eq(bucket[i].name, ident)
     99 				|| ast::ident_eq(bucket[i].ident, ident)) {
    100 			return bucket[i];
    101 		};
    102 	};
    103 	match (scp.parent) {
    104 	case null =>
    105 		return null;
    106 	case let s: *scope =>
    107 		return scope_lookup(s, ident);
    108 	};
    109 };