把Monarch從Microsoft VSCode請出來當Parser
最近用自己的Lazac解析source code,結果發現怎麼寫解析javascript和ruby的傷痛都在inline regexp上。要想不用AST,從string直接區分一個表達式是inline regexp還是普通除法,並且cover regexp的所有語法確實相當複雜。於是尋求其他解決方案。順帶分析分析一些VSCode的代碼吧。
TL;DR
NPM: https://www.npmjs.com/package/monarch.js
有沒有人已經寫好了同樣的東西呢?首先想到的當然是VSCode。找找package.json
,裏面有個叫vscode-textmate
的東西,這個是不是我們要的呢?於是順藤摸瓜,去了vscode-textmate
的github上看一看。的確很有用,但是它有兩個問題:
- 解析出來的scope有一大串,而且token的type各種語言都不太一樣,沒有統一成identifier、keywords之類的。
- 用過VSCode的早期版本都有感覺,當時很多時候它解析javascript的inline regexp也不對。顏色會標錯。
於是繼續尋找解決方案。看看有沒有Web based editor?Google了一下,發現了從Microsoft VSCode分離出來的monaco-editor
。以前一直想把VSCode轉成網頁版,竟然已經有弄好的,在Monaco Editor的網站,有一個標籤叫Monarch。一開始沒有注意,然後仔細閱讀發現它是一個定義Language的模塊,使用一堆regexp。而且doc裏自稱是inline regexp的解析很準確。試了試,javascript inline regexp確實不錯。換到ruby,註釋裏也戲稱解析ruby就是nightmare…那麼就是它了,下面就是Monarch的代碼在哪?
在github上搜索了一圈,Monarch似乎是包含在Monaco Editor裏的;那麼去找Monaco Editor的代碼,src
就一個ts
文件,doc
裏說代碼都在VSCode裏了。這還是很坑爹的…Monaco Editor是整個打包成Browser可用的組建了,VSCode的代碼量還是很龐大的,於是github上對VSCode的repo進行搜索Monarch,發現了它的幾個文件在一個standalone
的文件夾裏,全是ts
的。有monarchCommon
monarchCompiler
monarchLexer
和monarchTypes
,看看import
,只有monarchLexer
有不少。其他就零星幾個引用到最基本的諸如objects
types
的import
。能把Monarch分離出來麼?
它既然放在standalone
文件夾裏,該不會騙人吧…於是把Monarch相關的文件全部複製出來,再嘗試展開monarchLexer
的所有import
,發現很多import
都是一些interface
。但是遇到modeService
和standaloneThemeService
就有點犯難了。先把它們用null代替吧,到時候調試的時候遇到了error,一個一個mock吧。
Monarch在VSCode裏是怎麼調用的,這個搜索一下別的文件的import
的monarchCompiler
或者monarchLexer
就好了。原來它最後也是接入TextMate那套框架的,就是先把語言定義傳給monarchCompiler
,再用monarchLexer
創建一個adapter
可以適配原先的代碼。所以把學習這些代碼,把可用的部分提取出來。語言定義可以在一個monaco-languages
的package裏找到很多:npm install monaco-languages
,在其release文件夾裏有很多寫好的,除了javascript
有引用到typescript
的東西,我們可以直接從Monarch網站上覆制那個typescript
無關的版本,其他就把release/esm
下的文件改改export var ... => exports.
,最後把.language
傳給monarchCompiler
就好了。最終可以進行簡單的tokenize
了。
前面有提到modeService
和themeService
沒有,Monarch有兩個版本的tokenize
:tokenize
和tokenize2
,一個對應Classic
,一個對應Morden
。用tokenize2
會報錯,因爲沒有定義兩個service
。大概看了下modeService
和themeService
,一個是定義corss-reference和language下寫代碼有哪些會自動觸發的action,一個是配色方案。暫時不管了,以後再看吧。有普通的就夠用了。寫個package上傳到npm上吧。
J.Y.Liu
2019.01.21