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
JavaScript
#!/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: