Violet 是一个 Swift <-> Python 互操作的东西,只不过这次我们是从头开始实现整个语言。名字来源于 Violet Evergarden(紫罗兰永恒花园)。
为了这个项目,我们看了很多 没看完的 韩剧 好几个 小时,所以 如果 您能给个 ⭐,我们将非常感谢。
如果有什么地方不工作,您有什么有趣的 idea,或者只是有个问题,您可以发起一个 issue 或讨论。您也可以在 Twitter 上联系我们 @itBrokeAgain (乐观,耶!)。
BigInt
和哈希make test
和 make pytest
swift:latest
(5.6.0) - 使用 make docker-test
和 make docker-pytest
swift: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
模块时,会执行这些测试。
self
self
)也必须指定。Self
/类型名称
,但不是强制要求。self
🤞。所有这些源代码的破坏都是完全合理的。if
条件引入一个命名变量。if !isPrincess
或 if isDisnepCharacter && isPrincess
是允许的。&&
和 ||
,为其中一个创建一个变量。总之,只需使用带有提供的预设的 SwiftLint 和 SwiftFormat(请参阅 .swiftlint.yml 和 .swiftformat 文件)。
“Violet” 基于 MIT 许可证授权。 更多信息请参见 LICENSE 文件。