* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { NapiLog } = require("./NapiLog");
const re = require("./re")
var DataType = {
INT8: 1,
INT16: 2,
INT32: 3,
INT64: 4,
STRING: 5,
NODE: 6,
ATTR: 7,
ARRAY: 8,
REFERENCE: 9,
DELETE: 10,
BOOL: 11,
}
var NodeType = {
DATA: 0,
COPY: 1,
REFERENCE: 2,
DELETE: 3,
TEMPLETE: 4,
INHERIT: 5,
}
class NodeTools {
}
function getRoot(node) {
while (node.parent_ != undefined)
node = node.parent_
return node;
}
NodeTools.isElders = function (node, elders) {
while (node != undefined) {
if (node == elders) {
return true;
}
node = node.parent_
}
return false;
}
NodeTools.getPathByNode = function (node) {
if (node == null) return "";
let ret = node.name_;
while (node.parent_ != undefined) {
node = node.parent_;
if (node.nodeType_ == NodeType.REFERENCE) {
node = NodeTools.getNodeByPath(getRoot(node), node.ref_);
}
ret = node.name_ + "." + ret;
}
return ret;
}
NodeTools.getNodeByPath = function (node, path) {
let ps = path.split(".")
if (ps[0] == "root") ps.shift()
for (let p in ps) {
node = NodeTools.findChildByName(node, ps[p])
if (node == null) return null;
}
return node;
}
NodeTools.lookupInherit = function (node) {
if (node.type_ == DataType.NODE && node.nodeType_ == NodeType.INHERIT &&
node.parent_.nodeType_ == NodeType.INHERIT) {
let p = NodeTools.lookupInherit(node.parent_);
if (p == null) return p;
return NodeTools.findChildByName(p, node.ref_);
}
return NodeTools.findChildByName(node.parent_, node.ref_);
}
NodeTools.lookup = function (node) {
let refname;
if (node.type_ == DataType.NODE &&
(node.nodeType_ == NodeType.COPY ||
node.nodeType_ == NodeType.REFERENCE ||
node.nodeType_ == NodeType.INHERIT))
refname = node.ref_;
else if (node.type_ == DataType.ATTR &&
node.value_.type_ == DataType.REFERENCE)
refname = node.value_.value_;
else return null;
if (refname.indexOf(".") >= 0) return NodeTools.getNodeByPath(getRoot(node), refname);
let ret = NodeTools.findChildByName(node.parent_, refname);
if (ret == null) {
if (node.type_ == DataType.NODE && node.nodeType_ == NodeType.INHERIT &&
node.parent_.nodeType_ == NodeType.INHERIT) {
ret = NodeTools.lookupInherit(node);
}
}
return ret;
}
NodeTools.recursionNode = function (node, callback) {
if (node.type_ == DataType.NODE) {
callback(node)
for (let n in node.value_) {
NodeTools.recursionNode(node.value_[n], callback)
}
}
}
NodeTools.recursionAll = function (node, callback, isForward) {
let ret = false;
if (isForward) ret = callback(node)
if (node.type_ == DataType.NODE) {
for (let i = 0; i < node.value_.length; i++) {
if (NodeTools.recursionAll(node.value_[i], callback, isForward))
i--;
}
}
if (!isForward) ret = callback(node)
return ret;
}
NodeTools.redefineCheck = function (node) {
let ret = true;
NodeTools.recursionNode(node, (pn) => {
let nameMap = [];
for (let i in pn.value_) {
if (nameMap.indexOf(pn.value_[i].name_) >= 0) {
pn.value_[i].errMsg_ = "重名"
ret = false;
}
else {
nameMap.push(pn.value_[i].name_)
pn.value_[i].errMsg_ = null;
}
}
})
return ret;
}
function separate(node) {
let pn = node.parent_;
if (pn == null)
return;
for (let i in pn.value_) {
if (pn.value_[i] == node) {
pn.value_.splice(i, 1);
}
}
}
NodeTools.findChildByName = function (node, name) {
for (let i in node.value_) {
if (node.value_[i].name_ == name) {
return node.value_[i]
}
}
return null;
}
NodeTools.copyNode = function (node, parent) {
let ret = {
type_: node.type_,
name_: node.name_,
parent_: parent
}; if (node.raw_ != undefined)
ret.raw_ = node.raw_
switch (node.type_) {
case DataType.INT8:
case DataType.INT16:
case DataType.INT32:
case DataType.INT64:
ret.value_ = node.value_
ret.jinzhi_ = node.jinzhi_
break;
case 5:
ret.value_ = node.value_;
break;
case 6:
ret.nodeType_ = node.nodeType_;
if ([NodeType.INHERIT, NodeType.COPY, NodeType.REFERENCE].indexOf(node.nodeType_) > -1) {
ret.ref_ = node.ref_;
} else if (!([NodeType.DATA, NodeType.TEMPLETE, NodeType.DELETE].indexOf(node.nodeType_) > -1)) {
NapiLog.logError("unknow node type");
}
ret.value_ = []
for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)) }
break;
case 7:
ret.value_ = NodeTools.copyNode(node.value_, ret)
break;
case 8:
ret.value_ = []
for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)) }
break;
case 9:
ret.value_ = node.value_;
break;
case 10:
ret.value_ = null;
break;
case 11:
ret.value_ = node.value_
break;
default:
NapiLog.logInfo("unknow", node.type_)
break;
}return ret;
}
function makeError(node, errStr) {
if (node.raw_ != undefined) {
node.raw_.errMsg_ = errStr;
}
}
NodeTools.nodeNestCheck = function (node) {
NodeTools.recursionAll(node, (pn) => {
if (pn.type_ == DataType.NODE) {
if (pn.nodeType_ == NodeType.COPY && pn.raw_.errMsg_ == null) {
pn.raw_.errMsg_ = "有Copy的嵌套";
}
}
return false;
}, false);
}
NodeTools.recursionCopyAndReferenceNodes = function (pn) {
let ref = NodeTools.lookup(pn);
if (ref == null) {
NapiLog.logError("reference not exist" + NodeTools.getPathByNode(pn) + ":" + pn.ref_);
if (pn.nodeType_ == NodeType.COPY) makeError(pn, "复制目标没找到")
else makeError(pn, "引用目标没找到")
return false;
} else if (ref.nodeType_ == NodeType.TEMPLETE) {
if (pn.nodeType_ == NodeType.COPY) makeError(pn, "复制目标不能为模板节点")
else makeError(pn, "引用目标不能为模板节点")
return false;
} else if (ref.nodeType_ == NodeType.DELETE) {
if (pn.nodeType_ == NodeType.COPY) makeError(pn, "复制目标不能为删除节点")
else makeError(pn, "引用目标不能为删除节点")
return false;
} else if (NodeTools.isElders(pn, ref)) {
NapiLog.logError("circular reference" + NodeTools.getPathByNode(pn) + ":" + pn.ref_);
if (pn.nodeType_ == NodeType.COPY) {
makeError(pn, "循环复制")
} else {
makeError(pn, "循环引用")
}
return false;
} else if (pn.nodeType_ == NodeType.COPY) {
if (ref.nodeType_ == NodeType.COPY) {
pn.raw_.errMsg_ = "有Copy的嵌套";
}
pn.nodeType_ = NodeType.DATA;
let tref = NodeTools.copyNode(ref, pn.parent_);
tref.name_ = pn.name_;
NodeTools.merge(tref, pn)
pn.value_ = tref.value_;
return false;
} else if (pn.nodeType_ == NodeType.REFERENCE) {
pn.nodeType_ = ref.nodeType_; pn.name_ = ref.name_;
NodeTools.merge(ref, pn)
separate(pn);
return true;
}
return false;
}
NodeTools.checkInheritNode = function (pn) {
let ref = NodeTools.lookup(pn);
if (ref == null) {
makeError(pn, "找不到继承目标")
} else if (ref.type_ != DataType.NODE) {
makeError(pn, "不能继承属性")
} else if (ref.nodeType_ == NodeType.REFERENCE) {
makeError(pn, "不能继承引用类节点")
} else if (ref.nodeType_ == NodeType.DELETE) {
makeError(pn, "不能继承删除类节点")
} else if (ref.nodeType_ == NodeType.DATA) {
makeError(pn, "不能继承数据类节点")
} else if (ref.nodeType_ == NodeType.INHERIT) {
makeError(pn, "不能继承继承类节点")
} else if (ref.nodeType_ == NodeType.COPY) {
makeError(pn, "不能继承复制类节点")
}
}
NodeTools.nodeExpand = function (node) {
NodeTools.recursionAll(node, (pn) => {
if (pn.type_ == DataType.NODE) {
if (pn.nodeType_ == NodeType.DELETE) {
separate(pn);
return true;
} if (pn.nodeType_ == NodeType.COPY || pn.nodeType_ == NodeType.REFERENCE) {
return NodeTools.recursionCopyAndReferenceNodes(pn);
} if (pn.nodeType_ == NodeType.INHERIT) {
NodeTools.checkInheritNode(pn);
}
}
else if (pn.type_ == DataType.ATTR) {
if (pn.value_.type_ == DataType.DELETE) {
separate(pn);
return true;
} if (pn.value_.type_ == DataType.REFERENCE) {
let ref = NodeTools.lookup(pn);
if (ref == null || ref.type_ != DataType.NODE || ref.nodeType_ == NodeType.REFERENCE ||
ref.nodeType_ == NodeType.TEMPLETE || ref.nodeType_ == NodeType.DELETE) {
NapiLog.logError("reference invalid node" + NodeTools.getPathByNode(pn) + ":" + pn.value_.value_);
if (ref == null) makeError(pn, "找不到引用目标")
else if (ref.type_ != DataType.NODE) makeError(pn, "不能引用属性")
else if (ref.nodeType_ == NodeType.REFERENCE) makeError(pn, "不能引用引用类节点")
else if (ref.nodeType_ == NodeType.TEMPLETE) makeError(pn, "不能引用模板类节点")
else if (ref.nodeType_ == NodeType.DELETE) makeError(pn, "不能引用删除类节点")
} else {
pn.refNode_ = ref;
}
}
}
return false;
}, false);
}
NodeTools.inheritExpand = function (node) {
NodeTools.recursionAll(node, (pn) => {
let tt = re.match("^[a-zA-Z_]{1}[a-zA-Z_0-9]*$", pn.name_);
if (tt == null) {
makeError(pn, "名字不合规范")
}
if (pn.type_ != DataType.NODE) return false;
if (pn.nodeType_ != NodeType.INHERIT) return false;
let inherit = NodeTools.lookup(pn);
if (inherit == null) {
NapiLog.logError("inherit invalid node: " + NodeTools.getPathByNode(pn) + ":" + pn.ref_);
makeError(pn, "找不到继承目标")
return false;
}
pn.nodeType_ = NodeType.DATA;
let tinherit = NodeTools.copyNode(inherit, pn.parent_);
NodeTools.merge(tinherit, pn)
pn.value_ = tinherit.value_
return false;
}, true);
}
NodeTools.merge = function (node1, node2) {
if (node2 == null) {
return true;
}
if (node2.raw_ == undefined)
node1.raw_ = node2
else
node1.raw_ = node2.raw_
if (node1.type_ == DataType.NODE) {
if (node1.name_ != node2.name_) {
return false;
}
node1.nodeType_ = node2.nodeType_;
if (node2.nodeType_ == NodeType.INHERIT || node2.nodeType_ == NodeType.REFERENCE
|| node2.nodeType_ == NodeType.COPY) node1.ref_ = node2.ref_
if (node1.value_ == undefined) node1.value_ = [];
for (let i in node2.value_) {
let child2 = node2.value_[i];
let child1 = NodeTools.findChildByName(node1, child2.name_)
if (child1 == null) {
child1 = {
type_: child2.type_,
name_: child2.name_,
parent_: node1
}
node1.value_.push(child1)
}
else if (child1.type_ != child2.type_) {
child2.raw_.errMsg_ = "所修改的字节的类型和父节点类型不同";
return false;
}
NodeTools.merge(child1, child2);
}
}
else if (node1.type_ == DataType.ATTR) {
node1.value_ = NodeTools.copyNode(node2.value_, node1)
}
return true;
}
NodeTools.jinZhi10ToX = function (num, jinzhi) {
let ret;
switch (jinzhi) {
case 2:
ret = "0b"
break;
case 8:
ret = "0"
break;
case 10:
ret = ""
break;
case 16:
ret = "0x"
break;
default:
NapiLog.logError(jinzhi + "进制转换失败")
break;
}
return ret + num.toString(jinzhi);
}
NodeTools.jinZhiXTo10 = function (s) {
if (s == null || s.length == 0)
return [0, 10]
if (s[0] == '0') {
if (s.length == 1) {
return [parseInt(s, 10), 10];
}
else if (s[1] == 'b') {
return [parseInt(s.substring(2), 2), 2];
}
else if (s[1] == 'x' || s[1] == 'X') {
return [parseInt(s.substring(2), 16), 16];
}
else {
return [parseInt(s.substring(1), 8), 8];
}
}
else {
return [parseInt(s, 10), 10];
}
}
NodeTools.createNewNode = function (type, name, value, nodetype) {
let ret = new Object();
ret.type_ = type;
ret.name_ = name;
ret.value_ = value;
if (type < DataType.STRING) ret.jinzhi_ = 10;
if (type == DataType.NODE) ret.nodeType_ = nodetype;
return ret;
}
NodeTools.arrayToString = function (node, maxw) {
let ret = ""
let type = DataType.INT8;
for (let d in node.value_) {
if (type < node.value_[d].type_) type = node.value_[d].type_;
}
let line = ""
for (let d in node.value_) {
if (d > 0) {
line += ","
if (maxw != undefined) {
if (line.length >= maxw) {
ret += line + "\n";
line = "";
}
}
}
if (type == DataType.STRING)
line += '"' + node.value_[d].value_ + '"';
else
line += NodeTools.jinZhi10ToX(node.value_[d].value_, node.value_[d].jinzhi_);
}
ret += line;
return ret;
}
NodeTools.stringToArray = function (s) {
let type = DataType.INT8;
let ret = [];
s = s.replace(/\n/g, "")
if (s.length <= 0)
return ret;
if (s.indexOf('"') >= 0) {
type = DataType.STRING;
let p = 0;
let stat = 0;
let v
while (p < s.length && stat < 100) {
switch (stat) {
case 0:
if (s[p] == '"') {
stat = 1; v = "";
}
else if (s[p] != ' ') stat = 100;
break;
case 1:
if (s[p] == '"') {
stat = 2;
ret.push(NodeTools.createNewNode(type, "", v))
}
else v += s[p]
break;
case 2:
if (s[p] == ',') stat = 0;
else if (s[p] != ' ') stat = 100;
break;
}
p += 1;
}
} else {
let arr = s.split(",");
stringToArrayWithQuote(ret, type, arr);
} return ret;
}
function stringToArrayWithQuote(ret, type, arr) {
for (let i in arr) {
let num = NodeTools.jinZhiXTo10(arr[i])
if (isNaN(num[0])) num[0] = 0;
let attr = NodeTools.createNewNode(type, "", num[0]);
attr.jinzhi_ = num[1]
ret.push(attr)
if (num[0] <= 0xff) {
if (type < DataType.INT8) type = DataType.INT8;
}
else if (num[0] <= 0xffff) {
if (type < DataType.INT16) type = DataType.INT16;
}
else if (num[0] <= 0xffffffff) {
if (type < DataType.INT32) type = DataType.INT32;
}
else {
type = DataType.INT64;
}
}
if (type != DataType.INT8) {
for (let i in ret) {
ret[i].type_ = type;
}
}
}
module.exports = {
NodeTools,
DataType,
NodeType
}