From 0240dcc0698892d639e74a838f9b791c97351681 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Tue, 31 May 2022 17:33:29 +0300 Subject: [PATCH] add rudimentary variable support; note: the code sucks --- src/commands/commands.js | 9 +++ src/commands/interperter.js | 133 ++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 44 deletions(-) diff --git a/src/commands/commands.js b/src/commands/commands.js index 31bfe1c..77c5a9b 100644 --- a/src/commands/commands.js +++ b/src/commands/commands.js @@ -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(" ")); } } diff --git a/src/commands/interperter.js b/src/commands/interperter.js index 83c0476..a728913 100644 --- a/src/commands/interperter.js +++ b/src/commands/interperter.js @@ -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);