synthphonia/parser/
prod.rs

1use itertools::Itertools;
2use pest::iterators::Pair;
3
4use crate::{
5    galloc::AllocForStr, utils::TryRetain, value::{ConstValue, Type}
6};
7
8use super::{problem::{new_custom_error_span, Error, Rule}, config::Config};
9
10#[derive(PartialEq, Eq, Hash, Clone)]
11/// A variant-rich enumeration representing different types of production rules used in string synthesis. 
12/// 
13/// It includes variants for handling variables, constants, and operations with differing arities. 
14/// Each variant encapsulates a production rule as follows:
15/// 
16/// The `Var` variant takes a variable name and a configuration, associating this rule with a specific variable in the synthesis problem. 
17/// The `Const` variant holds a constant value alongside its configuration, representing fixed values in the synthesis. 
18/// Variants `Op1`, `Op2`, and `Op3` capture operations with one, two, and three operands respectively, each carrying the necessary operands as strings and concluding with a configuration object to manage operational parameters or constraints. 
19/// This structure enables flexible representation of grammatical constructs in syntax-guided synthesis tasks, supporting a wide range of synthesis requirements.
20pub enum ProdRule {
21    Var(String, Config),
22    Const(ConstValue, Config),
23    Op1(String, String, Config),
24    Op2(String, String, String, Config),
25    Op3(String, String, String, String, Config),
26}
27
28impl ConstValue {
29    /// Parses a `Pair` of `'_, Rule>` into a `ConstValue`, returning a result with either the parsed constant or an error. 
30
31    pub fn parse(pair: Pair<'_, Rule>) -> Result<Self, Error> {
32        let [value]: [_; 1] = pair.into_inner().collect_vec().try_into().unwrap();
33        match value.as_rule() {
34            Rule::numeral => {
35                if value.as_str().contains(".") {
36                    let f = value.as_str().parse::<f64>().map_err(|_| new_custom_error_span("Can not parse float".into(), value.as_span()))?;
37                    Ok(Self::Float(f.into()))
38                } else {
39                    let f = value.as_str().parse::<i64>().map_err(|_| new_custom_error_span("Can not parse int".into(), value.as_span()))?;
40                    Ok(Self::Int(f))
41                }
42            }
43            Rule::hexnum => {
44                let s = value.as_str().trim_start_matches("#x");
45                let f = u64::from_str_radix(s, 16)
46                    .map_err(|_| new_custom_error_span("Can not parse hex".into(), value.as_span()))?;
47                Ok(Self::BitVector(s.len() * 4, f))
48            }
49            Rule::binnum => {
50                let s = value.as_str().trim_start_matches("#b");
51                let f = u64::from_str_radix(s, 2)
52                    .map_err(|_| new_custom_error_span("Can not parse binary".into(), value.as_span()))?;
53                Ok(Self::BitVector(s.len(), f))
54            }
55            Rule::strlit => Ok(Self::Str(value.as_str()[1..(value.as_str().len() - 1)].galloc_str())),
56            Rule::boollit => match value.as_str() {
57                "true" => Ok(Self::Bool(true)),
58                "false" => Ok(Self::Bool(false)),
59                "null" => Ok(Self::Null),
60                _ => Err(new_custom_error_span("Can not parse the Boolean".into(), value.as_span())),
61            },
62            _ => panic!("should not reach here"),
63        }
64    }
65}
66
67impl ProdRule {
68    /// Returns the constant value associated with a specific production rule, if available. 
69
70    pub fn const_value(&self) -> Option<&ConstValue> {
71        match self {
72            ProdRule::Const(i, _) => Some(i),
73            _ => None,
74        }
75    }
76    /// Parses a `Pair` object into a `ProdRule` variant. 
77
78    pub fn parse(pair: Pair<'_, Rule>) -> Result<Self, Error> {
79        let mut vec = pair.into_inner().collect_vec();
80        let mut config = Config::new();
81        vec.try_retain(|x| {
82            if x.as_rule() == Rule::config {
83                config.merge(Config::parse(x.clone())?);
84                Ok(false)
85            } else { Ok(true) }
86        })?;
87        if vec.len() == 1 {
88            let [value]: [_; 1] = vec.try_into().unwrap();
89            match value.as_rule() {
90                Rule::value => Ok(Self::Const(ConstValue::parse(value)?, config)),
91                Rule::symbol => Ok(Self::Var(value.as_str().into(), config)),
92                _ => panic!("should not reach here"),
93            }
94        } else {
95            match vec.as_slice() {
96                [op, a1] => Ok(Self::Op1(op.as_str().into(), a1.as_str().into(), config)),
97                [op, a1, a2] => Ok(Self::Op2(op.as_str().into(), a1.as_str().into(), a2.as_str().into(), config)),
98                [op, a1, a2, a3] => Ok(Self::Op3(op.as_str().into(), a1.as_str().into(), a2.as_str().into(), a3.as_str().into(), config)),
99                _ => panic!("should not reach here"),
100            }
101        }
102    }
103}
104
105impl std::fmt::Debug for ProdRule {
106
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        match self {
109            Self::Var(arg0, _) => write!(f, "{}", arg0),
110            Self::Const(arg0, _) => write!(f, "{}", arg0),
111            Self::Op1(arg0, arg1, c) => write!(f, "({} {}{:?})", arg0, arg1, c),
112            Self::Op2(arg0, arg1, arg2, c) => write!(f, "({} {} {}{:?})", arg0, arg1, arg2, c),
113            Self::Op3(arg0, arg1, arg2, arg3, c) => write!(f, "({} {} {} {}{:?})", arg0, arg1, arg2, arg3, c),
114        }
115    }
116}