From 73a256af9828b31c4f50e532f76056bec638438c Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 17 May 2023 14:56:45 +0900 Subject: [PATCH 01/13] Set up rbs_collection.yaml and add a TypeProf-generated prototype rbs --- rbs_collection.lock.yaml | 26 ++ rbs_collection.yaml | 22 ++ sig/lrama/typeprof-generated.rbs | 542 +++++++++++++++++++++++++++++++ 3 files changed, 590 insertions(+) create mode 100644 rbs_collection.lock.yaml create mode 100644 rbs_collection.yaml create mode 100644 sig/lrama/typeprof-generated.rbs diff --git a/rbs_collection.lock.yaml b/rbs_collection.lock.yaml new file mode 100644 index 00000000..0e8ac60d --- /dev/null +++ b/rbs_collection.lock.yaml @@ -0,0 +1,26 @@ +--- +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: 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..dc54aa83 --- /dev/null +++ b/rbs_collection.yaml @@ -0,0 +1,22 @@ +# 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 diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs new file mode 100644 index 00000000..7314ffa3 --- /dev/null +++ b/sig/lrama/typeprof-generated.rbs @@ -0,0 +1,542 @@ +module Lrama + Token: untyped + VERSION: String + include Comparable + + def to_s: -> String + def as_comment: -> String + def precedence: -> untyped + def initial_rule?: -> untyped + def translated_code: (untyped member) -> untyped + | -> nil + | -> nil + attr_writer eof_symbol: bot + attr_writer error_symbol: bot + attr_writer undef_symbol: bot + attr_writer accept_symbol: bot + def term?: -> untyped + def nterm?: -> untyped + def eof_symbol?: -> false + def error_symbol?: -> false + def undef_symbol?: -> false + def accept_symbol?: -> false + def display_name: -> untyped + def enum_name: -> String + def comment: -> untyped + def translated_printer_code: (untyped tag) -> untyped + + private + def translated_user_code: -> untyped + def translated_initial_action_code: -> untyped + + public + def tag: -> untyped + def <=>: (untyped other) -> untyped + def braces_less_code: -> untyped + + class Command + def run: (untyped argv) -> bot + + private + def validate_report: (untyped report) -> {grammar: true} + def validate_trace: (untyped trace) -> Hash[untyped, untyped] + end + + class Context + ErrorActionNumber: Float + BaseMin: Float + @yydefact: Array[Integer]? + @yydefgoto: Array[Integer]? + @_actions: Array[untyped] + @yylast: Integer + @yypact_ninf: Float | Integer + @yytable_ninf: Integer + @base: Array[Float | Integer] + @table: Array[Integer] + @check: Array[untyped] + @sorted_actions: Array[untyped] + + 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: -> [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: -> [Integer] + def yyr2: -> [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: -> Array[untyped] + end + + class Digraph + @sets: Array[[Integer, untyped]] + @relation: Hash[untyped, untyped] + @base_function: Hash[untyped, nil] + @stack: Array[[Integer, untyped]] + @h: Hash[untyped, Float | Integer] + @result: Hash[untyped, nil] + + def initialize: (Array[[Integer, untyped]] sets, Hash[untyped, untyped] relation, Hash[untyped, nil] base_function) -> void + def compute: -> Hash[untyped, nil] + + private + def traverse: ([Integer, untyped] x) -> nil + end + + class Rule < Struct[untyped] + 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 + end + + class Symbol < Struct[untyped] + attr_accessor id(): Array[Symbol] | Symbol + attr_accessor alias_name(): String? + attr_accessor number(): Integer? + attr_accessor tag(): nil + attr_accessor term(): bool + attr_accessor token_id(): Integer? + attr_accessor nullable(): false? + attr_accessor precedence(): Precedence + attr_accessor printer(): Printer + end + + class Type < Struct[untyped] + attr_accessor id(): untyped + attr_accessor tag(): nil + end + + class Code < Struct[untyped] + attr_accessor type(): :initial_action | :lex_param | :parse_param | :printer | :union | :user_code + attr_accessor token_code(): untyped + end + + class Reference < Struct[untyped] + 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 < Struct[untyped] + attr_accessor type(): :left | :nonassoc | :right + attr_accessor precedence(): Integer + end + + class Printer < Struct[untyped] + attr_accessor ident_or_tags(): Array[untyped] + attr_accessor code(): Code + attr_accessor lineno(): untyped + end + + class Union < Struct[untyped] + attr_accessor code(): Code + attr_accessor lineno(): untyped + end + + class Grammar + @empty_symbol: nil + @terms: Array[Symbol]? + @nterms: Array[Symbol]? + + 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: Array[Symbol] | Symbol, ?alias_name: String?, ?tag: nil, ?token_id: Integer?, ?replace: bool) -> Symbol + def add_nterm: (id: untyped, ?alias_name: nil, ?tag: nil) -> Symbol? + def add_type: (id: untyped, tag: nil) -> 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], 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: -> bot + def validate!: -> nil + def compute_nullable: -> bot + 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: (Symbol id) -> Symbol? + def find_symbol_by_id!: (Symbol id) -> Symbol + def find_symbol_by_number!: (Integer number) -> Symbol + def find_rules_by_symbol!: (Symbol sym) -> bot + 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: -> bot + def replace_token_with_symbol: -> Array[Rule] + def token_to_symbol: (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 < Struct[untyped] + attr_accessor prologue_first_lineno(): untyped + attr_accessor prologue(): String + attr_accessor epilogue_first_lineno(): untyped + attr_accessor epilogue(): String + end + end + + class Lexer + 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, Complex | Float | Integer | Rational column) -> Parser::T + 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 | false ss, untyped line, Complex | Float | Integer | Rational column, Array[untyped] lines) -> [Parser::T, untyped] + def lex_string: (StringScanner | false ss, String terminator, untyped line, Array[untyped] lines) -> [String, untyped] + def lex_comment: (StringScanner | false ss, untyped line, Array[untyped] lines, String str) -> untyped + def lex_line_comment: (StringScanner | false ss, untyped line, String str) -> untyped + def lex_grammar_rules_tokens: -> nil + def debug: (String msg) -> nil + + public + attr_accessor line: bot + attr_accessor column: bot + attr_accessor referred: untyped + attr_accessor references: untyped + 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 + @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[Symbol] + + class T < Struct[untyped] + attr_accessor type(): untyped + attr_accessor s_value(): (Integer | String)? + end + + 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) -> nil + def consume!: (*untyped token_types) -> untyped + def consume_multi: (*untyped token_types) -> Array[untyped] + def eots?: -> untyped + end + end + + class Output + @out: untyped + @output_file_path: untyped + @template_name: untyped + @header_out: nil + @header_file_path: nil + + 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: nil, ?header_file_path: nil) -> void + def self.erb: (String input) -> ERB + | (String input) -> ERB + def eval_template: (String file, nil 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: -> nil + 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: (untyped str, nil ofile) -> untyped + end + + class Report + module Profile + def self.report_profile: -> untyped + end + + module Duration + self.@_report_duration_enabled: true + + def self.enable: -> true + def self.enabled?: -> true + def report_duration: (:compute_conflicts | :compute_default_reduction | :compute_direct_read_sets | :compute_follow_sets | :compute_includes_relation | :compute_look_ahead_sets | :compute_lookback_relation | :compute_lr0_states | :compute_read_sets | :compute_reads_relation | :report method_name) ?{ -> ((Array[State] | Hash[untyped, nil])?) } -> ((Array[State] | Hash[untyped, nil])?) + 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]? + def term_transitions: -> Array[untyped]? + def selected_term_transitions: -> Array[untyped] + def transition: (untyped sym) -> bot + 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: 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] + attr_accessor symbol(): untyped + attr_accessor reduce(): Reduce + attr_accessor which(): :error | :reduce | :shift + attr_accessor same_prec(): true + end + + class Conflict < Struct[untyped] + attr_accessor symbols(): [untyped] | false + attr_accessor reduce(): Reduce + attr_accessor type(): :reduce_reduce | :shift_reduce + end + end + + class States + include Report::Duration + @grammar: untyped + @warning: untyped + @trace_state: false + @direct_read_sets: Hash[untyped, untyped] + @read_sets: Hash[untyped, nil] + @follow_sets: Hash[untyped, nil] + @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[Array[State?]] + def compute_direct_read_sets: -> Array[State] + def compute_reads_relation: -> Array[State] + def compute_read_sets: -> Hash[untyped, nil] + 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, nil] + def compute_look_ahead_sets: -> Array[State] + def bitmap_to_terms: (nil 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 + 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 + + class Item < Struct[untyped] + attr_accessor rule(): untyped + attr_accessor position(): Integer + 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 From 718cbb35608e7f0d737c961ebba5fae2c7fd6ff8 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 17 May 2023 16:35:22 +0900 Subject: [PATCH 02/13] Invoke `rbs collection install` before `steep check` --- .github/workflows/test.yaml | 1 + .gitignore | 1 + 2 files changed, 2 insertions(+) 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/ From 1b5dadad518c63bdf9d615ed537e9b39af0829af Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Thu, 18 May 2023 23:56:57 +0900 Subject: [PATCH 03/13] Make `steep check` pass lib/lrama/lexer.rb --- Steepfile | 2 +- lib/lrama/lexer.rb | 81 ++++++++++++++++---------------- sig/lrama/typeprof-generated.rbs | 81 +++++++++++++++++++++++++++----- 3 files changed, 112 insertions(+), 52 deletions(-) diff --git a/Steepfile b/Steepfile index 12efa39a..6fb39f95 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb" end diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index 6c1139b4..ef8929c9 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -7,8 +7,9 @@ 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) + class Type < Struct.new(:id, :name, keyword_init: true) + end attr_accessor :line, :column, :referred # For User_code @@ -159,43 +160,43 @@ def lex_common(lines, tokens) when ss.scan(/\s+/) # skip when ss.scan(/;/) - tokens << create_token(Token::Semicolon, ss[0], line, ss.pos - column) + tokens << create_token(Token::Semicolon, ss[0] || raise, line, ss.pos - column) when ss.scan(/\|/) - tokens << create_token(Token::Bar, ss[0], line, ss.pos - column) + tokens << create_token(Token::Bar, ss[0] || raise, line, ss.pos - column) when ss.scan(/(\d+)/) - tokens << create_token(Token::Number, Integer(ss[0]), line, ss.pos - column) + tokens << create_token(Token::Number, Integer(ss[0] || raise), line, ss.pos - column) when ss.scan(/(<[a-zA-Z0-9_]+>)/) - tokens << create_token(Token::Tag, ss[0], line, ss.pos - column) + tokens << create_token(Token::Tag, ss[0] || raise, line, ss.pos - column) when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)\s*:/) - tokens << create_token(Token::Ident_Colon, ss[1], line, ss.pos - column) + tokens << create_token(Token::Ident_Colon, ss[1] || raise, line, ss.pos - column) when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)/) - tokens << create_token(Token::Ident, ss[0], line, ss.pos - column) + tokens << create_token(Token::Ident, ss[0] || raise, line, ss.pos - column) when ss.scan(/%expect/) - tokens << create_token(Token::P_expect, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_expect, ss[0] || raise, line, ss.pos - column) when ss.scan(/%define/) - tokens << create_token(Token::P_define, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_define, ss[0] || raise, line, ss.pos - column) when ss.scan(/%printer/) - tokens << create_token(Token::P_printer, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_printer, ss[0] || raise, line, ss.pos - column) when ss.scan(/%lex-param/) - tokens << create_token(Token::P_lex_param, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_lex_param, ss[0] || raise, line, ss.pos - column) when ss.scan(/%parse-param/) - tokens << create_token(Token::P_parse_param, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_parse_param, ss[0] || raise, line, ss.pos - column) when ss.scan(/%initial-action/) - tokens << create_token(Token::P_initial_action, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_initial_action, ss[0] || raise, line, ss.pos - column) when ss.scan(/%union/) - tokens << create_token(Token::P_union, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_union, ss[0] || raise, line, ss.pos - column) when ss.scan(/%token/) - tokens << create_token(Token::P_token, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_token, ss[0] || raise, line, ss.pos - column) when ss.scan(/%type/) - tokens << create_token(Token::P_type, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_type, ss[0] || raise, line, ss.pos - column) when ss.scan(/%nonassoc/) - tokens << create_token(Token::P_nonassoc, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_nonassoc, ss[0] || raise, line, ss.pos - column) when ss.scan(/%left/) - tokens << create_token(Token::P_left, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_left, ss[0] || raise, line, ss.pos - column) when ss.scan(/%right/) - tokens << create_token(Token::P_right, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_right, ss[0] || raise, line, ss.pos - column) when ss.scan(/%prec/) - tokens << create_token(Token::P_prec, ss[0], line, ss.pos - column) + tokens << create_token(Token::P_prec, ss[0] || raise, line, ss.pos - column) when ss.scan(/{/) token, line = lex_user_code(ss, line, ss.pos - column, lines) tokens << token @@ -209,17 +210,17 @@ def lex_common(lines, tokens) when ss.scan(/\/\//) line = lex_line_comment(ss, line, "") when ss.scan(/'(.)'/) - tokens << create_token(Token::Char, ss[0], line, ss.pos - column) + tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) when ss.scan(/'\\(.)'/) # '\\', '\t' - tokens << create_token(Token::Char, ss[0], line, ss.pos - column) + tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) when ss.scan(/'\\(\d+)'/) # '\13' - tokens << create_token(Token::Char, ss[0], line, ss.pos - column) + tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) when ss.scan(/%empty/) # skip 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 @@ -252,15 +253,15 @@ def lex_user_code(ss, line, column, lines) str << string next when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $$ - tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil - references << [:dollar, "$", tag, str.length, str.length + ss[0].length - 1] + tag = ss[1] ? create_token(Token::Tag, ss[1] || raise, line, str.length) : nil + references << [:dollar, "$", tag, str.length, str.length + (ss[0] || raise).length - 1] when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $1 - tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil - references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1] + tag = ss[1] ? create_token(Token::Tag, ss[1] || raise, line, str.length) : nil + references << [:dollar, Integer(ss[2] || raise), tag, str.length, str.length + (ss[0] || raise).length - 1] when ss.scan(/@\$/) # @$ - references << [:at, "$", nil, str.length, str.length + ss[0].length - 1] + references << [:at, "$", nil, str.length, str.length + (ss[0] || raise).length - 1] when ss.scan(/@(\d)+/) # @1 - references << [:at, Integer(ss[1]), nil, str.length, str.length + ss[0].length - 1] + references << [:at, Integer(ss[1] || raise), nil, str.length, str.length + (ss[0] || raise).length - 1] when ss.scan(/{/) brace_count += 1 when ss.scan(/}/) @@ -268,7 +269,7 @@ def lex_user_code(ss, line, column, lines) debug("Return lex_user_code: #{line}") if brace_count == 0 - str << ss[0] + str << (ss[0] || raise) user_code = Token.new(type: Token::User_code, s_value: str.freeze) user_code.line = first_line user_code.column = first_column @@ -276,18 +277,18 @@ def lex_user_code(ss, line, column, lines) return [user_code, line] end when ss.scan(/\/\*/) - str << ss[0] + str << (ss[0] || raise) line = lex_comment(ss, line, lines, str) when ss.scan(/\/\//) - str << ss[0] + str << (ss[0] || raise) line = lex_line_comment(ss, line, str) else # noop, just consume char - str << ss.getch + str << (ss.getch || raise) next end - str << ss[0] + str << (ss[0] || raise) end # Reach to end of input but brace does not match @@ -328,11 +329,11 @@ def lex_comment(ss, line, lines, str) when ss.scan(/\*\//) return line else - str << ss.getch + str << (ss.getch || raise) next end - str << ss[0] + str << (ss[0] || raise) end # Reach to end of input but quote does not match @@ -347,11 +348,11 @@ def lex_line_comment(ss, line, str) when ss.scan(/\n/) return line + 1 else - str << ss.getch + str << (ss.getch || raise) next end - str << ss[0] + str << (ss[0] || raise) end line # Reach to end of input diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 7314ffa3..45ccdd4e 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -1,5 +1,4 @@ module Lrama - Token: untyped VERSION: String include Comparable @@ -244,6 +243,70 @@ module Lrama end class Lexer + include Report::Duration + + class Token + def initialize: (type: untyped, s_value: ::String | Integer) -> void + + 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 @@ -264,22 +327,18 @@ module Lrama def initialize: (untyped text) -> void private - def create_token: (untyped `type`, (Integer | String)? s_value, untyped line, Complex | Float | Integer | Rational column) -> Parser::T + 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 | false ss, untyped line, Complex | Float | Integer | Rational column, Array[untyped] lines) -> [Parser::T, untyped] - def lex_string: (StringScanner | false ss, String terminator, untyped line, Array[untyped] lines) -> [String, untyped] - def lex_comment: (StringScanner | false ss, untyped line, Array[untyped] lines, String str) -> untyped - def lex_line_comment: (StringScanner | false ss, untyped line, String str) -> untyped + 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 - attr_accessor line: bot - attr_accessor column: bot - attr_accessor referred: untyped - attr_accessor references: untyped 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 @@ -383,7 +442,7 @@ module Lrama def self.enable: -> true def self.enabled?: -> true - def report_duration: (:compute_conflicts | :compute_default_reduction | :compute_direct_read_sets | :compute_follow_sets | :compute_includes_relation | :compute_look_ahead_sets | :compute_lookback_relation | :compute_lr0_states | :compute_read_sets | :compute_reads_relation | :report method_name) ?{ -> ((Array[State] | Hash[untyped, nil])?) } -> ((Array[State] | Hash[untyped, nil])?) + def report_duration: (::Symbol) ?{ -> ((Array[State] | Hash[untyped, nil])?) } -> ((Array[State] | Hash[untyped, nil])?) end end From beaf74f605cf28589571789a547f4786dd775db7 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 00:42:18 +0900 Subject: [PATCH 04/13] Make `steep check` pass lib/lrama/states.rb --- Steepfile | 2 +- lib/lrama/states.rb | 31 +++++--------- rbs_collection.lock.yaml | 4 ++ rbs_collection.yaml | 1 + sig/lrama/typeprof-generated.rbs | 71 +++++++++++++++++++------------- 5 files changed, 60 insertions(+), 49 deletions(-) diff --git a/Steepfile b/Steepfile index 6fb39f95..05e5ad7d 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb" end 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/rbs_collection.lock.yaml b/rbs_collection.lock.yaml index 0e8ac60d..fbd15b25 100644 --- a/rbs_collection.lock.yaml +++ b/rbs_collection.lock.yaml @@ -11,6 +11,10 @@ gems: version: '0' source: type: stdlib +- name: forwardable + version: '0' + source: + type: stdlib - name: stackprof version: '0.2' source: diff --git a/rbs_collection.yaml b/rbs_collection.yaml index dc54aa83..fcf237f9 100644 --- a/rbs_collection.yaml +++ b/rbs_collection.yaml @@ -20,3 +20,4 @@ gems: ignore: true - name: strscan - name: erb + - name: forwardable diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 45ccdd4e..7ec4d0f6 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -100,10 +100,10 @@ module Lrama @base_function: Hash[untyped, nil] @stack: Array[[Integer, untyped]] @h: Hash[untyped, Float | Integer] - @result: Hash[untyped, nil] + @result: Hash[untyped, Integer] - def initialize: (Array[[Integer, untyped]] sets, Hash[untyped, untyped] relation, Hash[untyped, nil] base_function) -> void - def compute: -> Hash[untyped, nil] + 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 @@ -213,7 +213,7 @@ module Lrama def find_symbol_by_id: (Symbol id) -> Symbol? def find_symbol_by_id!: (Symbol id) -> Symbol def find_symbol_by_number!: (Integer number) -> Symbol - def find_rules_by_symbol!: (Symbol sym) -> bot + def find_rules_by_symbol!: (Symbol sym) -> untyped def find_rules_by_symbol: (Symbol sym) -> nil def terms_count: -> Integer def terms: -> Array[Symbol] @@ -442,7 +442,7 @@ module Lrama def self.enable: -> true def self.enabled?: -> true - def report_duration: (::Symbol) ?{ -> ((Array[State] | Hash[untyped, nil])?) } -> ((Array[State] | Hash[untyped, nil])?) + def report_duration: [R] (::Symbol) { -> R } -> R end end @@ -467,10 +467,10 @@ module Lrama 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]? - def term_transitions: -> Array[untyped]? + def nterm_transitions: -> Array[[untyped, untyped, untyped]] + def term_transitions: -> Array[[untyped, untyped]] def selected_term_transitions: -> Array[untyped] - def transition: (untyped sym) -> bot + 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] @@ -479,7 +479,7 @@ module Lrama class Reduce attr_reader item: States::Item - attr_reader look_ahead: nil + 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 @@ -497,13 +497,17 @@ module Lrama 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(): true + attr_accessor same_prec(): bool end - class Conflict < Struct[untyped] + 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 @@ -511,13 +515,23 @@ module Lrama 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: untyped + @grammar: Grammar @warning: untyped @trace_state: false @direct_read_sets: Hash[untyped, untyped] - @read_sets: Hash[untyped, nil] - @follow_sets: Hash[untyped, nil] + @read_sets: Hash[untyped, Integer] + @follow_sets: Hash[[Integer, Integer], Integer] @la: Hash[untyped, untyped] attr_reader states: Array[State] @@ -538,20 +552,20 @@ module Lrama 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 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 enqueue_state: (Array[untyped] states, State state) -> Array[untyped] def compute_lr0_states: -> nil - def nterm_transitions: -> Array[Array[State?]] + 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, nil] + 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, nil] + def compute_follow_sets: -> Hash[untyped, Integer] def compute_look_ahead_sets: -> Array[State] - def bitmap_to_terms: (nil bit) -> Array[untyped] + 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] @@ -559,18 +573,19 @@ module Lrama def check_conflicts: -> nil public - 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 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 From c2c42a7ce94d421553517b2ae5654c8f8431d3db Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 02:03:52 +0900 Subject: [PATCH 05/13] Make `steep check` pass lib/lrama/grammar.rb --- Steepfile | 2 +- lib/lrama/grammar.rb | 58 +++++++++-------- lib/lrama/lexer.rb | 6 ++ sig/lrama/typeprof-generated.rbs | 104 ++++++++++++++++++++----------- 4 files changed, 109 insertions(+), 61 deletions(-) diff --git a/Steepfile b/Steepfile index 05e5ad7d..7af4e452 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb" 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 ef8929c9..6e0dfff1 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -8,6 +8,12 @@ class Lexer # s_value is semantic value class Token < Struct.new(:type, :s_value, keyword_init: true) + def s_value_str + s = s_value + raise if s.is_a?(Integer) + s + end + class Type < Struct.new(:id, :name, keyword_init: true) end diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 7ec4d0f6..a29537ea 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -6,27 +6,12 @@ module Lrama def as_comment: -> String def precedence: -> untyped def initial_rule?: -> untyped - def translated_code: (untyped member) -> untyped - | -> nil - | -> nil - attr_writer eof_symbol: bot - attr_writer error_symbol: bot - attr_writer undef_symbol: bot - attr_writer accept_symbol: bot def term?: -> untyped def nterm?: -> untyped def eof_symbol?: -> false def error_symbol?: -> false def undef_symbol?: -> false def accept_symbol?: -> false - def display_name: -> untyped - def enum_name: -> String - def comment: -> untyped - def translated_printer_code: (untyped tag) -> untyped - - private - def translated_user_code: -> untyped - def translated_initial_action_code: -> untyped public def tag: -> untyped @@ -109,7 +94,9 @@ module Lrama def traverse: ([Integer, untyped] x) -> nil end - class Rule < Struct[untyped] + 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] @@ -117,31 +104,65 @@ module Lrama attr_accessor nullable(): bool attr_accessor precedence_sym(): Symbol? attr_accessor lineno(): Integer + def translated_code: -> untyped end - class Symbol < Struct[untyped] - attr_accessor id(): Array[Symbol] | Symbol + 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(): nil attr_accessor term(): bool attr_accessor token_id(): Integer? - attr_accessor nullable(): false? + 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 < Struct[untyped] + class Type + def initialize: (id: untyped, tag: untyped) -> void attr_accessor id(): untyped attr_accessor tag(): nil end - class Code < Struct[untyped] + 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 < Struct[untyped] + 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 @@ -151,26 +172,32 @@ module Lrama attr_accessor position_in_rhs(): untyped end - class Precedence < Struct[untyped] + class Precedence + def initialize: (type: :left | :nonassoc | :right, precedence: Integer) -> void attr_accessor type(): :left | :nonassoc | :right attr_accessor precedence(): Integer end - class Printer < Struct[untyped] + 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(): untyped + attr_accessor lineno(): Integer + def translated_code: (untyped member) -> untyped end - class Union < Struct[untyped] + 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? @@ -190,7 +217,7 @@ module Lrama 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: Array[Symbol] | Symbol, ?alias_name: String?, ?tag: nil, ?token_id: Integer?, ?replace: bool) -> Symbol + def add_term: (id: Token, ?alias_name: String?, ?tag: nil, ?token_id: Integer?, ?replace: bool) -> Symbol def add_nterm: (id: untyped, ?alias_name: nil, ?tag: nil) -> Symbol? def add_type: (id: untyped, tag: nil) -> Array[Type] def add_nonassoc: (Symbol sym, Integer precedence) -> Precedence @@ -205,13 +232,13 @@ module Lrama def prologue=: (String prologue) -> String def epilogue_first_lineno=: (untyped epilogue_first_lineno) -> untyped def epilogue=: (String epilogue) -> String - def prepare: -> bot + def prepare: -> Array[Symbol] def validate!: -> nil - def compute_nullable: -> bot + 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: (Symbol id) -> Symbol? - def find_symbol_by_id!: (Symbol id) -> 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 @@ -225,16 +252,17 @@ module Lrama def append_special_symbols: -> Symbol? def normalize_rules: -> Array[[untyped, Array[untyped], untyped]] def collect_symbols: -> (Array[Array[Symbol] | Symbol]) - def fill_symbol_number: -> bot + def fill_symbol_number: -> void def replace_token_with_symbol: -> Array[Rule] - def token_to_symbol: (Symbol token) -> Symbol + 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 < Struct[untyped] + 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 @@ -242,11 +270,17 @@ module Lrama end end + class Token = Lexer::Token + class Lexer include Report::Duration class Token - def initialize: (type: untyped, s_value: ::String | Integer) -> void + def initialize: (type: untyped, s_value: (::String | Integer)) -> void + + def type: -> untyped + def s_value: -> (::String | Integer) + def s_value_str: -> ::String self.@i: Integer self.@types: Array[untyped] From c8d6930d4dd64e52a655160a336a70c9d2950ead Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 02:08:28 +0900 Subject: [PATCH 06/13] Make `steep check` pass lib/lrama/digraph.rb --- Steepfile | 2 +- lib/lrama/digraph.rb | 2 +- sig/lrama/typeprof-generated.rbs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Steepfile b/Steepfile index 7af4e452..eea6e062 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb" end 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/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index a29537ea..f6885948 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -82,7 +82,7 @@ module Lrama class Digraph @sets: Array[[Integer, untyped]] @relation: Hash[untyped, untyped] - @base_function: Hash[untyped, nil] + @base_function: Hash[untyped, Integer] @stack: Array[[Integer, untyped]] @h: Hash[untyped, Float | Integer] @result: Hash[untyped, Integer] From 48bbc15a156559e795bffaa6c8cd9a5ea38d27fc Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 02:33:18 +0900 Subject: [PATCH 07/13] Make `steep check` pass lib/lrama/output.rb --- Steepfile | 2 +- lib/lrama/output.rb | 37 +++++++++++++++------------ sig/lrama/typeprof-generated.rbs | 44 ++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/Steepfile b/Steepfile index eea6e062..1753344f 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb" end diff --git a/lib/lrama/output.rb b/lib/lrama/output.rb index 696aa79f..9708eca9 100644 --- a/lib/lrama/output.rb +++ b/lib/lrama/output.rb @@ -25,15 +25,17 @@ 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, '-') + eval <<-END # to make Steep skip type-checking + 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 + END def eval_template(file, path) erb = self.class.erb(File.read(file)) @@ -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/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index f6885948..55a38f23 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -8,10 +8,6 @@ module Lrama def initial_rule?: -> untyped def term?: -> untyped def nterm?: -> untyped - def eof_symbol?: -> false - def error_symbol?: -> false - def undef_symbol?: -> false - def accept_symbol?: -> false public def tag: -> untyped @@ -417,19 +413,41 @@ module Lrama end class Output + extend Forwardable + include Report::Duration + @out: untyped @output_file_path: untyped @template_name: untyped - @header_out: nil - @header_file_path: nil + @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: nil, ?header_file_path: nil) -> void + 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, nil path) -> untyped + def eval_template: (String file, String path) -> untyped def render: -> untyped def token_enums: -> String def symbol_enum: -> String @@ -445,9 +463,9 @@ module Lrama 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 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 @@ -455,7 +473,7 @@ module Lrama def template_basename: -> String def aux: -> untyped def int_array_to_string: (untyped ary) -> untyped - def spec_mapped_header_file: -> nil + def spec_mapped_header_file: -> String? def b4_cpp_guard__b4_spec_mapped_header_file: -> String private @@ -463,7 +481,7 @@ module Lrama def header_template_file: -> String def template_dir: -> String def string_array_to_string: (untyped ary) -> String - def replace_special_variables: (untyped str, nil ofile) -> untyped + def replace_special_variables: (String str, String ofile) -> untyped end class Report From 77980c43badfd8b12ee6cb9d31f677dc99086288 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 02:50:44 +0900 Subject: [PATCH 08/13] Make `steep check` pass lib/lrama/context.rb --- Steepfile | 2 +- lib/lrama/context.rb | 23 +++++++++++++---------- sig/lrama/typeprof-generated.rbs | 14 ++++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Steepfile b/Steepfile index 1753344f..ff20ef6a 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb" 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/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 55a38f23..d50bc558 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -23,18 +23,20 @@ module Lrama end class Context + include Report::Duration + ErrorActionNumber: Float BaseMin: Float @yydefact: Array[Integer]? @yydefgoto: Array[Integer]? - @_actions: Array[untyped] + @_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[untyped] + @sorted_actions: Array[[Integer, Array[[Integer, Integer]], Integer, Integer]] attr_reader states: untyped def initialize: (untyped states) -> void @@ -48,7 +50,7 @@ module Lrama def yynstates: -> untyped def yymaxutok: -> untyped def yytranslate: -> Array[Integer] - def yyrline: -> [Integer] + def yyrline: -> Array[Integer] def yytname: -> untyped def yypact_ninf: -> ((Float | Integer)?) def yytable_ninf: -> Integer? @@ -59,8 +61,8 @@ module Lrama def yytable: -> Array[Integer]? def yycheck: -> Array[untyped]? def yystos: -> untyped - def yyr1: -> [Integer] - def yyr2: -> [Integer] + def yyr1: -> Array[Integer] + def yyr2: -> Array[Integer] private def compute_tables: -> untyped @@ -72,7 +74,7 @@ module Lrama def compute_yydefgoto: -> untyped def sort_actions: -> Array[untyped] def debug_sorted_actions: -> untyped - def compute_packed_table: -> Array[untyped] + def compute_packed_table: -> void end class Digraph From e2bbdb7072a0acbaee1decd6373bf96bee597357 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 02:56:58 +0900 Subject: [PATCH 09/13] Make `steep check` pass lib/lrama/report.rb --- Steepfile | 2 +- sig/lrama/typeprof-generated.rbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Steepfile b/Steepfile index ff20ef6a..6d128e68 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb" end diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index d50bc558..dbe6464c 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -488,7 +488,7 @@ module Lrama class Report module Profile - def self.report_profile: -> untyped + def self.report_profile: { -> untyped } -> untyped end module Duration From f96415568d08e98fd0260fb23e659e1cf7fc87a8 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 03:01:38 +0900 Subject: [PATCH 10/13] Make `steep check` pass lib/lrama/command.rb --- Steepfile | 2 +- rbs_collection.lock.yaml | 4 ++++ rbs_collection.yaml | 1 + sig/lrama/typeprof-generated.rbs | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Steepfile b/Steepfile index 6d128e68..84707c4f 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb", "lib/lrama/command.rb" end diff --git a/rbs_collection.lock.yaml b/rbs_collection.lock.yaml index fbd15b25..205e6778 100644 --- a/rbs_collection.lock.yaml +++ b/rbs_collection.lock.yaml @@ -15,6 +15,10 @@ gems: version: '0' source: type: stdlib +- name: optparse + version: '0' + source: + type: stdlib - name: stackprof version: '0.2' source: diff --git a/rbs_collection.yaml b/rbs_collection.yaml index fcf237f9..ef9c283f 100644 --- a/rbs_collection.yaml +++ b/rbs_collection.yaml @@ -21,3 +21,4 @@ gems: - name: strscan - name: erb - name: forwardable + - name: optparse diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index dbe6464c..6c995f28 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -15,10 +15,10 @@ module Lrama def braces_less_code: -> untyped class Command - def run: (untyped argv) -> bot + def run: (untyped argv) -> void private - def validate_report: (untyped report) -> {grammar: true} + def validate_report: (untyped report) -> Hash[::Symbol, bool] def validate_trace: (untyped trace) -> Hash[untyped, untyped] end From 199933bfe1c2df1a5aa4a3752127f4268bec1358 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 03:05:15 +0900 Subject: [PATCH 11/13] Make `steep check` pass lib/lrama/states_reporter.rb --- Steepfile | 2 +- lib/lrama/states_reporter.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Steepfile b/Steepfile index 84707c4f..1e1fa155 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb", "lib/lrama/command.rb" + check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb", "lib/lrama/command.rb", "lib/lrama/states_reporter.rb" 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? From eda0fd5641107bdc43fc5b273ff8b03912353d73 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 03:20:04 +0900 Subject: [PATCH 12/13] Make `steep check` pass lib/lrama/parser.rb --- Steepfile | 2 +- lib/lrama/lexer.rb | 7 ++++++- lib/lrama/parser.rb | 8 ++++---- sig/lrama/typeprof-generated.rbs | 25 +++++++++++++------------ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Steepfile b/Steepfile index 1e1fa155..0fc867c0 100644 --- a/Steepfile +++ b/Steepfile @@ -3,5 +3,5 @@ target :lib do signature "sig" - check "lib/lrama/bitmap.rb", "lib/lrama/lexer.rb", "lib/lrama/states.rb", "lib/lrama/grammar.rb", "lib/lrama/digraph.rb", "lib/lrama/output.rb", "lib/lrama/context.rb", "lib/lrama/report.rb", "lib/lrama/command.rb", "lib/lrama/states_reporter.rb" + check "lib/lrama/" end diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index 6e0dfff1..2f9ca5e8 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -8,9 +8,14 @@ class Lexer # s_value is semantic value 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 if s.is_a?(Integer) + raise unless s.is_a?(String) s 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/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 6c995f28..9d14b248 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -110,7 +110,7 @@ module Lrama attr_accessor id(): Token attr_accessor alias_name(): String? attr_accessor number(): Integer? - attr_accessor tag(): nil + attr_accessor tag(): Token? attr_accessor term(): bool attr_accessor token_id(): Integer? attr_accessor nullable(): bool @@ -215,15 +215,15 @@ module Lrama 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: nil, ?token_id: Integer?, ?replace: bool) -> Symbol + 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: nil) -> Array[Type] + 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], lineno: untyped) -> Array[[untyped, Array[untyped], untyped]] + 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 @@ -277,7 +277,9 @@ module Lrama 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 @@ -381,6 +383,10 @@ module Lrama end class Parser + include Lrama::Report::Duration + + class T = Lexer::Token + @text: untyped def initialize: (untyped text) -> void @@ -392,12 +398,7 @@ module Lrama 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[Symbol] - - class T < Struct[untyped] - attr_accessor type(): untyped - attr_accessor s_value(): (Integer | String)? - end + def parse_grammar_rule_rhs: (TokenScanner ts, Grammar grammar) -> Array[Token] class TokenScanner @tokens: Array[untyped] @@ -407,8 +408,8 @@ module Lrama def current_token: -> untyped def current_type: -> untyped def next: -> untyped - def consume: (*untyped token_types) -> nil - def consume!: (*untyped token_types) -> 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 From ac3a073061302185503455796518a3ac8d16f550 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 May 2023 11:04:21 +0900 Subject: [PATCH 13/13] Follow advice from @soutaro --- Steepfile | 9 ++++- lib/lrama/lexer.rb | 68 ++++++++++++++++---------------- lib/lrama/output.rb | 4 +- sig/lrama/typeprof-generated.rbs | 5 +++ 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/Steepfile b/Steepfile index 0fc867c0..1d9f6c45 100644 --- a/Steepfile +++ b/Steepfile @@ -1,7 +1,12 @@ -# D = Steep::Diagnostic -# +D = Steep::Diagnostic + target :lib do signature "sig" + 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/lexer.rb b/lib/lrama/lexer.rb index 2f9ca5e8..33fb5d49 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -171,43 +171,43 @@ def lex_common(lines, tokens) when ss.scan(/\s+/) # skip when ss.scan(/;/) - tokens << create_token(Token::Semicolon, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Semicolon, ss[0], line, ss.pos - column) when ss.scan(/\|/) - tokens << create_token(Token::Bar, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Bar, ss[0], line, ss.pos - column) when ss.scan(/(\d+)/) - tokens << create_token(Token::Number, Integer(ss[0] || raise), line, ss.pos - column) + tokens << create_token(Token::Number, Integer(ss[0]), line, ss.pos - column) when ss.scan(/(<[a-zA-Z0-9_]+>)/) - tokens << create_token(Token::Tag, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Tag, ss[0], line, ss.pos - column) when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)\s*:/) - tokens << create_token(Token::Ident_Colon, ss[1] || raise, line, ss.pos - column) + tokens << create_token(Token::Ident_Colon, ss[1], line, ss.pos - column) when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)/) - tokens << create_token(Token::Ident, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Ident, ss[0], line, ss.pos - column) when ss.scan(/%expect/) - tokens << create_token(Token::P_expect, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_expect, ss[0], line, ss.pos - column) when ss.scan(/%define/) - tokens << create_token(Token::P_define, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_define, ss[0], line, ss.pos - column) when ss.scan(/%printer/) - tokens << create_token(Token::P_printer, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_printer, ss[0], line, ss.pos - column) when ss.scan(/%lex-param/) - tokens << create_token(Token::P_lex_param, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_lex_param, ss[0], line, ss.pos - column) when ss.scan(/%parse-param/) - tokens << create_token(Token::P_parse_param, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_parse_param, ss[0], line, ss.pos - column) when ss.scan(/%initial-action/) - tokens << create_token(Token::P_initial_action, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_initial_action, ss[0], line, ss.pos - column) when ss.scan(/%union/) - tokens << create_token(Token::P_union, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_union, ss[0], line, ss.pos - column) when ss.scan(/%token/) - tokens << create_token(Token::P_token, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_token, ss[0], line, ss.pos - column) when ss.scan(/%type/) - tokens << create_token(Token::P_type, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_type, ss[0], line, ss.pos - column) when ss.scan(/%nonassoc/) - tokens << create_token(Token::P_nonassoc, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_nonassoc, ss[0], line, ss.pos - column) when ss.scan(/%left/) - tokens << create_token(Token::P_left, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_left, ss[0], line, ss.pos - column) when ss.scan(/%right/) - tokens << create_token(Token::P_right, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_right, ss[0], line, ss.pos - column) when ss.scan(/%prec/) - tokens << create_token(Token::P_prec, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::P_prec, ss[0], line, ss.pos - column) when ss.scan(/{/) token, line = lex_user_code(ss, line, ss.pos - column, lines) tokens << token @@ -221,11 +221,11 @@ def lex_common(lines, tokens) when ss.scan(/\/\//) line = lex_line_comment(ss, line, "") when ss.scan(/'(.)'/) - tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Char, ss[0], line, ss.pos - column) when ss.scan(/'\\(.)'/) # '\\', '\t' - tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Char, ss[0], line, ss.pos - column) when ss.scan(/'\\(\d+)'/) # '\13' - tokens << create_token(Token::Char, ss[0] || raise, line, ss.pos - column) + tokens << create_token(Token::Char, ss[0], line, ss.pos - column) when ss.scan(/%empty/) # skip else @@ -264,15 +264,15 @@ def lex_user_code(ss, line, column, lines) str << string next when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $$ - tag = ss[1] ? create_token(Token::Tag, ss[1] || raise, line, str.length) : nil - references << [:dollar, "$", tag, str.length, str.length + (ss[0] || raise).length - 1] + tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil + references << [:dollar, "$", tag, str.length, str.length + ss[0].length - 1] when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $1 - tag = ss[1] ? create_token(Token::Tag, ss[1] || raise, line, str.length) : nil - references << [:dollar, Integer(ss[2] || raise), tag, str.length, str.length + (ss[0] || raise).length - 1] + tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil + references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1] when ss.scan(/@\$/) # @$ - references << [:at, "$", nil, str.length, str.length + (ss[0] || raise).length - 1] + references << [:at, "$", nil, str.length, str.length + ss[0].length - 1] when ss.scan(/@(\d)+/) # @1 - references << [:at, Integer(ss[1] || raise), nil, str.length, str.length + (ss[0] || raise).length - 1] + references << [:at, Integer(ss[1]), nil, str.length, str.length + ss[0].length - 1] when ss.scan(/{/) brace_count += 1 when ss.scan(/}/) @@ -280,7 +280,7 @@ def lex_user_code(ss, line, column, lines) debug("Return lex_user_code: #{line}") if brace_count == 0 - str << (ss[0] || raise) + str << ss[0] user_code = Token.new(type: Token::User_code, s_value: str.freeze) user_code.line = first_line user_code.column = first_column @@ -288,10 +288,10 @@ def lex_user_code(ss, line, column, lines) return [user_code, line] end when ss.scan(/\/\*/) - str << (ss[0] || raise) + str << ss[0] line = lex_comment(ss, line, lines, str) when ss.scan(/\/\//) - str << (ss[0] || raise) + str << ss[0] line = lex_line_comment(ss, line, str) else # noop, just consume char @@ -299,7 +299,7 @@ def lex_user_code(ss, line, column, lines) next end - str << (ss[0] || raise) + str << ss[0] end # Reach to end of input but brace does not match @@ -344,7 +344,7 @@ def lex_comment(ss, line, lines, str) next end - str << (ss[0] || raise) + str << ss[0] end # Reach to end of input but quote does not match @@ -363,7 +363,7 @@ def lex_line_comment(ss, line, str) next end - str << (ss[0] || raise) + str << ss[0] end line # Reach to end of input diff --git a/lib/lrama/output.rb b/lib/lrama/output.rb index 9708eca9..eb0c140f 100644 --- a/lib/lrama/output.rb +++ b/lib/lrama/output.rb @@ -25,7 +25,7 @@ def initialize(out:, output_file_path:, template_name:, grammar_file_path:, head @grammar = grammar end - eval <<-END # to make Steep skip type-checking + __skip__ = begin if ERB.instance_method(:initialize).parameters.last.first == :key def self.erb(input) ERB.new(input, trim_mode: '-') @@ -35,7 +35,7 @@ def self.erb(input) ERB.new(input, nil, '-') end end - END + end def eval_template(file, path) erb = self.class.erb(File.read(file)) diff --git a/sig/lrama/typeprof-generated.rbs b/sig/lrama/typeprof-generated.rbs index 9d14b248..bd9e1fb2 100644 --- a/sig/lrama/typeprof-generated.rbs +++ b/sig/lrama/typeprof-generated.rbs @@ -1,3 +1,8 @@ +# Prevent so many false positives in lib/lrama/lexer.rb +class StringScanner + def []: (Integer) -> String | ... +end + module Lrama VERSION: String include Comparable