Chapi —— 一個通用語言元信息轉換器
摘要:來,一起用高效(hard way)的方式學習多種編程語言,Kotlin + Scala、Python、Go、Java、TypeScript、C#。Ada, Delphi, Pascal, ALGOL, ...。
來,一起用高效(hard way)的方式學習多種編程語言,Kotlin + Scala、Python、Go、Java、TypeScript、C#……
Chapi 起源
爲了向開源重構與分析工具 Coca 中提供多語言支持(原先只支持 Java 語言),我又雙叕開始造新的輪子。上個月底嘗試了使用 Antlr 的 Go runtime,但是遇到一系列的挫折加之因爲公司內部的一些項目需要類似的工具,我便開始從 JVM 系的語言中尋找一個合適的選擇。。
結合疫情的影響,我結束了打蒼蠅爲樂的休息時間,在月初(2020.2.1)便啓動了 Chapi 項目的開發,使用的語言是 Kotlin。
在過去的半個月裏,我在這個項目上編寫了大量的代碼,一些有意思的內容、特性如下所示:
kotlinx.serialization
先是重寫了 Coca 的基礎設施中的 AST,再在其基礎上提供了更通用的代碼模型,並添加了不同類型語言的支持:
Features/Languages | Java | Python | Go | Kotlin | TypeScript | C | C# | Scala |
---|---|---|---|---|---|---|---|---|
syntax parse | :white_check_mark: | :white_check_mark: | :white_check_mark: | TBC | :white_check_mark: | TBC | :new: | :new: |
function call graph | :white_check_mark: | |||||||
arch/package graph | :white_check_mark: | |||||||
real world validate | :white_check_mark: |
我在維基百科上看到了一個編程語言的分類,便添加了更多編程語言的支持,以嘗試從不同的語言中構建出統一的代碼的數據模型。
Languages | plan support | |
---|---|---|
Algol | Ada, Delphi, Pascal, ALGOL, ... | Pascal? |
C family | C#, Java, Go, C, C++, Objective-C, Rust, ... | C, Java, C#, Rust? |
Functional | Scheme, Lisp, Clojure, Scala, ... | Scala |
Scripting | Lua, PHP, JavaScript, Python, Perl, Ruby, ... | Python, JavaScript |
Other | Fortran, Swift, Matlab, ... | Swift?, Fortran? |
與 Coca 稍有不同的是,這是一個過程比結果重要的項目。在實現的過程中,慢慢成爲代碼/代碼語法方面的專家。不同的編程語言都有各自獨特的語法,都需要不斷地熟悉相關的語法。
Chapi Core:代碼的模型
在繼續瞭解,讓我們來看看一個項目的結構:
系統(system) - 項目(project) - 源碼(source code) - 包(package) - 類(class) - 函數 - 參數 - 返回類型 - …… - 函數(function) - 對象(object) - 接口(interface) - ……(trait,struct) - 包(package) - 項目信息 - 依賴管理 - 項目(project)
它適用於 Java、TypeScript、Go 等語言,基於此,我們就有了 Chapi 的基礎的數據結構:
// for multiple project analysis code_project code_module // for package dependency analysis code_package_info code_dependency // package or file as dependency analysis code_package code_container // class-first or function-first code_data_struct code_function // function or class detail code_annotation code_field code_import code_member code_position code_property // method call information code_call
隨後,我們就可以開始將不同的編程語言轉爲 JSON。
插件化 AST:基於 Antlr 的 AST 解析
有了基礎模型之後,我們要做的事情就是程序員應該做的事情:AST 解析。我們需要編寫多種編程語言的 AST,好在我們已經有了 Antlr。而社區也已經有各種使用 Antlr 編寫的編程語言 AST,見 Antlr 官方維護的 https://github.com/antlr/grammars-v4/ 。
然後一點點地結合測試,解析我們所需要的數據:
- package name
- import name
-
class / data struct
- struct name
- struct parameters
- function name
- return types
- function parameters
-
function
- function name
- return types
- function parameters
-
method call
- new instance call
- parameter call
- field call
於是,下述的 Java 代碼:
package adapters.outbound.persistence.blog; public class BlogPO implements PersistenceObject<Blog> { @Override public Blog toDomainModel() { } }
便可以轉換爲 JSON 對象,存儲到數據庫中:
{"NodeName":"BlogPO","Type":"CLASS","Package":"adapters.outbound.persistence.blog","FilePath":"","Fields":[],"MultipleExtend":[],"Implements":["PersistenceObject<Blog>"],"Extend":"","Functions":[{"Name":"toDomainModel","Package":"","ReturnType":"Blog","MultipleReturns":[],"Parameters":[],"FunctionCalls":[],"Annotations":[{"Name":"Override","KeyValues":[]}],"Override":false,"Modifiers":[],"InnerStructures":[],"InnerFunctions":[],"Position":{"StartLine":6,"StartLinePosition":133,"StopLine":8,"StopLinePosition":145},"Extension":{},"IsConstructor":false,"extensionMap":{}}],"InnerStructures":[],"Annotations":[],"FunctionCalls":[],"Parameters":[],"InOutProperties":[],"Imports":[],"Extension":{}}
未來
有了這個 Chapi 生成的 JSON 數據,我們可以:
- 查找代碼中的壞味道
- 生成數據結構(class/struct)的依賴關係
- 可視化項目的依賴情況
- 自動化重構代碼
- ……
除此,我們還可以:
- 將 A 語言的領域模型轉換到 B 語言中(整潔架構條件下:純編程語言實現,無第三方依賴時)。
- 將設計模型轉換爲領域模型
- 實現領域模型的架構守護
- ……
想法有多大,Chapi 就有多少可能。
Chapi 需要你的參與
Chapi 是一個史詩級的工程,所以,如果你想提升你的底層知識、想進入開源社區,歡迎加入到 Chapi 的開發中。
在這裏,你將學會:
- 真實世界的 Kotlin 實戰
- 成爲一個代碼專家
- 熟悉某一語言、多個語言的語法樹解析
- TDD 的手把手實戰
- 開源項目經驗
怎樣?一起玩吧!