Skip to content

Commit

Permalink
Add metadata tags to the Node struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre committed Jun 1, 2024
1 parent 5a9f8ad commit 86e52bb
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 11 deletions.
13 changes: 11 additions & 2 deletions src/Runic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ include("debug.jl")
# Node #
########

const TagType = UInt32

# This is essentially just a re-packed `JuliaSyntax.GreenNode`.
struct Node
# The next three fields directly match JuliaSyntax.GreenNode. We can not store a
Expand All @@ -29,20 +31,27 @@ struct Node
head::JuliaSyntax.SyntaxHead
span::UInt32
kids::Union{Tuple{}, Vector{Node}}
# Metadata for the formatter
tags::TagType
end

function Node(head::JuliaSyntax.SyntaxHead, span::Integer)
return Node(head, span % UInt32, (), 0 % TagType)
end

# Re-package a GreenNode as a Node
function Node(node::JuliaSyntax.GreenNode)
tags = 0 % TagType
return Node(
JuliaSyntax.head(node), JuliaSyntax.span(node),
map(Node, JuliaSyntax.children(node)),
map(Node, JuliaSyntax.children(node)), tags,
)
end

function Base.show(io::IO, node::Node)
print(io, "Node({head: {kind: ")
show(io, kind(node))
print(io, ", flags: \"$(flags(node))\"}, span: $(span(node))})")
print(io, ", flags: \"$(stringify_flags(node))\"}, span: $(span(node)), tags: \"$(stringify_tags(node))\"})")
return nothing
end

Expand Down
84 changes: 82 additions & 2 deletions src/chisels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,90 @@
# Node utilities extensions and JuliaSyntax extensions #
########################################################

# See JuliaSyntax/src/parse_stream.jl
function stringify_flags(node::Node)
io = IOBuffer()
if JuliaSyntax.has_flags(node, JuliaSyntax.TRIVIA_FLAG)
write(io, "trivia,")
end
if JuliaSyntax.is_operator(kind(node))
if JuliaSyntax.has_flags(node, JuliaSyntax.DOTOP_FLAG)
write(io, "dotted,")
end
if JuliaSyntax.has_flags(node, JuliaSyntax.SUFFIXED_FLAG)
write(io, "suffixed,")
end
end
if kind(node) in KSet"call dotcall"
if JuliaSyntax.has_flags(node, JuliaSyntax.PREFIX_CALL_FLAG)
write(io, "prefix-call,")
end
if JuliaSyntax.has_flags(node, JuliaSyntax.INFIX_FLAG)
write(io, "infix-op,")
end
if JuliaSyntax.has_flags(node, JuliaSyntax.PREFIX_OP_FLAG)
write(io, "prefix-op,")
end
if JuliaSyntax.has_flags(node, JuliaSyntax.POSTFIX_OP_FLAG)
write(io, "postfix-op,")
end
end
if kind(node) in KSet"string cmdstring" &&
JuliaSyntax.has_flags(node, JuliaSyntax.TRIPLE_STRING_FLAG)
write(io, "triple,")
end
if kind(node) in KSet"string cmdstring Identifier" &&
JuliaSyntax.has_flags(node, JuliaSyntax.RAW_STRING_FLAG)
write(io, "raw,")
end
if kind(node) in KSet"tuple block macrocall" &&
JuliaSyntax.has_flags(node, JuliaSyntax.PARENS_FLAG)
write(io, "parens,")
end
if kind(node) === K"quote" && JuliaSyntax.has_flags(node, JuliaSyntax.COLON_QUOTE)
write(io, "colon,")
end
if kind(node) === K"toplevel" && JuliaSyntax.has_flags(node, JuliaSyntax.TOPLEVEL_SEMICOLONS_FLAG)
write(io, "semicolons,")
end
if kind(node) === K"struct" && JuliaSyntax.has_flags(node, JuliaSyntax.MUTABLE_FLAG)
write(io, "mutable,")
end
if kind(node) === K"module" && JuliaSyntax.has_flags(node, JuliaSyntax.BARE_MODULE_FLAG)
write(io, "baremodule,")
end
truncate(io, max(0, position(io) - 1)) # Remove trailing comma
return String(take!(io))
end


# Node tags #

# This node is responsible for incrementing the indentation level
const TAG_INDENT = TagType(1) << 0
# This node is responsible for decrementing the indentation level
const TAG_DEDENT = TagType(1) << 1

function has_tag(node::Node, tag::TagType)
return node.tags & tag != 0
end

function stringify_tags(node::Node)
io = IOBuffer()
if has_tag(node, TAG_INDENT)
write(io, "indent,")
end
if has_tag(node, TAG_DEDENT)
write(io, "dedent,")
end
truncate(io, max(0, position(io) - 1)) # Remove trailing comma
return String(take!(io))
end

# Create a new node with the same head but new kids
function make_node(node::Node, kids′::Vector{Node})
function make_node(node::Node, kids′::Vector{Node}, tags = TagType(0))
span′ = mapreduce(span, +, kids′; init = 0)
return Node(head(node), span′, kids′)
return Node(head(node), span′, kids′, tags)
end

function first_leaf(node::Node)
Expand Down
12 changes: 6 additions & 6 deletions src/runestone.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function trim_trailing_whitespace(ctx::Context, node::Node)
nb = replace_bytes!(ctx, str′, span(node))
@assert nb != span(node)
# Create new node and return it
node′ = Node(head(node), nb, ())
node′ = Node(head(node), nb)
return node′
end

Expand All @@ -50,7 +50,7 @@ function format_hex_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, spn)
@assert nb == length(bytes) == target_spans[i]
# Create new node and return it
node′ = Node(head(node), nb, ())
node′ = Node(head(node), nb)
return node′
end

Expand Down Expand Up @@ -88,7 +88,7 @@ function format_oct_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, spn)
@assert nb == length(bytes) == target_span
# Create new node and return it
node′ = Node(head(node), nb, ())
node′ = Node(head(node), nb)
return node′
end

Expand Down Expand Up @@ -145,7 +145,7 @@ function format_float_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, span(node))
@assert nb == length(bytes)
# Create new node and return it
node′ = Node(head(node), nb, ())
node′ = Node(head(node), nb)
return node′
end

Expand All @@ -160,7 +160,7 @@ function spaces_around_x(ctx::Context, node::Node, is_x::F) where F
kids′ = kids
any_changes = false
pos = position(ctx.fmt_io)
ws = Node(JuliaSyntax.SyntaxHead(K"Whitespace", JuliaSyntax.TRIVIA_FLAG), 1, ())
ws = Node(JuliaSyntax.SyntaxHead(K"Whitespace", JuliaSyntax.TRIVIA_FLAG), 1)

# Toggle for whether we are currently looking for whitespace or not
looking_for_whitespace = false
Expand Down Expand Up @@ -385,7 +385,7 @@ function replace_with_in(ctx::Context, node::Node)
# Construct the replacement
nb = replace_bytes!(ctx, "in", span(in_node))
in_node′ = Node(
JuliaSyntax.SyntaxHead(K"in", JuliaSyntax.TRIVIA_FLAG), nb, (),
JuliaSyntax.SyntaxHead(K"in", JuliaSyntax.TRIVIA_FLAG), nb,
)
accept_node!(ctx, in_node′)
kids′ = copy(kids)
Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using JuliaSyntax:
node = Runic.Node(JuliaSyntax.parseall(JuliaSyntax.GreenNode, "a = 1 + b\n"))

# Pretty-printing
@test sprint(show, node) == "Node({head: {kind: K\"toplevel\", flags: \"0\"}, span: 10})"
@test sprint(show, node) == "Node({head: {kind: K\"toplevel\", flags: \"\"}, span: 10, tags: \"\"})"

# JuliaSyntax duck-typing
for n in (node, Runic.verified_kids(node)...,)
Expand Down

0 comments on commit 86e52bb

Please sign in to comment.