From e6d0aaf9ea2f51465ed00f3361caa3dc1086c85f Mon Sep 17 00:00:00 2001 From: gnuxie Date: Wed, 28 Dec 2022 17:58:45 +0000 Subject: [PATCH] Richer paramater parsing. This commit is NOT contributed under the Apache-2.0 License. Copyright (C) 2022 Gnuxie All rights reserved. --- .../interface-manager/InterfaceCommand.ts | 10 +-- .../interface-manager/ParamaterParsing.ts | 71 +++++++++++++------ 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/commands/interface-manager/InterfaceCommand.ts b/src/commands/interface-manager/InterfaceCommand.ts index c59d0e15..513c9c60 100644 --- a/src/commands/interface-manager/InterfaceCommand.ts +++ b/src/commands/interface-manager/InterfaceCommand.ts @@ -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(name: string export class InterfaceCommand { constructor( - private readonly paramaterParser: ParamaterParser, + private readonly argumentListParser: IArgumentListParser, private readonly command: ExecutorType, public readonly designator: string[], ) { @@ -122,7 +122,7 @@ export class InterfaceCommand { // 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 { - return this.paramaterParser(...args); + return this.argumentListParser.parseFunction(...args); } public invoke(context: ThisParameterType, ...args: Parameters): ReturnType { @@ -130,7 +130,7 @@ export class InterfaceCommand { } public async parseThenInvoke(context: ThisParameterType, ...items: ReadItem[]): Promise> { - 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>; @@ -140,7 +140,7 @@ export class InterfaceCommand { } export function defineInterfaceCommand(description: { - paramaters: ParamaterParser, + paramaters: IArgumentListParser, table: string, command: ExecutorType, designator: string[], diff --git a/src/commands/interface-manager/ParamaterParsing.ts b/src/commands/interface-manager/ParamaterParsing.ts index e5152900..5d74d35f 100644 --- a/src/commands/interface-manager/ParamaterParsing.ts +++ b/src/commands/interface-manager/ParamaterParsing.ts @@ -172,30 +172,59 @@ export interface ParamaterDescription { export type ParamaterParser = (...readItems: ReadItem[]) => CommandResult; -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 }); - } } }