use crate::integer::Integer;
use crate::integer_polynomial::IntegerPolynomial;
use alloc::vec::Vec;
use core::str::FromStr;
use malachite_base::num::basic::traits::{NegativeOne, One, Zero};
use malachite_base::polynomial::Polynomial;
use malachite_base::vars::xyz::XyzVars;
use malachite_base::vars::{Var, VarScheme, char_is_reserved};
fn parse_monic<S: VarScheme + ?Sized>(var: Var<'_, S>, monic: &str) -> Option<usize> {
let (name, exponent) = match monic.split_once('^') {
Some((name, exponent)) => {
let exponent = usize::from_str(exponent).ok()?;
if exponent == 0 {
return None;
}
(name, exponent)
}
None => (monic, 1),
};
if var.scheme().parse_var(name) == Some(var.index()) {
Some(exponent)
} else {
None
}
}
fn split_terms(s: &str) -> Vec<&str> {
let mut terms = Vec::new();
let mut start = 0;
for (i, c) in s.char_indices() {
if i != 0 && (c == '+' || c == '-') {
terms.push(&s[start..i]);
start = if c == '+' { i + 1 } else { i };
}
}
terms.push(&s[start..]);
terms
}
fn parse_term<S: VarScheme + ?Sized>(var: Var<'_, S>, term: &str) -> Option<(Integer, usize)> {
if term.starts_with(|c: char| !char_is_reserved(c)) {
return Some((Integer::ONE, parse_monic(var, term)?));
}
if let Some(rest) = term.strip_prefix('-')
&& rest.starts_with(|c: char| !char_is_reserved(c))
{
return Some((Integer::NEGATIVE_ONE, parse_monic(var, rest)?));
}
let (coefficient, exponent) = match term.split_once('*') {
Some((coefficient, monic)) => (coefficient, parse_monic(var, monic)?),
None => (term, 0),
};
let coefficient = Integer::from_str(coefficient).ok()?;
if coefficient == 0u32 {
None
} else {
Some((coefficient, exponent))
}
}
pub(crate) fn from_string_with<S: VarScheme + ?Sized>(
var: Var<'_, S>,
s: &str,
) -> Option<IntegerPolynomial> {
if s == "0" {
return Some(IntegerPolynomial::ZERO);
}
if s.starts_with('+') {
return None;
}
let mut coefficients: Vec<Integer> = Vec::new();
for term in split_terms(s) {
let (coefficient, exponent) = parse_term(var, term)?;
if exponent >= coefficients.len() {
coefficients.resize(exponent + 1, Integer::ZERO);
} else if coefficients[exponent] != 0u32 {
return None;
}
coefficients[exponent] = coefficient;
}
Some(IntegerPolynomial::from_coefficients_asc(coefficients))
}
impl FromStr for IntegerPolynomial {
type Err = ();
#[inline]
fn from_str(s: &str) -> Result<Self, ()> {
Self::from_string_with(Var::new(&XyzVars, 0), s).ok_or(())
}
}