Module: Ibex::CLIErrorMessages
- Defined in:
- lib/ibex/cli/error_messages.rb,
sig/ibex/cli/error_messages.rbs
Overview
CLI subcommand and generation-file handling for example-keyed errors.
Instance Method Summary collapse
- #automaton_for_error_messages(input_path) ⇒ IR::Automaton
- #automaton_from_ir_for_messages(input_path) ⇒ IR::Automaton
- #error_message_search_limits ⇒ { max_tokens: Integer, max_configurations: Integer }
- #error_messages_option_parser ⇒ OptionParser
- #messages_file_mode(path) ⇒ Integer
- #positive_messages_limit(value, option) ⇒ Integer
- #run_error_messages_command(arguments) ⇒ Integer
- #write_error_message_update_report(update) ⇒ void
- #write_error_messages(automaton, input_path) ⇒ void
Instance Method Details
#automaton_for_error_messages(input_path) ⇒ IR::Automaton
78 79 80 81 82 83 84 85 |
# File 'lib/ibex/cli/error_messages.rb', line 78 def (input_path) return (input_path) if @options[:from] report_status("reading #{input_path}") grammar = normalize_grammar_path(input_path) handle_grammar_warnings(grammar, input_path) build_automaton(grammar, input_path) end |
#automaton_from_ir_for_messages(input_path) ⇒ IR::Automaton
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/ibex/cli/error_messages.rb', line 88 def (input_path) report_status("reading #{input_path}") value = IR::Validator.validate(File.read(input_path)) expected = @options[:from] == "grammar-ir" ? IR::Grammar : IR::Automaton raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input" unless value.is_a?(expected) if value.is_a?(IR::Automaton) && @options[:messages_algorithm_explicit] raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with --from=automaton-ir" end grammar = if value.is_a?(IR::Grammar) value elsif value.is_a?(IR::Automaton) value.grammar else raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input" end handle_grammar_warnings(grammar, input_path) return build_automaton(value, input_path) if value.is_a?(IR::Grammar) if value.is_a?(IR::Automaton) prepare_loaded_automaton(value, input_path) return value end raise Ibex::Error, "#{input_path}:1:1: expected #{@options[:from]} input" end |
#error_message_search_limits ⇒ { max_tokens: Integer, max_configurations: Integer }
144 145 146 147 148 149 150 151 |
# File 'lib/ibex/cli/error_messages.rb', line 144 def { max_tokens: @options.fetch(:messages_max_tokens, ErrorMessages::SentenceSearch::DEFAULT_MAX_TOKENS), max_configurations: @options.fetch( :messages_max_configurations, ErrorMessages::SentenceSearch::DEFAULT_MAX_CONFIGURATIONS ) } end |
#error_messages_option_parser ⇒ OptionParser
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/ibex/cli/error_messages.rb', line 48 def OptionParser.new do || . = "Usage: ibex errors (--list | --update[=FILE]) [options] grammarfile" .on("--list", "list shortest error sentences on stdout") { @options[:messages_list] = true } .on("--update[=FILE]", "update messages (defaults to grammar.messages)") do |value| @options[:messages_update] = value || true end .on("--max-tokens=N", Integer, "maximum error-sentence token budget") do |value| @options[:messages_max_tokens] = (value, "--max-tokens") end .on("--max-configurations=N", Integer, "maximum error-sentence configuration budget") do |value| @options[:messages_max_configurations] = (value, "--max-configurations") end .on("--from=FORMAT", %w[grammar-ir automaton-ir], "resume from IR JSON") do |value| @options[:from] = value end .on("--mode=MODE", %w[default extended], "grammar mode") { |value| @options[:mode] = value.to_sym } .on("--algorithm=NAME", %w[slr lalr ielr lr1], "parser construction algorithm") do |value| @options[:algorithm] = value.to_sym @options[:messages_algorithm_explicit] = true end .on("--warnings=CATEGORIES", "all, error, all,error, or none") do |value| @options[:warnings] = warning_categories(value) end .on("-S", "--output-status", "show pipeline status") { @options[:status] = true } .on("--help", "show help") { @options[:help] = true } end end |
#messages_file_mode(path) ⇒ Integer
171 172 173 174 175 |
# File 'lib/ibex/cli/error_messages.rb', line 171 def (path) return File.stat(path).mode & 0o777 if File.exist?(path) 0o666 & ~File.umask end |
#positive_messages_limit(value, option) ⇒ Integer
154 155 156 157 158 |
# File 'lib/ibex/cli/error_messages.rb', line 154 def (value, option) return value if value.positive? raise Ibex::Error, "(cli):1:1: #{option} must be positive" end |
#run_error_messages_command(arguments) ⇒ Integer
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/ibex/cli/error_messages.rb', line 26 def (arguments) parser = remaining = parser.parse(arguments) return print_help(parser) if @options[:help] if @options[:messages_list] && @options[:messages_update] raise Ibex::Error, "(cli):1:1: errors command accepts only one of --list or --update" end unless @options[:messages_list] || @options[:messages_update] raise Ibex::Error, "(cli):1:1: errors command requires --list or --update[=FILE]" end input = input_path(remaining) automaton = (input) if @options[:messages_list] @stdout.write(ErrorMessages.render(automaton, **)) else (automaton, input) end 0 end |
#write_error_message_update_report(update) ⇒ void
This method returns an undefined value.
161 162 163 164 165 166 167 168 |
# File 'lib/ibex/cli/error_messages.rb', line 161 def (update) classifications = { "uncovered" => update.uncovered, "unreachable" => update.unreachable, "moved" => update.moved } classifications.each do |label, items| items.each { |item| @stdout.puts("#{label}: #{item}") } end end |
#write_error_messages(automaton, input_path) ⇒ void
This method returns an undefined value.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/ibex/cli/error_messages.rb', line 116 def (automaton, input_path) configured = @options[:messages_update] path = configured == true ? default_output_path(input_path, ".messages") : configured raise Ibex::Error, "(cli):1:1: messages update path must not be empty" unless path.is_a?(String) && !path.empty? if same_file_target?(path, input_path) raise Ibex::Error, "(cli):1:1: messages update path must differ from the input path" end existing = if File.exist?(path) ErrorMessages.load(path) else ErrorMessages::Document.new(entries: []) end update = ErrorMessages.update(automaton, existing: existing, **) target_path = File.symlink?(path) ? File.realpath(path) : path directory = File.dirname(File.(target_path)) Tempfile.create([".ibex-messages-", ".tmp"], directory, encoding: "UTF-8") do |file| file.write(update.source) File.chmod((target_path), file.path) file.flush file.fsync File.rename(file.path, target_path) end (update) report_status("wrote #{path}") end |