use crate::parse::traits::{Parameter, Visibility};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AstNode {
pub node_type: NodeType,
pub byte_range: std::ops::Range<usize>,
pub line_number: usize,
pub column_number: usize,
pub children: Vec<AstNode>,
pub metadata: NodeMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NodeType {
Module,
Function,
Class,
Method,
Variable,
Import,
Expression,
Statement,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMetadata {
pub name_range: Option<std::ops::Range<usize>>,
pub qualified_name: Option<String>,
pub visibility: Option<Visibility>,
pub docstring_range: Option<std::ops::Range<usize>>,
pub is_exported: bool,
}
impl AstNode {
pub fn new(
node_type: NodeType,
byte_range: std::ops::Range<usize>,
line_number: usize,
column_number: usize,
) -> Self {
Self {
node_type,
byte_range,
line_number,
column_number,
children: Vec::new(),
metadata: NodeMetadata {
name_range: None,
qualified_name: None,
visibility: None,
docstring_range: None,
is_exported: false,
},
}
}
pub fn add_child(&mut self, child: AstNode) {
self.children.push(child);
}
pub fn text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
if self.byte_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(format!(
"Byte range {}..{} out of bounds for source of length {}",
self.byte_range.start,
self.byte_range.end,
source.len()
)));
}
std::str::from_utf8(&source[self.byte_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)
}
pub fn name<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
if let Some(ref range) = self.metadata.name_range {
if range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(format!(
"Name range {}..{} out of bounds for source of length {}",
range.start,
range.end,
source.len()
)));
}
return std::str::from_utf8(&source[range.clone()])
.map_err(crate::parse::traits::Error::Utf8);
}
Err(crate::parse::traits::Error::ParseFailed(
"No name range set".to_string(),
))
}
pub fn docstring<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if let Some(ref range) = self.metadata.docstring_range {
if range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(format!(
"Docstring range {}..{} out of bounds for source of length {}",
range.start,
range.end,
source.len()
)));
}
let text = std::str::from_utf8(&source[range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?;
Ok(Some(text))
} else {
Ok(None)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionElement {
pub name_range: std::ops::Range<usize>,
pub qualified_name: String,
pub parameters: Vec<Parameter>,
pub return_type: Option<String>,
pub byte_range: std::ops::Range<usize>,
pub line_number: usize,
pub is_async: bool,
pub docstring_range: Option<std::ops::Range<usize>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassElement {
pub name_range: std::ops::Range<usize>,
pub qualified_name: String,
pub base_classes: Vec<String>,
pub methods: Vec<FunctionElement>,
pub byte_range: std::ops::Range<usize>,
pub line_number: usize,
pub docstring_range: Option<std::ops::Range<usize>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleElement {
pub name_range: std::ops::Range<usize>,
pub qualified_name: String,
pub functions: Vec<FunctionElement>,
pub classes: Vec<ClassElement>,
pub imports: Vec<Import>,
pub byte_range: std::ops::Range<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Import {
pub module_path: String,
pub items: Vec<String>,
pub alias: Option<String>,
pub byte_range: std::ops::Range<usize>,
pub line_number: usize,
}
pub trait ZeroCopyText {
fn get_text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error>;
fn get_name<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error>;
fn get_docstring<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error>;
}
impl ZeroCopyText for AstNode {
fn get_text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
self.text(source)
}
fn get_name<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if let Some(ref range) = self.metadata.name_range {
if range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Name range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
} else {
Ok(None)
}
}
fn get_docstring<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
self.docstring(source)
}
}
impl ZeroCopyText for FunctionElement {
fn get_text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
if self.byte_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Function byte range out of bounds".to_string(),
));
}
std::str::from_utf8(&source[self.byte_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)
}
fn get_name<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if self.name_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Function name range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[self.name_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
}
fn get_docstring<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if let Some(ref range) = self.docstring_range {
if range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Docstring range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
} else {
Ok(None)
}
}
}
impl ZeroCopyText for ClassElement {
fn get_text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
if self.byte_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Class byte range out of bounds".to_string(),
));
}
std::str::from_utf8(&source[self.byte_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)
}
fn get_name<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if self.name_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Class name range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[self.name_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
}
fn get_docstring<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if let Some(ref range) = self.docstring_range {
if range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Docstring range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
} else {
Ok(None)
}
}
}
impl ZeroCopyText for ModuleElement {
fn get_text<'source>(
&self,
source: &'source [u8],
) -> Result<&'source str, crate::parse::traits::Error> {
if self.byte_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Module byte range out of bounds".to_string(),
));
}
std::str::from_utf8(&source[self.byte_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)
}
fn get_name<'source>(
&self,
source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
if self.name_range.end > source.len() {
return Err(crate::parse::traits::Error::ParseFailed(
"Module name range out of bounds".to_string(),
));
}
Ok(Some(
std::str::from_utf8(&source[self.name_range.clone()])
.map_err(crate::parse::traits::Error::Utf8)?,
))
}
fn get_docstring<'source>(
&self,
_source: &'source [u8],
) -> Result<Option<&'source str>, crate::parse::traits::Error> {
Ok(None)
}
}