鹦鹉虚拟机/多态容器 (PMC)
多态容器 (PMC) - 以前称为“鹦鹉魔法饼干” - 是鹦鹉的基本数据类型之一,也是最强大和灵活的数据类型之一。PMC 非常类似于类对象,具有数据存储和关联的类方法。PMC 包括所有聚合数据类型,包括数组、关联数组(哈希)、异常、结构和对象。鹦鹉附带了一组核心 PMC,但可以为特定程序或语言添加新的 PMC。
PMC 是用我们称之为“PMC 脚本”的类似 C 的语言编写并编译的。PMC 可以直接内置到鹦鹉中,也可以单独编写并在以后加载。在运行时加载的 PMC 称为“动态 PMC”,简称 DYNPMC。
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> 定义之外定义。
可以使用 ATTR
关键字为 PMC 提供一组自定义数据字段属性。ATTR 允许 PMC 扩展以包含自定义数据结构,这些数据结构由鹦鹉的内存子系统自动管理。以下是一个示例
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 没有显式提供这些接口,它可以从父 PMC 类继承,或者默认抛出异常。
VTABLE 方法可以通过两种方式定义:在使用类 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 语言脚本中编写,也可以在 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