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