feat(ast): 支持 inline def 与 @__attribute__(...) 语法糖(均 desugar 到既有装饰器)
- parser.vp:新增 inline 修饰符(软关键字,语句起始 + 后随函数定义时生效),合成 @t.attr.always_inline;inline 不进关键字表,作标识符的既有写法不受影响 - parser.vp:新增 @__attribute__(section(...), always_inline) desugar ⇒ @c.Attribute(t.attr.section(...), t.attr.always_inline);带/不带调用的属性名都支持,class/def 共用装饰器链,产出与手写形态逐字段同形
This commit is contained in:
1 parent
7025982944
commit
622ae03c9f
1 file changed
+182
+182
@@ -611,6 +611,86 @@ def _ParseVirtualModified(ps: rawptr[Parser], parent: rawptr[AST]):
|
||||
parent.append(stmt)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# inline 修饰符(软关键字):`inline def f(...)` ⇒ 合成 @t.attr.always_inline
|
||||
#
|
||||
# 与 virtual/novirtual 完全同构:只在「语句起始 + inline + 紧跟函数定义」时生效,
|
||||
# 其余位置的 inline 仍是普通标识符(故 `inline = 5` / 字段名 inline 等既有写法不受
|
||||
# 影响)。合成的装饰器与**手写** `@t.attr.always_inline` 逐字段同形,下游
|
||||
# FuncGenBase.extract_func_attrs → _append_llvm_attr 的 "always_inline" → LLVM
|
||||
# "alwaysinline" 映射原样复用;StubGen 跨模块 alwaysinline 合并规则同样原样生效。
|
||||
#
|
||||
# 为什么不进关键字表:`inline` 在 TPV/TPC 既有源码里可能是普通标识符,进表会把
|
||||
# 全局词法口径改掉;此处按软关键字文本判定,作用域只限"语句起始后随函数定义"。
|
||||
# ============================================================
|
||||
def _IsInlineModifier(ps: rawptr[Parser]) -> int:
|
||||
"""当前 token 是否为 `inline`(软关键字,且后随函数定义),1=是 / 0=否"""
|
||||
if _cur_type(ps) != TokenType.Name:
|
||||
return 0
|
||||
s: str = _cur_str(ps)
|
||||
if s is None or string.strcmp(s, "inline") != 0:
|
||||
return 0
|
||||
nxt: rawptr[Token] = ps.cur.next
|
||||
if nxt is None or nxt.type != TokenType.Name:
|
||||
return 0
|
||||
nxt2: rawptr[Token] = nxt.next
|
||||
if nxt2 is None:
|
||||
return 0
|
||||
# 后随 def(硬关键字):`inline def f(...)`
|
||||
if nxt.kw_subtype == Keyword.Def:
|
||||
return 1
|
||||
# 后随函数定义软关键字别名(fn/fun/func/function):与 _is_funcdef_kw 同口径
|
||||
# ——必须是 Name + '(' 或 '[T]',避免把 `inline func` 这种普通标识符组合误判。
|
||||
if nxt.kw_subtype == Keyword.Fn or nxt.kw_subtype == Keyword.Fun \
|
||||
or nxt.kw_subtype == Keyword.Func or nxt.kw_subtype == Keyword.Function:
|
||||
if nxt2.type == TokenType.Op \
|
||||
and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _MakeInlineMarker(ps: rawptr[Parser]) -> rawptr[AST]:
|
||||
"""由当前 inline token 构造标记节点 Attribute(Attribute(Name('t'),'attr'), 'always_inline')
|
||||
|
||||
形态与**手写** `@t.attr.always_inline` 装饰器逐字段同形。取属性名的既有逻辑
|
||||
(FuncGenBase._get_attr_name_from_node)对 Attribute 节点取最外层 attr,
|
||||
故 t.attr.always_inline → "always_inline" → _append_llvm_attr 映射为 LLVM
|
||||
"alwaysinline"。**刻意不用** `@c.Attribute(t.attr.x)` 形态:该形态的提取器
|
||||
要求本源文件 `import c`,而 includes/asm.vp 之类文件没有 import,会静默不内联。
|
||||
"""
|
||||
lineno: int = _cur_lineno(ps)
|
||||
col: int = _cur_col(ps)
|
||||
t_name: rawptr[AST] = Name(ps.pool, "t", ASTCtx.Load)
|
||||
attr_at: rawptr[AST] = Attribute(ps.pool, t_name, "attr", ASTCtx.Load)
|
||||
marker: rawptr[AST] = Attribute(ps.pool, attr_at, "always_inline", ASTCtx.Load)
|
||||
_set_pos(marker, lineno, col, 0, 0)
|
||||
return marker
|
||||
|
||||
|
||||
def _ParseInlineModified(ps: rawptr[Parser], parent: rawptr[AST]):
|
||||
"""`inline def f(...)`:消费 inline,合成 @t.attr.always_inline 后交给 _parse_funcdef"""
|
||||
marker: rawptr[AST] = _MakeInlineMarker(ps)
|
||||
if marker is None:
|
||||
return
|
||||
_advance(ps) # 消费 inline 修饰符
|
||||
# 合并既有装饰器(`@deco` + inline def 组合),标记追加在末尾;位置无关
|
||||
# (下游按装饰器名判定)。与 _ParseVirtualModified 同一套 pending_decorators 通道。
|
||||
merged: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8)
|
||||
if merged is None:
|
||||
return
|
||||
if ps.pending_decorators is not None:
|
||||
dn: sizet = len(ps.pending_decorators)
|
||||
di: sizet = 0
|
||||
while di < dn:
|
||||
merged.append(ps.pending_decorators.get(di))
|
||||
di += 1
|
||||
merged.append(marker)
|
||||
ps.pending_decorators = merged
|
||||
stmt: rawptr[AST] = _parse_funcdef(ps, 0)
|
||||
if stmt is not None:
|
||||
parent.append(stmt)
|
||||
|
||||
|
||||
def _IsBareDescriptor(ps: rawptr[Parser]) -> int:
|
||||
"""裸用描述符判定:整条语句只有一个描述符串(const[: volatile]),1=是 / 0=否。
|
||||
|
||||
@@ -2469,6 +2549,12 @@ def _parse_statement_into(ps: rawptr[Parser], parent: rawptr[AST]):
|
||||
if _IsVirtualModifier(ps) != 0:
|
||||
_ParseVirtualModified(ps, parent)
|
||||
return
|
||||
# inline 修饰符(软关键字):只在"语句起始 + inline + 紧跟函数定义"时生效,
|
||||
# 合成既有装饰器 @t.always_inline 后照常走 def 解析(见 _ParseInlineModified)。
|
||||
# 与 virtual/novirtual 同一位置、同一套 pending_decorators 通道。
|
||||
if _IsInlineModifier(ps) != 0:
|
||||
_ParseInlineModified(ps, parent)
|
||||
return
|
||||
# 类型描述符裸用:整条语句只有 `const` / `volatile`(缺类型)⇒ 响亮失败。
|
||||
# 只在"描述符串后直接换行/文件尾/分号"时命中(软关键字边界),故
|
||||
# `const = 5`(作标识符的赋值)/ `t.attr.const()` 等写法不命中、语义不变。
|
||||
@@ -3908,6 +3994,100 @@ def _parse_match_case(ps: rawptr[Parser]) -> rawptr[AST]:
|
||||
return node
|
||||
|
||||
|
||||
# ============================================================
|
||||
# __attribute__ 装饰器 desugar(C 风格属性书写法)
|
||||
#
|
||||
# @__attribute__(section(".text.wo"), always_inline)
|
||||
# def f(): ...
|
||||
#
|
||||
# 等价于手写 `@c.Attribute(t.attr.section(".text.wo"), t.attr.always_inline)`:
|
||||
# 实参用**无前缀**属性名,逐个 desugar 为 `t.attr.<name>`(带调用时保留实参),
|
||||
# 外层换成 `c.Attribute(...)`。产出的装饰器与手写形态逐字段同形 ⇒
|
||||
# ClassGenBase._has_decorator / FuncGenBase.extract_func_attrs / _append_llvm_attr
|
||||
# 原样识别(零新增判据);也即同时适用于 class 与 def(装饰器链共用本函数)。
|
||||
# 容错:实参已是 `t.attr.X` / `c.Attribute(...)` 形态时原样保留(允许混写)。
|
||||
# ============================================================
|
||||
def _IsMagicAttributeCallee(node: ast.AST*) -> int:
|
||||
"""节点是否为 `__attribute__`(Name 形态,或 X.__attribute__ 的尾段形态)"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "__attribute__") == 0:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "__attribute__") == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _MakeTAttrMarker(ps: rawptr[Parser], arg: ast.AST*) -> ast.AST*:
|
||||
"""把一个 __attribute__ 实参 desugar 为 `t.attr.<name>`(带调用则保留实参)
|
||||
|
||||
- `always_inline`(Name) → `t.attr.always_inline`
|
||||
- `section(".text.wo")`(Call)→ `t.attr.section(".text.wo")`
|
||||
- 已含 `t.attr.X` 形态(value 也是 Attribute)→ 原样返回
|
||||
"""
|
||||
if arg is None:
|
||||
return None
|
||||
k: int = arg.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at0: ast.Attribute* = ast.Attribute*(arg)
|
||||
if at0.value is not None and at0.value.kind() == ast.ASTKind.Attribute:
|
||||
return arg
|
||||
return arg
|
||||
attr_root: ast.AST* = Attribute(ps.pool, Name(ps.pool, "t", ASTCtx.Load),
|
||||
"attr", ASTCtx.Load)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm2: ast.Name* = ast.Name*(arg)
|
||||
if nm2.id is None:
|
||||
return arg
|
||||
mk: ast.AST* = Attribute(ps.pool, attr_root, nm2.id, ASTCtx.Load)
|
||||
_set_pos(mk, nm2.lineno, nm2.col_offset, 0, 0)
|
||||
return mk
|
||||
if k == ast.ASTKind.Call:
|
||||
cl2: ast.Call* = ast.Call*(arg)
|
||||
if cl2.func is None or cl2.func.kind() != ast.ASTKind.Name:
|
||||
return arg
|
||||
fnm: ast.Name* = ast.Name*(cl2.func)
|
||||
if fnm.id is None:
|
||||
return arg
|
||||
inner: ast.AST* = Attribute(ps.pool, attr_root, fnm.id, ASTCtx.Load)
|
||||
_set_pos(inner, fnm.lineno, fnm.col_offset, 0, 0)
|
||||
mk2: ast.AST* = Call(ps.pool, inner, cl2.args, cl2.keywords)
|
||||
_set_pos(mk2, cl2.lineno, cl2.col_offset, 0, 0)
|
||||
return mk2
|
||||
return arg
|
||||
|
||||
|
||||
def _DesugarMagicAttribute(ps: rawptr[Parser], expr: ast.AST*) -> ast.AST*:
|
||||
"""`@__attribute__(...)` → `@c.Attribute(t.attr.x, ...)`;其它装饰器原样返回"""
|
||||
if expr is None or expr.kind() != ast.ASTKind.Call:
|
||||
return expr
|
||||
cl: ast.Call* = ast.Call*(expr)
|
||||
if _IsMagicAttributeCallee(cl.func) == 0:
|
||||
return expr
|
||||
c_func: ast.AST* = Attribute(ps.pool, Name(ps.pool, "c", ASTCtx.Load),
|
||||
"Attribute", ASTCtx.Load)
|
||||
new_args: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8)
|
||||
if new_args is None:
|
||||
return expr
|
||||
if cl.args is not None:
|
||||
an: sizet = len(cl.args)
|
||||
ai: sizet = 0
|
||||
while ai < an:
|
||||
mk: ast.AST* = _MakeTAttrMarker(ps, cl.args.get(ai))
|
||||
if mk is not None:
|
||||
new_args.append(mk)
|
||||
ai += 1
|
||||
new_call: ast.AST* = Call(ps.pool, c_func, new_args, None)
|
||||
_set_pos(new_call, cl.lineno, cl.col_offset, 0, 0)
|
||||
return new_call
|
||||
|
||||
|
||||
def _parse_decorators(ps: rawptr[Parser]) -> rawptr[list[rawptr[AST]]]:
|
||||
"""解析装饰器链,返回 list。"""
|
||||
decs: rawptr[list[rawptr[AST]]] = list[rawptr[AST]](ps.pool, 8)
|
||||
@@ -3916,6 +4096,8 @@ def _parse_decorators(ps: rawptr[Parser]) -> rawptr[list[rawptr[AST]]]:
|
||||
col: int = _cur_col(ps)
|
||||
_advance(ps) # @
|
||||
expr: rawptr[AST] = _parse_namedexpr(ps)
|
||||
# C 风格 `@__attribute__(...)` desugar 成既有的 `@c.Attribute(t.attr.<x>...)`
|
||||
expr = _DesugarMagicAttribute(ps, expr)
|
||||
_skip_nl(ps)
|
||||
if _cur_type(ps) == TokenType.NewLine:
|
||||
_advance(ps)
|
||||
|
||||
Reference in new issue
Block a user