add callable closure vars

This commit is contained in:
LenAnderson
2024-04-02 08:48:41 -04:00
parent c2ddfdb85d
commit d826eb43d4
3 changed files with 120 additions and 63 deletions

View File

@ -1,4 +1,5 @@
import { substituteParams } from '../../script.js';
import { SlashCommandClosureExecutor } from './SlashCommandClosureExecutor.js';
import { SlashCommandClosureResult } from './SlashCommandClosureResult.js';
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
import { SlashCommandScope } from './SlashCommandScope.js';
@ -10,7 +11,7 @@ export class SlashCommandClosure {
/**@type {Map<string,string|SlashCommandClosure>}*/ arguments = {};
// @ts-ignore
/**@type {Map<string,string|SlashCommandClosure>}*/ providedArguments = {};
/**@type {SlashCommandExecutor[]}*/ executorList = [];
/**@type {(SlashCommandExecutor|SlashCommandClosureExecutor)[]}*/ executorList = [];
/**@type {String}*/ keptText;
constructor(parent) {
@ -39,6 +40,10 @@ export class SlashCommandClosure {
return closure;
}
/**
*
* @returns Promise<SlashCommandClosureResult>
*/
async execute() {
const closure = this.getCopy();
return await closure.executeDirect();
@ -98,6 +103,15 @@ export class SlashCommandClosure {
}
for (const executor of this.executorList) {
if (executor instanceof SlashCommandClosureExecutor) {
const closure = this.scope.getVariable(executor.name);
if (!closure || !(closure instanceof SlashCommandClosure)) throw new Error(`${name} is not a closure.`);
closure.scope.parent = this.scope;
closure.providedArguments = executor.providedArguments;
const result = await closure.execute();
this.scope.pipe = result.pipe;
interrupt = result.interrupt;
} else {
interrupt = executor.command.interruptsGeneration;
let args = {
_scope: this.scope,
@ -174,6 +188,9 @@ export class SlashCommandClosure {
this.scope.pipe = await executor.command.callback(args, value);
}
return Object.assign(new SlashCommandClosureResult(), { interrupt, newText: this.keptText, pipe: this.scope.pipe });
}
/**@type {SlashCommandClosureResult} */
const result = Object.assign(new SlashCommandClosureResult(), { interrupt, newText: this.keptText, pipe: this.scope.pipe });
return result;
}
}

View File

@ -0,0 +1,5 @@
export class SlashCommandClosureExecutor {
/**@type {String}*/ name = '';
// @ts-ignore
/**@type {Map<string,string|SlashCommandClosure>}*/ providedArguments = {};
}

View File

@ -1,5 +1,6 @@
import { SlashCommand } from './SlashCommand.js';
import { SlashCommandClosure } from './SlashCommandClosure.js';
import { SlashCommandClosureExecutor } from './SlashCommandClosureExecutor.js';
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
import { SlashCommandParserError } from './SlashCommandParserError.js';
// eslint-disable-next-line no-unused-vars
@ -232,6 +233,9 @@ export class SlashCommandParser {
this.discardWhitespace();
}
while (!this.testClosureEnd()) {
if (this.testClosureCall()) {
closure.executorList.push(this.parseClosureCall());
}
if (this.testCommand()) {
closure.executorList.push(this.parseCommand());
} else {
@ -260,6 +264,37 @@ export class SlashCommandParser {
return closure;
}
testClosureCall() {
return this.char == '/'
&& this.behind.slice(-1) != '\\'
&& !['/', '#'].includes(this.ahead[0])
&& /^\S+\(/.test(this.ahead)
;
}
testClosureCallEnd() {
return this.char == ')' && this.behind.slice(-1) != '\\';
}
parseClosureCall() {
this.take(); // discard /
let name = '';
while (!/\s|\(/.test(this.char)) name += this.take(); // take chars until opening (
this.take(); // discard opening (
const executor = new SlashCommandClosureExecutor();
executor.name = name;
this.discardWhitespace();
while (this.testNamedArgument()) {
const arg = this.parseNamedArgument();
executor.providedArguments[arg.key] = arg.value;
this.discardWhitespace();
}
if (this.testClosureCallEnd()) {
this.take(); // discard closing )
return executor;
} else {
throw new SlashCommandParserError(`Unexpected end of closure call at position ${this.index - 2}`, this.text, this.index);
}
}
testCommand() {
return this.char == '/' && this.behind.slice(-1) != '\\' && !['/', '#'].includes(this.ahead[0]);
}