Refactor NodeIdentity to use unique IDs
The `NodeIdentity` struct has been refactored to use a unique `id` field generated by an atomic counter. This ensures that each `NodeIdentity` instance is distinct, even if it has the same `SourceLocation`. The `location` field is now optional, allowing for anonymous nodes. This change improves the reliability of identity comparisons and provides a more robust way to manage AST node identities.
This commit is contained in:
@@ -130,9 +130,7 @@ impl Binder {
|
|||||||
};
|
};
|
||||||
binder.functions.push(FunctionCompiler::new(
|
binder.functions.push(FunctionCompiler::new(
|
||||||
ScopeKind::Root,
|
ScopeKind::Root,
|
||||||
Rc::new(crate::ast::types::NodeIdentity {
|
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation { line: 0, col: 0 }),
|
||||||
location: crate::ast::types::SourceLocation { line: 0, col: 0 },
|
|
||||||
}),
|
|
||||||
));
|
));
|
||||||
binder
|
binder
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,9 +101,10 @@ impl Dumper {
|
|||||||
if !captured_by.is_empty() {
|
if !captured_by.is_empty() {
|
||||||
for capturer in captured_by {
|
for capturer in captured_by {
|
||||||
self.write_indent();
|
self.write_indent();
|
||||||
|
let loc = capturer.location.unwrap_or(crate::ast::types::SourceLocation { line: 0, col: 0 });
|
||||||
self.output.push_str(&format!(
|
self.output.push_str(&format!(
|
||||||
"- Capturer: Lambda at line {}, col {}\n",
|
"- Capturer: Lambda at line {}, col {}\n",
|
||||||
capturer.location.line, capturer.location.col
|
loc.line, loc.col
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -717,9 +717,7 @@ mod tests {
|
|||||||
Symbol::from("*"),
|
Symbol::from("*"),
|
||||||
(
|
(
|
||||||
0,
|
0,
|
||||||
Rc::new(crate::ast::types::NodeIdentity {
|
crate::ast::types::NodeIdentity::new(crate::ast::types::SourceLocation { line: 0, col: 0 }),
|
||||||
location: crate::ast::types::SourceLocation { line: 0, col: 0 },
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
let globals = Rc::new(RefCell::new(global_names));
|
let globals = Rc::new(RefCell::new(global_names));
|
||||||
|
|||||||
@@ -134,9 +134,7 @@ impl Environment {
|
|||||||
let mut purity = self.global_purity.borrow_mut();
|
let mut purity = self.global_purity.borrow_mut();
|
||||||
|
|
||||||
let idx = values.len() as u32;
|
let idx = values.len() as u32;
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 });
|
||||||
location: SourceLocation { line: 0, col: 0 },
|
|
||||||
});
|
|
||||||
names.insert(Symbol::from(name), (idx, identity));
|
names.insert(Symbol::from(name), (idx, identity));
|
||||||
types.insert(idx, ty);
|
types.insert(idx, ty);
|
||||||
purity.insert(idx, func.purity);
|
purity.insert(idx, func.purity);
|
||||||
@@ -167,9 +165,7 @@ impl Environment {
|
|||||||
let mut purity = self.global_purity.borrow_mut();
|
let mut purity = self.global_purity.borrow_mut();
|
||||||
|
|
||||||
let idx = values.len() as u32;
|
let idx = values.len() as u32;
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(SourceLocation { line: 0, col: 0 });
|
||||||
location: SourceLocation { line: 0, col: 0 },
|
|
||||||
});
|
|
||||||
names.insert(Symbol::from(name), (idx, identity));
|
names.insert(Symbol::from(name), (idx, identity));
|
||||||
types.insert(idx, ty);
|
types.insert(idx, ty);
|
||||||
purity.insert(idx, Purity::Pure);
|
purity.insert(idx, Purity::Pure);
|
||||||
|
|||||||
+7
-21
@@ -29,9 +29,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
pub fn parse_expression(&mut self) -> Result<Node<UntypedKind>, String> {
|
pub fn parse_expression(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||||
let token_loc = self.current_token.location;
|
let token_loc = self.current_token.location;
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(token_loc);
|
||||||
location: token_loc,
|
|
||||||
});
|
|
||||||
|
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
TokenKind::LeftParen => self.parse_list(),
|
TokenKind::LeftParen => self.parse_list(),
|
||||||
@@ -93,9 +91,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn parse_atom(&mut self) -> Result<Node<UntypedKind>, String> {
|
fn parse_atom(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||||
let token = self.advance()?;
|
let token = self.advance()?;
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(token.location);
|
||||||
location: token.location,
|
|
||||||
});
|
|
||||||
|
|
||||||
let kind = match token.kind {
|
let kind = match token.kind {
|
||||||
TokenKind::Integer(n) => UntypedKind::Constant(Value::Int(n)),
|
TokenKind::Integer(n) => UntypedKind::Constant(Value::Int(n)),
|
||||||
@@ -123,9 +119,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn parse_list(&mut self) -> Result<Node<UntypedKind>, String> {
|
fn parse_list(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||||
let start_loc = self.advance()?.location; // consume '('
|
let start_loc = self.advance()?.location; // consume '('
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(start_loc);
|
||||||
location: start_loc,
|
|
||||||
});
|
|
||||||
|
|
||||||
if *self.peek() == TokenKind::RightParen {
|
if *self.peek() == TokenKind::RightParen {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
@@ -272,18 +266,14 @@ impl<'a> Parser<'a> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Ok(Node {
|
Ok(Node {
|
||||||
identity: Rc::new(NodeIdentity {
|
identity: NodeIdentity::new(token.location),
|
||||||
location: token.location,
|
|
||||||
}),
|
|
||||||
kind: UntypedKind::Parameter(sym),
|
kind: UntypedKind::Parameter(sym),
|
||||||
ty: (),
|
ty: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TokenKind::LeftBracket => {
|
TokenKind::LeftBracket => {
|
||||||
let token = self.advance()?;
|
let token = self.advance()?;
|
||||||
let identity = Rc::new(NodeIdentity {
|
let identity = NodeIdentity::new(token.location);
|
||||||
location: token.location,
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
while *self.peek() != TokenKind::RightBracket {
|
while *self.peek() != TokenKind::RightBracket {
|
||||||
@@ -344,9 +334,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.expect(TokenKind::RightBracket)?;
|
self.expect(TokenKind::RightBracket)?;
|
||||||
|
|
||||||
Ok(Node {
|
Ok(Node {
|
||||||
identity: Rc::new(NodeIdentity {
|
identity: NodeIdentity::new(token.location),
|
||||||
location: token.location,
|
|
||||||
}),
|
|
||||||
kind: UntypedKind::Tuple { elements },
|
kind: UntypedKind::Tuple { elements },
|
||||||
ty: (),
|
ty: (),
|
||||||
})
|
})
|
||||||
@@ -380,9 +368,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.expect(TokenKind::RightBrace)?;
|
self.expect(TokenKind::RightBrace)?;
|
||||||
|
|
||||||
Ok(Node {
|
Ok(Node {
|
||||||
identity: Rc::new(NodeIdentity {
|
identity: NodeIdentity::new(token.location),
|
||||||
location: token.location,
|
|
||||||
}),
|
|
||||||
kind: UntypedKind::Record { fields },
|
kind: UntypedKind::Record { fields },
|
||||||
ty: (),
|
ty: (),
|
||||||
})
|
})
|
||||||
|
|||||||
+43
-3
@@ -14,14 +14,54 @@ pub struct SourceLocation {
|
|||||||
pub col: u32,
|
pub col: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shared identity for nodes (Location, etc.)
|
/// Shared identity for nodes. The identity is defined by the object instance (unique ID).
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
/// SourceLocation is kept as optional metadata.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct NodeIdentity {
|
pub struct NodeIdentity {
|
||||||
pub location: SourceLocation,
|
pub id: u64,
|
||||||
|
pub location: Option<SourceLocation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for NodeIdentity {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for NodeIdentity {}
|
||||||
|
|
||||||
|
impl std::hash::Hash for NodeIdentity {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.id.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Identity = Rc<NodeIdentity>;
|
pub type Identity = Rc<NodeIdentity>;
|
||||||
|
|
||||||
|
static NODE_ID_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
|
||||||
|
|
||||||
|
impl NodeIdentity {
|
||||||
|
pub fn next_id() -> u64 {
|
||||||
|
NODE_ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new unique identity at the given location.
|
||||||
|
pub fn new(location: SourceLocation) -> Identity {
|
||||||
|
Rc::new(NodeIdentity {
|
||||||
|
id: Self::next_id(),
|
||||||
|
location: Some(location),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new unique identity without location metadata (for synthetic nodes).
|
||||||
|
pub fn anonymous() -> Identity {
|
||||||
|
Rc::new(NodeIdentity {
|
||||||
|
id: Self::next_id(),
|
||||||
|
location: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Interned string identifier
|
/// Interned string identifier
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct Keyword(pub u32);
|
pub struct Keyword(pub u32);
|
||||||
|
|||||||
Reference in New Issue
Block a user