#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Range {
pub line: usize,
pub offset: usize,
pub end_offset: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Tag {
Id,
String,
Number,
Nil,
True,
False,
Dots,
Table,
Pair,
Function,
Index,
Call,
Invoke,
Paren,
Op,
If,
While,
Do,
Fornum,
Forin,
Repeat,
Set,
OpSet,
Local,
Localrec,
Label,
Return,
Break,
Goto,
}
pub type NodeId = usize;
#[derive(Clone, Debug)]
pub enum Item {
Node(NodeId),
Str(Vec<u8>),
}
#[derive(Clone, Debug)]
pub enum Resolution {
Unknown,
NotString,
Str(NodeId),
Index {
keys: Vec<Self>,
global: NodeId,
previous_indexing_len: Option<usize>,
},
}
#[derive(Clone, Debug, Default)]
pub struct Node {
pub tag: Option<Tag>,
pub range: Option<Range>,
pub items: Vec<Item>,
pub implicit: bool,
pub end_range: Option<Range>,
pub var: Option<usize>,
pub value: Option<usize>,
pub name: Option<Vec<u8>>,
pub resolution: Option<Resolution>,
pub contains_call: Option<bool>,
}
#[derive(Default)]
pub struct Ast {
pub nodes: Vec<Node>,
}
impl Ast {
pub fn add(&mut self, node: Node) -> NodeId {
self.nodes.push(node);
self.nodes.len() - 1
}
pub fn list(&mut self, items: Vec<NodeId>) -> NodeId {
self.add(Node {
items: items.into_iter().map(Item::Node).collect(),
..Node::default()
})
}
pub fn tag(&self, id: NodeId) -> Option<Tag> {
self.nodes[id].tag
}
pub fn is(&self, id: NodeId, tag: Tag) -> bool {
self.nodes[id].tag == Some(tag)
}
pub fn range(&self, id: NodeId) -> Range {
self.nodes[id].range.expect("node has a range")
}
pub fn len(&self, id: NodeId) -> usize {
self.nodes[id].items.len()
}
pub fn get(&self, id: NodeId, i: usize) -> Option<NodeId> {
match self.nodes[id].items.get(i.checked_sub(1)?) {
Some(Item::Node(n)) => Some(*n),
_ => None,
}
}
pub fn kid(&self, id: NodeId, i: usize) -> NodeId {
self.get(id, i).expect("child node")
}
pub fn str(&self, id: NodeId, i: usize) -> Option<&[u8]> {
match self.nodes[id].items.get(i.checked_sub(1)?) {
Some(Item::Str(s)) => Some(s),
_ => None,
}
}
pub fn kids(&self, id: NodeId) -> Vec<NodeId> {
self.nodes[id]
.items
.iter()
.filter_map(|item| match item {
Item::Node(n) => Some(*n),
Item::Str(_) => None,
})
.collect()
}
}