Class: Ibex::Runtime::CST::SyntaxEditor
- Inherits:
-
Object
- Object
- Ibex::Runtime::CST::SyntaxEditor
- Defined in:
- lib/ibex/runtime/cst/editor.rb,
sig/ibex/runtime/cst/editor.rbs
Overview
Applies multiple occurrence-addressed replacements in one path-copying pass.
Instance Method Summary collapse
- #ancestor?(possible_ancestor, element) ⇒ Boolean
- #apply ⇒ SyntaxNode
- #apply_element(element) ⇒ green
-
#initialize(root) ⇒ SyntaxEditor
constructor
A new instance of SyntaxEditor.
- #replace(target, replacement) ⇒ self
- #same_occurrence?(left, right) ⇒ Boolean
Constructor Details
#initialize(root) ⇒ SyntaxEditor
Returns a new instance of SyntaxEditor.
21 22 23 24 |
# File 'lib/ibex/runtime/cst/editor.rb', line 21 def initialize(root) @root = root @edits = [] end |
Instance Method Details
#ancestor?(possible_ancestor, element) ⇒ Boolean
77 78 79 80 81 82 83 84 85 |
# File 'lib/ibex/runtime/cst/editor.rb', line 77 def ancestor?(possible_ancestor, element) parent = element.parent while parent return true if same_occurrence?(parent, possible_ancestor) parent = parent.parent end false end |
#apply ⇒ SyntaxNode
46 47 48 49 50 51 52 |
# File 'lib/ibex/runtime/cst/editor.rb', line 46 def apply green = apply_element(@root) return @root if green.equal?(@root.green) raise TypeError, "a syntax root must remain a GreenNode" unless green.is_a?(GreenNode) Editing.red_root(@root, green) end |
#apply_element(element) ⇒ green
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/ibex/runtime/cst/editor.rb', line 57 def apply_element(element) replacement = @edits.find { |target, _green| same_occurrence?(target, element) }&.fetch(1) return replacement if replacement return element.green if element.is_a?(SyntaxToken) changed = false children = element.children.map do |child| green = apply_element(child) changed ||= !green.equal?(child.green) green end return element.green unless changed GreenNode.new( kind: element.green.kind, children: children, flags: element.green.intrinsic_flags, annotations: element.green.annotations ) end |
#replace(target, replacement) ⇒ self
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/ibex/runtime/cst/editor.rb', line 27 def replace(target, replacement) raise ArgumentError, "edit target belongs to a different root" unless target.root.equal?(@root) green = Editing.green_element(replacement) duplicate = @edits.find { |existing, _value| same_occurrence?(existing, target) } if duplicate raise EditConflictError, "the same syntax occurrence has conflicting replacements" unless duplicate.fetch(1).equal?(green) return self end return self if @edits.any? { |existing, _value| ancestor?(existing, target) } @edits.reject! { |existing, _value| ancestor?(target, existing) } @edits << [target, green] self end |
#same_occurrence?(left, right) ⇒ Boolean
88 89 90 |
# File 'lib/ibex/runtime/cst/editor.rb', line 88 def same_occurrence?(left, right) left.root.equal?(right.root) && left.green.equal?(right.green) && left.offset == right.offset end |