costreamjs
Version:
A high-performance streaming programming language for parallel architecture. This repo (js-version) is created for better using & reading & debugging.
100 lines (99 loc) • 4.29 kB
JavaScript
/**
* 输入一个 object 返回 graphviz 工具能识别的 dot 字符串
*/
export function ast2dot(node){
ast2dot.count = 0
var header = `digraph { \n node [shape = record];\n`
var body = ''
dumpdot(node)
//应 dot 文件格式的要求, 对中间部分的 [] {} "" < > |这些特殊符号进行转义
body = body.replace(/\[(?!label|shape)/g, "\\[").replace(/](?!;)/g, "\\]")
body = body.replace(/(\{|\})/g, "\\$1")
body = body.replace(/"/g,`\\"`).replace(/\[label = \\"/g,`\[label = "`).replace(/\\"];/g,`"];`) // 左侧三重替换为右侧反向预查正则的降级写法 body = body.replace(/(?<!\[label = )\"(?!];)/g,`\\"`)
body = body.replace(/<(?!\d+>)/g,"\\<").replace(/>/g,`\\>`).replace(/(<\d+|-)\\>/g,"$1>") // 左侧表达式为右侧反向预查的降级写法 body = body.replace(/<(?!\d+>)/g,"\\<").replace(/(?<!<\d+|-)>/g,"\\>")
body = body.replace(/\|(?!<)/g,"\\|")
header += body + `}`
return header
function dumpdot(node){
//下面这个 if 大部分情况都走第二个分支
//第一个分支是为了 Program 语法树的根节点(可能有不同类型的孩子,例如 declaration,function,composite)
if(node instanceof Array){
if(node.length>0){
var types = [...new Set(node.map(x=>x.constructor.name))].join(" or ")
body += ` ${ast2dot.count} [label = "[${node.length} ${types}]"];\n`
var nThis = ast2dot.count++
var tag = 0
for(var i of Object.keys(node)){
var nChild = dumpdot(node[i])
body += ` ${nThis}:${tag++} -> ${nChild}\n`
}
}else{
var line = ` ${ast2dot.count} [label = "[ ]"`
return ast2dot.count++
}
}else{
if(!node.initializer && node.identifier){ //避免特殊的idNode产生的空白节点
node = node.identifier //减少空白dot节点
}
//生成一个dot 文件中的行
var nThis = newNode(node)
//遍历它的孩子将 nThis 和 nChild 进行连线
var tag = 0
for (var i of Object.keys(node)) {
if (node[i] === undefined) continue
if (node[i] instanceof Array) {
node[i].forEach((child) => {
var nChild = dumpdot(child)
body += ` ${nThis}:${tag} -> ${nChild}\n`
})
tag++
} else if (node[i] instanceof Object) {
var nChild = dumpdot(node[i])
body += ` ${nThis}:${tag++} -> ${nChild}\n`
} else {
tag++
}
}
}
return nThis
}
/**
* 输入 node 为 object 或 string 或 number,创建一行格式为
* 6 [label="<1> int |<2> 2"] 的 dot 字符串
* 返回该节点的序号, 例如6
*/
function newNode(node){
var line = ` ${ast2dot.count} [label = "`
if (typeof node === 'string' || typeof node === 'number'){
line += node
body += line + '"];\n'
return ast2dot.count++
}
var first = true
var tag = 0
var keys = Object.keys(node)
for(var i of keys){
if(node[i] === undefined) continue
if(i === "arg_list" && node[i].length == 0) continue
line+= first ? '' : " |"
first = false
line += `<${tag++}> `
if(typeof node[i] == 'number'){
line+= node[i]
}else if(typeof node[i] == 'string'){
line+= node[i]
}else if (node[i] instanceof Array) {
var types = [...new Set(node[i].map(x => x.constructor.name))]
if(types.length>=3) types= types.slice(0,2).concat("other")
types = types.join(" or ")
if (node[i].length > 0) line += `[${node[i].length} ${types}]`
else line += `[ ]`
}else{
line+= ' '
}
}
line += `"];\n`
body += line
return ast2dot.count++
}
}