/* * 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 super::{next_word, parse_number}; use ielr::input::{Node, ProdIdx}; use std::collections::HashMap; pub(super) fn parse_forbid( mut line: &str, nodes: &HashMap<&str, (Node, Vec)>, ) -> Result<(ProdIdx, usize, ProdIdx), String> { line = match line.strip_prefix('(') { Some(line) => line, None => return Err(String::from("expected '(' after '@forbid'")), }; let (line, prod_idx) = parse_prod_idx(line, nodes)?; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { return Err("expected ',' after the first production in @forbid".to_string()); }; let (line, index) = parse_number(line)?; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { return Err("expected ',' after the symbol index in @forbid".to_string()); }; let (line, forbidden_prod_idx) = parse_prod_idx(line, nodes)?; let line = if let Some(line) = line.strip_prefix(')') { line.trim_start() } else { return Err("expected ')' after the second production in @forbid".to_string()); }; if line.is_empty() { Ok(( prod_idx, TryInto::::try_into(index).map_err(|err| err.to_string())?, forbidden_prod_idx, )) } else { Err(format!("unknown characters after @forbid : {line:?}")) } } fn parse_prod_idx<'a>( line: &'a str, nodes: &HashMap<&str, (Node, Vec)>, ) -> Result<(&'a str, ProdIdx), String> { 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 '@forbid('")), }; let line = if let Some(line) = line.strip_prefix(',') { line.trim_start() } else { return Err(format!( "expected ',' after the node {node_name} in @forbid" )); }; let (line, index) = parse_number(line)?; let prod_idx = productions[index as usize]; Ok((line, prod_idx)) }