Groups work now.
This commit is contained in:
parent
9556818d48
commit
7f889a79a0
45
ast.json
45
ast.json
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
29
classes.js
29
classes.js
@ -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
|
||||||
}
|
}
|
173
parser.js
173
parser.js
@ -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;
|
||||||
|
};
|
2
pivot.js
2
pivot.js
@ -10,4 +10,4 @@ var ast = parse(tokenize(code));
|
|||||||
|
|
||||||
// Write the AST to ast.json.
|
// Write the AST to ast.json.
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
fs.writeFileSync("ast.json", JSON.stringify(ast, null, 4));
|
fs.writeFileSync("ast.json", JSON.stringify(ast, null, 4));
|
330
tokenizer.js
330
tokenizer.js
@ -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;
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user