Class: Ibex::Normalizer

Overview

Converts a frontend AST into immutable Grammar IR.

Constant Summary collapse

RESERVED_NAMES =

: Array

%w[result val _values].freeze
RUBY_KEYWORDS =
%w[
  __ENCODING__ __FILE__ __LINE__ alias and begin break case class def defined do else elsif end ensure false for if
  in module next nil not or redo rescue retry return self super then true undef unless until when while yield
].freeze
DEFAULT_MAX_PARAMETER_SPECIALIZATIONS =

: Array

1_000
DEFAULT_MAX_INLINE_EXPANSIONS =
10_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input, mode: :default, max_parameter_specializations: DEFAULT_MAX_PARAMETER_SPECIALIZATIONS, max_inline_expansions: DEFAULT_MAX_INLINE_EXPANSIONS) ⇒ Normalizer

Returns a new instance of Normalizer.

Raises:

  • (ArgumentError)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/ibex/normalize.rb', line 102

def initialize(input, mode: :default, max_parameter_specializations: DEFAULT_MAX_PARAMETER_SPECIALIZATIONS,
               max_inline_expansions: DEFAULT_MAX_INLINE_EXPANSIONS)
  validate_positive_limit!(:max_parameter_specializations, max_parameter_specializations)
  validate_positive_limit!(:max_inline_expansions, max_inline_expansions)
  normalized_mode = mode.to_sym
  raise ArgumentError, "mode must be :default or :extended" unless %i[default extended].include?(normalized_mode)

  @resolution = input if input.is_a?(Frontend::Resolution)
  ast = input.is_a?(Frontend::Resolution) ? input.root : input
  normalized_mode = :extended if ast.is_a?(Frontend::AST::Root) && ast.extended
  fail_at(ast.loc, "fragments must be resolved before normalization") if ast.is_a?(Frontend::AST::Fragment)
  unresolved = ast.declarations.find { |declaration| declaration.is_a?(Frontend::AST::Include) }
  fail_at(unresolved.loc, "includes must be resolved before normalization") if unresolved

  @ast = ast
  @mode = normalized_mode #: IR::grammar_mode
  @phase_guard = Normalize::PhaseGuard.new
  @symbols = [] #: Array[IR::GrammarSymbol]
  @symbols_by_name = {} #: Hash[String, IR::GrammarSymbol]
  @productions = [] #: Array[IR::Production]
  @warnings = [] #: Array[IR::grammar_warning]
  @helper_sequence = 0
  @current_include_chain = [] #: Array[IR::source_provenance]
  @parameter_specializations = {} #: Hash[[String, Array[String]], String]
  @parameter_worklist = [] #: Array[NormalizeParameters::parameter_frame]
  @parameter_worklist_active = false
  @max_parameter_specializations = max_parameter_specializations
  @max_inline_expansions = max_inline_expansions
  @inline_expansion_count = 0
  @inline_symbol_ids = Set.new #: Set[Integer]
  @inline_rule_by_symbol = {} #: Hash[Integer, String]
end

Instance Attribute Details

#phase_guardObject (readonly)

: Normalize::PhaseGuard



51
52
53
# File 'lib/ibex/normalize.rb', line 51

def phase_guard
  @phase_guard
end

Instance Method Details

#contextObject



157
# File 'lib/ibex/normalize.rb', line 157

def context = @phase_guard

#normalizeObject



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

def normalize
  phase(:declarations) { read_declarations }
  phase(:parameter_templates) { gather_parameter_templates }
  phase(:inline_rules) { gather_inline_rules }
  phase(:symbols) do
    intern_reserved_symbols
    intern_declared_terminals
    intern_user_nonterminals
  end
  parser_contract = phase(:parser_contract) { normalized_parser_contract }
  phase(:productions) { normalize_user_productions }
  phase(:expansions) { expand_inline_rules }
  phase(:validation) do
    validate_value_printers
    validate_recovery_declarations
    validate_grammar
  end
  phase(:build) { build_grammar(parser_contract) }
end