Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d32cf62
Introduce BalanceHeuristicExpand
schneems Jan 12, 2022
7324ef1
New direction BlockNode and IndentTree
schneems Jan 17, 2022
ddcc646
Initial tree building
schneems Jan 26, 2022
3682b6b
Handle invalid nodes
schneems Jan 26, 2022
a7d0fe2
Tree building perf commit
schneems Jan 26, 2022
6fd4e36
Reintroduce and fix InsertionSort for performance
schneems Jan 26, 2022
24cde0f
Fix missing deleted logic
schneems Jan 26, 2022
32eb0b3
Build tree recording
schneems Jan 27, 2022
20656d7
Slightly faster initial sorting
schneems Jan 27, 2022
b1acaf5
Tiny perf change to CodeLine#initialize
schneems Jan 27, 2022
763dec4
Remove unused code
schneems Jan 27, 2022
4ab2b70
Pull out inner/outer nodes
schneems Jan 27, 2022
5ba79c0
Rename @inner to @parents
schneems Jan 27, 2022
60d796e
Figure out search algorithm
schneems Jan 27, 2022
083e733
REXE test case
schneems Jan 28, 2022
c260450
Add more test cases
schneems Jan 28, 2022
22f9fc0
Add another test
schneems Jan 28, 2022
f2b8878
Fix problem with my logic for "inner/outer" check
schneems Jan 28, 2022
b7a6c65
Add misindentation test
schneems Jan 29, 2022
01c2b8c
Refactor decision logic into node
schneems Jan 29, 2022
1fa20e1
Initial idea to search by "diagnosing" a node
schneems Jan 31, 2022
16a109b
Fix BlockNode.from_parents above/below
schneems Feb 1, 2022
72cd93e
Fix BlockNode.from_parents that have 1 parent
schneems Feb 1, 2022
c5dbd27
Handle multiple case
schneems Feb 1, 2022
db85b5b
First indent tree search
schneems Feb 2, 2022
1a34697
Standardrb --fix
schneems Feb 3, 2022
6185b90
More search cases
schneems Feb 3, 2022
036373b
Follow multiple errors with IndentSearch
schneems Feb 5, 2022
f977054
Implement tracing on new search
schneems Feb 6, 2022
62bff09
Move IndentSearch to a proper file
schneems Feb 7, 2022
b8a1549
Add missing frozen string magic comment
schneems Feb 7, 2022
4301fab
Move BlockRecorder to proper file
schneems Feb 7, 2022
53eb266
Document IndentSearch
schneems Feb 7, 2022
ea6986e
Move journey to proper file
schneems Feb 7, 2022
ccd9816
Document and refactor IndentTree
schneems Feb 7, 2022
93bab24
Document BlockNode and update BlockDocument docs
schneems Feb 8, 2022
f3a83a5
Refactor logic to Diagnose class
schneems Feb 8, 2022
e06af0c
Fix problem with one bad internal node
schneems Feb 8, 2022
a666da7
Fix block reporter
schneems Feb 8, 2022
011e8a0
Diagnose docs, rename problems & fix one edge case
schneems Feb 8, 2022
70087ed
Refactor Diagnose into smaller methods & rename
schneems Feb 8, 2022
745dc3b
Move diagnose node to its own file
schneems Feb 8, 2022
194ee1b
standardrb --fix
schneems Feb 8, 2022
e0256d1
Finish extraction of Diagnose logic
schneems Feb 8, 2022
c0d8625
Remove unused BalanceHueristicExpand
schneems Feb 9, 2022
e5a70a9
WIP Integration with One failing test
schneems Feb 9, 2022
fc872fb
WIP 8 total failing tests
schneems Feb 9, 2022
026aa1b
WIP Initial BlockNodeContext
schneems Feb 10, 2022
60b4ed3
Update block building
schneems Feb 15, 2022
ee2c9fd
WIP WIP WIP????
schneems Feb 16, 2022
2303179
WIPPPPPPPPPPPPPPPPPPPPPPPPPP
schneems Feb 16, 2022
be9b4c4
WIP
schneems May 20, 2022
02285d2
Fix nested pseudo pair case
schneems Jun 4, 2022
ef535d5
192 examples, 2 failures, 1 pending
schneems Jun 7, 2022
fc7a62c
Check if one node can be pruned from multiple
schneems Jun 7, 2022
91b94a4
Move test out of ruby CLI
schneems Jun 8, 2022
c3b30da
Porting examples from existing tests
schneems Jun 8, 2022
4dfa1b2
This is a difficult problem
schneems Jul 26, 2022
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
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ GEM
rubocop-ast (>= 0.4.0)
ruby-prof (1.4.3)
ruby-progressbar (1.11.0)
stackprof (0.2.16)
stackprof (0.2.17)
standard (1.3.0)
rubocop (= 1.20.0)
rubocop-performance (= 1.11.5)
Expand Down
65 changes: 56 additions & 9 deletions lib/dead_end/api.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require_relative "version"

require "tmpdir"
Expand Down Expand Up @@ -60,6 +62,41 @@ def self.handle_error(e, re_raise: true, io: $stderr)
#
# Main private interface
def self.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr)
call_now(source: source, filename: filename, terminal: terminal, record_dir: record_dir, timeout: timeout, io: io)
# call_old(source: source, filename: filename, terminal: terminal, record_dir: record_dir, timeout: timeout, io: io)
end

def self.call_now(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr)
search = nil
code_lines = nil
filename = nil if filename == DEFAULT_VALUE
Timeout.timeout(timeout) do
code_lines = CleanDocument.new(source: source).call.lines

if DeadEnd.valid?(code_lines)
io.puts "Syntax OK"
obj = Object.new
def obj.document_ok?; true; end
return obj
end

document = BlockDocument.new(code_lines: code_lines).call
tree = IndentTree.new(document: document).call
search = IndentSearch.new(tree: tree).call
end

blocks = search.finished.map(&:node).map {|node| CodeBlock.new(lines: node.lines) }

DisplayInvalidBlocks.new(
io: io,
blocks: blocks,
filename: filename,
terminal: terminal,
code_lines: code_lines,
).call
end

def self.call_old(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr)
search = nil
filename = nil if filename == DEFAULT_VALUE
Timeout.timeout(timeout) do
Expand All @@ -73,7 +110,7 @@ def self.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_
blocks: blocks,
filename: filename,
terminal: terminal,
code_lines: search.code_lines
code_lines: search.code_lines,
).call
rescue Timeout::Error => e
io.puts "Search timed out DEAD_END_TIMEOUT=#{timeout}, run with DEBUG=1 for more info"
Expand All @@ -85,13 +122,15 @@ def self.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_
# Used to generate a unique directory to record
# search steps for debugging
def self.record_dir(dir)
time = Time.now.strftime("%Y-%m-%d-%H-%M-%s-%N")
dir = Pathname(dir)
symlink = dir.join("last").tap { |path| path.delete if path.exist? }
dir.join(time).tap { |path|
path.mkpath
FileUtils.symlink(path.basename, symlink)
}
@record_dir ||= begin
time = Time.now.strftime("%Y-%m-%d-%H-%M-%s-%N")
dir = Pathname(dir)
symlink = dir.join("last").tap { |path| path.delete if path.exist? }
dir.join(time).tap { |path|
path.mkpath
FileUtils.symlink(path.basename, symlink)
}
end
end

# DeadEnd.valid_without? [Private]
Expand Down Expand Up @@ -187,12 +226,20 @@ def self.valid?(source)
require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
require_relative "lex_pair_diff"
require_relative "ripper_errors"
require_relative "priority_queue"
require_relative "unvisited_lines"
require_relative "around_block_scan"
require_relative "indent_block_expand"
require_relative "priority_engulf_queue"
require_relative "pathname_from_message"
require_relative "display_invalid_blocks"
require_relative "parse_blocks_from_indent_line"

require_relative "block_node"
require_relative "indent_tree"
require_relative "block_document"

require_relative "indent_search"
require_relative "diagnose_node"
4 changes: 2 additions & 2 deletions lib/dead_end/around_block_scan.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def capture_neighbor_context
break
end

lines << line
lines << line if line.is_kw? || line.is_end?
end

lines.reverse!
Expand All @@ -140,7 +140,7 @@ def capture_neighbor_context
break
end

lines << line
lines << line if line.is_kw? || line.is_end?
end

lines
Expand Down
126 changes: 126 additions & 0 deletions lib/dead_end/block_document.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# frozen_string_literal: true

module DeadEnd
# Convert an array of code lines to a linked list of BlockNodes
#
# Each BlockNode is connected to the node above and below it.
# A BlockNode can "capture" other nodes. This process is recursively
# performed to build a hierarchical tree structure via IndentTree
#
# document = BlockDocument.new(code_lines: code_lines)
# document.call
#
# A BlockDocument also holds a priority queue for all BlockNodes
#
# Empty lines are ignored so blocks in the list may have gaps in
# line/index numbers.
#
# A core operation is the ability to to "capture"
# several blocks immutably. This process creates a new block
# that holds the captured state and substitutes it into the graph
# data structure for the original block
#
# node.above.leaning # => :left
# node.below.leaning # => :right

# block = document.capture_all([node.above, node.below])
# block.leaning # => :equal
#
class BlockDocument
attr_reader :blocks, :queue, :root, :code_lines

include Enumerable

def initialize(code_lines:)
@code_lines = code_lines
@queue = InsertionSortQueue.new
@root = nil
end

def to_a
map(&:itself)
end

def each
node = @root
while node
yield node
node = node.below
end
end

def to_s
string = +""
each do |block|
string << block.to_s
end
string
end

def call
last = nil
blocks = @code_lines.filter_map do |line|
next if line.empty?

node = BlockNode.new(lines: line, indent: line.indent)
@root ||= node
node.above = last
last&.below = node
last = node
node
end

if last.above
last.above.below = last
end

# Need all above/below set to determine correct next_indent
@queue.replace(blocks.sort)

self
end

def capture_all(inner)
now = BlockNode.from_blocks(inner)
while queue&.peek&.deleted?
queue.pop
end

if inner.first == @root
@root = now
end

if inner.first&.above
inner.first.above.below = now
now.above = inner.first.above
end

if inner.last&.below
inner.last.below.above = now
now.below = inner.last.below
end
now
end

def capture(node:, captured:)
inner = []
inner.concat(Array(captured))
inner << node
inner.sort_by! { |block| block.start_index }

capture_all(inner)
end

def pop
@queue.pop
end

def peek
@queue.peek
end

def inspect
"#<DeadEnd::BlockDocument:0x000000010b375lol >"
end
end
end
Loading