Browse Source

Add metadata tags to the Node struct.

pull/19/head
Fredrik Ekre 2 years ago
parent
commit
86e52bb9b3
No known key found for this signature in database
GPG Key ID: DE82E6D5E364C0A2
  1. 13
      src/Runic.jl
  2. 84
      src/chisels.jl
  3. 12
      src/runestone.jl
  4. 2
      test/runtests.jl

13
src/Runic.jl

@ -21,6 +21,8 @@ include("debug.jl")
# Node # # Node #
######## ########
const TagType = UInt32
# This is essentially just a re-packed `JuliaSyntax.GreenNode`. # This is essentially just a re-packed `JuliaSyntax.GreenNode`.
struct Node struct Node
# The next three fields directly match JuliaSyntax.GreenNode. We can not store a # The next three fields directly match JuliaSyntax.GreenNode. We can not store a
@ -29,20 +31,27 @@ struct Node
head::JuliaSyntax.SyntaxHead head::JuliaSyntax.SyntaxHead
span::UInt32 span::UInt32
kids::Union{Tuple{}, Vector{Node}} 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 end
# Re-package a GreenNode as a Node # Re-package a GreenNode as a Node
function Node(node::JuliaSyntax.GreenNode) function Node(node::JuliaSyntax.GreenNode)
tags = 0 % TagType
return Node( return Node(
JuliaSyntax.head(node), JuliaSyntax.span(node), JuliaSyntax.head(node), JuliaSyntax.span(node),
map(Node, JuliaSyntax.children(node)), map(Node, JuliaSyntax.children(node)), tags,
) )
end end
function Base.show(io::IO, node::Node) function Base.show(io::IO, node::Node)
print(io, "Node({head: {kind: ") print(io, "Node({head: {kind: ")
show(io, kind(node)) 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 return nothing
end end

84
src/chisels.jl

@ -4,10 +4,90 @@
# Node utilities extensions and JuliaSyntax extensions # # 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 # 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) span′ = mapreduce(span, +, kids′; init = 0)
return Node(head(node), span′, kids′) return Node(head(node), span′, kids′, tags)
end end
function first_leaf(node::Node) function first_leaf(node::Node)

12
src/runestone.jl

@ -25,7 +25,7 @@ function trim_trailing_whitespace(ctx::Context, node::Node)
nb = replace_bytes!(ctx, str′, span(node)) nb = replace_bytes!(ctx, str′, span(node))
@assert nb != span(node) @assert nb != span(node)
# Create new node and return it # Create new node and return it
node′ = Node(head(node), nb, ()) node′ = Node(head(node), nb)
return node′ return node′
end end
@ -50,7 +50,7 @@ function format_hex_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, spn) nb = replace_bytes!(ctx, bytes, spn)
@assert nb == length(bytes) == target_spans[i] @assert nb == length(bytes) == target_spans[i]
# Create new node and return it # Create new node and return it
node′ = Node(head(node), nb, ()) node′ = Node(head(node), nb)
return node′ return node′
end end
@ -88,7 +88,7 @@ function format_oct_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, spn) nb = replace_bytes!(ctx, bytes, spn)
@assert nb == length(bytes) == target_span @assert nb == length(bytes) == target_span
# Create new node and return it # Create new node and return it
node′ = Node(head(node), nb, ()) node′ = Node(head(node), nb)
return node′ return node′
end end
@ -145,7 +145,7 @@ function format_float_literals(ctx::Context, node::Node)
nb = replace_bytes!(ctx, bytes, span(node)) nb = replace_bytes!(ctx, bytes, span(node))
@assert nb == length(bytes) @assert nb == length(bytes)
# Create new node and return it # Create new node and return it
node′ = Node(head(node), nb, ()) node′ = Node(head(node), nb)
return node′ return node′
end end
@ -160,7 +160,7 @@ function spaces_around_x(ctx::Context, node::Node, is_x::F) where F
kids′ = kids kids′ = kids
any_changes = false any_changes = false
pos = position(ctx.fmt_io) 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 # Toggle for whether we are currently looking for whitespace or not
looking_for_whitespace = false looking_for_whitespace = false
@ -385,7 +385,7 @@ function replace_with_in(ctx::Context, node::Node)
# Construct the replacement # Construct the replacement
nb = replace_bytes!(ctx, "in", span(in_node)) nb = replace_bytes!(ctx, "in", span(in_node))
in_node′ = 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′) accept_node!(ctx, in_node′)
kids′ = copy(kids) kids′ = copy(kids)

2
test/runtests.jl

@ -11,7 +11,7 @@ using JuliaSyntax:
node = Runic.Node(JuliaSyntax.parseall(JuliaSyntax.GreenNode, "a = 1 + b\n")) node = Runic.Node(JuliaSyntax.parseall(JuliaSyntax.GreenNode, "a = 1 + b\n"))
# Pretty-printing # 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 # JuliaSyntax duck-typing
for n in (node, Runic.verified_kids(node)...,) for n in (node, Runic.verified_kids(node)...,)

Loading…
Cancel
Save