syntax-parser 是徹底利用 JS 編寫的詞法解析+語法解析引擎,因此徹底支持在瀏覽器、NodeJS 環境執行。html
它能夠幫助你快速生成 詞法解析器,亦或進一步生成 語法解析器,將字符串解析成語法樹,語法解析器還支持下一步智能提示功能,輸入光標位置,給出輸入推薦。git
目前 syntax-parser 功能逐漸穩定,內核性能還在逐步優化中,咱們會利用 syntax-parser 引擎的能力,完成一些使人驚喜的小 DEMO,若是與你的業務場景剛好契合,歡迎使用!github
此次的 DEMO 是:利用 syntax-parser 快速完成四則運算語法解析器!typescript
經過下面 20 行配置,生成一個能解析英文、數字、加減乘除、左右括號的詞法解析器,so easy!json
import { createLexer } from 'syntax-parser' const myLexer = createLexer([ { type: 'whitespace', regexes: [/^(\s+)/], ignore: true }, { type: 'word', regexes: [/^([a-zA-Z0-9]+)/] // 解析數字 }, { type: 'operator', regexes: [ /^(\(|\))/, // 解析 ( ) /^(\+|\-|\*|\/)/ // 解析 + - * / ] } ]);
咱們可使用 myLexer
將字符串解析爲一個個 Token:數組
myLexer('1 + 2 - 3 * b / (x + y)')
不過此次的目的是生成語法樹,因此咱們會把 myLexer
做爲參數傳給語法解析器。瀏覽器
五個文法,20 行代碼搞定,表示四則運算的文法,能夠參考 此文。編輯器
利用 chain
,能夠高效表示每個文法表達式要匹配的字符串、表示匹配次數,還支持嵌入新的文法函數。這些相互依賴的文法組成了一個文法鏈條,完整表達了四則運算的邏輯:函數
import { chain, createParser, many, matchTokenType } from 'syntax-parser' const root = () => chain(term, many(addOp, root))(parseTermAst); const term = () => chain(factor, many(mulOp, root))(parseTermAst); const mulOp = () => chain(['*', '/'])(ast => ast[0].value); const addOp = () => chain(['+', '-'])(ast => ast[0].value); const factor = () => chain([ chain('(', root, ')')(ast => ast[1]), chain(matchTokenType('word'))(ast => ast[0].value) ])(ast => ast[0]); const myParser = createParser( root, // Root grammar. myLexer // Created in lexer example. );
createParser
函數第一個參數接收根文法表達式,第二個參數是詞法解析器,咱們將上面建立的 myLexer
傳入。 parseTermAst
函數單獨提出來,目的是輔助生成語法樹,一共 20 行代碼:性能
const parseTermAst = (ast: any) => ast[1] ? ast[1].reduce( (obj: any, next: any) => next[0] ? { operator: next[0], left: obj || ast[0], right: next[1] } : { operator: next[1] && next[1].operator, left: obj || ast[0], right: next[1] && next[1].right }, null ) : ast[0];
這個函數是爲了將語法樹變得更規整,不然獲得的 AST 解析將會是數組,而不是像 left
right
operator
這麼有含義的對象。
PS:本文的 DEMO 沒有考慮乘除高優先級問題。
最後獲得的 myParser
就是語法解析器了!直接執行就能拿到語法樹結果!
const result = myParser('1 + 2 - (3 - 4 + 5) * 6 / 7'); console.log(result.ast)
咱們打印出語法樹,運行結果以下:
{ "operator": "/", "left": { "operator": "-", "left": { "operator": "+", "left": "1", "right": "2" }, "right": { "operator": "*", "left": { "operator": "+", "left": { "operator": "-", "left": "3", "right": "4" }, "right": "5" }, "right": "6" } }, "right": "7" }
不只語法樹,咱們構造一個錯誤的輸入試試!
const result = myParser('1 + 2 - (3 - 4 + 5) * 6 / '); console.log(result.error)
此次咱們打印錯誤信息:
{ "suggestions": [ { "type": "string", "value": "(" }, { "type": "special", "value": "word" } ], "token": { "type": "operator", "value": "/", "position": [ 24, 25 ] }, "reason": "incomplete" }
精準的提示了最後一個 /
位置不完整,建議是填寫 (
或者一個單詞。這都是根據文法自動生成的建議,提示很少一個,很多一個!
最精髓的功能到了,這個語法解析器就是爲了作自動提示,因此支持多傳一個參數,告訴我當前你光標的位置:
const result = myParser('1 + 1', 5) console.log(result.nextMatchings)
假設語句寫到這裏,咱們光標位置定位到 5 的位置,也就是最後一個 1 後面,nextMatchings
屬性會告訴咱們後面的可能狀況:
[ { "type": "string", "value": "-" }, { "type": "string", "value": "+" }, { "type": "string", "value": "/" }, { "type": "string", "value": "*" } ]
筆者拿 monaco-editor
舉例,利用上面的語法樹解析,咱們能夠輕鬆完成下面的效果:
不管是智能補全,仍是錯誤提示都是 100% 精準無誤的(根據上面編寫的文法表達式)。
相比普通的語法解析器在解析錯誤時直接拋出錯誤,syntax-parser 不只提供語法樹,還能根據文法智能提示光標位置的輸入推薦,哪怕是輸入錯誤的狀況下,是否是解決了你們的痛點呢?若是以爲好用,歡迎給 syntax-parser 提 建議 或者 pr !