feat: add initial plot.py module with beast visualization logic
This commit introduces the core plotting module for the beast project, including the initial implementation of data visualization functions and chart generation utilities. The module provides the foundational structure for rendering beast-related metrics and graphical outputs.
This commit is contained in:
@@ -0,0 +1,462 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "semantic.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void _rava_semantic_error(RavaSemanticAnalyzer_t *analyzer, const char *message, int line, int col);
|
||||
static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *node);
|
||||
static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr);
|
||||
|
||||
RavaSemanticAnalyzer_t* rava_semantic_analyzer_create() {
|
||||
RavaSemanticAnalyzer_t *analyzer = calloc(1, sizeof(RavaSemanticAnalyzer_t));
|
||||
analyzer->symbol_table = rava_symbol_table_create();
|
||||
analyzer->error_message = NULL;
|
||||
analyzer->had_error = false;
|
||||
analyzer->error_count = 0;
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
void rava_semantic_analyzer_destroy(RavaSemanticAnalyzer_t *analyzer) {
|
||||
if (!analyzer) return;
|
||||
rava_symbol_table_destroy(analyzer->symbol_table);
|
||||
free(analyzer->error_message);
|
||||
free(analyzer);
|
||||
}
|
||||
|
||||
static void _rava_semantic_error(RavaSemanticAnalyzer_t *analyzer, const char *message, int line, int col) {
|
||||
analyzer->had_error = true;
|
||||
analyzer->error_count++;
|
||||
|
||||
if (analyzer->error_message) free(analyzer->error_message);
|
||||
analyzer->error_message = malloc(512);
|
||||
snprintf(analyzer->error_message, 512, "Semantic error at line %d, column %d: %s",
|
||||
line, col, message);
|
||||
}
|
||||
|
||||
static RavaType_t* _rava_semantic_resolve_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *type_node) {
|
||||
(void)analyzer;
|
||||
if (!type_node || type_node->type != RAVA_AST_TYPE) return NULL;
|
||||
|
||||
RavaType_t *base_type = rava_type_from_name(type_node->data.type.type_name);
|
||||
|
||||
if (type_node->data.type.is_array) {
|
||||
return rava_type_create_array(base_type, type_node->data.type.array_dimensions);
|
||||
}
|
||||
|
||||
return base_type;
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_class(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *class_node) {
|
||||
if (class_node->type != RAVA_AST_CLASS_DECL) return false;
|
||||
|
||||
char *class_name = class_node->data.class_decl.name;
|
||||
RavaType_t *class_type = rava_type_create_class(class_name);
|
||||
|
||||
RavaSymbol_t *class_symbol = rava_symbol_create(RAVA_SYMBOL_CLASS, class_name, class_type);
|
||||
class_symbol->modifiers = class_node->data.class_decl.modifiers;
|
||||
class_symbol->modifiers_count = class_node->data.class_decl.modifiers_count;
|
||||
class_symbol->declaration = class_node;
|
||||
|
||||
if (!rava_symbol_table_define(analyzer->symbol_table, class_symbol)) {
|
||||
_rava_semantic_error(analyzer, "Class already defined", class_node->line, class_node->column);
|
||||
rava_symbol_destroy(class_symbol);
|
||||
return false;
|
||||
}
|
||||
|
||||
rava_symbol_table_enter_scope(analyzer->symbol_table, class_name);
|
||||
|
||||
for (size_t i = 0; i < class_node->children_count; i++) {
|
||||
_rava_semantic_analyze_node(analyzer, class_node->children[i]);
|
||||
}
|
||||
|
||||
rava_symbol_table_exit_scope(analyzer->symbol_table);
|
||||
|
||||
return !analyzer->had_error;
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_method(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *method_node) {
|
||||
if (method_node->type != RAVA_AST_METHOD_DECL) return false;
|
||||
|
||||
char *method_name = method_node->data.method_decl.name;
|
||||
RavaType_t *return_type = _rava_semantic_resolve_type(analyzer, method_node->data.method_decl.return_type);
|
||||
|
||||
RavaSymbol_t *method_symbol = rava_symbol_create(RAVA_SYMBOL_METHOD, method_name, return_type);
|
||||
method_symbol->modifiers = method_node->data.method_decl.modifiers;
|
||||
method_symbol->modifiers_count = method_node->data.method_decl.modifiers_count;
|
||||
method_symbol->declaration = method_node;
|
||||
|
||||
if (!rava_symbol_table_define(analyzer->symbol_table, method_symbol)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Method '%s' already defined", method_name);
|
||||
_rava_semantic_error(analyzer, error_msg, method_node->line, method_node->column);
|
||||
rava_symbol_destroy(method_symbol);
|
||||
return false;
|
||||
}
|
||||
|
||||
rava_symbol_table_enter_scope(analyzer->symbol_table, method_name);
|
||||
|
||||
for (size_t i = 0; i < method_node->children_count; i++) {
|
||||
RavaASTNode_t *child = method_node->children[i];
|
||||
|
||||
if (child->type == RAVA_AST_PARAM_DECL) {
|
||||
char *param_name = child->data.var_decl.name;
|
||||
RavaType_t *param_type = _rava_semantic_resolve_type(analyzer, child->data.var_decl.type);
|
||||
|
||||
RavaSymbol_t *param_symbol = rava_symbol_create(RAVA_SYMBOL_PARAMETER, param_name, param_type);
|
||||
param_symbol->declaration = child;
|
||||
|
||||
if (!rava_symbol_table_define(analyzer->symbol_table, param_symbol)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Parameter '%s' already defined", param_name);
|
||||
_rava_semantic_error(analyzer, error_msg, child->line, child->column);
|
||||
rava_symbol_destroy(param_symbol);
|
||||
}
|
||||
} else if (child->type == RAVA_AST_BLOCK_STMT) {
|
||||
_rava_semantic_analyze_node(analyzer, child);
|
||||
}
|
||||
}
|
||||
|
||||
rava_symbol_table_exit_scope(analyzer->symbol_table);
|
||||
|
||||
return !analyzer->had_error;
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_field(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *field_node) {
|
||||
if (field_node->type != RAVA_AST_FIELD_DECL) return false;
|
||||
|
||||
char *field_name = field_node->data.var_decl.name;
|
||||
RavaType_t *field_type = _rava_semantic_resolve_type(analyzer, field_node->data.var_decl.type);
|
||||
|
||||
RavaSymbol_t *field_symbol = rava_symbol_create(RAVA_SYMBOL_FIELD, field_name, field_type);
|
||||
field_symbol->declaration = field_node;
|
||||
|
||||
if (!rava_symbol_table_define(analyzer->symbol_table, field_symbol)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Field '%s' already defined", field_name);
|
||||
_rava_semantic_error(analyzer, error_msg, field_node->line, field_node->column);
|
||||
rava_symbol_destroy(field_symbol);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (field_node->data.var_decl.initializer) {
|
||||
RavaType_t *init_type = _rava_semantic_check_expression(analyzer, field_node->data.var_decl.initializer);
|
||||
if (init_type && !rava_type_is_assignable_to(init_type, field_type)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg),
|
||||
"Cannot assign '%s' to field of type '%s'",
|
||||
rava_type_to_string(init_type),
|
||||
rava_type_to_string(field_type));
|
||||
_rava_semantic_error(analyzer, error_msg, field_node->line, field_node->column);
|
||||
}
|
||||
}
|
||||
|
||||
return !analyzer->had_error;
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_var_decl(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *var_node) {
|
||||
if (var_node->type != RAVA_AST_VAR_DECL) return false;
|
||||
|
||||
char *var_name = var_node->data.var_decl.name;
|
||||
RavaType_t *var_type = _rava_semantic_resolve_type(analyzer, var_node->data.var_decl.type);
|
||||
|
||||
RavaSymbol_t *var_symbol = rava_symbol_create(RAVA_SYMBOL_VARIABLE, var_name, var_type);
|
||||
var_symbol->declaration = var_node;
|
||||
|
||||
if (!rava_symbol_table_define(analyzer->symbol_table, var_symbol)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Variable '%s' already defined", var_name);
|
||||
_rava_semantic_error(analyzer, error_msg, var_node->line, var_node->column);
|
||||
rava_symbol_destroy(var_symbol);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (var_node->data.var_decl.initializer) {
|
||||
RavaType_t *init_type = _rava_semantic_check_expression(analyzer, var_node->data.var_decl.initializer);
|
||||
if (init_type && !rava_type_is_assignable_to(init_type, var_type)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg),
|
||||
"Cannot assign '%s' to variable of type '%s'",
|
||||
rava_type_to_string(init_type),
|
||||
rava_type_to_string(var_type));
|
||||
_rava_semantic_error(analyzer, error_msg, var_node->line, var_node->column);
|
||||
}
|
||||
}
|
||||
|
||||
return !analyzer->had_error;
|
||||
}
|
||||
|
||||
static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr) {
|
||||
if (!expr) return NULL;
|
||||
|
||||
switch (expr->type) {
|
||||
case RAVA_AST_LITERAL_EXPR: {
|
||||
switch (expr->data.literal.literal_type) {
|
||||
case RAVA_TOKEN_LITERAL_INTEGER:
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
case RAVA_TOKEN_LITERAL_LONG:
|
||||
return rava_type_create_primitive(RAVA_TYPE_LONG);
|
||||
case RAVA_TOKEN_LITERAL_FLOAT:
|
||||
return rava_type_create_primitive(RAVA_TYPE_FLOAT);
|
||||
case RAVA_TOKEN_LITERAL_DOUBLE:
|
||||
return rava_type_create_primitive(RAVA_TYPE_DOUBLE);
|
||||
case RAVA_TOKEN_LITERAL_STRING:
|
||||
return rava_type_create_class("String");
|
||||
case RAVA_TOKEN_LITERAL_CHARACTER:
|
||||
return rava_type_create_primitive(RAVA_TYPE_CHAR);
|
||||
case RAVA_TOKEN_LITERAL_TRUE:
|
||||
case RAVA_TOKEN_LITERAL_FALSE:
|
||||
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
|
||||
case RAVA_TOKEN_LITERAL_NULL:
|
||||
return rava_type_create_primitive(RAVA_TYPE_NULL);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
case RAVA_AST_IDENTIFIER_EXPR: {
|
||||
char *name = expr->data.identifier.name;
|
||||
|
||||
if (strcmp(name, "System") == 0) {
|
||||
return rava_type_from_name("System");
|
||||
}
|
||||
if (strcmp(name, "Files") == 0) {
|
||||
return rava_type_from_name("Files");
|
||||
}
|
||||
|
||||
RavaSymbol_t *symbol = rava_symbol_table_resolve(analyzer->symbol_table, name);
|
||||
if (!symbol) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Undefined identifier '%s'", name);
|
||||
_rava_semantic_error(analyzer, error_msg, expr->line, expr->column);
|
||||
return NULL;
|
||||
}
|
||||
return symbol->type;
|
||||
}
|
||||
|
||||
case RAVA_AST_BINARY_EXPR: {
|
||||
RavaType_t *left_type = _rava_semantic_check_expression(analyzer, expr->data.binary.left);
|
||||
RavaType_t *right_type = _rava_semantic_check_expression(analyzer, expr->data.binary.right);
|
||||
|
||||
if (!left_type || !right_type) return NULL;
|
||||
|
||||
if (expr->data.binary.op >= RAVA_BINOP_EQ && expr->data.binary.op <= RAVA_BINOP_GE) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
if (expr->data.binary.op == RAVA_BINOP_AND || expr->data.binary.op == RAVA_BINOP_OR) {
|
||||
if (left_type->kind != RAVA_TYPE_BOOLEAN || right_type->kind != RAVA_TYPE_BOOLEAN) {
|
||||
_rava_semantic_error(analyzer, "Logical operators require boolean operands",
|
||||
expr->line, expr->column);
|
||||
return NULL;
|
||||
}
|
||||
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
return rava_type_binary_result(left_type, right_type);
|
||||
}
|
||||
|
||||
case RAVA_AST_UNARY_EXPR: {
|
||||
return _rava_semantic_check_expression(analyzer, expr->data.unary.operand);
|
||||
}
|
||||
|
||||
case RAVA_AST_ASSIGN_EXPR: {
|
||||
RavaType_t *target_type = _rava_semantic_check_expression(analyzer, expr->data.assign.target);
|
||||
RavaType_t *value_type = _rava_semantic_check_expression(analyzer, expr->data.assign.value);
|
||||
|
||||
if (target_type && value_type && !rava_type_is_assignable_to(value_type, target_type)) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg),
|
||||
"Cannot assign '%s' to '%s'",
|
||||
rava_type_to_string(value_type),
|
||||
rava_type_to_string(target_type));
|
||||
_rava_semantic_error(analyzer, error_msg, expr->line, expr->column);
|
||||
}
|
||||
|
||||
return target_type;
|
||||
}
|
||||
|
||||
case RAVA_AST_CALL_EXPR: {
|
||||
_rava_semantic_check_expression(analyzer, expr->data.call.callee);
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_semantic_check_expression(analyzer, expr->data.call.arguments[i]);
|
||||
}
|
||||
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
RavaASTNode_t *member = expr->data.call.callee;
|
||||
const char *method = member->data.member_access.member;
|
||||
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
||||
strcmp(member->data.member_access.object->data.identifier.name, "Files") == 0) {
|
||||
if (strcmp(method, "read") == 0) {
|
||||
return rava_type_create_class("String");
|
||||
} else if (strcmp(method, "write") == 0 || strcmp(method, "exists") == 0 ||
|
||||
strcmp(method, "delete") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
||||
strcmp(member->data.member_access.object->data.identifier.name, "System") == 0) {
|
||||
if (strcmp(method, "currentTimeMillis") == 0 || strcmp(method, "nanoTime") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_LONG);
|
||||
}
|
||||
}
|
||||
if (strcmp(method, "length") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
} else if (strcmp(method, "charAt") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_CHAR);
|
||||
} else if (strcmp(method, "equals") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
|
||||
} else if (strcmp(method, "compareTo") == 0) {
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
}
|
||||
}
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
}
|
||||
|
||||
case RAVA_AST_MEMBER_ACCESS_EXPR: {
|
||||
_rava_semantic_check_expression(analyzer, expr->data.member_access.object);
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
}
|
||||
|
||||
case RAVA_AST_ARRAY_ACCESS_EXPR: {
|
||||
RavaType_t *array_type = _rava_semantic_check_expression(analyzer, expr->data.array_access.array);
|
||||
RavaType_t *index_type = _rava_semantic_check_expression(analyzer, expr->data.array_access.index);
|
||||
|
||||
if (index_type && index_type->kind != RAVA_TYPE_INT && index_type->kind != RAVA_TYPE_LONG) {
|
||||
_rava_semantic_error(analyzer, "Array index must be an integer", expr->line, expr->column);
|
||||
}
|
||||
|
||||
if (array_type && array_type->kind == RAVA_TYPE_ARRAY) {
|
||||
return array_type->data.array.element_type;
|
||||
}
|
||||
return rava_type_create_primitive(RAVA_TYPE_INT);
|
||||
}
|
||||
|
||||
case RAVA_AST_NEW_EXPR: {
|
||||
RavaType_t *type = _rava_semantic_resolve_type(analyzer, expr->data.new_expr.type);
|
||||
|
||||
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
|
||||
RavaType_t *arg_type = _rava_semantic_check_expression(analyzer, expr->data.new_expr.arguments[i]);
|
||||
if (type && type->kind == RAVA_TYPE_ARRAY && arg_type) {
|
||||
if (arg_type->kind != RAVA_TYPE_INT && arg_type->kind != RAVA_TYPE_LONG) {
|
||||
_rava_semantic_error(analyzer, "Array size must be an integer", expr->line, expr->column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_statement(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *stmt) {
|
||||
if (!stmt) return true;
|
||||
|
||||
switch (stmt->type) {
|
||||
case RAVA_AST_BLOCK_STMT:
|
||||
for (size_t i = 0; i < stmt->children_count; i++) {
|
||||
_rava_semantic_analyze_node(analyzer, stmt->children[i]);
|
||||
}
|
||||
return true;
|
||||
|
||||
case RAVA_AST_IF_STMT: {
|
||||
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.if_stmt.condition);
|
||||
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
|
||||
_rava_semantic_error(analyzer, "If condition must be boolean", stmt->line, stmt->column);
|
||||
}
|
||||
_rava_semantic_analyze_node(analyzer, stmt->data.if_stmt.then_stmt);
|
||||
if (stmt->data.if_stmt.else_stmt) {
|
||||
_rava_semantic_analyze_node(analyzer, stmt->data.if_stmt.else_stmt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case RAVA_AST_WHILE_STMT: {
|
||||
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.while_stmt.condition);
|
||||
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
|
||||
_rava_semantic_error(analyzer, "While condition must be boolean", stmt->line, stmt->column);
|
||||
}
|
||||
_rava_semantic_analyze_node(analyzer, stmt->data.while_stmt.body);
|
||||
return true;
|
||||
}
|
||||
|
||||
case RAVA_AST_FOR_STMT:
|
||||
if (stmt->data.for_stmt.init) {
|
||||
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
|
||||
_rava_semantic_analyze_node(analyzer, stmt->data.for_stmt.init);
|
||||
} else {
|
||||
_rava_semantic_check_expression(analyzer, stmt->data.for_stmt.init);
|
||||
}
|
||||
}
|
||||
if (stmt->data.for_stmt.condition) {
|
||||
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.for_stmt.condition);
|
||||
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
|
||||
_rava_semantic_error(analyzer, "For condition must be boolean", stmt->line, stmt->column);
|
||||
}
|
||||
}
|
||||
if (stmt->data.for_stmt.update) {
|
||||
_rava_semantic_check_expression(analyzer, stmt->data.for_stmt.update);
|
||||
}
|
||||
_rava_semantic_analyze_node(analyzer, stmt->data.for_stmt.body);
|
||||
return true;
|
||||
|
||||
case RAVA_AST_RETURN_STMT:
|
||||
if (stmt->data.return_stmt.value) {
|
||||
_rava_semantic_check_expression(analyzer, stmt->data.return_stmt.value);
|
||||
}
|
||||
return true;
|
||||
|
||||
case RAVA_AST_EXPR_STMT:
|
||||
if (stmt->children_count > 0) {
|
||||
_rava_semantic_check_expression(analyzer, stmt->children[0]);
|
||||
}
|
||||
return true;
|
||||
|
||||
case RAVA_AST_VAR_DECL:
|
||||
return _rava_semantic_analyze_var_decl(analyzer, stmt);
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *node) {
|
||||
if (!node) return true;
|
||||
|
||||
switch (node->type) {
|
||||
case RAVA_AST_COMPILATION_UNIT:
|
||||
for (size_t i = 0; i < node->children_count; i++) {
|
||||
_rava_semantic_analyze_node(analyzer, node->children[i]);
|
||||
}
|
||||
return true;
|
||||
|
||||
case RAVA_AST_CLASS_DECL:
|
||||
return _rava_semantic_analyze_class(analyzer, node);
|
||||
|
||||
case RAVA_AST_METHOD_DECL:
|
||||
return _rava_semantic_analyze_method(analyzer, node);
|
||||
|
||||
case RAVA_AST_FIELD_DECL:
|
||||
return _rava_semantic_analyze_field(analyzer, node);
|
||||
|
||||
case RAVA_AST_CONSTRUCTOR_DECL:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return _rava_semantic_analyze_statement(analyzer, node);
|
||||
}
|
||||
}
|
||||
|
||||
bool rava_semantic_analyze(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *root) {
|
||||
if (!analyzer || !root) return false;
|
||||
|
||||
_rava_semantic_analyze_node(analyzer, root);
|
||||
|
||||
return !analyzer->had_error;
|
||||
}
|
||||
|
||||
RavaType_t* rava_semantic_get_expression_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr) {
|
||||
return _rava_semantic_check_expression(analyzer, expr);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef RAVA_SEMANTIC_H
|
||||
#define RAVA_SEMANTIC_H
|
||||
|
||||
#include "../parser/parser.h"
|
||||
#include "../types/types.h"
|
||||
#include "symbol_table.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
RavaSymbolTable_t *symbol_table;
|
||||
char *error_message;
|
||||
bool had_error;
|
||||
int error_count;
|
||||
} RavaSemanticAnalyzer_t;
|
||||
|
||||
RavaSemanticAnalyzer_t* rava_semantic_analyzer_create();
|
||||
void rava_semantic_analyzer_destroy(RavaSemanticAnalyzer_t *analyzer);
|
||||
|
||||
bool rava_semantic_analyze(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *root);
|
||||
|
||||
RavaType_t* rava_semantic_get_expression_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "symbol_table.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
RavaSymbolTable_t* rava_symbol_table_create() {
|
||||
RavaSymbolTable_t *table = malloc(sizeof(RavaSymbolTable_t));
|
||||
table->global_scope = rava_scope_create("global", NULL);
|
||||
table->current_scope = table->global_scope;
|
||||
return table;
|
||||
}
|
||||
|
||||
void rava_symbol_table_destroy(RavaSymbolTable_t *table) {
|
||||
if (!table) return;
|
||||
rava_scope_destroy(table->global_scope);
|
||||
free(table);
|
||||
}
|
||||
|
||||
RavaScope_t* rava_scope_create(const char *name, RavaScope_t *parent) {
|
||||
RavaScope_t *scope = calloc(1, sizeof(RavaScope_t));
|
||||
scope->name = strdup(name);
|
||||
scope->symbols = NULL;
|
||||
scope->parent = parent;
|
||||
scope->children = NULL;
|
||||
scope->children_count = 0;
|
||||
scope->children_capacity = 0;
|
||||
return scope;
|
||||
}
|
||||
|
||||
void rava_scope_destroy(RavaScope_t *scope) {
|
||||
if (!scope) return;
|
||||
|
||||
free(scope->name);
|
||||
|
||||
RavaSymbol_t *symbol = scope->symbols;
|
||||
while (symbol) {
|
||||
RavaSymbol_t *next = symbol->next;
|
||||
rava_symbol_destroy(symbol);
|
||||
symbol = next;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scope->children_count; i++) {
|
||||
rava_scope_destroy(scope->children[i]);
|
||||
}
|
||||
free(scope->children);
|
||||
|
||||
free(scope);
|
||||
}
|
||||
|
||||
void rava_symbol_table_enter_scope(RavaSymbolTable_t *table, const char *scope_name) {
|
||||
RavaScope_t *new_scope = rava_scope_create(scope_name, table->current_scope);
|
||||
|
||||
if (table->current_scope->children_count >= table->current_scope->children_capacity) {
|
||||
size_t new_capacity = table->current_scope->children_capacity == 0 ? 4 :
|
||||
table->current_scope->children_capacity * 2;
|
||||
table->current_scope->children = realloc(table->current_scope->children,
|
||||
sizeof(RavaScope_t*) * new_capacity);
|
||||
table->current_scope->children_capacity = new_capacity;
|
||||
}
|
||||
|
||||
table->current_scope->children[table->current_scope->children_count++] = new_scope;
|
||||
table->current_scope = new_scope;
|
||||
}
|
||||
|
||||
void rava_symbol_table_exit_scope(RavaSymbolTable_t *table) {
|
||||
if (table->current_scope->parent) {
|
||||
table->current_scope = table->current_scope->parent;
|
||||
}
|
||||
}
|
||||
|
||||
RavaSymbol_t* rava_symbol_create(RavaSymbolKind_e kind, const char *name, RavaType_t *type) {
|
||||
RavaSymbol_t *symbol = calloc(1, sizeof(RavaSymbol_t));
|
||||
symbol->kind = kind;
|
||||
symbol->name = strdup(name);
|
||||
symbol->type = type;
|
||||
symbol->modifiers = NULL;
|
||||
symbol->modifiers_count = 0;
|
||||
symbol->declaration = NULL;
|
||||
symbol->next = NULL;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
void rava_symbol_destroy(RavaSymbol_t *symbol) {
|
||||
if (!symbol) return;
|
||||
free(symbol->name);
|
||||
rava_type_destroy(symbol->type);
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
bool rava_symbol_table_define(RavaSymbolTable_t *table, RavaSymbol_t *symbol) {
|
||||
if (!table || !symbol) return false;
|
||||
|
||||
if (rava_symbol_table_resolve_in_scope(table->current_scope, symbol->name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
symbol->next = table->current_scope->symbols;
|
||||
table->current_scope->symbols = symbol;
|
||||
return true;
|
||||
}
|
||||
|
||||
RavaSymbol_t* rava_symbol_table_resolve(RavaSymbolTable_t *table, const char *name) {
|
||||
if (!table || !name) return NULL;
|
||||
|
||||
RavaScope_t *scope = table->current_scope;
|
||||
while (scope) {
|
||||
RavaSymbol_t *symbol = rava_symbol_table_resolve_in_scope(scope, name);
|
||||
if (symbol) return symbol;
|
||||
scope = scope->parent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RavaSymbol_t* rava_symbol_table_resolve_in_scope(RavaScope_t *scope, const char *name) {
|
||||
if (!scope || !name) return NULL;
|
||||
|
||||
RavaSymbol_t *symbol = scope->symbols;
|
||||
while (symbol) {
|
||||
if (strcmp(symbol->name, name) == 0) {
|
||||
return symbol;
|
||||
}
|
||||
symbol = symbol->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool rava_symbol_has_modifier(RavaSymbol_t *symbol, RavaModifier_e modifier) {
|
||||
if (!symbol) return false;
|
||||
|
||||
for (size_t i = 0; i < symbol->modifiers_count; i++) {
|
||||
if (symbol->modifiers[i] == modifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef RAVA_SYMBOL_TABLE_H
|
||||
#define RAVA_SYMBOL_TABLE_H
|
||||
|
||||
#include "../types/types.h"
|
||||
#include "../parser/parser.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
RAVA_SYMBOL_CLASS,
|
||||
RAVA_SYMBOL_METHOD,
|
||||
RAVA_SYMBOL_FIELD,
|
||||
RAVA_SYMBOL_VARIABLE,
|
||||
RAVA_SYMBOL_PARAMETER
|
||||
} RavaSymbolKind_e;
|
||||
|
||||
typedef struct RavaSymbol_t {
|
||||
RavaSymbolKind_e kind;
|
||||
char *name;
|
||||
RavaType_t *type;
|
||||
RavaModifier_e *modifiers;
|
||||
size_t modifiers_count;
|
||||
RavaASTNode_t *declaration;
|
||||
size_t local_index;
|
||||
|
||||
struct RavaSymbol_t *next;
|
||||
} RavaSymbol_t;
|
||||
|
||||
typedef struct RavaScope_t {
|
||||
char *name;
|
||||
RavaSymbol_t *symbols;
|
||||
struct RavaScope_t *parent;
|
||||
struct RavaScope_t **children;
|
||||
size_t children_count;
|
||||
size_t children_capacity;
|
||||
} RavaScope_t;
|
||||
|
||||
typedef struct {
|
||||
RavaScope_t *global_scope;
|
||||
RavaScope_t *current_scope;
|
||||
} RavaSymbolTable_t;
|
||||
|
||||
RavaSymbolTable_t* rava_symbol_table_create();
|
||||
void rava_symbol_table_destroy(RavaSymbolTable_t *table);
|
||||
|
||||
RavaScope_t* rava_scope_create(const char *name, RavaScope_t *parent);
|
||||
void rava_scope_destroy(RavaScope_t *scope);
|
||||
|
||||
void rava_symbol_table_enter_scope(RavaSymbolTable_t *table, const char *scope_name);
|
||||
void rava_symbol_table_exit_scope(RavaSymbolTable_t *table);
|
||||
|
||||
RavaSymbol_t* rava_symbol_create(RavaSymbolKind_e kind, const char *name, RavaType_t *type);
|
||||
void rava_symbol_destroy(RavaSymbol_t *symbol);
|
||||
|
||||
bool rava_symbol_table_define(RavaSymbolTable_t *table, RavaSymbol_t *symbol);
|
||||
RavaSymbol_t* rava_symbol_table_resolve(RavaSymbolTable_t *table, const char *name);
|
||||
RavaSymbol_t* rava_symbol_table_resolve_in_scope(RavaScope_t *scope, const char *name);
|
||||
|
||||
bool rava_symbol_has_modifier(RavaSymbol_t *symbol, RavaModifier_e modifier);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user