add rudimentary variable support; note: the code sucks
This commit is contained in:
parent
2e27b99dbf
commit
0240dcc069
2 changed files with 98 additions and 44 deletions
|
@ -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(" "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue