1use once_cell::unsync::OnceCell;
5use peg::{str::LineCol, Parse};
6use std::{
7 borrow::Cow,
8 error::Error,
9 fmt, mem,
10 num::NonZeroUsize,
11 ops::{Range, RangeInclusive},
12 str::FromStr,
13};
14use tex_parser::ast::{self, input_context::InputContext, GetPos};
15
16#[derive(Debug)]
17pub struct ParseError {
18 pub file_name: String,
19 pub line: usize,
20 pub column: usize,
21 pub byte_index: usize,
22 pub message: String,
23}
24
25impl fmt::Display for ParseError {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(
28 f,
29 "{}:{}:{}: error: {}",
30 self.file_name, self.line, self.column, self.message
31 )
32 }
33}
34
35impl Error for ParseError {}
36
37pub type Result<T, E = ParseError> = std::result::Result<T, E>;
38
39struct Parser<'a> {
40 file_name: &'a str,
41 input: &'a str,
42}
43
44macro_rules! err {
45 ($this:expr, $pos:expr, $($fmt_args:tt)+) => {
46 return Err($this.err_pos($pos, format!($($fmt_args)+)))
47 };
48}
49
50macro_rules! err_if {
51 ($cond:expr, $this:expr, $pos:expr, $($fmt_args:tt)+) => {
52 if $cond {
53 err!($this, $pos, $($fmt_args)+);
54 }
55 };
56}
57
58macro_rules! unwrap_or {
59 ($opt:expr, $($none:tt)+) => {
60 match $opt {
61 Some(v) => v,
62 None => { $($none)+ }
63 }
64 };
65}
66
67struct TableRowIterator<'input, 'rest> {
68 parser: &'rest Parser<'input>,
69 tabular_body: std::slice::Iter<'rest, ast::Token>,
70 pos_after_body: ast::Pos,
71 column_definitions: &'rest [ColumnDefinition],
72 column_ranges: Vec<ColumnRange>,
73 column_range: Option<ColumnRange>,
74 finished: bool,
75}
76
77impl GetPos for TableRowIterator<'_, '_> {
78 fn pos(&self) -> ast::Pos {
79 self.tabular_body
80 .clone()
81 .next()
82 .map_or(self.pos_after_body, GetPos::pos)
83 }
84}
85
86impl<'input, 'rest> TableRowIterator<'input, 'rest> {
87 fn new(
88 parser: &'rest Parser<'input>,
89 tabular_body: std::slice::Iter<'rest, ast::Token>,
90 pos_after_body: impl GetPos,
91 column_definitions: &'rest [ColumnDefinition],
92 ) -> Self {
93 Self {
94 parser,
95 tabular_body,
96 pos_after_body: pos_after_body.pos(),
97 column_definitions,
98 column_ranges: Vec::new(),
99 column_range: None,
100 finished: false,
101 }
102 }
103 fn column_end_index(&self) -> usize {
104 self.column_range
105 .as_ref()
106 .or(self.column_ranges.last())
107 .map_or(0, |c| c.indexes.end)
108 }
109 fn columns_left(&self) -> usize {
110 self.column_definitions.len() - self.column_end_index()
111 }
112 fn is_field_column(&self) -> bool {
113 self.columns_left() > 1
114 }
115 fn is_opcode_column(&self) -> bool {
116 self.columns_left() == 1
117 }
118 fn get_new_column_indexes(
119 &mut self,
120 new_column_width: usize,
121 pos: impl GetPos,
122 reason: impl FnOnce() -> String,
123 ) -> Result<Range<usize>> {
124 let start_index = self.column_end_index();
125 let cols_left = self.columns_left();
126 err_if!(
127 new_column_width > cols_left,
128 self.parser,
129 pos,
130 "{reason}: {cols_left} column(s) available out of {total} total",
131 reason = reason(),
132 cols_left = cols_left,
133 total = self.column_definitions.len()
134 );
135 let end_index = start_index + new_column_width;
136 Ok(start_index..end_index)
137 }
138 fn next_helper(&mut self) -> Result<Option<Vec<ColumnRange>>> {
139 if self.finished {
140 return Ok(None);
141 }
142 let mut columns = loop {
143 let mut tabular_body_temp = self.tabular_body.clone();
144 let token = unwrap_or!(tabular_body_temp.next(), {
145 self.column_ranges.extend(self.column_range.take());
146 self.finished = true;
147 if self.column_ranges.is_empty() {
148 return Ok(None);
149 }
150 break mem::replace(&mut self.column_ranges, Vec::new());
151 });
152 match token {
153 ast::Token::AlignmentTab(alignment_tab) => {
154 self.tabular_body = tabular_body_temp;
155 if let Some(column_range) = self.column_range.take() {
156 self.column_ranges.push(column_range);
157 } else {
158 let indexes = self.get_new_column_indexes(1, alignment_tab, || {
159 "this column would go past the table column count".into()
160 })?;
161 self.column_ranges.push(ColumnRange {
162 pos: alignment_tab.pos(),
163 indexes,
164 multi_column: None,
165 body: None,
166 })
167 }
168 }
169 ast::Token::Macro(macro_) if macro_.name.content == "\\" => {
170 self.tabular_body = tabular_body_temp;
171 self.column_ranges.extend(self.column_range.take());
172 break mem::replace(&mut self.column_ranges, Vec::new());
173 }
174 ast::Token::Macro(m) if m.name.content == "multicolumn" => {
175 self.tabular_body = tabular_body_temp;
176 err_if!(
177 self.column_range.is_some(),
178 self.parser,
179 m,
180 "`\\multicolumn` must be first thing in its column"
181 );
182 let (num_cols, num_cols_pos): (NonZeroUsize, _) =
183 self.parser.parse_number_in_group(
184 self.pos_after_body,
185 self.tabular_body.next().map(Cow::Borrowed),
186 || "expected `{{<number>}}` (like `{{12}}`)".into(),
187 )?;
188 let indexes =
189 self.get_new_column_indexes(num_cols.get(), num_cols_pos, || {
190 format!(
191 "`\\multicolumn{{{}}}` would go past the table column count",
192 num_cols
193 )
194 })?;
195 let cols_group = self.parser.unwrap_group_or_error(
196 self.pos_after_body,
197 self.tabular_body.next().map(Cow::Borrowed),
198 )?;
199 let mut multi_column = MultiColumn {
200 pos: cols_group.tokens_pos(),
201 kind: MultiColumnKind::Center,
202 vertical_bar_on_left: false,
203 vertical_bar_on_right: false,
204 };
205 let mut cols_group_str = match &*cols_group.tokens {
206 [ast::Token::CharTokens(char_tokens)] => &*char_tokens.content,
207 _ => err!(
208 self.parser,
209 cols_group.tokens_pos(),
210 "invalid `\\multicolumn` cols group"
211 ),
212 };
213 if let Some(rest) = cols_group_str.strip_prefix("|") {
214 cols_group_str = rest;
215 multi_column.vertical_bar_on_left = true;
216 }
217 if let Some(rest) = cols_group_str.strip_suffix("|") {
218 cols_group_str = rest;
219 multi_column.vertical_bar_on_right = true;
220 }
221 multi_column.kind = unwrap_or!(
222 MultiColumnKind::from_str(cols_group_str),
223 err!(
224 self.parser,
225 cols_group.tokens_pos(),
226 "invalid `\\multicolumn` cols group"
227 )
228 );
229 let body = self.parser.unwrap_group_or_error(
230 self.pos_after_body,
231 self.tabular_body.next().map(Cow::Borrowed),
232 )?;
233 self.parser
234 .skip_rest_of_column_body_else_error(&mut self.tabular_body, true)?;
235 let mut body_iter = body.tokens.iter();
236 let body = self.parser.parse_column_body(
237 &mut body_iter,
238 &body.end,
239 self.column_definitions,
240 false,
241 self.is_field_column(),
242 self.is_opcode_column(),
243 )?;
244 self.parser
245 .skip_rest_of_column_body_else_error(&mut body_iter, false)?;
246 self.column_range = Some(ColumnRange {
247 pos: m.pos(),
248 indexes,
249 multi_column: Some(multi_column),
250 body,
251 });
252 }
253 token if Parser::is_column_body_ignored(token) => {
254 self.tabular_body = tabular_body_temp;
255 }
256 token => {
257 assert!(self.column_range.is_none(), "token={:?}", token);
258 let is_field_column = self.is_field_column();
259 let is_opcode_column = self.is_opcode_column();
260 let body = self.parser.parse_column_body(
261 &mut self.tabular_body,
262 self.pos_after_body,
263 self.column_definitions,
264 true,
265 is_field_column,
266 is_opcode_column,
267 )?;
268 if body.is_none() {
269 continue;
270 }
271 let indexes = self.get_new_column_indexes(1, token, || {
272 "this column would go past the table column count".into()
273 })?;
274 self.parser
275 .skip_rest_of_column_body_else_error(&mut self.tabular_body, true)?;
276 self.column_range = Some(ColumnRange {
277 pos: token.pos(),
278 indexes,
279 multi_column: None,
280 body: body,
281 });
282 }
283 }
284 };
285 columns.reverse();
286 for column in &mut columns {
287 let rev_start = self.column_definitions.len() - column.indexes.end;
288 let rev_end = self.column_definitions.len() - column.indexes.start;
289 column.indexes = rev_start..rev_end;
290 }
291 Ok(Some(columns))
292 }
293 fn peekable(self) -> PeekableTableRowIterator<'input, 'rest> {
294 PeekableTableRowIterator {
295 iter: self,
296 peek_value: None,
297 }
298 }
299}
300
301impl<'input, 'rest> Iterator for TableRowIterator<'input, 'rest> {
302 type Item = Result<Vec<ColumnRange>>;
303
304 fn next(&mut self) -> Option<Self::Item> {
305 let retval = self.next_helper();
306 if retval.is_err() {
307 self.finished = true;
308 }
309 retval.transpose()
310 }
311}
312
313struct PeekableTableRowIterator<'input, 'rest> {
314 iter: TableRowIterator<'input, 'rest>,
315 peek_value: Option<Vec<ColumnRange>>,
316}
317
318impl GetPos for PeekableTableRowIterator<'_, '_> {
319 fn pos(&self) -> ast::Pos {
320 self.peek_value
321 .as_ref()
322 .and_then(|v| v.first())
323 .map_or_else(|| self.iter.pos(), |v| v.pos)
324 }
325}
326
327impl<'input, 'rest> PeekableTableRowIterator<'input, 'rest> {
328 fn peek(&mut self) -> Option<Result<&[ColumnRange]>> {
329 if self.peek_value.is_none() {
330 match self.iter.next()? {
331 Ok(value) => {
332 self.peek_value = Some(value);
333 }
334 Err(e) => return Some(Err(e)),
335 }
336 }
337 Some(Ok(self.peek_value.as_ref().unwrap()))
338 }
339}
340
341impl<'input, 'rest> Iterator for PeekableTableRowIterator<'input, 'rest> {
342 type Item = Result<Vec<ColumnRange>>;
343
344 fn next(&mut self) -> Option<Self::Item> {
345 if let Some(peek_value) = self.peek_value.take() {
346 return Some(Ok(peek_value));
347 }
348 self.iter.next()
349 }
350}
351
352impl<'input> Parser<'input> {
353 const COLUMN_START_PADDING: usize = 1;
354 const COLUMN_END_PADDING: usize = 1;
355 fn new(file_name: &'input str, input: &'input str) -> Self {
356 Self { file_name, input }
357 }
358 fn err_line_col(&self, line_col: LineCol, message: String) -> ParseError {
359 ParseError {
360 file_name: self.file_name.into(),
361 line: line_col.line,
362 column: line_col.column,
363 byte_index: line_col.offset,
364 message,
365 }
366 }
367 fn err_pos(&self, pos: impl GetPos, message: String) -> ParseError {
368 self.err_line_col(self.input.position_repr(pos.pos().byte_index), message)
369 }
370 fn expect_environment<'env>(
371 &self,
372 environment: &'env ast::Environment,
373 name: &str,
374 ) -> Result<&'env ast::Environment> {
375 if environment.name.content == name {
376 Ok(environment)
377 } else {
378 err!(self, environment, "expected `\\begin{{{}}}`", name);
379 }
380 }
381 fn unwrap_group_or_error<'t>(
382 &self,
383 pos_if_token_is_none: impl GetPos,
384 token: Option<Cow<'t, ast::Token>>,
385 ) -> Result<Cow<'t, ast::Group>> {
386 let token_pos = token.as_ref().map(|t| t.pos());
387 let group = token.and_then(|t| match t {
388 Cow::Borrowed(t) => t.group().map(Cow::Borrowed),
389 Cow::Owned(t) => t.into_group().map(Cow::Owned),
390 });
391 Ok(unwrap_or!(
392 group,
393 err!(
394 self,
395 token_pos.unwrap_or(pos_if_token_is_none.pos()),
396 "expected `{{`"
397 )
398 ))
399 }
400 fn parse_number_in_group<T: FromStr>(
401 &self,
402 pos_if_token_is_none: impl GetPos,
403 token: Option<Cow<'_, ast::Token>>,
404 error_message: impl FnOnce() -> String,
405 ) -> Result<(T, ast::Pos)>
406 where
407 T::Err: fmt::Display,
408 {
409 let num_cols_group = self.unwrap_group_or_error(pos_if_token_is_none, token)?;
410 match &*num_cols_group.tokens {
411 [ast::Token::Number(num_cols)] => Ok((
412 num_cols.parse_with_err_arg(self, Parser::err_pos)?,
413 num_cols.pos,
414 )),
415 _ => Err(self.err_pos(&*num_cols_group, error_message())),
416 }
417 }
418 fn parse_tabular_column_definitions(
419 &self,
420 columns_group: &ast::Group,
421 ) -> Result<Vec<ColumnDefinition>> {
422 let mut tokens = ast::SplitCharTokensIter::new(&columns_group.tokens).peekable();
423 let mut retval = Vec::new();
424 loop {
425 let kind = match unwrap_or!(tokens.next().as_deref(), break) {
426 ast::Token::CharTokens(c) if c.content == "l" => {
427 ColumnKind::LeftJustified { keyword_pos: c.pos }
428 }
429 ast::Token::CharTokens(c) if c.content == "p" => {
430 let width = self
431 .unwrap_group_or_error(&columns_group.end, tokens.next())?
432 .into_owned();
433 ColumnKind::ParagraphTop {
434 keyword_pos: c.pos,
435 width,
436 }
437 }
438 token => err!(self, token, "expected `tabular` column definition"),
439 };
440 retval.push(ColumnDefinition {
441 kind,
442 merged_def: OnceCell::new(),
443 });
444 }
445 err_if!(
446 retval.len() < 2,
447 self,
448 columns_group,
449 "there must be at least 2 columns"
450 );
451 retval.reverse();
452 Ok(retval)
453 }
454 fn skip_rest_if_matches_else_error<'a, I: Iterator<Item = &'a ast::Token> + Clone>(
455 &self,
456 tokens: &mut I,
457 mut matches: impl FnMut(&'a ast::Token) -> bool,
458 mut is_terminator: impl FnMut(&'a ast::Token) -> bool,
459 error_message: impl FnOnce(&'a ast::Token) -> String,
460 ) -> Result<()> {
461 loop {
462 let mut temp_tokens = tokens.clone();
463 let token = unwrap_or!(temp_tokens.next(), break Ok(()));
464 if is_terminator(token) {
465 break Ok(());
466 } else if !matches(token) {
467 return Err(self.err_pos(token, error_message(token)));
468 }
469 *tokens = temp_tokens;
470 }
471 }
472 fn is_column_body_ignored(token: &ast::Token) -> bool {
473 match token {
474 ast::Token::Whitespace(_) | ast::Token::ParBreak(_) => true,
475 _ => false,
476 }
477 }
478 fn is_column_body_terminator(token: &ast::Token, is_top_level: bool) -> bool {
479 match token {
480 ast::Token::AlignmentTab(_) => is_top_level,
481 ast::Token::Macro(m) if m.name.content == "\\" => is_top_level,
482 _ => false,
483 }
484 }
485 fn is_column_body_text(token: &ast::Token) -> bool {
486 match token {
487 ast::Token::CharTokens(_)
488 | ast::Token::Group(_)
489 | ast::Token::Whitespace(_)
490 | ast::Token::Number(_) => true,
491 ast::Token::Punctuation(ast::Punctuation { pos: _, ch }) if matches!(ch, '-' | '.') => {
492 true
493 }
494 _ => false,
495 }
496 }
497 fn is_column_body_bold_text(token: &ast::Token) -> bool {
498 match token {
499 ast::Token::CharTokens(_) => true,
500 ast::Token::Punctuation(_) => true,
501 ast::Token::Whitespace(_) => true,
502 ast::Token::Macro(_) => true,
503 ast::Token::Group(_) => true,
504 _ => false,
505 }
506 }
507 fn skip_rest_of_column_body_else_error<'a>(
508 &self,
509 tokens: &mut std::slice::Iter<ast::Token>,
510 is_top_level: bool,
511 ) -> Result<()> {
512 self.skip_rest_if_matches_else_error(
513 tokens,
514 Self::is_column_body_ignored,
515 |token| Self::is_column_body_terminator(token, is_top_level),
516 |token| format!("unexpected token: {:?}", token),
517 )
518 }
519 fn is_register_macro(macro_: &ast::Macro) -> bool {
520 matches!(
521 &*macro_.name.content,
522 "rdprime" | "rsoneprime" | "rstwoprime"
523 )
524 }
525 fn parse_field_def_name(
526 &self,
527 first_token: Option<&ast::Token>,
528 tabular_body: &mut std::slice::Iter<ast::Token>,
529 pos_after_body: impl GetPos,
530 ) -> Result<FieldDefName> {
531 let token = unwrap_or!(
532 first_token.or_else(|| tabular_body.next()),
533 err!(self, pos_after_body, "expected field name")
534 );
535 match token {
536 ast::Token::Macro(macro_) if Self::is_register_macro(macro_) => {
537 Ok(FieldDefName::Macro(macro_.name.clone()))
538 }
539 ast::Token::CharTokens(char_tokens) => {
540 Ok(FieldDefName::CharTokens(char_tokens.clone()))
541 }
542 _ => err!(self, token, "expected field name"),
543 }
544 }
545 fn match_token_or_error<'a, T: GetPos>(
546 &self,
547 matches: impl FnOnce(&T) -> bool,
548 tabular_body: &mut std::slice::Iter<'a, T>,
549 pos_after_body: impl GetPos,
550 error_message: impl FnOnce() -> String,
551 ) -> Result<&'a T> {
552 let pos = match tabular_body.next() {
553 Some(token) if matches(token) => return Ok(token),
554 Some(token) => token.pos(),
555 None => pos_after_body.pos(),
556 };
557 Err(self.err_pos(pos, error_message()))
558 }
559 fn parse_field_def_slice(
560 &self,
561 name: FieldDefName,
562 tabular_body: &mut std::slice::Iter<ast::Token>,
563 pos_after_body: impl GetPos,
564 ) -> Result<FieldDefSlice> {
565 self.match_token_or_error(
566 |t| {
567 matches!(
568 t,
569 ast::Token::Punctuation(ast::Punctuation { pos: _, ch: '[' })
570 )
571 },
572 tabular_body,
573 &pos_after_body,
574 || "expected `[`".into(),
575 )?;
576 let mut bit_ranges = Vec::new();
577 loop {
578 let (end, end_bit_pos): (u32, _) = match tabular_body.next() {
579 Some(ast::Token::Number(num)) => {
580 (num.parse_with_err_arg(self, Self::err_pos)?, num.pos())
581 }
582 token => err!(
583 self,
584 token.map_or(pos_after_body.pos(), GetPos::pos),
585 "expected number"
586 ),
587 };
588 if let Some(ast::Token::Punctuation(ast::Punctuation { pos: _, ch: ':' })) =
589 tabular_body.clone().next()
590 {
591 tabular_body.next();
592 let (start, start_bit_pos): (u32, _) = match tabular_body.next() {
593 Some(ast::Token::Number(num)) => {
594 (num.parse_with_err_arg(self, Self::err_pos)?, num.pos())
595 }
596 token => err!(
597 self,
598 token.map_or(pos_after_body.pos(), GetPos::pos),
599 "expected number"
600 ),
601 };
602 err_if!(
603 end < start,
604 self,
605 end_bit_pos,
606 "range end ({}) must not be less than range start ({})",
607 end,
608 start
609 );
610 bit_ranges.push(FieldBitRange {
611 bits: start..=end,
612 end_bit_pos,
613 start_bit_pos: Some(start_bit_pos),
614 });
615 } else {
616 bit_ranges.push(FieldBitRange {
617 bits: end..=end,
618 end_bit_pos,
619 start_bit_pos: None,
620 });
621 }
622 match unwrap_or!(
623 tabular_body.next(),
624 err!(self, pos_after_body, "missing `]`")
625 ) {
626 ast::Token::Punctuation(ast::Punctuation { pos: _, ch: ']' }) => {
627 break;
628 }
629 ast::Token::DollarInlineMath(ast::DollarInlineMath {
630 begin,
631 content,
632 end: _,
633 }) => match &**content {
634 [ast::MathToken::Macro(ast::Macro { escape: _, name })]
635 if name.content == "vert" =>
636 {
637 continue;
638 }
639 _ => err!(self, begin, "expected `$\\vert$`"),
640 },
641 token => err!(self, token, "expected `$\\vert$` or `]`"),
642 }
643 }
644 Ok(FieldDefSlice { name, bit_ranges })
645 }
646 fn parse_field_def_alternate(
647 &self,
648 field_def_name: FieldDefName,
649 tabular_body: &mut std::slice::Iter<ast::Token>,
650 pos_after_body: impl GetPos,
651 ) -> Result<FieldDefAlternate> {
652 let mut names = vec![field_def_name];
653 while let Some(ast::Token::Punctuation(ast::Punctuation { pos: _, ch: '/' })) =
654 tabular_body.clone().next()
655 {
656 tabular_body.next();
657 names.push(self.parse_field_def_name(None, tabular_body, &pos_after_body)?);
658 }
659 Ok(FieldDefAlternate { names })
660 }
661 fn parse_field_def(
662 &self,
663 first_token: &ast::Token,
664 tabular_body: &mut std::slice::Iter<ast::Token>,
665 pos_after_body: impl GetPos,
666 ) -> Result<FieldDef> {
667 match first_token {
668 ast::Token::Number(num) => {
669 return Ok(FieldDef {
670 body: FieldDefBody::LiteralNumber(num.clone()),
671 excluded_values: Vec::new(),
672 });
673 }
674 ast::Token::Punctuation(p) if p.ch == '-' => {
675 let first_token = first_token.punctuation().unwrap();
676 let mut content = String::from(first_token.ch);
677 for _ in 1..3 {
678 let token = self
679 .match_token_or_error(
680 |t| matches!(t, ast::Token::Punctuation(p) if p.ch == '-'),
681 tabular_body,
682 &pos_after_body,
683 || "expected: `-`".into(),
684 )?
685 .punctuation()
686 .unwrap();
687 content.push(token.ch);
688 }
689 return Ok(FieldDef {
690 body: FieldDefBody::Wildcard(Wildcard {
691 pos: first_token.pos(),
692 content,
693 }),
694 excluded_values: Vec::new(),
695 });
696 }
697 _ => {}
698 }
699 let field_def_name =
700 self.parse_field_def_name(Some(first_token), tabular_body, &pos_after_body)?;
701 let body = match tabular_body.clone().next() {
702 Some(ast::Token::Punctuation(ast::Punctuation { pos: _, ch: '[' })) => {
703 FieldDefBody::Slice(self.parse_field_def_slice(
704 field_def_name,
705 tabular_body,
706 &pos_after_body,
707 )?)
708 }
709 _ => FieldDefBody::Alternate(self.parse_field_def_alternate(
710 field_def_name,
711 tabular_body,
712 &pos_after_body,
713 )?),
714 };
715 let excluded_values = match tabular_body
716 .clone()
717 .next()
718 .and_then(ast::Token::dollar_inline_math)
719 .map(|v| &*v.content)
720 {
721 Some([ast::MathToken::Macro(macro_)]) if macro_.name.content == "neq" => {
722 tabular_body.next();
723 match tabular_body.next() {
724 Some(ast::Token::Number(num)) => vec![num.clone()],
725 Some(ast::Token::DollarInlineMath(dollar_inline_math)) => {
726 let mut dollar_inline_math_body = dollar_inline_math.content.iter();
727 self.match_token_or_error(
728 |t| matches!(t, ast::MathToken::Macro(m) if m.name.content == "{"),
729 &mut dollar_inline_math_body,
730 &dollar_inline_math.end,
731 || "expected `\\{{`".into(),
732 )?;
733 let mut excluded_values = match dollar_inline_math_body.next() {
734 Some(ast::MathToken::Number(num)) => vec![num.clone()],
735 _ => err!(self, dollar_inline_math.content_pos(), "expected number"),
736 };
737 while let Some(token) = dollar_inline_math_body.next() {
738 if matches!(token, ast::MathToken::Macro(m) if m.name.content == "}") {
739 if let Some(token) = dollar_inline_math_body.next() {
740 err!(self, token, "unexpected token");
741 }
742 break;
743 }
744 err_if!(
745 !matches!(
746 token,
747 ast::MathToken::AnyChar(ast::AnyChar { pos: _, ch: ',' })
748 ),
749 self,
750 token,
751 "expected `,` or `\\}}`"
752 );
753 match dollar_inline_math_body.next() {
754 Some(ast::MathToken::Number(num)) => {
755 excluded_values.push(num.clone())
756 }
757 Some(token) => {
758 err!(self, token, "expected number")
759 }
760 None => {
761 err!(self, dollar_inline_math.end.pos(), "expected number")
762 }
763 }
764 }
765 excluded_values
766 }
767 token => err!(self,
768 token.map_or_else(||pos_after_body.pos(), GetPos::pos),
769 "expected number or list of numbers (like so: `$\\{{<num>[,<num>[,<num>[...]]]\\}}$`)"
770 ),
771 }
772 }
773 _ => Vec::new(),
774 };
775 Ok(FieldDef {
776 body,
777 excluded_values,
778 })
779 }
780 fn parse_opcode_name(
781 &self,
782 first_token: &ast::Token,
783 tabular_body: &mut std::slice::Iter<ast::Token>,
784 is_top_level: bool,
785 ) -> Result<OpcodeName> {
786 let pos = first_token.pos();
787 let mut first_token = Some(first_token);
788 let mut name = None;
789 let mut group = None;
790 while let Some(token) = first_token.or_else(|| tabular_body.clone().next()) {
791 if Self::is_column_body_terminator(token, is_top_level) {
792 assert!(first_token.is_none());
793 break;
794 }
795 if first_token.take().is_none() {
796 tabular_body.next();
797 }
798 match token {
799 ast::Token::CharTokens(char_tokens) => name
800 .get_or_insert(String::new())
801 .push_str(&char_tokens.content),
802 ast::Token::Punctuation(p) => {
803 name.get_or_insert(String::new()).push(p.ch);
804 }
805 ast::Token::Group(_) | ast::Token::Whitespace(_) => break,
806 _ => err!(self, token, "expected `{{`"),
807 }
808 }
809 while let Some(token) = tabular_body.clone().next() {
810 if Self::is_column_body_terminator(token, is_top_level) {
811 break;
812 }
813 tabular_body.next();
814 match token {
815 ast::Token::Whitespace(_) => {}
816 ast::Token::Group(g) => {
817 group = Some(g.clone());
818 break;
819 }
820 _ => err!(self, token, "expected: `{{`"),
821 }
822 }
823 Ok(OpcodeName {
824 pos,
825 name: unwrap_or!(name, err!(self, pos, "expected: opcode name")),
826 group,
827 })
828 }
829 fn parse_column_body(
830 &self,
831 tabular_body: &mut std::slice::Iter<ast::Token>,
832 pos_after_body: impl GetPos,
833 column_definitions: &[ColumnDefinition],
834 is_top_level: bool,
835 is_field_column: bool,
836 is_opcode_column: bool,
837 ) -> Result<Option<ColumnBody>> {
838 loop {
839 let token = unwrap_or!(tabular_body.clone().next(), return Ok(None));
840 if Self::is_column_body_terminator(token, is_top_level) {
841 return Ok(None);
842 }
843 tabular_body.next();
844 if Self::is_column_body_ignored(token) {
845 continue;
846 }
847 return Ok(Some(match token {
848 ast::Token::Macro(macro_)
849 if matches!(&*macro_.name.content, "cline" | "whline") && is_top_level =>
850 {
851 self.unwrap_group_or_error(
852 &pos_after_body,
853 tabular_body.next().map(Cow::Borrowed),
854 )?;
855 continue;
856 }
857 ast::Token::Macro(macro_) if Self::is_register_macro(macro_) => {
858 let field_def = self.parse_field_def(token, tabular_body, pos_after_body)?;
859 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
860 ColumnBody::FieldDef(field_def)
861 }
862 ast::Token::Macro(macro_) if macro_.name.content == "instbit" => {
863 let (bit, pos) = self.parse_number_in_group(
864 pos_after_body,
865 tabular_body.next().map(Cow::Borrowed),
866 || "expected `{{<bit-number>}}` (like `{{12}}`)".into(),
867 )?;
868 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
869 ColumnBody::InstBit(InstBit { pos, bit })
870 }
871 ast::Token::Macro(macro_) if macro_.name.content == "instbitrange" => {
872 let (end_bit, end_bit_pos) = self.parse_number_in_group(
873 &pos_after_body,
874 tabular_body.next().map(Cow::Borrowed),
875 || "expected `{{<start-bit-number>}}` (like `{{12}}`)".into(),
876 )?;
877 let (start_bit, start_bit_pos) = self.parse_number_in_group(
878 pos_after_body,
879 tabular_body.next().map(Cow::Borrowed),
880 || "expected `{{<end-bit-number>}}` (like `{{12}}`)".into(),
881 )?;
882 err_if!(
883 start_bit > end_bit,
884 self,
885 start_bit_pos,
886 "start bit must not be bigger than end bit"
887 );
888 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
889 ColumnBody::InstBitRange(InstBitRange {
890 bits: start_bit..=end_bit,
891 end_bit_pos,
892 start_bit_pos,
893 })
894 }
895 ast::Token::Macro(macro_) if macro_.name.content == "bf" => {
896 let mut tokens: Vec<ast::Token> = vec![token.clone()];
897 while let Some(token) = tabular_body
898 .clone()
899 .next()
900 .filter(|token| Self::is_column_body_bold_text(token))
901 {
902 tabular_body.next();
903 tokens.push(token.clone());
904 }
905 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
906 ColumnBody::ColumnBodyBoldText(ColumnBodyBoldText {
907 pos: tokens[0].pos(),
908 tokens,
909 })
910 }
911 ast::Token::Group(g) => {
912 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
913 ColumnBody::Group(g.clone())
914 }
915 _ if Self::is_column_body_text(token) => {
916 if is_field_column {
917 let field_def =
918 self.parse_field_def(token, tabular_body, pos_after_body)?;
919 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
920 return Ok(Some(ColumnBody::FieldDef(field_def)));
921 } else if is_opcode_column {
922 let opcode_name =
923 self.parse_opcode_name(token, tabular_body, is_top_level)?;
924 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
925 return Ok(Some(ColumnBody::OpcodeName(opcode_name)));
926 }
927 let mut tokens: Vec<ast::Token> = vec![token.clone()];
928 while let Some(token) = tabular_body
929 .clone()
930 .next()
931 .filter(|token| Self::is_column_body_text(token))
932 {
933 tabular_body.next();
934 tokens.push(token.clone());
935 }
936 self.skip_rest_of_column_body_else_error(tabular_body, is_top_level)?;
937 ColumnBody::ColumnBodyText(ColumnBodyText {
938 pos: tokens[0].pos(),
939 tokens,
940 })
941 }
942 _ => err!(self, token, "unexpected token"),
943 }));
944 }
945 }
946 fn assert_column_is_empty(&self, column: &ColumnRange) -> Result<()> {
947 err_if!(
948 column.multi_column.is_some(),
949 self,
950 column.pos,
951 "`\\multicolumn` is not allowed here"
952 );
953 err_if!(
954 column.body.is_some(),
955 self,
956 column.pos,
957 "column must be empty here"
958 );
959 Ok(())
960 }
961 fn parse_blank_row(&self, row_iterator: &mut PeekableTableRowIterator) -> Result<()> {
962 let pos = row_iterator.pos();
963 let columns = unwrap_or!(row_iterator.next(), err!(self, pos, "expected: blank row"))?;
964 for column in columns.iter().rev() {
965 self.assert_column_is_empty(column)?;
966 }
967 Ok(())
968 }
969 fn parse_instruction_bit_ranges_row(
970 &self,
971 row_iterator: &mut PeekableTableRowIterator,
972 column_definitions: &[ColumnDefinition],
973 ) -> Result<()> {
974 let pos = row_iterator.pos();
975 let columns = unwrap_or!(
976 row_iterator.next(),
977 err!(self, pos, "expected: instruction bit ranges row")
978 )?;
979 err_if!(
980 columns.is_empty(),
981 self,
982 columns.last().map_or(pos, |v| v.pos),
983 "not enough columns in instruction bit ranges row"
984 );
985 let (last_column, columns) = columns.split_last().unwrap();
986 self.assert_column_is_empty(last_column)?;
987 for column_range in columns {
988 err_if!(
989 column_range.indexes.len() != 1,
990 self,
991 column_range.pos,
992 "spanning multiple columns using `\\multicolumn{{{}}}` is not allowed in instruction bit ranges row",
993 column_range.indexes.len()
994 );
995 err_if!(
996 column_range.body.is_none(),
997 self,
998 column_range.pos,
999 "empty columns are not allowed in instruction bit ranges row"
1000 );
1001 }
1002 err_if!(
1003 columns.len()
1004 != column_definitions.len() - Self::COLUMN_START_PADDING - Self::COLUMN_END_PADDING,
1005 self,
1006 columns.last().map_or(pos, |v| v.pos),
1007 "not enough columns in instruction bit ranges row"
1008 );
1009 let mut last_range_end = None;
1010 let mut index = 0;
1011 while index < columns.len() {
1012 let mut column_range = index..index + 1;
1013 let column = &columns[index];
1014 let bit_range = match (
1015 column.body.as_ref().unwrap(),
1016 column.multi_column.as_ref().map(|v| v.kind),
1017 ) {
1018 (ColumnBody::InstBit(v), None)
1019 | (ColumnBody::InstBit(v), Some(MultiColumnKind::Center)) => v.clone().into(),
1020 (ColumnBody::InstBitRange(v), None) => v.clone(),
1021 (ColumnBody::InstBit(right), Some(MultiColumnKind::Right)) => {
1022 err_if!(
1023 index + 1 >= columns.len(),
1024 self,
1025 column.pos,
1026 "`\\multicolumn{{1}}{{r}}` is not valid here: this is the first column",
1028 );
1029 column_range = index..index + 2;
1030 let left_column = &columns[index + 1];
1031 err_if!(
1032 Some(MultiColumnKind::Left)
1033 != left_column.multi_column.as_ref().map(|v| v.kind),
1034 self,
1035 left_column.pos,
1036 "expected: `\\multicolumn{{1}}{{l}}`",
1037 );
1038 if let ColumnBody::InstBit(left) = left_column.body.as_ref().unwrap() {
1039 InstBitRange {
1040 bits: right.bit..=left.bit,
1041 end_bit_pos: left.pos,
1042 start_bit_pos: right.pos,
1043 }
1044 } else {
1045 err!(
1046 self,
1047 left_column.body.as_ref().unwrap().pos(),
1048 "expected: `\\instbit`"
1049 )
1050 }
1051 }
1052 _ => err!(
1053 self,
1054 column.body.as_ref().unwrap().pos(),
1055 "expected `\\instbit` or `\\instbitrange`"
1056 ),
1057 };
1058 if let Some((last_range_end, last_range_end_pos)) = mem::replace(
1059 &mut last_range_end,
1060 Some((*bit_range.bits.end(), bit_range.end_bit_pos)),
1061 ) {
1062 let next_bit_index = unwrap_or!(
1063 last_range_end.checked_add(1),
1064 err!(self, last_range_end_pos, "number too big")
1065 );
1066 err_if!(
1067 *bit_range.bits.start() != next_bit_index,
1068 self,
1069 bit_range.start_bit_pos,
1070 "expected {}",
1071 next_bit_index
1072 );
1073 } else {
1074 err_if!(
1075 *bit_range.bits.start() != 0,
1076 self,
1077 bit_range.start_bit_pos,
1078 "expected 0"
1079 );
1080 }
1081 let mut padded_column_range = column_range.clone();
1082 padded_column_range.start += Self::COLUMN_START_PADDING;
1083 padded_column_range.end += Self::COLUMN_START_PADDING;
1084 let merged_def = MergedColumnDefinition {
1085 column_range: padded_column_range.clone(),
1086 bit_range,
1087 };
1088 for c in &column_definitions[padded_column_range.clone()] {
1089 c.merged_def.set(merged_def.clone()).ok().unwrap();
1090 }
1091 index = column_range.end;
1092 }
1093 Ok(())
1094 }
1095 fn parse_instruction_field(
1096 &self,
1097 column: ColumnRange,
1098 column_definitions: &[ColumnDefinition],
1099 is_fence_instruction_form: bool,
1100 ) -> Result<InstructionField> {
1101 let field_def = match column.body {
1102 Some(ColumnBody::FieldDef(field_def)) => field_def,
1103 _ => err!(self, column.pos, "expected: instruction field"),
1104 };
1105 let field_matches_name_or_num = |name: &str, num_len: usize| -> bool {
1106 field_def.only_char_tokens().map(|v| &*v.content) == Some(name)
1107 || matches!(&field_def.body, FieldDefBody::LiteralNumber(num) if num.content.len() == num_len)
1108 };
1109 if is_fence_instruction_form {
1110 let bits = match column.indexes {
1111 Range { start: 5, end: 6 } => {
1112 err_if!(
1113 !field_matches_name_or_num("succ", 4),
1114 self,
1115 column.pos,
1116 "expected fence instruction's `succ` field"
1117 );
1118 Some(20..=23)
1119 }
1120 Range { start: 6, end: 9 } => {
1121 err_if!(
1122 !field_matches_name_or_num("pred", 4),
1123 self,
1124 column.pos,
1125 "expected fence instruction's `pred` field"
1126 );
1127 Some(24..=27)
1128 }
1129 _ => None,
1130 };
1131 if let Some(bits) = bits {
1132 return Ok(InstructionField {
1133 field_def,
1134 instruction_bit_range: InstBitRange {
1135 bits,
1136 end_bit_pos: column.pos,
1137 start_bit_pos: column.pos,
1138 },
1139 });
1140 }
1141 }
1142 let column_pos = column.pos;
1143 let mismatch_err = || {
1144 self.err_pos(
1145 column_pos,
1146 "instruction field doesn't match up with instruction-bit-numbers row".into(),
1147 )
1148 };
1149 let start_column_definition = unwrap_or!(
1150 column_definitions[column.indexes.start].merged_def.get(),
1151 return Err(mismatch_err());
1152 );
1153 if start_column_definition.column_range.start != column.indexes.start {
1154 return Err(mismatch_err());
1155 }
1156 let last_column_definition = unwrap_or!(
1157 column_definitions[column.indexes.clone().last().unwrap()].merged_def.get(),
1158 return Err(mismatch_err());
1159 );
1160 if last_column_definition.column_range.end != column.indexes.end {
1161 return Err(mismatch_err());
1162 }
1163 let instruction_bit_range = InstBitRange {
1164 bits: *start_column_definition.bit_range.bits.start()
1165 ..=*last_column_definition.bit_range.bits.end(),
1166 end_bit_pos: last_column_definition.bit_range.end_bit_pos,
1167 start_bit_pos: start_column_definition.bit_range.start_bit_pos,
1168 };
1169 Ok(InstructionField {
1170 instruction_bit_range,
1171 field_def,
1172 })
1173 }
1174 fn parse_instruction_fields(
1175 &self,
1176 row: Vec<ColumnRange>,
1177 column_definitions: &[ColumnDefinition],
1178 is_fence_instruction_form: bool,
1179 ) -> Result<Vec<InstructionField>> {
1180 let first = row.first().expect("row already checked to be non-empty");
1181 err_if!(
1182 first.indexes.len() != Self::COLUMN_START_PADDING,
1183 self,
1184 first.pos,
1185 "spanning multiple columns using `\\multicolumn{{{}}}` is not allowed here",
1186 first.indexes.len()
1187 );
1188 let last = row.last().expect("row already checked to be non-empty");
1189 err_if!(
1190 last.indexes.len() != Self::COLUMN_END_PADDING,
1191 self,
1192 last.pos,
1193 "spanning multiple columns using `\\multicolumn{{{}}}` is not allowed here",
1194 last.indexes.len()
1195 );
1196 err_if!(
1197 row.len() < Self::COLUMN_START_PADDING + Self::COLUMN_END_PADDING,
1198 self,
1199 last.pos,
1200 "row doesn't have enough columns"
1201 );
1202 let row_len = row.len();
1203 let fields = row
1204 .into_iter()
1205 .take(row_len - Self::COLUMN_END_PADDING)
1206 .skip(Self::COLUMN_START_PADDING)
1207 .map(|column| {
1208 self.parse_instruction_field(column, column_definitions, is_fence_instruction_form)
1209 })
1210 .collect::<Result<_>>()?;
1211 Ok(fields)
1212 }
1213 fn parse_instruction_form_rows(
1214 &self,
1215 row_iterator: &mut PeekableTableRowIterator,
1216 column_definitions: &[ColumnDefinition],
1217 ) -> Result<Vec<InstructionForm>> {
1218 let mut instruction_forms = Vec::new();
1219 while let Some(row) = row_iterator.peek().transpose()? {
1220 let name = match row.first() {
1221 Some(ColumnRange {
1222 body: Some(ColumnBody::OpcodeName(name)),
1223 ..
1224 }) if name.group.is_none() && name.name.ends_with("-type") => InstructionFormName {
1225 pos: name.pos,
1226 name: name.name.clone(),
1227 },
1228 _ => break,
1229 };
1230 let fields = self.parse_instruction_fields(
1231 row_iterator.next().unwrap().unwrap(),
1232 column_definitions,
1233 false,
1234 )?;
1235 instruction_forms.push(InstructionForm { name, fields });
1236 }
1237 Ok(instruction_forms)
1238 }
1239 fn parse_instruction(
1240 &self,
1241 row: Vec<ColumnRange>,
1242 column_definitions: &[ColumnDefinition],
1243 ) -> Result<Instruction> {
1244 let opcode = match row.first().expect("row already checked to be non-empty") {
1245 ColumnRange {
1246 body: Some(ColumnBody::OpcodeName(opcode)),
1247 ..
1248 } => opcode.clone(),
1249 column => err!(self, column.pos, "expected: opcode"),
1250 };
1251 let is_fence_instruction_form = matches!(&*opcode.name, "FENCE" | "FENCE.TSO" | "PAUSE");
1252 Ok(Instruction {
1253 opcode,
1254 fields: self.parse_instruction_fields(
1255 row,
1256 column_definitions,
1257 is_fence_instruction_form,
1258 )?,
1259 })
1260 }
1261 fn parse_instruction_set_section(
1262 &self,
1263 tabular_env: &ast::Environment,
1264 ) -> Result<InstructionSetSection> {
1265 let mut tabular_body = tabular_env.body.iter();
1266 let mut first_token = tabular_body.next();
1267 match first_token.and_then(|t| Some(&*t.char_tokens()?.content)) {
1268 Some(pos) if matches!(pos, "t" | "b" | "c") => {
1269 first_token = None;
1270 }
1271 _ => {}
1272 }
1273 let column_definitions = self.parse_tabular_column_definitions(unwrap_or!(
1274 first_token
1275 .or_else(|| tabular_body.next())
1276 .and_then(ast::Token::group),
1277 err!(
1278 self,
1279 tabular_env.body_pos(),
1280 "expected `tabular` column definitions"
1281 )
1282 ))?;
1283 let mut row_iterator =
1284 TableRowIterator::new(self, tabular_body, &tabular_env.end, &column_definitions)
1285 .peekable();
1286 self.parse_blank_row(&mut row_iterator)?;
1287 self.parse_instruction_bit_ranges_row(&mut row_iterator, &column_definitions)?;
1288 let forms = self.parse_instruction_form_rows(&mut row_iterator, &column_definitions)?;
1289 let mut instructions = Vec::new();
1290 for row in row_iterator {
1291 let row = row?;
1292 match &*row {
1293 [ColumnRange {
1294 body: Some(ColumnBody::Group(_)),
1295 ..
1296 }, ..]
1297 | [ColumnRange { body: None, .. }, ColumnRange { body: None, .. }]
1298 | [ColumnRange {
1299 body: Some(ColumnBody::ColumnBodyBoldText(_)),
1300 ..
1301 }, ..] => continue,
1302 _ => instructions.push(self.parse_instruction(row, &column_definitions)?),
1303 }
1304 }
1305 Ok(InstructionSetSection {
1306 forms,
1307 instructions,
1308 })
1309 }
1310 fn parse_instruction_set(&self, document: &ast::Document) -> Result<InstructionSet> {
1311 let mut sections = Vec::new();
1312 for table_env in document.content.iter().filter_map(ast::Token::environment) {
1313 let table_env = self.expect_environment(table_env, "table")?;
1314 let mut section = None;
1315 for small_env in table_env.body.iter().filter_map(ast::Token::environment) {
1316 let small_env = self.expect_environment(small_env, "small")?;
1317 for center_env in small_env.body.iter().filter_map(ast::Token::environment) {
1318 let center_env = self.expect_environment(center_env, "center")?;
1319 for tabular_env in center_env.body.iter().filter_map(ast::Token::environment) {
1320 let tabular_env = self.expect_environment(tabular_env, "tabular")?;
1321 err_if!(
1322 section.is_some(),
1323 self,
1324 tabular_env,
1325 "multiple `\\begin{{tabular}}` in single `\\begin{{table}}`"
1326 );
1327 section = Some(self.parse_instruction_set_section(tabular_env)?);
1328 }
1329 }
1330 }
1331 sections.push(unwrap_or!(
1332 section,
1333 err!(
1334 self,
1335 table_env,
1336 "missing `\\begin{{tabular}}` in this `\\begin{{table}}`"
1337 )
1338 ));
1339 }
1340 err_if!(sections.is_empty(), self, document, "no environment found");
1341 Ok(InstructionSet { sections })
1342 }
1343}
1344
1345#[derive(Debug, Clone)]
1346pub struct InstructionSetSection {
1347 pub forms: Vec<InstructionForm>,
1348 pub instructions: Vec<Instruction>,
1349}
1350
1351#[derive(Debug, Clone)]
1352pub struct InstructionSet {
1353 pub sections: Vec<InstructionSetSection>,
1354}
1355
1356#[derive(Debug, Clone)]
1357pub enum ColumnKind {
1358 ParagraphTop {
1359 keyword_pos: ast::Pos,
1360 width: ast::Group,
1361 },
1362 LeftJustified {
1363 keyword_pos: ast::Pos,
1364 },
1365 }
1367
1368#[derive(Debug, Clone)]
1369pub struct MergedColumnDefinition {
1370 pub column_range: Range<usize>,
1371 pub bit_range: InstBitRange,
1372}
1373
1374#[derive(Debug, Clone)]
1375pub struct ColumnDefinition {
1376 pub kind: ColumnKind,
1377 pub merged_def: OnceCell<MergedColumnDefinition>,
1378}
1379
1380#[derive(Debug, Clone)]
1381pub struct InstBit {
1382 pub pos: ast::Pos,
1383 pub bit: u32,
1384}
1385
1386#[derive(Debug, Clone)]
1387pub struct InstBitRange {
1388 pub bits: RangeInclusive<u32>,
1389 pub end_bit_pos: ast::Pos,
1390 pub start_bit_pos: ast::Pos,
1391}
1392
1393impl From<InstBit> for InstBitRange {
1394 fn from(v: InstBit) -> Self {
1395 Self {
1396 bits: v.bit..=v.bit,
1397 end_bit_pos: v.pos,
1398 start_bit_pos: v.pos,
1399 }
1400 }
1401}
1402
1403#[derive(Debug, Clone)]
1404pub struct FieldBitRange {
1405 pub bits: RangeInclusive<u32>,
1406 pub end_bit_pos: ast::Pos,
1407 pub start_bit_pos: Option<ast::Pos>,
1408}
1409
1410#[derive(Debug, Clone)]
1411pub enum FieldDefName {
1412 Macro(ast::MacroName),
1413 CharTokens(ast::CharTokens),
1414}
1415
1416impl GetPos for FieldDefName {
1417 fn pos(&self) -> ast::Pos {
1418 match self {
1419 FieldDefName::Macro(v) => v.pos(),
1420 FieldDefName::CharTokens(v) => v.pos(),
1421 }
1422 }
1423}
1424
1425#[derive(Debug, Clone)]
1426pub struct FieldDefSlice {
1427 pub name: FieldDefName,
1428 pub bit_ranges: Vec<FieldBitRange>,
1429}
1430
1431impl GetPos for FieldDefSlice {
1432 fn pos(&self) -> ast::Pos {
1433 self.name.pos()
1434 }
1435}
1436
1437#[derive(Debug, Clone)]
1438pub struct FieldDefAlternate {
1439 pub names: Vec<FieldDefName>,
1441}
1442
1443impl GetPos for FieldDefAlternate {
1444 fn pos(&self) -> ast::Pos {
1445 self.names[0].pos()
1446 }
1447}
1448
1449#[derive(Debug, Clone)]
1450pub struct Wildcard {
1451 pub pos: ast::Pos,
1453 pub content: String,
1454}
1455
1456impl GetPos for Wildcard {
1457 fn pos(&self) -> ast::Pos {
1458 self.pos
1459 }
1460}
1461
1462#[derive(Debug, Clone)]
1463pub enum FieldDefBody {
1464 Alternate(FieldDefAlternate),
1465 Slice(FieldDefSlice),
1466 Wildcard(Wildcard),
1467 LiteralNumber(ast::Number),
1468}
1469
1470impl GetPos for FieldDefBody {
1471 fn pos(&self) -> ast::Pos {
1472 match self {
1473 FieldDefBody::Alternate(v) => v.pos(),
1474 FieldDefBody::Slice(v) => v.pos(),
1475 FieldDefBody::Wildcard(v) => v.pos(),
1476 FieldDefBody::LiteralNumber(v) => v.pos(),
1477 }
1478 }
1479}
1480
1481#[derive(Debug, Clone)]
1482pub struct FieldDef {
1483 pub body: FieldDefBody,
1484 pub excluded_values: Vec<ast::Number>,
1485}
1486
1487impl FieldDef {
1488 pub fn only_char_tokens(&self) -> Option<&ast::CharTokens> {
1489 if !self.excluded_values.is_empty() {
1490 return None;
1491 }
1492 match &self.body {
1493 FieldDefBody::Alternate(FieldDefAlternate { names }) => match &**names {
1494 [FieldDefName::CharTokens(char_tokens)] => Some(char_tokens),
1495 _ => None,
1496 },
1497 _ => None,
1498 }
1499 }
1500}
1501
1502impl GetPos for FieldDef {
1503 fn pos(&self) -> ast::Pos {
1504 self.body.pos()
1505 }
1506}
1507
1508#[derive(Debug, Clone)]
1509pub struct ColumnBodyText {
1510 pub pos: ast::Pos,
1511 pub tokens: Vec<ast::Token>,
1512}
1513
1514#[derive(Debug, Clone)]
1515pub struct OpcodeName {
1516 pub pos: ast::Pos,
1517 pub name: String,
1518 pub group: Option<ast::Group>,
1519}
1520
1521#[derive(Debug, Clone)]
1522pub struct ColumnBodyBoldText {
1523 pub pos: ast::Pos,
1524 pub tokens: Vec<ast::Token>,
1525}
1526
1527#[derive(Debug, Clone)]
1528pub enum ColumnBody {
1529 InstBit(InstBit),
1530 InstBitRange(InstBitRange),
1531 FieldDef(FieldDef),
1532 ColumnBodyText(ColumnBodyText),
1533 OpcodeName(OpcodeName),
1534 ColumnBodyBoldText(ColumnBodyBoldText),
1535 Group(ast::Group),
1536}
1537
1538impl GetPos for ColumnBody {
1539 fn pos(&self) -> ast::Pos {
1540 match self {
1541 ColumnBody::InstBit(v) => v.pos,
1542 ColumnBody::InstBitRange(v) => v.end_bit_pos, ColumnBody::FieldDef(v) => v.pos(),
1544 ColumnBody::ColumnBodyText(v) => v.pos,
1545 ColumnBody::OpcodeName(v) => v.pos,
1546 ColumnBody::ColumnBodyBoldText(v) => v.pos,
1547 ColumnBody::Group(v) => v.pos(),
1548 }
1549 }
1550}
1551
1552#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1553pub enum MultiColumnKind {
1554 Left,
1555 Right,
1556 Center,
1557}
1558
1559impl MultiColumnKind {
1560 pub fn from_str(s: &str) -> Option<Self> {
1561 match s {
1562 "l" => Some(Self::Left),
1563 "c" => Some(Self::Center),
1564 "r" => Some(Self::Right),
1565 _ => None,
1566 }
1567 }
1568}
1569
1570#[derive(Debug, Clone)]
1571pub struct MultiColumn {
1572 pub pos: ast::Pos,
1573 pub kind: MultiColumnKind,
1574 pub vertical_bar_on_left: bool,
1575 pub vertical_bar_on_right: bool,
1576}
1577
1578#[derive(Debug, Clone)]
1579pub struct ColumnRange {
1580 pub pos: ast::Pos,
1581 pub indexes: Range<usize>,
1582 pub multi_column: Option<MultiColumn>,
1583 pub body: Option<ColumnBody>,
1584}
1585
1586#[derive(Debug, Clone)]
1587pub struct InstructionField {
1588 pub instruction_bit_range: InstBitRange,
1589 pub field_def: FieldDef,
1590}
1591
1592#[derive(Debug, Clone)]
1593pub struct InstructionFormName {
1594 pub pos: ast::Pos,
1595 pub name: String,
1596}
1597
1598#[derive(Debug, Clone)]
1599pub struct InstructionForm {
1600 pub name: InstructionFormName,
1601 pub fields: Vec<InstructionField>,
1602}
1603
1604#[derive(Debug, Clone)]
1605pub struct Instruction {
1606 pub opcode: OpcodeName,
1607 pub fields: Vec<InstructionField>,
1608}
1609
1610pub fn parse(file_name: &str, input: &str) -> Result<InstructionSet> {
1611 ast::Pos::call_with_input_context(InputContext { file_name, input }, || {
1612 let parser = Parser::new(file_name, input);
1613 let document = tex_parser::parse(input)
1614 .map_err(|e| parser.err_line_col(e.location, format!("expected: {}", e.expected)))?;
1615 parser.parse_instruction_set(&document)
1616 })
1617}