teroshdl
Version:
Backend for terosHDL IDE
382 lines (359 loc) • 13.7 kB
JavaScript
// Copyright 2020 Teros Technology
//
// Ismael Perez Rojo
// Carlos Alberto Ruiz Naranjo
// Alfredo Saez
//
// This file is part of Colibri.
//
// Colibri is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Colibri is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Colibri. If not, see <https://www.gnu.org/licenses/>.
const clone = require('clone');
const Doxygen_parser = require('./doxygen_parser');
class Ts_base_parser {
constructor(){
this.command_end_regex = /@end/gm;
}
search_multiple_in_tree(element, matching_title) {
var arr_match = [];
function recursive_searchTree(element, matching_title) {
let type = element.type;
if (type === matching_title) {
arr_match.push(element);
} else if (element !== null) {
var i;
var result = null;
for (i = 0; result === null && i < element.childCount; i++) {
result = recursive_searchTree(element.child(i), matching_title);
}
return result;
}
return null;
}
recursive_searchTree(element, matching_title);
return arr_match;
}
search_in_tree(element, matching_title) {
var match = undefined;
function recursive_searchTree(element, matching_title) {
let type = element.type;
if (type === matching_title) {
match = element;
} else if (element !== null) {
var i;
var result = null;
for (i = 0; result === null && i < element.childCount; i++) {
result = recursive_searchTree(element.child(i), matching_title);
if (result !== null) {
break;
}
}
return result;
}
return null;
}
recursive_searchTree(element, matching_title);
return match;
}
get_item_multiple_from_childs(p, type) {
if (p === undefined) {
return [];
}
let items = [];
let cursor = p.walk();
cursor.gotoFirstChild();
do {
if (cursor.nodeType === type) {
let item = cursor.currentNode();
items.push(item);
}
}
while (cursor.gotoNextSibling() === true);
return items;
}
get_item_from_childs(p, type) {
if (p === undefined) {
return undefined;
}
let item = undefined;
let cursor = p.walk();
let break_p = false;
cursor.gotoFirstChild();
do {
if (cursor.nodeType === type) {
item = cursor.currentNode();
break_p = true;
}
}
while (cursor.gotoNextSibling() === true && break_p === false);
return item;
}
get_item_from_childs_last(p, type) {
if (p === undefined) {
return undefined;
}
let item = undefined;
let cursor = p.walk();
cursor.gotoFirstChild();
do {
if (cursor.nodeType === type) {
item = cursor.currentNode();
}
}
while (cursor.gotoNextSibling() === true);
return item;
}
parse_doxy(dic, file_type) {
if (dic.info === undefined){
dic.info = {};
}
// remove any spaces between linefeed and trim the string
let desc_root = dic[file_type];
// always remove carriage return
desc_root.description = desc_root.description.replace(/\r/gm, "");
// look for single line commands
const single_line_regex = /^\s*[@\\](file|date|title|custom_section_begin|custom_section_end)\s.+$/gm;
// get all matches for single line attributes
let matches_array = Array.from(desc_root.description.matchAll(single_line_regex));
// add a new property for the newly found matches
if (matches_array.length > 0) {
dic.info = {};
// append found matches
for (let index = 0; index < matches_array.length; index++) {
dic.info[matches_array[index][1]] = matches_array[index][0].replace(/^\s*[@\\](file|date|title|custom_section_begin|custom_section_end)/, "").trim();
}
// clean up the description field
desc_root.description = desc_root.description.replace(single_line_regex, "");
}
desc_root.description = desc_root.description.replace(/@copyright/gm, "\n@copyright");
desc_root.description = desc_root.description.replace(/@author/gm, "\n@author");
desc_root.description = desc_root.description.replace(/@version/gm, "\n@version");
desc_root.description = desc_root.description.replace(/@project/gm, "\n@project");
desc_root.description = desc_root.description.replace(/@brief/gm, "\n@brief");
desc_root.description = desc_root.description.replace(/@details/gm, "\n@details");
Doxygen_parser.parse_copyright(dic, desc_root);
Doxygen_parser.parse_author(dic, desc_root);
Doxygen_parser.parse_version(dic, desc_root);
Doxygen_parser.parse_project(dic, desc_root);
Doxygen_parser.parse_brief(dic, desc_root);
Doxygen_parser.parse_details(dic, desc_root);
return dic;
}
normalize_description(description){
return description;
let desc_inst = description.replace(/\n\s*\n/g, '<br>');
desc_inst = desc_inst.replace(/\n/g, '');
return desc_inst;
}
get_comment(comment){
if (comment === undefined){
return '';
}
let txt_comment = comment.slice(2);
if (this.comment_symbol === '') {
return txt_comment;
}
else if (txt_comment[0] === this.comment_symbol) {
return txt_comment.slice(1);
}
return '';
}
get_comment_with_break(comment){
if (comment === undefined){
return '';
}
let txt_comment = comment.slice(2);
if (this.comment_symbol === '') {
return txt_comment + '\n';
}
else if (txt_comment[0] === this.comment_symbol) {
return txt_comment.slice(1) + '\n';
}
return '';
}
set_symbol(symbol){
if (symbol === undefined) {
this.comment_symbol = '';
}
else{
this.comment_symbol = symbol;
}
}
parse_mermaid(dic,file_type) {
// the command regex
const mermaid_regex = /^\s*[@\\]mermaid\s*.*[@\\]end/gms;
// a variable to hold if a mermaid is found and currently opened
let mermaid_open = false;
// easy access to the entity description
let desc_root = dic[file_type];
// hold the mermaid data
let mermaid = "";
// always remove carriage return
desc_root.description = desc_root.description.replace(/\r/gm, "");
let match = desc_root.description.match(mermaid_regex)
if (match !== undefined && match !== null && match.length > 0) {
desc_root.description = desc_root.description.replace(match[0],"");
mermaid = match[0].replace(/[@\\]mermaid/gm,"")
mermaid = mermaid.replace(/[@\\]end/gm,"")
desc_root.description = desc_root.description.replace("\n\n","")
dic[file_type]['description'] = desc_root.description
dic[file_type]['mermaid'] = mermaid;
}
return dic;
}
parse_ports_group(dic) {
const group_regex = /^\s*[@\\]portgroup\s.*$/gm;
let ports = dic.ports;
// hold the current group name
let group_name = "";
// flag to check if a group is open
let group_open = false;
// loop along all ports
for (let i = 0; i < ports.length; i++) {
let group = ports[i].description.match(group_regex);
// look for a new group name
if (group !== null && group.length > 0) {
group_open = true;
ports[i].description = ports[i].description.replace(/^\s*[@\\]portgroup\s/gm, "");
group_name = ports[i].description.match(/^\s*\w+/)[0];
ports[i].description = ports[i].description.replace(group_name, "");
}
ports[i].group = group_name;
}
dic.ports = ports;
return dic;
}
parse_virtual_bus(dic) {
const virtual_bus_regex_followed = /^\s*[@\\]virtualbus\s.*\n\n/gms;
const virtual_bus_regex_not_followed = /^\s*[@\\]virtualbus\s.*/
const virtual_bus_dir_regex = /^\s*[@\\]dir\s/gm;
const virtual_bus_keep_regex = /^\s*[@\\]keepports\s/gm
// the base struct is used to reset the virtual_bus_struct when needed
const virtual_bus_base_struct = {
"name": "",
"description": "",
"direction": "in",
"keep_ports": false,
"ports": []
}
let ports = dic.ports;
// hold the indexes that gets removed from the ports list
let ports_to_remove = [];
// holds the current virtual bus and gets filled when a new one is encountered
let virtual_bus_struct = clone(virtual_bus_base_struct);
// holds all the found virtual buses found so for
let virtual_bus_array = [];
// indicates if a virtual bus is found in a port or not
let virtual_bus_open = false;
// loop along all ports
for (let i = 0; i < ports.length; i++) {
// strip description from \r if present to deal with \n exclusively
ports[i].description = ports[i].description.replace(/\r/gm, "");
let virtual_bus = ports[i].description.match(virtual_bus_regex_followed);
if (virtual_bus === null) {
virtual_bus = ports[i].description.match(virtual_bus_regex_not_followed);
}
if (virtual_bus !== null) {
if (virtual_bus_open) {
// new virtual bus is found and another one was still open, add the old one to the array and clean it
virtual_bus_array.push(clone(virtual_bus_struct));
virtual_bus_struct = clone(virtual_bus_base_struct);
}
let virtual_bus_description = virtual_bus[0];
// clean the port description from the found virtual bus command
dic.ports[i].description = ports[i].description.replace(virtual_bus_regex_not_followed, "");
dic.ports[i].description = ports[i].description.replace(/\n\n/, "");
dic.ports[i].description = ports[i].description.replace(this.command_end_regex, "");
// strip virtual bus description from the command part
virtual_bus_description = virtual_bus_description.replace(/^\s*[@\\]virtualbus\s/, "");
// construct the name and description of virtual bus
let virtual_bus_name = virtual_bus_description.match(/^\s*\w+/);
if (virtual_bus_name !== null) {
virtual_bus_name = virtual_bus_description.match(/^\s*\w+/)[0];
}
else {
virtual_bus_name = "";
}
virtual_bus_description = virtual_bus_description.replace(virtual_bus_name, "");
let virtual_bus_dir = virtual_bus_description.match(virtual_bus_dir_regex);
// look for optional direction
if (virtual_bus_dir !== null && virtual_bus_dir.length > 0) {
virtual_bus_description = virtual_bus_description.replace(virtual_bus_dir[0], "");
virtual_bus_description = virtual_bus_description.replace(/\n\n/, "");
virtual_bus_dir = virtual_bus_description.match(/^\s*(out|in)/gm);
if (virtual_bus_dir !== null) {
virtual_bus_description = virtual_bus_description.replace(virtual_bus_dir[0], "");
virtual_bus_struct.direction = virtual_bus_dir[0].trim();
} else{
virtual_bus_struct.direction = "in";
}
}
// look for optional flag to keep in signals in table
let keep_ports = virtual_bus_description.match(virtual_bus_keep_regex);
// look for optional direction
if (keep_ports !== null && keep_ports.length > 0) {
virtual_bus_description = virtual_bus_description.replace(keep_ports[0], "");
virtual_bus_struct.keep_ports = true;
}
// update the virtual bus struct with the newly found fields
virtual_bus_struct.name = virtual_bus_name;
virtual_bus_struct.description = virtual_bus_description;
// keep the virtual bus opened to add incoming ports
virtual_bus_open = true;
}
if (virtual_bus_open) {
// copy the port to the newly created virtualbus
virtual_bus_struct.ports.push(clone(ports[i]));
// append current index to be removed
ports_to_remove.push(clone(i))
}
// remove any added \n to description
dic.ports[i].description = ports[i].description.replace(/\n/, "");
if (ports[i].description.match(this.command_end_regex) !== null) {
if (virtual_bus_open) {
virtual_bus_open = false;
for (let i = 0; i < virtual_bus_struct.ports.length; i++) {
virtual_bus_struct.ports[i].description = virtual_bus_struct.ports[i].description.replace(this.command_end_regex, "");
}
virtual_bus_array.push(clone(virtual_bus_struct));
virtual_bus_struct = clone(virtual_bus_base_struct);
}
}
}
if (virtual_bus_array.length > 0) {
// append the vbus to the json
dic.virtual_buses = virtual_bus_array;
// remove ports from the list
for (let index = 0; index < ports_to_remove.length; index++) {
const element = ports_to_remove[index];
dic.ports.splice(element - index, 1)
}
for (let index = 0; index < virtual_bus_array.length; index++) {
const element = virtual_bus_array[index];
dic.ports.push({
"name": element.name,
"type": "virtual_bus",
"line": -1,
"direction": element.direction,
"default_value": "",
"description": element.description,
"group": ""
});
}
}
return dic;
}
}
module.exports = {
Ts_base_parser: Ts_base_parser
};