Groups work now.

This commit is contained in:
ElementG9 2019-03-14 19:05:56 -06:00
parent 9556818d48
commit 7f889a79a0
5 changed files with 325 additions and 254 deletions

View File

@ -11,44 +11,39 @@
}, },
{ {
"type": "Group", "type": "Group",
"value": "{", "value": "(",
"tokens": [
{
"type": "Left Delimiter",
"value": "{",
"layer": 0
}
]
},
{
"type": "Group",
"value": "a",
"tokens": [ "tokens": [
{ {
"type": "Variable", "type": "Variable",
"value": "a", "value": "a",
"layer": 2 "layer": 1
},
{
"type": "Operator",
"value": "++",
"layer": 2
} }
] ]
}, },
{ {
"type": "Group", "type": "Group",
"value": "asdf", "value": "{",
"tokens": [ "tokens": [
{ {
"type": "Variable", "type": "Function Call",
"value": "asdf", "value": "return",
"layer": 0 "layer": 1
}, },
{ {
"type": "Operator", "type": "Group",
"value": "=", "value": "(",
"layer": 0 "tokens": [
{
"type": "Variable",
"value": "a",
"layer": 2
},
{
"type": "Operator",
"value": "++",
"layer": 2
}
]
} }
] ]
} }

View File

@ -1,20 +1,21 @@
// This is the most basic type of token. // This is the most basic type of token.
var token = function (type, value) { var token = function (type, value) {
this.type = type; this.type = type;
this.value = value; this.value = value;
}; };
// This is a group of tokens. // This is a group of tokens.
var group = function (type, tokens) { var group = function (type, tokens, index) {
this.type = "Group"; this.type = "Group";
this.value = type; this.value = type;
this.tokens; this.index = index;
if(typeof tokens != "undefined") { this.tokens;
this.tokens = tokens; if (typeof tokens != "undefined") {
} else { this.tokens = tokens;
this.tokens = []; } else {
} this.tokens = [];
}
} }
module.exports = { module.exports = {
token: token, token: token,
group: group group: group
} }

171
parser.js
View File

@ -5,55 +5,130 @@ const group = require("./classes.js").group;
// parse() takes an array of tokens in, and outputs an // parse() takes an array of tokens in, and outputs an
// Abstract Syntax Tree (a structured array of tokens). // Abstract Syntax Tree (a structured array of tokens).
module.exports = tokens => { module.exports = tokens => {
// Variables for later. // Variables for later.
var layer = 0; var layer = 0;
var delimiterCount = 0; var delimiterCount = 0;
var deepestLayer = 0; var deepestLayer = 0;
// Give each token a layer number based on delimiters. // Give each token a layer number based on delimiters.
for (var i = 0; i < tokens.length; i++) { for (var i = 0; i < tokens.length; i++) {
if (tokens[i].type == "Left Delimiter") { if (tokens[i].type == "Left Delimiter") {
layer++; layer++;
if(layer > deepestLayer) { if (layer > deepestLayer) {
deepestLayer = layer; deepestLayer = layer;
} }
delimiterCount++; delimiterCount++;
}
tokens[i].layer = layer;
if (tokens[i].type == "Right Delimiter") {
layer--;
}
} }
// Lower the layer of delimiters. tokens[i].layer = layer;
for (var i = 0; i < tokens.length; i++) { if (tokens[i].type == "Right Delimiter") {
if ((tokens[i].type == "Left Delimiter") || (tokens[i].type == "Right Delimiter")) { layer--;
tokens[i].layer--; }
} }
} // Lower the layer of delimiters.
if (layer > 0) { // Unclosed delimiter. for (var i = 0; i < tokens.length; i++) {
} else if (layer < 0) { // Overclosed delimiter. if ((tokens[i].type == "Left Delimiter") || (tokens[i].type == "Right Delimiter")) {
} tokens[i].layer--;
// Reset layer for structuring. }
layer = 0; }
/* - - - DO NOT TOUCH THIS - - - */ if (layer > 0) { // Unclosed delimiter.
for(var i=deepestLayer;i>=0;i--) { } else if (layer < 0) { // Overclosed delimiter.
var temp = []; }
var firstIndex; // Give each token an index.
for(var j=0;j<tokens.length;j++) { for (let i = 0; i < tokens.length; i++) {
if(tokens[j].layer == i) { tokens[i].index = i;
if(temp.length <= 0) { }
firstIndex = j; // Structure the layers.
} // Count the rising edges of the layers to determine how many groups should exist.
temp.push(tokens[j]); let structure = function () {
} else { let layer = 0;
if(temp.length > 0) { let risingFalling = []; // Create an array to store indices of rising/falling edges.
var g = new group(tokens[firstIndex].value,temp); for (let i = 0; i < tokens.length; i++) {
tokens.splice(firstIndex-1,temp.length+2,g); // Add a rising and a falling tag to each token.
temp = []; tokens[i].rising = false;
} tokens[i].falling = false;
} if (tokens[i].layer > layer) { // If the token moves up a layer.
// Create a new rising index in risingFalling.
risingFalling.push({
type: 'rising',
index: i
});
tokens[i].rising = true; // Note that the token is a rising edge.
layer++;
} else if (tokens[i].layer < layer) {
// Create a new falling index in risingFalling.
risingFalling.push({
type: 'falling',
index: i
});
tokens[i].falling = true; // Note that the token is a falling edge.
layer--;
}
}
// Loop through the list of rising/falling edges.
for (let i = 0; i < risingFalling.length; i++) {
if (i != risingFalling.length - 1) { // If not the last edge.
let item = risingFalling[i];
let nextItem = risingFalling[i + 1];
// If a falling edge follows a rising edge, classifiy it as a group.
if ((item.type == 'rising') && (nextItem.type == 'falling')) {
// Get the group together as one item.
let selectedItems = tokens.slice(item.index, nextItem.index);
tokens.splice(item.index, selectedItems.length, new group(tokens[item.index - 1].value, selectedItems, item.index));
} }
}
} }
/* - - - OK YOU CAN TOUCH AGAIN - - - */ risingFalling = []; // Reset the list of edges.
// Return the structured tokens. // Count the edges again.
return tokens; for (let i = 0; i < tokens.length; i++) {
if (tokens[i].layer > layer) {
risingFalling.push({
type: 'rising',
index: i
});
layer++;
} else if (tokens[i].layer < layer) {
risingFalling.push({
type: 'falling',
index: i
});
layer--;
}
}
// If there are still edges, run again.
if (risingFalling.length) {
structure();
}
};
// Start the recursion.
structure();
let trimDelimiters = function (thing) {
// Loop through the tokens of thing.
for (let i = 0; i < thing.length; i++) {
// Delete unnecessary keys.
if (typeof thing[i].rising != 'undefined') {
delete thing[i].rising;
}
if (typeof thing[i].falling != 'undefined') {
delete thing[i].falling;
}
if (typeof thing[i].index != 'undefined') {
delete thing[i].index;
}
if (typeof thing[i].index != 'undefined') {
delete thing[i].index;
}
// Remove delimiters.
if ((thing[i].type == 'Left Delimiter') || (thing[i].type == 'Right Delimiter')) {
thing.splice(i, 1);
i--;
}
// If a token is a group, look at the group's tokens.
if (thing[i].type == 'Group') {
trimDelimiters(thing[i].tokens);
}
}
};
// Start the recursion.
trimDelimiters(tokens);
// Return the structured tokens.
return tokens;
}; };

View File

@ -3,168 +3,168 @@ const token = require("./classes.js").token;
// Create the tokenizer function. // Create the tokenizer function.
// tokenize() takes Pivot code in, and outputs an array of tokens. // tokenize() takes Pivot code in, and outputs an array of tokens.
module.exports = exp => { module.exports = exp => {
// Check functions for different token types. // Check functions for different token types.
var isDigit = char => { var isDigit = char => {
return /\d/.test(char); return /\d/.test(char);
}; };
var isLetter = char => { var isLetter = char => {
return /[a-z]/i.test(char); return /[a-z]/i.test(char);
}; };
var isOperator = char => { var isOperator = char => {
return /\+|-|\*|\/|\^|=/.test(char); return /\+|-|\*|\/|\^|=/.test(char);
}; };
var isLeftDelimiter = char => { var isLeftDelimiter = char => {
return (/\(|\[|\{|"|'|`/.test(char)); return (/\(|\[|\{|"|'|`/.test(char));
}; };
var isRightDelimiter = char => { var isRightDelimiter = char => {
return (/\)|\]|\}/.test(char)); return (/\)|\]|\}/.test(char));
}; };
var isComma = char => { var isComma = char => {
return (char === ","); return (char === ",");
}; };
var isPeriod = char => { var isPeriod = char => {
return (char === "."); return (char === ".");
}; };
var result = []; // The final array of tokens. var result = []; // The final array of tokens.
var nb = []; // Number buffer. Allows for multiple digits to be one number. var nb = []; // Number buffer. Allows for multiple digits to be one number.
var lb = []; // Letter buffer. Allows for multiple letters to be one variable / function. var lb = []; // Letter buffer. Allows for multiple letters to be one variable / function.
var ob = []; // Operator buffer. Allows for multi-character operators. E.g. ++ or ==. var ob = []; // Operator buffer. Allows for multi-character operators. E.g. ++ or ==.
var sb = []; // String buffer. Allows for multi-character strings. var sb = []; // String buffer. Allows for multi-character strings.
var inString = false; // Keep track of whether in string or not. var inString = false; // Keep track of whether in string or not.
var stringType; // Keep track of what type of string. E.g. "" or ''. var stringType; // Keep track of what type of string. E.g. "" or ''.
exp = exp.split(""); // Split the expression into an array of characters. exp = exp.split(""); // Split the expression into an array of characters.
/* - - - DO NOT TOUCH THIS - - - */ /* - - - DO NOT TOUCH THIS - - - */
for (var i = 0; i < exp.length; i++) { // Loop through all of the characters. for (var i = 0; i < exp.length; i++) { // Loop through all of the characters.
var char = exp[i]; // Create a quick reference to the current char. var char = exp[i]; // Create a quick reference to the current char.
if (i >= 1) { if (i >= 1) {
if (exp[i - 1] == "\\") { if (exp[i - 1] == "\\") {
exp.splice(i - 1, 2, `\\${char}`); exp.splice(i - 1, 2, `\\${char}`);
i--; i--;
continue; continue;
} }
if (exp[i - 1] == "$" && char == "{") { if (exp[i - 1] == "$" && char == "{") {
exp.splice(i - 1, 2, `\${`); exp.splice(i - 1, 2, `\${`);
i--; i--;
continue; continue;
} }
} }
} }
/* - - - OK YOU CAN TOUCH AGAIN - - - */ /* - - - OK YOU CAN TOUCH AGAIN - - - */
// Nevermind, just don't mess with any of this file. // Nevermind, just don't mess with any of this file.
for (var i = 0; i < exp.length; i++) { for (var i = 0; i < exp.length; i++) {
var char = exp[i]; var char = exp[i];
if (inString) { if (inString) {
if (char == `'` || char == `"` || char == "`") { if (char == `'` || char == `"` || char == "`") {
var exitString = () => { var exitString = () => {
inString = false; inString = false;
if (sb.length == 0) { if (sb.length == 0) {
result.push(new token("String", null)); result.push(new token("String", null));
} else { } else {
var string = sb.join(""); var string = sb.join("");
result.push(new token("String", string)); result.push(new token("String", string));
} }
sb = []; sb = [];
}; };
if (char == `'` && stringType == "single") { if (char == `'` && stringType == "single") {
exitString(); exitString();
} else if (char == `"` && stringType == "double") { } else if (char == `"` && stringType == "double") {
exitString(); exitString();
} else if (char == "`" && stringType == "backtick") { } else if (char == "`" && stringType == "backtick") {
exitString(); exitString();
} else { } else {
if (char == `'`) { if (char == `'`) {
sb.push(`\'`); sb.push(`\'`);
} }
if (char == `"`) { if (char == `"`) {
sb.push(`\"`); sb.push(`\"`);
} }
if (char == "`") { if (char == "`") {
sb.push("\`"); sb.push("\`");
} }
} }
} else { } else {
sb.push(char); sb.push(char);
} }
} else { } else {
if (isDigit(char)) { if (isDigit(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
nb.push(char); nb.push(char);
} else if (isLetter(char)) { } else if (isLetter(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
lb.push(char); lb.push(char);
} else if (isOperator(char)) { } else if (isOperator(char)) {
result.push(new token("Number", nb.join(""))); result.push(new token("Number", nb.join("")));
nb = []; nb = [];
result.push(new token("Variable", lb.join(""))); result.push(new token("Variable", lb.join("")));
lb = []; lb = [];
ob.push(char); ob.push(char);
} else if (isLeftDelimiter(char)) { } else if (isLeftDelimiter(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
result.push(new token("Function Call", lb.join(""))); result.push(new token("Function Call", lb.join("")));
lb = []; lb = [];
if (char == `'` || char == `"` || char == "`") { if (char == `'` || char == `"` || char == "`") {
inString = true; inString = true;
if (char == `'`) { if (char == `'`) {
stringType = "single"; stringType = "single";
} else if (char == `"`) { } else if (char == `"`) {
stringType = "double"; stringType = "double";
} else if (char == "`") { } else if (char == "`") {
stringType = "backtick"; stringType = "backtick";
} }
} else { } else {
result.push(new token("Left Delimiter", char)); result.push(new token("Left Delimiter", char));
} }
} else if (isRightDelimiter(char)) { } else if (isRightDelimiter(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
result.push(new token("Number", nb.join(""))); result.push(new token("Number", nb.join("")));
nb = []; nb = [];
result.push(new token("Variable", lb.join(""))); result.push(new token("Variable", lb.join("")));
lb = []; lb = [];
result.push(new token("Right Delimiter", char)); result.push(new token("Right Delimiter", char));
} else if (isComma(char)) { } else if (isComma(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
result.push(new token("Number", nb.join(""))); result.push(new token("Number", nb.join("")));
nb = []; nb = [];
result.push(new token("Variable", lb.join(""))); result.push(new token("Variable", lb.join("")));
lb = []; lb = [];
result.push(new token("Comma", char)); result.push(new token("Comma", char));
} else if (isPeriod(char)) { } else if (isPeriod(char)) {
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
nb.push(char); nb.push(char);
} }
} }
} }
result.push(new token("Operator", ob.join(""))); result.push(new token("Operator", ob.join("")));
ob = []; ob = [];
result.push(new token("Number", nb.join(""))); result.push(new token("Number", nb.join("")));
nb = []; nb = [];
lb.forEach(item => { lb.forEach(item => {
result.push(new token("Variable", item)); result.push(new token("Variable", item));
}); });
lb = []; lb = [];
for (var i = 0; i < 3; i++) { for (var i = 0; i < 3; i++) {
result.forEach((item, index) => { result.forEach((item, index) => {
if (item.value == "") { if (item.value == "") {
result.splice(index, 1); result.splice(index, 1);
} }
}); });
} }
result.forEach((item, index) => { result.forEach((item, index) => {
if (item.value == "-" && index != 0) { if (item.value == "-" && index != 0) {
if (result[index - 1].type != "Variable" && result[index - 1].type != "Number") { if (result[index - 1].type != "Variable" && result[index - 1].type != "Number") {
if (result[index + 1].type == "Number") { if (result[index + 1].type == "Number") {
result[index + 1].value = "-" + result[index + 1].value; result[index + 1].value = "-" + result[index + 1].value;
result.splice(index, 1); result.splice(index, 1);
} }
} }
} }
}); });
return result; return result;
}; };