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