python_ast/ast/tree/
name.rs1use proc_macro2::TokenStream;
2use pyo3::{FromPyObject, PyErr};
3use quote::{format_ident, quote};
4
5use crate::{CodeGen, CodeGenContext, IsIdentifier, PythonOptions, SymbolTableScopes};
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Default, Eq, FromPyObject, Hash, PartialEq, Serialize, Deserialize)]
11#[repr(transparent)]
12pub struct Identifier(String);
13
14impl TryFrom<&str> for Identifier {
15 type Error = PyErr;
16
17 fn try_from(value: &str) -> Result<Self, Self::Error> {
18 if value.isidentifier()? {
19 Ok(Identifier(value.to_string()))
20 } else {
21 Err(PyErr::new::<pyo3::exceptions::PyNameError, _>(format!(
22 "Invalid Identifier: {}",
23 String::from(value)
24 )))
25 }
26 }
27}
28
29impl AsRef<str> for Identifier {
30 fn as_ref(&self) -> &str {
31 self.0.as_str()
32 }
33}
34
35impl Into<String> for Identifier {
36 fn into(self) -> String {
37 self.0
38 }
39}
40
41#[derive(Clone, Debug, Default, Eq, FromPyObject, Hash, PartialEq, Serialize, Deserialize)]
43pub struct Name {
44 pub id: String,
45}
46
47impl TryFrom<&str> for Name {
48 type Error = PyErr;
49
50 fn try_from(s: &str) -> Result<Self, Self::Error> {
51 let parts = s.split('.');
52 log::debug!("parts: {:?}", parts);
53
54 let mut v = Vec::new();
55 for part in parts {
56 let ident = Identifier::try_from(part)?;
57 v.push(String::from(ident.as_ref()));
58 }
59
60 Ok(Name { id: v.join(".") })
61 }
62}
63
64impl AsRef<str> for Name {
65 fn as_ref(&self) -> &str {
66 self.id.as_str()
67 }
68}
69
70impl Into<String> for Name {
71 fn into(self) -> String {
72 self.id
73 }
74}
75
76impl CodeGen for Name {
77 type Context = CodeGenContext;
78 type Options = PythonOptions;
79 type SymbolTable = SymbolTableScopes;
80
81 fn to_rust(
82 self,
83 _ctx: Self::Context,
84 _options: Self::Options,
85 _symbols: Self::SymbolTable,
86 ) -> Result<TokenStream, Box<dyn std::error::Error>> {
87 if self.id.contains('.') {
89 let parts: Vec<&str> = self.id.split('.').collect();
90 let idents: Vec<_> = parts.iter().map(|part| format_ident!("{}", part)).collect();
91 Ok(quote!(#(#idents)::*))
92 } else {
93 let name = format_ident!("{}", self.id);
94 Ok(quote!(#name))
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn good_name_works() {
105 let name = Name::try_from("this.symbol");
106 assert!(name.is_ok());
107 }
108
109 #[test]
110 fn bad_name_works() {
111 let name = Name::try_from("this.0symbol");
112 assert!(name.is_err());
113 }
114}