Skip to content

Commit

Permalink
initial indent-pass
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre committed Jun 5, 2024
1 parent 80a9753 commit 5c2e058
Show file tree
Hide file tree
Showing 5 changed files with 616 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/Manifest.toml
*.cov
27 changes: 25 additions & 2 deletions src/Runic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ mutable struct Context
debug::Bool
check::Bool
diff::Bool
# Global state
indent_level::Int # track (hard) indentation level
call_depth::Int # track call-depth level for debug printing
# Current state
# node::Union{Node, Nothing}
prev_sibling::Union{Node, Nothing}
Expand Down Expand Up @@ -138,9 +141,12 @@ function Context(
# Debug mode enforces verbose and assert
verbose = debug ? true : verbose
assert = debug ? true : assert
indent_level = 0
call_depth = 0
prev_sibling = next_sibling = nothing
return Context(
src_str, src_tree, src_io, fmt_io, fmt_tree,
quiet, verbose, assert, debug, check, diff, nothing, nothing,
src_str, src_tree, src_io, fmt_io, fmt_tree, quiet, verbose, assert, debug, check,
diff, call_depth, indent_level, prev_sibling, next_sibling,
)
end

Expand Down Expand Up @@ -180,6 +186,8 @@ function format_node_with_kids!(ctx::Context, node::Node)
return nothing
end

ctx.call_depth += 1

# Keep track of the siblings on this stack
prev_sibling = ctx.prev_sibling
next_sibling = ctx.next_sibling
Expand Down Expand Up @@ -240,6 +248,7 @@ function format_node_with_kids!(ctx::Context, node::Node)
# Reset the siblings
ctx.prev_sibling = prev_sibling
ctx.next_sibling = next_sibling
ctx.call_depth -= 1
# Return a new node if any of the kids changed
if any_kid_changed
return make_node(node, kids′)
Expand All @@ -259,7 +268,18 @@ Format a node. Return values:
function format_node!(ctx::Context, node::Node)::Union{Node, Nothing, NullNode}
node_kind = kind(node)

# Not that two separate `if`s are used here because a node like `else` can be both
# dedent and indent
if has_tag(node, TAG_INDENT)
ctx.indent_level += 1
end
if has_tag(node, TAG_DEDENT)
ctx.indent_level -= 1
end

# Go through the runestone and apply transformations.
ctx.call_depth += 1
@return_something insert_delete_mark_newlines(ctx, node)
@return_something trim_trailing_whitespace(ctx, node)
@return_something format_hex_literals(ctx, node)
@return_something format_oct_literals(ctx, node)
Expand All @@ -268,6 +288,8 @@ function format_node!(ctx::Context, node::Node)::Union{Node, Nothing, NullNode}
@return_something spaces_around_assignments(ctx, node)
@return_something no_spaces_around_colon_etc(ctx, node)
@return_something for_loop_use_in(ctx, node)
@return_something four_space_indent(ctx, node)
ctx.call_depth -= 1

# If the node is unchanged at this point, just keep going.

Expand Down Expand Up @@ -346,6 +368,7 @@ function format_node!(ctx::Context, node::Node)::Union{Node, Nothing, NullNode}
node_kind === K"where" ||
node_kind === K"while"
)
@assert !JuliaSyntax.is_trivia(node)
node′ = format_node_with_kids!(ctx, node)
@assert node′ !== nullnode
return node′
Expand Down
46 changes: 44 additions & 2 deletions src/chisels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,42 @@ end
const TAG_INDENT = TagType(1) << 0
# This node is responsible for decrementing the indentation level
const TAG_DEDENT = TagType(1) << 1
# This (NewlineWs) node is the last one before a TAG_DEDENT
const TAG_PRE_DEDENT = TagType(1) << 2
# This (NewlineWs) node is a line continuation
const TAG_LINE_CONT = UInt32(1) << 31

function add_tag(node::Node, tag::TagType)
@assert is_leaf(node)
return Node(head(node), span(node), node.kids, node.tags | tag)
end

function tag_leading_newline(node::Node, tag::TagType)
if is_leaf(node)
if kind(node) === K"NewlineWs" && !has_tag(node, tag)
return add_tag(node, tag)
else
return nothing
end
else
kids = verified_kids(node)
if length(kids) < 1
return nothing
end
# Skip over whitespace + comment which can mask the newline
idx = findfirst(x -> !(kind(x) in KSet"Whitespace Comment"), kids)
if idx === nothing
return nothing
end
kid′ = tag_leading_newline(kids[idx], tag)
if kid′ === nothing
return nothing
else
kids[idx] = kid′
return node
end
end
end

function has_tag(node::Node, tag::TagType)
return node.tags & tag != 0
Expand All @@ -80,12 +116,18 @@ function stringify_tags(node::Node)
if has_tag(node, TAG_DEDENT)
write(io, "dedent,")
end
if has_tag(node, TAG_PRE_DEDENT)
write(io, "pre-dedent,")
end
if has_tag(node, TAG_LINE_CONT)
write(io, "line-cont.,")
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}, tags = TagType(0))
function make_node(node::Node, kids′::Vector{Node}, tags = node.tags)
span′ = mapreduce(span, +, kids′; init = 0)
return Node(head(node), span′, kids′, tags)
end
Expand Down Expand Up @@ -135,7 +177,7 @@ end

# Extract the operator of an infix op call node
function infix_op_call_op(node::Node)
@assert is_infix_op_call(node)
@assert is_infix_op_call(node) || kind(node) === K"||"
kids = verified_kids(node)
first_operand_index = findfirst(!JuliaSyntax.is_whitespace, kids)
op_index = findnext(JuliaSyntax.is_operator, kids, first_operand_index + 1)
Expand Down
Loading

0 comments on commit 5c2e058

Please sign in to comment.