feat(ast): 将AST上下文重构为模块并添加字符串池支持
- 将scc_ast_ctx重命名为scc_ast_module以更好地反映其功能 - 添加scc_strpool_t用于统一管理AST节点名称字符串的生命周期 - 实现scc_ast_module_intern函数用于字符串驻留 - 更新所有相关的初始化、销毁和访问函数命名 - 修改内存分配宏以使用新的模块结构 refactor(parser): 更新解析器以使用AST模块和字符串池 - 将解析器中的ast_ctx字段替换为ast_module - 在创建AST节点时使用新的ast_module参数 - 使用scc_ast_module_intern函数处理标识符和字符串字面量 - 确保所有字符串都被正确驻留到模块的字符串池中 refactor(sema): 更新语义分析器使用AST模块 - 将sema_ctx中的ast_ctx字段替换为ast_module - 更新语义分析器初始化函数参数 refactor(ast2ir): 更新AST到IR转换器使用AST模块 - 将ast_ctx字段替换为ast_module - 更新上下文初始化函数参数和实现 fix(cfg): 修复CFG模块中的符号查找错误 - 修正scc_cfg_module_unsafe_get_symbol函数中的边界检查条件 perf(ir): 完善各IR层模块的内存清理机制 - 为HIR模块添加函数和基本块元数据的释放逻辑 - 为MIR和LIR模块完善完整的资源清理和内存释放 - 确保所有分配的元数据结构都能被正确释放 chore(deps): 添加scc_utils依赖到AST库 - 在libs/ast/cbuild.toml中添加对scc_utils的依赖
This commit is contained in:
@@ -240,7 +240,14 @@ static inline char *scc_str_move_cstr(scc_str_t *str) {
|
||||
}
|
||||
|
||||
static inline scc_str_t scc_str_move(scc_str_t *str) {
|
||||
return scc_str_from_cstr(scc_str_move_cstr(str));
|
||||
if (str == nullptr || str->data == nullptr) {
|
||||
return scc_str_empty();
|
||||
}
|
||||
scc_str_t result = *str;
|
||||
str->data = nullptr;
|
||||
str->cap = 0;
|
||||
str->size = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __SCC_CORE_STR_H__ */
|
||||
|
||||
@@ -106,7 +106,7 @@ typedef size_t usize;
|
||||
#define scc_vec_push(vec, value) \
|
||||
do { \
|
||||
if ((vec).size >= (vec).cap) { \
|
||||
int cap = (vec).cap ? (vec).cap * 2 : 4; \
|
||||
usize cap = (vec).cap ? (vec).cap * 2 : 4; \
|
||||
scc_vec_realloc(vec, cap); \
|
||||
} \
|
||||
Assert((vec).data != nullptr); \
|
||||
|
||||
@@ -42,12 +42,13 @@ usize scc_fread(scc_file_t file, void *buffer, usize size) {
|
||||
usize scc_fwrite(scc_file_t file, const void *buf, usize size) {
|
||||
if (file == scc_stdout) {
|
||||
scc_pal_write(buf, size);
|
||||
return size;
|
||||
} else if (file == scc_stderr) {
|
||||
scc_pal_ewrite(buf, size);
|
||||
return size;
|
||||
} else {
|
||||
return scc_pal_fwrite(file, buf, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbool scc_fexists(const char *path) {
|
||||
|
||||
30
runtime/scc_utils/include/scc_path.h
Normal file
30
runtime/scc_utils/include/scc_path.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef __SCC_PATH_H__
|
||||
#define __SCC_PATH_H__
|
||||
|
||||
/**
|
||||
* @brief 检查路径是否为绝对路径
|
||||
* @param path 要检查的路径
|
||||
* @return 1 是绝对路径, 0 不是
|
||||
*/
|
||||
int scc_path_is_absolute(const char *path);
|
||||
|
||||
/**
|
||||
* @brief 检查路径是否包含 .. 路径穿越组件
|
||||
* @param path 要检查的路径
|
||||
* @return 1 包含 .., 0 不包含
|
||||
*/
|
||||
int scc_path_has_dotdot(const char *path);
|
||||
|
||||
/**
|
||||
* @brief 检查路径是否安全用作 #include 文件名
|
||||
*
|
||||
* 拒绝条件:
|
||||
* - 绝对路径(以 / \ 开头,或 Windows 驱动符如 C:\)
|
||||
* - 包含 .. 路径穿越组件
|
||||
*
|
||||
* @param path 要检查的路径
|
||||
* @return 0 安全, -1 不安全
|
||||
*/
|
||||
int scc_path_check_include_safe(const char *path);
|
||||
|
||||
#endif /* __SCC_PATH_H__ */
|
||||
@@ -4,6 +4,7 @@
|
||||
// #include "kllist.h"
|
||||
#include "scc_hashtable.h"
|
||||
#include "scc_strpool.h"
|
||||
#include "scc_path.h"
|
||||
#include <scc_core.h>
|
||||
|
||||
#endif /* __SMCC_UTILS_H__ */
|
||||
|
||||
@@ -44,13 +44,15 @@ void scc_hashtable_usize_init(scc_hashtable_t *ht) {
|
||||
scc_hashtable_init(ht, ht_usizehash, ht_usizecmp, nullptr);
|
||||
}
|
||||
|
||||
static int next_power_of_two(int n) {
|
||||
static usize next_power_of_two(usize n) {
|
||||
if (n == 0) return 32;
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
n |= n >> 32;
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
@@ -119,14 +121,18 @@ static void adjust_capacity(scc_hashtable_t *ht, usize new_cap) {
|
||||
|
||||
void *scc_hashtable_set(scc_hashtable_t *ht, const void *key, void *value) {
|
||||
if (ht->count + ht->tombstone_count >= ht->entries.cap * 0.75) {
|
||||
int new_cap = ht->entries.cap < SCC_INIT_HASHMAP_SIZE
|
||||
? SCC_INIT_HASHMAP_SIZE
|
||||
: ht->entries.cap * 2;
|
||||
usize new_cap = ht->entries.cap < SCC_INIT_HASHMAP_SIZE
|
||||
? SCC_INIT_HASHMAP_SIZE
|
||||
: ht->entries.cap * 2;
|
||||
adjust_capacity(ht, new_cap);
|
||||
}
|
||||
|
||||
u32 hash = ht->hash_func(key, ht->userdata);
|
||||
scc_hashtable_entry_t *entry = find_entry(ht, key, hash);
|
||||
if (entry == nullptr) {
|
||||
LOG_FATAL("scc_hashtable_set: hash table is full");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *old_value = nullptr;
|
||||
if (entry->state == ENTRY_ACTIVE) {
|
||||
|
||||
67
runtime/scc_utils/src/scc_path.c
Normal file
67
runtime/scc_utils/src/scc_path.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <scc_core.h>
|
||||
#include <scc_path.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SCC_PATH_SEP_A '\\'
|
||||
#define SCC_PATH_SEP_B '/'
|
||||
#define SCC_IS_DRIVE_LETTER(c) \
|
||||
(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
#else
|
||||
#define SCC_PATH_SEP_A '/'
|
||||
#define SCC_PATH_SEP_B '/' /* no alternative separator on non-Windows */
|
||||
#endif
|
||||
|
||||
int scc_path_is_absolute(const char *path) {
|
||||
if (path == nullptr || path[0] == '\0')
|
||||
return 0;
|
||||
|
||||
/* Unix absolute: /path */
|
||||
if (path[0] == '/')
|
||||
return 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows absolute: C:\path or \path */
|
||||
if (path[0] == '\\')
|
||||
return 1;
|
||||
if (SCC_IS_DRIVE_LETTER(path[0]) && path[1] == ':')
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scc_path_has_dotdot(const char *path) {
|
||||
if (path == nullptr)
|
||||
return 0;
|
||||
|
||||
const char *p = path;
|
||||
while (*p) {
|
||||
/* Look for '.' followed by '.' */
|
||||
if (p[0] == '.' && p[1] == '.') {
|
||||
char next = p[2];
|
||||
/* ".." at end of string or followed by a separator */
|
||||
if (next == '\0' || next == SCC_PATH_SEP_A || next == SCC_PATH_SEP_B) {
|
||||
/* Must also check that this ".." is at start or preceded by a separator */
|
||||
if (p == path ||
|
||||
p[-1] == SCC_PATH_SEP_A || p[-1] == SCC_PATH_SEP_B) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scc_path_check_include_safe(const char *path) {
|
||||
if (path == nullptr || path[0] == '\0')
|
||||
return -1;
|
||||
|
||||
if (scc_path_is_absolute(path))
|
||||
return -1;
|
||||
|
||||
if (scc_path_has_dotdot(path))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -22,7 +22,16 @@ const char *scc_strpool_intern(scc_strpool_t *pool, const char *str) {
|
||||
return new_str;
|
||||
}
|
||||
|
||||
void scc_strpool_drop(scc_strpool_t *pool) { scc_hashtable_drop(&pool->ht); }
|
||||
void scc_strpool_drop(scc_strpool_t *pool) {
|
||||
// Free all interned string allocations before dropping the hash table
|
||||
for (usize i = 0; i < pool->ht.entries.cap; i++) {
|
||||
scc_hashtable_entry_t *entry = &scc_vec_at(pool->ht.entries, i);
|
||||
if (entry->state == ENTRY_ACTIVE) {
|
||||
scc_free((void *)entry->key);
|
||||
}
|
||||
}
|
||||
scc_hashtable_drop(&pool->ht);
|
||||
}
|
||||
|
||||
void scc_strpool_foreach(scc_strpool_t *pool, scc_strpool_iter_fn iter_func,
|
||||
void *context) {
|
||||
|
||||
Reference in New Issue
Block a user