From a6444a4e1fbfa3df19d5739d4bacc484d83921dd Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 9 Aug 2026 17:10:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(includes):=20=E8=BD=AF=E5=85=B3=E9=94=AE?= =?UTF-8?q?=E5=AD=97=20fn/fun/func/function=20=E4=B8=8E=20match=20?= =?UTF-8?q?=E8=AF=AD=E5=8F=A5=E5=88=A4=E5=AE=9A;=20=E8=A7=A3=E6=9E=90=20fa?= =?UTF-8?q?il-fast=20=E9=94=99=E8=AF=AF=E8=AE=B0=E5=BD=95(get=5Fparse=5Fer?= =?UTF-8?q?r=5F*)=20+=20=E7=9B=B8=E9=82=BB=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E5=AD=97=E9=9D=A2=E9=87=8F=E9=9A=90=E5=BC=8F=E6=8B=BC=E6=8E=A5?= =?UTF-8?q?;=20ord/chr=20=E5=86=85=E7=BD=AE=E5=87=BD=E6=95=B0;=20llvmlite?= =?UTF-8?q?=20build=5Falloca=5Faligned;=20memhub=20=E8=B6=85=E5=9D=97?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E8=BF=94=E5=9B=9E=20NULL;=20numpy=20?= =?UTF-8?q?=E6=98=BE=E5=BC=8F=20string./stdio.=20=E5=89=8D=E7=BC=80;=20thi?= =?UTF-8?q?s=20=E6=95=B0=E7=BB=84=E8=BF=AD=E4=BB=A3=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/ast/__init__.vp | 1 + includes/ast/parser.vp | 252 +++++++++++++++++++++++++++++++-- includes/ast/tokens.vp | 10 ++ includes/builtins.vp | 11 ++ includes/llvmlite/__builder.vp | 29 +++- includes/llvmlite/__init__.vp | 2 +- includes/memhub.vp | 9 +- includes/numpy/__init__.vp | 42 +++--- includes/this.vp | 2 +- 9 files changed, 320 insertions(+), 38 deletions(-) diff --git a/includes/ast/__init__.vp b/includes/ast/__init__.vp index a02ac6d..d5509fa 100644 --- a/includes/ast/__init__.vp +++ b/includes/ast/__init__.vp @@ -53,6 +53,7 @@ from .lexer import Lexer, _lexer_init, tokenize, new_lexer from .parser import Parser, _parser_init, parse_tokens, new_parser from .parser import _parse_test from .parser import _dbg_lookup_lit_val, _dbg_lit_found +from .parser import get_parse_err_line, get_parse_err_col, get_parse_err_msg # ============================================================ # Global Memory Pool Pointer (follows project rules: declare _mbuddy) diff --git a/includes/ast/parser.vp b/includes/ast/parser.vp index 2a114f4..e6c8e66 100644 --- a/includes/ast/parser.vp +++ b/includes/ast/parser.vp @@ -93,6 +93,110 @@ def _cur_kw(ps: Parser | t.CPtr) -> t.CInt: return ps.cur.kw_subtype +def _is_funcdef_kw(ps: Parser | t.CPtr, kw: t.CInt) -> int: + """判断当前 token 是否为函数定义关键字(def 及其别名 fn/fun/func/function) + + def 是硬关键字直接判定;fn/fun/func/function 是软关键字, + 仅当下一个 token 是 Name 且再下一个是 '('(或泛型 '[T]' 前的 '[')时 + 判定为函数定义。否则按普通标识符处理,兼容既有代码把 func 用作 + 字段/参数名(如 AST 节点 func 字段、Call.func 注解 `func: AST | t.CPtr`)。 + """ + if kw == Keyword.Def: + return 1 + if kw == Keyword.Fn or kw == Keyword.Fun \ + or kw == Keyword.Func or kw == Keyword.Function: + # 软关键字 lookahead: 下个是 Name,再下个是 '(' 或 '[T...]' 泛型参数(PEP 695) + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type != TokenType.Name: + return 0 + nxt2: Token | t.CPtr = nxt.next + if nxt2 is None: + return 0 + if nxt2.type == TokenType.Op \ + and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + return 1 + return 0 + return 0 + + +def _is_match_stmt(ps: Parser | t.CPtr) -> int: + """match 是软关键字(CPython 3.10+):lookahead 判断是否为 match 语句 + + match 后直接跟 ':'(变量注解,如 lexer.vp 的 `match: t.CInt = 1`)、 + '='(赋值,如 `match = 0`)、换行/文件尾 → 按普通标识符; + 否则扫描至行尾,在括号深度 0 处出现 ':' → match 语句(subject 后必须冒号)。 + case/type 同理为软关键字(case 仅在 match 套件内消费,type 无语句分发)。 + """ + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: + return 0 + if nxt.type == TokenType.Op: + if nxt.op_subtype == TokOp.Colon: + return 0 + if nxt.op_subtype == TokOp.Equal: + return 0 + walk: Token | t.CPtr = nxt + depth: t.CInt = 0 + while walk is not None: + if walk.type == TokenType.NewLine or walk.type == TokenType.EndMarker: + return 0 + if walk.type == TokenType.Op: + wop: t.CInt = walk.op_subtype + if wop == TokOp.LPar or wop == TokOp.Lsqb or wop == TokOp.LBrace: + depth += 1 + elif wop == TokOp.RPar or wop == TokOp.Rsqb or wop == TokOp.RBrace: + if depth > 0: + depth -= 1 + elif wop == TokOp.Colon and depth == 0: + return 1 + walk = walk.next + return 0 + + +# 解析错误位置与消息(fail-fast 仿 Python SyntaxError 报告,首次错误记录) +_g_parse_err_line: t.CInt = 0 +_g_parse_err_col: t.CInt = 0 +_g_parse_err_msg: str = None + + +def _record_parse_err(ps: Parser | t.CPtr): + """记录首个解析错误的位置与消息(只记录第一次,后续错误不覆盖)""" + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = _cur_lineno(ps) + _g_parse_err_col = _cur_col(ps) + err_s: str = _cur_str(ps) + if err_s is None: + err_s = "(none)" + # 消息文本用 stdlib 拷贝(token 的 str_val 在 pool 中,生命周期覆盖本次编译但保险起见独立存储) + buf_m: str = stdlib.malloc(128) + if buf_m is not None: + stdio.snprintf(buf_m, 128, "意外的 token '%s'", err_s) + _g_parse_err_msg = buf_m + else: + _g_parse_err_msg = err_s + + +def get_parse_err_line() -> t.CInt: + """获取最近一次解析错误的行号(0=无错误)""" + return _g_parse_err_line + + +def get_parse_err_col() -> t.CInt: + """获取最近一次解析错误的列号(0=无错误)""" + return _g_parse_err_col + + +def get_parse_err_msg() -> str: + """获取最近一次解析错误的错误消息(仿 Python SyntaxError 消息文本)""" + return _g_parse_err_msg + + def _cur_str(ps: Parser | t.CPtr) -> str: if ps.cur is None: return None return ps.cur.str_val @@ -128,6 +232,7 @@ def _expect_type(ps: Parser | t.CPtr, ttype: t.CInt) -> t.CInt: if _cur_type(ps) == ttype: _advance(ps) return 1 + _record_parse_err(ps) ps.error_count += 1 return 0 @@ -137,6 +242,7 @@ def _expect_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id: _advance(ps) return 1 + _record_parse_err(ps) ps.error_count += 1 return 0 @@ -187,9 +293,6 @@ def _new_const_float(pool: memhub.MemManager | t.CPtr, val: t.CDouble, _g_dbg_pts[_g_dbg_cnt] = t.CUInt64T(new_c) _g_dbg_vals[_g_dbg_cnt] = val _g_dbg_cnt += 1 - # NEWF-DBG: 打印浮点常量构造值+节点指针+存储后读回(定位浮点 CDefine 值错误) - stdio.printf("[NEWF-DBG] val=%.17g ptr=%p readback=%.17g int_val=%lld\n", - val, t.CSizeT(new_c), new_c.float_val, new_c.int_val) return new_c @@ -387,6 +490,7 @@ def _parse_or_test(ps: Parser | t.CPtr) -> AST | t.CPtr: values.append(left) while _cur_kw(ps) == Keyword.Or: _advance(ps) + _skip_nl(ps) # 括号内跨行: a or\n b right: AST | t.CPtr = _parse_and_test(ps) if right is None: break values.append(right) @@ -405,6 +509,7 @@ def _parse_and_test(ps: Parser | t.CPtr) -> AST | t.CPtr: values.append(left) while _cur_kw(ps) == Keyword.And: _advance(ps) + _skip_nl(ps) # 括号内跨行: a and\n b right: AST | t.CPtr = _parse_not_test(ps) if right is None: break values.append(right) @@ -440,6 +545,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: if op_id == OpKind.NoneOp: return left _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行: a ==\n b right: AST | t.CPtr = _parse_bitor(ps) # Single comparison: construct ops and comparators list ops: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) @@ -460,6 +566,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: cur_left: AST | t.CPtr = right while next_op != OpKind.NoneOp: _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行链式比较 cur_right: AST | t.CPtr = _parse_bitor(ps) ops2: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) ops2.append(next_op) @@ -837,9 +944,30 @@ def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr: is_dquote: t.CInt = ps.cur.kw_subtype & 16 is_char: t.CInt = ps.cur.kw_subtype & 32 _advance(ps) + node: AST | t.CPtr if is_fstr: - return _parse_fstring(ps, sval, lineno, col) - return _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char) + node = _parse_fstring(ps, sval, lineno, col) + else: + node = _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char) + # Python 相邻字符串字面量隐式拼接:"a" "b" → "ab" + # Nl 是括号内换行 token(允许括号内跨行拼接);语句级换行是 NewLine,不跳过 + while True: + _skip_nl(ps) + if _cur_type(ps) != TokenType.String: + break + n_sval: str = _cur_str(ps) + n_fstr: t.CInt = ps.cur.kw_subtype & 4 + n_triple: t.CInt = ps.cur.kw_subtype & 8 + n_dquote: t.CInt = ps.cur.kw_subtype & 16 + n_char: t.CInt = ps.cur.kw_subtype & 32 + _advance(ps) + n_node: AST | t.CPtr + if n_fstr: + n_node = _parse_fstring(ps, n_sval, lineno, col) + else: + n_node = _new_const_str(ps.pool, n_sval, lineno, col, n_dquote, n_triple, n_char) + node = _concat_str_nodes(ps.pool, node, n_node) + return node if _match_op(ps, TokOp.Ellipsis): _advance(ps) @@ -885,10 +1013,12 @@ def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr: break e: AST | t.CPtr = _parse_expr(ps) elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(多行元组) _expect_op(ps, TokOp.RPar) node = Tuple(ps.pool, elts, ASTCtx.Load) _set_pos(node, lineno, col, 0, 0) return node + _skip_nl(ps) # (expr\n) 单表达式括号跨行收尾 _expect_op(ps, TokOp.RPar) # Check for generator expression if _cur_kw(ps) == Keyword.For: @@ -921,6 +1051,7 @@ def _parse_list(ps: Parser | t.CPtr) -> AST | t.CPtr: break e: AST | t.CPtr = _parse_expr(ps) elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(base64.vp 多行列表) _expect_op(ps, TokOp.Rsqb) node = List(ps.pool, elts, ASTCtx.Load) _set_pos(node, lineno, col, 0, 0) @@ -965,6 +1096,7 @@ def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr: v: AST | t.CPtr = _parse_expr(ps) keys.append(k) values.append(v) + _skip_nl(ps) # 末元素无尾逗号时收尾 _expect_op(ps, TokOp.RBrace) node = Dict(ps.pool, keys, values) _set_pos(node, lineno, col, 0, 0) @@ -977,10 +1109,12 @@ def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr: elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) elts.append(first) while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) # 括号内跨行集合字面量 if _match_op(ps, TokOp.RBrace): break e: AST | t.CPtr = _parse_expr(ps) elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾 _expect_op(ps, TokOp.RBrace) node = Set(ps.pool, elts) _set_pos(node, lineno, col, 0, 0) @@ -1005,6 +1139,58 @@ def _parse_sub_expr(ps: Parser | t.CPtr, src: str) -> AST | t.CPtr: return _parse_test(sub_ps) +def _append_str_value(pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr, + node: AST | t.CPtr): + """将字符串节点展开加入 values(JoinedStr 展开其 values,其余直接追加)""" + if node is None: + return + if node.kind() == ASTKind.JoinedStr: + js_val: JoinedStr | t.CPtr = (JoinedStr | t.CPtr)(node) + if js_val.values is not None: + n_v: t.CSizeT = js_val.values.__len__() + i_v: t.CSizeT + for i_v in range(n_v): + values.append(js_val.values.get(i_v)) + else: + values.append(node) + + +def _concat_str_nodes(pool: memhub.MemManager | t.CPtr, + a: AST | t.CPtr, b: AST | t.CPtr) -> AST | t.CPtr: + """合并相邻字符串字面量节点(Python 隐式拼接 "a" "b" → "ab") + + 纯常量字符串直接拼接文本;涉及 f-string(JoinedStr/FormattedValue)时 + 合并到 JoinedStr 的 values 列表。 + """ + if a is None: + return b + if b is None: + return a + # 两个都是常量字符串 → 直接拼接文本 + if a.kind() == ASTKind.Constant and b.kind() == ASTKind.Constant: + ca_c: Constant | t.CPtr = (Constant | t.CPtr)(a) + cb_c: Constant | t.CPtr = (Constant | t.CPtr)(b) + if ca_c.const_kind == CONST_STR and cb_c.const_kind == CONST_STR \ + and ca_c.str_val is not None and cb_c.str_val is not None: + la_c: t.CSizeT = string.strlen(ca_c.str_val) + lb_c: t.CSizeT = string.strlen(cb_c.str_val) + buf_c: str = pool.alloc(la_c + lb_c + 1) + if buf_c is not None: + string.memcpy(buf_c, ca_c.str_val, la_c) + string.memcpy(buf_c + la_c, cb_c.str_val, lb_c + 1) + return _new_const_str(pool, buf_c, a.lineno, a.col_offset, 0, 0, 0) + # 涉及 f-string → 合并到 JoinedStr + values_c: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8) + _append_str_value(pool, values_c, a) + _append_str_value(pool, values_c, b) + if values_c.__len__() == 1: + return values_c.get(0) + node_c: AST | t.CPtr = JoinedStr(pool, values_c) + _set_pos(node_c, a.lineno, a.col_offset, 0, 0) + return node_c + + def _parse_fstring(ps: Parser | t.CPtr, content: str, lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: """Parse f-string content, building JoinedStr or FormattedValue nodes""" @@ -1375,12 +1561,12 @@ def _parse_statement_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): if stmt is not None: parent.append(stmt) return - if kw == Keyword.With or kw == Keyword.Def or kw == Keyword.Class: + if kw == Keyword.With or _is_funcdef_kw(ps, kw) != 0 or kw == Keyword.Class: stmt = _parse_compound(ps) if stmt is not None: parent.append(stmt) return - if kw == Keyword.Match or kw == Keyword.Async: + if (kw == Keyword.Match and _is_match_stmt(ps) != 0) or kw == Keyword.Async: stmt = _parse_compound(ps) if stmt is not None: parent.append(stmt) @@ -1399,7 +1585,45 @@ def _parse_simple_stmt_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): s: AST | t.CPtr = _parse_small_stmt(ps) if s is None: break parent.append(s) + # 先跳过 Nl(括号内换行,如多行函数调用参数间的换行,属合法 token) _skip_nl(ps) + # 语句结束检查:simple_stmt 必须以换行/文件尾结束。 + # 残留 token(如相邻表达式 `func12344444 avg3(...)` 被静默拆成多条语句、 + # `def` 缺失的关键字函数定义残留)是语法错误(fail-fast),禁止静默, + # 并仿 Python 报告错误位置(SyntaxError at line/col)。 + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + err_str: str = _cur_str(ps) + if err_str is None: + err_str = "(none)" + # 定位:从链表头找 cur,记录前一个 token 与下一个 token 的上下文 + prev_tok: Token | t.CPtr = None + walk_tok: Token | t.CPtr = ps.tokens + while walk_tok is not None and walk_tok is not ps.cur: + prev_tok = walk_tok + walk_tok = walk_tok.next + pv_str: str = "(head)" + pv_line: t.CInt = 0 + pv_col: t.CInt = 0 + if prev_tok is not None: + pv_str = prev_tok.str_val + pv_line = prev_tok.lineno + pv_col = prev_tok.col_offset + nxt_tok: Token | t.CPtr = ps.cur.next + nxt_str: str = "(none)" + nxt_line: t.CInt = 0 + nxt_col: t.CInt = 0 + if nxt_tok is not None: + nxt_str = nxt_tok.str_val + nxt_line = nxt_tok.lineno + nxt_col = nxt_tok.col_offset + stdio.printf("[AST] SyntaxError: line %d col %d (end %d %d), 意外的 token '%s' (type=%d) | prev='%s' (line %d col %d) | next='%s' (line %d col %d)\n", + _g_parse_err_line, _g_parse_err_col, ps.cur.end_lineno, ps.cur.end_col_offset, + err_str, _cur_type(ps), + pv_str, pv_line, pv_col, + nxt_str, nxt_line, nxt_col) + ps.error_count += 1 + return if _cur_type(ps) == TokenType.NewLine: _advance(ps) @@ -1774,13 +1998,13 @@ def _parse_compound(ps: Parser | t.CPtr) -> AST | t.CPtr: return _parse_try(ps) if kw == Keyword.With: return _parse_with(ps, 0) - if kw == Keyword.Def: + if _is_funcdef_kw(ps, kw) != 0: return _parse_funcdef(ps, 0) if kw == Keyword.Class: return _parse_classdef(ps) if kw == Keyword.Async: _advance(ps) - if _cur_kw(ps) == Keyword.Def: + if _is_funcdef_kw(ps, _cur_kw(ps)) != 0: return _parse_funcdef(ps, 1) if _cur_kw(ps) == Keyword.For: return _parse_for(ps, 1) @@ -1788,7 +2012,7 @@ def _parse_compound(ps: Parser | t.CPtr) -> AST | t.CPtr: return _parse_with(ps, 1) ps.error_count += 1 return None - if kw == Keyword.Match: + if kw == Keyword.Match and _is_match_stmt(ps) != 0: return _parse_match(ps) ps.error_count += 1 return None @@ -2460,9 +2684,17 @@ def parse_tokens(pool: memhub.MemManager | t.CPtr, """Parse an AST Module from a token list.""" if pool is None or tokens is None: return None + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + _g_parse_err_line = 0 + _g_parse_err_col = 0 + _g_parse_err_msg = None ps: Parser | t.CPtr = new_parser(pool) if ps is None: return None _parser_init(ps, tokens, pool) module_node: Module | t.CPtr = Module(pool) _parse_module_body(ps, module_node) + # fail-fast: 解析出错(error_count > 0)时返回 None,由调用方(TPV 等)报错终止, + # 避免错误代码静默编译(如 `func12344444 avg3(...)` 缺 def 关键字的函数定义残留)。 + if ps.error_count > 0: + return None return module_node diff --git a/includes/ast/tokens.vp b/includes/ast/tokens.vp index c0addb7..5f4fc29 100644 --- a/includes/ast/tokens.vp +++ b/includes/ast/tokens.vp @@ -72,6 +72,11 @@ class Keyword(t.CEnum): Match: t.State Case: t.State Type: t.State + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + Fn: t.State + Fun: t.State + Func: t.State + Function: t.State # ============================================================ @@ -246,6 +251,11 @@ def _init_keywords(pool: memhub.MemManager | t.CPtr): _kw_intern(pool, "match", Keyword.Match) _kw_intern(pool, "case", Keyword.Case) _kw_intern(pool, "type", Keyword.Type) + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + _kw_intern(pool, "fn", Keyword.Fn) + _kw_intern(pool, "fun", Keyword.Fun) + _kw_intern(pool, "func", Keyword.Func) + _kw_intern(pool, "function", Keyword.Function) # ============================================================ diff --git a/includes/builtins.vp b/includes/builtins.vp index ee88700..5296c61 100644 --- a/includes/builtins.vp +++ b/includes/builtins.vp @@ -1,2 +1,13 @@ import t +# ============================================================ +# 内置函数(Python 语义,自动与 builtins 关联,无需显式 import) +# ord: 字符 → ASCII 码(int) +# chr: ASCII 码 → 字符(t.CChar) +# ============================================================ + +def ord(s: t.CChar) -> int: + return s + +def chr(i: int) -> t.CChar: + return i diff --git a/includes/llvmlite/__builder.vp b/includes/llvmlite/__builder.vp index fd8afa5..3899ff3 100644 --- a/includes/llvmlite/__builder.vp +++ b/includes/llvmlite/__builder.vp @@ -125,7 +125,9 @@ def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt: def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: """%N = alloca - 返回类型为 ty* 的 SSA 值 + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 """ if builder is None: return None pool: memhub.MemBuddy | t.CPtr = builder.Pool @@ -145,6 +147,31 @@ def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | return SSAValue(pool, result_ty_ptr, name) +def build_alloca_aligned(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + align: int) -> Value | t.CPtr: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + if builder is None: return None + pool: memhub.MemBuddy | t.CPtr = builder.Pool + name: t.CChar | t.CPtr = _alloc_ssa_name(builder) + ty_s: t.CChar | t.CPtr = _type_str(builder, ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align) + _emit(builder, line) + + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + def build_alloca_at_entry(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: """%N = alloca (在函数入口块生成,确保支配性) diff --git a/includes/llvmlite/__init__.vp b/includes/llvmlite/__init__.vp index 37dc422..162a821 100644 --- a/includes/llvmlite/__init__.vp +++ b/includes/llvmlite/__init__.vp @@ -40,7 +40,7 @@ from .__module import ( from .__builder import ( IRBuilder, new_builder, position_at_end, builder_cur_block_is_terminated, - build_alloca, build_alloca_at_entry, build_load, build_store, + build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store, build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem, build_and, build_or, build_xor, build_shl, build_lshr, build_ashr, build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg, diff --git a/includes/memhub.vp b/includes/memhub.vp index e8d2576..0db8107 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -224,10 +224,11 @@ class MemSlab(MemManager): stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") stdlib.exit(1) if size > self.block_size: - stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") - stdio.printf("[OOM] 尝试分配: %zu 字节,失败(超过 block_size=%zu)\n", size, self.block_size) - stdio.printf("[OOM] 说明: 请求大小超过 MemSlab 块大小,应改用 MemBuddy/MemPool。\n") - stdlib.exit(1) + # 超块大小请求 = 调用方错误:优雅失败返回 NULL(类 malloc 语义,调用方自行判断)。 + # 与 free_list 耗尽(真正的 OOM,打印后 exit(1))区分开。 + stdio.printf("[WARN] MemSlab: 请求 %zu 字节超过 block_size=%zu,分配失败返回 NULL;应改用 MemBuddy/MemPool。\n", + size, self.block_size) + return None block: t.CVoid | t.CPtr = self.free_list self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) self.used_count += 1 diff --git a/includes/numpy/__init__.vp b/includes/numpy/__init__.vp index b06f2e6..f8e5456 100644 --- a/includes/numpy/__init__.vp +++ b/includes/numpy/__init__.vp @@ -44,7 +44,7 @@ class ndarray[T]: self.pool = pool self.data = pool.alloc(n * T.__sizeof__()) if self.data: - memset(self.data, 0, n * T.__sizeof__()) + string.memset(self.data, 0, n * T.__sizeof__()) self.ndim = 1 self.size = n self.shape[0] = n @@ -148,7 +148,7 @@ class ndarray[T]: def copy(self) -> ndarray[T] | t.CPtr: result: ndarray[T] | t.CPtr = _empty_like(self) if not result: return None - memcpy(result.data, self.data, self.size * T.__sizeof__()) + string.memcpy(result.data, self.data, self.size * T.__sizeof__()) return result def reshape(self, new_shape: INTPTR, new_ndim: t.CInt) -> ndarray[T] | t.CPtr: @@ -253,30 +253,30 @@ class ndarray[T]: def print_arr(self): if self.ndim == 1: - printf("[") + stdio.printf("[") i: t.CSizeT = 0 while i < self.size: - if i > 0: printf(", ") - printf("%.4f", self.data[i]) + if i > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i]) i += 1 - printf("]\n") + stdio.printf("]\n") elif self.ndim == 2: rows: t.CSizeT = self.shape[0] cols: t.CSizeT = self.shape[1] - printf("[") + stdio.printf("[") i: t.CSizeT = 0 while i < rows: - if i > 0: printf(" ") - printf("[") + if i > 0: stdio.printf(" ") + stdio.printf("[") j: t.CSizeT = 0 while j < cols: - if j > 0: printf(", ") - printf("%.4f", self.data[i * cols + j]) + if j > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i * cols + j]) j += 1 if i < rows - 1: - printf("]\n") + stdio.printf("]\n") else: - printf("]]\n") + stdio.printf("]]\n") i += 1 @@ -298,7 +298,7 @@ Uint8Array: t.CTypedef = ndarray[t.CUnsignedChar] def _alloc_ndarray(pool: memhub.MemManager | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: a: ndarray[t.CDouble] | t.CPtr = pool.alloc(ndarray[t.CDouble].__sizeof__()) if a: - memset(a, 0, ndarray[t.CDouble].__sizeof__()) + string.memset(a, 0, ndarray[t.CDouble].__sizeof__()) return a def _compute_strides(a: ndarray[t.CDouble] | t.CPtr): @@ -337,7 +337,7 @@ def array(pool: memhub.MemManager | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSize if not a.data: pool.free(a) return None - memcpy(a.data, data, n * t.CDouble.__sizeof__()) + string.memcpy(a.data, data, n * t.CDouble.__sizeof__()) a.pool = pool a.ndim = 1 a.size = n @@ -353,7 +353,7 @@ def zeros(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | if not a.data: pool.free(a) return None - memset(a.data, 0, n * t.CDouble.__sizeof__()) + string.memset(a.data, 0, n * t.CDouble.__sizeof__()) a.pool = pool a.ndim = 1 a.size = n @@ -420,7 +420,7 @@ def empty2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> if not a.data: pool.free(a) return None - memset(a.data, 0, total * t.CDouble.__sizeof__()) + string.memset(a.data, 0, total * t.CDouble.__sizeof__()) a.pool = pool a.ndim = 2 a.size = total @@ -669,8 +669,8 @@ def concatenate(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) total: t.CSizeT = a.size + b.size result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, total) if not result: return None - memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) - memcpy(result.data + a.size, b.data, b.size * t.CDouble.__sizeof__()) + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + string.memcpy(result.data + a.size, b.data, b.size * t.CDouble.__sizeof__()) return result def sort_arr(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: @@ -913,7 +913,7 @@ def flatten(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: result.ndim = 1 result.shape[0] = a.size result.strides[0] = 1 - memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) return result def trace(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: @@ -1049,7 +1049,7 @@ def zeros_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: if not result.data: a.pool.free(result) return None - memset(result.data, 0, a.size * t.CDouble.__sizeof__()) + string.memset(result.data, 0, a.size * t.CDouble.__sizeof__()) result.pool = a.pool result.ndim = a.ndim result.size = a.size diff --git a/includes/this.vp b/includes/this.vp index b101f47..8c93b93 100644 --- a/includes/this.vp +++ b/includes/this.vp @@ -29,7 +29,7 @@ Anzrfcnprf ner vaperqvoyl inyhnoyr — hfr gurz trarebhfyl!""" m: t.CArray[t.CChar, 256] = [0] l: t.CArray[int, 2] = [65, 97] - for k in l: + for k in [65, 97]: for i in range(26): m[k + i] = (k + ((i + 13) % 26)) # Implicit type conversion