UNPKG

costreamjs

Version:

A high-performance streaming programming language for parallel architecture. This repo (js-version) is created for better using & reading & debugging.

298 lines (290 loc) 12.5 kB
import { jump_statement, blockNode, idNode, ternaryNode, expNode, labeled_statement, forNode, declareNode, declarator, compositeNode, ComInOutNode, compBodyNode, inOutdeclNode, strdclNode, paramNode, binopNode, operatorNode, operBodyNode, constantNode, unaryNode, winStmtNode, callNode, compositeCallNode, selection_statement, castNode, parenNode, matrix_section, matrix_constant, matrix_slice_pair, lib_binopNode, whileNode, doNode, splitjoinNode, addNode, splitNode, joinNode } from "./node.js" import { COStreamJS, top } from "../FrontEnd/global" import { error } from "../utils/color.js"; export function ast2String(root) { var result = '' root.forEach((x, idx) => { result += x.toString() + (x instanceof declareNode ? ';' : '') + '\n' }) return result.replace(/ {2,}/g, ' ').beautify() } /** * 输入一个 list 返回它转化后的 string, 可以配置分隔符 split 例如',' * 也可以配置 start 和 end 例如'{' '}' */ function list2String(list, split, start, end) { if (!list || list.length == 0) return '' var str = start ? start : '' list.forEach((x, idx) => { str += x.toString() str += split && idx < list.length - 1 ? split : '' }) return end ? str + end : str } /** * 执行下列代码后, statement 类型的节点可以执行 toString 用于代码生成或调试 */ declarator.prototype.toString = function () { var str = this.identifier.toString() + '' str += this.op ? this.op : '' if (this.initializer instanceof Array) { str += list2String(this.initializer, ',', '{', '}') } else { str += this.initializer ? this.initializer.toString() : '' } return str } idNode.prototype.toString = function(){ return this.name.toString() + (this.arg_list.length > 0? list2String(this.arg_list, '][','[',']') :'').replace(/\[0]/g,'[]') } declareNode.prototype.toString = function () { return this.type + ' ' + list2String(this.init_declarator_list, ', ') } compositeNode.prototype.toString = function () { var str = 'composite ' + this.compName + '(' str += this.inout ? this.inout.toString() : '' str += ')' + this.body.toString() return str } ComInOutNode.prototype.toString = function () { return 'input ' + list2String(this.input_list,',') + ', output ' + list2String(this.output_list,',') } inOutdeclNode.prototype.toString = function () { return this.strType.toString() + this.id } strdclNode.prototype.toString = function () { var str = 'stream<' this.id_list.forEach(({ type, identifier }) => { str += type + ' ' + identifier + ',' }) return str.slice(0, -1) + '>' } compBodyNode.prototype.toString = function () { var str = '{\n' str += this.param ? this.param.toString() : '' str += list2String(this.stmt_list, ';\n') + ';\n}\n' return str } paramNode.prototype.toString = function () { return 'param\n ' + this.param_list.map(x=>x.type+' '+x.identifier) + ';\n' } const isNoSemi = node => ['blockNode', 'forNode', 'selection_statement'].includes(node.constructor.name) //将每一行 statement 的';'上提至 blockNode 处理 let prefixString = '' //有些特殊的语句需要在前一行加入一个前缀行用于存储一些信息 blockNode.prototype.toString = function () { prefixString = '' if (!this.stmt_list || this.stmt_list.length == 0) return '{ }' var str = '{\n'; this.stmt_list.forEach(x => { const line = x.toString() if(prefixString){ str += prefixString + '\n'; prefixString = '' } str += line str += isNoSemi(x) ? '\n' :';\n' }) return str + '}\n' } jump_statement.prototype.toString = function () { var str = this.op1 + ' ' str += this.op2 ? this.op2 + ' ' : '' return str } labeled_statement.prototype.toString = function () { var str = this.op1 + ' ' str += this.op2 ? this.op2 : '' return str + ' ' + this.op3 + this.statement.toString() } //expNode 的子类 binopNode.prototype.toString = function () { // 强制执行 toString 来实现对 N 等标识符在符号表中的查询 if(this.op === '*'){ const lshape = top.shapeCache.get(this.left), rshape = top.shapeCache.get(this.right) const lString = lshape && lshape != '1,1' ? this.left.toString()+'.matrix()' : this.left.toString() const rString = rshape && rshape != '1,1' ? this.right.toString()+'.matrix()' : this.right.toString() return lString + this.op + rString } if(['+','-','/'].includes(this.op)){ const lshape = top.shapeCache.get(this.left), rshape = top.shapeCache.get(this.right) const lString = lshape && lshape != '1,1' ? this.left.toString()+'.array()' : this.left.toString() const rString = rshape && rshape != '1,1' ? this.right.toString()+'.array()' : this.right.toString() return lString + this.op + rString } if(this.op !== '.'){ return this.left.toString() + this.op + this.right.toString() } return this.left.toString() + this.op + this.right // 例如 In[0].i = i 时, 对左边的.i 不检查符号表, 而对右侧的 i 检查是否是上层符号表的成员 } ternaryNode.prototype.toString = function (){ return this.first.toString() + '?' + this.second.toString() + ':' + this.third.toString(); } constantNode.prototype.toString = function () { let value = this.value let escaped = this.source.replace(/\n|↵/g, "\\n") return Number.isNaN(value) ? escaped : value.toString() } castNode.prototype.toString = function () { return '(' + this.type + ')' + this.exp } parenNode.prototype.toString = function () { return '(' + this.exp + ')' } unaryNode.prototype.toString = function () { return '' + this.first.toString() + this.second.toString() } operatorNode.prototype.toString = function () { var str = this.operName + '(' str += this.inputs ? this.inputs : '' return str + ')' + this.operBody } operBodyNode.prototype.toString = function () { var str = '{\n' str += this.stmt_list ? list2String(this.stmt_list, ';\n','',';\n') : '' str += this.init ? 'init' + this.init : '' str += this.work ? 'work' + this.work : '' str += this.win ? 'window{' + list2String(this.win, ';\n') + ';\n' + '}' : '' return str + '\n}\n' } winStmtNode.prototype.toString = function () { return this.winName + ' ' + this.type + '(' + list2String(this.arg_list, ',') + ')' } forNode.prototype.toString = function () { var str = 'for(' str += this.init ? this.init.toString() + ';' : ';' str += this.cond ? this.cond.toString() + ';' : ';' str += this.next ? this.next.toString() : '' str += ')' + this.statement.toString() str += this.statement instanceof blockNode ? '' : ';' // 若该 for 只有一条语句, 则补充一个分号 return str } whileNode.prototype.toString = function (){ return 'while(' + this.exp + ')' + this.statement; } doNode.prototype.toString = function (){ return 'do' + this.statement + 'while(' + this.exp + ')' } selection_statement.prototype.toString = function () { if (this.op1 === 'if') { var str = 'if(' + this.exp + ')' + this.statement str += this.op4 === 'else' ? ('else ' + this.else_statement) : '' return str } else if (this.op1 == 'switch') { } } splitNode.prototype.toString = function (){ return this.name + ' ' + this.type + '(' + list2String(this.arg_list,',') + ');'; } joinNode.prototype.toString = function (){ return this.name + ' ' + this.type + '(' + list2String(this.arg_list,',') + ');'; } splitjoinNode.prototype.toString = function (){ var str = this.compName + '(' + list2String(this.inputs,',') + ')' + '{\n' str += this.split + '\n' str += list2String(this.body_stmts,'\n') str += this.join + '\n}' return str } addNode.prototype.toString = function (){ if(this.content instanceof compositeCallNode){ return this.name + ' ' + this.content.compName + '(' + list2String(this.content.params,',') + ')' } return this.name + ' ' + this.content.toString() } const differentPlatformPrint = { 'X86': args => 'cout<<' + list2String(args, '<<'), 'WEB': args => 'console.log(' + list2String(args, ",") + ')', 'default': args => 'print(' + list2String(args, ',') + ')' } const differentPlatformPrintln = { 'X86': args => 'cout<<' + list2String(args, '<<') + '<<endl', 'WEB': args => 'console.log(' + list2String(args, ',') + `,'\\n')`, 'default': args => 'println(' + list2String(args, ',') + ')' } callNode.prototype.toString = function () { const platform = COStreamJS.options.platform if (this.name === "print") { return differentPlatformPrint[platform](this.arg_list) } else if (this.name === "println") { return differentPlatformPrintln[platform](this.arg_list) } else if(this.name === "Native"){ if(this.arg_list[1].source.slice(1,-1) !== platform){ error(this._loc, `该 Native 函数与当前的执行平台不符`); return this.name; } return this.arg_list[0].source.slice(1,-1) //通过 slice 来移除左右两侧的引号 } else if(this.name === "random" && platform === "X86"){ return `rand()/(double)RAND_MAX`; } else if(this.name instanceof lib_binopNode){ if(this.name.function_name === 'identity'){ return 'Matrix::Identity('+this.arg_list[0]+','+this.arg_list[0]+')' }else{ return this.name + '(' + list2String(this.arg_list, ',') + ')' } } else if(this.name instanceof binopNode){ if(this.name.right === "det"){ return this.name.left+'.determinant()' }else if(this.name.right === 'identity'){ return 'Matrix::Identity('+this.arg_list[0]+','+this.arg_list[0]+')' }else if(['sin','cos','pow','exp'].includes(this.name.right)){ return this.name.left+'.array().'+this.name.right+ '(' + list2String(this.arg_list, ',') + ')' }else if(this.name.right === 'rank'){ prefixString = `Eigen::FullPivLU<Matrix> luA(${this.name.left});` return `luA.rank()` }else { return this.name + '(' + list2String(this.arg_list, ',') + ')' } } else{ return this.name + '(' + list2String(this.arg_list, ',') + ')' } } compositeCallNode.prototype.toString = function () { var str = this.compName + '(' str += this.inputs ? list2String(this.inputs, ',') : '' str += ')(' str += this.params ? list2String(this.params, ',') : '' return str + ')' } matrix_slice_pair.prototype.toString = function (){ if(!this.op) return this.start.toString() return (this.start || '')+':'+(this.end||'') } matrix_section.prototype.toString = function (){ const platform = COStreamJS.options.platform // 如果是矩阵切片节点[0:5,0:5]而非数组取下标节点 if (this.slice_pair_list[0].op === ':'){ if (platform === 'X86') { //矩阵切片构建规则为 matrix[i:i+p, j:j+q] 转化为 matrix.block(i,j,p,q) , 参考http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html let i = this.slice_pair_list[0].start let p = this.slice_pair_list[0].end + '-' + i let j = this.slice_pair_list[1].start let q = this.slice_pair_list[1].end + '-' + j return this.exp + `.block(${i},${j},${p},${q})` } } // 如果是矩阵切片节点(两个数字), 例如 data[i,j] 转义为 data(i,j) else if(this.slice_pair_list.length == 2){ return this.exp.toString() + '(' + list2String(this.slice_pair_list, ',') + ')' } // 其他情况 return this.exp.toString() + '[' + list2String(this.slice_pair_list, ',') + ']' } lib_binopNode.prototype.toString = function (){ if(this.lib_name === 'Matrix'){ let maps = { 'zeros': 'Zero', 'random': 'Random', 'Constant': 'Constant', 'ones':'Ones' } return 'Matrix::' + maps[this.function_name] }else{ throw new Error(error(this._loc,'暂不支持矩阵之外的库')) } } let m_count = 0;// 控制临时变量名的一个计数器 matrix_constant.prototype.toString = function(){ var arrayName = 'm' + m_count prefixString = `double ${arrayName}[] = {${this.rawData.join(',')}};` return `Eigen::Map<Eigen::Matrix<double,${this.shape[0]},${this.shape[1]}>>(${arrayName})` }