Skip to main content

reqlang_expr/
ast.rs

1//! Abstract syntax tree types
2
3use crate::{prelude::CompileTimeEnv, span::Spanned, types::Type};
4
5#[derive(Debug, PartialEq)]
6pub enum Expr {
7    Bool(Box<ExprBool>),
8    Identifier(Box<ExprIdentifier>),
9    Call(Box<ExprCall>),
10    String(Box<ExprString>),
11    Number(Box<ExprNumber>),
12    Error,
13}
14
15impl Expr {
16    pub fn identifier(identifier: &str) -> Self {
17        Self::Identifier(Box::new(ExprIdentifier::new(identifier)))
18    }
19
20    pub fn identifier_with_type(identifier: &str, ty: Type) -> Self {
21        Self::Identifier(Box::new(ExprIdentifier(
22            identifier.to_string(),
23            ExprIdentifier::get_identifier_kind(identifier),
24            Some(ty),
25        )))
26    }
27
28    pub fn string(string: &str) -> Self {
29        Self::String(ExprString::new(string).into())
30    }
31
32    pub fn number(value: f64) -> Self {
33        Self::Number(ExprNumber::new(value).into())
34    }
35
36    pub fn call(callee: ExprS, args: Vec<ExprS>) -> Self {
37        Self::Call(Box::new(ExprCall {
38            callee: callee.into(),
39            args,
40        }))
41    }
42
43    pub fn bool(value: bool) -> Self {
44        Self::Bool(Box::new(ExprBool::new(value)))
45    }
46
47    pub fn get_type(&self) -> Type {
48        match self {
49            Expr::Bool(_) => Type::Bool,
50            Expr::Identifier(identifier) => identifier
51                .get_type()
52                .as_ref()
53                .unwrap_or(&Type::Unknown)
54                .clone(),
55            Expr::Call(_) => Type::Unknown,
56            Expr::String(_) => Type::String,
57            Expr::Number(_) => Type::Number,
58            Expr::Error => Type::Unknown,
59        }
60    }
61}
62
63#[derive(Debug, PartialEq)]
64pub struct ExprIdentifier(pub String, pub IdentifierKind, pub Option<Type>);
65
66impl ExprIdentifier {
67    pub fn new(identifier: &str) -> Self {
68        Self(
69            identifier.to_string(),
70            Self::get_identifier_kind(identifier),
71            None,
72        )
73    }
74
75    pub fn get_identifier_kind(identifier: &str) -> IdentifierKind {
76        let identifier_prefix = &identifier[..1];
77
78        match identifier_prefix {
79            "?" => IdentifierKind::Prompt,
80            "!" => IdentifierKind::Secret,
81            ":" => IdentifierKind::Var,
82            "@" => IdentifierKind::Client,
83            _ => {
84                let prefix_char: char = identifier_prefix.chars().nth(0).unwrap();
85
86                if prefix_char.is_uppercase() {
87                    IdentifierKind::Type
88                } else {
89                    IdentifierKind::Builtin
90                }
91            }
92        }
93    }
94
95    /// The full name of the identifier from the source code
96    ///
97    /// This is different from [Self::name] as it always includes a sigil prefix
98    /// for variables, prompts, secrets, and client identifiers.
99    pub fn full_name(&self) -> &str {
100        &self.0
101    }
102
103    /// The look up name for the identifier
104    ///
105    /// For builtins this is just the identifier name
106    ///
107    /// For variables, prompts, secrets, and client identifiers, it returns the
108    /// non sigil prefix version of the identifier.
109    ///
110    /// - builtin_fn => builtin_fn
111    /// - :variable => variable
112    /// - ?prompt => prompt
113    /// - !secret => secret
114    /// - @client => client
115    ///
116    pub fn lookup_name(&self) -> &str {
117        match self.identifier_kind() {
118            IdentifierKind::Builtin => &self.0,
119            IdentifierKind::Var => &self.0[1..],
120            IdentifierKind::Prompt => &self.0[1..],
121            IdentifierKind::Secret => &self.0[1..],
122            IdentifierKind::Client => &self.0[1..],
123            IdentifierKind::Type => &self.0,
124        }
125    }
126
127    pub fn identifier_kind(&self) -> &IdentifierKind {
128        &self.1
129    }
130
131    pub fn get_type(&self) -> &Option<Type> {
132        &self.2
133    }
134}
135
136#[derive(Debug, PartialEq)]
137pub enum IdentifierKind {
138    Builtin,
139    Var,
140    Prompt,
141    Secret,
142    Client,
143    Type,
144}
145
146#[derive(Debug, PartialEq)]
147pub struct ExprString(pub String);
148
149impl ExprString {
150    pub fn new(string: &str) -> Self {
151        Self(string.to_string())
152    }
153}
154
155#[derive(Debug, PartialEq)]
156pub struct ExprNumber(pub f64);
157
158impl ExprNumber {
159    pub fn new(value: f64) -> Self {
160        Self(value)
161    }
162}
163
164#[derive(Debug, PartialEq)]
165pub struct ExprCall {
166    pub callee: Box<ExprS>,
167    pub args: Vec<ExprS>,
168}
169
170#[derive(Debug, PartialEq)]
171pub struct ExprBool(pub bool);
172
173impl ExprBool {
174    pub fn new(value: bool) -> Self {
175        Self(value)
176    }
177}
178
179pub type ExprS = Spanned<Expr>;
180
181pub fn add_type_to_expr_parse(expr: &mut Expr) {
182    match expr {
183        Expr::Identifier(expr_identifier) => match expr_identifier.identifier_kind() {
184            IdentifierKind::Builtin => {}
185            IdentifierKind::Var => {
186                expr_identifier.2 = Some(Type::String);
187            }
188            IdentifierKind::Prompt => {
189                expr_identifier.2 = Some(Type::String);
190            }
191            IdentifierKind::Secret => {
192                expr_identifier.2 = Some(Type::String);
193            }
194            IdentifierKind::Client => {
195                expr_identifier.2 = Some(Type::Value);
196            }
197            IdentifierKind::Type => {
198                //
199            }
200        },
201        Expr::Call(expr_call) => {
202            for arg in &mut expr_call.args {
203                add_type_to_expr_parse(&mut arg.0);
204            }
205        }
206        _ => {}
207    }
208}
209
210pub fn add_type_to_expr(expr: &mut Expr, env: &CompileTimeEnv) {
211    match expr {
212        Expr::Identifier(expr_identifier) => match expr_identifier.identifier_kind() {
213            IdentifierKind::Builtin => {
214                if let Some((_, index)) = env.get_builtin_index(expr_identifier.lookup_name()) {
215                    if let Some(v) = env.get_builtin(index as usize) {
216                        let v_type: Type = v.clone().into();
217
218                        expr_identifier.2 = Some(v_type);
219                    }
220                } else if let Some((_, index)) =
221                    env.get_user_builtin_index(expr_identifier.lookup_name())
222                {
223                    if let Some(v) = env.get_builtin(index as usize) {
224                        let v_type: Type = v.clone().into();
225
226                        expr_identifier.2 = Some(v_type);
227                    }
228                }
229            }
230            IdentifierKind::Var => {
231                let index = env.get_var_index(expr_identifier.lookup_name());
232
233                if index.is_some() {
234                    expr_identifier.2 = Some(Type::String);
235                }
236            }
237            IdentifierKind::Prompt => {
238                let index = env.get_prompt_index(expr_identifier.lookup_name());
239
240                if index.is_some() {
241                    expr_identifier.2 = Some(Type::String);
242                }
243            }
244            IdentifierKind::Secret => {
245                let index = env.get_secret_index(expr_identifier.lookup_name());
246
247                if index.is_some() {
248                    expr_identifier.2 = Some(Type::String);
249                }
250            }
251            IdentifierKind::Client => {
252                let index = env.get_client_context_index(expr_identifier.lookup_name());
253
254                if index.is_some() {
255                    expr_identifier.2 = Some(Type::String);
256                }
257            }
258            IdentifierKind::Type => {
259                //
260            }
261        },
262        Expr::Call(expr_call) => {
263            for arg in &mut expr_call.args {
264                add_type_to_expr(&mut arg.0, env);
265            }
266        }
267        _ => {}
268    }
269}