add rudimentary variable support; note: the code sucks

This commit is contained in:
hippoz 2022-05-31 17:33:29 +03:00
parent 2e27b99dbf
commit 0240dcc069
Signed by: hippoz
GPG key ID: 7C52899193467641
2 changed files with 98 additions and 44 deletions

View file

@ -64,5 +64,14 @@ export default {
val ??= "null"; val ??= "null";
return typeof val === "string" ? val : JSON.stringify(val); return typeof val === "string" ? val : JSON.stringify(val);
},
set: function({ createStream, argv, argc }) {
if (argc < 2) {
return "set: expected at least 2 arguments";
}
const name = argv[0];
argv.splice(0, 1);
createStream(name, argv.join(" "));
} }
} }

View file

@ -6,7 +6,9 @@ const MAX_STREAMS = 6;
const TokenType = { const TokenType = {
Command: "Command", Command: "Command",
Argument: "Argument", Argument: "Argument",
Pipe: "Pipe" Pipe: "Pipe",
VariableArgument: "VariableArgument",
EndOfLine: "EndOfLine"
}; };
const InstructionType = { const InstructionType = {
@ -28,32 +30,43 @@ function tokenize(message) {
const tokens = []; const tokens = [];
let val = ""; let val = "";
let expecting = Expected.Command; let expecting = Expected.Command;
// length +1 so we get char === undefined at the end of the string const lines = message.split("\n");
for (let i = 0; i < message.length + 1; i++) {
const char = message[i];
if (char === " " || (char === undefined && val !== "")) { // if the character is a string OR if we are at the end of the string and still have a value for (let line = 0; line < lines.length; line++) {
if (expecting === Expected.AfterCommand) { expecting = Expected.Command;
if (val === "|") {
tokens.push(token(TokenType.Pipe, "|")); // length +1 so we get char === undefined at the end of the string
expecting = Expected.Command; for (let i = 0; i < lines[line].length + 1; i++) {
} else { const char = lines[line][i];
tokens.push(token(TokenType.Argument, val));
if (char === " " || (char === undefined && val !== "")) { // if the character is a string OR if we are at the end of the string and still have a value
if (expecting === Expected.AfterCommand) {
if (val === "|") {
tokens.push(token(TokenType.Pipe, "|"));
expecting = Expected.Command;
} else if (val.startsWith("$") && val.length > 1) {
tokens.push(token(TokenType.VariableArgument, val.substring(1, val.length)));
expecting = Expected.AfterCommand;
} else {
tokens.push(token(TokenType.Argument, val));
expecting = Expected.AfterCommand;
}
} else if (expecting === Expected.Command) {
tokens.push(token(TokenType.Command, val));
expecting = Expected.AfterCommand; expecting = Expected.AfterCommand;
} else {
return {
error: "Unexpected 'expecting' value, this is probably a bug in the parser",
tokens: null,
};
} }
} else if (expecting === Expected.Command) { val = "";
tokens.push(token(TokenType.Command, val));
expecting = Expected.AfterCommand;
} else { } else {
return { val += char;
error: "Unexpected 'expecting' value, this is probably a bug in the parser",
tokens: null,
};
} }
val = "";
} else {
val += char;
} }
tokens.push(token(TokenType.EndOfLine, ""));
} }
if (expecting !== Expected.AfterCommand) { if (expecting !== Expected.AfterCommand) {
return { return {
@ -67,21 +80,31 @@ function tokenize(message) {
}; };
} }
const CommandArgumentType = {
Variable: "Variable",
Immediate: "Immediate"
};
function tokensToInstructions(tokens) { function tokensToInstructions(tokens) {
const streamName = "_commandStream"
const instructions = [ const instructions = [
{ type: InstructionType.CreateStream, name: streamName } { type: InstructionType.CreateStream, name: "SHELL", value: "tuna" },
]; ];
let commandName = null; let commandName = null;
let commandArgs = []; let commandArgs = [];
let currentLine = 0;
let currentStream = `_commandStream$${currentLine}`;
instructions.push({ type: InstructionType.CreateStream, name: currentStream, value: "" });
const endCommand = () => { const endCommand = () => {
instructions.push({ instructions.push({
type: InstructionType.Run, type: InstructionType.Run,
name: commandName, name: commandName,
args: commandArgs, args: commandArgs,
inStream: streamName, inStream: currentStream,
outStream: streamName outStream: currentStream
}); });
commandName = null; commandName = null;
commandArgs = []; commandArgs = [];
@ -104,7 +127,7 @@ function tokensToInstructions(tokens) {
instructions: null instructions: null
} }
} }
commandArgs.push(tok.value); commandArgs.push({ value: tok.value, type: CommandArgumentType.Immediate });
} else if (tok.type === TokenType.Pipe) { } else if (tok.type === TokenType.Pipe) {
if (!commandName) { if (!commandName) {
return { return {
@ -113,25 +136,31 @@ function tokensToInstructions(tokens) {
} }
} }
endCommand(); endCommand();
} else if (tok.type === TokenType.VariableArgument) {
if (!commandName) {
return {
error: "Got TokenType.VariableArgument, however commandName is null",
instructions: null
}
}
commandArgs.push({ value: tok.value, type: CommandArgumentType.Variable });
} else if (tok.type === TokenType.EndOfLine) {
endCommand();
currentLine++;
currentStream = `_commandStream$${currentLine}`;
instructions.push({ type: InstructionType.CreateStream, name: currentStream, value: "" });
} else { } else {
return { return {
error: "Unknown tok.type", error: "Unknown tok.type",
instructions: null instructions: null
} }
} }
if ((i + 1) === tokens.length) {
if (commandName === null) {
return {
error: "End of input, yet commandName is null",
instructions: null
}
}
endCommand();
}
} }
instructions.push({ type: InstructionType.DisplayStream, name: streamName }); for (let i = 0; i < currentLine; i++) {
instructions.push({ type: InstructionType.DisplayStream, name: `_commandStream$${i}` });
}
return { return {
error: null, error: null,
@ -140,19 +169,25 @@ function tokensToInstructions(tokens) {
} }
function interpretInstructions(instructions, displayFunc) { function interpretInstructions(instructions, displayFunc) {
console.log(instructions);
if (instructions.length > MAX_INSTRUCTIONS) { if (instructions.length > MAX_INSTRUCTIONS) {
return { error: `Arbitrary limit of ${MAX_INSTRUCTIONS} instructions reached` }; return { error: `Arbitrary limit of ${MAX_INSTRUCTIONS} instructions reached` };
} }
const streams = new Map(); const streams = new Map();
const createStream = (name, value) => {
if (streams.size > MAX_STREAMS) {
return { error: `Arbitrary limit of ${MAX_STREAMS} streams reached` };
}
streams.set(name, value);
};
for (let i = 0; i < instructions.length; i++) { for (let i = 0; i < instructions.length; i++) {
const inst = instructions[i]; const inst = instructions[i];
switch (inst.type) { switch (inst.type) {
case InstructionType.CreateStream: { case InstructionType.CreateStream: {
if (streams.size > MAX_STREAMS) { createStream(inst.name, inst.value);
return { error: `Arbitrary limit of ${MAX_STREAMS} streams reached` };
}
streams.set(inst.name, "");
break; break;
} }
case InstructionType.Run: { case InstructionType.Run: {
@ -164,11 +199,21 @@ function interpretInstructions(instructions, displayFunc) {
if (inst.inStream) { if (inst.inStream) {
streamInput = streams.get(inst.inStream); streamInput = streams.get(inst.inStream);
} }
const args = [];
for (let i = 0; i < inst.args.length; i++) {
const arg = inst.args[i];
if (arg.type === CommandArgumentType.Variable) {
args.push(streams.get(arg.value) ?? "");
} else {
args.push(arg.value);
}
}
try { try {
let streamOutput = commandFunc({ let streamOutput = commandFunc({
argv: inst.args, argv: args,
argc: inst.args.length, argc: args.length,
streamInput streamInput,
createStream
}); });
if (inst.outStream) { if (inst.outStream) {
streams.set(inst.outStream, streamOutput); streams.set(inst.outStream, streamOutput);