mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-05-26 02:14:02 +00:00
Richer paramater parsing.
This commit is NOT contributed under the Apache-2.0 License. Copyright (C) 2022 Gnuxie <Gnuxie@protonmail.com> All rights reserved.
This commit is contained in:
@@ -30,7 +30,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReadItem } from "./CommandReader";
|
||||
import { ParamaterParser, ArgumentStream } from "./ParamaterParsing";
|
||||
import { ParamaterParser, ArgumentStream, IArgumentListParser } from "./ParamaterParsing";
|
||||
import { CommandResult } from "./Validation";
|
||||
|
||||
/**
|
||||
@@ -112,7 +112,7 @@ export function findCommandTable<ExecutorType extends BaseFunction>(name: string
|
||||
|
||||
export class InterfaceCommand<ExecutorType extends BaseFunction> {
|
||||
constructor(
|
||||
private readonly paramaterParser: ParamaterParser,
|
||||
private readonly argumentListParser: IArgumentListParser,
|
||||
private readonly command: ExecutorType,
|
||||
public readonly designator: string[],
|
||||
) {
|
||||
@@ -122,7 +122,7 @@ export class InterfaceCommand<ExecutorType extends BaseFunction> {
|
||||
// probably... it's just that means that invoke has to return the validation result lol.
|
||||
// Though this makes no sense if parsing is part of finding a matching command.
|
||||
public parseArguments(...args: ReadItem[]): ReturnType<ParamaterParser> {
|
||||
return this.paramaterParser(...args);
|
||||
return this.argumentListParser.parseFunction(...args);
|
||||
}
|
||||
|
||||
public invoke(context: ThisParameterType<ExecutorType>, ...args: Parameters<ExecutorType>): ReturnType<ExecutorType> {
|
||||
@@ -130,7 +130,7 @@ export class InterfaceCommand<ExecutorType extends BaseFunction> {
|
||||
}
|
||||
|
||||
public async parseThenInvoke(context: ThisParameterType<ExecutorType>, ...items: ReadItem[]): Promise<ReturnType<ExecutorType>> {
|
||||
const paramaterDescription = this.paramaterParser(...items);
|
||||
const paramaterDescription = this.argumentListParser.parseFunction(...items);
|
||||
if (paramaterDescription.isErr()) {
|
||||
// The inner type is irrelevant when it is Err, i don't know how to encode this in TS's type system but whatever.
|
||||
return paramaterDescription as ReturnType<Awaited<ExecutorType>>;
|
||||
@@ -140,7 +140,7 @@ export class InterfaceCommand<ExecutorType extends BaseFunction> {
|
||||
}
|
||||
|
||||
export function defineInterfaceCommand<ExecutorType extends BaseFunction>(description: {
|
||||
paramaters: ParamaterParser,
|
||||
paramaters: IArgumentListParser,
|
||||
table: string,
|
||||
command: ExecutorType,
|
||||
designator: string[],
|
||||
|
||||
@@ -172,30 +172,59 @@ export interface ParamaterDescription {
|
||||
|
||||
export type ParamaterParser = (...readItems: ReadItem[]) => CommandResult<ParsedArguments>;
|
||||
|
||||
export function paramaters(descriptions: ParamaterDescription[], restParser: undefined|RestParser = undefined): ParamaterParser {
|
||||
return (...readItems: ReadItem[]) => {
|
||||
const itemStream = new ArgumentStream(readItems);
|
||||
for (const paramater of descriptions) {
|
||||
if (itemStream.peekItem() === undefined) {
|
||||
// FIXME asap: we need a proper paramater description?
|
||||
return CommandError.Result('expected an argument', `An argument for the paramater ${paramater.name} was expected but was not provided.`);
|
||||
// So this should really just be something used by defineInterfaceCommand which turns paramaters into a validator that can be used.
|
||||
// It can't be, because then otherwise how does the semantics for union work?
|
||||
// We should have a new type of CommandResult that accepts a ParamterDescription, and can render what's wrong (e.g. missing paramater).
|
||||
// Showing where in the item stream it is missing and the command syntax and everything lovely like that.
|
||||
// How does that work with Union?
|
||||
export function paramaters(descriptions: ParamaterDescription[], restParser: undefined|RestParser = undefined): IArgumentListParser {
|
||||
return new ArgumentListParser(descriptions, restParser);
|
||||
}
|
||||
|
||||
export interface IArgumentListParser {
|
||||
readonly parseFunction: ParamaterParser,
|
||||
readonly descriptions: ParamaterDescription[],
|
||||
readonly restParser?: RestParser,
|
||||
}
|
||||
|
||||
/**
|
||||
* Zis is le argument list parser
|
||||
* It is used directly by InterfaceCommand to consume, parse, validate le arguments.
|
||||
*/
|
||||
class ArgumentListParser implements IArgumentListParser {
|
||||
public readonly parseFunction: ParamaterParser
|
||||
constructor(
|
||||
public readonly descriptions: ParamaterDescription[],
|
||||
public readonly restParser: undefined|RestParser = undefined,
|
||||
) {
|
||||
this.parseFunction = this.makeParseFunction(descriptions, restParser);
|
||||
}
|
||||
|
||||
private makeParseFunction(descriptions: ParamaterDescription[], restParser: undefined|RestParser): ParamaterParser {
|
||||
return (...readItems: ReadItem[]) => {
|
||||
const itemStream = new ArgumentStream(readItems);
|
||||
for (const paramater of descriptions) {
|
||||
if (itemStream.peekItem() === undefined) {
|
||||
// FIXME asap: we need a proper paramater description?
|
||||
return CommandError.Result('expected an argument', `An argument for the paramater ${paramater.name} was expected but was not provided.`);
|
||||
}
|
||||
const item = itemStream.readItem()!;
|
||||
const result = paramater.acceptor.validator(item);
|
||||
if (result.err) {
|
||||
// should really allow the help to be printed later on and keep the whole context?
|
||||
return CommandResult.Err(result.err);
|
||||
}
|
||||
}
|
||||
const item = itemStream.readItem()!;
|
||||
const result = paramater.acceptor.validator(item);
|
||||
if (result.err) {
|
||||
// should really allow the help to be printed later on and keep the whole context?
|
||||
return CommandResult.Err(result.err);
|
||||
if (restParser) {
|
||||
const result = restParser.parseRest(itemStream);
|
||||
if (result.isErr()) {
|
||||
return CommandResult.Err(result.err);
|
||||
}
|
||||
return CommandResult.Ok({ immediateArguments: readItems, rest: result.ok });
|
||||
} else {
|
||||
return CommandResult.Ok({ immediateArguments: readItems });
|
||||
}
|
||||
}
|
||||
if (restParser) {
|
||||
const result = restParser.parseRest(itemStream);
|
||||
if (result.isErr()) {
|
||||
return CommandResult.Err(result.err);
|
||||
}
|
||||
return CommandResult.Ok({ immediateArguments: readItems, rest: result.ok });
|
||||
} else {
|
||||
return CommandResult.Ok({ immediateArguments: readItems });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user