1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const { NapiLog } = require('./NapiLog');
17const re = require('./re');
18
19const MAX_DECIMAL = 10;
20const MAX_BINARY = 2;
21const MAX_OCTAL = 8;
22const MAX_HEXADECIMAL = 16;
23const STAT_SIZE = 100;
24
25const DataType = {
26  INT8: 1,
27  INT16: 2,
28  INT32: 3,
29  INT64: 4,
30  STRING: 5,
31  NODE: 6,
32  ATTR: 7,
33  ARRAY: 8,
34  REFERENCE: 9,
35  DELETE: 10,
36  BOOL: 11,
37};
38const NodeType = {
39  DATA: 0,
40  COPY: 1,
41  REFERENCE: 2,
42  DELETE: 3,
43  TEMPLETE: 4,
44  INHERIT: 5,
45};
46
47class NodeTools {}
48
49function getRoot(node) {
50  while (node.parent_ !== undefined) {
51    node = node.parent_;
52  }
53  return node;
54}
55
56NodeTools.isElders = function (node, elders) {
57  while (node !== undefined) {
58    if (node === elders) {
59      return true;
60    }
61    node = node.parent_;
62  }
63  return false;
64};
65
66NodeTools.getPathByNode = function (node, expandRef = true) {
67  if (node === null) {
68    return '';
69  }
70  let ret = node.name_;
71  while (node !== null && node.parent_ !== undefined) {
72    node = node.parent_;
73    if (expandRef && node.nodeType_ === NodeType.REFERENCE) {
74      if (node.ref_.startsWith(getRoot(node).name_)) {
75        node = NodeTools.getNodeByPath(getRoot(node), node.ref_);
76      } else {
77        node = NodeTools.getNodeByPath(node.parent_, node.ref_);
78      }
79    }
80    if (node !== null) {
81      ret = node.name_ + '.' + ret;
82    }
83  }
84  return ret;
85};
86NodeTools.getNodeByPath = function (node, path) {
87  let ps = path.split('.');
88  if (ps[0] === 'root') {
89    ps.shift();
90  }
91  for (let p in ps) {
92    node = NodeTools.findChildByName(node, ps[p]);
93    if (node === null) {
94      return null;
95    }
96  }
97  return node;
98};
99
100NodeTools.lookupInherit = function (node) {
101  if (
102    node.type_ === DataType.NODE &&
103    node.nodeType_ === NodeType.INHERIT &&
104    node.parent_.nodeType_ === NodeType.INHERIT
105  ) {
106    let p = NodeTools.lookupInherit(node.parent_);
107    if (p === null) {
108      return p;
109    }
110    return NodeTools.findChildByName(p, node.ref_);
111  }
112  return NodeTools.findChildByName(node.parent_, node.ref_);
113};
114
115NodeTools.lookup = function (node) {
116  let refname;
117  if (
118    node.type_ === DataType.NODE &&
119    (node.nodeType_ === NodeType.COPY ||
120      node.nodeType_ === NodeType.REFERENCE ||
121      node.nodeType_ === NodeType.INHERIT)
122  ) {
123    refname = node.ref_;
124  }
125  else if (
126    node.type_ === DataType.ATTR &&
127    node.value_.type_ === DataType.REFERENCE
128  ) {
129    refname = node.value_.value_;
130  }
131  else { return null; }
132  if (refname.indexOf('.') >= 0) {
133    return NodeTools.getNodeByPath(getRoot(node), refname);
134  }
135
136  let ret = NodeTools.findChildByName(node.parent_, refname);
137  if (ret === null) {
138    if (
139      node.type_ === DataType.NODE &&
140      node.nodeType_ === NodeType.INHERIT &&
141      node.parent_.nodeType_ === NodeType.INHERIT
142    ) {
143      ret = NodeTools.lookupInherit(node);
144    }
145  }
146  return ret;
147};
148
149NodeTools.recursionNode = function (node, callback) {
150  if (node.type_ === DataType.NODE) {
151    callback(node);
152    for (let n in node.value_) {
153      NodeTools.recursionNode(node.value_[n], callback);
154    }
155  }
156};
157NodeTools.recursionAll = function (node, callback, isForward) {
158  let ret = false;
159  if (isForward) {
160    ret = callback(node);
161  }
162  if (node.type_ === DataType.NODE) {
163    for (let i = 0; i < node.value_.length; i++) {
164      if (NodeTools.recursionAll(node.value_[i], callback, isForward)) {
165        i--;
166      }
167    }
168  }
169  if (!isForward) {
170    ret = callback(node);
171  }
172  return ret;
173};
174NodeTools.redefineCheck = function (node) {
175  let ret = true;
176  NodeTools.recursionNode(node, (pn) => {
177    let nameMap = [];
178    for (let i in pn.value_) {
179      if (nameMap.indexOf(pn.value_[i].name_) >= 0) {
180        pn.value_[i].errMsg_ = '重名:' + pn.value_[i].lineno_;
181        ret = false;
182      } else {
183        nameMap.push(pn.value_[i].name_);
184        pn.value_[i].errMsg_ = null;
185      }
186    }
187  });
188  return ret;
189};
190function separate(node) {
191  let pn = node.parent_;
192  if (pn === null) {
193    return;
194  }
195  for (let i in pn.value_) {
196    if (pn.value_[i] === node) {
197      pn.value_.splice(i, 1);
198    }
199  }
200}
201NodeTools.findChildByName = function (node, name) {
202  for (let i in node.value_) {
203    if (node.value_[i].name_ === name) {
204      return node.value_[i];
205    }
206  }
207  return null;
208};
209
210NodeTools.copyNode = function (node, parent) {
211  let ret = {
212    type_: node.type_,
213    name_: node.name_,
214    lineno_: node.lineno_,
215    parent_: parent,
216  };
217  if (node.raw_ !== undefined) {
218    ret.raw_ = node.raw_;
219  }
220  switch (node.type_) {
221    case DataType.INT8:
222    case DataType.INT16:
223    case DataType.INT32:
224    case DataType.INT64:
225      ret.value_ = node.value_;
226      ret.jinzhi_ = node.jinzhi_;
227      break;
228    case DataType.STRING:
229      ret.value_ = node.value_;
230      break;
231    case DataType.NODE:
232      ret.nodeType_ = node.nodeType_;
233      if ([NodeType.INHERIT, NodeType.COPY, NodeType.REFERENCE].indexOf(node.nodeType_) > -1) {
234        ret.ref_ = node.ref_;
235      } else if (!([NodeType.DATA, NodeType.TEMPLETE, NodeType.DELETE].indexOf(node.nodeType_) > -1)) {
236        NapiLog.logError('unknow node type:' + ret.lineno_);
237      }
238      ret.value_ = [];
239      for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)); }
240      break;
241    case DataType.ATTR:
242      ret.value_ = NodeTools.copyNode(node.value_, ret);
243      break;
244    case DataType.ARRAY:
245      ret.value_ = [];
246      for (let i in node.value_) { ret.value_.push(NodeTools.copyNode(node.value_[i], ret)); }
247      break;
248    case DataType.REFERENCE:
249      ret.value_ = node.value_;
250      break;
251    case DataType.DELETE:
252      ret.value_ = null;
253      break;
254    case DataType.BOOL:
255      ret.value_ = node.value_;
256      break;
257    default:
258      NapiLog.logInfo('unknow', node.type_);
259      break;
260  }
261  return ret;
262};
263
264function makeError(node, errStr) {
265  if (node.raw_ !== undefined) {
266    node.raw_.errMsg_ = errStr;
267  }
268}
269NodeTools.nodeNestCheck = function (node) {
270  NodeTools.recursionAll(
271    node,
272    (pn) => {
273      if (pn.type_ === DataType.NODE) {
274        if (pn.nodeType_ === NodeType.COPY && pn.raw_.errMsg_ === null) {
275          pn.raw_.errMsg_ = '有Copy的嵌套' + pn.raw_.lineno_;
276        }
277      }
278      return false;
279    },
280    false
281  );
282};
283NodeTools.recursionCopyAndReferenceNodes = function (pn) {
284  let ref = NodeTools.lookup(pn);
285  if (ref === null) {
286    NapiLog.logError(
287      'reference not exist' + NodeTools.getPathByNode(pn) + ':' + pn.ref_
288    );
289    if (pn.nodeType_ === NodeType.COPY) {
290      makeError(pn, pn.name_ + ' 复制目标没找到!');
291    } else {
292      makeError(pn, pn.name_ + ' 引用目标没找到!');
293    }
294    return false;
295  } else if (ref.nodeType_ === NodeType.TEMPLETE) {
296    if (pn.nodeType_ === NodeType.COPY) {
297      makeError(pn, pn.name_ + ' 复制目标不能为模板节点!');
298    } else {
299      makeError(pn, pn.name_ + ' 引用目标不能为模板节点!');
300    }
301    return false;
302  } else if (ref.nodeType_ === NodeType.DELETE) {
303    if (pn.nodeType_ === NodeType.COPY) {
304      makeError(pn, pn.name_ + ' 复制目标不能为删除节点!');
305    } else {
306      makeError(pn, pn.name_ + ' 引用目标不能为删除节点!');
307    }
308    return false;
309  } else if (NodeTools.isElders(pn, ref)) {
310    NapiLog.logError(
311      'circular reference' + NodeTools.getPathByNode(pn) + ':' + pn.ref_
312    );
313    if (pn.nodeType_ === NodeType.COPY) {
314      makeError(pn, pn.name_ + ' 循环复制!');
315    } else {
316      makeError(pn, pn.name_ + ' 循环引用!');
317    }
318    return false;
319  } else if (pn.nodeType_ === NodeType.COPY) {
320    if (ref.nodeType_ === NodeType.COPY) {
321      pn.raw_.errMsg_ = '有Copy的嵌套:' + pn.raw_.lineno_;
322    }
323    pn.nodeType_ = NodeType.DATA;
324    let tref = NodeTools.copyNode(ref, pn.parent_);
325    tref.name_ = pn.name_;
326    NodeTools.merge(tref, pn);
327    pn.value_ = tref.value_;
328    return false;
329  } else if (pn.nodeType_ === NodeType.REFERENCE) {
330    pn.nodeType_ = ref.nodeType_;
331    pn.name_ = ref.name_;
332    pn.ref_ = ref.ref_;
333    NodeTools.merge(ref, pn);
334    separate(pn);
335    return true;
336  }
337  return false;
338};
339
340NodeTools.checkInheritNode = function (pn) {
341  let ref = NodeTools.lookup(pn);
342  if (ref === null) {
343    makeError(pn, pn.name_ + ' 继承目标找不到!');
344  } else if (ref.type_ !== DataType.NODE) {
345    makeError(pn, pn.name_ + ' 不能继承属性!');
346  } else if (ref.nodeType_ === NodeType.REFERENCE) {
347    makeError(pn, pn.name_ + ' 不能继承引用类节点!');
348  } else if (ref.nodeType_ === NodeType.DELETE) {
349    makeError(pn, pn.name_ + ' 不能继承删除类节点!');
350  } else if (ref.nodeType_ === NodeType.DATA) {
351    makeError(pn, pn.name_ + ' 不能继承数据类节点!');
352  } else if (ref.nodeType_ === NodeType.INHERIT) {
353    makeError(pn, pn.name_ + ' 不能继承继承类节点!');
354  } else if (ref.nodeType_ === NodeType.COPY) {
355    makeError(pn, pn.name_ + ' 不能继承复制类节点!');
356  }
357};
358
359NodeTools.nodeExpand = function (node) {
360  NodeTools.recursionAll(node, (pn) => {
361    if (pn.type_ === DataType.NODE) {
362      if (pn.nodeType_ === NodeType.DELETE) {
363        separate(pn);
364        return true;
365      }
366      if (pn.nodeType_ === NodeType.COPY || pn.nodeType_ === NodeType.REFERENCE) {
367        return NodeTools.recursionCopyAndReferenceNodes(pn);
368      }
369      if (pn.nodeType_ === NodeType.INHERIT) {
370        NodeTools.checkInheritNode(pn);
371      }
372    } else if (pn.type_ === DataType.ATTR) {
373      if (pn.value_.type_ === DataType.DELETE) {
374        separate(pn);
375        return true;
376      }
377      if (pn.value_.type_ === DataType.REFERENCE) {
378        let ref = NodeTools.lookup(pn);
379        if (ref === null || ref.type_ !== DataType.NODE || ref.nodeType_ === NodeType.REFERENCE ||
380          ref.nodeType_ === NodeType.TEMPLETE || ref.nodeType_ === NodeType.DELETE
381        ) {
382          NapiLog.logError('reference invalid node' + NodeTools.getPathByNode(pn) + ':' + pn.value_.value_);
383          if (ref === null) {
384            makeError(pn, pn.name_ + ' 找不到引用目标!');
385          } else if (ref.type_ !== DataType.NODE) {
386            makeError(pn, pn.name_ + ' 不能引用属性!');
387          } else if (ref.nodeType_ === NodeType.REFERENCE) {
388            makeError(pn, pn.name_ + ' 不能引用引用类节点!');
389          } else if (ref.nodeType_ === NodeType.TEMPLETE) {
390            makeError(pn, pn.name_ + ' 不能引用模板类节点!');
391          } else if (ref.nodeType_ === NodeType.DELETE) {
392            makeError(pn, pn.name_ + ' 不能引用删除类节点!');
393          }
394        } else {
395          pn.refNode_ = ref;
396        }
397      }
398      }
399    return false;
400  }, false);
401};
402
403NodeTools.inheritExpand = function (node) {
404  NodeTools.recursionAll(
405    node,
406    (pn) => {
407      let tt = re.match('^[a-zA-Z_]{1}[a-zA-Z_0-9]*$', pn.name_);
408      if (tt === null) {
409        makeError(pn, pn.name_ + ' 名字不合规范!');
410      }
411      if (pn.type_ !== DataType.NODE) {
412        return false;
413      }
414      if (pn.nodeType_ !== NodeType.INHERIT) {
415        return false;
416      }
417      let inherit = NodeTools.lookup(pn);
418      if (inherit === null) {
419        NapiLog.logError(
420          'inherit invalid node: ' + NodeTools.getPathByNode(pn) + ':' + pn.ref_
421        );
422        makeError(pn, '继承目标找不到!');
423        return false;
424      }
425      pn.nodeType_ = NodeType.DATA;
426      let tinherit = NodeTools.copyNode(inherit, pn.parent_);
427      NodeTools.merge(tinherit, pn);
428      pn.value_ = tinherit.value_;
429      return false;
430    },
431    true
432  );
433};
434NodeTools.merge = function (node1, node2) {
435  if (node2 === null) {
436    return true;
437  }
438  if (node2.raw_ === undefined) {
439    node1.raw_ = node2;
440  } else {
441    node1.raw_ = node2.raw_;
442  }
443  if (node1.type_ === DataType.NODE) {
444    if (node1.name_ !== node2.name_) {
445      return false;
446    }
447    node1.nodeType_ = node2.nodeType_;
448    if (node2.nodeType_ === NodeType.INHERIT || node2.nodeType_ === NodeType.REFERENCE || node2.nodeType_ === NodeType.COPY) {
449      node1.ref_ = node2.ref_;
450    }
451    if (node1.value_ === undefined) {
452      node1.value_ = [];
453    }
454
455    for (let i in node2.value_) {
456      let child2 = node2.value_[i];
457      let child1 = NodeTools.findChildByName(node1, child2.name_);
458      if (child1 === null) {
459        child1 = {
460          type_: child2.type_,
461          name_: child2.name_,
462          lineno_: child2.lineno_,
463          parent_: node1,
464        };
465        node1.value_.push(child1);
466      } else if (child1.type_ !== child2.type_) {
467        child2.raw_.errMsg_ =
468          '所修改的子节的类型和父节点类型不同:' + child2.raw_.lineno_;
469        return false;
470      }
471      NodeTools.merge(child1, child2);
472    }
473  } else if (node1.type_ === DataType.ATTR) {
474    node1.value_ = NodeTools.copyNode(node2.value_, node1);
475  }
476  return true;
477};
478NodeTools.jinZhi10ToX = function (num, jinzhi) {
479  let ret;
480  switch (jinzhi) {
481    case MAX_BINARY:
482      ret = '0b';
483      break;
484    case MAX_OCTAL:
485      ret = '0';
486      break;
487    case MAX_DECIMAL:
488      ret = '';
489      break;
490    case MAX_HEXADECIMAL:
491      ret = '0x';
492      break;
493    default:
494      NapiLog.logError(jinzhi + '进制转换失败');
495      break;
496  }
497  return ret + num.toString(jinzhi);
498};
499NodeTools.jinZhiXTo10 = function (s) {
500  if (s === null || s.length === 0) {
501    return [0, MAX_DECIMAL];
502  }
503
504  s = s.trim();
505  if (!isFinite(s)) {
506    return [undefined, MAX_DECIMAL];
507  }
508
509  try {
510    if (s[0] === '0') {
511      if (s.length === 1) {
512        return [BigInt(s), MAX_DECIMAL];
513      } else if (s[1] === 'b' || s[1] === 'B') {
514        return [BigInt(s), MAX_BINARY];
515      } else if (s[1] === 'x' || s[1] === 'X') {
516        return [BigInt(s), MAX_HEXADECIMAL];
517      } else {
518        return [BigInt('0o' + s.substring(1)), MAX_OCTAL];
519      }
520    } else {
521      return [BigInt(s), MAX_DECIMAL];
522    }
523  } catch (ex) {
524    NapiLog.logError(ex.message);
525    return [undefined, MAX_DECIMAL];
526  }
527};
528
529NodeTools.createNewNode = function (type, name, value, nodetype) {
530  let ret = new Object();
531  ret.type_ = type;
532  ret.name_ = name;
533  ret.value_ = value;
534  ret.isOpen_ = true;
535  if (type < DataType.STRING) {
536    ret.jinzhi_ = MAX_DECIMAL;
537  }
538  if (type === DataType.NODE) {
539    ret.nodeType_ = nodetype;
540  }
541  return ret;
542};
543NodeTools.arrayToString = function (node, maxw) {
544  let ret = '';
545  let type = DataType.INT8;
546  for (let d in node.value_) {
547    if (type < node.value_[d].type_) {
548      type = node.value_[d].type_;
549    }
550  }
551  let line = '';
552  for (let d in node.value_) {
553    if (d > 0) {
554      line += ',';
555      if (maxw !== undefined) {
556        if (line.length >= maxw) {
557          ret += line + '\n';
558          line = '';
559        }
560      }
561    }
562    if (type === DataType.STRING) {
563      line += '"' + node.value_[d].value_ + '"';
564    } else {
565      line += NodeTools.jinZhi10ToX(node.value_[d].value_, node.value_[d].jinzhi_);
566    }
567  }
568  ret += line;
569  return ret;
570};
571
572NodeTools.stringToArray = function (s) {
573  let type = DataType.INT8;
574  let ret = [];
575  s = s.replace(/\n/g, '');
576  if (s.length <= 0) {
577    return ret;
578  }
579  if (s.indexOf('"') >= 0) {
580    type = DataType.STRING;
581    let p = 0;
582    let stat = 0;
583    let v;
584    while (p < s.length && stat < STAT_SIZE) {
585      switch (stat) {
586        case 0:
587          if (s[p] === '"') {
588            stat = 1;
589            v = '';
590          } else if (s[p] !== ' ') {
591            stat = STAT_SIZE;
592          }
593          break;
594        case 1:
595          if (s[p] === '"') {
596            stat = 2;
597            ret.push(NodeTools.createNewNode(type, '', v));
598          } else {
599            v += s[p];
600          }
601          break;
602        case 2:
603          if (s[p] === ',') {
604            stat = 0;
605          }
606          else if (s[p] !== ' ') {
607            stat = STAT_SIZE;
608          }
609          break;
610      }
611      p += 1;
612    }
613  } else {
614    let arr = s.split(',');
615    stringToArrayWithQuote(ret, type, arr);
616  }
617  return ret;
618};
619
620function stringToArrayWithQuote(ret, type, arr) {
621  for (let i in arr) {
622    let num = NodeTools.jinZhiXTo10(arr[i]);
623    if (num[0] === undefined) {
624      num[0] = 0;
625    }
626    let attr = NodeTools.createNewNode(type, '', num[0]);
627    attr.jinzhi_ = num[1];
628    ret.push(attr);
629    if (num[0] <= 0xff) {
630      if (type < DataType.INT8) {
631        type = DataType.INT8;
632      }
633    } else if (num[0] <= 0xffff) {
634      if (type < DataType.INT16) {
635        type = DataType.INT16;
636      }
637    } else if (num[0] <= 0xffffffff) {
638      if (type < DataType.INT32) {
639        type = DataType.INT32;
640      }
641    } else {
642      type = DataType.INT64;
643    }
644  }
645  if (type !== DataType.INT8) {
646    for (let i in ret) {
647      ret[i].type_ = type;
648    }
649  }
650}
651
652module.exports = {
653  NodeTools,
654  DataType,
655  NodeType,
656};
657