Class: Ibex::Runtime::CST::GreenBuilder
- Inherits:
-
Object
- Object
- Ibex::Runtime::CST::GreenBuilder
- Defined in:
- lib/ibex/runtime/cst/green/builder.rb
Overview
LR bottom-up builder backed by a Green element stack. rubocop:disable Naming/PredicateMethod -- mutation methods report whether they found a target.
Constant Summary collapse
- EMPTY_TRIVIA =
empty_trivia.freeze
Instance Method Summary collapse
-
#absorb_into_error(pop_count, skipped: []) ⇒ Object
Preserve popped and discarded Green elements in one error node.
-
#append_to_last_error(skipped) ⇒ Object
Append discarded input to the most recent error node on the stack.
-
#append_trailing_to_last_token(trivia) ⇒ Object
Path-copy the right edge to attach balanced trailing trivia.
- #elements ⇒ Object
-
#finish_source_file(eof_token, incomplete: false) ⇒ Object
Wrap the completed start node and explicit EOF token.
-
#finish_synthetic_root(trailing = [], incomplete: false) ⇒ Object
Preserve every available fragment when parsing terminates without a start node.
-
#initialize(kinds:, cache: NodeCache.new) ⇒ GreenBuilder
constructor
A new instance of GreenBuilder.
- #lexical_error(text, leading: EMPTY_TRIVIA) ⇒ Object
-
#make_token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) ⇒ Object
Construct an interned token without changing the builder stack.
- #missing(expected_kind) ⇒ Object
- #node(kind, arity, flags: 0) ⇒ Object
- #restore(elements) ⇒ Object
- #size ⇒ Object
- #snapshot ⇒ Object
-
#subtree(value) ⇒ Object
Push one already validated nonterminal without rebuilding its descendants.
- #token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) ⇒ Object
Constructor Details
#initialize(kinds:, cache: NodeCache.new) ⇒ GreenBuilder
Returns a new instance of GreenBuilder.
21 22 23 24 25 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 21 def initialize(kinds:, cache: NodeCache.new) @kinds = kinds @cache = cache @stack = [] end |
Instance Method Details
#absorb_into_error(pop_count, skipped: []) ⇒ Object
Preserve popped and discarded Green elements in one error node.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 85 def absorb_into_error(pop_count, skipped: []) raise ArgumentError, "pop_count must be non-negative" if pop_count.negative? raise ArgumentError, "green stack underflow" if pop_count > @stack.length empty = [] #: Array[child] popped = pop_count.zero? ? empty : @stack.pop(pop_count) value = @cache.intern_node( GreenNode.new( kind: @kinds.fetch(:error_node), children: popped + skipped, flags: Flags::CONTAINS_ERROR ) ) @stack << value value end |
#append_to_last_error(skipped) ⇒ Object
Append discarded input to the most recent error node on the stack.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 131 def append_to_last_error(skipped) index = @stack.rindex { |element| element.is_a?(GreenNode) && element.kind == @kinds.fetch(:error_node) } return false unless index error = @stack.fetch(index) return false unless error.is_a?(GreenNode) @stack[index] = @cache.intern_node( GreenNode.new( kind: error.kind, children: error.children + [skipped], flags: error.intrinsic_flags | Flags::CONTAINS_ERROR, annotations: error.annotations ) ) true end |
#append_trailing_to_last_token(trivia) ⇒ Object
Path-copy the right edge to attach balanced trailing trivia.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 149 def append_trailing_to_last_token(trivia) return false if trivia.empty? index = @stack.length - 1 while index >= 0 replacement = with_rightmost_trailing(@stack.fetch(index), trivia) if replacement @stack[index] = replacement return true end index -= 1 end false end |
#elements ⇒ Object
176 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 176 def elements = @stack.dup.freeze |
#finish_source_file(eof_token, incomplete: false) ⇒ Object
Wrap the completed start node and explicit EOF token.
103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 103 def finish_source_file(eof_token, incomplete: false) raise ArgumentError, "expected one completed start node" unless @stack.one? flags = Flags::SYNTHETIC flags |= Flags::INCOMPLETE_INPUT if incomplete @cache.intern_node( GreenNode.new( kind: @kinds.fetch(:source_file), children: [@stack.fetch(0), eof_token], flags: flags ) ) end |
#finish_synthetic_root(trailing = [], incomplete: false) ⇒ Object
Preserve every available fragment when parsing terminates without a start node.
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 118 def finish_synthetic_root(trailing = [], incomplete: false) flags = Flags::SYNTHETIC | Flags::CONTAINS_ERROR flags |= Flags::INCOMPLETE_INPUT if incomplete @cache.intern_node( GreenNode.new( kind: @kinds.fetch(:synthetic_root), children: @stack + trailing, flags: flags ) ) end |
#lexical_error(text, leading: EMPTY_TRIVIA) ⇒ Object
74 75 76 77 78 79 80 81 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 74 def lexical_error(text, leading: EMPTY_TRIVIA) value = @cache.intern_token_fields( kind: @kinds.fetch(:lexical_error_token), text: text, leading: leading, flags: Flags::CONTAINS_ERROR ) @stack << value value end |
#make_token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) ⇒ Object
Construct an interned token without changing the builder stack.
38 39 40 41 42 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 38 def make_token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) @cache.intern_token_fields( kind: kind, text: text, leading: leading, trailing: trailing, flags: flags ) end |
#missing(expected_kind) ⇒ Object
64 65 66 67 68 69 70 71 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 64 def missing(expected_kind) value = @cache.intern_token_fields( kind: @kinds.fetch(:missing_token), text: "", expected_kind: expected_kind, flags: Flags::CONTAINS_MISSING | Flags::SYNTHETIC ) @stack << value value end |
#node(kind, arity, flags: 0) ⇒ Object
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 45 def node(kind, arity, flags: 0) raise ArgumentError, "arity must be non-negative" if arity.negative? raise ArgumentError, "green stack underflow" if arity > @stack.length empty = [] #: Array[child] children = arity.zero? ? empty : @stack.pop(arity) value = @cache.intern_node(GreenNode.new(kind: kind, children: children, flags: flags)) @stack << value value end |
#restore(elements) ⇒ Object
168 169 170 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 168 def restore(elements) @stack = elements.dup end |
#size ⇒ Object
173 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 173 def size = @stack.length |
#snapshot ⇒ Object
165 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 165 def snapshot = @stack.dup |
#subtree(value) ⇒ Object
Push one already validated nonterminal without rebuilding its descendants.
58 59 60 61 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 58 def subtree(value) @stack << value value end |
#token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) ⇒ Object
29 30 31 32 33 |
# File 'lib/ibex/runtime/cst/green/builder.rb', line 29 def token(kind, text, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0) value = make_token(kind, text, leading: leading, trailing: trailing, flags: flags) @stack << value value end |