Class: Ibex::Frontend::TokenAdapter::RuleState

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/frontend/token_adapter/rule_state.rb,
sig/ibex/frontend/token_adapter/rule_state.rbs

Overview

Classifies context-dependent tokens in the grammar rule section.

Constant Summary collapse

SCALAR_TYPES =

Returns:

  • (Hash[Symbol, external_token])
{
  literal: :LITERAL, integer: :INTEGER, action: :ACTION, user_code: :USER_CODE
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRuleState

Returns a new instance of RuleState.

RBS:

  • () -> void



21
22
23
24
25
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 21

def initialize
  @state = :rules_lhs
  @section = :rules
  @delimiters = DelimiterTracker.new
end

Instance Attribute Details

#sectionparser_section (readonly)

Signature:

  • Hash[Symbol, external_token]

Returns:

  • (parser_section)


12
13
14
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 12

def section
  @section
end

#stateSymbol (readonly)

Signature:

  • Symbol

Returns:

  • (Symbol)


13
14
15
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 13

def state
  @state
end

Instance Method Details

#adjacent?(left, right) ⇒ Boolean

RBS:

  • (Token left, Token right) -> bool

Parameters:

Returns:

  • (Boolean)


181
182
183
184
185
186
187
188
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 181

def adjacent?(left, right)
  left_span = left.span
  right_span = right.span
  return left_span.end_byte == right_span.start_byte if left_span && right_span

  left.location.line == right.location.line &&
    left.location.column + string_value(left).length == right.location.column
end

#classify(token, remaining, last_external:, previous_external:) ⇒ external_token

RBS:

  • (Token token, Array[Token] remaining, last_external: external_token?, previous_external: external_token?) -> external_token

Parameters:

  • token (Token)
  • remaining (Array[Token])
  • last_external: (external_token, nil)
  • previous_external: (external_token, nil)

Returns:

  • (external_token)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 29

def classify(token, remaining, last_external:, previous_external:)
  external = if token.type == :identifier
               classify_identifier(token, remaining, last_external, previous_external)
             elsif token.type == :node
               @node_annotation = true
               :NODE
             elsif token.type == :inline
               classify_inline
             elsif token.type == :empty
               :EMPTY
             elsif SCALAR_TYPES.key?(token.type)
               SCALAR_TYPES.fetch(token.type)
             else
               classify_punctuation(token)
             end
  @delimiters.observe(token, external, last_external)
  @node_annotation = false if token.type == :")" && @node_annotation
  external
end

#classify_identifier(token, remaining, last_external, previous_external) ⇒ external_token

RBS:

  • (Token token, Array[Token] remaining, external_token? last_external, external_token? previous_external) -> external_token

Parameters:

  • token (Token)
  • remaining (Array[Token])
  • last_external (external_token, nil)
  • previous_external (external_token, nil)

Returns:

  • (external_token)


80
81
82
83
84
85
86
87
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 80

def classify_identifier(token, remaining, last_external, previous_external)
  return :IDENTIFIER if @node_annotation
  return rule_lhs(token) if @state == :rules_lhs
  return :IDENTIFIER unless @state == :rule_rhs
  return :IDENTIFIER if named_reference_name?(last_external, previous_external)

  classify_rhs_identifier(token, remaining)
end

#classify_inlineexternal_token

RBS:

  • () -> external_token

Returns:

  • (external_token)


73
74
75
76
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 73

def classify_inline
  reset_rule_boundary if @state == :rule_rhs && @delimiters.empty?
  :INLINE
end

#classify_punctuation(token) ⇒ external_token

RBS:

  • (Token token) -> external_token

Parameters:

Returns:

  • (external_token)


191
192
193
194
195
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 191

def classify_punctuation(token)
  @state = :rule_rhs if @state == :rule_colon && token.type == :":"
  reset_rule_boundary if @state == :rule_rhs && token.type == :";" && @delimiters.empty?
  string_value(token)
end

#classify_rhs_identifier(token, remaining) ⇒ external_token

RBS:

  • (Token token, Array[Token] remaining) -> external_token

Parameters:

Returns:

  • (external_token)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 90

def classify_rhs_identifier(token, remaining)
  value = string_value(token)
  return :IDENTIFIER if value == "end" && @delimiters.open_kind
  return finish_rules if value == "end"

  following = remaining.first
  return :IDENTIFIER unless following
  return start_rule(token) if rule_boundary?(token, following) ||
                              parameterized_rule_boundary?(token, remaining)
  return separated_terminal(token) if separated_list_call?(token, following)
  return :PARAMETERIZED_REFERENCE if parameterized_call?(token, following)

  :IDENTIFIER
end

#expectation(token) ⇒ String?

RBS:

  • (Token? token) -> String?

Parameters:

Returns:

  • (String, nil)


60
61
62
63
64
65
66
67
68
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 60

def expectation(token)
  if @state == :rules_lhs && @section == :rules
    rules_lhs_expectation(token)
  elsif @state == :rule_colon
    ":"
  elsif @state == :rule_rhs && %w[) ,].include?(token&.value)
    "a grammar symbol"
  end
end

#finish_rulesexternal_token

RBS:

  • () -> external_token

Returns:

  • (external_token)


160
161
162
163
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 160

def finish_rules
  @section = :user_code
  :END
end

#group_openingToken?

RBS:

  • () -> Token?

Returns:



50
51
52
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 50

def group_opening
  @delimiters.group_opening
end

#named_reference_name?(last_external, previous_external) ⇒ Boolean

RBS:

  • (external_token? last_external, external_token? previous_external) -> bool

Parameters:

  • last_external (external_token, nil)
  • previous_external (external_token, nil)

Returns:

  • (Boolean)


119
120
121
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 119

def named_reference_name?(last_external, previous_external)
  last_external == ":" && %i[IDENTIFIER LITERAL].include?(previous_external)
end

#open_delimiter_kinddelimiter_kind?

RBS:

  • () -> delimiter_kind?

Returns:

  • (delimiter_kind, nil)


55
56
57
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 55

def open_delimiter_kind
  @delimiters.open_kind
end

#parameter_definition_tail?(tail) ⇒ Boolean

RBS:

  • (Array[Token] tail) -> bool

Parameters:

Returns:

  • (Boolean)


142
143
144
145
146
147
148
149
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 142

def parameter_definition_tail?(tail)
  closing = tail.index { |entry| entry.type == :")" }
  return false unless closing && tail[closing + 1]&.type == :":"

  formals = tail.take(closing)
  !formals.empty? && formals.length.odd? &&
    formals.each_with_index.all? { |entry, index| entry.type == (index.even? ? :identifier : :",") }
end

#parameterized_call?(token, following) ⇒ Boolean

RBS:

  • (Token token, Token following) -> bool

Parameters:

Returns:

  • (Boolean)


176
177
178
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 176

def parameterized_call?(token, following)
  following.type == :"(" && adjacent?(token, following)
end

#parameterized_rule_boundary?(token, remaining) ⇒ Boolean

RBS:

  • (Token token, Array[Token] remaining) -> bool

Parameters:

Returns:

  • (Boolean)


132
133
134
135
136
137
138
139
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 132

def parameterized_rule_boundary?(token, remaining)
  lhs_column = @lhs_column
  opening = remaining.first
  return false unless lhs_column && @delimiters.empty? && token.location.column <= lhs_column
  return false unless opening&.type == :"(" && adjacent?(token, opening)

  parameter_definition_tail?(remaining.drop(1))
end

#reset_rule_boundaryvoid

This method returns an undefined value.

RBS:

  • () -> void



198
199
200
201
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 198

def reset_rule_boundary
  @lhs_column = nil
  @state = :rules_lhs
end

#rule_boundary?(token, following) ⇒ Boolean

RBS:

  • (Token token, Token following) -> bool

Parameters:

Returns:

  • (Boolean)


124
125
126
127
128
129
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 124

def rule_boundary?(token, following)
  lhs_column = @lhs_column
  return false unless lhs_column

  @delimiters.empty? && following.type == :":" && token.location.column <= lhs_column
end

#rule_lhs(token) ⇒ external_token

RBS:

  • (Token token) -> external_token

Parameters:

Returns:

  • (external_token)


106
107
108
109
110
111
112
113
114
115
116
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 106

def rule_lhs(token)
  if string_value(token) == "end"
    @section = :user_code
    return :END
  end

  @rule_seen = true
  @lhs_column = token.location.column
  @state = :rule_colon
  :LHS
end

#rules_lhs_expectation(token) ⇒ String

RBS:

  • (Token? token) -> String

Parameters:

Returns:

  • (String)


204
205
206
207
208
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 204

def rules_lhs_expectation(token)
  return "identifier" unless token&.type == :eof

  @rule_seen ? "end" : "at least one rule"
end

#separated_list_call?(token, following) ⇒ Boolean

RBS:

  • (Token token, Token following) -> bool

Parameters:

Returns:

  • (Boolean)


166
167
168
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 166

def separated_list_call?(token, following)
  %w[separated_list separated_nonempty_list].include?(string_value(token)) && following.type == :"("
end

#separated_terminal(token) ⇒ external_token

RBS:

  • (Token token) -> external_token

Parameters:

Returns:

  • (external_token)


171
172
173
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 171

def separated_terminal(token)
  string_value(token) == "separated_list" ? :SEPARATED_LIST : :SEPARATED_NONEMPTY_LIST
end

#start_rule(token) ⇒ external_token

RBS:

  • (Token token) -> external_token

Parameters:

Returns:

  • (external_token)


152
153
154
155
156
157
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 152

def start_rule(token)
  @rule_seen = true
  @lhs_column = token.location.column
  @state = :rule_colon
  :LHS
end

#string_value(token) ⇒ String

RBS:

  • (Token token) -> String

Parameters:

Returns:

  • (String)


211
212
213
214
215
216
# File 'lib/ibex/frontend/token_adapter/rule_state.rb', line 211

def string_value(token)
  value = token.value
  return value if value.is_a?(String)

  raise Ibex::Error, "#{token.location}: expected text token"
end