常用 RPython 模块¶
内容
此页面列出了 rpython/rlib 中的一些模块,以及一些关于它们可以用于什么的提示。此处的模块将构成 RPython 程序的一些通用的库(因为大多数标准库模块不是 RPython)。大多数这些模块仍然比较粗糙,并且可能会在某些时候发生变化。通常,查看 rpython/rlib/test 中的测试以了解如何使用模块是很有用的。
listsort¶
rpython/rlib/listsort.py 模块包含 timsort 排序算法的实现(列表的 sort 方法不是 RPython)。要使用它,请(全局)通过调用 MySort = listsort.make_timsort_class(lt=my_comparison_func)
创建一个类。还有其他可选参数,但通常您会使用 lt=...
传递一个比较列表中两个对象的函数。您需要为每种“类型”的列表和每个比较函数创建一个类。
MySort
的构造函数接受一个列表作为参数,当调用 MySort
实例的 sort
方法时,该列表将在原地排序。
nonconst¶
rpython/rlib/nonconst.py 模块主要用于测试。 流图构建器 和 注释器 会执行相当多的常量折叠,这在测试中有时并不希望发生。要阻止对某个值的常量折叠,请使用 NonConst
类。 NonConst
的构造函数接受任意值。 NonConst
的实例在注释期间的行为将类似于该值,但不会发生常量折叠。
objectmodel¶
rpython/rlib/objectmodel.py 模块包含各种功能的混合。一些更有用的功能包括
ComputedIntSymbolic
:ComputedIntSymbolic
的实例在注释器中被视为未知值的整数。该值由一个无参数函数确定(该函数需要传递到类的构造函数中)。当后端发出代码时,将调用该函数以确定值。CDefinedIntSymbolic
:CDefinedIntSymbolic
的实例在注释器中也被视为未知值的整数。当发出 C 代码时,它们将由符号的expr
属性表示(这也是构造函数的第一个参数)。r_dict
:- 一个类似 RPython dict 的对象。r_dict 的构造函数接受两个函数:
key_eq
和key_hash
,它们用于比较和散列字典中的条目。 instantiate(cls)
:- 在不调用
__init__
的情况下实例化类cls
。 we_are_translated()
:- 当在 CPython 上运行时,此函数返回
False
,但注释器认为其返回值为True
。因此,它可以用于在 CPython 上执行与翻译后不同的操作。这应该非常谨慎地使用(主要用于优化或调试代码)。 cast_object_to_weakaddress(obj)
:- 返回 obj 的一种“弱引用”,只是没有任何便利性。它返回的弱地址在对象死亡时不会失效,因此您需要自己注意何时对象死亡。使用时要格外小心。
cast_weakadress_to_object(obj)
:- 上一个函数的反函数。如果对象已死亡,则会发生段错误。
UnboxedValue
:- 这是一个类,应该用作携带正好一个整数字段的类的基类。该类应该具有
__slots__
,并且只定义一个条目。翻译后,此类的实例不会被分配,而是由 *带标签的指针* 表示,即最低位设置为 1 的指针。
rarithmetic¶
rpython/rlib/rarithmetic.py 模块包含处理常规 Python 和 RPython 代码中算术代码行为细微差异的功能。大多数功能已在 RPython 说明 中描述。
rbigint¶
rpython/rlib/rbigint.py 模块包含 Python long
类型(它本身在 RPython 中不受支持)的完整 RPython 实现。 rbigint
类包含该实现。要构造 rbigint
实例,请使用静态方法 fromint
、 frombool
、 fromfloat
和 fromdecimalstr
。要转换回其他类型,请使用方法 toint
、 tobool
、 touint
和 tofloat
。由于 RPython 不支持运算符重载,因此 rbigint
的所有特殊方法(通常以“__”开头和结尾)都省略了这些下划线,以提高可读性(因此可以使用 a.add(b)
来添加两个 rbigint 实例)。
rrandom¶
rpython/rlib/rrandom.py 模块包含梅森旋转随机数生成器的实现。它包含一个类 Random
,最重要的是它有一个 random
方法,该方法返回介于 0.0 和 1.0 之间的伪随机浮点数。
rsocket¶
rpython/rlib/rsocket.py 模块包含套接字标准库功能的 RPython 实现,但接口略有不同。Python 套接字 API 的难点在于地址不是“类型良好”的对象:根据地址族,它们是元组、字符串等,这对于 RPython 不合适。相反, rsocket
包含 Address 类的层次结构,采用典型的静态面向对象编程风格。
rstrategies¶
rpython/rlib/rstrategies 模块包含一个库,用于在 RPython 虚拟机中实现存储策略。该库与语言无关且可扩展。更多详细信息和示例可以在 rstrategies 文档 中找到。
streamio¶
rpython/rlib/streamio.py 包含 RPython 流 I/O 实现(由 Guido van Rossum 作为 sio.py 在 CPython 沙箱中启动,作为 Python 3000 中即将推出的新文件实现的原型)。
unroll¶
rpython/rlib/unroll.py 模块最重要的是包含函数 unrolling_iterable
,它包装了一个迭代器。在 RPython 代码中遍历迭代器不会在生成的流图中产生循环,而是会展开循环。
rsre¶
我们用于 PyPy 的正则表达式实现。请注意,它很难在其他语言中重用:在 Python 中,正则表达式首先由标准库中的纯 Python 代码编译成字节码格式。此较低级别的模块仅理解此字节码格式。如果没有完整的 Python 解释器,您就无法将正则表达式语法翻译成字节码格式。(对于仅具有静态正则表达式的有限用例,存在一些技巧:它们可以在翻译期间预编译。或者,您可以想象执行一个 Python 子进程来在运行时翻译正则表达式……)
解析¶
该 rpython/rlib/parsing/ 模块是一个仍在开发中的模块,用于在 RPython 中生成词法分析器和解析器。它目前仍处于高度实验阶段,主要由 Prolog 解释器 使用(尽管使用方式略微不标准)。指定词法分析器/语法的最简单方法是使用正则表达式和简单的 EBNF 格式将其写下来。
正则表达式是使用有限自动机实现的。解析引擎使用 Packrat 解析,它具有 O(n) 的解析时间,但比 LL(n) 和 LR(n) 语法更强大。
正则表达式¶
正则表达式语法主要是 re 模块语法的子集。注意:这与 rlib.rsre 不同。默认情况下,非特殊字符匹配自身。如果连接正则表达式,则结果将匹配单个正则表达式匹配的字符串的连接。
|
R|S
匹配任何既匹配 R 又匹配 S 的字符串。*
R*
匹配 R 的 0 次或多次重复。+
R+
匹配 R 的 1 次或多次重复。?
R?
匹配 R 的 0 次或 1 次重复。(...)
- 可以使用括号对正则表达式进行分组(注意,与 Python 的 re 模块相反,您以后无法匹配此组的内容)。
{m}
R{m}
匹配 R 的正好 m 次重复。{m, n}
R{m, n}
匹配 R 的 m 到 n 次重复(包括 m 和 n)。[]
- 匹配一组字符。要匹配的字符可以按顺序列出。可以使用
-
指定字符范围。例如,[ac-eg]
匹配字符 a、c、d、e 和 g。可以通过以^
开头来反转整个集合。因此 [^a] 匹配除 a 之外的任何内容。
要解析正则表达式并获取其匹配器,可以在 rpython.rlib.parsing.regexparse
模块中使用函数 make_runner(s)
。它返回一个具有 recognize(input)
方法的对象,该方法根据 input
是否匹配字符串返回 True 或 False。
EBNF¶
为了描述词法分析器和语法,rpython.rlib.parsing.ebnfparse
定义了执行此操作的语法。
语法文件包含一系列规则。每个规则要么描述正则表达式,要么描述语法规则。
正则表达式规则具有以下形式
NAME: "regex";
NAME 是正则表达式生成的标记的名称(它必须由大写字母组成),regex
是一个具有上述语法的正则表达式。一个标记名称是特殊情况:名为 IGNORE
的标记将在传递给解析器之前从标记流中过滤掉,因此可用于匹配注释或不重要的空格。
语法规则具有以下形式
name: expansion_1 | expansion_2 | ... | expansion_n;
其中 expansion_i
是非终结符或标记名称的序列
symbol_1 symbol_2 symbol_3 ... symbol_n
这意味着非终结符符号 name
(它必须由小写字母组成)可以扩展为任何扩展。扩展可以由标记名称、非终结符名称或文字的序列组成,文字是带引号的字符串,按字面意思匹配。
一个例子让它更清楚
IGNORE: " ";
DECIMAL: "0|[1-9][0-9]*";
additive: multitive "+" additive |
multitive;
multitive: primary "*" multitive |
primary;
primary: "(" additive ")" | DECIMAL;
此语法描述了涉及加法和乘法的算术表达式的语法。词法分析器生成一系列 DECIMAL 标记或与“+”、“*”、“(”或“)”之一匹配的标记。任何空格都将被忽略。语法生成一个遵循运算符优先级的语法树。例如,表达式 12 + 4 * 5
被解析成以下树
解析树¶
解析过程构建一棵由 Symbol
和 Nonterminal
实例组成的树,前者对应于标记,后者对应于非终结符符号。这两个类都位于 rpython/rlib/parsing/tree.py 模块中。您可以使用 view()
方法 Nonterminal
实例来获取解析树的 pygame 视图。
Symbol
实例具有以下属性:symbol
,它是标记的名称,以及 additional_info
,它是匹配的源。
Nonterminal
实例具有以下属性:symbol
是非终结符的名称,以及 children
,它是子属性的列表。
访问者¶
要为 RPython 的解析树编写树访问者,在 rpython/rlib/parsing/tree.py 中有一个特殊的基类 RPythonVisitor
可供使用。如果您的类使用此类,它将生成一个 dispatch(node)
方法,该方法将调用一个合适的 visit_<symbol>
方法,具体取决于 node
参数。这里 <symbol> 被访问节点的 symbol
属性替换。
为了使访问者成为 RPython,所有访问方法的返回值都需要是相同类型。
树转换¶
如上面算术示例的树所示,默认情况下,解析树包含许多实际上没有传达有用信息的节点。为了去除其中的一些节点,语法格式中有一些支持可以自动创建转换树以删除额外节点的访问者。最简单的转换只是删除节点,但还有更复杂的转换。
这些转换的语法是在非终结符的扩展中用 [… ]、<…> 或 >…< 将符号括起来。
[symbol_1 symbol_2 … symbol_n]¶
这将生成一个转换器,该转换器将完全从树中删除封闭的符号。
示例
IGNORE: " ";
n: "A" [","] n | "A";
解析字符串“A, A, A”得到树
digraph G{ "-1213678004" [label="n"]; "-1213678004" -> "-1213681108"; "-1213681108" [shape=box,label="__0_A\n'A'"]; "-1213678004" -> "-1213681332"; "-1213681332" [shape=box,label="__1_,\n','"]; "-1213678004" -> "-1213837780"; "-1213837780" [label="n"]; "-1213837780" -> "-1213837716"; "-1213837716" [shape=box,label="__0_A\n'A'"]; "-1213837780" -> "-1213839476"; "-1213839476" [shape=box,label="__1_,\n','"]; "-1213837780" -> "-1213839956"; "-1213839956" [label="n"]; "-1213839956" -> "-1213840948"; "-1213840948" [shape=box,label="__0_A\n'A'"]; }转换后,树已删除“,”节点
digraph G{ "-1219325716" [label="n"]; "-1219325716" -> "-1219325844"; "-1219325844" [shape=box,label="__0_A\n'A'"]; "-1219325716" -> "-1219324372"; "-1219324372" [label="n"]; "-1219324372" -> "-1219325524"; "-1219325524" [shape=box,label="__0_A\n'A'"]; "-1219324372" -> "-1219324308"; "-1219324308" [label="n"]; "-1219324308" -> "-1219325492"; "-1219325492" [shape=box,label="__0_A\n'A'"]; }<symbol>¶
这将用 symbol 替换父节点。每个扩展最多可以包含一个用 <…> 括起来的符号,因为父节点显然只能替换一次。
示例
IGNORE: " ";
n: "a" "b" "c" m;
m: "(" <n> ")" | "d";
解析字符串“a b c (a b c d)”得到树
digraph G{ "-1214029460" [label="n"]; "-1214029460" -> "-1214026452"; "-1214026452" [shape=box,label="__0_a\n'a'"]; "-1214029460" -> "-1214028276"; "-1214028276" [shape=box,label="__1_b\n'b'"]; "-1214029460" -> "-1214027316"; "-1214027316" [shape=box,label="__2_c\n'c'"]; "-1214029460" -> "-1214026868"; "-1214026868" [label="m"]; "-1214026868" -> "-1214140436"; "-1214140436" [shape=box,label="__3_(\n'('"]; "-1214026868" -> "-1214143508"; "-1214143508" [label="n"]; "-1214143508" -> "-1214141364"; "-1214141364" [shape=box,label="__0_a\n'a'"]; "-1214143508" -> "-1214141748"; "-1214141748" [shape=box,label="__1_b\n'b'"]; "-1214143508" -> "-1214140756"; "-1214140756" [shape=box,label="__2_c\n'c'"]; "-1214143508" -> "-1214144468"; "-1214144468" [label="m"]; "-1214144468" -> "-1214414868"; "-1214414868" [shape=box,label="__5_d\n'd'"]; "-1214026868" -> "-1214141492"; "-1214141492" [shape=box,label="__4_)\n')'"]; }转换后,树如下所示
digraph G{ "-1219949908" [label="n"]; "-1219949908" -> "-1214026452"; "-1214026452" [shape=box,label="__0_a\n'a'"]; "-1219949908" -> "-1214028276"; "-1214028276" [shape=box,label="__1_b\n'b'"]; "-1219949908" -> "-1214027316"; "-1214027316" [shape=box,label="__2_c\n'c'"]; "-1219949908" -> "-1219949876"; "-1219949876" [label="n"]; "-1219949876" -> "-1214141364"; "-1214141364" [shape=box,label="__0_a\n'a'"]; "-1219949876" -> "-1214141748"; "-1214141748" [shape=box,label="__1_b\n'b'"]; "-1219949876" -> "-1214140756"; "-1214140756" [shape=box,label="__2_c\n'c'"]; "-1219949876" -> "-1219949748"; "-1219949748" [label="m"]; "-1219949748" -> "-1214414868"; "-1214414868" [shape=box,label="__5_d\n'd'"]; }>nonterminal_1 nonterminal_2 … nonterminal_n<¶
这将用其子节点替换节点 nonterminal_1 到 nonterminal_n。
示例
IGNORE: " ";
DECIMAL: "0|[1-9][0-9]*";
list: DECIMAL >list< | DECIMAL;
解析字符串“1 2”得到树
digraph G{ "-1213518708" [label="list"]; "-1213518708" -> "-1213518196"; "-1213518196" [shape=box,label="DECIMAL\n'1'"]; "-1213518708" -> "-1213518260"; "-1213518260" [label="list"]; "-1213518260" -> "-1213520308"; "-1213520308" [shape=box,label="DECIMAL\n'2'"]; }转换后的树如下所示
digraph G{ "-1219505652" [label="list"]; "-1219505652" -> "-1213518196"; "-1213518196" [shape=box,label="DECIMAL\n'1'"]; "-1219505652" -> "-1213520308"; "-1213520308" [shape=box,label="DECIMAL\n'2'"]; }请注意,转换是递归工作的。这意味着以下内容也有效:如果解析字符串“1 2 3 4 5”,则树首先如下所示
digraph G{ "-1213611892" [label="列表"]; "-1213611892" -> "-1213608980"; "-1213608980" [shape=box,label="DECIMAL\n'1'"]; "-1213611892" -> "-1213623476"; "-1213623476" [label="列表"]; "-1213623476" -> "-1213623380"; "-1213623380" [shape=box,label="DECIMAL\n'2'"]; "-1213623476" -> "-1213442868"; "-1213442868" [label="列表"]; "-1213442868" -> "-1213441652"; "-1213441652" [shape=box,label="DECIMAL\n'3'"]; "-1213442868" -> "-1213441332"; "-1213441332" [label="列表"]; "-1213441332" -> "-1213441620"; "-1213441620" [shape=box,label="DECIMAL\n'4'"]; "-1213441332" -> "-1213443060"; "-1213443060" [label="列表"]; "-1213443060" -> "-1213442100"; "-1213442100" [shape=box,label="DECIMAL\n'5'"]; }但是转换后,整个结构坍缩为一个节点,并带有很多子节点。
digraph G{ "-1219430228" [label="列表"]; "-1219430228" -> "-1213608980"; "-1213608980" [shape=box,label="DECIMAL\n'1'"]; "-1219430228" -> "-1213623380"; "-1213623380" [shape=box,label="DECIMAL\n'2'"]; "-1219430228" -> "-1213441652"; "-1213441652" [shape=box,label="DECIMAL\n'3'"]; "-1219430228" -> "-1213441620"; "-1213441620" [shape=box,label="DECIMAL\n'4'"]; "-1219430228" -> "-1213442100"; "-1213442100" [shape=box,label="DECIMAL\n'5'"]; }EBNF 语法格式的扩展¶
EBNF 语法格式有一些扩展,这些扩展实际上只是语法糖,但可以使编写语法更容易。它们是
symbol?
:- 匹配 symbol 的 0 次或 1 次重复。
symbol*
:- 匹配 symbol 的 0 次或多次重复。在树转换后,所有这些重复都是当前 symbol 的子节点。
symbol+
:- 匹配 symbol 的 1 次或多次重复。在树转换后,所有这些重复都是当前 symbol 的子节点。
这些是通过以正确的方式向语法添加更多规则来实现的。例如:语法
s: a b? c;
被转换为如下所示
s: a >_maybe_symbol_0_< c | a c;
_maybe_symbol_0_: b;
语法
s: a b* c;
被转换为如下所示
s: a >_star_symbol_0< c | a c;
_star_symbol_0: b >_symbol_star_0< | b;
语法
s: a b+ c;
被转换为如下所示
s: a >_plus_symbol_0< c;
_plus_symbol_0: b >_plus_symbol_0< | b;
完整示例¶
针对 json 格式 的一个半完整的解析器
STRING: "\\"[^\\\\"]*\\"";
NUMBER: "\-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][\+\-]?[0-9]+)?";
IGNORE: " |\n";
value: <STRING> | <NUMBER> | <object> | <array> | <"null"> |
<"true"> | <"false">;
object: ["{"] (entry [","])* entry ["}"];
array: ["["] (value [","])* value ["]"];
entry: STRING [":"] value;
解析字符串的结果树
{"a": "5", "b": [1, null, 3, true, {"f": "g", "h": 6}]}
如下所示
digraph G{ "-1220061652" [label="对象"]; "-1220061652" -> "-1220127636"; "-1220127636" [label="条目"]; "-1220127636" -> "-1213915636"; "-1213915636" [shape=box,label="STRING\n'a'"]; "-1220127636" -> "-1214251156"; "-1214251156" [shape=box,label="STRING\n'5'"]; "-1220061652" -> "-1220063188"; "-1220063188" [label="条目"]; "-1220063188" -> "-1214253076"; "-1214253076" [shape=box,label="STRING\n'b'"]; "-1220063188" -> "-1220059444"; "-1220059444" [label="数组"]; "-1220059444" -> "-1214253364"; "-1214253364" [shape=box,label="NUMBER\n'1'"]; "-1220059444" -> "-1214254292"; "-1214254292" [shape=box,label="__0_null\n'null'"]; "-1220059444" -> "-1214253268"; "-1214253268" [shape=box,label="NUMBER\n'3'"]; "-1220059444" -> "-1214252596"; "-1214252596" [shape=box,label="__1_true\n'true'"]; "-1220059444" -> "-1220062260"; "-1220062260" [label="对象"]; "-1220062260" -> "-1220060116"; "-1220060116" [label="条目"]; "-1220060116" -> "-1214211860"; "-1214211860" [shape=box,label="STRING\n'f'"]; "-1220060116" -> "-1214210132"; "-1214210132" [shape=box,label="STRING\n'g'"]; "-1220062260" -> "-1220062868"; "-1220062868" [label="条目"]; "-1220062868" -> "-1214211956"; "-1214211956" [shape=box,label="STRING\n'h'"]; "-1220062868" -> "-1214212308"; "-1214212308" [shape=box,label="NUMBER\n'6'"]; }