Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion math-core/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl<'source> Lexer<'source> {

while self.peek.1.is_ascii_alphanumeric()
|| self.peek.1.is_ascii_whitespace()
|| matches!(self.peek.1, '|' | '.' | '-' | ',' | '*')
|| matches!(self.peek.1, '|' | '.' | '-' | ',' | '*' | ':')
{
self.read_char();
}
Expand Down
12 changes: 10 additions & 2 deletions math-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,16 @@ mod tests {
// ("hspace_whitespace_in_between", r"\hspace{ 4 em }"),
("array_simple", r"\begin{array}{lcr} 0 & 1 & 2 \end{array}"),
(
"array_center_lines",
r"\begin{array}{ |c| |cc| } 1 & 2 & 3\\ 4 & 5 & 6 \end{array}",
"array_lines",
r"\begin{array}{ |l| |rc| } 10 & 20 & 30\\ 4 & 5 & 6 \end{array}",
),
(
"array_many_lines",
r"\begin{array}{ ||::|l } 10\\ 2 \end{array}",
),
(
"subarray",
r"\sum_{\begin{subarray}{c} 0 \le i \le m\\ 0 < j < n \end{subarray}}",
),
];

Expand Down
17 changes: 13 additions & 4 deletions math-core/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ where
Token::Begin => {
// Read the environment name.
let env_name = self.parse_ascii_text_group()?.1;
let array_spec = if env_name == "array" {
let array_spec = if env_name == "array" || env_name == "subarray" {
// Parse the array options.
let (loc, options) = self.parse_ascii_text_group()?;
Some(
Expand Down Expand Up @@ -660,10 +660,19 @@ where
align: Alignment::Centered,
attr: None,
},
"array" => {
// SAFETY: `array_spec` is guaranteed to be Some because we checked for "array" above.
let spec = unsafe { array_spec.unwrap_unchecked() };
array_variant @ ("array" | "subarray") => {
// SAFETY: `array_spec` is guaranteed to be Some because we checked for
// "array" and "subarray" above.
// TODO: Refactor this to avoid using `unsafe`.
let mut spec = unsafe { array_spec.unwrap_unchecked() };
let style = if array_variant == "subarray" {
spec.is_sub = true;
Some(Style::ScriptStyle)
} else {
None
};
Node::Array {
style,
content,
array_spec: self.arena.alloc_array_spec(spec),
}
Expand Down
30 changes: 0 additions & 30 deletions math-core/src/snapshots/math_core__tests__array_center_lines.snap

This file was deleted.

32 changes: 32 additions & 0 deletions math-core/src/snapshots/math_core__tests__array_lines.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
source: math-core/src/lib.rs
expression: "\\begin{array}{ |l| |rc| } 10 & 20 & 30\\\\ 4 & 5 & 6 \\end{array}"
---
<math>
<mtable style="border-left: 0.05em solid black">
<mtr>
<mtd style="text-align: -webkit-left;text-align: -moz-left;border-right: 0.05em solid black;">
<mn>10</mn>
</mtd>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="text-align: -webkit-right;text-align: -moz-right;">
<mn>20</mn>
</mtd>
<mtd style="border-right: 0.05em solid black;">
<mn>30</mn>
</mtd>
</mtr>
<mtr>
<mtd style="text-align: -webkit-left;text-align: -moz-left;border-right: 0.05em solid black;">
<mn>4</mn>
</mtd>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="text-align: -webkit-right;text-align: -moz-right;">
<mn>5</mn>
</mtd>
<mtd style="border-right: 0.05em solid black;">
<mn>6</mn>
</mtd>
</mtr>
</mtable>
</math>
26 changes: 26 additions & 0 deletions math-core/src/snapshots/math_core__tests__array_many_lines.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
source: math-core/src/lib.rs
expression: "\\begin{array}{ ||::|l } 10\\\\ 2 \\end{array}"
---
<math>
<mtable style="border-left: 0.05em solid black">
<mtr>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em dashed black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em dashed black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="text-align: -webkit-left;text-align: -moz-left;">
<mn>10</mn>
</mtd>
</mtr>
<mtr>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em dashed black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em dashed black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="border-right: 0.05em solid black;padding-left: 0.1em;padding-right: 0.1em;"></mtd>
<mtd style="text-align: -webkit-left;text-align: -moz-left;">
<mn>2</mn>
</mtd>
</mtr>
</mtable>
</math>
29 changes: 29 additions & 0 deletions math-core/src/snapshots/math_core__tests__subarray.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: math-core/src/lib.rs
expression: "\\sum_{\\begin{subarray}{c} 0 \\le i \\le m\\\\ 0 < j < n \\end{subarray}}"
---
<math>
<munder>
<mo>∑</mo>
<mtable displaystyle="false" scriptlevel="1">
<mtr>
<mtd style="padding-top: 0;padding-bottom: 0;">
<mn>0</mn>
<mo>≤</mo>
<mi>i</mi>
<mo>≤</mo>
<mi>m</mi>
</mtd>
</mtr>
<mtr>
<mtd style="padding-top: 0;padding-bottom: 0;">
<mn>0</mn>
<mo>&lt;</mo>
<mi>j</mi>
<mo>&lt;</mo>
<mi>n</mi>
</mtd>
</mtr>
</mtable>
</munder>
</math>
41 changes: 24 additions & 17 deletions math-core/src/specifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,13 @@ pub fn parse_column_specification<'arena>(
arena: &'arena Arena,
) -> Option<ArraySpec<'arena>> {
let mut column_spec = Vec::new();
let mut begins_with_line = false;
let mut beginning_line: Option<LineType> = None;
let mut has_content_column = false;

// We will work with bytes to avoid UTF-8 checks.
// This is possible because we only match on ASCII characters.
for ch in s.as_bytes() {
let ch = *ch;
match ch {
b'l' | b'c' | b'r' => {
let alignment = match ch {
Expand All @@ -140,22 +141,27 @@ pub fn parse_column_specification<'arena>(
column_spec.push(ColumnSpec::WithContent(alignment, None));
has_content_column = true;
}
b'|' => {
b'|' | b':' => {
let line_type = match ch {
b'|' => LineType::Solid,
b':' => LineType::Dashed,
_ => unreachable!(),
};
if let Some(last) = column_spec.last_mut() {
// If the last column was a content column, we need to add a line type.
// If it is already set, we add a new element to the column spec vector.
if let ColumnSpec::WithContent(_, line_type @ None) = last {
*line_type = Some(LineType::Solid);
if let ColumnSpec::WithContent(_, last_line_type @ None) = last {
*last_line_type = Some(line_type);
} else {
column_spec.push(ColumnSpec::OnlyLine(LineType::Solid))
column_spec.push(ColumnSpec::OnlyLine(line_type))
}
} else {
// Nothing has been added yet, so this is the first column.
if begins_with_line {
// If `begins_with_line` is already true, we have a double line.
column_spec.push(ColumnSpec::OnlyLine(LineType::Solid))
if beginning_line.is_none() {
beginning_line = Some(line_type);
} else {
begins_with_line = true;
// If there already is a `beginning_line`, we have a double line.
column_spec.push(ColumnSpec::OnlyLine(line_type))
}
}
}
Expand All @@ -174,7 +180,8 @@ pub fn parse_column_specification<'arena>(
}

Some(ArraySpec {
begins_with_line,
beginning_line,
is_sub: false,
column_spec: arena.alloc_column_specs(column_spec.as_slice()),
})
}
Expand All @@ -201,7 +208,7 @@ mod tests {
fn column_parse_simple() {
let arena = Arena::new();
let spec = parse_column_specification("l|c|r", &arena).unwrap();
assert_eq!(spec.begins_with_line, false);
assert!(matches!(spec.beginning_line, None));
assert_eq!(spec.column_spec.len(), 3);
assert!(matches!(
spec.column_spec[0],
Expand All @@ -221,7 +228,7 @@ mod tests {
fn column_parse_line_at_beginning() {
let arena = Arena::new();
let spec = parse_column_specification("|ccc", &arena).unwrap();
assert_eq!(spec.begins_with_line, true);
assert!(matches!(spec.beginning_line, Some(LineType::Solid)));
assert_eq!(spec.column_spec.len(), 3);
assert!(matches!(
spec.column_spec[0],
Expand All @@ -241,7 +248,7 @@ mod tests {
fn column_parse_multiple_line_at_beginning() {
let arena = Arena::new();
let spec = parse_column_specification(" | ||c", &arena).unwrap();
assert_eq!(spec.begins_with_line, true);
assert!(matches!(spec.beginning_line, Some(LineType::Solid)));
assert_eq!(spec.column_spec.len(), 3);
assert!(matches!(
spec.column_spec[0],
Expand All @@ -260,12 +267,12 @@ mod tests {
#[test]
fn column_parse_with_spaces() {
let arena = Arena::new();
let spec = parse_column_specification(" c | | c| | | c ", &arena).unwrap();
assert_eq!(spec.begins_with_line, false);
let spec = parse_column_specification(" c : | c| : | c ", &arena).unwrap();
assert!(matches!(spec.beginning_line, None));
assert_eq!(spec.column_spec.len(), 6);
assert!(matches!(
spec.column_spec[0],
ColumnSpec::WithContent(ColumnAlignment::Centered, Some(LineType::Solid))
ColumnSpec::WithContent(ColumnAlignment::Centered, Some(LineType::Dashed))
));
assert!(matches!(
spec.column_spec[1],
Expand All @@ -277,7 +284,7 @@ mod tests {
));
assert!(matches!(
spec.column_spec[3],
ColumnSpec::OnlyLine(LineType::Solid)
ColumnSpec::OnlyLine(LineType::Dashed)
));
assert!(matches!(
spec.column_spec[4],
Expand Down
Loading
Loading