pub mod node;
use self::node::Node;
use crate::grammar::{Element, NamedSymbol, Primitive};
use crate::utils::ptr_util::{OwnedPtr, WeakPtr};
use std::collections::HashMap;
#[derive(Debug)]
pub struct Ast {
elements: Vec<Node>,
lookup_table: HashMap<String, usize>,
}
impl Ast {
pub fn create() -> Ast {
let elements = vec![
Node::Primitive(OwnedPtr::new(Primitive::Bool)),
Node::Primitive(OwnedPtr::new(Primitive::Int8)),
Node::Primitive(OwnedPtr::new(Primitive::UInt8)),
Node::Primitive(OwnedPtr::new(Primitive::Int16)),
Node::Primitive(OwnedPtr::new(Primitive::UInt16)),
Node::Primitive(OwnedPtr::new(Primitive::Int32)),
Node::Primitive(OwnedPtr::new(Primitive::UInt32)),
Node::Primitive(OwnedPtr::new(Primitive::VarInt32)),
Node::Primitive(OwnedPtr::new(Primitive::VarUInt32)),
Node::Primitive(OwnedPtr::new(Primitive::Int64)),
Node::Primitive(OwnedPtr::new(Primitive::UInt64)),
Node::Primitive(OwnedPtr::new(Primitive::VarInt62)),
Node::Primitive(OwnedPtr::new(Primitive::VarUInt62)),
Node::Primitive(OwnedPtr::new(Primitive::Float32)),
Node::Primitive(OwnedPtr::new(Primitive::Float64)),
Node::Primitive(OwnedPtr::new(Primitive::String)),
Node::Primitive(OwnedPtr::new(Primitive::AnyClass)),
];
let lookup_table = HashMap::from([
("bool".to_owned(), 0),
("int8".to_owned(), 1),
("uint8".to_owned(), 2),
("int16".to_owned(), 3),
("uint16".to_owned(), 4),
("int32".to_owned(), 5),
("uint32".to_owned(), 6),
("varint32".to_owned(), 7),
("varuint32".to_owned(), 8),
("int64".to_owned(), 9),
("uint64".to_owned(), 10),
("varint62".to_owned(), 11),
("varuint62".to_owned(), 12),
("float32".to_owned(), 13),
("float64".to_owned(), 14),
("string".to_owned(), 15),
("AnyClass".to_owned(), 16),
]);
Ast { elements, lookup_table }
}
pub fn find_node<'a>(&'a self, identifier: &str) -> Result<&'a Node, LookupError> {
self.lookup_table
.get(identifier)
.map(|i| &self.elements[*i])
.ok_or_else(|| LookupError::DoesNotExist {
identifier: identifier.to_owned(),
})
}
pub fn find_node_with_scope<'a>(&'a self, identifier: &str, scope: &str) -> Result<&'a Node, LookupError> {
if let Some(unprefixed_identifier) = identifier.strip_prefix("::") {
return self.find_node(unprefixed_identifier);
}
let mut scopes = scope.split("::").collect::<Vec<_>>();
while !scopes.is_empty() {
let candidate = scopes.join("::") + "::" + identifier;
if let Some(i) = self.lookup_table.get(&candidate) {
return Ok(&self.elements[*i]);
}
scopes.pop();
}
self.find_node(identifier)
}
pub fn find_element<'a, T: Element + ?Sized>(&'a self, identifier: &str) -> Result<&'a T, LookupError>
where
&'a T: TryFrom<&'a Node, Error = LookupError>,
{
self.find_node(identifier).and_then(|x| x.try_into())
}
pub fn find_element_with_scope<'a, T: Element + ?Sized>(
&'a self,
identifier: &str,
scope: &str,
) -> Result<&'a T, LookupError>
where
&'a T: TryFrom<&'a Node, Error = LookupError>,
{
self.find_node_with_scope(identifier, scope).and_then(|x| x.try_into())
}
pub fn as_slice(&self) -> &[Node] {
self.elements.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [Node] {
self.elements.as_mut_slice()
}
pub(crate) fn add_element<T: Element>(&mut self, element: OwnedPtr<T>) -> WeakPtr<T>
where
OwnedPtr<T>: Into<Node>,
{
let weak_ptr = element.downgrade();
self.elements.push(element.into());
weak_ptr
}
pub(crate) fn add_named_element<T: NamedSymbol>(&mut self, element: OwnedPtr<T>) -> WeakPtr<T>
where
OwnedPtr<T>: Into<Node>,
{
let scoped_identifier = element.borrow().parser_scoped_identifier();
self.lookup_table.insert(scoped_identifier, self.elements.len());
self.add_element(element)
}
}
impl Default for Ast {
fn default() -> Self {
Self::create()
}
}
#[derive(Debug)]
pub enum LookupError {
DoesNotExist {
identifier: String,
},
TypeMismatch {
expected: String,
actual: String,
is_concrete: bool,
},
}