Skip to main content

yog_script_analyze/ast/
indexer.rs

1//! An indexer (`T this[i32 i] { get; set; }`): what `x[i]` reads and
2//! writes. Its accessors are methods named as the CLR names them —
3//! `get_Item(i)`, `set_Item(i, value)` — so inheritance and the JVM treat
4//! them as any method.
5
6use super::{Accessor, Method, MethodBody, Name, Param, Type, value_param};
7use crate::source::token::Span;
8use crate::system::INDEXER;
9use crate::words::{get, set};
10
11/// What joins an accessor's word to the indexer's name (`get_Item`).
12const ACCESSOR_SEP: char = '_';
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Indexer {
16    pub ty: Type,
17    pub params: Vec<Param>,
18    pub accessors: Vec<Accessor>,
19    pub span: Span,
20}
21
22/// An indexer's accessor's method name: `get_Item`, `set_Item`.
23pub fn accessor_name(word: &str) -> String {
24    format!("{word}{ACCESSOR_SEP}{INDEXER}")
25}
26
27impl Indexer {
28    /// Its `get` as a method: what `x[i]` calls.
29    pub fn getter(&self) -> Option<Method> {
30        let body = self.accessor(get::WORD.text)?;
31        Some(self.method(
32            get::WORD.text,
33            Some(self.ty.clone()),
34            self.params.clone(),
35            body,
36        ))
37    }
38
39    /// Its `set` as a method, the value its last parameter: what `x[i] = v` calls.
40    pub fn setter(&self) -> Option<Method> {
41        let body = self.accessor(set::WORD.text)?;
42        let mut params = self.params.clone();
43        let at = Name {
44            text: set::WORD.text.to_string(),
45            span: self.span,
46        };
47        params.push(value_param(&self.ty, &at));
48        Some(self.method(set::WORD.text, None, params, body))
49    }
50
51    /// Accessor `word`'s body (none when it has none), if it has that accessor.
52    fn accessor(&self, word: &str) -> Option<Option<MethodBody>> {
53        self.accessors
54            .iter()
55            .find(|a| a.name.text == word)
56            .map(|a| a.body.clone())
57    }
58
59    fn method(
60        &self,
61        word: &str,
62        ret: Option<Type>,
63        params: Vec<Param>,
64        body: Option<MethodBody>,
65    ) -> Method {
66        Method {
67            ret,
68            name: Name {
69                text: accessor_name(word),
70                span: self.span,
71            },
72            generics: Vec::new(),
73            params,
74            constraints: Vec::new(),
75            requires: None,
76            body,
77        }
78    }
79}