Mojo 编译器早期演进:2022 年 10 月解析器与语言特性里程碑全览
2026/9/11 3:37:16 网站建设 项目流程

Mojo 编译器早期演进:2022 年 10 月解析器与语言特性里程碑全览

【免费下载链接】mojoThe Modular Platform (includes MAX & Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo

本文基于官方发布记录 Mojo/docs/site/releases/2022-10.md 整理而成,系统梳理 Mojo 语言在 2022 年 10 月一个月内完成的解析器(Parser)与编译器前端关键里程碑:从最基础的表达式与赋值语法、作用域处理和函数 IR 生成,到字面量、参数化函数、var变量声明、结构体声明、控制流语句、&expr传引用,直至return None语法糖与完整的表达式运算符体系。读者可借此理解 Mojo 编译器前端(对应仓库中的Mojo/lib/MojoParser)的演进路径,以及今日 Mojo 语法诸多设计(如参数化类型SIMD[dtype, length]index类型、省略self类型等)的历史由来。

一、背景:为什么 2022 年 10 月值得关注

Mojo 是一种面向高性能计算与 AI 基础设施的编程语言,其编译器前端位于仓库的Mojo/lib/MojoParser目录,包含 Lexer.cpp、ParserBase.cpp、ParserStmts.cpp、ParserExprs.cpp、IREmitter.cpp 等核心文件,负责词法分析、语法解析、类型推断与 IR 生成。

2022 年 10 月是 Mojo 编译前端从"能解析极简函数"到"具备现代语言骨架"的密集开发期。当月发布记录以周为单位记录了五个里程碑批次,每一批都对应着从零搭建解析器过程中必不可少的能力。理解这段历史,有助于开发者把握 Mojo 语法设计背后的动机,例如:

  • 为什么def函数的参数类型可以省略(当时即被设计为对象类型语义);
  • 为什么成员方法可以省略self的类型标注;
  • 为什么return无表达式等价于return None
  • 为什么&expr被引入来表示按引用(by-ref)参数。

下文按时间顺序逐周展开,并尽可能结合当前仓库源码印证这些特性在后续版本中的延续形态。

二、2022-10-03 周:解析器脚手架与函数 IR 生成

本周是当月工作的起点,完成了四项基础能力:

  1. 基础解析器脚手架与初始语法产生式(parser productions),包括平凡表达式(trivial expressions)和赋值表达式的解析规则;
  2. 基础作用域处理与函数 IR 生成,并支持前向声明(forward declarations);
  3. 简单函数的解析,例如def foo(x: Int):已经可以解析;
  4. 内建类型上简单算术表达式(如x + y)的 IR 发射

值得注意的是当时的限制:所有参数类型都被硬编码为 MLIR 的index类型。这意味着当时解析器虽然能接受Int之类的类型标注,但语义上并未建立类型系统,统一按index处理。从当前仓库看,index已演进为 Mojo 的内建整数类型,在文档中被描述为"临时内建类型",广泛用于参数化类型的宽度/长度参数(如width: indexSIMD[dt, width]中的宽度)。

作用域处理与 IR 生成的能力,在今日实现中对应 IREmitter.cpp 与 ParserStmts.cpp 中parseStmtListOrCompoundparseSuite等函数对语句块与作用域的递归管理。

三、2022-10-10 周:字面量与参数化函数

本周聚焦两件事:

  1. 整型、浮点、字符串字面量的解析——这是任何语言解析器的必备基础;
  2. 函数输入参数和结果(输入输出)的解析,首次支持"参数化函数"(parametric functions),即带编译期参数的函数:
def fooparam: Int -> Int: result = param + arg return result

这里的[param: Int]是编译期参数(comptime parameter),与运行时参数(arg: Int)相区分。这是 Mojo 参数化(泛型)能力的最早雏形。参数化函数的编译期求值语义,在后来的设计中逐步深化为系统的 comptime 模型,相关设计可见 Mojo/proposals/comptime-expr.md 提案文档。

四、2022-10-17 周:var 声明、结构体与控制流

本周是语法面扩充最大的一周,共四项重要进展:

1. 显式变量声明var

新增var关键字,用于在函数体内和结构体内声明变量,且支持类型引用:

def foo(lhs: index, rhs: index) -> index: var result: index = lhs + rhs return result

var result: index = lhs + rhs展示了"显式类型标注 + 初始化表达式"的完整声明语法。结构体内var成员(fields)的声明形态也在同周的结构体支持中出现(见下文)。

2.index临时内建类型

文档明确指出index被加入为"临时内建类型"。它在当时承担整数与尺寸索引的双重角色,这一设计延续至今:在今天的 Mojo 中,index仍是参数化类型常用的长度/尺寸参数类型。

3. 结构体声明与类型引用

实现了结构体声明的解析,以及函数中对类型声明的引用:

struct Foo: var member: index def bar(x: Foo, obj) -> index: return x.member

这里展示了两个关键语法决策:

  • 结构体成员用var member: index声明,与函数内局部变量声明语法统一;
  • def中,类型可以省略以表示对象类型(object type),如obj参数。这是 Mojo 后来"动态对象"语义的起点——def函数中的未标注参数被视为对象类型(在早期实现中与 PythonObject 密切相关)。

4.if语句与while循环

解析器首次支持两种核心控制流语句:

def if_stmt(c: index, a: index, b: index) -> index: var result: index = 0 if c: result = a else: result = b return result def while_stmt(init: index): while init > 1: init = init - 1

if/else的分支结构与while循环的语句块解析,在今日的 ParserStmts.cpp 中分别由parseIfStmt类逻辑与循环语句解析逻辑承担(文件中存在针对循环体内错误处理的inLoopBody/inLoopStmt区分)。

5. 错误发射与处理显著改进

同周还"显著改进了错误发射与处理",使解析器可以在解析一个文件时同时发射多个错误(multi-error emission),而不是遇到第一个错误就停止。这是提升开发者体验的重要基础能力。当前解析器中错误报告依赖 ParserBase.h 中emitError/emitTokenError体系,可携带词法位置(llvm::SMLoc)并支持 InflightDiag 风格的增量诊断,正是这一方向的延续。

五、2022-10-24 周:右结合性、一元运算与传引用

本周标志着表达式语法与类型系统的关键突破:

1. 右结合性与一元运算符

解析器新增对右结合(right-associativity)与一元运算(unary ops)的支持,例如幂运算符a ** b ** c(从右向左结合)与取负运算符-a。优先级与结合性的处理,在 ParserExprs.cpp 中有完整实现,例如:

  • Precedence::kPowerExprNode::kPow对应幂运算(见 ParserExprs.cpp 附近);
  • getUnaryOpInfo根据 token 种类返回一元运算信息,alloc<UnaryOpNode>构建一元运算节点(见 ParserExprs.cpp 附近)。

2.&expr:显式传引用

新增对&expr的支持,用于在函数中标注按引用(by-ref)参数。文档特别解释了引入原因:结构体方法的self类型隐式是指针,因此需要&语法来显式表达引用语义。这一设计正是 Mojo 后来"传引用与借用"体系(对应borrowed/inout/owned等参数约定)的直接前身。

3. 参数化函数声明

实现了参数化函数声明的完整形态——参数化类型SIMD结构体与参数化函数fancy_add

struct SIMD[dt: DType, width: index]: fn struct_method(self: &SIMD[dt, width]): pass def fancy_adddt: DType, width: index -> index: return width

这段示例同时体现了三个重要特性:

  • 结构体可携带编译期参数[dt: DType, width: index]
  • 成员方法中self: &SIMD[dt, width]展示了&传引用语法在方法签名中的应用;
  • 参数化函数可对参数化类型做编译期多态。

从当前仓库看,SIMD已发展为 Mojo 标准库的核心内建类型,其现代声明为struct SIMDdtype: DType, length: SIMDLength,见 Mojo/stdlib/std/builtin/simd.mojo,而DType是定义在 Mojo/stdlib/std/builtin/dtype.mojo 中的数据结构类型。2022 年 10 月示例中的dt: DType, width: index与现代的dtype: DType, length: SIMDLength一脉相承(宽度参数类型从index演进为专门的SIMDLength)。

六、2022-10-31 周:return 语法糖、表达式补全与省略 self

当月收尾周完成三项收口工作:

1.return无表达式 =return None

修订了return的处理:不带表达式的return语句是return None的语法糖,使隐式返回None的函数可以更简洁地提前退出:

def just_return(): return

这一设计保证了"提前返回"与"函数末尾隐式返回None"语义一致,同时让无返回值函数(def)的提前退出写法更干净。在现代 Mojo 中,None是表示空值的内建类型,return无表达式的语义与 2022 年 10 月的这一决策保持一致。

2. 更多表达式解析支持

新增解析以下表达式类别:

  • if-else 表达式(条件表达式);
  • 位运算运算符(bitwise operators);
  • 移位运算符(shift operators);
  • 比较运算(comparisons);
  • 整除(floor division);
  • 取余(remainder);
  • 矩阵乘法(matmul,即@运算符)。

至此,Mojo 表达式的运算符体系基本成型,为后续标准库与数值计算库(如张量算子)提供了语法基础。

3.self参数类型可省略

成员方法的self参数类型现在可以省略。也就是说,之前必须写fn struct_method(self: &SIMD[dt, width]),此后可以直接写fn struct_method(self),编译器自行推断self的类型。这一改动显著简化了方法定义,与现代 Mojo 中fn foo(self)的写法完全一致。

七、从 2022 年 10 月回望:里程碑的意义

将五周工作放在一起看,可以清晰识别出 Mojo 语言早期的演进主线:

周次核心能力对今日语法的意义
10-03解析器脚手架、作用域、函数 IR、算术表达式编译器前端骨架;index类型起源
10-10整型/浮点/字符串字面量;参数化函数泛型/编译期参数的雏形
10-17var声明、结构体、if/while、多错误发射变量、类型与控制的语法基石
10-24右结合、一元运算、&expr、参数化声明运算符优先级体系;传引用语义
10-31return None语法糖、完整表达式集、省略self现代 Mojo 方法定义的直接来源

这些语法决策在随后的版本中持续演进:index演化为内建整数类型;&expr发展为完整的引用/借用参数约定体系;参数化函数演进为今日标准库中SIMD[dtype: DType, length: SIMDLength](见 simd.mojo)这样的内建参数化类型;解析器的错误处理则沉淀为 ParserBase.h 中带词法位置的多错误诊断体系。

对于希望深入理解 Mojo 编译器前端的读者,可以从 Mojo/lib/MojoParser 目录入手,重点阅读:

  • Lexer.cpp:词法分析,token 划分与字面量识别;
  • ParserBase.h:解析器公共基础设施与错误报告;
  • ParserStmts.cpp:语句级解析(varifwhilereturn等);
  • ParserExprs.cpp:表达式解析与运算符优先级/结合性;
  • IREmitter.cpp:从 AST 到 MLIR IR 的发射。

一言以蔽之,2022 年 10 月是 Mojo 从"概念验证"走向"可编程语言"的分水岭:当月完成的表达式、控制流、结构体、参数化与引用语义,构成了此后 Mojo 全部语言能力的地基。

【免费下载链接】mojoThe Modular Platform (includes MAX & Mojo)项目地址: https://gitcode.com/GitHub_Trending/mo/mojo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询