diff --git a/ast/parser.vp b/ast/parser.vp index 363e884..fc49f9d 100644 --- a/ast/parser.vp +++ b/ast/parser.vp @@ -251,6 +251,40 @@ def _is_typedef(ps: rawptr[Parser]) -> int: return 1 +def _is_export_extern_var(ps: rawptr[Parser]) -> int: + """`export NAME :` / `extern NAME :` 变量声明的软关键字判定(1=是,0=否)。 + + `export` / `extern` 既可用于**函数**声明(`export def f()` / `export f()` / + `extern def f()`,见 `_is_funcdef_kw`),也可用于**变量**声明 + (`export gdt: [7]gdt_entry = []`;`extern a: int`)。二者由第三个 token 区分: + 函数是 `(`(参数表)或 `[`(泛型),变量是 `:`(类型注解)。 + + - `export name(` / `extern def f(`(函数)⇒ 本判据不命中,函数语义逐字不变; + - `export = 5` / `export(x)` / `export.attr`(把 export 当标识符)⇒ 不命中; + - `export NAME:` 后缺类型等非法形态在 `_parse_export_extern_var` 内 + `_record_parse_err` **响亮失败**(非静默)。 + """ + kw: int = _cur_kw(ps) + if kw != Keyword.Export and kw != Keyword.Extern: + return 0 + nxt: rawptr[Token] = ps.cur.next + if nxt is None: + return 0 + if nxt.type != TokenType.Name: + return 0 + # 名字必须是**非关键字**标识符(排除 `export def f()` 之类把关键字当名字的形态) + if nxt.kw_subtype != Keyword.NotKeyword: + return 0 + nxt2: rawptr[Token] = nxt.next + if nxt2 is None: + return 0 + if nxt2.type != TokenType.Op: + return 0 + if nxt2.op_subtype != TokOp.Colon: + return 0 + return 1 + + def _is_match_stmt(ps: rawptr[Parser]) -> int: """match 是软关键字(CPython 3.10+):lookahead 判断是否为 match 语句 @@ -2760,6 +2794,15 @@ def _parse_statement_into(ps: rawptr[Parser], parent: rawptr[AST]): if td_stmt is not None: parent.append(td_stmt) return + # export / extern 变量声明(软关键字):`export NAME: T [= v]` / + # `extern NAME: T`(**不带**初始值)→ 带存储类标记的模块级 AnnAssign + # (见 _parse_export_extern_var)。函数形态(`export NAME(` / + # `extern def NAME(`)被 lookahead 排除,语义逐字不变。 + if _is_export_extern_var(ps) != 0: + ee_stmt: rawptr[AST] = _parse_export_extern_var(ps) + if ee_stmt is not None: + parent.append(ee_stmt) + return # virtual / novirtual 修饰符(软关键字):只在"语句起始 + 紧跟 class/def" # 时生效;合成既有装饰器 @t.CVTable / @t.NoVTable 后照常走 class/def 解析 # (见 _ParseVirtualModified)。放在 class/def 分派之前:修饰符必须先被消费, @@ -3813,6 +3856,75 @@ def _parse_typedef(ps: rawptr[Parser]) -> rawptr[AST]: return node +def _parse_export_extern_var(ps: rawptr[Parser]) -> rawptr[AST]: + """`export NAME: T [= v]` / `extern NAME: T` → 带存储类标记的模块级 AnnAssign。 + + - **export**:注解改写为 `T | t.CExport`,与 `export def` **同一标记、同一消费 + 路径**(定义端裸名,不加模块 SHA1 头——内联汇编 / C 符号对接必需)。 + 允许带初始值;`export tss_buf: [104]uint8`(无初始值)生成零初始化全局定义。 + - **extern**:注解改写为 `T | t.State`(= t.CExtern | t.CExport:仅声明 + 裸名), + 与 `extern def` 同口径。**不允许初始值**(符号定义在外部), + `extern a: int = 1` → `_record_parse_err` **响亮失败**(非静默)。 + + 行号/列号取自 `export`/`extern` 关键字位置,报错回显定位到真实源码行; + 语句必须换行/文件尾结束(与 _parse_typedef / _parse_define_const 同口径)。 + """ + lineno: int = _cur_lineno(ps) + col: int = _cur_col(ps) + is_extern: int = 0 + if _cur_kw(ps) == Keyword.Extern: + is_extern = 1 + _advance(ps) # export / extern + if _cur_type(ps) != TokenType.Name: + # 缺变量名(如 `export : int`):响亮失败。 + _record_parse_err(ps) + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + if _expect_op(ps, TokOp.Colon) == 0: + # 缺 `:`(如 `export x`):响亮失败。 + return None + ann: rawptr[AST] = _parse_type_ann(ps) + if ann is None: + ps.error_count += 1 + _record_parse_err(ps) + return None + # 存储类标记:export → t.CExport(裸名导出);extern → t.State(声明 + 裸名) + storage_attr: rawptr[AST] = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "State" if is_extern != 0 else "CExport", + ASTCtx.Load) + annotation: rawptr[AST] = BinOp(ps.pool, ann, OpKind.BitOr, storage_attr) + value: rawptr[AST] = None + if _match_op(ps, TokOp.Equal): + if is_extern != 0: + # extern 变量是外部定义:本模块不允许带初始值。 + _RecordDescriptorErr("extern 变量声明不能带初始值(符号定义在外部)", + lineno, col) + ps.error_count += 1 + return None + _advance(ps) + value = _parse_test(ps) + if value is None: + ps.error_count += 1 + _record_parse_err(ps) + return None + target: rawptr[AST] = Name(ps.pool, name, ASTCtx.Store) + _set_pos(target, lineno, col, 0, 0) + node: rawptr[AST] = AnnAssign(ps.pool, target, annotation, value, + 1 if value is not None else 0) + _set_pos(node, lineno, col, 0, 0) + _skip_nl(ps) + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + ps.error_count += 1 + return None + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + return node + + def _parse_enumdef(ps: rawptr[Parser]) -> rawptr[AST]: """enum NAME: 语法糖 → 与 `class NAME(t.CEnum):` 逐字段同形的 ClassDef。