Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/green_tree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,17 @@ end

Base.summary(node::GreenNode) = summary(node.head)

Base.hash(node::GreenNode, h::UInt) = hash((node.head, node.span, node.children), h)
function Base.hash(node::GreenNode, h::UInt)
children = node.children
if children === nothing
h = hash(nothing, h)
else # optimization - avoid extra allocations from `hash(::AbstractVector, ::UInt)`
for child in children
h = hash(child, h)
end
end
hash(node.head, hash(node.span, h))
end
function Base.:(==)(n1::GreenNode, n2::GreenNode)
n1.head == n2.head && n1.span == n2.span && n1.children == n2.children
end
Expand Down Expand Up @@ -129,4 +139,3 @@ function build_tree(::Type{GreenNode}, stream::ParseStream; kws...)
GreenNode(h, span, collect(GreenNode{SyntaxHead}, cs))
end
end

3 changes: 2 additions & 1 deletion src/source_files.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ struct SourceFile
line_starts::Vector{Int}
end

Base.hash(s::SourceFile, h::UInt) = hash((s.code, s.byte_offset, s.filename, s.first_line, s.line_starts), h)
Base.hash(s::SourceFile, h::UInt) =
hash(s.code, hash(s.byte_offset, hash(s.filename, hash(s.first_line, hash(s.line_starts, h)))))
function Base.:(==)(a::SourceFile, b::SourceFile)
a.code == b.code && a.byte_offset == b.byte_offset && a.filename == b.filename &&
a.first_line == b.first_line && a.line_starts == b.line_starts
Expand Down
22 changes: 19 additions & 3 deletions src/syntax_tree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,18 @@ mutable struct TreeNode{NodeData} # ? prevent others from using this with Node
end

# Exclude parent from hash and equality checks. This means that subtrees can compare equal.
Base.hash(node::TreeNode, h::UInt) = hash((node.children, node.data), h)
function Base.hash(node::TreeNode, h::UInt)
h = hash(node.data, h)
children = node.children
if children === nothing
return hash(nothing, h)
else # optimization - avoid extra allocations from `hash(::AbstractVector, ::UInt)`
for child in children
h = hash(child, h)
end
return h
end
end
function Base.:(==)(a::TreeNode{T}, b::TreeNode{T}) where T
a.children == b.children && a.data == b.data
end
Expand Down Expand Up @@ -50,9 +61,14 @@ struct SyntaxData <: AbstractSyntaxData
val::Any
end

Base.hash(data::SyntaxData, h::UInt) = hash((data.source, data.raw, data.position, data.val), h)
Base.hash(data::SyntaxData, h::UInt) =
hash(data.source, hash(data.raw, hash(data.position,
# Avoid dynamic dispatch:
# This does not support custom `hash` implementation that may be defined for `typeof(data.val)`,
# However, such custom user types should not generally appear in the AST.
Core.invoke(hash, Tuple{Any,UInt}, data.val, h))))
function Base.:(==)(a::SyntaxData, b::SyntaxData)
a.source == b.source && a.raw == b.raw && a.position == b.position && a.val == b.val
a.source == b.source && a.raw == b.raw && a.position == b.position && a.val === b.val
end

"""
Expand Down
Loading