Parse command substitutions

This commit is contained in:
Tangent Wantwight 2023-08-25 19:10:45 -04:00
parent ca5d64eca7
commit a97f38a7b9
4 changed files with 147 additions and 13 deletions

View file

@ -17,13 +17,23 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
"enchanted": "para",
},
{
"text": "[2",
},
{
"enchanted": "+",
},
{
"text": "2]",
"pieces": [
{
"script": [
[
{
"enchanted": "2",
},
{
"enchanted": "+",
},
{
"enchanted": "2",
},
],
],
},
],
},
],
[

View file

@ -129,7 +129,118 @@ b`)
// variables- bare, brace
});
describe("command interpolation", () => {});
describe("command interpolation", () => {
it("can parse empty command interpolations", () =>
expect(parse("[]")).toEqual([true, [[{ pieces: [{ script: [] }] }]]]));
it("can parse one-word command interpolations", () =>
expect(parse("[a]")).toEqual([
true,
[[{ pieces: [{ script: [[{ enchanted: "a" }]] }] }]],
]));
it("can parse multi-word command interpolations", () =>
expect(parse("[a b c]")).toEqual([
true,
[
[
{
pieces: [
{
script: [
[
{ enchanted: "a" },
{ enchanted: "b" },
{ enchanted: "c" },
],
],
},
],
},
],
],
]));
it("can parse multi-command command interpolations", () =>
expect(parse("[a; b c]")).toEqual([
true,
[
[
{
pieces: [
{
script: [
[{ enchanted: "a" }],
[{ enchanted: "b" }, { enchanted: "c" }],
],
},
],
},
],
],
]));
it("can parse nested command interpolations", () =>
expect(parse("[[a]]")).toEqual([
true,
[
[
{
pieces: [
{
script: [[{ pieces: [{ script: [[{ enchanted: "a" }]] }] }]],
},
],
},
],
],
]));
it("can parse pre-word command interpolations", () =>
expect(parse("[a]b")).toEqual([
true,
[[{ pieces: [{ script: [[{ enchanted: "a" }]] }, { text: "b" }] }]],
]));
it("can parse mid-word command interpolations", () =>
expect(parse("a[b]c")).toEqual([
true,
[
[
{
pieces: [
{ text: "a" },
{ script: [[{ enchanted: "b" }]] },
{ text: "c" },
],
},
],
],
]));
it("can parse end-word command interpolations", () =>
expect(parse("a[b]")).toEqual([
true,
[[{ pieces: [{ text: "a" }, { script: [[{ enchanted: "b" }]] }] }]],
]));
it("can parse multiple command interpolations in a word", () =>
expect(parse("[a][b]")).toEqual([
true,
[
[
{
pieces: [
{ script: [[{ enchanted: "a" }]] },
{ script: [[{ enchanted: "b" }]] },
],
},
],
],
]));
test.each(["[", "a["])(
"does not permit unterminated commands {%s}",
(text) => expect(parse(text)).toMatchObject([false, {}])
);
test.each(['["]"', '"["]', "[{]}", "{[}]"])(
"does not permit overlapping commands and quotes {%s}",
(text) => expect(parse(text)).toMatchObject([false, {}])
);
});
describe("brace words", () => {
it("can parse empty braces", () =>

View file

@ -13,6 +13,7 @@ import {
EnchantedWord as EnchantedWordType,
InterpolatedPiece,
Script,
ScriptPiece,
SimplifyWord,
TextWord,
Word as WordType,
@ -24,7 +25,7 @@ const Comment = Regex(/#[^\n]*/y)
const PreWordWhitespace = Regex(/[^\S\n;]+/y).expects("whitespace");
const EnchantedWord = Regex(/[^\]\[\}\{$\\";\s]+(?=[\s;]|$)/y)
const EnchantedWord = Regex(/[^\]\[\}\{$\\";\s]+(?=[\s;\]]|$)/y)
.map(([enchanted]) => ({ enchanted } as EnchantedWordType))
.expects("ENCHANTED_WORD");
@ -32,7 +33,16 @@ const BackslashEscape = Regex(/\\(.)/y)
.expects("\\")
.map(([, char]) => ({ text: char }));
const BARE_WORD_CHAR = /[^\s\\;]+/y;
const BARE_WORD_CHAR = /[^\s\\;\[]+/y;
const BARE_BRACKET_WORD_CHAR = /[^\s\\;\[\]]+/y;
let BracketScript: Pattern<Script>;
const Bracket: Pattern<ScriptPiece> = Sequence(
Regex(/\[/y).expects("["),
Use(() => BracketScript)
)
.expects("[")
.map(([, script]) => ({ script }));
function bareWordTmpl(charRegex: RegExp) {
return Sequence(
@ -41,6 +51,7 @@ function bareWordTmpl(charRegex: RegExp) {
1,
Choose<InterpolatedPiece>(
BackslashEscape,
Bracket,
Regex(charRegex)
.expects("CHAR")
.map(([text]) => ({ text }))
@ -55,7 +66,8 @@ const QuotedWord = Sequence(
0,
Choose<InterpolatedPiece>(
BackslashEscape,
Regex(/[^"\\]+/y)
Bracket,
Regex(/[^"\\\[]+/y)
.expects("CHAR")
.map(([text]) => ({ text }))
)
@ -128,6 +140,7 @@ function scriptTmpl(bareWordCharRegex: RegExp, endPattern: Pattern<unknown>) {
}
const Script = scriptTmpl(BARE_WORD_CHAR, End());
BracketScript = scriptTmpl(BARE_BRACKET_WORD_CHAR, Regex(/\]/y).expects("]"));
const ERROR_CONTEXT = /(?<=([^\n]{0,50}))([^\n]{0,50})/y;

View file

@ -31,8 +31,8 @@ export type HtmlWord = {
export type TextPiece = TextWord;
export type VariablePiece = { variable: string };
export type CommandPiece = { command: unknown };
export type InterpolatedPiece = TextPiece | VariablePiece | CommandPiece;
export type ScriptPiece = { script: Script };
export type InterpolatedPiece = TextPiece | VariablePiece | ScriptPiece;
/**
* A word whose value needs to be determined by evaluating some combination of variable and command