UNPKG

costreamjs

Version:

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

1,180 lines (1,122 loc) 357 kB
#!/usr/bin/env node var COStreamJS = (function () { 'use strict'; function debug(...args) { console.log("%c " + args[0], "color: #0598bd", ...args.slice(1)); } function green(...args) { console.log("%c " + args[0], "color: #00bc00", ...args.slice(1)); } function line(...args) { const line = args[0].first_line || args[0]; console.log(`%c line:${line} %c ${args[1]} `, "color: #00bc00", "color: #0598bd", ...args.slice(2)); } const errors = []; function error$1(...args) { const error_obj = { msg:'', other:[] }; args.forEach(arg =>{ if(typeof arg === "string"){ error_obj.msg += arg; }else if(typeof arg === 'object' && arg !== null && arg.first_line !== undefined){ error_obj.loc = arg; }else{ error_obj.other.push(arg); } }); errors.push(error_obj); console.log("%c " + error_obj.msg, "color: #cd3131", ...error_obj.other); } /** * 输入一个 object 返回 graphviz 工具能识别的 dot 字符串 */ 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{ 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++ } } /** * 深拷贝一个数据结构, 包括其原型链, 但以下滑线_开头的属性名浅拷贝, 例如 _symbol_table */ function deepCloneWithoutCircle(node) { let hasVisitedNode = new WeakMap(); return deepClone(node) function deepClone(node) { if (hasVisitedNode.has(node)) { console.error("深拷贝出现循环引用错误,请检查:",node); } else { if (['number', 'boolean', 'string', 'undefined'].includes(typeof node) || node === null) { return node } else { hasVisitedNode.set(node, true); let obj = new node.constructor(); Object.keys(node).forEach(key => { if(key.startsWith('_')){ obj[key] = node[key]; }else{ obj[key] = deepClone(node[key]); } }); return obj } } } } function checkBraceMatching(str = ''){ let stack = [], line = 1; let symmetry = { '[':']', '(':')', '{':'}' }; for(let s of str){ if(s == '(' || s == '[' || s == '{'){ stack.push(s); }else if( s == ')' || s == ']' || s == '}'){ let top = stack.pop(); if(symmetry[top] !== s){ throw new Error(error$1({first_line:line}, `括号不匹配`)) } }else if( s == '\n'){ line++; } } return true } var utils = /*#__PURE__*/Object.freeze({ __proto__: null, checkBraceMatching: checkBraceMatching, debug: debug, line: line, error: error$1, green: green, errors: errors, ast2dot: ast2dot, deepCloneWithoutCircle: deepCloneWithoutCircle }); const defaultDescriptor = { configurable: true, enumerable: false, value: undefined, writable: true }; /** * 定义 target 的 key 属性为私有属性, 例如 一个 node 的 this._source 和 this._loc */ function definePrivate(target, key) { var descriptor = Object.getOwnPropertyDescriptor(target, key) || defaultDescriptor; descriptor.enumerable = false; Object.defineProperty(target, key, descriptor); } /** * 输入一段带有'{' '}'的字符串,然后按照层级在\n 的后面添加空格, 来美化输出 */ String.prototype.beautify = function (space_num = 2) { var space = (x) => Array(x).fill(' ').join(''); var stage = 0, result = ''; var str = this.replace(/\{(?![ \t]*\n)/g, '{\n'); // 在 { 右侧添加换行符 str = str.replace(/\}/g, '\n\}').replace(/\}(?![ \t;]*\n)/g, '}\n'); // 在 } 的左右两侧都添加换行符,除非右侧已经有换行符或者右侧有个紧挨着的';'(全局 declareNode 的特例) var stmts = str.split('\n').map(x => x.trim()).filter((str,idx,arr)=>str || arr[idx+1] !== '}'); // 移除右花括号}前的空行(若该行trim为空且下一行为}则删去) for (var s of stmts) { if (/\}/.test(s)) stage--; result += space(stage * space_num) + s + '\n'; if (/\{$/.test(s)) stage++; } return result }; class Node$1 { constructor(loc) { this._loc = loc; ['_loc'].forEach(key => { definePrivate(this, key); }); } } /********************************************************/ /* 1.1 declaration */ /********************************************************/ class declareNode extends Node$1 { constructor(loc, type, init_declarator_list) { super(loc); this.type = type; this.init_declarator_list = [].concat(init_declarator_list); } } class idNode extends Node$1{ constructor(loc, name, arg){ super(loc); this.name = name; this.arg_list = []; if(arg){ this.isArray = true; this.arg_list.push(arg); } } } class declarator extends Node$1 { constructor(loc, identifier, initializer) { super(loc); this.identifier = identifier; initializer && (this.op = '='); this.initializer = initializer; definePrivate(this, 'type'); } } /********************************************************/ /* 1.2 function.definition 函数声明 */ /********************************************************/ class function_definition extends Node$1 { constructor(loc, type, declarator,param_list, compound) { super(loc); this.type = type; this.name = declarator.name; this.op1 = '('; this.param_list = param_list; this.op2 = ')'; this.funcBody = compound; } } /********************************************************/ /* 2. composite */ /********************************************************/ class compositeNode extends Node$1 { constructor(loc, head = {}, body = {}) { super(loc); Object.assign(this, { op: 'composite', compName: head.compName, inout: head.inout, body }); } } class compHeadNode extends Node$1 { constructor(loc, compName, inout) { super(loc); Object.assign(this, { op: 'composite', compName, inout }); } } class ComInOutNode extends Node$1 { constructor(loc, input_list = [], output_list = []) { super(loc); Object.assign(this, { op1: 'input', input_list, op2: 'output', output_list }); } } class inOutdeclNode extends Node$1 { constructor(loc, strType, id) { super(loc); Object.assign(this, { strType, id }); } } class strdclNode extends Node$1 { constructor(loc, type, identifier) { super(loc); this.op = 'stream<'; this.id_list = [ { type, identifier } ]; this.op2 = '>'; } copy(){ const copy = new strdclNode(this._loc); //为每个object申请了一块新的内存 copy.id_list = this.id_list.map(({type,identifier})=>{ const idWithShape = { type,identifier }; definePrivate(idWithShape,'shape'); //定义一个不可枚举的shape属性 return idWithShape }); return copy } } class compBodyNode extends Node$1 { constructor(loc, param, stmt_list) { super(loc); Object.assign(this, { op1: '{', param, stmt_list, op2: '}' }); } } class paramNode extends Node$1 { constructor(loc, param_list) { super(loc); if (param_list) { this.op = 'param'; } this.param_list = param_list; } } class operBodyNode extends Node$1 { constructor(loc, stmt_list, init, work, win) { super(loc); Object.assign(this, { stmt_list: stmt_list || [] , op1: 'init', init, op2: 'work', work, op3: 'window', win }); } } class winStmtNode extends Node$1 { constructor(loc, winName, options = {}) { super(loc); Object.assign(this, { winName, type: options.type, arg_list: options.arg_list || [] }); } } /********************************************************/ /* 3. statement 花括号内以';'结尾的结构是statement */ /********************************************************/ class blockNode extends Node$1 { constructor(loc, op1, stmt_list, op2) { super(loc); Object.assign(this, { op1, stmt_list, op2 }); } } class jump_statement extends Node$1 { constructor(loc, op1, op2) { super(loc); Object.assign(this, { op1, op2 }); } } class labeled_statement extends Node$1 { constructor(loc, op1, op2, op3, statement) { super(loc); Object.assign(this, { op1, op2, op3, statement }); } } class selection_statement extends Node$1 { constructor(loc, op1, op2, exp, op3, statement, op4, else_statement) { super(loc); Object.assign(this, { op1, op2, exp, op3, statement, op4, else_statement }); } } class whileNode extends Node$1 { constructor(loc, exp, statement) { super(loc); Object.assign(this, { type: 'while', op1: '(', exp, op2: ')', statement }); } } class doNode extends Node$1 { constructor(loc, exp, statement) { super(loc); Object.assign(this, { type: 'do', op1: '(', statement, op2: ')', op3: 'while', exp }); } } class forNode extends Node$1 { constructor(loc, init, cond, next, statement) { super(loc); Object.assign(this, { type: 'for', op1: '(', init, cond, next, op2: ')', statement }); } } /********************************************************/ /* 4. expression 计算表达式头节点 */ /********************************************************/ class expNode extends Node$1 { constructor(loc) { super(loc); //检查是否有常量传播插件提供的 getValue 函数 if (expNode.prototype.getValue) { expNode.prototype.getValue.call(this); } } } class unaryNode extends expNode { constructor(loc, first, second) { super(loc); Object.assign(this, { first, second }); } }class castNode extends expNode { constructor(loc, type, exp) { super(loc); Object.assign(this, { op1: '(', type, op2: ')', exp }); } } class binopNode extends expNode { constructor(loc, left, op, right) { super(loc); Object.assign(this, { left, op, right }); } } class ternaryNode extends expNode { constructor(loc, first, second, third) { super(loc); Object.assign(this, { first, op1: '?', second, op2: ':', third }); } } class parenNode extends expNode { constructor(loc, exp) { super(loc); Object.assign(this, { op1: '(', exp, op2: ')' }); } } class callNode extends expNode { constructor(loc, name, arg_list) { super(loc); this.name = name; this.op1 = '('; this.arg_list = arg_list; this.op2 = ')'; } } class constantNode extends expNode { constructor(loc, sourceStr='') { super(loc); this.source = sourceStr.toString(); } } /********************************************************/ /* operNode in expression's right */ /********************************************************/ class operNode extends Node$1 { constructor(loc) { super(loc); this.outputs = []; } } class fileReaderNode extends operNode{ constructor(loc,fileName,dataLength){ super(loc); this.fileName = fileName; this.operName = 'FileReader'; this.dataLength = dataLength - 0; // 字符串转数字 } } class fileWriterNode extends operNode{ constructor(loc,streamName,fileName,dataLength){ super(loc); this.inputs = [streamName]; this.operName = "FileWriter"; this.fileName = fileName; this.dataLength = dataLength; } } class compositeCallNode extends operNode { constructor(loc, compName, inputs, params = []) { super(loc); Object.assign(this, { compName, op1: '(', inputs, op2: ')', op3: '(', params, op4: ')' }); } } class operatorNode extends operNode { constructor(loc, operName, inputs, operBody) { super(loc); Object.assign(this, { operName, inputs: inputs ||[], operBody }); } } class splitjoinNode extends operNode { constructor(loc, options = {}) { super(loc); this.compName = options.compName; this.inputs = options.inputs; this.stmt_list = options.stmt_list; this.split = options.split; this.body_stmts = options.body_stmts; this.join = options.join; } } class pipelineNode extends operNode { constructor(loc, options = {}) { super(loc); this.compName = options.compName; this.inputs = options.inputs; this.body_stmts = options.body_stmts; } } class splitNode extends Node$1 { constructor(loc, node = {}) { super(loc); this.name = "split"; this.type = node instanceof duplicateNode ? "duplicate" : "roundrobin"; if (node.arg_list) { Object.assign(this, { op1: '(', arg_list: node.arg_list, op2: ')' }); } } } class joinNode extends Node$1 { constructor(loc, node = {}) { super(loc); this.name = "join"; this.type = node instanceof duplicateNode ? "duplicate" : "roundrobin"; if (node.arg_list) { Object.assign(this, { op1: '(', arg_list: node.arg_list, op2: ')' }); } } } class duplicateNode extends Node$1 { constructor(loc, arg_list) { super(loc); this.arg_list = arg_list; } } class roundrobinNode extends Node$1 { constructor(loc, arg_list) { super(loc); this.arg_list = arg_list; } } class addNode extends Node$1 { constructor(loc, content) { super(loc); this.name = "add"; this.content = content; } } /********************************************************/ /* 矩阵相关 node */ /********************************************************/ class matrix_constant extends expNode{ constructor(loc, rawData){ super(loc); definePrivate(this,'shape'); this.rawData = rawData.map(x => ( x instanceof matrix_constant ? x.rawData : x )); if(this.rawData[0] instanceof Array){ if(Array.isArray(this.rawData[0][0])){ error$1(loc,"暂不支持超过2维的数据, 只能是1维向量或2维矩阵"); return } this.shape = [this.rawData.length, this.rawData[0].length]; }else{ // 向量型的矩阵, 行数为1 const cols = this.rawData.length; this.shape = [1, cols]; } } } /* 存放矩阵切片的下标, 例如 vector[0:5] 表示 下标[0,5) 即0~5不含5 兼容多重格式(_表示 undefined), 例如 * [1:5] --- { start: 1, op:':', end: 5 } * [1:] --- { start: 1, op:':', end: _ } * [:5] --- { start: _, op:':', end: 5 } * [:] --- { start: _, op:':', end: _ } * [0] --- { start: 0, op: _ , end: _ } */ class matrix_slice_pair extends Node$1 { constructor(loc, start, op, end) { super(loc); this.start = start; this.op = op; this.end = end; } } /** 存放 name[1:4, 2:5] 的结构, 寓意为矩阵切片结果 */ class matrix_section extends expNode{ constructor(loc, exp, slice_pair_list){ super(loc); this.exp = exp; this.slice_pair_list = slice_pair_list; } } class lib_binopNode extends Node$1{ constructor(loc, lib_name,function_name){ super(loc); this.lib_name = lib_name; this.function_name = function_name; } } /********************************************************/ /* 神经网络相关 node */ /********************************************************/ class sequentialNode extends operNode { constructor(loc, options = {}) { super(loc); this.compName = options.compName; this.inputs = options.inputs; this.arg_list = options.arg_list; this.body_stmts = options.body_stmts; } }class layerNode extends Node$1 { constructor(loc, layerName, arg_list) { super(loc); this.layerName = layerName; this.arg_list = arg_list; this.prevLayer = null; this.nextLayer = null; this.inputSize = []; /** 神经网络层级 */ this.level = 0; } /** @returns {number[]} */ getInputSize(/** @type {sequentialNode} */ sequential){ if(this.prevLayer){ if(this.prevLayer instanceof denseLayerNode){ return [1, this.prevLayer.cols, 1] // 设置本层的输入数据规模, 用一个三维向量描述: [rows, cols, depth] }else if(this.prevLayer instanceof conv2DLayerNode){ return this.prevLayer.outputFeatureMapSize }else if(this.prevLayer instanceof maxPooling2DLayerNode){ return this.prevLayer.outputPooledSize }else if(this.prevLayer instanceof averagePooling2DLayerNode){ return this.prevLayer.outputPooledSize }else if(this.prevLayer instanceof activationLayerNode){ return this.prevLayer.inputSize }else{ error$1("未识别的 layer 类型:", this.prevLayer); } }else{ if(sequential.arg_list[0] instanceof parenNode){ return sequential.arg_list[0].exp.map(_=>_.value) } return [1, sequential.arg_list[0].value, 1] // [rows, cols, depth] } } }class denseLayerNode extends layerNode { constructor(loc, layerName, arg_list = [0]) { super(loc, layerName, arg_list); /** 权值矩阵输入 */ this.rows = 0; /** 权值矩阵输出 */ this.cols = arg_list[0].value; // FIXME: 这里简单起见直接拿到数字. 应该放到 ast2ssg 中的 } init(/** @type {sequentialNode} */ sequential){ this.inputSize = this.getInputSize(sequential); this.rows = this.inputSize.reduce((a,b)=>a*b); // 求得所有维度的乘积, 例如[1,100,1] 返回 1*100*1 = 100 } } class conv2DLayerNode extends layerNode { // filters, kernel_size, strides, padding constructor(loc, layerName, arg_list = [3, [2, 2], [1, 1], [0, 0]]) { super(loc, layerName, arg_list); try{ this.filters = arg_list[0].value; // filters // 以下三行的 '||' 操作符的意义: 当该参数是 parenNode 时, 取它的 exp. (而当 arg_list 取上方的默认值时,则不需取 exp) this.kernel_size = (arg_list[1].exp || arg_list[1]) .map(num => num.value); // kernel_size this.strides = (arg_list[2].exp || arg_list[2]) .map(num => num.value); // strides this.paddings = (arg_list[3].exp || arg_list[3]) .map(num => num.value); // paddings }catch(err){ error$1(loc, "conv2DLayerNode 参数解析错误, 请检查"); } // 以下三个成员在 init 中进行初始化 this.inputSize = []; this.outputFeatureMapSize = []; this.inputErrorSize = []; } /** 根据上一层初始化本层输出特征图的尺寸和输入空间的维度 */ init(/** @type {sequentialNode} */ sequential){ this.outputFeatureMapSize = []; // 本层反向传播过程中 传入误差的尺寸` this.inputErrorSize = []; // 按照arg_list爲傳入整個sequential結構的參數列表(rows, cols, depth) this.inputSize = this.getInputSize(sequential); this.outputFeatureMapSize = [ (this.inputSize[0] + 2 * this.paddings[0] - this.kernel_size[0]) / this.strides[0] + 1, // rows (this.inputSize[1] + 2 * this.paddings[1] - this.kernel_size[1]) / this.strides[1] + 1, // cols this.filters // depth ]; for(let i = 0; i < 2; i++) { // 2 * (kernel_size - 1) + (outputFeaureMapSize - 1)* stride + 1 this.inputErrorSize.push(2 * (this.kernel_size[i] - 1) + (this.outputFeatureMapSize[i] - 1) * this.strides[i] + 1); } } } class maxPooling2DLayerNode extends layerNode { constructor(loc, layerName, arg_list = [0]){ super(loc, layerName, arg_list); this.pool_size = arg_list[0].value; this.depth = 0; this.outputPooledSize = []; } init(/** @type {sequentialNode} */ sequential){ this.inputSize = this.getInputSize(sequential); this.outputPooledSize[0] = Math.floor(this.inputSize[0] / this.pool_size); this.outputPooledSize[1] = Math.floor(this.inputSize[1] / this.pool_size); this.outputPooledSize[2] = this.inputSize[2]; this.depth = this.inputSize[2]; } } class averagePooling2DLayerNode extends layerNode { constructor(loc, layerName, arg_list = [0]){ super(loc, layerName, arg_list); this.pool_size = arg_list[0].value; this.depth = 0; } init(/** @type {sequentialNode} */ sequential){ this.inputSize = this.getInputSize(sequential); this.outputPooledSize[0] = this.inputSize[0] / this.pool_size; this.outputPooledSize[1] = this.inputSize[1] / this.pool_size; this.outputPooledSize[2] = this.inputSize[2]; this.depth = this.inputSize[2]; } } class activationLayerNode extends layerNode { constructor(loc, layerName, arg_list){ super(loc, layerName, arg_list); this.count = 1; } init(/** @type {sequentialNode} */ sequential){ this.inputSize = this.getInputSize(sequential); this.inputSize.forEach(num => this.count*=num); } } var NodeTypes = /*#__PURE__*/Object.freeze({ __proto__: null, Node: Node$1, declareNode: declareNode, idNode: idNode, declarator: declarator, function_definition: function_definition, compositeNode: compositeNode, compHeadNode: compHeadNode, ComInOutNode: ComInOutNode, inOutdeclNode: inOutdeclNode, strdclNode: strdclNode, compBodyNode: compBodyNode, paramNode: paramNode, operBodyNode: operBodyNode, winStmtNode: winStmtNode, blockNode: blockNode, jump_statement: jump_statement, labeled_statement: labeled_statement, selection_statement: selection_statement, whileNode: whileNode, doNode: doNode, forNode: forNode, expNode: expNode, unaryNode: unaryNode, castNode: castNode, binopNode: binopNode, ternaryNode: ternaryNode, parenNode: parenNode, callNode: callNode, constantNode: constantNode, operNode: operNode, fileReaderNode: fileReaderNode, fileWriterNode: fileWriterNode, compositeCallNode: compositeCallNode, operatorNode: operatorNode, splitjoinNode: splitjoinNode, pipelineNode: pipelineNode, splitNode: splitNode, joinNode: joinNode, duplicateNode: duplicateNode, roundrobinNode: roundrobinNode, addNode: addNode, matrix_constant: matrix_constant, matrix_slice_pair: matrix_slice_pair, matrix_section: matrix_section, lib_binopNode: lib_binopNode, sequentialNode: sequentialNode, layerNode: layerNode, denseLayerNode: denseLayerNode, conv2DLayerNode: conv2DLayerNode, maxPooling2DLayerNode: maxPooling2DLayerNode, averagePooling2DLayerNode: averagePooling2DLayerNode, activationLayerNode: activationLayerNode }); var version = "0.10.3"; class FlatNode { constructor(/** @type {operatorNode} */ node, params = []) { this.name = node.operName; // opeator名字 this.PreName = node.operName; // cwb记录Operator被重命名前的名字 this.visitTimes = 0; // 表示该结点是否已经被访问过,与dumpdot有关 this._symbol_table = undefined; // 存储对应 operator 所在的 composite 的符号表. 主要目的是获取 paramNames /** @type {operatorNode} 指向operator(经常量传播后的) */ this.contents = node; /** @type {number[]}*/ this.params = params; this.nOut = 0; // 输 出 边个数 this.nIn = 0; // 输 入 边个数 //两级划分算法中,actor所在的place号、thread号、thread中的序列号 this.place_id = 0; this.thread_id = 0; this.post_thread_id = 0; this.serial_id = 0; //节点work函数的静态工作量 this.work_estimate = 0; // opeator在ssg的flatnodes中的顺序编号 this.num = 0; /** @type {FlatNode[]} 输出边各operator */ this.outFlatNodes = []; /** @type {FlatNode[]} 输入边各operator */ this.inFlatNodes = []; /** @type {number[]} */ this.outPushWeights = []; // 输 出 边各权重 this.inPopWeights = []; // 输 入 边各权重 this.inPeekWeights = []; // 输 入 边各权重 /** init调度次数 */ this.initCount = 0; /** 稳态调度次数 */ this.steadyCount = 0; /** 阶段号 */ this.stageNum = 0; } AddOutEdges(/*FlatNode */ dest) { this.outFlatNodes.push(dest); this.nOut++; } AddInEdges(/*FlatNode */ src) { this.inFlatNodes.push(src); this.nIn++; } // 访问该结点 VisitNode() { this.visitTimes++; } ResetVisitTimes() { this.visitTimes = 0; } } const MAX_SCOPE_DEPTH = 100; //定义最大嵌套深度为100 /** @type {SymbolTable[]} */ let runningStack = []; const current_version = Array.from({length:MAX_SCOPE_DEPTH}).fill(0); const symbolTableList = /** @type{SymbolTable[]}*/[]; class Variable { constructor(valType, name, i, _loc) { this.type = valType; if(valType !== 'Matrix'){ if(Array.isArray(i)){ this.shape = [i.length,1]; }else{ this.shape = [1,1]; } } this.name = name; this._loc = _loc; /** @type {Node} */ this.value = i; } } class CompositeSymbol { constructor(/** @type {compositeNode} */ comp) { this.composite = comp; this.count = 0; // 用于区分多次调用同一 composite } } class SymbolTable { constructor(prev, loc) { this.count = 0; // FIXME: 不确定有什么用 this.root = prev ? prev.root : this; // 标记全局最根部的符号表 this.loc = loc; /** @type {SymbolTable} */ this.prev = prev; symbolTableList.push(this); this.sid = SymbolTable.sid++; this.funcTable = {}; /** @type {Dict<{strType: strdclNode, fromIndex: number, fromFlatNode:FlatNode, toIndex: number, toFlatNode: FlatNode}>} */ this.streamTable = {}; /** @type {Dict<Variable>} */ this.memberTable = {}; // 专门用来存储一个operator的成员变量字段 this.paramNames = prev && prev.paramNames.length > 0 ? prev.paramNames : []; // 子符号表继承父符号表的paramNames /** @type {Dict<Variable>} */ this.variableTable = {}; //变量 this.compTable = {}; // composite this.optTable = {}; //operator this.shapeCache = new Map(); }; getPrev() { return this.prev; } /** @returns { {type: 'variable'|'stream' |'func'|'oper'|'member', origin: SymbolTable}} */ searchName(name){ if(this.variableTable.hasOwnProperty(name)) return { type: 'variable', origin: this} if(this.streamTable.hasOwnProperty(name)) return { type: 'stream', origin: this} if(this.funcTable.hasOwnProperty(name)) return { type: 'func', origin: this} if(this.optTable.hasOwnProperty(name)) return { type: 'oper', origin: this} if(this.memberTable.hasOwnProperty(name)) return { type: 'member', origin: this} if(this.prev) return this.prev.searchName(name) return undefined; } getVariableValue(name){ return this.LookupIdentifySymbol(name).value; } setVariableValue(name,val){ return this.LookupIdentifySymbol(name).value = val } getExactSymbolTable(name){ if(this.variableTable[name]) return this return this.prev && this.prev.getExactSymbolTable(name) } /** @returns{Variable} */ LookupIdentifySymbol(name){ if(this.variableTable[name]) return this.variableTable[name] if(this.prev){ return this.prev.LookupIdentifySymbol(name) }else{ console.warn(`在符号表中查找不到该变量的值: ${name}`); return new Variable('double',name,0) } } InsertCompositeSymbol(/** @type {compositeNode} */comp){ this.compTable[comp.compName] = new CompositeSymbol(comp); } InsertStreamSymbol(/** @type {inOutdeclNode} */ inOutNode){ const name = inOutNode.id; if(this.streamTable[name]){ error(inOutNode._loc,`数据流名 ${name} 重复定义, 已忽略该定义`); }else{ this.streamTable[name]= { strType: inOutNode.strType.copy() }; } } InsertOperatorSymbol(name, operatorNode){ this.optTable[name] = operatorNode; } InsertMemberSymbol(/** @type {declareNode} */ decl){ decl.init_declarator_list.forEach((/** @type {declarator} */de) =>{ let name = de.identifier.name; let { initializer, arg_list } = de.identifier; if(de.identifier.arg_list.length){ var variable = new Variable(de.type,name,undefined, de._loc); variable.shape = arg_list.map(_=>_.value); }else{ var variable = new Variable(de.type,name,initializer, de._loc); } this.memberTable[name] = variable; }); } LookupFunctionSymbol(name){ if(this.funcTable[name]) return this.funcTable[name] if(this.prev){ return this.prev.LookupFunctionSymbol(name) }else{ console.warn(`在符号表中查找不到该函数: ${name}`); } } } SymbolTable.sid = 0; // 类的静态类型, 类似 vue 的 cid, 用来区分生成的符号表的顺序 SymbolTable.prototype.InsertIdentifySymbol = function InsertIdentifySymbol(/** @type {Variable} */ node){ if(node instanceof Variable){ let name = node.name; if(this.variableTable[name]) { throw new Error(error(node._loc,`${name} 重复定义`)) }else{ this.variableTable[name]= node; } }else{ throw new Error("插入 IndetifySymbol 时出错, node 类型错误") } }; //对外的包装对象 var COStreamJS = { S : null, gMainComposite : null, files: {}, options: { platform: 'default' }, plugins: { matrix: false, image: false }, version }; COStreamJS.__proto__ = {}; /** @type {SymbolTable} */ let top; function setTop(newTop){ top = newTop; } /* parser generated by jison 0.4.18 */ /* Returns a Parser object of the following structure: Parser: { yy: {} } Parser.prototype: { yy: {}, trace: function(), symbols_: {associative list: name ==> number}, terminals_: {associative list: number ==> name}, productions_: [...], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), table: [...], defaultActions: {...}, parseError: function(str, hash), parse: function(input), lexer: { EOF: 1, parseError: function(str, hash), setInput: function(input), input: function(), unput: function(str), more: function(), less: function(n), pastInput: function(), upcomingInput: function(), showPosition: function(), test_match: function(regex_match_array, rule_index), next: function(), lex: function(), begin: function(condition), popState: function(), _currentRules: function(), topState: function(), pushState: function(condition), options: { ranges: boolean (optional: true ==> token location info will include a .range[] member) flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) }, performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), rules: [...], conditions: {associative list: name ==> set}, } } token location info (@$, _$, etc.): { first_line: n, last_line: n, first_column: n, last_column: n, range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) } the parseError function receives a 'hash' object with these members for lexer and parser errors: { text: (matched text) token: (the produced terminal token, if any) line: (yylineno) } while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { loc: (yylloc) expected: (string describing the set of expected tokens) recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) } */ var parser = (function(){ var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,7],$V1=[1,21],$V2=[1,15],$V3=[1,22],$V4=[1,13],$V5=[1,16],$V6=[1,17],$V7=[1,18],$V8=[1,19],$V9=[1,20],$Va=[5,10,11,38,44,146,147,148,149,150,151],$Vb=[1,28],$Vc=[1,29],$Vd=[22,23],$Ve=[22,23,24],$Vf=[2,187],$Vg=[12,18],$Vh=[2,13],$Vi=[1,44],$Vj=[1,43],$Vk=[12,18,20,23,24,25],$Vl=[5,10,11,12,22,23,25,30,32,38,44,52,57,58,61,68,80,82,84,86,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,138,139,146,147,148,149,150,151],$Vm=[11,12,22,23,25,30,44,52,57,58,80,82,84,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,146,147,148,149,150,151],$Vn=[1,68],$Vo=[1,78],$Vp=[1,66],$Vq=[1,82],$Vr=[1,72],$Vs=[1,71],$Vt=[1,79],$Vu=[1,80],$Vv=[1,63],$Vw=[1,64],$Vx=[1,69],$Vy=[1,70],$Vz=[1,73],$VA=[1,74],$VB=[1,75],$VC=[1,76],$VD=[1,77],$VE=[1,85],$VF=[1,118],$VG=[1,104],$VH=[1,103],$VI=[1,114],$VJ=[1,101],$VK=[1,102],$VL=[1,106],$VM=[1,107],$VN=[1,108],$VO=[1,109],$VP=[1,110],$VQ=[1,111],$VR=[1,112],$VS=[1,113],$VT=[1,127],$VU=[12,18,24],$VV=[12,18,24,27,32,81],$VW=[2,157],$VX=[1,140],$VY=[1,141],$VZ=[1,134],$V_=[1,135],$V$=[1,132],$V01=[1,133],$V11=[1,136],$V21=[1,137],$V31=[1,138],$V41=[1,139],$V51=[1,142],$V61=[1,143],$V71=[1,144],$V81=[1,145],$V91=[1,146],$Va1=[1,147],$Vb1=[1,148],$Vc1=[1,149],$Vd1=[1,131],$Ve1=[12,18,24,27,32,45,47,81,113,114,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132],$Vf1=[2,138],$Vg1=[12,18,20,24,27,32,45,47,81,113,114,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132,134],$Vh1=[12,18,20,23,24,25,27,32,45,47,81,103,104,105,113,114,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132,134],$Vi1=[1,162],$Vj1=[11,22,23,25,57,58,99,100,104,105,106,107,109,113,114,115,116],$Vk1=[12,18,32],$Vl1=[11,12,22,23,25,30,32,44,52,57,58,61,68,80,82,84,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,138,139,146,147,148,149,150,151],$Vm1=[11,12,22,23,25,30,32,44,52,57,58,61,68,80,82,84,86,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,138,139,146,147,148,149,150,151],$Vn1=[11,12,22,23,24,25,30,32,44,52,57,58,61,68,80,82,84,86,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,138,139,146,147,148,149,150,151],$Vo1=[1,181],$Vp1=[12,18,24,27],$Vq1=[18,47],$Vr1=[1,236],$Vs1=[18,32],$Vt1=[5,10,11,12,22,23,25,30,32,38,44,52,57,58,61,68,80,82,84,86,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,138,139,140,146,147,148,149,150,151],$Vu1=[18,24],$Vv1=[12,18,24,27,32,45,47,81,113,114,120,121,122,123,124,125,126,127,128,129,130,132],$Vw1=[12,18,24,27,32,45,47,81,120,121,122,123,124,125,126,129,130,132],$Vx1=[12,18,24,27,32,81,120,121,122,125,126,129,130,132],$Vy1=[12,18,24,27,32,45,47,81,120,121,122,123,124,125,126,127,128,129,130,132],$Vz1=[1,279],$VA1=[2,167],$VB1=[18,27],$VC1=[12,18,20,23,24,25,27,30,32,45,47,81,103,104,105,113,114,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132,134],$VD1=[1,285],$VE1=[1,303],$VF1=[1,316],$VG1=[1,339],$VH1=[2,170],$VI1=[1,350],$VJ1=[1,364],$VK1=[1,374],$VL1=[1,396],$VM1=[22,32],$VN1=[11,12,22,23,25,30,32,44,52,57,58,80,82,84,87,88,89,90,91,92,93,99,100,104,105,106,107,109,113,114,115,116,146,147,148,149,150,151]; var parser = {trace: function trace () { }, yy: {}, symbols_: {"error":2,"prog_start":3,"translation_unit":4,"EOF":5,"external_declaration":6,"function_definition":7,"declaration":8,"composite_definition":9,"IMPORT":10,"MATRIX":11,";":12,"declaring_list":13,"stream_declaring_list":14,"type_specifier":15,"init_declarator_list":16,"init_declarator":17,",":18,"declarator":19,"=":20,"initializer":21,"IDENTIFIER":22,"(":23,")":24,"[":25,"constant_expression":26,"]":27,"stream_type_specifier":28,"assignment_expression":29,"{":30,"initializer_list":31,"}":32,"parameter_type_list":33,"compound_statement":34,"parameter_declaration":35,"composite_head":36,"composite_body":37,"COMPOSITE":38,"composite_head_inout":39,"INPUT":40,"composite_head_inout_member_list":41,"OUTPUT":42,"composite_head_inout_member":43,"STREAM":44,"<":45,"stream_declaration_list":46,">":47,"composite_body_param_opt":48,"statement_list":49,"PARAM":50,"operator_add":51,"ADD":52,"operator_pipeline":53,"operator_splitjoin":54,"operator_layer":55,"operator_default_call":56,"PIPELINE":57,"SPLITJOIN":58,"split_statement":59,"join_statement":60,"SPLIT":61,"duplicate_statement":62,"roundrobin_statement":63,"ROUNDROBIN":64,"argument_expression_list":65,"DUPLICATE":66,"exp":67,"JOIN":68,"DENSE":69,"CONV2D":70,"MAXPOOLING2D":71,"AVERAGEPOOLING2D":72,"ACTIVATION":73,"statement":74,"labeled_statement":75,"expression_statement":76,"selection_statement":77,"iteration_statement":78,"jump_statement":79,"CASE":80,":":81,"DEFAULT":82,"multi_expression":83,"IF":84,"expression":85,"ELSE":86,"SWITCH":87,"WHILE":88,"DO":89,"FOR":90,"CONTINUE":91,"BREAK":92,"RETURN":93,"matrix_slice_pair":94,"matrix_slice_pair_list":95,"matrix_slice":96,"vector_expression":97,"primary_expression":98,"NUMBER":99,"STRING_LITERAL":100,"operator_arguments":101,"postfix_expression":102,".":103,"++":104,"--":105,"FILEREADER":106,"FILEWRITER":107,"operator_selfdefine_body":108,"SEQUENTIAL":109,"unary_expression":110,"unary_operator":111,"basic_type_name":112,"+":113,"-":114,"~":115,"!":116,"*":117,"/":118,"%":119,"^":120,"|":121,"&":122,"<=":123,">=":124,"==":125,"!=":126,"<<":127,">>":128,"||":129,"&&":130,"conditional_expression":131,"?":132,"assignment_operator":133,"ASSIGNMENT_OPERATOR":134,"operator_selfdefine_body_init":135,"operator_selfdefine_body_work":136,"operator_selfdefine_body_window_list":137,"INIT":138,"WORK":139,"WINDOW":140,"operator_selfdefine_window_list":141,"operator_selfdefine_window":142,"window_type":143,"SLIDING":144,"TUMBLING":145,"CONST":146,"INT":147,"LONG":148,"FLOAT":149,"DOUBLE":150,"STRING":151,"$accept":0,"$end":1}, terminals_: {2:"error",5:"EOF",10:"IMPORT",11:"MATRIX",12:";",18:",",20:"=",22:"IDENTIFIER",23:"(",24:")",25:"[",27:"]",30:"{",32:"}",38:"COMPOSITE",40:"INPUT",42:"OUTPUT",44:"STREAM",45:"<",47:">",50:"PARAM",52:"ADD",57:"PIPELINE",58:"SPLITJOIN",61:"SPLIT",64:"ROUNDROBIN",66:"DUPLICATE",68:"JOIN",69:"DENSE",70:"CONV2D",71:"MAXPOOLING2D",72:"AVERAGEPOOLING2D",73:"ACTIVATION",80:"CASE",81:":",82:"DEFAULT",84:"IF",86:"ELSE",87:"SWITCH",88:"WHILE",89:"DO",90:"FOR",91:"CONTINUE",92:"BREAK",93:"RETURN",99:"NUMBER",100:"STRING_LITERAL",103:".",104:"++",105:"--",106:"FILEREADER",107:"FILEWRITER",109:"SEQUENTIAL",113:"+",114:"-",115:"~",116:"!",117:"*",118:"/",119:"%",120:"^",121:"|",122:"&",123:"<=",124:">=",125:"==",126:"!=",127:"<<",128:">>",129:"||",130:"&&",132:"?",134:"ASSIGNMENT_OPERATOR",138:"INIT",139:"WORK",140:"WINDOW",144:"SLIDING",145:"TUMBLING",146:"CONST",147:"INT",148:"LONG",149:"FLOAT",150:"DOUBLE",151:"STRING"}, productions_: [0,[3,2],[4,1],[4,2],[6,1],[6,1],[6,1],[6,3],[8,2],[8,2],[13,2],[16,1],[16,3],[17,1],[17,3],[19,1],[19,3],[19,4],[19,3],[14,2],[14,3],[21,1],[21,3],[21,4],[31,1],[31,3],[7,6],[7,5],[33,1],[33,3],[35,2],[9,2],[36,5],[39,0],[39,2],[39,5],[39,2],[39,5],[41,1],[41,3],[43,2],[28,4],[46,2],[46,4],[37,4],[48,0],[48,3],[51,2],[51,2],[51,2],[51,2],[53,4],[54,6],[54,7],[59,2],[59,2],[63,4],[63,5],[62,4],[62,5],[60,2],[56,4],[56,5],[55,5],[55,5],[55,5],[55,5],[55,5],[74,1],[74,1],[74,1],[74,1],[74,1],[74,1],[74,1],[74,1],[75,4],[75,3],[34,2],[34,3],[49,1],[49,2],[76,1],[76,2],[77,5],[77,7],[77,5],[78,5],[78,7],[78,6],[78,7],[79,2],[79,2],[79,2],[79,3],[94,1],[94,1],[94,2],[94,2],[94,3],[95,1],[95,3],[96,3],[97,3],[83,1],[83,3],[98,1],[98,1],[98,1],[98,3],[98,1],[101,2],[101,3],[102,1],[102,2],[102,2],[102,3],[102,3],[102,2],[102,2],[102,8],[102,9],[102,3],[102,9],[102,10],[102,7],[102,10],[65,1],[65,3],[110,1],[110,2],[110,2],[110,2],[110,4],[111,1],[111,1],[111,1],[111,1],[67,1],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[67,3],[131,1],[131,5],[29,1],[29,3],[133,1],[133,1],[85,1],[26,1],[108,5],[108,6],[135,0],[135,2],[136,2],[137,0],[137,4],[141,1],[141,2],[142,3],[143,3],[143,3],[143,4],[143,4],[15,1],[15,2],[112,1],[112,1],[112,2],[112,1],[112,1],[112,1],[112,1]], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { /* this == yyval */ var $0 = $$.length - 1; switch (yystate) { case 1: return $$[$0-1] case 2: case 11: case 100: this.$ = [$$[$0]]; break; case 3: case 12: case 29: case 39: case 128: case 173: this.$.push($$[$0]); break; case 7: COStreamJS.plugins.matrix = true; break; case 8: case 9: case 22: case 41: case 83: case 102: case 112: case 171: this.$ = $$[$0-1]; break; case 10: this.$ = new declareNode(this._$,$$[$0-1],$$[$0]); $$[$0].forEach(d=>d.type=$$[$0-1]); break; case 13: this.$ = new declarator(this._$,$$[$0],undefined); break; case 14: this.$ = new declarator(this._$,$$[$0-2],$$[$0]); break; case 15: this.$ = new idNode(this._$,$$[$0]); break; case 16: