import {Command, ParseContext, StrTerm} from "./command.js"; import {LexInput} from "../lexer.js"; import {StrVM} from "../vm.js"; import {Awaitable} from "../../util/types.js"; export const QUOTEMARKS = ['"', '\'', '`'] export const stripQuotemarkLayer = (s: string, marks?: string[]): string => { if ( !marks ) { marks = QUOTEMARKS } for ( const mark of marks ) { if ( !s.startsWith(mark) || !s.endsWith(mark) ) { continue } s = s.substring(mark.length, s.length - mark.length) break } return s } 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') } execute(vm: StrVM, data: { with?: StrTerm }): Awaitable { return vm.replaceContextMatchingTerm(ctx => ({ string: sub => { let quote = '\'' if ( data.with ) { quote = ctx.resolveString(data.with) } sub = stripQuotemarkLayer(sub) sub = sub.replaceAll(quote, `\\${quote}`) return `${quote}${sub}${quote}` } })) } }