Module: Ibex::Frontend::BootstrapParserRules

Included in:
BootstrapParser
Defined in:
lib/ibex/frontend/parser/rules.rb,
sig/ibex/frontend/parser/rules.rbs

Overview

Parses productions and extended RHS items.

Constant Summary collapse

EXTENDED_SUFFIXES =

Returns:

{
  "?": AST::Optional, "*": AST::Star, "+": AST::Plus
}.freeze

Instance Method Summary collapse

Instance Method Details

#alternative_end?(lhs) ⇒ Boolean

RBS:

  • (Token lhs) -> bool

Parameters:

Returns:

  • (Boolean)


170
171
172
173
# File 'lib/ibex/frontend/parser/rules.rb', line 170

def alternative_end?(lhs)
  # @type self: BootstrapParser
  %i[| ; inline node eof user_code].include?(current.type) || keyword?("end") || rule_start?(lhs)
end

#parse_actionAST::InlineAction

RBS:

  • () -> AST::InlineAction

Returns:



109
110
111
112
113
# File 'lib/ibex/frontend/parser/rules.rb', line 109

def parse_action
  # @type self: BootstrapParser
  token = advance
  AST::InlineAction.new(code: token_string(token), loc: token.location)
end

#parse_alternative(lhs) ⇒ AST::Alternative

RBS:

  • (Token lhs) -> AST::Alternative

Parameters:

Returns:



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ibex/frontend/parser/rules.rb', line 45

def parse_alternative(lhs)
  # @type self: BootstrapParser
  location = current.location
  items = [] #: Array[AST::item]
  precedence = nil #: String?
  until alternative_end?(lhs)
    if accept(:"=")
      precedence = parse_symbol_name
      break
    end
    items << parse_item
  end
  action = nil #: AST::InlineAction?
  last_item = items.last
  if last_item.is_a?(AST::InlineAction)
    items.pop
    action = last_item
  end
  node_annotation = parse_node_annotation
  AST::Alternative.new(
    items: items, action: action, precedence: precedence, node_annotation: node_annotation, loc: location
  )
end

#parse_groupAST::item

RBS:

  • () -> AST::item

Returns:

  • (AST::item)


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ibex/frontend/parser/rules.rb', line 136

def parse_group
  # @type self: BootstrapParser
  opening = advance
  extended_only!(opening.location, "EBNF groups")
  alternatives = [[]] #: Array[Array[AST::item]]
  until current.type == :")"
    fail_at(opening.location, "unterminated EBNF group") if current.type == :eof
    if accept(:|)
      alternatives << []
      next
    end
    fail_at(current.location, "actions inside EBNF groups are not supported") if current.type == :action

    alternatives.last << parse_item
  end
  expect(:")")
  parse_suffix(AST::Group.new(alternatives: alternatives, loc: opening.location))
end

#parse_itemAST::item

RBS:

  • () -> AST::item

Returns:

  • (AST::item)


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ibex/frontend/parser/rules.rb', line 88

def parse_item
  # @type self: BootstrapParser
  return parse_action if current.type == :action

  if current.type == :empty
    token = advance
    extended_only!(token.location, "%empty")
    return AST::Empty.new(loc: token.location)
  end
  return parse_separated_list if separated_list?
  return parse_parameterized_reference if parameterized_call?
  return parse_group if current.type == :"("

  token = expect_symbol
  named_reference = parse_named_reference
  item = AST::SymbolReference.new(name: token_string(token), named_reference: named_reference,
                                  loc: token.location)
  parse_suffix(item)
end

#parse_named_referenceString?

RBS:

  • () -> String?

Returns:

  • (String, nil)


116
117
118
119
120
121
122
123
# File 'lib/ibex/frontend/parser/rules.rb', line 116

def parse_named_reference
  # @type self: BootstrapParser
  return nil unless current.type == :":"

  extended_only!(current.location, "named references")
  advance
  token_string(expect(:identifier))
end

#parse_node_annotationAST::NodeAnnotation?

RBS:

  • () -> AST::NodeAnnotation?

Returns:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ibex/frontend/parser/rules.rb', line 70

def parse_node_annotation
  # @type self: BootstrapParser
  marker = accept(:node)
  return unless marker

  extended_only!(marker.location, "@node")
  name = expect(:identifier)
  expect(:"(")
  fields = [] #: Array[String]
  unless current.type == :")"
    fields << token_string(expect(:identifier))
    fields << token_string(expect(:identifier)) while accept(:",")
  end
  expect(:")")
  AST::NodeAnnotation.new(name: token_string(name), fields: fields, loc: marker.location)
end

#parse_ruleAST::Rule

RBS:

  • () -> AST::Rule

Returns:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/ibex/frontend/parser/rules.rb', line 23

def parse_rule
  # @type self: BootstrapParser
  inline = accept(:inline)
  extended_only!(inline.location, "inline rules") if inline
  lhs = expect(:identifier)
  parameters = parse_rule_parameters(lhs)
  expect(:":")
  alternatives = [] #: Array[AST::Alternative]
  loop do
    alternatives << parse_alternative(lhs)
    next if accept(:|)

    accept(:";")
    break
  end
  AST::Rule.new(
    lhs: token_string(lhs), parameters: parameters, alternatives: alternatives, loc: lhs.location,
    inline: !!inline
  )
end

#parse_rulesArray[AST::Rule]

RBS:

  • () -> Array[AST::Rule]

Returns:



14
15
16
17
18
19
20
# File 'lib/ibex/frontend/parser/rules.rb', line 14

def parse_rules
  # @type self: BootstrapParser
  rules = [] #: Array[AST::Rule]
  rules << parse_rule until keyword?("end") || %i[eof user_code].include?(current.type)
  fail_expected("at least one rule") if rules.empty?
  rules
end

#parse_separated_listAST::SeparatedList

RBS:

  • () -> AST::SeparatedList

Returns:



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/ibex/frontend/parser/rules.rb', line 156

def parse_separated_list
  # @type self: BootstrapParser
  function = advance
  extended_only!(function.location, "separated lists")
  expect(:"(")
  item = parse_item
  expect(:",")
  separator = parse_item
  expect(:")")
  AST::SeparatedList.new(item: item, separator: separator,
                         nonempty: function.value == "separated_nonempty_list", loc: function.location)
end

#parse_suffix(item) ⇒ AST::item

RBS:

  • (AST::item item) -> AST::item

Parameters:

  • item (AST::item)

Returns:

  • (AST::item)


126
127
128
129
130
131
132
133
# File 'lib/ibex/frontend/parser/rules.rb', line 126

def parse_suffix(item)
  # @type self: BootstrapParser
  while (wrapper = EXTENDED_SUFFIXES[current.type])
    extended_only!(current.location, "EBNF suffixes")
    item = wrapper.new(item: item, loc: advance.location)
  end
  item
end

#rule_start?(lhs) ⇒ Boolean

RBS:

  • (Token lhs) -> bool

Parameters:

Returns:

  • (Boolean)


176
177
178
179
180
181
182
# File 'lib/ibex/frontend/parser/rules.rb', line 176

def rule_start?(lhs)
  # @type self: BootstrapParser
  return false unless current.type == :identifier && current.location.column <= lhs.location.column
  return true if lookahead.type == :":"

  parameterized_rule_start?
end

#separated_list?Boolean

RBS:

  • () -> bool

Returns:

  • (Boolean)


185
186
187
188
# File 'lib/ibex/frontend/parser/rules.rb', line 185

def separated_list?
  # @type self: BootstrapParser
  %w[separated_list separated_nonempty_list].include?(current.value) && lookahead.type == :"("
end