/* * Copyright 2022 Arnaud Golfouse * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use ielr::input::{Node, ProdIdx}; use std::collections::HashMap; use super::{next_word, parse_number}; pub(super) fn parse_precedence( line: &str, nodes: &HashMap<&str, (Node, Vec)>, ) -> Result<(ProdIdx, Option, Option), String> { let line = match line.strip_prefix('(') { Some(line) => line.trim_start(), None => return Err(String::from("expected '(' after '@precedence'")), }; let (node_name, productions, line) = match next_word(line) { Some((word, line)) => { if let Some((_, productions)) = nodes.get(word) { (word, productions, line) } else { return Err(format!("unknown node: {word}")); } } None => { return Err(String::from( "expected node identifier after '@precedence('", )) } }; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { return Err(format!( "expected ',' after the node {node_name} in @precedence" )); }; let (line, index) = parse_number(line)?; let production = productions[index as usize]; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { return Err(format!("expected ',' after {index} in @precedence")); }; let (line, left_prec, maybe_right) = if let Some(line) = line.strip_prefix("left") { let line = if let Some(line) = line.trim_start().strip_prefix('=') { line.trim_start() } else { return Err(String::from("expected '=' after 'left' in @precedence")); }; let (line, n) = parse_number(line)?; let (line, maybe_right) = if let Some(line) = line.strip_prefix(',') { (line.trim_start(), true) } else { (line, false) }; (line, Some(n as u16), maybe_right) } else { (line, None, true) }; if !maybe_right { if let Some(line) = line.strip_prefix(')') { if !line.trim().is_empty() { return Err(format!( "incorrect syntax after closing ')' in @precedence:\n\"{line}\"" )); } return Ok((production, left_prec, None)); } else { return Err(String::from("expected ')' at the end of @precedence")); }; } let (line, right_prec) = if let Some(line) = line.strip_prefix("right") { let line = if let Some(line) = line.trim_start().strip_prefix('=') { line.trim_start() } else { return Err(String::from("expected '=' after 'right' in @precedence")); }; let (line, n) = parse_number(line)?; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { line }; (line, Some(n as u16)) } else { (line, None) }; if let Some(line) = line.strip_prefix(')') { if !line.trim().is_empty() { Err(format!( "incorrect syntax after closing ')' in @precedence:\n\"{line}\"" )) } else { Ok((production, left_prec, right_prec)) } } else { Err(String::from("expected ')' at the end of @precedence")) } }