wagon_parser/parser/
atom.rs

1use std::fmt::Display;
2use std::hash::Hash;
3use std::write;
4
5use super::{Parse, LexerBridge, ParseResult, Tokens, WagParseError, Ident, SpannableNode, Spannable, expression::Expression, ResultNext};
6use super::helpers::{between, between_right};
7use crate::either_token;
8use crate::firstpass::{GetReqAttributes, RewriteToSynth};
9
10use wagon_lexer::math::Math;
11use wagon_macros::match_error;
12use wagon_utils::ConversionError;
13use wagon_value::{Valueable, Value, RecursiveValue};
14
15use ordered_float::NotNan;
16
17use wagon_macros::new_unspanned;
18
19#[derive(PartialEq, Debug, Eq, Hash, Clone)]
20/// A python-style dictionary.
21///
22/// # Grammar
23/// <code>[Dictionary] -> [Ident] "[" [Expression] "]";</code>
24pub struct Dictionary(Ident, Expression);
25
26impl Dictionary {
27	/// Deconstruct the dictionary into it's [`Ident`] and [`Expression`].
28	#[must_use] 
29	pub const fn deconstruct(&self) -> (&Ident, &Expression) {
30		(&self.0, &self.1)
31	}
32}
33
34#[derive(PartialEq, Debug, Eq, Hash, Clone)]
35#[new_unspanned]
36/// The base elements of each expression.
37///
38/// The data in here is kind of similar to [`wagon_value::Value`] and `TryFrom` is implemented for it as a result.
39/// However, an `Atom` includes additional syntactic data, which is not important (or even not available) for `Value` (for example, an [`Ident`]).
40/// As a result, [`Atom::Ident`], [`Atom::Dict`] and [`Atom::Group`] can not be directly converted and manual implementation is required.
41///
42/// # Grammar
43/// <span><pre>
44/// [Atom] -> [Ident]
45///      |  [Dictionary]
46///      |  [bool]
47///      |  [i32]
48///      |  [f32]
49///      |  [String]
50///      |  `"("` [Expression] `")"`
51///      ;
52/// </pre></span>
53pub enum Atom {
54	/// An [`Ident`].
55	Ident(Ident),
56	/// A [`Dictionary`].
57	Dict(Dictionary),
58	/// A [`bool`].
59	LitBool(bool),
60	/// An [`i32`].
61	LitNum(i32),
62	/// An [`f32`].
63	LitFloat(NotNan<f32>),
64	/// A [`String`].
65	LitString(String),
66	/// Another full [`Expression`]. Enclosed by `()`.
67	Group(SpannableNode<Expression>)
68}
69
70impl Parse for Atom {
71
72	fn parse(lexer: &mut LexerBridge) -> ParseResult<Self> {
73	    match_error!(match lexer.next_result()? {
74	    	#[expect("identifier or dictionary")]
75	        either_token!(Identifier(x)) => {
76	        	if let Ok(inner) = between(lexer, &Tokens::MathToken(Math::LBr), &Tokens::MathToken(Math::RBr)) {
77	        		Ok(Self::Dict(Dictionary(x, inner)))
78	        	} else {
79	        		Ok(Self::Ident(x))
80	        	}
81	        },
82	        Tokens::MathToken(Math::LitBool(x)) => Ok(Self::LitBool(x)),
83	        Tokens::MathToken(Math::LitInt(x)) => Ok(Self::LitNum(x)),
84	        Tokens::MathToken(Math::LitFloat(x)) => {
85	        	match NotNan::new(x) {
86				    Ok(f) => Ok(Self::LitFloat(f)),
87				    Err(e) => Err(WagParseError::FloatError(e, lexer.span())),
88				}
89	        },
90	        #[expect("string")]
91	        either_token!(LitString(x)) => Ok(Self::LitString(x)),
92	        Tokens::MathToken(Math::LPar) => {
93	        	let resp = between_right(lexer, &Tokens::MathToken(Math::RPar))?;
94	        	Ok(Self::Group(resp))
95	        },
96	    })
97	}
98}
99
100impl GetReqAttributes for Atom {
101    fn get_req_attributes(&self) -> crate::firstpass::ReqAttributes {
102        match self {
103        	Self::Ident(i) => { 
104        		let mut req = crate::firstpass::ReqAttributes::new();
105        		req.insert(i.clone().into());
106        		req
107        	},
108        	Self::Group(e) => e.get_req_attributes(),
109        	_ => crate::firstpass::ReqAttributes::new()
110        }
111    }
112}
113
114impl RewriteToSynth for Atom {
115    fn rewrite_to_synth(&mut self) -> crate::firstpass::ReqAttributes {
116        match self {
117        	Self::Ident(i) => { 
118        		let mut req = crate::firstpass::ReqAttributes::new();
119        		let as_synth = i.to_synth();
120        		req.insert(i.clone().into());
121        		*i = as_synth;
122        		req
123        	},
124        	Self::Group(e) => e.rewrite_to_synth(),
125        	_ => crate::firstpass::ReqAttributes::new()
126        }
127    }
128}
129
130impl Display for Atom {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        match self {
133            Self::Ident(x) => write!(f, "{x}"),
134            Self::Dict(x) => write!(f, "{x}"),
135            Self::LitBool(x) => write!(f, "{x}"),
136            Self::LitNum(x) => write!(f, "{x}"),
137            Self::LitFloat(x) => write!(f, "{x}"),
138            Self::LitString(x) => write!(f, "\"{x}\""),
139            Self::Group(x) => write!(f, "({x})"),
140        }
141    }
142}
143
144impl Display for Dictionary {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        write!(f, "{}[{}]", self.0, self.1)
147    }
148}
149
150impl<T: Valueable> TryFrom<Atom> for Value<T> {
151    type Error = ConversionError<Atom, Self>;
152
153    fn try_from(value: Atom) -> Result<Self, Self::Error> {
154        match value {
155            Atom::LitBool(b) => Ok(Self::Bool(b)),
156            Atom::LitNum(i) => Ok(Self::Natural(i)),
157            Atom::LitFloat(f) => Ok(Self::Float(f)),
158            Atom::LitString(s) => Ok(Self::String(s)),
159            other => Err(ConversionError::new(other)),
160        }
161    }
162}
163
164impl TryFrom<Atom> for RecursiveValue {
165    type Error = ConversionError<Atom, Self>;
166
167    fn try_from(value: Atom) -> Result<Self, Self::Error> {
168        Ok(Self::from(Value::try_from(value).map_err(wagon_utils::ConversionError::convert)?))
169    }
170}