來,一起用高效(hard way)的方式學習多種編程語言,Kotlin + Scala、Python、Go、Java、TypeScript、C#……
Chapi 起源
為了向開源重構與分析工具 Coca 中提供多語言支持(原先只支持 Java 語言),我又雙叕開始造新的輪子。上個月底嘗試了使用 Antlr 的 Go runtime,但是遇到一系列的挫折加之因為公司內部的一些項目需要類似的工具,我便開始從 JVM 系的語言中尋找一個合適的選擇。。
結合疫情的影響,我結束了打蒼蠅為樂的休息時間,在月初(2020.2.1)便啟動了 Chapi 項目的開發,使用的語言是 Kotlin。
在過去的半個月裡,我在這個項目上編寫了大量的代碼,一些有意思的內容、特性如下所示:
完全 TDD 的項目。只有充分的測試,才能保證語法解析不出錯。
Kotlin 語言。Java 是 Antlr 框架的一等公民,Kotlin 是 JVM 系,更加簡潔。
主流編程語言支持。已經完全支持 Java 語言,支持 Python、Go、TypeScript 的數據結構解析,正在支持 Scala、C 和 C# 語言。
-
插件化支持。(正在實現)
JSON 輸出(基於 <code>kotlinx.serialization/<code>)。
統一的代碼數據結構模型。
先是重寫了 Coca 的基礎設施中的 AST,再在其基礎上提供了更通用的代碼模型,並添加了不同類型語言的支持:
我在維基百科上看到了一個編程語言的分類,便添加了更多編程語言的支持,以嘗試從不同的語言中構建出統一的代碼的數據模型。
與 Coca 稍有不同的是,這是一個過程比結果重要的項目。在實現的過程中,慢慢成為代碼/代碼語法方面的專家。不同的編程語言都有各自獨特的語法,都需要不斷地熟悉相關的語法。
Chapi Core:代碼的模型
在繼續瞭解,讓我們來看看一個項目的結構:
<code>系統(system)/<code>
<code>- 項目(project)/<code>
<code>- 源碼(source code)/<code>
<code>- 包(package)/<code>
<code>- 類(class)/<code>
<code>- 函數/<code>
<code>- 參數/<code>
<code>- 返回類型/<code>
<code>- ……/<code>
<code>- 函數(function)/<code>
<code>- 對象(object)/<code>
<code>- 接口(interface)/<code>
<code>- ……(trait,struct)/<code>
<code>- 包(package)/<code>
<code>- 項目信息/<code>
<code>- 依賴管理/<code>
<code>- 項目(project)/<code>
它適用於 Java、TypeScript、Go 等語言,基於此,我們就有了 Chapi 的基礎的數據結構:
<code>// for multiple project analysis/<code>
<code>code_project/<code>
<code>code_module/<code>
<code>// for package dependency analysis/<code>
<code>code_package_info/<code>
<code>code_dependency/<code>
<code>// package or file as dependency analysis/<code>
<code>code_package/<code>
<code>code_container/<code>
<code>// class-first or function-first/<code>
<code>code_data_struct/<code>
<code>code_function/<code>
<code>// function or class detail/<code>
<code>code_annotation/<code>
<code>code_field/<code>
<code>code_import/<code>
<code>code_member/<code>
<code>code_position/<code>
<code>code_property/<code>
<code>// method call information/<code>
<code>code_call/<code>
隨後,我們就可以開始將不同的編程語言轉為 JSON。
插件化 AST:基於 Antlr 的 AST 解析
有了基礎模型之後,我們要做的事情就是程序員應該做的事情:AST 解析。我們需要編寫多種編程語言的 AST,好在我們已經有了 Antlr。而社區也已經有各種使用 Antlr 編寫的編程語言 AST,見 Antlr 官方維護的 https://github.com/antlr/grammars-v4/ 。
然後一點點地結合測試,解析我們所需要的數據:
<code>1.package name/<code>
<code>2.import name/<code>
<code>3.class / data struct/<code>
<code>1.struct name/<code>
<code>2.struct parameters/<code>
<code>3.function name/<code>
<code>4.return types/<code>
<code>5.function parameters/<code>
<code>4.function/<code>
<code>1.function name/<code>
<code>2.return types/<code>
<code>3.function parameters/<code>
<code>5.method call/<code>
<code>1.new instance call/<code>
<code>2.parameter call/<code>
<code>3.field call/<code>
於是,下述的 Java 代碼:
<code>package adapters.outbound.persistence.blog;/<code>
<code>public class BlogPOimplementsPersistenceObject<Blog> {/<code>
<code>@Override/<code>
<code>public BlogtoDomainModel {/<code>
<code>}/<code>
<code>}/<code>
便可以轉換為 JSON 對象,存儲到數據庫中:
<code>{"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":{}}/<blog>/<code>
未來
有了這個 Chapi 生成的 JSON 數據,我們可以:
查找代碼中的壞味道
生成數據結構(class/struct)的依賴關係
可視化項目的依賴情況
自動化重構代碼
……
除此,我們還可以:
將 A 語言的領域模型轉換到 B 語言中(整潔架構條件下:純編程語言實現,無第三方依賴時)。
將設計模型轉換為領域模型
實現領域模型的架構守護
……
想法有多大,Chapi 就有多少可能。
Chapi 需要你的參與
Chapi 是一個史詩級的工程,所以,如果你想提升你的底層知識、想進入開源社區,歡迎加入到 Chapi 的開發中。
在這裡,你將學會:
真實世界的 Kotlin 實戰
成為一個代碼專家
熟悉某一語言、多個語言的語法樹解析
TDD 的手把手實戰
開源項目經驗
怎樣?一起玩吧!
GitHub:https://github.com/phodal/chapi
閱讀更多 Phodal 的文章