Violet 是一个 Swift <-> Python 互操作的东西,只不过这次我们是从头开始实现整个语言。名字来源于 Violet Evergarden(紫罗兰永恒花园)。
为了这个项目,我们看了很多 没看完的 韩剧 好几个 小时,所以 如果 您能给个 ⭐,我们将非常感谢。
如果有什么地方不工作,您有什么有趣的 idea,或者只是有个问题,您可以发起一个 issue 或讨论。您也可以在 Twitter 上联系我们 @itBrokeAgain (乐观,耶!)。
BigInt 和哈希make test 和 make pytestswift:latest (5.6.0) - 使用 make docker-test 和 make docker-pytestswift:5.3.2 - 使用 make docker-test-old 和 make docker-pytest-old整个 Violet 是在 2014 年的 rMBP (最低配置:8GB 内存 + 128 GB 存储) 上编写的,所以可以肯定地说没有其他需求。
我们的目标是兼容 Python 3.7 的特性集。
我们只对语言本身感兴趣,不涉及额外的模块。这意味着除了最基本的模块 (sys, builtins 和一些其他模块) 之外,不支持导入任何其他东西 (虽然你可以导入其他 Python 文件)。
请查看 Documentation 目录,了解已知未实现的特性列表。 不过,没有未知未实现的特性列表……
垃圾回收 是一个很棒的特性。 目前,我们分配对象,但唯一可以释放它们的方法是调用 py.destroy(),它会销毁整个 Python 上下文 (以及它拥有的所有对象)。
顺便说一句,请记住使用 with 语句 来管理资源,不要依赖对象的生命周期 (特别是对于文件描述符)。
尾部分配的 tuples。 目前,我们将 tuple 元素存储在 Swift 数组中 (elements: [PyObject])。 更好的主意是在元组之后分配更多空间,并将元素存储在那里 (这在 C 中称为 flexible array member (灵活数组元素))。 这可以节省一个指针间接寻址,并且对缓存更好,因为我们可以将一些第一个元素放在与 type, __dict__ 等相同的行中。我们也可以对其他不可变容器类型执行此操作。
str - 目前是原生 Swift String。 这将迫使我们实现自己的 String 类型 - 不难,但需要很多时间。int - 目前是我们自己的 BigInt 实现 (它确实将 Int32 范围内的值存储在指针内部)。您可以浏览所有模块导出 - open/public 声明 - 这里 (由 Ariel 生成)。
核心模块
NonEmptyArray, SourceLocation, SipHash, trap 和 unreachable 之类的东西。BigInt 类型的所有预期操作,但实际上它主要关注小整数的性能 - Python 只有一个 int 类型,并且小数字最常见。Int32 的联合 (通过 tagged pointer(标签指针)) (称为 Smi, 之后是 V8) 和堆分配 (幅度 + 符号表示),带有 ARC 用于垃圾回收。 << 真是令人头大 💤BigInt 模块。 数字很难,并且由于某种原因,人类决定“除法”是一回事。Foundation.FileManager 版本。Violet
Lexer)转换为 抽象语法树 (AST)。AST 类型定义由 Elsa 模块从 Elsa definitions/ast.letitgo 生成。enum Instruction 2 字节。 有一些有趣的案例,例如 .formatValue(conversion: StringConversion, hasFormat: Bool) (其中 StringConversion 是一个有 4 个可能值的 enum),但编译器应该处理它。labels 数组)。Elsa 模块从 Elsa definitions/opcodes.letitgo 生成。CodeObjectBuilder 创建 CodeObjects (哇……多么令人惊讶!)。Parser.AST 转换为 Bytecode.CodeObject。Py 代表 Python 上下文。 常见用法:py.newInt(2) 或 py.add(lhs, rhs)。
包含 int, str, list 和 100+ 其他 Python 类型。
Python 对象表示为一个 Swift struct,带有一个单独的 ptr: RawPtr 存储属性。 ptr 指向具有自定义布局的堆分配存储。 布局由 Sourcery 使用 sourcery: storedProperty 注释生成。 阅读 Documentation 目录中的文档!
// sourcery: pytype = int
public struct PyInt: PyObjectMixin {
// sourcery: storedProperty
public var value: BigInt { self.valuePtr.pointee }
public let ptr: RawPtr
}
包含引导 Python 所需的模块:builtins, sys, _imp, _os 和 _warnings。
不包含 importlib 和 importlib_external 模块,因为这些模块是用 Python 编写的。 它们与 CPython 版本略有不同 (我们有 80% 的代码,但只有 20% 的功能 <great-success-meme.gif>)。
PyResult<Wrapped> = Wrapped | PyBaseException 用于错误处理。
Bytecode.CodeObject 中的指令操作 Python 对象,以便输出大致类似于 CPython 的操作。Instruction 的大量 switch。PyTests 目录编写的 Python 测试。工具/支持
Elsa definitions 目录的 .letitgo 文件。Parser.AST 和 Bytecode.Instruction 类型。AST。Violet 中有两种类型的测试
Swift 测试 - 存储在 ./Tests 目录中的标准 Swift 单元测试。 您可以通过在存储库根目录中键入 make test 来运行它们。
如果您不接触 BigInt 和 UnicodeData 模块,您可能想要禁用它们的单元测试。
BigInt - 我们使用 基于属性的测试,这意味着我们测试数百万个输入以检查通用规则是否成立(例如:a+b=c -> c-a=b 等)。 这需要时间,但通过在位运算中发现奇怪的溢出(我们存储“符号 + 幅度”,因此位运算有点难以实现)来弥补自己。UnicodeData
0x11_0000 个值要测试,所以……它并不快。COMBINING VERTICAL LINE ABOVE (U+030d) 是字母数字吗?” (答案:不是。但是您必须注意,因为 HANGUL CHOSEONG THIEUTH (U+1110) 是)。Python 测试 - 存储在 ./PyTests 目录中的用 Python 编写的测试。 您可以通过在存储库根目录中键入 make pytest 来运行它们(还有一个用于发布模式的 make pytest-r)。
当您运行 PyTests 模块时,会执行这些测试。
selfself)也必须指定。Self/类型名称,但不是强制要求。self 🤞。所有这些源代码的破坏都是完全合理的。if 条件引入一个命名变量。if !isPrincess 或 if isDisnepCharacter && isPrincess 是允许的。&& 和 ||,为其中一个创建一个变量。总之,只需使用带有提供的预设的 SwiftLint 和 SwiftFormat(请参阅 .swiftlint.yml 和 .swiftformat 文件)。
“Violet” 基于 MIT 许可证授权。 更多信息请参见 LICENSE 文件。