Skip to main content

sim_kernel/pratt/
object.rs

1use std::sync::Arc;
2
3use crate::{
4    CORE_TABLE_CLASS_ID, ClassRef, Cx, DefaultFactory, Expr, Factory, Fixity, Object, Result,
5    Symbol, Value,
6};
7
8use super::types::PrattTable;
9
10/// Runtime [`Object`] wrapper exposing a named [`PrattTable`] to the kernel as
11/// a core table value.
12// sim-non-citizen(reason = "parser table registry marker; reconstruct by loading the parser table lib", kind = "marker", descriptor = "")
13#[derive(Clone)]
14pub struct PrattTableObject {
15    /// Symbol naming this operator table.
16    pub symbol: Symbol,
17    /// The wrapped operator table.
18    pub table: PrattTable,
19}
20
21impl PrattTableObject {
22    /// Wraps an operator table under the given name.
23    pub fn new(symbol: Symbol, table: PrattTable) -> Self {
24        Self { symbol, table }
25    }
26}
27
28impl Object for PrattTableObject {
29    fn display(&self, _cx: &mut Cx) -> Result<String> {
30        Ok(format!("#<pratt-table {}>", self.symbol))
31    }
32
33    fn as_any(&self) -> &dyn std::any::Any {
34        self
35    }
36}
37
38impl crate::ObjectCompat for PrattTableObject {
39    fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
40        if let Some(value) = cx
41            .registry()
42            .class_by_symbol(&Symbol::qualified("core", "Table"))
43        {
44            return Ok(value.clone());
45        }
46        cx.factory()
47            .class_stub(CORE_TABLE_CLASS_ID, Symbol::qualified("core", "Table"))
48    }
49    fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
50        Ok(Expr::Symbol(self.symbol.clone()))
51    }
52    fn as_table(&self, cx: &mut Cx) -> Result<Value> {
53        let operators = self
54            .table
55            .operators()
56            .into_iter()
57            .map(|operator| {
58                cx.factory().table(vec![
59                    (Symbol::new("symbol"), cx.factory().symbol(operator.symbol)?),
60                    (
61                        Symbol::new("fixity"),
62                        cx.factory().string(
63                            match operator.fixity {
64                                Fixity::Prefix => "prefix",
65                                Fixity::InfixLeft => "infix-left",
66                                Fixity::InfixRight => "infix-right",
67                                Fixity::Postfix => "postfix",
68                                Fixity::Mixfix => "mixfix",
69                            }
70                            .to_owned(),
71                        )?,
72                    ),
73                    (
74                        Symbol::new("left-bp"),
75                        cx.factory().number_literal(
76                            Symbol::qualified("numbers", "f64"),
77                            operator.left_bp.to_string(),
78                        )?,
79                    ),
80                    (
81                        Symbol::new("right-bp"),
82                        cx.factory().number_literal(
83                            Symbol::qualified("numbers", "f64"),
84                            operator.right_bp.to_string(),
85                        )?,
86                    ),
87                ])
88            })
89            .collect::<Result<Vec<_>>>()?;
90
91        cx.factory().table(vec![
92            (
93                Symbol::new("symbol"),
94                cx.factory().symbol(self.symbol.clone())?,
95            ),
96            (Symbol::new("operators"), cx.factory().list(operators)?),
97        ])
98    }
99}
100
101/// Boxes a named operator table into an opaque runtime [`Value`].
102pub fn pratt_table_value(symbol: Symbol, table: PrattTable) -> Value {
103    DefaultFactory
104        .opaque(Arc::new(PrattTableObject::new(symbol, table)))
105        .expect("pratt table object should always be boxable")
106}