From 7848c5bcd60332c2c7328e4bdaaf7af40971b3c7 Mon Sep 17 00:00:00 2001 From: theseanl Date: Thu, 25 Jan 2024 08:06:46 +0900 Subject: [PATCH] chore: minor change as per reviews --- .../libs/printer/printer.ts | 2 +- .../libs/argspec-parser.ts | 40 ++++++++++++------- .../libs/gobble-single-argument.ts | 15 ++++--- .../tests/gobble-single-argument.test.ts | 30 ++++++-------- .../libs/newcommand.ts | 12 +++--- .../tests/macro-expansion.test.ts | 17 ++++---- 6 files changed, 63 insertions(+), 53 deletions(-) diff --git a/packages/unified-latex-prettier/libs/printer/printer.ts b/packages/unified-latex-prettier/libs/printer/printer.ts index e4ad93de..2cc02339 100644 --- a/packages/unified-latex-prettier/libs/printer/printer.ts +++ b/packages/unified-latex-prettier/libs/printer/printer.ts @@ -84,7 +84,7 @@ export function printLatexAst( case "whitespace": return line; case "hash_number": - return "#" + node.number.toString(10); + return `#${node.number}`; default: console.warn("Printing unknown type", node); return printRaw(node); diff --git a/packages/unified-latex-util-argspec/libs/argspec-parser.ts b/packages/unified-latex-util-argspec/libs/argspec-parser.ts index cda6063a..6901b279 100644 --- a/packages/unified-latex-util-argspec/libs/argspec-parser.ts +++ b/packages/unified-latex-util-argspec/libs/argspec-parser.ts @@ -34,14 +34,6 @@ export function printRaw( function printRawInner(node: ArgSpec.Node) { const decorators = getDecorators(node); let spec = decorators; - function appendDefaultArg() { - if (node.defaultArg) { - spec = appendTokenOrGroup(spec, node.defaultArg); - } - } - function appendCollection(collection: string[]) { - spec += printTokenOrCollection(collection); - } const type = node.type; switch (type) { case "body": @@ -58,7 +50,9 @@ function printRawInner(node: ArgSpec.Node) { spec += node.defaultArg ? "D" : "d"; spec += node.openBrace + node.closeBrace; } - appendDefaultArg(); + if (node.defaultArg) { + spec = appendTokenOrGroup(spec, node.defaultArg); + } return spec; case "mandatory": // {...} is the default enclosure for mandatory arguments @@ -68,20 +62,22 @@ function printRawInner(node: ArgSpec.Node) { spec += node.defaultArg ? "R" : "r"; spec += node.openBrace + node.closeBrace; } - appendDefaultArg(); + if (node.defaultArg) { + spec = appendTokenOrGroup(spec, node.defaultArg); + } return spec; case "embellishment": spec += node.defaultArgs ? "E" : "e"; - appendCollection(node.tokens); + spec += printTokenOrCollection(node.tokens); if (node.defaultArgs) { - appendCollection(node.defaultArgs); + spec += printTokenOrCollection(node.defaultArgs); } return spec; case "verbatim": return spec + "v" + node.openBrace; case "until": { spec += "u"; - appendCollection(node.stopTokens); + spec += printTokenOrCollection(node.stopTokens); return spec; } default: @@ -95,8 +91,22 @@ function printRawInner(node: ArgSpec.Node) { * This function will reconstruct a representative in an inverse image of token_or_group * for a given array of strings, and append it to a given string. * In order to avoid parsing ambiguity, we force enclose the representative with braces in some case. - * For instance, if the given string ends with a control word such as "\asdf", and if the representative is a - * whitespace where we are in a circumstance where no whitespaces are allowed. + * + * Examples) + * Appending a `token_or_group` representing an embellishment tokens, with existingString `e`. + * token of several chars "ab" --> {ab} will be appended, so the result will be `e{ab}`. + * token of single char "^" ---> ^ will be appended, so the result will be `e^`. + * token of single char " " ---> { } will be appended, so the result will be `e{ }`. + * + * Appending a `token_or_group` representing a bracespec of a delimited argument spec. + * Already constructed a string until the opening brace, existingString = "r\open". + * If the bracespec is a single alphabetric char "a", then we need to append it with braces, so the result will be "r\open{a}". + * + * Appending an embellishment token, with existingString = "e{a\token". + * If a next token is again a control world, say \anotherToken, we can append it as-is. "e{a\token\anotherToken". + * If a next token is a single char, say "b", we may either enclose it with braces or separate it with a space, + * because in this circumstance, space can be used to separate tokens (as conveyed by allowWhitespace = true). + * Then the result will be "e{a\token b". */ function appendTokenOrGroup( existingString: string, diff --git a/packages/unified-latex-util-arguments/libs/gobble-single-argument.ts b/packages/unified-latex-util-arguments/libs/gobble-single-argument.ts index c8a2e61a..19534f7d 100644 --- a/packages/unified-latex-util-arguments/libs/gobble-single-argument.ts +++ b/packages/unified-latex-util-arguments/libs/gobble-single-argument.ts @@ -236,7 +236,6 @@ function cloneStringNode(node: Ast.String, content: string): Ast.String { return Object.assign({}, node, { content }); } -type Braces = string | Ast.Macro | Ast.Whitespace; /** * Find the position of the open brace and the closing brace. * Returns undefined if the brace isn't found. @@ -246,8 +245,8 @@ type Braces = string | Ast.Macro | Ast.Whitespace; function findBracePositions( nodes: Ast.Node[], startPos: number, - openMark?: Braces, - closeMark?: Braces, + openMark?: string | Ast.Macro | Ast.Whitespace, + closeMark?: string | Ast.Macro | Ast.Whitespace, endPos?: number ): [number, number] | undefined { let openMarkPos: number | undefined = startPos; @@ -285,9 +284,15 @@ function findBracePositions( return [openMarkPos, closeMarkPos]; } +/** + * Find the position of the delimiter in `nodes`. A delimiter can either be a single character, + * or a single control word or a symbol (represented as Ast.Macro). Returns `undefined` + * if it cannot be found. If a search found a character delimiter in a middle of a string, + * this function may mutate `nodes` to split the string. + */ function findDelimiter( nodes: Ast.Node[], - token: Braces, + token: string | Ast.Macro | Ast.Whitespace, startPos: number, endPos?: number ): number | undefined { @@ -338,7 +343,7 @@ function findDelimiter( function parseToken( str: string | undefined -): string | Ast.Whitespace | Ast.Macro { +): string | Ast.Macro | Ast.Whitespace { if (!str) { return ""; } diff --git a/packages/unified-latex-util-arguments/tests/gobble-single-argument.test.ts b/packages/unified-latex-util-arguments/tests/gobble-single-argument.test.ts index c450f432..73be64d5 100644 --- a/packages/unified-latex-util-arguments/tests/gobble-single-argument.test.ts +++ b/packages/unified-latex-util-arguments/tests/gobble-single-argument.test.ts @@ -601,8 +601,8 @@ describe("unified-latex-util-arguments", () => { expect(nodes).toEqual([{ content: "yx", type: "string" }]); }); it("can gobble an 'until' argument with multiple stop tokens", () => { - let argspec = parseArgspec("u{a \\bcd}")[0]; - value = "asdf asydfxya{x}sa \\bcd2df"; + let argspec = parseArgspec("u{| \\stop}")[0]; + value = "|this_bar_is_not_a_stop|{token}this| \\stop is."; file = processLatexToAstViaUnified().processSync({ value }); let nodes = trimRenderInfo((file.result as any).content) as Ast.Node[]; expect(gobbleSingleArgument(nodes, argspec)).toEqual({ @@ -611,28 +611,24 @@ describe("unified-latex-util-arguments", () => { content: [ // Due to a current implementation of gobbleSingleArgument, // we may introduce extra string split during the search. - { type: "string", content: "a" }, - { type: "string", content: "sdf" }, - { type: "whitespace" }, - { type: "string", content: "a" }, - { type: "string", content: "sydfxy" }, - { type: "string", content: "a" }, + { type: "string", content: "|" }, + { type: "string", content: "this_bar_is_not_a_stop" }, + { type: "string", content: "|" }, { type: "group", - content: [{ type: "string", content: "x" }], + content: [{ type: "string", content: "token" }], }, - { type: "string", content: "s" }, + { type: "string", content: "this" }, ], openMark: "", - closeMark: "a \\bcd", + closeMark: "| \\stop", }, - nodesRemoved: 11, + nodesRemoved: 8, }); expect(nodes).toEqual([ - { - type: "string", - content: "2df", - }, + { type: "whitespace" }, + { type: "string", content: "is" }, + { type: "string", content: "." }, ]); }); it("gobbleSingleArgument gobbles non-punctuation delimited arguments", () => { @@ -825,7 +821,7 @@ describe("unified-latex-util-arguments", () => { nodesRemoved: 2, }); }); - it("can gobble optional argument with default argument", () => { + it("can skip optional argument with default argument", () => { const expectNoMatch = (ast: Ast.Node[]) => { expect( gobbleSingleArgument(ast, parseArgspec("O{default}")[0]) diff --git a/packages/unified-latex-util-macros/libs/newcommand.ts b/packages/unified-latex-util-macros/libs/newcommand.ts index fa45a1d2..67c42821 100644 --- a/packages/unified-latex-util-macros/libs/newcommand.ts +++ b/packages/unified-latex-util-macros/libs/newcommand.ts @@ -252,24 +252,24 @@ export function createMacroExpander( // some options that is provided to whatever function that called this to // the below parse call. Note that `parse` is done in several passes, and we // may be able to cache result of a first few passes that aren't context-dependent. - const subst = parse(defaultArg).content; - const hasSubstitutions = attachHashNumbers(subst); + const sub = parse(defaultArg).content; + const hasSubstitutions = attachHashNumbers(sub); if (!hasSubstitutions) { - return subst; + return sub; } stack.push(hashNum); try { - expandArgs(subst); + expandArgs(sub); if (lastSelfReference !== hashNum) { - return subst; + return sub; } // At this point, we have encountered #n while expanding #n. // Check if we got exactly #n by expanding #n, // in which case we should return the -NoValue-. - if (`#${hashNum}` === printRaw(subst)) { + if (`#${hashNum}` === printRaw(sub)) { // We are good, clear the last self-reference variable lastSelfReference = null; return emptyArg(); diff --git a/packages/unified-latex-util-macros/tests/macro-expansion.test.ts b/packages/unified-latex-util-macros/tests/macro-expansion.test.ts index 43381194..a2776ad4 100644 --- a/packages/unified-latex-util-macros/tests/macro-expansion.test.ts +++ b/packages/unified-latex-util-macros/tests/macro-expansion.test.ts @@ -1,11 +1,10 @@ +import util from "util"; import { m } from "@unified-latex/unified-latex-builder"; import * as Ast from "@unified-latex/unified-latex-types"; -import util from "util"; -import { attachMacroArgsInArray } from "../../unified-latex-util-arguments/libs/attach-arguments"; - import * as latexParser from "@unified-latex/unified-latex-util-parse"; import { printRaw } from "@unified-latex/unified-latex-util-print-raw"; import { trimRenderInfo } from "@unified-latex/unified-latex-util-render-info"; +import { attachMacroArgsInArray } from "../../unified-latex-util-arguments/libs/attach-arguments"; import { expandMacros } from "../libs/expand-macros"; import { createMacroExpander } from "../libs/newcommand"; @@ -169,16 +168,16 @@ describe("unified-latex-utils-macros", () => { }); it("Can substitute default arguments that cross-references each other", () => { - let substitutionBody = latexParser.parse("#1/#2").content; + let substitutionBody = latexParser.parse("#1.#2").content; // This macro defines the args that will be substituted let macro = parseXxxMacro("\\xxx", "O{#2} O{#1}"); const expander = createMacroExpander(substitutionBody, "O{#2} O{#1}"); - expect(printRaw(expander(macro))).toEqual("/"); + expect(printRaw(expander(macro))).toEqual("."); }); it("Can substitute default arguments referencing other default arguments that cross-references each other", () => { - let substitutionBody = latexParser.parse("#1/#2/#3/#4").content; + let substitutionBody = latexParser.parse("#1.#2.#3.#4").content; // This macro defines the args that will be substituted let macro = parseXxxMacro("\\xxx", "O{a#2#4} O{#3} O{#2} O{b#2}"); @@ -186,12 +185,12 @@ describe("unified-latex-utils-macros", () => { substitutionBody, "O{a#2#4} O{#3} O{#2} O{b#2}" ); - expect(printRaw(expander(macro))).toEqual("ab///b"); + expect(printRaw(expander(macro))).toEqual("ab...b"); }); it("Can substitute default arguments with complex dependency graph", () => { let substitutionBody = latexParser.parse( - "#1/#2/#3/#4/#5/#6/#7/#8/#9" + "#1.#2.#3.#4.#5.#6.#7.#8.#9" ).content; // This macro defines the args that will be substituted let macro = parseXxxMacro( @@ -203,7 +202,7 @@ describe("unified-latex-utils-macros", () => { substitutionBody, "D<>{#2} E{^_}{{#1}{#4}} O{#5} E{<>,}{{#3}{a#3b#1c#7}{#9d#4}} O{#6e} D\\a\\b{f#8}" ); - expect(printRaw(expander(macro))).toEqual("/////abc9d/9d/abc9de/9"); + expect(printRaw(expander(macro))).toEqual(".....abc9d.9d.abc9de.9"); }); it("Can expand macro", () => {