wagon_parser/parser/
expression.rs

1use std::{fmt::Display, write};
2
3use crate::firstpass::{GetReqAttributes, ReqAttributes, RewriteToSynth};
4
5use super::{Parse, LexerBridge, ParseResult, Tokens, WagParseError, SpannableNode, ResultPeek, ResultNext};
6use wagon_lexer::math::Math;
7
8use wagon_macros::match_error;
9use super::disjunct::Disjunct;
10
11use wagon_macros::new_unspanned;
12
13#[derive(PartialEq, Debug, Eq, Hash, Clone)]
14#[new_unspanned]
15/// An expression in the WAGon attribute evaluation DSL.
16///
17/// # Grammar
18/// <span><pre>
19/// [Expression] -> SubProc | If | [Disjunct];
20/// SubProc -> `"$(" /[^)]*/ ")"`; // A bash-style $() expression
21/// If -> "if" [Disjunct] "then" [Disjunct] ("else" [Expression])?;
22/// </pre></span>
23pub enum Expression {
24	/// A subprocess that should do evaluation in the shell.
25	Subproc(SpannableNode<String>),
26	/// An if(-else) statement.
27	If {
28		/// If this evaluation returns true.
29		this: SpannableNode<Disjunct>,
30		/// Do this.
31		then: SpannableNode<Disjunct>,
32		/// Else, evaluate this expression.
33		r#else: Option<Box<SpannableNode<Expression>>>
34	},
35	/// The next layer down. See [`Disjunct`].
36	Disjunct(SpannableNode<Disjunct>),
37}
38
39impl Parse for Expression {
40
41	fn parse(lexer: &mut LexerBridge) -> ParseResult<Self> { 
42		match lexer.peek_result()? {
43			Tokens::MathToken(Math::If) => {lexer.next(); Self::parse_if(lexer)},
44			Tokens::MathToken(Math::Bash(_)) => Ok(Self::Subproc(SpannableNode::parse(lexer)?)),
45			_ => Ok(Self::Disjunct(SpannableNode::parse(lexer)?))
46		}
47	}
48}
49
50impl Expression {
51
52	fn parse_if(lexer: &mut LexerBridge) -> ParseResult<Self> {
53		let this = SpannableNode::parse(lexer)?;
54		let then = match_error!(match lexer.next_result()? {
55			Tokens::MathToken(Math::Then) => SpannableNode::parse(lexer)
56		})?;
57		let r#else = match lexer.peek_result()? {
58		    Tokens::MathToken(Math::Else) => {lexer.next(); Some(Box::new(SpannableNode::parse(lexer)?))},
59		    _ => None
60		};
61		Ok(Self::If { this, then, r#else })
62	}
63}
64
65impl RewriteToSynth for Expression {
66    fn rewrite_to_synth(&mut self) -> ReqAttributes {
67        match self {
68		    Self::Subproc(_) => ReqAttributes::new(),
69		    Self::If { this, then, r#else } => {
70		    	let mut req = this.rewrite_to_synth();
71		    	req.extend(then.rewrite_to_synth());
72		    	if let Some(cont) = r#else {
73		    		req.extend(cont.node.rewrite_to_synth());
74		    	}
75		    	req
76		    },
77		    Self::Disjunct(d) => d.rewrite_to_synth(),
78		}
79    }
80}
81
82impl GetReqAttributes for Expression {
83    fn get_req_attributes(&self) -> ReqAttributes {
84        match self {
85		    Self::Subproc(_) => ReqAttributes::new(),
86		    Self::If { this, then, r#else } => {
87		    	let mut req = this.get_req_attributes();
88		    	req.extend(then.get_req_attributes());
89		    	if let Some(cont) = r#else {
90		    		req.extend(cont.get_req_attributes());
91		    	}
92		    	req
93		    },
94		    Self::Disjunct(d) => d.get_req_attributes(),
95		}
96    }
97}
98
99impl Display for Expression {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        match self {
102            Self::Subproc(s) => write!(f, "$({s})"),
103            Self::If { this, then, r#else } => {
104            	if let Some(e) = r#else {
105            		write!(f, "if {this} {{ {then} }} else {{ {e} }}")
106            	} else {
107            		write!(f, "if {this} {{ {then} }}")
108            	}
109            },
110            Self::Disjunct(d) => write!(f, "{d}"),
111        }
112    }
113}