sem.c (7119B)
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "sem.h"
#include "parser.h"
#include "utils.h"
#define CALLOC_SZ 16
#define BASE_DEPTH 1
static int next_id = 100;
Scope
scope_init(Node* node)
{
Scope s = (Scope) { .parent = NULL,
.symbols = (Symbol**)calloc(CALLOC_SZ, sizeof(Symbol*)),
.children = (Scope**)calloc(CALLOC_SZ, sizeof(Scope*)),
.cap = CALLOC_SZ,
.len = 0,
.ch_cap = CALLOC_SZ,
.ch_len = 0,
.depth = BASE_DEPTH,
.owner = node,
.id = next_id++ };
if (s.symbols == NULL) panic_at(node, "scope_init: could not alloc");
if (s.children == NULL) panic_at(node, "scope_init: could not alloc");
return s;
}
static Scope*
new_scope_from_scope(Scope* parent_scope, Node* node)
{
// new scope
Scope* scope = (Scope*)calloc(1, sizeof(Scope));
if (scope == NULL) panic_at(node, "new_scope_from_scope: could not alloc");
scope->id = next_id++;
scope->owner = node;
node->scope = scope;
// init symbols list
scope->symbols = (Symbol**)calloc(CALLOC_SZ, sizeof(Symbol*));
if (scope->symbols == NULL) panic_at(node, "new_scope_from_scope: symbols: could not alloc");
scope->cap = CALLOC_SZ;
scope->len = 0;
scope->children = (Scope**)calloc(CALLOC_SZ, sizeof(Scope*));
if (scope->children == NULL) panic_at(node, "new_scope_from_scope: children: could not alloc");
scope->ch_cap = CALLOC_SZ;
scope->ch_len = 0;
// init parent and depth
if (parent_scope != NULL) {
scope->parent = parent_scope;
scope->depth = parent_scope->depth + 1;
assert(parent_scope->children != NULL);
if (parent_scope->ch_len == parent_scope->ch_cap) {
parent_scope->ch_cap *= 2;
parent_scope->children = (Scope**)realloc(parent_scope->children, parent_scope->ch_cap * sizeof(Scope*));
assert(parent_scope->children != NULL && "realloc failed");
}
parent_scope->children[parent_scope->ch_len++] = scope;
} else {
scope->parent = NULL;
scope->depth = BASE_DEPTH;
}
return scope;
}
static void
add_to_scope(Scope* scope, Symbol* sym)
{
if (scope->len >= scope->cap) {
scope->cap *= 2;
scope->symbols = (Symbol**)realloc(scope->symbols, scope->cap * sizeof(Symbol*));
}
scope->symbols[scope->len++] = sym;
}
static void
scope_var(Scope* scope, Ast* ast, Node* node)
{
const char* var_name = span_str(ast->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 });
const char* type_name = span_str(ast->src, node->data.var_decl.type->data.ident.name, (char[IDENTSZ]) { 0 });
Symbol* sym = (Symbol*)calloc(1, sizeof(Symbol));
if (sym == NULL) panic_at(node, "scope_var: symbol: could not alloc");
TypeInfo* type = (TypeInfo*)calloc(1, sizeof(TypeInfo));
if (type == NULL) panic_at(node, "scope_var: type: could not alloc");
if (strcmp(type_name, "float") == 0) {
type->type = SYMTYPE_FLOAT;
} else if (strcmp(type_name, "int") == 0) {
type->type = SYMTYPE_INT;
} else if (strcmp(type_name, "uint") == 0) {
type->type = SYMTYPE_UINT;
} else if (strcmp(type_name, "str") == 0) {
type->type = SYMTYPE_STR;
} else if (strcmp(type_name, "chr") == 0) {
type->type = SYMTYPE_CHR;
} else if (strcmp(type_name, "bool") == 0) {
type->type = SYMTYPE_BOOL;
} else if (strcmp(type_name, "struct") == 0) {
type->type = SYMTYPE_STRUCT;
} else if (strcmp(type_name, "i8") == 0) {
type->type = SYMTYPE_I8;
} else if (strcmp(type_name, "i16") == 0) {
type->type = SYMTYPE_I16;
} else if (strcmp(type_name, "i32") == 0) {
type->type = SYMTYPE_I32;
} else if (strcmp(type_name, "i64") == 0) {
type->type = SYMTYPE_I64;
} else if (strcmp(type_name, "i128") == 0) {
type->type = SYMTYPE_I128;
} else if (strcmp(type_name, "u8") == 0) {
type->type = SYMTYPE_U8;
} else if (strcmp(type_name, "u16") == 0) {
type->type = SYMTYPE_U16;
} else if (strcmp(type_name, "u32") == 0) {
type->type = SYMTYPE_U32;
} else if (strcmp(type_name, "u64") == 0) {
type->type = SYMTYPE_U64;
} else if (strcmp(type_name, "u128") == 0) {
type->type = SYMTYPE_U128;
} else if (strcmp(type_name, "f32") == 0) {
type->type = SYMTYPE_F32;
} else if (strcmp(type_name, "f64") == 0) {
type->type = SYMTYPE_F64;
} else if (strcmp(type_name, "f128") == 0) {
type->type = SYMTYPE_F128;
} else {
if (type_name[0] >= 'A' && type_name[0] <= 'Z') {
type->type = SYMTYPE_USER;
} else {
panic_at(node, "sem: not yet defined type '%s' for variable '%s'", type_name, var_name);
}
}
sym->name = node->data.var_decl.name;
sym->decl = node->data.var_decl.init;
sym->type = type;
printf("scope_var: adding to scope %s (%s)\n", var_name, type_name);
add_to_scope(scope, sym);
}
static void
scope_func(Scope* parent_scope, Ast* ast, Node* node)
{
Scope* scope = new_scope_from_scope(parent_scope, node);
node->scope = scope;
for (size_t i = 0; i < node->data.block.len; i++) {
Node* stmt = node->data.block.stmts[i];
stmt->scope = scope;
switch (stmt->type) {
case NODE_VAR_DECL: {
scope_var(scope, ast, stmt);
break;
}
default:
continue;
}
}
}
void
scope_program(Scope* scope, Ast* ast)
{
for (size_t i = 0; i < ast->node->data.program.len; i++) {
Node* node = ast->node->data.program.decl[i];
node->scope = scope;
switch (node->type) {
case NODE_VAR_DECL:
scope_var(scope, ast, node);
break;
case NODE_FUNCTION_DECL:
scope_func(/*parent_scope*/ scope, ast, node->data.function_decl.body);
break;
default:
printf("unknown definition at TODO\n");
}
}
}
void
scope_print(Scope* scope, Ast* ast)
{
if (scope == NULL || scope->symbols == NULL) return;
for (size_t i = 0; i < scope->len; i++) {
Symbol* sym = scope->symbols[i];
const char* name = span_str(ast->src, sym->name, (char[IDENTSZ]) { 0 });
int parent = -1;
if (scope->parent != NULL) parent = scope->parent->id;
bool has_owner_node = false;
if (scope->owner != NULL) has_owner_node = true;
printf("[depth %d] [id %d] Symbol name `%s` \t of type %s (parent %d, owner %s)\n",
scope->depth,
scope->id,
name,
type_kind_str(sym->type->type),
parent,
has_owner_node ? "yes" : "no");
}
if (scope->ch_len == 0) return;
for (size_t j = 0; j < scope->ch_len; j++) {
Scope* child_scope = scope->children[j];
scope_print(child_scope, ast);
}
}
const char*
type_kind_str(SymbolType t)
{
static const char* type_strings[] = {
[SYMTYPE_VOID] = "TYPE_VOID",
[SYMTYPE_INT] = "TYPE_INT",
[SYMTYPE_I8] = "TYPE_I8",
[SYMTYPE_I16] = "TYPE_I16",
[SYMTYPE_I32] = "TYPE_I32",
[SYMTYPE_I64] = "TYPE_I64",
[SYMTYPE_I128] = "TYPE_I128",
[SYMTYPE_UINT] = "TYPE_UINT",
[SYMTYPE_U8] = "TYPE_U8",
[SYMTYPE_U16] = "TYPE_U16",
[SYMTYPE_U32] = "TYPE_U32",
[SYMTYPE_U64] = "TYPE_U64",
[SYMTYPE_U128] = "TYPE_U128",
[SYMTYPE_F32] = "TYPE_F32",
[SYMTYPE_F64] = "TYPE_F64",
[SYMTYPE_F128] = "TYPE_F128",
[SYMTYPE_FLOAT] = "TYPE_FLOAT",
[SYMTYPE_STR] = "TYPE_STR",
[SYMTYPE_CHR] = "TYPE_CHR",
[SYMTYPE_BOOL] = "TYPE_BOOL",
[SYMTYPE_STRUCT] = "TYPE_STRUCT",
[SYMTYPE_USER] = "TYPE_USER",
[SYMTYPE_FUNC] = "TYPE_FUNC",
[SYMTYPE_TODO] = "TYPE_TODO",
};
return (t >= SYMTYPE_VOID && t <= SYMTYPE_TODO) ? type_strings[t] : "UNKNOWN_TYPE_KIND";
}