refactor(ast): 移除内置类型头文件并优化类型初始化

移除了独立的ast_builtin.h头文件,将内置类型定义整合到现有结构中,
同时修复了类型初始化函数命名不一致的问题。

BREAKING CHANGE: 原有的ast_builtin.h头文件已被移除,
相关内置类型声明已重构为新的接口形式。

fix(parser): 修复表达式解析中的位置信息处理

确保条件表达式和逗号表达式的解析正确获取并传递位置信息,
避免在语法树构建过程中丢失源码位置。

refactor(ir): 修复IR转储中的类型转换问题

添加必要的类型转换以防止整数溢出,并优化代码格式以提高可读性。

feat(parser): 添加表达式解析测试套件

引入全面的表达式解析测试框架,覆盖从基本表达式到复杂嵌套表达式
的各种场景,确保解析器功能的正确性和稳定性。
This commit is contained in:
zzy
2026-03-18 12:18:56 +08:00
parent 2e5e98868d
commit 5f915ba8d3
12 changed files with 1376 additions and 1370 deletions

View File

@@ -1,31 +0,0 @@
#ifndef __SCC_AST_BUILTIN_H__
#define __SCC_AST_BUILTIN_H__
#include "ast_def.h"
extern scc_ast_type_t scc_ast_builtin_type_va_list;
extern scc_ast_type_t scc_ast_builtin_type_void;
extern scc_ast_type_t scc_ast_builtin_type_bool;
extern scc_ast_type_t scc_ast_builtin_type_char;
extern scc_ast_type_t scc_ast_builtin_type_short;
extern scc_ast_type_t scc_ast_builtin_type_long;
extern scc_ast_type_t scc_ast_builtin_type_long_long;
extern scc_ast_type_t scc_ast_builtin_type_int;
extern scc_ast_type_t scc_ast_builtin_type_float;
extern scc_ast_type_t scc_ast_builtin_type_double;
extern scc_ast_type_t scc_ast_builtin_type_long_double;
extern scc_ast_type_t scc_ast_builtin_type_complex_float;
extern scc_ast_type_t scc_ast_builtin_type_complex_double;
extern scc_ast_type_t scc_ast_builtin_type_complex_long_double;
extern scc_ast_type_t scc_ast_builtin_type_unsigned_char;
extern scc_ast_type_t scc_ast_builtin_type_unsigned_short;
extern scc_ast_type_t scc_ast_builtin_type_unsigned_int;
extern scc_ast_type_t scc_ast_builtin_type_unsigned_long;
extern scc_ast_type_t scc_ast_builtin_type_unsigned_long_long;
extern scc_ast_type_t scc_ast_builtin_type_signed_char;
extern scc_ast_type_t scc_ast_builtin_type_signed_short;
extern scc_ast_type_t scc_ast_builtin_type_signed_int;
extern scc_ast_type_t scc_ast_builtin_type_signed_long;
extern scc_ast_type_t scc_ast_builtin_type_signed_long_long;
#endif

View File

@@ -1,7 +1,6 @@
#ifndef __SCC_AST_H__ #ifndef __SCC_AST_H__
#define __SCC_AST_H__ #define __SCC_AST_H__
#include "ast_builtin.h"
#include "ast_def.h" #include "ast_def.h"
#include "ast_dump.h" #include "ast_dump.h"
@@ -508,9 +507,9 @@ static inline void scc_ast_expr_lvalue_init(scc_ast_expr_t *expr,
} }
// have defined builtin type // have defined builtin type
static inline void _scc_ast_type_builtin_init(scc_ast_type_t *type, static inline void scc_ast_type_builtin_init(scc_ast_type_t *type,
scc_ast_builtin_type_t builtin, scc_ast_builtin_type_t builtin,
scc_pos_t loc) { scc_pos_t loc) {
Assert(type != null); Assert(type != null);
type->base.loc = loc; type->base.loc = loc;
type->base.type = SCC_AST_TYPE_BUILTIN; type->base.type = SCC_AST_TYPE_BUILTIN;

View File

@@ -1,128 +0,0 @@
#include <ast_builtin.h>
#define SCC_AST_BUILTIN_TYPE_HEADER \
.base.type = SCC_AST_TYPE_BUILTIN, .base.loc.col = 0, .base.loc.line = 0, \
.base.loc.name = "__scc_ast_builtin_type", .base.loc.offset = 0
// va_list
scc_ast_type_t scc_ast_builtin_type_va_list = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_VA_LIST,
};
scc_ast_type_t scc_ast_builtin_type_void = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_VOID,
};
scc_ast_type_t scc_ast_builtin_type_bool = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_BOOL,
};
scc_ast_type_t scc_ast_builtin_type_char = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_CHAR,
};
scc_ast_type_t scc_ast_builtin_type_short = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SHORT,
};
scc_ast_type_t scc_ast_builtin_type_int = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_INT,
};
scc_ast_type_t scc_ast_builtin_type_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG,
};
scc_ast_type_t scc_ast_builtin_type_long_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG_LONG,
};
// unsigned 类型
scc_ast_type_t scc_ast_builtin_type_unsigned_char = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR,
};
scc_ast_type_t scc_ast_builtin_type_unsigned_short = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT,
};
scc_ast_type_t scc_ast_builtin_type_unsigned_int = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_INT,
};
scc_ast_type_t scc_ast_builtin_type_unsigned_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG,
};
scc_ast_type_t scc_ast_builtin_type_unsigned_long_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
};
// signed 类型(实际上与默认相同,但为了完整性)
scc_ast_type_t scc_ast_builtin_type_signed_char = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_CHAR,
};
scc_ast_type_t scc_ast_builtin_type_signed_short = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_SHORT,
};
scc_ast_type_t scc_ast_builtin_type_signed_int = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_INT,
};
scc_ast_type_t scc_ast_builtin_type_signed_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG,
};
scc_ast_type_t scc_ast_builtin_type_signed_long_long = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
};
scc_ast_type_t scc_ast_builtin_type_float = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_FLOAT,
};
scc_ast_type_t scc_ast_builtin_type_double = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_DOUBLE,
};
scc_ast_type_t scc_ast_builtin_type_long_double = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_LONG_DOUBLE,
};
scc_ast_type_t scc_ast_builtin_type_complex_float = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT,
};
scc_ast_type_t scc_ast_builtin_type_complex_double = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE,
};
scc_ast_type_t scc_ast_builtin_type_complex_long_double = {
SCC_AST_BUILTIN_TYPE_HEADER,
.builtin.type = SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE,
};

View File

@@ -21,7 +21,7 @@ static const char *get_node_type_str(scc_ir_node_tag_t tag) {
[SCC_IR_NODE_RET] = "Return", [SCC_IR_NODE_RET] = "Return",
}; };
if (tag >= 0 && tag < sizeof(node_types) / sizeof(node_types[0]) && if (tag >= 0 && (usize)tag < sizeof(node_types) / sizeof(node_types[0]) &&
node_types[tag] != NULL) { node_types[tag] != NULL) {
return node_types[tag]; return node_types[tag];
} }
@@ -39,11 +39,12 @@ static const char *get_op_str(scc_ir_op_type_t op) {
[SCC_IR_OP_DIV] = "/", [SCC_IR_OP_MOD] = "%", [SCC_IR_OP_DIV] = "/", [SCC_IR_OP_MOD] = "%",
[SCC_IR_OP_AND] = "&", [SCC_IR_OP_OR] = "|", [SCC_IR_OP_AND] = "&", [SCC_IR_OP_OR] = "|",
[SCC_IR_OP_XOR] = "^", [SCC_IR_OP_NOT] = "~", [SCC_IR_OP_XOR] = "^", [SCC_IR_OP_NOT] = "~",
[SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>", [SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
[SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right [SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
}; };
if (op >= 0 && op < sizeof(ops) / sizeof(ops[0]) && ops[op] != NULL) { if (op >= 0 && (usize)op < sizeof(ops) / sizeof(ops[0]) &&
ops[op] != NULL) {
return ops[op]; return ops[op];
} }
return "<unknown_op>"; return "<unknown_op>";
@@ -64,7 +65,7 @@ static const char *get_type_tag_str(scc_ir_type_tag_t tag) {
[SCC_IR_TYPE_STRUCT] = "struct", [SCC_IR_TYPE_VECTOR] = "vector", [SCC_IR_TYPE_STRUCT] = "struct", [SCC_IR_TYPE_VECTOR] = "vector",
}; };
if (tag >= 0 && tag < sizeof(type_tags) / sizeof(type_tags[0]) && if (tag >= 0 && (usize)tag < sizeof(type_tags) / sizeof(type_tags[0]) &&
type_tags[tag] != NULL) { type_tags[tag] != NULL) {
return type_tags[tag]; return type_tags[tag];
} }

View File

@@ -427,8 +427,8 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
return null; return null;
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
scc_pos_t pos = tok_ptr->loc;
if (tok_ptr && tok_ptr->type == SCC_TOK_COND) { if (tok_ptr && tok_ptr->type == SCC_TOK_COND) {
scc_pos_t pos = tok_ptr->loc;
// 消耗 '?' // 消耗 '?'
scc_lexer_tok_t q_tok; scc_lexer_tok_t q_tok;
if (!scc_parser_next_consume(parser, &q_tok)) if (!scc_parser_next_consume(parser, &q_tok))
@@ -867,6 +867,9 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
if (tok_ptr == null || tok_ptr->type != SCC_TOK_COMMA) { if (tok_ptr == null || tok_ptr->type != SCC_TOK_COMMA) {
break; break;
} }
scc_pos_t pos = tok_ptr->loc;
scc_parser_next_consume(parser, null);
scc_ast_expr_t *right = scc_parse_assignment_expression(parser); scc_ast_expr_t *right = scc_parse_assignment_expression(parser);
if (!right) { if (!right) {
parser_sync(parser); parser_sync(parser);
@@ -874,8 +877,7 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
} }
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t)); scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
Assert(expr != null); Assert(expr != null);
scc_ast_expr_binary_init(expr, SCC_AST_OP_COMMA, left, right, scc_ast_expr_binary_init(expr, SCC_AST_OP_COMMA, left, right, pos);
tok_ptr->loc);
left = expr; left = expr;
} }
return left; return left;

View File

@@ -529,7 +529,7 @@ static scc_ast_type_t *build_type_from_info(type_spec_info_t *info,
} }
scc_ast_type_t *type = ast_type_alloc(); scc_ast_type_t *type = ast_type_alloc();
_scc_ast_type_builtin_init(type, builtin, pos); scc_ast_type_builtin_init(type, builtin, pos);
// 注意限定符const, volatile不应在此处处理应由上层函数负责 // 注意限定符const, volatile不应在此处处理应由上层函数负责
return type; return type;
} }
@@ -930,8 +930,12 @@ static void parse_parameter_type_list(scc_parser_t *parser,
param = scc_malloc(sizeof(scc_ast_decl_t)); param = scc_malloc(sizeof(scc_ast_decl_t));
Assert(param != null); Assert(param != null);
// FIXME // FIXME
scc_ast_decl_param_init(param, &scc_ast_builtin_type_va_list, null, type = scc_malloc(sizeof(scc_ast_type_t));
tok_ptr->loc); Assert(type != null);
scc_ast_type_builtin_init(type, SCC_AST_BUILTIN_TYPE_VA_LIST,
tok_ptr->loc);
scc_ast_decl_param_init(param, type, null, tok_ptr->loc);
scc_parser_next_consume(parser, null);
scc_vec_push(*params, param); scc_vec_push(*params, param);
break; break;
} }

View File

@@ -117,12 +117,13 @@ void scc_sema_init(scc_sema_callbacks_t *callbacks) {
callbacks->got_type = got_type_callback; callbacks->got_type = got_type_callback;
scc_sema_symtab_init(sema_symtab); scc_sema_symtab_init(sema_symtab);
// FIXME memory leak
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
scc_ast_type_builtin_init(type, SCC_AST_BUILTIN_TYPE_VA_LIST,
scc_pos_create());
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_list", scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_list",
&scc_ast_builtin_type_va_list.base); &type->base);
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_size_t",
&scc_ast_builtin_type_long_long.base);
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_ptrdiff_t",
&scc_ast_builtin_type_long_long.base);
} }
void scc_sema_drop(scc_sema_callbacks_t *callbacks) {} void scc_sema_drop(scc_sema_callbacks_t *callbacks) {}

View File

View File

@@ -0,0 +1,95 @@
#include <scc_lexer.h>
#include <scc_parser.h>
#include <stdio.h>
#include <string.h>
#include <utest/acutest.h>
typedef scc_ast_node_t *(*scc_parse_node_func)(scc_parser_t *parser);
static scc_ast_node_t *process_input(const char *input,
scc_parse_node_func parse_func,
cbool need_sema) {
int res = 0;
scc_sstream_t mem_stream;
res = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
16);
Assert(res == 0);
scc_lexer_t lexer;
scc_lexer_init(&lexer, scc_sstream_to_ring(&mem_stream));
scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(&lexer, 64, false);
scc_parser_t parser;
if (need_sema) {
scc_sema_callbacks_t sema_callbacks;
scc_sema_init(&sema_callbacks);
scc_parser_init(&parser, tok_ring, &sema_callbacks);
} else {
scc_parser_init(&parser, tok_ring, null);
}
scc_ast_node_t *ret = parse_func(&parser);
cbool not_eof = false;
scc_ring_not_eof(*parser.ring, not_eof);
if (not_eof == true) {
// FIXME MAYBE free
LOG_ERROR("Didn't consume all tokens");
return null;
}
scc_lexer_drop_ring(parser.ring);
scc_parser_drop(&parser);
scc_lexer_drop(&lexer);
scc_sstream_drop(&mem_stream);
return ret;
}
typedef void (*scc_tree_dump_output_t)(void *userdata, const char *fmt, ...);
#define BUFFER_SIZE (4096)
char expect_buffer[BUFFER_SIZE];
char output_buffer[BUFFER_SIZE];
static void dump2buffer(void *_buffer, const char *fmt, ...) {
char *buffer = _buffer;
va_list args;
va_start(args, fmt);
int res = scc_vsnprintf(buffer + strlen(buffer),
BUFFER_SIZE - strlen(buffer) - 1, fmt, args);
Assert(res > 0);
va_end(args);
}
static void _scc_check_ast(scc_ast_node_t *expect_node_ptr, const char *str,
scc_parse_node_func parse_func, cbool need_sema) {
scc_ast_node_t *output_node_ptr = process_input(str, parse_func, need_sema);
scc_tree_dump_ctx_t ctx;
expect_buffer[0] = '\n', expect_buffer[1] = '\0';
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer);
scc_ast_dump_node(&ctx, expect_node_ptr);
scc_tree_dump_ctx_drop(&ctx);
output_buffer[0] = '\n', output_buffer[1] = '\0';
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer);
scc_ast_dump_node(&ctx, output_node_ptr);
scc_tree_dump_ctx_drop(&ctx);
}
#define SCC_CHECK_AST_WITH_SEMA(expect_node_ptr, str, parse_func) \
do { \
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
true); \
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
TEST_MSG("Expected: %s", expect_buffer); \
TEST_MSG("Produced: %s", output_buffer); \
} while (0);
#define SCC_CHECK_AST(expect_node_ptr, str, parse_func) \
do { \
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
false); \
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
TEST_MSG("Expected: %s", expect_buffer); \
TEST_MSG("Produced: %s", output_buffer); \
} while (0);

View File

@@ -0,0 +1,395 @@
void init_func(void);
#define TEST_INIT init_func()
#include "parser_test.h"
static scc_ast_type_t int_type;
void init_func(void) {
scc_ast_type_builtin_init(&int_type, SCC_AST_BUILTIN_TYPE_INT,
scc_pos_create());
}
#define LOC scc_pos_create()
static void test_primary_expr(void) {
TEST_CASE("identifier");
{
scc_ast_expr_t ident;
scc_ast_expr_identifier_init(&ident, "x", LOC);
SCC_CHECK_AST(&ident.base, "x", scc_parse_expression);
}
TEST_CASE("integer literal");
{
scc_ast_expr_t int_lit;
scc_ast_expr_literal_int_init(&int_lit, "42", false, LOC);
SCC_CHECK_AST(&int_lit.base, "42", scc_parse_expression);
}
TEST_CASE("string literal");
{
scc_ast_expr_t str_lit;
scc_ast_expr_literal_string_init(&str_lit, "\"hello\"", false, LOC);
SCC_CHECK_AST(&str_lit.base, "\"hello\"", scc_parse_expression);
}
TEST_CASE("parenthesized expression");
{
scc_ast_expr_t ident;
scc_ast_expr_identifier_init(&ident, "y", LOC);
// 解析器应直接返回内部表达式,因此期望结果与 "y" 相同
SCC_CHECK_AST(&ident.base, "(y)", scc_parse_expression);
}
}
static void test_postfix_expr(void) {
TEST_CASE("array subscript");
{
scc_ast_expr_t a, index, subscript;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_literal_int_init(&index, "10", false, LOC);
scc_ast_expr_array_subscript_init(&subscript, &a, &index, LOC);
SCC_CHECK_AST(&subscript.base, "a[10]", scc_parse_expression);
}
TEST_CASE("function call (no arguments)");
{
scc_ast_expr_t callee, call;
scc_ast_expr_identifier_init(&callee, "f", LOC);
scc_ast_expr_vec_t args;
scc_vec_init(args);
scc_ast_expr_call_init(&call, &callee, &args, LOC);
SCC_CHECK_AST(&call.base, "f()", scc_parse_expression);
}
TEST_CASE("function call (with arguments)");
{
scc_ast_expr_t callee, arg1, arg2, call;
scc_ast_expr_identifier_init(&callee, "f", LOC);
scc_ast_expr_literal_int_init(&arg1, "1", false, LOC);
scc_ast_expr_identifier_init(&arg2, "x", LOC);
scc_ast_expr_vec_t args;
scc_vec_init(args);
scc_vec_push(args, &arg1);
scc_vec_push(args, &arg2);
scc_ast_expr_call_init(&call, &callee, &args, LOC);
SCC_CHECK_AST(&call.base, "f(1, x)", scc_parse_expression);
}
TEST_CASE("member access (.)");
{
scc_ast_expr_t obj, member;
scc_ast_expr_identifier_init(&obj, "s", LOC);
scc_ast_expr_member_init(&member, &obj, "field", LOC);
SCC_CHECK_AST(&member.base, "s.field", scc_parse_expression);
}
TEST_CASE("pointer member access (->)");
{
scc_ast_expr_t ptr, member;
scc_ast_expr_identifier_init(&ptr, "p", LOC);
scc_ast_expr_ptr_member_init(&member, &ptr, "field", LOC);
SCC_CHECK_AST(&member.base, "p->field", scc_parse_expression);
}
TEST_CASE("postfix increment/decrement");
{
scc_ast_expr_t x, post_inc, post_dec;
scc_ast_expr_identifier_init(&x, "x", LOC);
scc_ast_expr_unary_init(&post_inc, SCC_AST_OP_POSTFIX_INCREMENT, &x,
LOC);
scc_ast_expr_unary_init(&post_dec, SCC_AST_OP_POSTFIX_DECREMENT, &x,
LOC);
SCC_CHECK_AST(&post_inc.base, "x++", scc_parse_expression);
SCC_CHECK_AST(&post_dec.base, "x--", scc_parse_expression);
}
}
static void test_unary_expr(void) {
scc_ast_expr_t x;
scc_ast_expr_identifier_init(&x, "x", LOC);
TEST_CASE("prefix increment");
{
scc_ast_expr_t pre_inc;
scc_ast_expr_unary_init(&pre_inc, SCC_AST_OP_PREFIX_INCREMENT, &x, LOC);
SCC_CHECK_AST(&pre_inc.base, "++x", scc_parse_expression);
}
TEST_CASE("prefix decrement");
{
scc_ast_expr_t pre_dec;
scc_ast_expr_unary_init(&pre_dec, SCC_AST_OP_PREFIX_DECREMENT, &x, LOC);
SCC_CHECK_AST(&pre_dec.base, "--x", scc_parse_expression);
}
TEST_CASE("address-of");
{
scc_ast_expr_t addr;
scc_ast_expr_unary_init(&addr, SCC_AST_OP_ADDRESS_OF, &x, LOC);
SCC_CHECK_AST(&addr.base, "&x", scc_parse_expression);
}
TEST_CASE("indirection (dereference)");
{
scc_ast_expr_t deref;
scc_ast_expr_unary_init(&deref, SCC_AST_OP_INDIRECTION, &x, LOC);
SCC_CHECK_AST(&deref.base, "*x", scc_parse_expression);
}
TEST_CASE("unary plus");
{
scc_ast_expr_t plus;
scc_ast_expr_unary_init(&plus, SCC_AST_OP_UNARY_PLUS, &x, LOC);
SCC_CHECK_AST(&plus.base, "+x", scc_parse_expression);
}
TEST_CASE("unary minus");
{
scc_ast_expr_t minus;
scc_ast_expr_unary_init(&minus, SCC_AST_OP_UNARY_MINUS, &x, LOC);
SCC_CHECK_AST(&minus.base, "-x", scc_parse_expression);
}
TEST_CASE("bitwise NOT");
{
scc_ast_expr_t bit_not;
scc_ast_expr_unary_init(&bit_not, SCC_AST_OP_BITWISE_NOT, &x, LOC);
SCC_CHECK_AST(&bit_not.base, "~x", scc_parse_expression);
}
TEST_CASE("logical NOT");
{
scc_ast_expr_t log_not;
scc_ast_expr_unary_init(&log_not, SCC_AST_OP_LOGICAL_NOT, &x, LOC);
SCC_CHECK_AST(&log_not.base, "!x", scc_parse_expression);
}
TEST_CASE("sizeof expression");
{
scc_ast_expr_t sizeof_expr;
scc_ast_expr_sizeof_init(&sizeof_expr, NULL, &x, LOC);
SCC_CHECK_AST(&sizeof_expr.base, "sizeof(x)", scc_parse_expression);
}
TEST_CASE("sizeof type");
{
scc_ast_expr_t sizeof_type;
scc_ast_expr_sizeof_init(&sizeof_type, &int_type, NULL, LOC);
SCC_CHECK_AST(&sizeof_type.base, "sizeof(int)", scc_parse_expression);
}
}
static void test_cast_expr(void) {
TEST_CASE("cast");
{
scc_ast_expr_t x, cast;
scc_ast_expr_identifier_init(&x, "x", LOC);
scc_ast_expr_cast_init(&cast, &int_type, &x, LOC);
SCC_CHECK_AST(&cast.base, "(int)x", scc_parse_expression);
}
}
static void test_binary_expr(void) {
scc_ast_expr_t a, b, c, d;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_identifier_init(&b, "b", LOC);
scc_ast_expr_identifier_init(&c, "c", LOC);
scc_ast_expr_identifier_init(&d, "d", LOC);
TEST_CASE("multiplication and addition (priority)");
{
// a * b + c
scc_ast_expr_t mul, add;
scc_ast_expr_binary_init(&mul, SCC_AST_OP_MUL, &a, &b, LOC);
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &mul, &c, LOC);
SCC_CHECK_AST(&add.base, "a * b + c", scc_parse_expression);
}
TEST_CASE("subtraction (left associativity)");
{
// a - b - c => (a - b) - c
scc_ast_expr_t sub1, sub2;
scc_ast_expr_binary_init(&sub1, SCC_AST_OP_SUB, &a, &b, LOC);
scc_ast_expr_binary_init(&sub2, SCC_AST_OP_SUB, &sub1, &c, LOC);
SCC_CHECK_AST(&sub2.base, "a - b - c", scc_parse_expression);
}
TEST_CASE("shift");
{
// a << b
scc_ast_expr_t shift;
scc_ast_expr_binary_init(&shift, SCC_AST_OP_LEFT_SHIFT, &a, &b, LOC);
SCC_CHECK_AST(&shift.base, "a << b", scc_parse_expression);
}
TEST_CASE("relational");
{
// a < b
scc_ast_expr_t lt;
scc_ast_expr_binary_init(&lt, SCC_AST_OP_LESS, &a, &b, LOC);
SCC_CHECK_AST(&lt.base, "a < b", scc_parse_expression);
}
TEST_CASE("equality");
{
// a == b
scc_ast_expr_t eq;
scc_ast_expr_binary_init(&eq, SCC_AST_OP_EQUAL, &a, &b, LOC);
SCC_CHECK_AST(&eq.base, "a == b", scc_parse_expression);
}
TEST_CASE("bitwise operators (priority)");
{
// a & b ^ c | d => ((a & b) ^ c) | d
scc_ast_expr_t bitand, bitxor, bitor;
scc_ast_expr_binary_init(&bitand, SCC_AST_OP_BITWISE_AND, &a, &b, LOC);
scc_ast_expr_binary_init(&bitxor, SCC_AST_OP_BITWISE_XOR, &bitand, &c,
LOC);
scc_ast_expr_binary_init(&bitor, SCC_AST_OP_BITWISE_OR, &bitxor, &d,
LOC);
SCC_CHECK_AST(&bitor.base, "a & b ^ c | d", scc_parse_expression);
}
TEST_CASE("logical operators (priority)");
{
// a && b || c => (a && b) || c
scc_ast_expr_t logand, logor;
scc_ast_expr_binary_init(&logand, SCC_AST_OP_LOGICAL_AND, &a, &b, LOC);
scc_ast_expr_binary_init(&logor, SCC_AST_OP_LOGICAL_OR, &logand, &c,
LOC);
SCC_CHECK_AST(&logor.base, "a && b || c", scc_parse_expression);
}
}
static void test_conditional_expr(void) {
scc_ast_expr_t a, b, c;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_identifier_init(&b, "b", LOC);
scc_ast_expr_identifier_init(&c, "c", LOC);
TEST_CASE("simple conditional");
{
scc_ast_expr_t cond;
scc_ast_expr_cond_init(&cond, &a, &b, &c, LOC);
SCC_CHECK_AST(&cond.base, "a ? b : c", scc_parse_expression);
}
TEST_CASE("nested conditional (right associative)");
{
// a ? b : c ? d : e => a ? b : (c ? d : e)
scc_ast_expr_t d, e, inner, outer;
scc_ast_expr_identifier_init(&d, "d", LOC);
scc_ast_expr_identifier_init(&e, "e", LOC);
scc_ast_expr_cond_init(&inner, &c, &d, &e, LOC);
scc_ast_expr_cond_init(&outer, &a, &b, &inner, LOC);
SCC_CHECK_AST(&outer.base, "a ? b : c ? d : e", scc_parse_expression);
}
}
static void test_assignment_expr(void) {
scc_ast_expr_t a, b, c;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_identifier_init(&b, "b", LOC);
scc_ast_expr_identifier_init(&c, "c", LOC);
scc_ast_expr_t lit42;
scc_ast_expr_literal_int_init(&lit42, "42", false, LOC);
TEST_CASE("simple assignment");
{
// a = 42
scc_ast_expr_t assign;
scc_ast_expr_binary_init(&assign, SCC_AST_OP_ASSIGN, &a, &lit42, LOC);
SCC_CHECK_AST(&assign.base, "a = 42", scc_parse_expression);
}
TEST_CASE("chained assignment (right associative)");
{
// a = b = c
scc_ast_expr_t inner, outer;
scc_ast_expr_binary_init(&inner, SCC_AST_OP_ASSIGN, &b, &c, LOC);
scc_ast_expr_binary_init(&outer, SCC_AST_OP_ASSIGN, &a, &inner, LOC);
SCC_CHECK_AST(&outer.base, "a = b = c", scc_parse_expression);
}
TEST_CASE("compound assignment");
{
// a += b
scc_ast_expr_t add_assign;
scc_ast_expr_binary_init(&add_assign, SCC_AST_OP_ASSIGN_ADD, &a, &b,
LOC);
SCC_CHECK_AST(&add_assign.base, "a += b", scc_parse_expression);
}
TEST_CASE("assignment with expression");
{
// a = a - b + 42
scc_ast_expr_t sub, add, assign;
scc_ast_expr_binary_init(&sub, SCC_AST_OP_SUB, &a, &b, LOC);
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &sub, &lit42, LOC);
scc_ast_expr_binary_init(&assign, SCC_AST_OP_ASSIGN, &a, &add, LOC);
SCC_CHECK_AST(&assign.base, "a = a - b + 42", scc_parse_expression);
}
}
static void test_comma_expr(void) {
TEST_CASE("comma operator");
{
scc_ast_expr_t a, b, comma;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_identifier_init(&b, "b", LOC);
scc_ast_expr_binary_init(&comma, SCC_AST_OP_COMMA, &a, &b, LOC);
SCC_CHECK_AST(&comma.base, "a, b", scc_parse_expression);
}
}
static void test_complex_expr(void) {
TEST_CASE("mixed operators with precedence");
{
scc_ast_expr_t a, b, c, d;
scc_ast_expr_identifier_init(&a, "a", LOC);
scc_ast_expr_identifier_init(&b, "b", LOC);
scc_ast_expr_identifier_init(&c, "c", LOC);
scc_ast_expr_identifier_init(&d, "d", LOC);
// a + b * c - d
scc_ast_expr_t mul, add, sub;
scc_ast_expr_binary_init(&mul, SCC_AST_OP_MUL, &b, &c, LOC);
scc_ast_expr_binary_init(&add, SCC_AST_OP_ADD, &a, &mul, LOC);
scc_ast_expr_binary_init(&sub, SCC_AST_OP_SUB, &add, &d, LOC);
SCC_CHECK_AST(&sub.base, "a + b * c - d", scc_parse_expression);
}
TEST_CASE("postfix and unary combination");
{
scc_ast_expr_t p, post_inc, deref;
scc_ast_expr_identifier_init(&p, "p", LOC);
scc_ast_expr_unary_init(&post_inc, SCC_AST_OP_POSTFIX_INCREMENT, &p,
LOC);
scc_ast_expr_unary_init(&deref, SCC_AST_OP_INDIRECTION, &post_inc, LOC);
SCC_CHECK_AST(&deref.base, "*p++", scc_parse_expression);
}
}
static void test_detail_expr(void) {
TEST_CASE("multi string literal connection");
scc_ast_expr_t str;
scc_ast_expr_literal_string_init(&str, "\"ab\"", false, scc_pos_create());
SCC_CHECK_AST(&str.base, "\"a\" \"b\"", scc_parse_expression);
}
TEST_LIST = {
{"test_primary_expr", test_primary_expr},
{"test_postfix_expr", test_postfix_expr},
{"test_unary_expr", test_unary_expr},
{"test_cast_expr", test_cast_expr},
{"test_binary_expr", test_binary_expr},
{"test_conditional_expr", test_conditional_expr},
{"test_assignment_expr", test_assignment_expr},
{"test_comma_expr", test_comma_expr},
{"test_complex_expr", test_complex_expr},
{"test_detail_expr", test_detail_expr},
{NULL, NULL},
};

View File

@@ -0,0 +1,583 @@
void init_func(void);
#define TEST_INIT init_func()
#include "parser_test.h"
static scc_ast_type_t int_type;
static scc_ast_type_t char_type;
static scc_ast_type_t void_type;
static scc_ast_type_t pointer_int_type;
static scc_ast_type_t pointer_char_type;
static scc_ast_type_t pointer_void_type;
static scc_ast_type_t pointer_pointer_int_type;
void init_func(void) {
scc_ast_type_builtin_init(&int_type, SCC_AST_BUILTIN_TYPE_INT,
scc_pos_create());
scc_ast_type_builtin_init(&char_type, SCC_AST_BUILTIN_TYPE_CHAR,
scc_pos_create());
scc_ast_type_builtin_init(&void_type, SCC_AST_BUILTIN_TYPE_VOID,
scc_pos_create());
scc_ast_type_pointer_init(&pointer_int_type, &int_type, scc_pos_create());
scc_ast_type_pointer_init(&pointer_char_type, &char_type, scc_pos_create());
scc_ast_type_pointer_init(&pointer_void_type, &void_type, scc_pos_create());
scc_ast_type_pointer_init(&pointer_pointer_int_type, &pointer_int_type,
scc_pos_create());
}
static void test_builtin_type(void) {
#define CHECK_BUILTIN_TYPE(type, str) \
do { \
scc_ast_type_t builtin_type; \
scc_ast_type_builtin_init(&builtin_type, type, scc_pos_create()); \
SCC_CHECK_AST(&builtin_type.base, str, scc_parse_type_name); \
} while (0)
// CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_VA_LIST, "...");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_VOID, "void");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_BOOL, "bool");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_CHAR, "char");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SHORT, "short");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_INT, "int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG, "long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG, "long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_LONG, "long long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_LONG, "long long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR, "unsigned char");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT, "unsigned short");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_INT, "unsigned int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG, "unsigned long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG, "unsigned long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
"unsigned long long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
"unsigned long long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_CHAR, "signed char");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_SHORT, "signed short");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_INT, "signed int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG, "signed long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG, "signed long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
"signed long long");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
"signed long long int");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_FLOAT, "float");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_DOUBLE, "double");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_LONG_DOUBLE, "long double");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT, "complex float");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE, "complex double");
CHECK_BUILTIN_TYPE(SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE,
"complex long double");
#undef CHECK_BUILTIN_TYPE
}
static void test_pointer_type(void) {
TEST_CASE("simple pointer");
// int *
SCC_CHECK_AST(&pointer_int_type.base, "int *", scc_parse_type_name);
// int **
SCC_CHECK_AST(&pointer_pointer_int_type.base, "int **",
scc_parse_type_name);
// int *** (需要临时构建)
{
scc_ast_type_t ptr_ptr_ptr_int;
scc_ast_type_pointer_init(&ptr_ptr_ptr_int, &pointer_pointer_int_type,
scc_pos_create());
SCC_CHECK_AST(&ptr_ptr_ptr_int.base, "int ***", scc_parse_type_name);
}
}
static void test_array_type(void) {
scc_ast_expr_t size_5, size_3;
TEST_CASE("fixed size array");
{
// int [5]
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t array_5_int;
scc_ast_type_array_init(&array_5_int, &int_type, &size_5,
scc_pos_create());
SCC_CHECK_AST(&array_5_int.base, "int [5]", scc_parse_type_name);
}
TEST_CASE("incomplete array");
{
// int []
scc_ast_type_t array_unknown_int;
scc_ast_type_array_init(&array_unknown_int, &int_type, NULL,
scc_pos_create());
SCC_CHECK_AST(&array_unknown_int.base, "int []", scc_parse_type_name);
}
TEST_CASE("multidimensional array");
{
// int [5][3]
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_expr_literal_int_init(&size_3, "3", false, scc_pos_create());
scc_ast_type_t inner_array;
scc_ast_type_array_init(&inner_array, &int_type, &size_3,
scc_pos_create());
scc_ast_type_t outer_array;
scc_ast_type_array_init(&outer_array, &inner_array, &size_5,
scc_pos_create());
SCC_CHECK_AST(&outer_array.base, "int [5][3]", scc_parse_type_name);
}
TEST_CASE("pointer to array");
{
// int (*)[5]
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t array_5_int;
scc_ast_type_array_init(&array_5_int, &int_type, &size_5,
scc_pos_create());
scc_ast_type_t ptr_to_array;
scc_ast_type_pointer_init(&ptr_to_array, &array_5_int,
scc_pos_create());
SCC_CHECK_AST(&ptr_to_array.base, "int (*)[5]", scc_parse_type_name);
}
TEST_CASE("array of pointers");
{
// int *[5]
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t array_of_ptr;
scc_ast_type_array_init(&array_of_ptr, &pointer_int_type, &size_5,
scc_pos_create());
SCC_CHECK_AST(&array_of_ptr.base, "int *[5]", scc_parse_type_name);
}
}
static void test_function_type(void) {
TEST_CASE("function with no parameters (old-style)");
{
// int ()
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, NULL,
scc_pos_create());
SCC_CHECK_AST(&func_type.base, "int ()", scc_parse_type_name);
}
TEST_CASE("function with void parameter");
{
// int (void)
scc_ast_decl_t void_param;
scc_ast_decl_param_init(&void_param, &void_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &void_param);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
SCC_CHECK_AST(&func_type.base, "int (void)", scc_parse_type_name);
}
TEST_CASE("function with parameters");
{
// int (int, float)
scc_ast_type_t float_type;
scc_ast_type_builtin_init(&float_type, SCC_AST_BUILTIN_TYPE_FLOAT,
scc_pos_create());
scc_ast_decl_t param_int, param_float;
scc_ast_decl_param_init(&param_int, &int_type, NULL, scc_pos_create());
scc_ast_decl_param_init(&param_float, &float_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &param_int);
scc_vec_push(params, &param_float);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
SCC_CHECK_AST(&func_type.base, "int (int, float)", scc_parse_type_name);
}
TEST_CASE("function with variadic parameters");
{
// int (int, ...)
scc_ast_type_t va_list_type;
scc_ast_type_builtin_init(&va_list_type, SCC_AST_BUILTIN_TYPE_VA_LIST,
scc_pos_create());
scc_ast_decl_t param_int, param_var;
scc_ast_decl_param_init(&param_int, &int_type, NULL, scc_pos_create());
scc_ast_decl_param_init(&param_var, &va_list_type, "...",
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &param_int);
scc_vec_push(params, &param_var);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
SCC_CHECK_AST(&func_type.base, "int (int, ...)", scc_parse_type_name);
}
TEST_CASE("function returning pointer");
{
// int *()
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &pointer_int_type, NULL,
scc_pos_create());
SCC_CHECK_AST(&func_type.base, "int *()", scc_parse_type_name);
}
TEST_CASE("pointer to function");
{
// int (*)(void)
scc_ast_decl_t void_param;
scc_ast_decl_param_init(&void_param, &void_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &void_param);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
scc_ast_type_t ptr_to_func;
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
SCC_CHECK_AST(&ptr_to_func.base, "int (*)(void)", scc_parse_type_name);
}
}
static void test_struct_union_type(void) {
TEST_CASE("struct tag (incomplete)");
{
// struct S
scc_ast_type_t struct_type;
scc_ast_type_struct_init(&struct_type, "S", NULL, scc_pos_create());
SCC_CHECK_AST(&struct_type.base, "struct S", scc_parse_type_name);
}
TEST_CASE("union tag (incomplete)");
{
// union U
scc_ast_type_t union_type;
scc_ast_type_union_init(&union_type, "U", NULL, scc_pos_create());
SCC_CHECK_AST(&union_type.base, "union U", scc_parse_type_name);
}
TEST_CASE("anonymous struct definition");
{
// struct { int x; }
scc_ast_decl_t field_x;
scc_ast_decl_val_init(&field_x, &int_type, "x", NULL, scc_pos_create());
scc_ast_decl_vec_t fields;
scc_vec_init(fields);
scc_vec_push(fields, &field_x);
scc_ast_decl_t struct_decl;
scc_ast_decl_struct_init(&struct_decl, NULL, &fields, scc_pos_create());
scc_ast_type_t struct_type;
scc_ast_type_struct_init(&struct_type, NULL, &struct_decl,
scc_pos_create());
SCC_CHECK_AST(&struct_type.base, "struct { int x; }",
scc_parse_type_name);
}
TEST_CASE("named struct definition");
{
// struct S { int x; }
scc_ast_decl_t field_x;
scc_ast_decl_val_init(&field_x, &int_type, "x", NULL, scc_pos_create());
scc_ast_decl_vec_t fields;
scc_vec_init(fields);
scc_vec_push(fields, &field_x);
scc_ast_decl_t struct_decl;
scc_ast_decl_struct_init(&struct_decl, "S", &fields, scc_pos_create());
scc_ast_type_t struct_type;
scc_ast_type_struct_init(&struct_type, "S", &struct_decl,
scc_pos_create());
SCC_CHECK_AST(&struct_type.base, "struct S { int x; }",
scc_parse_type_name);
}
TEST_CASE("union definition");
{
// union { int a; float b; }
scc_ast_type_t float_type;
scc_ast_type_builtin_init(&float_type, SCC_AST_BUILTIN_TYPE_FLOAT,
scc_pos_create());
scc_ast_decl_t field_a, field_b;
scc_ast_decl_val_init(&field_a, &int_type, "a", NULL, scc_pos_create());
scc_ast_decl_val_init(&field_b, &float_type, "b", NULL,
scc_pos_create());
scc_ast_decl_vec_t fields;
scc_vec_init(fields);
scc_vec_push(fields, &field_a);
scc_vec_push(fields, &field_b);
scc_ast_decl_t union_decl;
scc_ast_decl_union_init(&union_decl, NULL, &fields, scc_pos_create());
scc_ast_type_t union_type;
scc_ast_type_union_init(&union_type, NULL, &union_decl,
scc_pos_create());
SCC_CHECK_AST(&union_type.base, "union { int a; float b; }",
scc_parse_type_name);
}
}
static void test_enum_type(void) {
TEST_CASE("enum tag (incomplete)");
{
// enum E
scc_ast_type_t enum_type;
scc_ast_type_enum_init(&enum_type, "E", NULL, scc_pos_create());
SCC_CHECK_AST(&enum_type.base, "enum E", scc_parse_type_name);
}
TEST_CASE("anonymous enum definition");
{
// enum { RED, GREEN, BLUE }
scc_ast_expr_t red, green, blue;
scc_ast_expr_identifier_init(&red, "RED", scc_pos_create());
scc_ast_expr_identifier_init(&green, "GREEN", scc_pos_create());
scc_ast_expr_identifier_init(&blue, "BLUE", scc_pos_create());
scc_ast_expr_vec_t enumerators;
scc_vec_init(enumerators);
scc_vec_push(enumerators, &red);
scc_vec_push(enumerators, &green);
scc_vec_push(enumerators, &blue);
scc_ast_decl_t enum_decl;
scc_ast_decl_enum_init(&enum_decl, NULL, &enumerators,
scc_pos_create());
scc_ast_type_t enum_type;
scc_ast_type_enum_init(&enum_type, NULL, &enum_decl, scc_pos_create());
SCC_CHECK_AST(&enum_type.base, "enum { RED, GREEN, BLUE }",
scc_parse_type_name);
}
TEST_CASE("named enum definition");
{
// enum E { RED, GREEN, BLUE }
scc_ast_expr_t red, green, blue;
scc_ast_expr_identifier_init(&red, "RED", scc_pos_create());
scc_ast_expr_identifier_init(&green, "GREEN", scc_pos_create());
scc_ast_expr_identifier_init(&blue, "BLUE", scc_pos_create());
scc_ast_expr_vec_t enumerators;
scc_vec_init(enumerators);
scc_vec_push(enumerators, &red);
scc_vec_push(enumerators, &green);
scc_vec_push(enumerators, &blue);
scc_ast_decl_t enum_decl;
scc_ast_decl_enum_init(&enum_decl, "E", &enumerators, scc_pos_create());
scc_ast_type_t enum_type;
scc_ast_type_enum_init(&enum_type, "E", &enum_decl, scc_pos_create());
SCC_CHECK_AST(&enum_type.base, "enum E { RED, GREEN, BLUE }",
scc_parse_type_name);
}
}
static void test_specifier_type(void) {
TEST_CASE("const/volatile on builtin types");
{
// const int
scc_ast_type_t const_int = int_type;
const_int.quals.is_const = true;
SCC_CHECK_AST(&const_int.base, "const int", scc_parse_type_name);
// volatile int
scc_ast_type_t volatile_int = int_type;
volatile_int.quals.is_volatile = true;
SCC_CHECK_AST(&volatile_int.base, "volatile int", scc_parse_type_name);
// const volatile int
scc_ast_type_t const_volatile_int = int_type;
const_volatile_int.quals.is_const = true;
const_volatile_int.quals.is_volatile = true;
SCC_CHECK_AST(&const_volatile_int.base, "const volatile int",
scc_parse_type_name);
}
TEST_CASE("const/volatile on pointers");
{
// int * const (const pointer to int)
scc_ast_type_t const_ptr_to_int = pointer_int_type;
const_ptr_to_int.quals.is_const = true;
SCC_CHECK_AST(&const_ptr_to_int.base, "int * const",
scc_parse_type_name);
// const int * (pointer to const int)
scc_ast_type_t const_int = int_type;
const_int.quals.is_const = true;
scc_ast_type_t ptr_to_const_int;
scc_ast_type_pointer_init(&ptr_to_const_int, &const_int,
scc_pos_create());
SCC_CHECK_AST(&ptr_to_const_int.base, "const int *",
scc_parse_type_name);
// const int * const (const pointer to const int)
scc_ast_type_t const_ptr_to_const_int;
scc_ast_type_pointer_init(&const_ptr_to_const_int, &const_int,
scc_pos_create());
const_ptr_to_const_int.quals.is_const = true;
SCC_CHECK_AST(&const_ptr_to_const_int.base, "const int * const",
scc_parse_type_name);
// volatile int * restrict (restrict pointer to volatile int)
scc_ast_type_t volatile_int = int_type;
volatile_int.quals.is_volatile = true;
scc_ast_type_t restrict_ptr_to_volatile_int;
scc_ast_type_pointer_init(&restrict_ptr_to_volatile_int, &volatile_int,
scc_pos_create());
restrict_ptr_to_volatile_int.quals.is_restrict = true;
SCC_CHECK_AST(&restrict_ptr_to_volatile_int.base,
"volatile int * restrict", scc_parse_type_name);
}
TEST_CASE("const on array element type");
{
// const int [5]
scc_ast_expr_t size_5;
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t const_int = int_type;
const_int.quals.is_const = true;
scc_ast_type_t const_array;
scc_ast_type_array_init(&const_array, &const_int, &size_5,
scc_pos_create());
SCC_CHECK_AST(&const_array.base, "const int [5]", scc_parse_type_name);
}
}
static void test_hard_type(void) {
TEST_CASE("pointer to array of pointers to function");
// int (*(*)[5])(void)
{
// 1) 函数类型 int (void)
scc_ast_decl_t void_param;
scc_ast_decl_param_init(&void_param, &void_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &void_param);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
// 2) 指向函数的指针
scc_ast_type_t ptr_to_func;
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
// 3) 数组元素为上述指针大小5
scc_ast_expr_t size_5;
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t array_of_ptr;
scc_ast_type_array_init(&array_of_ptr, &ptr_to_func, &size_5,
scc_pos_create());
// 4) 指向数组的指针
scc_ast_type_t ptr_to_array;
scc_ast_type_pointer_init(&ptr_to_array, &array_of_ptr,
scc_pos_create());
SCC_CHECK_AST(&ptr_to_array.base, "int (*(*)[5])(void)",
scc_parse_type_name);
}
TEST_CASE("pointer to function returning pointer to array");
// int (*(*)(void))[5]
{
// 1) 数组类型 int [5]
scc_ast_expr_t size_5;
scc_ast_expr_literal_int_init(&size_5, "5", false, scc_pos_create());
scc_ast_type_t array_type;
scc_ast_type_array_init(&array_type, &int_type, &size_5,
scc_pos_create());
// 2) 指向数组的指针
scc_ast_type_t ptr_to_array;
scc_ast_type_pointer_init(&ptr_to_array, &array_type, scc_pos_create());
// 3) 函数类型,返回上述指针,无参数
scc_ast_decl_t void_param;
scc_ast_decl_param_init(&void_param, &void_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &void_param);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &ptr_to_array, &params,
scc_pos_create());
// 4) 指向函数的指针
scc_ast_type_t ptr_to_func;
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
SCC_CHECK_AST(&ptr_to_func.base, "int (*(*)(void))[5]",
scc_parse_type_name);
}
TEST_CASE("function returning pointer to function");
// int (*())(void)
{
// 1) 函数类型 int (void)
scc_ast_decl_t void_param;
scc_ast_decl_param_init(&void_param, &void_type, NULL,
scc_pos_create());
scc_ast_decl_vec_t params;
scc_vec_init(params);
scc_vec_push(params, &void_param);
scc_ast_type_t func_type;
scc_ast_type_function_init(&func_type, &int_type, &params,
scc_pos_create());
// 2) 指向该函数的指针
scc_ast_type_t ptr_to_func;
scc_ast_type_pointer_init(&ptr_to_func, &func_type, scc_pos_create());
// 3) 外部函数类型,返回上述指针,无参数
scc_ast_type_t outer_func;
scc_ast_type_function_init(&outer_func, &ptr_to_func, NULL,
scc_pos_create());
SCC_CHECK_AST(&outer_func.base, "int (*())(void)", scc_parse_type_name);
}
}
TEST_LIST = {
{"test_builtin_type", test_builtin_type},
{"test_pointer_type", test_pointer_type},
{"test_array_type", test_array_type},
{"test_function_type", test_function_type},
{"test_struct_union_type", test_struct_union_type},
{"test_enum_type", test_enum_type},
{"test_specifier_type", test_specifier_type},
{"test_hard_type", test_hard_type},
{NULL, NULL},
};

File diff suppressed because it is too large Load Diff