鹦鹉虚拟机/多态容器 (PMCs)
多态容器 (PMCs) - 以前称为 '鹦鹉魔法饼干' - 是鹦鹉的基本数据类型之一,也是最强大、最灵活的数据类型之一。PMC 非常类似于类对象,具有数据存储和关联的类方法。PMC 包括所有聚合数据类型,包括数组、关联数组(哈希)、异常、结构和对象。鹦鹉带有一套核心 PMC,但可以为特定程序或语言添加新的 PMC。
PMC 用我们称之为“PMC 脚本”的类 C 语言编写并编译。PMC 可以直接内置到鹦鹉中,也可以单独编写并在稍后加载。在运行时加载的 PMC 称为“动态 PMC”,简称为 **DYNPMCs**。
PMC 定义是用一种类 C 语言编写的,该语言使用名为 pmc2c.pl
的特殊 PMC 编译器程序转换为 C 代码。转换为 C 代码后,PMC 将包含在鹦鹉构建过程中。
PMC 编译器 pmc2c.pl
有许多任务要执行。它将 PMC 转换为合法的 C 语法,将函数名插入相应的表中,并将有关 PMC 及其方法的信息导出到鹦鹉系统的其他部分。
用于编写 PMC 的脚本语言基于 C。事实上,它大部分是 C,只是添加了一些额外的关键字和结构。PMC 编译器将 PMC 文件转换为 C 代码以进行编译。所有标准 ANSI C 89 代码都可以在 PMC 文件中使用。这里我们将列出一些添加的内容。
PMC 的所有方法和 vtable 必须包含在 PMC 类声明中
pmclass NAME { }
除了只给出 PMC 的名称外,你还可以指定单一继承
pmclass NAME is SUPERNAME { }
其中 SUPERNAME 是父 PMC 类的名称。在你的 PMC vtable 方法中,你可以使用 SUPER 关键字访问父类的 vtable 方法。
你还可以使用 needs_ext 关键字分配一个名为 PMC_EXT 的额外存储区域。PMC_EXT 是一个额外的结构,可以分配它来帮助进行特殊操作,例如在多个解释器之间共享。如果 PMC 不是自动线程安全的,则应添加 PMC_EXT。
说明符 | 含义 |
---|---|
is SUPERNAME | 指定父类(如果有) |
need_ext | 需要 PMC_EXT 进行特殊处理 |
abstract | 该类是抽象的,不能实例化 |
no_init | PMC 没有 Parrot 可以调用的 init vtable 方法。通常,Parrot 在首次创建 PMC 时会调用 init 方法。如果你不需要它,请使用 no_init 。 |
provides INTERFACE | INTERFACE 是标准接口之一,PMC 可以像使用该类型的对象一样使用。接口是 "array"、"hash" |
与普通的 C 一样,你可以定义额外的函数来帮助进行计算。这些函数应该用普通的 C(没有特殊关键字或值)编写,并且应该在 C<pmclass> 定义之外定义。
PMC 可以使用 ATTR
关键字获得一组自定义的数据字段属性。ATTR 允许扩展 PMC 以包含自定义数据结构,这些数据结构由 Parrot 的内存子系统自动管理。以下是一个示例
pmclass Foo { ATTR INTVAL bar; ATTR PMC baz; ... }
属性存储在自定义数据结构中,可以使用与 PMC 相同的名称的宏访问该结构,但所有字母都大写
Parrot_Foo_attributes * attrs = PARROT_FOO(SELF); attrs->bar = 7; /* it's an INTVAL */ attrs->baz = pmc_new( ... ) /* It's a PMC */
请注意属性结构的类型名称是 Parrot_
,后面跟着 PMC 的名称(大小写与 pmclass
定义中使用的大小写相同),最后是 _attributes
。返回此结构的宏是 PARROT_
,后面跟着 PMC 的名称,所有字母都大写。
VTABLE 接口以及 vtable 中的特定函数可能会在 Parrot 1.0 版本发布之前发生变化。
PMC 可以为任意数量的 VTABLE 接口提供定义。任何未定义的接口都将回退到一个默认实现,该实现会抛出一个错误。VTABLE 接口必须全部遵循预定义的格式,尝试定义不是正常接口之一或不使用与正常接口相同的参数列表和返回值的 VTABLE 接口将抛出一个错误。
所有 VTABLE 和 METHOD 声明的参数可以是 INTVAL、FLOATVAL、STRING 或 PMC,因为这些是 PIR 代码可以传递的唯一值。VTABLE 接口使用 VTABLE 关键字定义,PMC 上的方法可以使用 METHOD 关键字定义。
所有 PMC 都具有标准 API,即它们与所有其他 PMC 共享的接口。这个标准接口被称为 **VTABLE**。VTABLE 是一个包含大约 150 个标准函数的列表,称为“VTABLE 接口”,它们实现了 PMC 的基本、通用行为。所有 PMC 都实现了所有这些接口,尽管如果没有明确提供,它可以从父 PMC 类继承,或者可以默认抛出一个异常。
VTABLE 方法可以通过两种方式之一定义,在 .pmc
中使用类 C 语言的 PMC,或在 PIR 中使用 :vtable
函数限定符。VTABLE 对应于可以对任何对象执行的一些基本操作,例如算术、类操作、强制转换操作(到 INTVAL、FLOATVAL、STRING 或 PMC)以及其他常见操作。无论 VTABLE 方法是如何定义的,它们都必须具有非常特定的名称。
VTABLE 函数都具有固定的名称和参数列表。在实现新的 VTABLE 方法时,必须严格遵守此规定,否则可能会出现几个编译错误和警告。有关所有 vtable 方法及其预期函数签名的列表,你可以查看头文件 /include/parrot/vtables.h
。
在 VTABLE 方法内部,可以使用几个可用的关键字
- SELF
- 当前 PMC
- INTERP
- 鹦鹉解释器
- SUPER
- 父 PMC 类。
你也可以使用标准点表示法引用当前 PMC 的其他方法或 vtable 方法,例如
SELF.VTABLE_OR_METHOD_NAME()
如果您想将所有或部分处理默认到超类(如果您有超类),您可以使用 SUPER() 函数来实现。任何您未实现的 vtable 方法将自动默认到超类(如果有)或默认父类。
除了 VTABLE 之外,PMC 还可以提供一系列名为方法的自定义接口函数,以提供额外的功能。请注意,方法不会像 VTABLE 方法那样集成到 PIR 运算符或 PASM 操作码中。方法可以在单个 PMC 的类 C PMC 脚本中编写,也可以在 PIR 中为用户定义的 PMC 子类编写。
定义方法后,可以使用PCCINVOKE
命令在 PMC 文件中访问它。
所有 vtable 方法的完整列表位于附录中。
- 内置 PMC 附录
- http://www.parrotcode.org/docs/pdd/pdd04_datatypes.html
- http://www.parrotcode.org/docs/pdd/pdd17_pmc.html
- http://www.parrotcode.org/docs/pmc2c.html
- http://www.parrotcode.org/docs/pmc.html