把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