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 println!("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 let name = format_ident!("{}", self.id);
88 Ok(quote!(#name))
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn good_name_works() {
98 let name = Name::try_from("this.symbol");
99 assert!(name.is_ok());
100 }
101
102 #[test]
103 fn bad_name_works() {
104 let name = Name::try_from("this.0symbol");
105 assert!(name.is_err());
106 }
107}