diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 483afb45..97e32986 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -35,6 +35,7 @@ jobs: ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: bundle install + - run: bundle exec rbs collection install - run: bundle exec steep check test-ruby: runs-on: ubuntu-20.04 diff --git a/.gitignore b/.gitignore index e14c5727..b1ae6365 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .irbrc /Gemfile.lock /pkg/ +/.gem_rbs_collection/ diff --git a/Steepfile b/Steepfile index 12efa39a..1d9f6c45 100644 --- a/Steepfile +++ b/Steepfile @@ -1,7 +1,12 @@ -# D = Steep::Diagnostic -# +D = Steep::Diagnostic + target :lib do signature "sig" - check "lib/lrama/bitmap.rb" + configure_code_diagnostics do |hash| + hash[D::Ruby::ImplicitBreakValueMismatch] = :hint + hash[D::Ruby::ElseOnExhaustiveCase] = :hint + end + + check "lib/lrama/" end diff --git a/lib/lrama/context.rb b/lib/lrama/context.rb index 90864700..96ade43e 100644 --- a/lib/lrama/context.rb +++ b/lib/lrama/context.rb @@ -118,7 +118,7 @@ def yytable_ninf end def yypact - @base[0...yynstates] + @base[0...yynstates] || raise end def yydefact @@ -126,7 +126,7 @@ def yydefact end def yypgoto - @base[yynstates..-1] + @base[yynstates..-1] || raise end def yydefgoto @@ -227,6 +227,7 @@ def compute_yydefact # * number = -Float::INFINITY, error by %nonassoc # * number > 0, shift then move to state "number" # * number < 0, reduce by "-number" rule. Rule "number" is already added by 1. + # @type var actions: Array[Integer | Float] actions = Array.new(@states.terms.count, 0) if state.reduces.map(&:selected_look_ahead).any? {|la| !la.empty? } @@ -273,9 +274,11 @@ def compute_yydefact end end + # @type var s: Array[[Integer, Integer]] s = actions.each_with_index.map do |n, i| - [i, n] - end.select do |i, n| + [i, n] #: [Integer, Integer] + end + s = s.select do |i, n| # Remove default_reduction_rule entries n != 0 end @@ -287,10 +290,10 @@ def compute_yydefact # * Array of tuple, [from, to] where from is term number and to is action. # * The number of "Array of tuple" used by sort_actions # * "width" used by sort_actions - @_actions << [state.id, s, s.count, s.last[0] - s.first[0] + 1] + @_actions << [state.id, s, s.count, (s.last || raise)[0] - (s.first || raise)[0] + 1] end - @yydefact[state.id] = state.default_reduction_rule ? state.default_reduction_rule.id + 1 : 0 + (@yydefact || raise)[state.id] = state.default_reduction_rule ? state.default_reduction_rule.id + 1 : 0 end end @@ -327,7 +330,7 @@ def compute_yydefgoto end k = nterm_number_to_sequence_number(nterm.number) - @yydefgoto[k] = default_goto + (@yydefgoto || raise)[k] = default_goto if not_default_gotos.count != 0 v = nterm_number_to_vector_number(nterm.number) @@ -427,7 +430,7 @@ def compute_packed_table next end - res = lowzero - froms_and_tos.first[0] + res = lowzero - (froms_and_tos.first || raise)[0] while true do ok = true @@ -476,7 +479,7 @@ def compute_packed_table @yylast = high # replace_ninf - @yypact_ninf = (@base.select {|i| i != BaseMin } + [0]).min - 1 + @yypact_ninf = ((@base.select {|i| i != BaseMin } + [0]).min || raise) - 1 @base.map! do |i| case i when BaseMin @@ -486,7 +489,7 @@ def compute_packed_table end end - @yytable_ninf = (@table.compact.select {|i| i != ErrorActionNumber } + [0]).min - 1 + @yytable_ninf = ((@table.compact.select {|i| i != ErrorActionNumber } + [0]).min || raise) - 1 @table.map! do |i| case i when nil diff --git a/lib/lrama/digraph.rb b/lib/lrama/digraph.rb index 28f26781..0b9a4e22 100644 --- a/lib/lrama/digraph.rb +++ b/lib/lrama/digraph.rb @@ -35,7 +35,7 @@ def traverse(x) @relation[x] && @relation[x].each do |y| traverse(y) if @h[y] == 0 - @h[x] = [@h[x], @h[y]].min + @h[x] = [@h[x], @h[y]].min || raise @result[x] |= @result[y] # F x = F x + F y end diff --git a/lib/lrama/grammar.rb b/lib/lrama/grammar.rb index 8ca75cb6..138d1f68 100644 --- a/lib/lrama/grammar.rb +++ b/lib/lrama/grammar.rb @@ -2,7 +2,7 @@ require "lrama/lexer" module Lrama - Rule = Struct.new(:id, :lhs, :rhs, :code, :nullable, :precedence_sym, :lineno, keyword_init: true) do + class Rule < Struct.new(:id, :lhs, :rhs, :code, :nullable, :precedence_sym, :lineno, keyword_init: true) # TODO: Change this to display_name def to_s l = lhs.id.s_value @@ -41,7 +41,7 @@ def translated_code # `token_id` is tokentype for term, internal sequence number for nterm # # TODO: Add validation for ASCII code range for Token::Char - Symbol = Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, keyword_init: true) do + class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, keyword_init: true) attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol def term? @@ -89,19 +89,19 @@ def enum_name if alias_name name = number.to_s + alias_name else - name = number.to_s + id.s_value + name = number.to_s + id.s_value_str end when term? && id.type == Token::Ident - name = id.s_value - when nterm? && (id.s_value.include?("$") || id.s_value.include?("@")) - name = number.to_s + id.s_value + name = id.s_value_str + when nterm? && (id.s_value_str.include?("$") || id.s_value_str.include?("@")) + name = number.to_s + id.s_value_str when nterm? - name = id.s_value + name = id.s_value_str else raise "Unexpected #{self}" end - "YYSYMBOL_" + name.gsub(/[^a-zA-Z_0-9]+/, "_") + "YYSYMBOL_" + (name || raise).gsub(/[^a-zA-Z_0-9]+/, "_") end # comment for yysymbol_kind_t @@ -113,22 +113,23 @@ def comment when eof_symbol? # YYEOF alias_name - when (term? && 0 < token_id && token_id < 128) + when (term? && 0 < (token_id || raise) && (token_id || raise) < 128) # YYSYMBOL_3_backslash_, YYSYMBOL_14_ alias_name || id.s_value - when id.s_value.include?("$") || id.s_value.include?("@") + when id.s_value_str.include?("$") || id.s_value_str.include?("@") # YYSYMBOL_21_1 - id.s_value + id.s_value_str else # YYSYMBOL_keyword_class, YYSYMBOL_strings_1 - alias_name || id.s_value + alias_name || id.s_value_str end end end - Type = Struct.new(:id, :tag, keyword_init: true) + class Type < Struct.new(:id, :tag, keyword_init: true) + end - Code = Struct.new(:type, :token_code, keyword_init: true) do + class Code < Struct.new(:type, :token_code, keyword_init: true) extend Forwardable def_delegators "token_code", :s_value, :line, :column, :references @@ -166,7 +167,7 @@ def translated_printer_code(tag) when ref.type == :at # @n raise "@#{ref.number} can not be used in %printer." else - raise "Unexpected. #{code}, #{ref}" + raise "Unexpected. #{self}, #{ref}" end t_code[first_column..last_column] = str @@ -205,7 +206,7 @@ def translated_user_code i = -ref.position_in_rhs + ref.number str = "(yylsp[#{i}])" else - raise "Unexpected. #{code}, #{ref}" + raise "Unexpected. #{self}, #{ref}" end t_code[first_column..last_column] = str @@ -235,7 +236,7 @@ def translated_initial_action_code when ref.type == :at # @n raise "@#{ref.number} can not be used in initial_action." else - raise "Unexpected. #{code}, #{ref}" + raise "Unexpected. #{self}, #{ref}" end t_code[first_column..last_column] = str @@ -247,7 +248,7 @@ def translated_initial_action_code # type: :dollar or :at # ex_tag: "$1" (Optional) - Reference = Struct.new(:type, :number, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true) do + class Reference < Struct.new(:type, :number, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true) def tag if ex_tag ex_tag @@ -257,7 +258,7 @@ def tag end end - Precedence = Struct.new(:type, :precedence, keyword_init: true) do + class Precedence < Struct.new(:type, :precedence, keyword_init: true) include Comparable def <=>(other) @@ -265,13 +266,13 @@ def <=>(other) end end - Printer = Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true) do + class Printer < Struct.new(:ident_or_tags, :code, :lineno, keyword_init: true) def translated_code(member) code.translated_printer_code(member) end end - Union = Struct.new(:code, :lineno, keyword_init: true) do + class Union < Struct.new(:code, :lineno, keyword_init: true) def braces_less_code # Remove braces code.s_value[1..-2] @@ -283,7 +284,8 @@ def braces_less_code # Grammar is the result of parsing an input grammar file class Grammar # Grammar file information not used by States but by Output - Aux = Struct.new(:prologue_first_lineno, :prologue, :epilogue_first_lineno, :epilogue, keyword_init: true) + class Aux < Struct.new(:prologue_first_lineno, :prologue, :epilogue_first_lineno, :epilogue, keyword_init: true) + end attr_reader :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux attr_accessor :union, :expect, @@ -565,7 +567,7 @@ def append_special_symbols # $accept term = add_nterm(id: Token.new(type: Token::Ident, s_value: "$accept")) - term.accept_symbol = true + (term || raise).accept_symbol = true @accept_symbol = term end @@ -595,15 +597,18 @@ def normalize_rules # 1. Add $accept rule to the top of rules accept = find_symbol_by_s_value!("$accept") eof = find_symbol_by_number!(0) - lineno = @_rules.first ? @_rules.first[2] : 0 - @rules << Rule.new(id: @rules.count, lhs: accept, rhs: [@_rules.first[0], eof], code: nil, lineno: lineno) + lineno = @_rules.first ? (@_rules.first || raise)[2] : 0 + @rules << Rule.new(id: @rules.count, lhs: accept, rhs: [(@_rules.first || raise)[0], eof], code: nil, lineno: lineno) extracted_action_number = 1 # @n as nterm @_rules.each do |lhs, rhs, lineno| + # @type var a: Array[[Token, Token]] a = [] rhs1 = [] + # @type var code: Token? code = nil + # @type var precedence_sym: Symbol? precedence_sym = nil # 2. Extract precedence and last action @@ -672,6 +677,7 @@ def normalize_rules # Collect symbols from rules def collect_symbols @rules.flat_map(&:rhs).each do |s| + # @type var s: Token | Symbol case s when Token if s.type == Token::Char @@ -704,6 +710,7 @@ def fill_symbol_number end (@symbols.select(&:term?) + @symbols.select(&:nterm?)).each do |sym| + # @type var sym: Symbol while used_numbers[number] do number += 1 end @@ -795,6 +802,7 @@ def fill_default_precedence # Explicitly specified precedence has the highest priority next if rule.precedence_sym + # @type var precedence_sym: Symbol? precedence_sym = nil rule.rhs.each do |sym| precedence_sym = sym if sym.term? diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index 6c1139b4..33fb5d49 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -7,8 +7,20 @@ class Lexer include Lrama::Report::Duration # s_value is semantic value - Token = Struct.new(:type, :s_value, keyword_init: true) do - Type = Struct.new(:id, :name, keyword_init: true) + class Token < Struct.new(:type, :s_value, keyword_init: true) + def s_value_int + s = s_value + raise unless s.is_a?(Integer) + s + end + def s_value_str + s = s_value + raise unless s.is_a?(String) + s + end + + class Type < Struct.new(:id, :name, keyword_init: true) + end attr_accessor :line, :column, :referred # For User_code @@ -219,7 +231,7 @@ def lex_common(lines, tokens) else l = line - lines.first[1] split = ss.string.split("\n") - col = ss.pos - split[0...l].join("\n").length + col = ss.pos - (split[0...l] || raise).join("\n").length raise "Parse error (unknown token): #{split[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{col})" end end @@ -283,7 +295,7 @@ def lex_user_code(ss, line, column, lines) line = lex_line_comment(ss, line, str) else # noop, just consume char - str << ss.getch + str << (ss.getch || raise) next end @@ -328,7 +340,7 @@ def lex_comment(ss, line, lines, str) when ss.scan(/\*\//) return line else - str << ss.getch + str << (ss.getch || raise) next end @@ -347,7 +359,7 @@ def lex_line_comment(ss, line, str) when ss.scan(/\n/) return line + 1 else - str << ss.getch + str << (ss.getch || raise) next end diff --git a/lib/lrama/output.rb b/lib/lrama/output.rb index 696aa79f..eb0c140f 100644 --- a/lib/lrama/output.rb +++ b/lib/lrama/output.rb @@ -25,13 +25,15 @@ def initialize(out:, output_file_path:, template_name:, grammar_file_path:, head @grammar = grammar end - if ERB.instance_method(:initialize).parameters.last.first == :key - def self.erb(input) - ERB.new(input, trim_mode: '-') - end - else - def self.erb(input) - ERB.new(input, nil, '-') + __skip__ = begin + if ERB.instance_method(:initialize).parameters.last.first == :key + def self.erb(input) + ERB.new(input, trim_mode: '-') + end + else + def self.erb(input) + ERB.new(input, nil, '-') + end end end @@ -47,13 +49,15 @@ def render tmp = eval_template(template_file, @output_file_path) @out << tmp - if @header_file_path - tmp = eval_template(header_template_file, @header_file_path) + header_file_path = @header_file_path + if header_file_path + tmp = eval_template(header_template_file, header_file_path) - if @header_out - @header_out << tmp + header_out = @header_out + if header_out + header_out << tmp else - File.write(@header_file_path, tmp) + File.write(header_file_path, tmp) end end end @@ -224,7 +228,7 @@ def user_args end def extract_param_name(param) - /\A(.)+([a-zA-Z0-9_]+)\z/.match(param)[2] + (/\A(.)+([a-zA-Z0-9_]+)\z/.match(param) || raise)[2] || raise end def parse_param_name @@ -317,8 +321,9 @@ def spec_mapped_header_file end def b4_cpp_guard__b4_spec_mapped_header_file - if @header_file_path - "YY_YY_" + @header_file_path.gsub(/[^a-zA-Z_0-9]+/, "_").upcase + "_INCLUDED" + header_file_path = @header_file_path + if header_file_path + "YY_YY_" + header_file_path.gsub(/[^a-zA-Z_0-9]+/, "_").upcase + "_INCLUDED" else "" end diff --git a/lib/lrama/parser.rb b/lib/lrama/parser.rb index e90a94c6..693260ce 100644 --- a/lib/lrama/parser.rb +++ b/lib/lrama/parser.rb @@ -159,8 +159,8 @@ def parse_bison_declarations(ts, grammar) # Can replace 0 (EOF) grammar.add_term( id: id, - alias_name: opt_string && opt_string.s_value, - token_id: opt_number && opt_number.s_value, + alias_name: opt_string && opt_string.s_value_str, + token_id: opt_number && opt_number.s_value_int, tag: opt_tag, replace: true, ) @@ -229,7 +229,7 @@ def parse_grammar_rule(ts, grammar) rhs = parse_grammar_rule_rhs(ts, grammar) - grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? rhs.first.line : lhs.line) + grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? (rhs.first || raise).line : lhs.line) while true do case ts.current_type @@ -238,7 +238,7 @@ def parse_grammar_rule(ts, grammar) bar_lineno = ts.current_token.line ts.next rhs = parse_grammar_rule_rhs(ts, grammar) - grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? rhs.first.line : bar_lineno) + grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? (rhs.first || raise).line : bar_lineno) when T::Semicolon # ; ts.next diff --git a/lib/lrama/states.rb b/lib/lrama/states.rb index f907db30..0b439394 100644 --- a/lib/lrama/states.rb +++ b/lib/lrama/states.rb @@ -28,7 +28,7 @@ def add_not_selected_symbol(sym) def selected_look_ahead if @look_ahead - @look_ahead - @not_selected_symbols + (@look_ahead || raise) - @not_selected_symbols else [] end @@ -48,7 +48,7 @@ def initialize(next_sym, next_items) # * symbol: A symbol under discussion # * reduce: A reduce under discussion # * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative) - ResolvedConflict = Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) do + class ResolvedConflict < Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) def report_message s = symbol.display_name r = reduce.rule.precedence_sym.display_name @@ -71,7 +71,8 @@ def report_message end end - Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true) + class Conflict < Struct.new(:symbols, :reduce, :type, keyword_init: true) + end attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts, :default_reduction_rule, :closure, :items @@ -133,7 +134,7 @@ def set_items_to_state(items, next_state) def set_look_ahead(rule, look_ahead) reduce = reduces.find do |r| r.rule == rule - end + end || raise reduce.look_ahead = look_ahead end @@ -198,7 +199,7 @@ def transition(sym) def find_reduce_by_item!(item) reduces.find do |r| r.item == item - end || (raise "reduce is not found. #{item}, #{state}") + end || (raise "reduce is not found. #{item}") end def default_reduction_rule=(default_reduction_rule) @@ -236,7 +237,7 @@ class States :accept_symbol, :eof_symbol, :find_symbol_by_s_value! # TODO: Validate position is not over rule rhs - Item = Struct.new(:rule, :position, keyword_init: true) do + class Item < Struct.new(:rule, :position, keyword_init: true) # Optimization for States#setup_state def hash [rule.id, position].hash @@ -411,16 +412,6 @@ def rr_conflicts @states.flat_map(&:rr_conflicts) end - def initial_attrs - h = {} - - attrs.each do |attr| - h[attr.id] = false - end - - h - end - def trace_state if @trace_state yield STDERR @@ -603,7 +594,7 @@ def compute_reads_relation def compute_read_sets sets = nterm_transitions.map do |state, nterm, next_state| - [state.id, nterm.token_id] + [state.id, nterm.token_id] #: [::Integer, untyped] end @read_sets = Digraph.new(sets, @reads_relation, @direct_read_sets).compute @@ -661,7 +652,7 @@ def compute_lookback_relation def compute_follow_sets sets = nterm_transitions.map do |state, nterm, next_state| - [state.id, nterm.token_id] + [state.id, nterm.token_id] #: [::Integer, untyped] end @follow_sets = Digraph.new(sets, @includes_relation, @read_sets).compute @@ -794,11 +785,11 @@ def compute_default_reduction # Do not set, if shift with `error` exists. next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol) - state.default_reduction_rule = state.reduces.map do |r| + state.default_reduction_rule = (state.reduces.map do |r| [r.rule, r.rule.id, (r.look_ahead || []).count] end.sort_by do |rule, rule_id, count| [-count, rule_id] - end.first.first + end.first || raise).first end end diff --git a/lib/lrama/states_reporter.rb b/lib/lrama/states_reporter.rb index 25893e61..d28dca0f 100644 --- a/lib/lrama/states_reporter.rb +++ b/lib/lrama/states_reporter.rb @@ -139,6 +139,7 @@ def report_states(io, itemsets, lookaheads, solved, verbose) nl = false max_len = state.non_default_reduces.flat_map(&:look_ahead).compact.map(&:display_name).map(&:length).max || 0 max_len = [max_len, "$default".length].max if state.default_reduction_rule + # @type var ary: Array[[untyped, State::Reduce]] ary = [] state.non_default_reduces.each do |reduce| @@ -284,6 +285,7 @@ def report_states(io, itemsets, lookaheads, solved, verbose) # Report LA io << " [Look-Ahead Sets]\n" + # @type var tmp: Array[[Rule, Array[Symbol]]] tmp = [] max_len = 0 @states.rules.each do |rule| @@ -295,7 +297,7 @@ def report_states(io, itemsets, lookaheads, solved, verbose) end tmp.each do |rule, syms| syms.each do |sym| - io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n" + io << " #{sym.id.s_value_str.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n" end end io << "\n" if !tmp.empty? diff --git a/rbs_collection.lock.yaml b/rbs_collection.lock.yaml new file mode 100644 index 00000000..205e6778 --- /dev/null +++ b/rbs_collection.lock.yaml @@ -0,0 +1,34 @@ +--- +sources: +- type: git + name: ruby/gem_rbs_collection + revision: d0d7aeed98fa74427b30b336fc402ea86d526f35 + remote: https://github.com/ruby/gem_rbs_collection.git + repo_dir: gems +path: ".gem_rbs_collection" +gems: +- name: erb + version: '0' + source: + type: stdlib +- name: forwardable + version: '0' + source: + type: stdlib +- name: optparse + version: '0' + source: + type: stdlib +- name: stackprof + version: '0.2' + source: + type: git + name: ruby/gem_rbs_collection + revision: d0d7aeed98fa74427b30b336fc402ea86d526f35 + remote: https://github.com/ruby/gem_rbs_collection.git + repo_dir: gems +- name: strscan + version: '0' + source: + type: stdlib +gemfile_lock_path: Gemfile.lock diff --git a/rbs_collection.yaml b/rbs_collection.yaml new file mode 100644 index 00000000..ef9c283f --- /dev/null +++ b/rbs_collection.yaml @@ -0,0 +1,24 @@ +# Download sources +sources: + - type: git + name: ruby/gem_rbs_collection + remote: https://github.com/ruby/gem_rbs_collection.git + revision: main + repo_dir: gems + +# You can specify local directories as sources also. +# - type: local +# path: path/to/your/local/repository + +# A directory to install the downloaded RBSs +path: .gem_rbs_collection + +gems: + # Skip loading rbs gem's RBS. + # It's unnecessary if you don't use rbs as a library. + - name: rbs + ignore: true + - name: strscan + - name: erb + - name: forwardable + - name: optparse diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs new file mode 100644 index 00000000..bd9e1fb2 --- /dev/null +++ b/sig/lrama/typeprof-generated.rbs @@ -0,0 +1,676 @@ +# Prevent so many false positives in lib/lrama/lexer.rb +class StringScanner + def []: (Integer) -> String | ... +end + +module Lrama + VERSION: String + include Comparable + + def to_s: -> String + def as_comment: -> String + def precedence: -> untyped + def initial_rule?: -> untyped + def term?: -> untyped + def nterm?: -> untyped + + public + def tag: -> untyped + def <=>: (untyped other) -> untyped + def braces_less_code: -> untyped + + class Command + def run: (untyped argv) -> void + + private + def validate_report: (untyped report) -> Hash[::Symbol, bool] + def validate_trace: (untyped trace) -> Hash[untyped, untyped] + end + + class Context + include Report::Duration + + ErrorActionNumber: Float + BaseMin: Float + @yydefact: Array[Integer]? + @yydefgoto: Array[Integer]? + @_actions: Array[[Integer, Array[[Integer, Integer]], Integer, Integer]] + @yylast: Integer + @yypact_ninf: Float | Integer + @yytable_ninf: Integer + @base: Array[Float | Integer] + @table: Array[Integer] + @check: Array[untyped] + @sorted_actions: Array[[Integer, Array[[Integer, Integer]], Integer, Integer]] + + attr_reader states: untyped + def initialize: (untyped states) -> void + def yytokentype: -> untyped + def yysymbol_kind_t: -> untyped + def yyfinal: -> untyped + def yylast: -> Integer? + def yyntokens: -> untyped + def yynnts: -> untyped + def yynrules: -> untyped + def yynstates: -> untyped + def yymaxutok: -> untyped + def yytranslate: -> Array[Integer] + def yyrline: -> Array[Integer] + def yytname: -> untyped + def yypact_ninf: -> ((Float | Integer)?) + def yytable_ninf: -> Integer? + def yypact: -> (Array[Float | Integer]) + def yydefact: -> Array[Integer]? + def yypgoto: -> (Array[Float | Integer]) + def yydefgoto: -> Array[Integer]? + def yytable: -> Array[Integer]? + def yycheck: -> Array[untyped]? + def yystos: -> untyped + def yyr1: -> Array[Integer] + def yyr2: -> Array[Integer] + + private + def compute_tables: -> untyped + def vectors_count: -> untyped + def rule_id_to_action_number: (untyped rule_id) -> untyped + def nterm_number_to_sequence_number: (untyped nterm_number) -> untyped + def nterm_number_to_vector_number: (untyped nterm_number) -> untyped + def compute_yydefact: -> untyped + def compute_yydefgoto: -> untyped + def sort_actions: -> Array[untyped] + def debug_sorted_actions: -> untyped + def compute_packed_table: -> void + end + + class Digraph + @sets: Array[[Integer, untyped]] + @relation: Hash[untyped, untyped] + @base_function: Hash[untyped, Integer] + @stack: Array[[Integer, untyped]] + @h: Hash[untyped, Float | Integer] + @result: Hash[untyped, Integer] + + def initialize: (Array[[Integer, untyped]] sets, Hash[untyped, untyped] relation, Hash[untyped, Integer] base_function) -> void + def compute: -> Hash[untyped, Integer] + + private + def traverse: ([Integer, untyped] x) -> nil + end + + class Rule + def initialize: (id: Integer, lhs: untyped, rhs: untyped, code: untyped, ?nullable: untyped, ?precedence_sym: untyped, lineno: Integer) -> void + + attr_accessor id(): Integer + attr_accessor lhs(): Symbol + attr_accessor rhs(): Array[Symbol] + attr_accessor code(): Code? + attr_accessor nullable(): bool + attr_accessor precedence_sym(): Symbol? + attr_accessor lineno(): Integer + def translated_code: -> untyped + end + + class Symbol + def initialize: (id: Token, alias_name: untyped, number: untyped, tag: untyped, term: untyped, token_id: untyped, nullable: untyped, ?precedence: untyped, ?printer: untyped) -> void + attr_accessor id(): Token + attr_accessor alias_name(): String? + attr_accessor number(): Integer? + attr_accessor tag(): Token? + attr_accessor term(): bool + attr_accessor token_id(): Integer? + attr_accessor nullable(): bool + attr_accessor precedence(): Precedence + attr_accessor printer(): Printer + attr_writer eof_symbol: bool + attr_writer error_symbol: bool + attr_writer undef_symbol: bool + attr_writer accept_symbol: bool + def term?: -> bool + def nterm?: -> bool + def eof_symbol?: -> bool + def error_symbol?: -> bool + def undef_symbol?: -> bool + def accept_symbol?: -> bool + def display_name: -> untyped + def enum_name: -> String + def comment: -> untyped + end + + class Type + def initialize: (id: untyped, tag: untyped) -> void + attr_accessor id(): untyped + attr_accessor tag(): nil + end + + class Code + def initialize: (type: :initial_action | :lex_param | :parse_param | :printer | :union | :user_code, token_code: Token) -> void + + extend Forwardable + + # Forwardable methods for Grammer + def s_value: -> untyped + def line: -> Integer + def column: -> Integer + def references: -> untyped + + attr_accessor type(): :initial_action | :lex_param | :parse_param | :printer | :union | :user_code + attr_accessor token_code(): untyped + + def translated_code: -> untyped + def translated_printer_code: (untyped tag) -> untyped + + private + def translated_user_code: -> untyped + def translated_initial_action_code: -> untyped + end + + class Reference + def initialize: (type: untyped, number: untyped, ex_tag: untyped, first_column: untyped, last_column: untyped, ?referring_symbol: untyped, ?position_in_rhs: untyped) -> void + attr_accessor type(): untyped + attr_accessor number(): untyped + attr_accessor ex_tag(): untyped + attr_accessor first_column(): untyped + attr_accessor last_column(): untyped + attr_accessor referring_symbol(): untyped + attr_accessor position_in_rhs(): untyped + end + + class Precedence + def initialize: (type: :left | :nonassoc | :right, precedence: Integer) -> void + attr_accessor type(): :left | :nonassoc | :right + attr_accessor precedence(): Integer + end + + class Printer + def initialize: (ident_or_tags: untyped, code: Code, lineno: Integer) -> void + attr_accessor ident_or_tags(): Array[untyped] + attr_accessor code(): Code + attr_accessor lineno(): Integer + def translated_code: (untyped member) -> untyped + end + + class Union + def initialize: (code: Code, lineno: Integer) -> void + attr_accessor code(): Code + attr_accessor lineno(): untyped + end + + class Grammar + @symbols: Array[untyped] + @empty_symbol: nil + @terms: Array[Symbol]? + @nterms: Array[Symbol]? + @rules: Array[untyped] + + attr_reader eof_symbol: Symbol? + attr_reader error_symbol: Symbol? + attr_reader undef_symbol: Symbol? + attr_reader accept_symbol: Symbol? + attr_reader aux: Aux + attr_accessor union: Union + attr_accessor expect: untyped + attr_accessor printers: Array[Printer] + attr_accessor lex_param: untyped + attr_accessor parse_param: untyped + attr_accessor initial_action: Code + attr_accessor symbols: Array[Symbol] + attr_accessor types: Array[Type] + attr_accessor rules: Array[Rule] + attr_accessor _rules: Array[[untyped, Array[untyped], untyped]] + attr_accessor sym_to_rules: Hash[untyped, untyped] + def initialize: -> void + def add_printer: (ident_or_tags: Array[untyped], code: Code, lineno: untyped) -> Array[Printer] + def add_term: (id: Token, ?alias_name: String?, ?tag: Token?, ?token_id: Integer?, ?replace: bool) -> Symbol + def add_nterm: (id: untyped, ?alias_name: nil, ?tag: nil) -> Symbol? + def add_type: (id: untyped, tag: untyped) -> Array[Type] + def add_nonassoc: (Symbol sym, Integer precedence) -> Precedence + def add_left: (Symbol sym, Integer precedence) -> Precedence + def add_right: (Symbol sym, Integer precedence) -> Precedence + def set_precedence: (Symbol sym, Precedence precedence) -> Precedence + def set_union: (Code code, untyped lineno) -> Union + def add_rule: (lhs: untyped, rhs: Array[Symbol | Token], lineno: untyped) -> Array[[untyped, Array[untyped], untyped]] + def build_references: (untyped token_code) -> untyped + def build_code: (:initial_action | :lex_param | :parse_param | :printer | :union `type`, untyped token_code) -> Code + def prologue_first_lineno=: (untyped prologue_first_lineno) -> untyped + def prologue=: (String prologue) -> String + def epilogue_first_lineno=: (untyped epilogue_first_lineno) -> untyped + def epilogue=: (String epilogue) -> String + def prepare: -> Array[Symbol] + def validate!: -> nil + def compute_nullable: -> void + def find_symbol_by_s_value: (String s_value) -> Symbol? + def find_symbol_by_s_value!: (String s_value) -> Symbol + def find_symbol_by_id: (Token id) -> Symbol? + def find_symbol_by_id!: (Token id) -> Symbol + def find_symbol_by_number!: (Integer number) -> Symbol + def find_rules_by_symbol!: (Symbol sym) -> untyped + def find_rules_by_symbol: (Symbol sym) -> nil + def terms_count: -> Integer + def terms: -> Array[Symbol] + def nterms_count: -> Integer + def nterms: -> Array[Symbol] + + private + def find_nterm_by_id!: (untyped id) -> Symbol + def append_special_symbols: -> Symbol? + def normalize_rules: -> Array[[untyped, Array[untyped], untyped]] + def collect_symbols: -> (Array[Array[Symbol] | Symbol]) + def fill_symbol_number: -> void + def replace_token_with_symbol: -> Array[Rule] + def token_to_symbol: (Token | Symbol token) -> Symbol + def fill_default_precedence: -> Array[Rule] + def fill_sym_to_rules: -> Array[Rule] + def fill_nterm_type: -> Array[Type] + def fill_symbol_printer: -> Array[Symbol] + def validate_symbol_number_uniqueness!: -> nil + + class Aux + def initialize: (?prologue_first_lineno: untyped, ?prologue: untyped, ?epilogue_first_lineno: untyped, ?epilogue: untyped) -> void + attr_accessor prologue_first_lineno(): untyped + attr_accessor prologue(): String + attr_accessor epilogue_first_lineno(): untyped + attr_accessor epilogue(): String + end + end + + class Token = Lexer::Token + + class Lexer + include Report::Duration + + class Token + def initialize: (type: untyped, s_value: (::String | Integer)) -> void + + def type: -> untyped + def type=: (untyped) -> untyped + def s_value: -> (::String | Integer) + def s_value_int: -> Integer + def s_value_str: -> ::String + + self.@i: Integer + self.@types: Array[untyped] + def self.define_type: (::Symbol) -> void + + attr_accessor line: Integer + attr_accessor column: Integer + attr_accessor referred: untyped + attr_accessor references: untyped + + class Type + def initialize: (id: untyped, name: ::String) -> void + end + + class P_expect # %expect + end + class P_define # %define + end + class P_printer # %printer + end + class P_lex_param # %lex-param + end + class P_parse_param # %parse-param + end + class P_initial_action # %initial-action + end + class P_union # %union + end + class P_token # %token + end + class P_type # %type + end + class P_nonassoc # %nonassoc + end + class P_left # %left + end + class P_right # %right + end + class P_prec # %prec + end + class User_code # { ... } + end + class Tag # + end + class Number # 0 + end + class Ident_Colon # k_if:, k_if : (spaces can be there) + end + class Ident # api.pure, tNUMBER + end + class Semicolon # ; + end + class Bar # | + end + class String # "str" + end + class Char # '+' + end + end + + Initial: Integer + Prologue: Integer + BisonDeclarations: Integer + GrammarRules: Integer + Epilogue: Integer + self.@i: Integer + self.@types: Array[Type] + @text: untyped + @state: Integer + @debug: false + + attr_reader prologue: Array[untyped] + attr_reader bison_declarations: Array[untyped] + attr_reader grammar_rules: Array[untyped] + attr_reader epilogue: Array[untyped] + attr_reader bison_declarations_tokens: Array[untyped] + attr_reader grammar_rules_tokens: Array[untyped] + def initialize: (untyped text) -> void + + private + def create_token: (untyped `type`, (Integer | String) s_value, untyped line, Integer column) -> Token + def lex_text: -> untyped + def lex_common: (Array[untyped] lines, Array[untyped] tokens) -> nil + def lex_bison_declarations_tokens: -> nil + def lex_user_code: (StringScanner ss, untyped line, Integer column, Array[untyped] lines) -> [Token, untyped] + def lex_string: (StringScanner ss, String terminator, untyped line, Array[untyped] lines) -> [String, untyped] + def lex_comment: (StringScanner ss, untyped line, Array[untyped] lines, String str) -> untyped + def lex_line_comment: (StringScanner ss, untyped line, String str) -> untyped + def lex_grammar_rules_tokens: -> nil + def debug: (String msg) -> nil + + public + def to_s: -> String + def self.define_type: (:Bar | :Char | :Ident | :Ident_Colon | :Number | :P_define | :P_expect | :P_initial_action | :P_left | :P_lex_param | :P_nonassoc | :P_parse_param | :P_prec | :P_printer | :P_right | :P_token | :P_type | :P_union | :Semicolon | :String | :Tag | :User_code name) -> Integer + + class Type < Struct[untyped] + attr_accessor id(): Integer + attr_accessor name(): String + end + end + + class Parser + include Lrama::Report::Duration + + class T = Lexer::Token + + @text: untyped + + def initialize: (untyped text) -> void + def parse: -> untyped + + private + def process_prologue: (Grammar grammar, Lexer lexer) -> String + def process_epilogue: (Grammar grammar, Lexer lexer) -> String + def parse_bison_declarations: (TokenScanner ts, Grammar grammar) -> nil + def parse_grammar_rules: (TokenScanner ts, Grammar grammar) -> nil + def parse_grammar_rule: (TokenScanner ts, Grammar grammar) -> nil + def parse_grammar_rule_rhs: (TokenScanner ts, Grammar grammar) -> Array[Token] + + class TokenScanner + @tokens: Array[untyped] + @index: Integer + + def initialize: (Array[untyped] tokens) -> void + def current_token: -> untyped + def current_type: -> untyped + def next: -> untyped + def consume: (*untyped token_types) -> Token? + def consume!: (*untyped token_types) -> Token + def consume_multi: (*untyped token_types) -> Array[untyped] + def eots?: -> untyped + end + end + + class Output + extend Forwardable + include Report::Duration + + @out: untyped + @output_file_path: untyped + @template_name: untyped + @header_out: IO? + @header_file_path: String? + @context: Context + @grammar: Grammar + + # Forwardable methods for Context + def yyfinal: -> untyped + def yylast: -> Integer? + def yyntokens: -> untyped + def yynnts: -> untyped + def yynrules: -> untyped + def yynstates: -> untyped + def yymaxutok: -> untyped + def yypact_ninf: -> ((Float | Integer)?) + def yytable_ninf: -> Integer? + + # Forwardable methods for Grammer + def eof_symbol?: -> bool + def error_symbol?: -> bool + def undef_symbol?: -> bool + def accept_symbol?: -> bool + + attr_reader grammar_file_path: untyped + attr_reader context: untyped + attr_reader grammar: untyped + def initialize: (out: untyped, output_file_path: untyped, template_name: untyped, grammar_file_path: untyped, context: untyped, grammar: untyped, ?header_out: IO?, ?header_file_path: String?) -> void + def self.erb: (String input) -> ERB + | (String input) -> ERB + def eval_template: (String file, String path) -> untyped + def render: -> untyped + def token_enums: -> String + def symbol_enum: -> String + def yytranslate: -> untyped + def yyrline: -> untyped + def yytname: -> String + def int_type_for: (untyped ary) -> String + def symbol_actions_for_printer: -> String + def user_initial_action: (?String comment) -> String + def user_actions: -> String + def omit_braces_and_blanks: (untyped param) -> untyped + def parse_param: -> String + def lex_param: -> String + def user_formals: -> String + def user_args: -> String + def extract_param_name: (String param) -> String + def parse_param_name: -> String + def lex_param_name: -> String + def parse_param_use: (untyped val, untyped loc) -> String + def yylex_formals: -> String + def table_value_equals: (untyped table, untyped value, untyped literal, untyped symbol) -> String + def yyerror_args: -> String + def template_basename: -> String + def aux: -> untyped + def int_array_to_string: (untyped ary) -> untyped + def spec_mapped_header_file: -> String? + def b4_cpp_guard__b4_spec_mapped_header_file: -> String + + private + def template_file: -> String + def header_template_file: -> String + def template_dir: -> String + def string_array_to_string: (untyped ary) -> String + def replace_special_variables: (String str, String ofile) -> untyped + end + + class Report + module Profile + def self.report_profile: { -> untyped } -> untyped + end + + module Duration + self.@_report_duration_enabled: true + + def self.enable: -> true + def self.enabled?: -> true + def report_duration: [R] (::Symbol) { -> R } -> R + end + end + + class State + @items_to_state: Hash[untyped, untyped] + @nterm_transitions: Array[untyped] + @term_transitions: Array[untyped] + + attr_reader id: Integer + attr_reader accessing_symbol: untyped + attr_reader kernels: [States::Item] + attr_reader conflicts: Array[untyped] + attr_reader resolved_conflicts: Array[untyped] + attr_reader default_reduction_rule: nil + attr_reader closure: untyped + attr_reader items: Array[States::Item] + attr_accessor shifts: Array[Shift] + attr_accessor reduces: Array[Reduce] + def initialize: (Integer id, untyped accessing_symbol, [States::Item] kernels) -> void + def closure=: (untyped closure) -> Array[States::Item] + def non_default_reduces: -> Array[Reduce] + def compute_shifts_reduces: -> Array[Reduce] + def set_items_to_state: (untyped items, untyped next_state) -> untyped + def set_look_ahead: (untyped rule, untyped look_ahead) -> untyped + def nterm_transitions: -> Array[[untyped, untyped, untyped]] + def term_transitions: -> Array[[untyped, untyped]] + def selected_term_transitions: -> Array[untyped] + def transition: (untyped sym) -> untyped + def find_reduce_by_item!: (untyped item) -> Reduce + def default_reduction_rule=: (untyped default_reduction_rule) -> Array[Reduce] + def sr_conflicts: -> Array[untyped] + def rr_conflicts: -> Array[untyped] + def report_message: -> String + + class Reduce + attr_reader item: States::Item + attr_reader look_ahead: Array[::Symbol] | nil + attr_reader not_selected_symbols: Array[untyped] + attr_accessor default_reduction: true + def initialize: (States::Item item) -> void + def rule: -> untyped + def look_ahead=: (untyped look_ahead) -> untyped + def add_not_selected_symbol: (untyped sym) -> Array[untyped] + def selected_look_ahead: -> Array[untyped] + end + + class Shift + attr_reader next_sym: untyped + attr_reader next_items: Array[untyped] + attr_accessor not_selected: true + def initialize: (untyped next_sym, Array[untyped] next_items) -> void + end + + class ResolvedConflict < Struct[untyped] + def initialize: (symbol: ::Symbol, reduce: Reduce, which: (:error | :reduce | :shift), ?same_prec: bool) -> void + + attr_accessor symbol(): untyped + attr_accessor reduce(): Reduce + attr_accessor which(): :error | :reduce | :shift + attr_accessor same_prec(): bool + end + + class Conflict + def initialize: (symbols: Array[::Symbol], reduce: Reduce, type: (:reduce_reduce | :shift_reduce)) -> void + + attr_accessor symbols(): [untyped] | false + attr_accessor reduce(): Reduce + attr_accessor type(): :reduce_reduce | :shift_reduce + end + end + + class States + extend Forwardable + + # Forwardable methods for Grammer + def symbols: -> Array[Symbol] + def terms: -> Array[Symbol] + def nterms: -> Array[Symbol] + def rules: -> Array[Rule] + def accept_symbol: -> Symbol? + def find_symbol_by_s_value!: (String s_value) -> Symbol + + include Report::Duration + @grammar: Grammar + @warning: untyped + @trace_state: false + @direct_read_sets: Hash[untyped, untyped] + @read_sets: Hash[untyped, Integer] + @follow_sets: Hash[[Integer, Integer], Integer] + @la: Hash[untyped, untyped] + + attr_reader states: Array[State] + attr_reader reads_relation: Hash[untyped, untyped] + attr_reader includes_relation: Hash[untyped, untyped] + attr_reader lookback_relation: Hash[untyped, untyped] + def initialize: (untyped grammar, untyped warning, ?trace_state: false) -> void + def compute: -> nil + def reporter: -> untyped + def states_count: -> Integer + def direct_read_sets: -> Hash[untyped, untyped] + def read_sets: -> Hash[untyped, Array[untyped]] + def follow_sets: -> Hash[untyped, Array[untyped]] + def la: -> Hash[untyped, untyped] + + private + def sr_conflicts: -> Array[Array[untyped]] + def rr_conflicts: -> Array[Array[untyped]] + def initial_attrs: -> Hash[untyped, untyped] + def trace_state: { (IO) -> IO } -> IO? + def create_state: (untyped accessing_symbol, [Item] kernels, Hash[untyped, untyped] states_creted) -> [State, bool] + def setup_state: (untyped state) -> untyped + def enqueue_state: (Array[untyped] states, State state) -> Array[untyped] + def compute_lr0_states: -> nil + def nterm_transitions: -> Array[[State, untyped, untyped]] + def compute_direct_read_sets: -> Array[State] + def compute_reads_relation: -> Array[State] + def compute_read_sets: -> Hash[untyped, Integer] + def transition: (State state, untyped symbols) -> State + def compute_includes_relation: -> Array[State] + def compute_lookback_relation: -> Array[State] + def compute_follow_sets: -> Hash[untyped, Integer] + def compute_look_ahead_sets: -> Array[State] + def bitmap_to_terms: (Integer bit) -> Array[untyped] + def compute_conflicts: -> Array[State] + def compute_shift_reduce_conflicts: -> Array[State] + def compute_reduce_reduce_conflicts: -> Array[State] + def compute_default_reduction: -> Array[State] + def check_conflicts: -> nil + + public + + class Item < Struct[untyped] + def initialize: (rule: untyped, position: Integer) -> void + attr_accessor rule(): untyped + attr_accessor position(): Integer + def hash: -> Integer + def rule_id: -> untyped + def next_sym: -> untyped + def end_of_rule?: -> untyped + def new_by_next_position: -> Item + def previous_sym: -> untyped + def display_name: -> String + def display_rest: -> String + end + end + + class StatesReporter + include Report::Duration + @states: untyped + + def initialize: (untyped states) -> void + def report: (untyped io, **untyped) -> ((Array[State] | Hash[untyped, nil])?) + + private + def _report: (untyped io, ?grammar: false, ?states: false, ?itemsets: false, ?lookaheads: false, ?solved: false, ?verbose: false) -> untyped + def report_conflicts: (untyped io) -> nil + def report_grammar: (untyped io) -> untyped + def report_states: (untyped io, false itemsets, false lookaheads, false solved, false verbose) -> untyped + end + + class Warning + @out: IO + + attr_reader errors: Array[untyped] + attr_reader warns: Array[untyped] + def initialize: (?IO `out`) -> void + def error: (untyped message) -> Array[untyped] + def warn: (untyped message) -> Array[untyped] + def has_error?: -> bool + end +end