Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix font commands extending to all binary and ternary operants #101

Merged
merged 1 commit into from
Nov 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fix font commands extending to all binary and ternary operants
**Output Changes**

* When writing something like `bf A_(ij)` previously the boldface was
  incorrectly applied to the indices (ij) as well as the intended
  matrix (A). Now the boldface will only be applied to the matrix
  unless everything is put in a group `bf (A_(ij))`.

Fixes: #97
runarberg committed Nov 24, 2023
commit 8af250ad063e6e145f566725e63b8b41cc4e3a1b
88 changes: 62 additions & 26 deletions src/compiler/parser/handlers/command.js
Original file line number Diff line number Diff line change
@@ -4,12 +4,54 @@ import expr from "./expr.js";
* @typedef {import("../../tokenizer/index.js").Token} Token
* @typedef {import("../index.js").Node} Node
* @typedef {import("../index.js").UnaryOperation} UnaryOperation
* @typedef {import("../index.js").BinaryOperation} BinaryOperation
* @typedef {import("../index.js").TernaryOperation} TernaryOperation
* @typedef {UnaryOperation | BinaryOperation | TernaryOperation} Operation
* @typedef {import("../index.js").Term} Term
*/

/**
* @param {Node} node
* @param {string[]} transforms
* @returns {Operation | Term}
*/
function insertTransformNode(node, transforms) {
if (node.type === "Term" && node.items.length > 0) {
// Only apply transform to first node.
const [first, ...rest] = node.items;
return {
...node,
items: [insertTransformNode(first, transforms), ...rest],
};
}

if (node.type === "BinaryOperation") {
const [left, right] = node.items;
return {
...node,
items: [insertTransformNode(left, transforms), right],
};
}

if (node.type === "TernaryOperation") {
const [a, b, c] = node.items;
return {
...node,
items: [insertTransformNode(a, transforms), b, c],
};
}

return {
type: "UnaryOperation",
name: "command",
transforms,
items: [node],
};
}

/**
* @param {import("../parse.js").State} State
* @returns {{ node: UnaryOperation | Term; end: number }}
* @returns {{ node: Operation | Term; end: number }}
*/
export default function command({ start, tokens }) {
const token = tokens[start];
@@ -58,41 +100,35 @@ export default function command({ start, tokens }) {

const next = expr({ stack: [], start: pos, tokens });

if (next.node.type === "Term") {
// Only apply command to the first item in the term
const [first, ...rest] = next.node.items;

/** @type {Node[]} */
const items = first
? [
{
type: "UnaryOperation",
name: "command",
transforms: textTransforms,
items: [first],
},
...rest,
]
: [];
if (textTransforms.length === 0) {
// Only apply styles.
return {
node: {
type: "UnaryOperation",
name: "command",
styles,
items: [next.node],
},
end: next.end,
};
}

const node = insertTransformNode(next.node, textTransforms);

if (styles.size > 0) {
return {
node: {
type: "Term",
type: "UnaryOperation",
name: "command",
styles,
items,
items: [node],
},
end: next.end,
};
}

return {
node: {
type: "UnaryOperation",
name: "command",
transforms: textTransforms,
styles,
items: [next.node],
},
node,
end: next.end,
};
}
51 changes: 45 additions & 6 deletions src/compiler/parser/handlers/command.test.js
Original file line number Diff line number Diff line change
@@ -7,8 +7,9 @@ test("no opperant", (t) => {
const { end, node } = command({ start: 0, tokens });

t.true(end >= tokens.length);
t.is(node.type, "Term");
t.deepEqual(node.items, []);
t.is(node.type, "UnaryOperation");
t.is(node.name, "command");
t.deepEqual(node.items, [{ type: "Term", items: [] }]);
});

test("unknown command", (t) => {
@@ -19,12 +20,11 @@ test("unknown command", (t) => {
const { end, node } = command({ start: 0, tokens });

t.is(end, tokens.length);
t.is(node.type, "Term");
t.is(node.type, "UnaryOperation");
t.is(node.name, "command");
t.deepEqual(node.items, [
{
type: "UnaryOperation",
name: "command",
transforms: [],
type: "Term",
items: [
{
type: "IdentLiteral",
@@ -178,6 +178,45 @@ test("multiple text-transform with following term", (t) => {
]);
});

test("text and style command with following term", (t) => {
const tokens = [
{ type: "command", name: "color", value: "red" },
{ type: "command", name: "text-transform", value: "bf" },
{ type: "ident", value: "A" },
{ type: "ident", value: "b" },
];

const { end, node } = command({ start: 0, tokens });

t.is(end, tokens.length);
t.is(node.type, "UnaryOperation");
t.deepEqual(node.styles, new Map([["color", "red"]]));
t.deepEqual(node.items, [
{
type: "Term",
items: [
{
type: "UnaryOperation",
name: "command",
transforms: ["bf"],
items: [
{
type: "IdentLiteral",
value: "A",
attrs: undefined,
},
],
},
{
type: "IdentLiteral",
value: "b",
attrs: undefined,
},
],
},
]);
});

test("text-transform on a group", (t) => {
const tokens = [
{ type: "command", name: "text-transform", value: "bf" },
12 changes: 12 additions & 0 deletions test/fonts.js
Original file line number Diff line number Diff line change
@@ -105,3 +105,15 @@ test("Mathvariants for fenced groups", (t) => {
test("Mathvariants for matrices", (t) => {
t.snapshot(render("bf [a; b]"));
});

test("Mathvariants for subscripts", (t) => {
t.snapshot(render("bf a_i"));
});

test("Mathvariants for superscripts", (t) => {
t.snapshot(render("bf a^2"));
});

test("Mathvariants for sub-superscripts", (t) => {
t.snapshot(render("bf a_i^2"));
});
18 changes: 18 additions & 0 deletions test/snapshots/fonts.js.md
Original file line number Diff line number Diff line change
@@ -257,3 +257,21 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

'<math><mrow><mo fence="true">[</mo><mtable><mtr><mtd><mi>𝐚</mi></mtd></mtr><mtr><mtd><mi>𝐛</mi></mtd></mtr></mtable><mo fence="true">]</mo></mrow></math>'

## Mathvariants for subscripts

> Snapshot 1

'<math><msub><mi>𝐚</mi><mi>i</mi></msub></math>'

## Mathvariants for superscripts

> Snapshot 1

'<math><msup><mi>𝐚</mi><mn>2</mn></msup></math>'

## Mathvariants for sub-superscripts

> Snapshot 1

'<math><msubsup><mi>𝐚</mi><mi>i</mi><mn>2</mn></msubsup></math>'
Binary file modified test/snapshots/fonts.js.snap
Binary file not shown.