refactor(ast2ir): 移除废弃的ABI依赖并优化类型转换处理

移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。
重构了基本类型解析功能,将parse_base_type函数提取为独立的
scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。

feat(ast2ir): 实现整数常量表达式求值器

新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则,
包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和
类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。

refactor(ast2ir): 完善类型提升和算术转换机制

改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题,
添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。

fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题

修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。
使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了
数组声明的正确性。
This commit is contained in:
zzy
2026-05-31 17:30:22 +08:00
parent c4467b8420
commit d2eafa9dc6
27 changed files with 2579 additions and 218 deletions

View File

@@ -7,6 +7,7 @@ executes the resulting binary, and validates the process return code or stdout.
from __future__ import annotations
import argparse
import difflib
import logging
import os
import subprocess
@@ -23,7 +24,8 @@ from typing import Sequence
# Configuration
# ---------------------------------------------------------------------------
WORKSPACE = Path(__file__).resolve().parent
CC_PATH = WORKSPACE / "../../build/dev/scc"
CC_ROOT = WORKSPACE / "../.."
CC_PATH = CC_ROOT / "build/dev/scc"
CONFIG_PATH = WORKSPACE / "expect.toml"
DEFAULT_TIMEOUT = 1 # seconds
@@ -99,8 +101,15 @@ class Runner:
text=True,
timeout=self.timeout,
)
except subprocess.TimeoutExpired:
return False, "Compilation timed out"
except subprocess.TimeoutExpired as e:
# e.stdout, e.stderr 为已捕获的部分输出(字符串)
captured_stderr = e.stderr.strip() if e.stderr else ""
captured_stdout = e.stdout.strip() if e.stdout else ""
err_msg = f"""Compilation timed out.
stderr: {captured_stderr or '(no output)'}
stdout: {captured_stdout or '(no output)'}
cmd: {" ".join(cmd)}"""
return False, err_msg
except OSError as exc:
return False, f"Failed to invoke compiler: {exc}"
@@ -127,6 +136,26 @@ class Runner:
return proc.returncode, proc.stdout, proc.stderr.strip()
def _print_diff(self, expected: str, actual: str) -> None:
"""Print unified diff between expected and actual stdout."""
expected_lines = expected.splitlines()
actual_lines = actual.splitlines()
diff = difflib.unified_diff(
expected_lines, actual_lines,
fromfile='expected', tofile='actual',
lineterm=''
)
# diff = difflib.ndiff(
# expected_lines, actual_lines,
# )
diff_lines = list(diff)
if not diff_lines:
logger.error(" Strings differ but no diff generated?")
return
logger.error(" Diff (expected vs actual):")
for line in diff_lines:
logger.error(" %s", line)
def run_one(self, test: TestCase) -> bool:
"""Run a single test case. Returns True if passed."""
logger.info("Testing %s", test.source)
@@ -157,9 +186,14 @@ class Runner:
if passed:
logger.info(" PASSED")
else:
logger.error(
" FAILED: expected %r, got %r", test.expected, actual
)
if test.test_type == "stdout":
logger.error(" FAILED: stdout mismatch")
self._print_diff(test.expected, actual)
else:
logger.error(
" FAILED: expected return code %r, got %r",
test.expected, actual
)
# 4. Cleanup
self._remove(exe_path)
@@ -326,12 +360,12 @@ def main() -> None:
runner = Runner(
cc=args.cc,
workspace=WORKSPACE,
workspace=CC_ROOT,
timeout=args.timeout,
keep_temps=args.keep_temps,
)
global_timeout = DEFAULT_TIMEOUT * 3
global_timeout = args.timeout * 3
passed, total = runner.run_all(selected, global_timeout)
logger.info("=" * 40)
if global_timeout and total < len(selected):