taitan_orm_parser/template_parser/structs/
variable.rs1use nom::branch::alt;
2use nom::bytes::complete::tag;
3use nom::character::complete::{alpha1, alphanumeric1, multispace0};
4use nom::combinator::{map, recognize};
5use nom::error::context;
6use nom::multi::many0;
7use nom::sequence::{delimited, pair, preceded, tuple};
8use nom::IResult;
9use std::fmt::{Display, Formatter};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Variable {
13 Simple(String),
14 Backquote(String),
15 Brackets(String),
16 DoubleQuote(String),
17}
18
19impl Variable {
20 pub fn parse(input: &str) -> IResult<&str, Variable> {
21 alt((
22 parse_quoted_variable, map(parse_simple_variable, Variable::Simple), ))(input)
25 }
26 pub fn get_ident(&self) -> &str {
27 match self {
28 Variable::Simple(ident)
29 | Variable::Backquote(ident)
30 | Variable::Brackets(ident)
31 | Variable::DoubleQuote(ident) => ident,
32 }
33 }
34}
35
36impl Display for Variable {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 match self {
39 Variable::Simple(ident) => write!(f, "{}", ident),
40 Variable::Backquote(ident) => write!(f, "`{}`", ident),
41 Variable::Brackets(ident) => write!(f, "[{}]", ident),
42 Variable::DoubleQuote(ident) => write!(f, "\"{}\"", ident),
43 }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct VariableChain {
49 pub variables: Vec<Variable>,
50}
51impl VariableChain {
52 pub fn new(variables: Vec<Variable>) -> VariableChain {
53 VariableChain { variables }
54 }
55 pub fn parse(input: &str) -> IResult<&str, VariableChain> {
56 context(
58 "VariableChain",
59 map(
60 tuple((
61 Variable::parse, many0(preceded(
63 multispace0,
64 preceded(tag("."), preceded(multispace0, Variable::parse)),
65 )), )),
67 |(first, rest)| VariableChain {
68 variables: std::iter::once(first).chain(rest.into_iter()).collect(),
69 },
70 ),
71 )(input)
72 }
73}
74
75impl Display for VariableChain {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 let mut result = String::new();
78 for (index, variable) in self.variables.iter().enumerate() {
79 if index > 0 {
80 result.push('.');
81 }
82 result.push_str(&variable.to_string());
83 }
84 write!(f, "{}", result)
85 }
86}
87
88fn parse_simple_variable(input: &str) -> IResult<&str, String> {
89 map(
91 recognize(pair(
92 alpha1, many0(alt((alphanumeric1, tag("_")))), )),
95 |s: &str| s.to_string(),
96 )(input)
97}
98
99fn parse_quoted_variable(input: &str) -> IResult<&str, Variable> {
100 alt((
102 map(
103 delimited(
104 tag("`"),
105 preceded(multispace0, parse_simple_variable),
106 preceded(multispace0, tag("`")),
107 ),
108 |var| Variable::Backquote(var.to_string()),
109 ),
110 map(
111 delimited(
112 tag("["),
113 preceded(multispace0, parse_simple_variable),
114 preceded(multispace0, tag("]")),
115 ),
116 |var| Variable::Brackets(var.to_string()),
117 ),
118 map(
119 delimited(
120 tag("\""),
121 preceded(multispace0, parse_simple_variable),
122 preceded(multispace0, tag("\"")),
123 ),
124 |var| Variable::DoubleQuote(var.to_string()),
125 ),
126 ))(input)
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 #[test]
133 fn test_parse_variable_chain_spec_001() {
134 let template = "sdfs.[ sdf ].` uire123`.\"gsdg \". dfdsl";
135 let (_, variable_chain) = VariableChain::parse(template).unwrap();
136 assert_eq!(
137 variable_chain.variables,
138 vec![
139 Variable::Simple("sdfs".to_string()),
140 Variable::Brackets("sdf".to_string()),
141 Variable::Backquote("uire123".to_string()),
142 Variable::DoubleQuote("gsdg".to_string()),
143 Variable::Simple("dfdsl".to_string()),
144 ]
145 );
146 }
147
148 #[test]
149 fn test_parse_variable_chain_spec_002() {
150 let template = "123";
151 let parse_result = VariableChain::parse(template);
152 assert!(parse_result.is_err());
153
154 let template = "'asdfv'";
155 let parse_result = VariableChain::parse(template);
156 assert!(parse_result.is_err());
157 }
158}