moon_script/parsing/
mod.rs

1use alloc::fmt::Debug;
2use alloc::string::{String, ToString};
3use alloc::vec::Vec;
4use core::mem;
5
6
7
8use pest::iterators::Pair;
9use pest_derive::Parser;
10use simple_detailed_error::SimpleError;
11
12use statement_parsing::WalkInput;
13
14use crate::engine::context::ContextBuilder;
15use crate::engine::Engine;
16use crate::execution::ast::{Statement, AST};
17use crate::execution::RuntimeVariable;
18use crate::function::{MoonFunction, ToAbstractFunction};
19use crate::value::FullValue;
20use crate::HashMap;
21use crate::HashSet;
22use crate::LazyLock;
23
24
25pub(crate) mod value_parsing;
26pub(crate) mod statement_parsing;
27pub mod error;
28
29#[derive(Parser)]
30#[grammar = "language_definition.pest"]
31pub(crate) struct SimpleParser;
32
33#[derive(Clone, Debug)]
34pub(crate) struct FunctionInfo {
35    can_inline_result: bool,
36    function: MoonFunction,
37    return_type_name: Option<String>,
38}
39
40impl FunctionInfo {
41    pub(crate) fn new<Dummy, Params, ReturnValue, Function, AbstractFunction: ToAbstractFunction<Params, ReturnValue, Function, Dummy>>
42    (function: AbstractFunction) -> Self {
43        Self::new_raw(function.abstract_function())
44    }
45
46    pub(crate) const fn new_raw(function: MoonFunction) -> Self {
47        Self { function, return_type_name: None, can_inline_result: false }
48    }
49
50    pub(crate) const fn inline(mut self) -> FunctionInfo {
51        self.can_inline_result = true;
52        self
53    }
54}
55
56/// Builder pattern for defining custom Engine's functions
57#[derive(Clone, Debug)]
58pub struct FunctionDefinition {
59    pub(crate) associated_type_name: Option<String>,
60    pub(crate) module_name: Option<String>,
61    pub(crate) function_name: String,
62    pub(crate) function_info: FunctionInfo,
63}
64
65impl FunctionDefinition {
66    /// Creates a new function with the name and function indicated as arguments.
67    ///
68    /// This for example defines a function called 'sum_two' that sums two **u8**s:
69    ///
70    /// ```rust
71    ///moon_script::FunctionDefinition::new("sum_two", |num:u8, other:u8| num+other);
72    /// ```
73    ///
74    /// You can use it this way:
75    ///
76    /// ```rust
77    /// use moon_script::{ContextBuilder, Engine, FunctionDefinition};
78    ///
79    /// let my_sum_function = FunctionDefinition::new("sum_two", |num:u8, other:u8| num+other);
80    ///
81    /// let mut engine = Engine::new();
82    /// engine.add_function(my_sum_function);
83    ///
84    /// let result = engine.parse("return sum_two(10,5);", ContextBuilder::new())
85    ///     .unwrap().execute().map(|value|u8::try_from(value)).unwrap().unwrap();
86    ///
87    /// assert_eq!(15, result);
88    /// ```
89    pub fn new<Name: Into<String>, Dummy, Params, ReturnValue, Function, AbstractFunction: ToAbstractFunction<Params, ReturnValue, Function, Dummy>>
90    (function_name: Name, function: AbstractFunction) -> Self {
91        let mut function_info = FunctionInfo::new_raw(function.abstract_function());
92        function_info.return_type_name = MoonValueKind::get_kind_string_of::<ReturnValue>();
93        Self {
94            function_info: function_info,
95            function_name: function_name.into(),
96            module_name: None,
97            associated_type_name: None,
98        }
99    }
100
101    /// Specifies the module name for this function.
102    pub fn module_name<Name: Into<String>>(mut self, module_name: Name) -> Self {
103        self.module_name = Some(module_name.into());
104        self
105    }
106
107    /// Specifies the associated type for this function.
108    ///
109    ///
110    /// This is a function associated to the moon script primitive Integer:
111    /// ```rust
112    /// moon_script::FunctionDefinition::new("sum_two", |num:u8, other:u8| num+other)
113    ///     .associated_type_name(moon_script::MoonValueKind::Integer);
114    /// ```
115    ///
116    /// This is a function associated to a custom type that can be read as an u8:
117    /// ```rust
118    /// moon_script::FunctionDefinition::new("sum_two", |num:u8, other:u8| num+other)
119    ///     .associated_type_name("MyCustomTypeName");
120    /// ```
121    ///
122    pub fn associated_type_name<'input, Name: Into<MoonValueKind<'input>>>(mut self, associated_type_name: Name) -> Self {
123        self.associated_type_name = associated_type_name.into().get_moon_value_type().map(|string| string.to_string());
124        self
125    }
126
127    /// Specifies the associated type for this function, but instead of receiving a name or a
128    /// [crate::MoonValueKind], it receives the value, this is preferred over
129    /// [Self::associated_type_name] but it doesn't allow you to create pseudo-types, requiring
130    /// the use of real types.
131    ///
132    /// ```
133    /// use moon_script::{ContextBuilder, Engine, FunctionDefinition, InputVariable};
134    /// let mut engine = Engine::new();
135    /// engine.add_function(FunctionDefinition::new("add_two", |n:u8|n+2).associated_type_of::<u8>());
136    /// let context_with_variable = ContextBuilder::new().with_variable(InputVariable::new("five").associated_type_of::<u8>());
137    /// let ast = engine.parse("five.add_two()", context_with_variable).unwrap();
138    ///
139    /// let result : u8 = ast.executor().push_variable("five", 5).execute().unwrap().try_into().unwrap();
140    ///
141    /// assert_eq!(7, result);
142    ///
143    /// ```
144    pub fn associated_type_of<T>(mut self) -> Self {
145        self.associated_type_name = MoonValueKind::get_kind_string_of::<T>();
146        self
147    }
148
149    /// Marks this function as constant, being able to inline it's results when compiling the script
150    /// if the arguments are also constant.
151    pub const fn inline(mut self) -> Self {
152        self.function_info.can_inline_result = true;
153        self
154    }
155
156    /// Specifies the type of the return value for this function, if let unmarked, associations
157    /// cannot be used and therefore properties won't work.
158    pub fn known_return_type_name<'input, Name: Into<MoonValueKind<'input>>>(mut self, return_type_name: Name) -> Self {
159        self.function_info.return_type_name = return_type_name.into().get_moon_value_type().map(|string| string.to_string());
160        self
161    }
162
163    /// Specifies the type of the return value for this function, but instead of receiving a name or
164    /// a [crate::MoonValueKind], it receives the value, this is preferred over
165    /// [Self::known_return_type_name] but it doesn't allow you to create pseudo-types, requiring
166    /// the use of real types.
167    pub fn known_return_type_of<T>(mut self) -> Self {
168        self.function_info.return_type_name = MoonValueKind::get_kind_string_of::<T>();
169        self
170    }
171}
172
173
174struct Privatize;
175
176/// Types of Moon values
177pub enum MoonValueKind<'selflf> {
178    Null,
179    Boolean,
180    Integer,
181    Decimal,
182    String,
183    Array,
184    Function,
185    Invalid,
186    #[allow(private_interfaces)]
187    CustomStr(&'selflf str, Privatize),
188    #[allow(private_interfaces)]
189    CustomString(String, Privatize),
190}
191
192static RESERVED_MOON_VALUE_KINDS: LazyLock<HashSet<String>> = LazyLock::new(|| {
193    [MoonValueKind::Null, MoonValueKind::Boolean, MoonValueKind::Integer,
194        MoonValueKind::Decimal, MoonValueKind::String, MoonValueKind::Array,
195        MoonValueKind::Function]
196        .map(|value_kind| value_kind.get_moon_value_type().unwrap().to_string())
197        .into_iter()
198        .collect::<HashSet<String>>()
199});
200
201pub(crate) static RUST_TYPES_TO_MOON_VALUE_KINDS: LazyLock<HashMap<&'static str, String>> = LazyLock::new(|| {
202    [
203        (core::any::type_name::<()>(), MoonValueKind::Null),
204        (core::any::type_name::<bool>(), MoonValueKind::Boolean),
205        (core::any::type_name::<i8>(), MoonValueKind::Integer),
206        (core::any::type_name::<i16>(), MoonValueKind::Integer),
207        (core::any::type_name::<i32>(), MoonValueKind::Integer),
208        (core::any::type_name::<i64>(), MoonValueKind::Integer),
209        (core::any::type_name::<i128>(), MoonValueKind::Integer),
210        (core::any::type_name::<isize>(), MoonValueKind::Integer),
211        (core::any::type_name::<u8>(), MoonValueKind::Integer),
212        (core::any::type_name::<u16>(), MoonValueKind::Integer),
213        (core::any::type_name::<u32>(), MoonValueKind::Integer),
214        (core::any::type_name::<u64>(), MoonValueKind::Integer),
215        (core::any::type_name::<u128>(), MoonValueKind::Integer),
216        (core::any::type_name::<usize>(), MoonValueKind::Integer),
217        (core::any::type_name::<f32>(), MoonValueKind::Decimal),
218        (core::any::type_name::<f64>(), MoonValueKind::Decimal),
219        (core::any::type_name::<String>(), MoonValueKind::String),
220    ]
221        .map(|(rust_type, moon_value_kind)| {
222            (rust_type, moon_value_kind.get_moon_value_type().unwrap().to_string())
223        })
224        .into_iter()
225        .collect()
226});
227
228
229static RESULT_TYPE_PREFIX: LazyLock<String> = LazyLock::new(|| {
230    let result = core::any::type_name::<Result<(), ()>>();
231    let result_start = result.find(r"<").unwrap();
232    result[0..result_start + 1].to_string()
233});
234
235fn decouple_ok_argument_from_its_result(type_in_use: &str) -> Option<&str> {
236    if !type_in_use.starts_with(&*RESULT_TYPE_PREFIX) { return None; };
237
238    let type_in_use = &type_in_use[RESULT_TYPE_PREFIX.len()..];
239    let mut opened_brackets_and_diamonds = 0_usize;
240    let end = type_in_use.chars().enumerate().filter(|(_, char)| {
241        match char {
242            '(' | '<' => opened_brackets_and_diamonds += 1,
243            ')' | '>' => opened_brackets_and_diamonds -= 1,
244            ',' => return true,
245            _ => {}
246        }
247        false
248    }).next().unwrap().0;
249    Some(&type_in_use[..end])
250}
251
252impl MoonValueKind<'_> {
253    pub(crate) fn get_kind_string_of<T>() -> Option<String> {
254        RUST_TYPES_TO_MOON_VALUE_KINDS
255            .get(core::any::type_name::<T>()).cloned()
256            .map(|string|
257                decouple_ok_argument_from_its_result(&string).map(|s| s.to_string()).unwrap_or(string)
258            )
259            .or_else(||
260                MoonValueKind::from(core::any::type_name::<T>())
261                    .get_moon_value_type().map(|string| string.to_string())
262            )
263            .filter(|name| !name.eq("null"))
264    }
265
266    pub(crate) fn get_moon_value_type(&self) -> Option<&str> {
267        Some(match self {
268            MoonValueKind::Null => "null",
269            MoonValueKind::Boolean => "bool",
270            MoonValueKind::Integer => "int",
271            MoonValueKind::Decimal => "decimal",
272            MoonValueKind::String => "string",
273            MoonValueKind::Array => "array",
274            MoonValueKind::Function => "function",
275            MoonValueKind::Invalid => return None,
276            MoonValueKind::CustomStr(str, _) => str,
277            MoonValueKind::CustomString(str, _) => str
278        })
279    }
280}
281
282impl<'typename> From<&'typename str> for MoonValueKind<'typename> {
283    fn from(value: &'typename str) -> Self {
284        if RESERVED_MOON_VALUE_KINDS.contains(value) {
285            return Self::Invalid;
286        }
287        Self::CustomStr(value, Privatize)
288    }
289}
290
291impl From<String> for MoonValueKind<'_> {
292    fn from(value: String) -> Self {
293        if RESERVED_MOON_VALUE_KINDS.contains(&value) {
294            return Self::Invalid;
295        }
296        Self::CustomString(value, Privatize)
297    }
298}
299
300fn optimize_variables(context: &mut ContextBuilder, inlineable_variables: Vec<(String, usize)>, statements: &mut Vec<Statement>) -> (Vec<RuntimeVariable>, HashMap<String, usize>) {
301    let variables = context.take_all_variables();
302    let mut variables = variables.into_iter()
303        .flat_map(|(block_level, variables)| {
304            variables.into_iter().enumerate()
305                .map(move |(var_index, variable)| ((block_level, var_index), variable))
306        }).collect::<HashMap<_, _>>();
307
308
309    let mut used_variables = HashMap::new();
310    statements.iter_mut().for_each(|statement| {
311        statement_parsing::walk_statement(&mut |input| {
312            match input {
313                WalkInput::Statement(block) => {
314                    match block {
315                        Statement::UnoptimizedAssignament { block_level, var_index, .. } => {
316                            if !used_variables.contains_key(&(*block_level, *var_index)) {
317                                log::trace!("Found used variable of block {block_level} and index {var_index}");
318                                let variable = variables.remove(&(*block_level, *var_index)).unwrap();
319                                log::trace!(" - Variable: {variable:?})");
320                                used_variables.insert((*block_level, *var_index), variable);
321                            }
322                        }
323                        _ => {}
324                    }
325                }
326                WalkInput::Value(value) => {
327                    match value {
328                        FullValue::Variable { block_level, var_index } => {
329                            if !used_variables.contains_key(&(*block_level, *var_index)) {
330                                log::trace!("Found used variable of block {block_level} and index {var_index}");
331                                let variable = variables.remove(&(*block_level, *var_index)).unwrap();
332                                log::trace!(" - Variable: {variable:?})");
333                                used_variables.insert((*block_level, *var_index), variable);
334                            }
335                        }
336                        _ => {}
337                    }
338                }
339            }
340        }, statement)
341    });
342    let mut used_variables = used_variables.into_iter().collect::<Vec<_>>();
343
344    used_variables.sort_by(|((block_a, index_a), _), ((block_b, index_b), _)| {
345        block_a.cmp(block_b).then_with(|| index_a.cmp(index_b))
346    });
347
348    let used_variables_and_new_indexes = used_variables.into_iter()
349        .enumerate()
350        .map(|(index, ((block_level, var_level), variable))| ((block_level, var_level), (index, variable)))
351        .collect::<HashMap<_, _>>();
352
353    let parameterized_variables = inlineable_variables.into_iter()
354        .filter(|(_, index)| used_variables_and_new_indexes.contains_key(&(0, *index)))
355        .map(|(name, index)| {
356            let final_variable_index = used_variables_and_new_indexes.get(&(0, index)).unwrap().0;
357            (name, final_variable_index)
358        })
359        .collect();
360
361    statements.iter_mut().for_each(|statement| {
362        statement_parsing::walk_statement(&mut |input| {
363            match input {
364                WalkInput::Statement(block) => {
365                    match block {
366                        Statement::UnoptimizedAssignament { block_level, var_index, value } => {
367                            let direct_index = used_variables_and_new_indexes.get(&(*block_level, *var_index)).unwrap().0;
368                            log::trace!("Substitued variable of assignament for block {block_level} and index {var_index} for simplified index {direct_index}");
369                            *block = Statement::OptimizedAssignament { var_index: direct_index, value: mem::replace(value, FullValue::Null) };
370                        }
371                        _ => {}
372                    }
373                }
374                WalkInput::Value(value) => {
375                    match value {
376                        FullValue::Variable { block_level, var_index } => {
377                            let direct_index = used_variables_and_new_indexes.get(&(*block_level, *var_index)).unwrap().0;
378                            log::trace!("Substitued variable of value for block {block_level} and index {var_index} for simplified index {direct_index}");
379                            *value = FullValue::DirectVariable(direct_index);
380                        }
381                        _ => {}
382                    }
383                }
384            }
385        }, statement)
386    });
387
388    let mut used_variables_and_new_indexes = used_variables_and_new_indexes.into_iter()
389        .map(|(_, variable)| variable)
390        .collect::<Vec<_>>();
391    used_variables_and_new_indexes.sort_by_key(|(index, _)| *index);
392
393    let variables = used_variables_and_new_indexes.into_iter()
394        .map(|(_, variable)| RuntimeVariable { value: variable.first_value })
395        .collect::<Vec<_>>();
396    (variables, parameterized_variables)
397}
398
399pub(crate) fn build_ast<'input>(token: Pair<'input, Rule>, base: &Engine, mut context: ContextBuilder) -> Result<AST, Vec<SimpleError<'input>>> {
400    if token.as_rule() != Rule::BASE_STATEMENTS {}
401    let statements_tokens = token.into_inner().next().unwrap();
402    context.started_parsing = true;
403    let inlineable_variables = context.in_use_variables.get(0).map(|(_, variables)| {
404        variables.iter().enumerate()
405            .filter(|(_, variable)| { variable.current_known_value.is_none() })
406            .map(|(block_0_var_index, variable)| (variable.name.clone(), block_0_var_index))
407            .collect::<Vec<_>>()
408    }).unwrap_or_default();
409    let mut statements = statement_parsing::build_token(statements_tokens, base, &mut context, true)?;
410    replace_last_fn_call_for_return_statement(&mut statements);
411
412    let (variables, parameterized_variables) = optimize_variables(&mut context, inlineable_variables, &mut statements);
413    Ok(AST { statements, variables, parameterized_variables })
414}
415
416fn replace_last_fn_call_for_return_statement(statements: &mut Vec<Statement>) {
417    if let Some(last_statement) = statements.last_mut() {
418        let is_fn_call = match last_statement {
419            Statement::FnCall(_) => true,
420            _ => false,
421        };
422        if is_fn_call {
423            let fn_call = match mem::replace(last_statement, Statement::ReturnCall(FullValue::Null)) {
424                Statement::FnCall(function) => function,
425                _ => unreachable!()
426            };
427            *last_statement = Statement::ReturnCall(FullValue::Function(fn_call));
428        }
429    }
430}
431
432fn line_and_column_of_token(token: &Pair<Rule>, context: &mut ContextBuilder) -> (usize, usize) {
433    let mut line_and_column = token.line_col();
434    if context.parsing_position_column_is_fixed || line_and_column.0 <= 1 {
435        line_and_column = (line_and_column.0 + context.start_parsing_position_offset.0, line_and_column.1 + context.start_parsing_position_offset.1)
436    } else {
437        line_and_column = (line_and_column.0 + context.start_parsing_position_offset.0, line_and_column.1)
438    }
439    line_and_column
440}
441
442
443pub(crate) trait AddSourceOfError<'input> {
444    fn add_where_error(self, input: &'input str, line_and_column: (usize, usize)) -> Self;
445}
446
447
448impl<'input, V> AddSourceOfError<'input> for Result<V, Vec<SimpleError<'input>>> {
449    fn add_where_error(self, input: &'input str, line_and_column: (usize, usize)) -> Self {
450        self.map_err(|errors| errors.into_iter().map(|error| {
451            if error.current_at().is_none() { error.at(input).start_point_of_error(line_and_column.0, line_and_column.1) } else { error }
452        }).collect::<Vec<_>>())
453    }
454}