algomin
Version:
Algomin - Viszualizing Distributed Algorithms
126 lines (104 loc) • 4.11 kB
JavaScript
export class Parser {
/**
* Parses an Algomin animation code by splitting and checking
* each line if a regex matches the given command. Then it filters out
* the paramters and pushes it as a JSON object to the return list.
* @param expression_string Expression String of Algomin Code
* @returns {*[]}
*/
parseExpression(expression_string) {
let instructions = [];
const lines = expression_string.split('\n');
const objectRegex = /^(\w+)\s*=\s*shape\(([^)]+)\)$/i;
const sendMessageRegex = /^(\w+)\.sendMessage\(([^)]+)\)$/i;
const waitRegex = /wait\(duration=(\d+)\)/;
const killRegex = /([a-zA-Z_$][a-zA-Z0-9_$]*)\.kill\(\)/;
for (const [i, line] of lines.entries()) {
if (line.trim() === "") {
continue;
}
if (objectRegex.exec(line)) {
const id = line.split(" ").join("").split("=")[0];
instructions.push({id: id, type: "SHAPE", args: this.parseArgs(line)});
} else if (sendMessageRegex.exec(line)) {
const source = line.split(".")[0];
instructions.push({source: source, type: "SEND", args: this.parseArgs(line)});
} else if (waitRegex.exec(line)) {
instructions.push({source: null, type: "WAIT", args: this.parseArgs(line)});
} else if (killRegex.exec(line)) {
const source = line.split(".")[0];
instructions.push({source: source, type: "KILL", args: this.parseArgs(line)});
} else {
throw new Error(`Unrecognized line at ${i+1}: ${line}`);
}
}
return instructions;
}
/**
* Splits all arguments it finds in a line and returns a JSON of all parameters
* @param line String
* @returns {{}}
*/
parseArgs(line) {
let first_bracket_index = -1;
let last_bracket_index = -1;
for (let i = 0; i < line.length; i++) {
if (line[i] === "(" && first_bracket_index < 0) {
first_bracket_index = i;
} else if (line[i] === ")") {
last_bracket_index = i;
}
}
let new_line = line.substring(first_bracket_index + 1, last_bracket_index + 1)
let inside_quote = false;
let last_index = 0;
let key_values = []
new_line = this.removeSpaces(new_line);
for (let i = 0; i < new_line.length; i++) {
if (new_line[i] === '"' || new_line[i] === "'") {
inside_quote = !inside_quote;
}
if ((new_line[i] === "," || new_line[i] === ")") && inside_quote === false) {
key_values.push(new_line.substring(last_index, i));
last_index = i + 1;
}
}
return this.listToDict(key_values);
}
/**
* Removes all whitespaces by also checking if it is inside quotes to not
* disrupt passed Parameter string values
* @param line String
* @returns {string}
*/
removeSpaces(line) {
let new_line = "";
let inside_quote = false;
for (let i = 0; i < line.length; i++) {
if (line[i] === '"' || line[i] === "'") {
inside_quote = !inside_quote;
}
if (!(line[i] === " " && !inside_quote)) {
new_line += line[i]
}
}
return new_line;
}
/**
* Transforms a list of arguments to a dict
* @param list List of Strings
* @returns {{}}
*/
listToDict(list) {
const dict = {};
list.forEach(element => {
let [key, value] = element.split('=');
if (!isNaN(parseInt(value))) {
dict[key] = parseInt(value);
} else if (value){
dict[key] = value.replaceAll("'", "");
}
});
return dict;
}
}