Add & register more basic commands
This commit is contained in:
parent
c437958406
commit
bfc9459b69
@ -3,6 +3,8 @@ export type Awaitable<T> = T | Promise<T>
|
|||||||
export type JSONScalar = string | boolean | number | undefined
|
export type JSONScalar = string | boolean | number | undefined
|
||||||
export type JSONData = JSONScalar | Array<JSONScalar | JSONData> | { [key: string]: JSONScalar | JSONData }
|
export type JSONData = JSONScalar | Array<JSONScalar | JSONData> | { [key: string]: JSONScalar | JSONData }
|
||||||
|
|
||||||
|
export type ElementType<T extends readonly any[]> = T extends (infer U)[] ? U : never;
|
||||||
|
|
||||||
/** A typescript-compatible version of Object.hasOwnProperty. */
|
/** A typescript-compatible version of Object.hasOwnProperty. */
|
||||||
export function hasOwnProperty<X extends {}, Y extends PropertyKey>(obj: X, prop: Y): obj is X & Record<Y, unknown> { // eslint-disable-line @typescript-eslint/ban-types
|
export function hasOwnProperty<X extends {}, Y extends PropertyKey>(obj: X, prop: Y): obj is X & Record<Y, unknown> { // eslint-disable-line @typescript-eslint/ban-types
|
||||||
return Object.hasOwnProperty.call(obj, prop)
|
return Object.hasOwnProperty.call(obj, prop)
|
||||||
|
|||||||
16
src/vm/commands/clear.ts
Normal file
16
src/vm/commands/clear.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Clear extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'clear')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'clear'
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import {
|
|||||||
IsNotKeywordError,
|
IsNotKeywordError,
|
||||||
UnexpectedEndOfInputError
|
UnexpectedEndOfInputError
|
||||||
} from "../parse.js";
|
} from "../parse.js";
|
||||||
|
import {ElementType} from "../../util/types.js";
|
||||||
|
|
||||||
export type StrLVal = { term: 'variable', name: string }
|
export type StrLVal = { term: 'variable', name: string }
|
||||||
|
|
||||||
@ -48,7 +49,12 @@ export class ParseContext {
|
|||||||
return { term: 'string', value: input.value, literal: input.literal }
|
return { term: 'string', value: input.value, literal: input.literal }
|
||||||
}
|
}
|
||||||
|
|
||||||
popKeywordInSet<T extends string[]>(options: T) {
|
popOptionalKeywordInSet<const T extends readonly string[]>(options: T): (StrTerm & { value: ElementType<T> }) | undefined {
|
||||||
|
if ( this.inputs.length ) return this.popKeywordInSet(options)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
popKeywordInSet<const T extends readonly string[]>(options: T): StrTerm & { value: ElementType<T> } {
|
||||||
if ( !this.inputs.length ) {
|
if ( !this.inputs.length ) {
|
||||||
throw new UnexpectedEndOfInputError('Unexpected end of input. Expected one of: ' + options.join(', '))
|
throw new UnexpectedEndOfInputError('Unexpected end of input. Expected one of: ' + options.join(', '))
|
||||||
}
|
}
|
||||||
@ -58,6 +64,8 @@ export class ParseContext {
|
|||||||
if ( input.literal || !options.includes(input.value) ) {
|
if ( input.literal || !options.includes(input.value) ) {
|
||||||
throw new IsNotKeywordError('Unexpected term: ' + input.value + ' (expected one of: ' + options.join(', ') + ')')
|
throw new IsNotKeywordError('Unexpected term: ' + input.value + ' (expected one of: ' + options.join(', ') + ')')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { term: 'string', value: input.value as ElementType<T> }
|
||||||
}
|
}
|
||||||
|
|
||||||
popLVal(): StrLVal {
|
popLVal(): StrLVal {
|
||||||
|
|||||||
18
src/vm/commands/contains.ts
Normal file
18
src/vm/commands/contains.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { LexInput } from "../lexer.js";
|
||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
|
||||||
|
export class Contains extends Command<{ find: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { find: StrTerm } {
|
||||||
|
return {
|
||||||
|
find: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'contains'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'contains')
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/enclose.ts
Normal file
24
src/vm/commands/enclose.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type EncloseData = {
|
||||||
|
left?: StrTerm,
|
||||||
|
right?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Enclose extends Command<EncloseData> {
|
||||||
|
attemptParse(context: ParseContext): EncloseData {
|
||||||
|
return {
|
||||||
|
left: context.popOptionalTerm(),
|
||||||
|
right: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'enclose'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'enclose')
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/vm/commands/help.ts
Normal file
16
src/vm/commands/help.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Help extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'help')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'help'
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/indent.ts
Normal file
24
src/vm/commands/indent.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type IndentData = {
|
||||||
|
type: 'space'|'tab',
|
||||||
|
level?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Indent extends Command<IndentData> {
|
||||||
|
attemptParse(context: ParseContext): IndentData {
|
||||||
|
return {
|
||||||
|
type: context.popKeywordInSet(['space', 'tab']).value,
|
||||||
|
level: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'indent')
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'indent'
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,19 +11,67 @@ import {Paste} from "./paste.js";
|
|||||||
import {RunFile} from "./runfile.js";
|
import {RunFile} from "./runfile.js";
|
||||||
import {Save} from "./save.js";
|
import {Save} from "./save.js";
|
||||||
import {To} from "./to.js";
|
import {To} from "./to.js";
|
||||||
|
import {Lipsum} from "./lipsum.js";
|
||||||
|
import {Indent} from "./indent.js";
|
||||||
|
import {Clear} from "./clear.js";
|
||||||
|
import {Contains} from "./contains.js";
|
||||||
|
import {Enclose} from "./enclose.js";
|
||||||
|
import {Help} from "./help.js";
|
||||||
|
import {Join} from "./join.js";
|
||||||
|
import {Lines} from "./lines.js";
|
||||||
|
import {Lower} from "./lower.js";
|
||||||
|
import {LSub} from "./lsub.js";
|
||||||
|
import {Missing} from "./missing.js";
|
||||||
|
import {Prefix} from "./prefix.js";
|
||||||
|
import {Quote} from "./quote.js";
|
||||||
|
import {Redo} from "./redo.js";
|
||||||
|
import {Replace} from "./replace.js";
|
||||||
|
import {RSub} from "./rsub.js";
|
||||||
|
import {Show} from "./show.js";
|
||||||
|
import {Split} from "./split.js";
|
||||||
|
import {Suffix} from "./suffix.js";
|
||||||
|
import {Trim} from "./trim.js";
|
||||||
|
import {Undo} from "./undo.js";
|
||||||
|
import {Unique} from "./unique.js";
|
||||||
|
import {Unquote} from "./unquote.js";
|
||||||
|
import {Upper} from "./upper.js";
|
||||||
|
|
||||||
export type Commands = Command<CommandData>[]
|
export type Commands = Command<CommandData>[]
|
||||||
export const commands: Commands = [
|
export const commands: Commands = [
|
||||||
|
new Clear,
|
||||||
|
new Contains,
|
||||||
new Copy,
|
new Copy,
|
||||||
new Edit,
|
new Edit,
|
||||||
|
new Enclose,
|
||||||
new Exit,
|
new Exit,
|
||||||
new From,
|
new From,
|
||||||
|
new Help,
|
||||||
new History,
|
new History,
|
||||||
|
new Indent,
|
||||||
new InFile,
|
new InFile,
|
||||||
|
new Join,
|
||||||
|
new Lines,
|
||||||
|
new Lipsum,
|
||||||
new Load,
|
new Load,
|
||||||
|
new Lower,
|
||||||
|
new LSub,
|
||||||
|
new Missing,
|
||||||
new OutFile,
|
new OutFile,
|
||||||
new Paste,
|
new Paste,
|
||||||
|
new Prefix,
|
||||||
|
new Quote,
|
||||||
|
new Redo,
|
||||||
|
new Replace,
|
||||||
|
new RSub,
|
||||||
new RunFile,
|
new RunFile,
|
||||||
new Save,
|
new Save,
|
||||||
|
new Show,
|
||||||
|
new Split,
|
||||||
|
new Suffix,
|
||||||
new To,
|
new To,
|
||||||
|
new Trim,
|
||||||
|
new Undo,
|
||||||
|
new Unique,
|
||||||
|
new Unquote,
|
||||||
|
new Upper,
|
||||||
]
|
]
|
||||||
|
|||||||
18
src/vm/commands/join.ts
Normal file
18
src/vm/commands/join.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Join extends Command<{ with: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { with: StrTerm } {
|
||||||
|
return {
|
||||||
|
with: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'join'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'join')
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/lines.ts
Normal file
24
src/vm/commands/lines.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type LinesData = {
|
||||||
|
on?: StrTerm,
|
||||||
|
with?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Lines extends Command<LinesData> {
|
||||||
|
attemptParse(context: ParseContext): LinesData {
|
||||||
|
return {
|
||||||
|
on: context.popOptionalTerm(),
|
||||||
|
with: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'lines'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'lines')
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,13 @@
|
|||||||
import {Command, ParseContext, StrTerm} from './command.js'
|
import {Command, ParseContext, StrTerm} from './command.js'
|
||||||
import {LexInput} from '../lexer.js'
|
import {LexInput} from '../lexer.js'
|
||||||
|
|
||||||
export class Lipsum extends Command<{ length: StrTerm }> {
|
export type LipsumData = { length: StrTerm, type: 'word'|'line'|'para' }
|
||||||
attemptParse(context: ParseContext): { length: StrTerm } {
|
|
||||||
|
export class Lipsum extends Command<LipsumData> {
|
||||||
|
attemptParse(context: ParseContext): LipsumData {
|
||||||
return {
|
return {
|
||||||
length: context.popTerm(),
|
length: context.popTerm(),
|
||||||
|
type: context.popKeywordInSet(['word', 'line', 'para']).value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/vm/commands/lower.ts
Normal file
16
src/vm/commands/lower.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Lower extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'lower')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'lower'
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/lsub.ts
Normal file
24
src/vm/commands/lsub.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type LSubData = {
|
||||||
|
offset: StrTerm,
|
||||||
|
length?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LSub extends Command<LSubData> {
|
||||||
|
attemptParse(context: ParseContext): LSubData {
|
||||||
|
return {
|
||||||
|
offset: context.popTerm(),
|
||||||
|
length: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'lsub'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'lsub')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/missing.ts
Normal file
18
src/vm/commands/missing.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { LexInput } from "../lexer.js";
|
||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
|
||||||
|
export class Missing extends Command<{ find: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { find: StrTerm } {
|
||||||
|
return {
|
||||||
|
find: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'missing'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'missing')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/prefix.ts
Normal file
18
src/vm/commands/prefix.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Prefix extends Command<{ with: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { with: StrTerm } {
|
||||||
|
return {
|
||||||
|
with: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'prefix'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'prefix')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/quote.ts
Normal file
18
src/vm/commands/quote.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Quote extends Command<{ with?: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { with?: StrTerm } {
|
||||||
|
return {
|
||||||
|
with: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'quote'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'quote')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/redo.ts
Normal file
18
src/vm/commands/redo.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Redo extends Command<{ steps: StrTerm }> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'redo')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): { steps: StrTerm } {
|
||||||
|
return {
|
||||||
|
steps: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'redo'
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/replace.ts
Normal file
24
src/vm/commands/replace.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type ReplaceData = {
|
||||||
|
find: StrTerm,
|
||||||
|
with: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Replace extends Command<ReplaceData> {
|
||||||
|
attemptParse(context: ParseContext): ReplaceData {
|
||||||
|
return {
|
||||||
|
find: context.popTerm(),
|
||||||
|
with: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'replace'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'replace')
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/rsub.ts
Normal file
24
src/vm/commands/rsub.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type RSubData = {
|
||||||
|
offset: StrTerm,
|
||||||
|
length?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RSub extends Command<RSubData> {
|
||||||
|
attemptParse(context: ParseContext): RSubData {
|
||||||
|
return {
|
||||||
|
offset: context.popTerm(),
|
||||||
|
length: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'rsub'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'rsub')
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/vm/commands/show.ts
Normal file
16
src/vm/commands/show.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Show extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'show')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'show'
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/split.ts
Normal file
24
src/vm/commands/split.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type SplitData = {
|
||||||
|
on: StrTerm,
|
||||||
|
with?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Split extends Command<SplitData> {
|
||||||
|
attemptParse(context: ParseContext): SplitData {
|
||||||
|
return {
|
||||||
|
on: context.popTerm(),
|
||||||
|
with: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'split'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'split')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/suffix.ts
Normal file
18
src/vm/commands/suffix.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Suffix extends Command<{ with: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { with: StrTerm } {
|
||||||
|
return {
|
||||||
|
with: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'suffix'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'suffix')
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/vm/commands/trim.ts
Normal file
24
src/vm/commands/trim.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export type TrimData = {
|
||||||
|
type?: 'start'|'end'|'both'|'left'|'right'|'lines',
|
||||||
|
char?: StrTerm,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Trim extends Command<TrimData> {
|
||||||
|
attemptParse(context: ParseContext): TrimData {
|
||||||
|
return {
|
||||||
|
type: context.popOptionalKeywordInSet(['start', 'end', 'both', 'left', 'right', 'lines'])?.value,
|
||||||
|
char: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'trim'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'trim')
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/undo.ts
Normal file
18
src/vm/commands/undo.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Undo extends Command<{ steps: StrTerm }> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'undo')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): { steps: StrTerm } {
|
||||||
|
return {
|
||||||
|
steps: context.popTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'undo'
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/vm/commands/unique.ts
Normal file
16
src/vm/commands/unique.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Unique extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'unique')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'unique'
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/vm/commands/unquote.ts
Normal file
18
src/vm/commands/unquote.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Unquote extends Command<{ with?: StrTerm }> {
|
||||||
|
attemptParse(context: ParseContext): { with?: StrTerm } {
|
||||||
|
return {
|
||||||
|
with: context.popOptionalTerm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'unquote'
|
||||||
|
}
|
||||||
|
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'unquote')
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/vm/commands/upper.ts
Normal file
16
src/vm/commands/upper.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {Command, ParseContext} from "./command.js";
|
||||||
|
import {LexInput} from "../lexer.js";
|
||||||
|
|
||||||
|
export class Upper extends Command<{}> {
|
||||||
|
isParseCandidate(token: LexInput): boolean {
|
||||||
|
return this.isKeyword(token, 'upper')
|
||||||
|
}
|
||||||
|
|
||||||
|
attemptParse(context: ParseContext): {} {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDisplayName(): string {
|
||||||
|
return 'upper'
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user