Module: Ibex::CLIAnalysis
- Defined in:
- lib/ibex/cli/analysis.rb,
sig/ibex/cli/analysis.rbs
Overview
CLI entry points for deterministic grammar diff and metrics reports.
Instance Method Summary collapse
- #algo_set?(settings) ⇒ Boolean
- #analysis_options(arguments, command, operands:) ⇒ Hash[Symbol, untyped]
- #build_analysis_automaton(grammar, algorithm, algorithm_explicit) ⇒ IR::Automaton
- #load_analysis_automaton(path, algorithm, explicit:) ⇒ IR::Automaton
- #run_diff_command(arguments) ⇒ Integer
- #run_metrics_command(arguments) ⇒ Integer
- #write_analysis_report(report, format) ⇒ void
Instance Method Details
#algo_set?(settings) ⇒ Boolean
125 126 127 |
# File 'lib/ibex/cli/analysis.rb', line 125 def algo_set?(settings) settings.fetch(:configuration_explicit).include?(:algorithm) end |
#analysis_options(arguments, command, operands:) ⇒ Hash[Symbol, untyped]
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/ibex/cli/analysis.rb', line 56 def (arguments, command, operands:) settings = { paths: [], algorithm: Configuration::Registry.fetch("parser.algorithm").default, mode: Configuration::Registry.fetch("grammar.mode").default, format: "json", configuration_explicit: [] } #: Hash[Symbol, untyped] parser = OptionParser.new do || . = "Usage: ibex #{command} [options] #{operands}" .on("--algorithm=NAME", %w[slr lalr ielr lr1], "algorithm for grammar inputs") do |value| set_local_configuration_option(settings, :algorithm, value.to_sym) end .on("--mode=MODE", %w[default extended], "grammar mode") do |value| set_local_configuration_option(settings, :mode, value.to_sym) set_configuration_option(:mode, value.to_sym) end .on("--format=FORMAT", %w[json text], "json or text") { |value| settings[:format] = value } .on("--help", "show help") { settings[:help] = .to_s } end settings[:paths] = parser.parse(arguments) settings[:algorithm] = local_configuration_value(settings, "parser.algorithm") settings end |
#build_analysis_automaton(grammar, algorithm, algorithm_explicit) ⇒ IR::Automaton
97 98 99 100 101 102 103 104 105 106 |
# File 'lib/ibex/cli/analysis.rb', line 97 def build_analysis_automaton(grammar, algorithm, algorithm_explicit) explicit_keys = algorithm_explicit ? [:algorithm] : [] #: Array[Symbol] active = activate_analysis_grammar( grammar, options: { algorithm: algorithm }, explicit_keys: explicit_keys ) LALR::Builder.new( active, algorithm: configuration_value("parser.algorithm"), entry_isolation: configuration_value("parser.entries") == :isolated ).build end |
#load_analysis_automaton(path, algorithm, explicit:) ⇒ IR::Automaton
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/ibex/cli/analysis.rb', line 79 def load_analysis_automaton(path, algorithm, explicit:) source = File.binread(path) if source.lstrip.start_with?("{") value = IR::Validator.validate(source) if value.is_a?(IR::Automaton) raise Ibex::Error, "(cli):1:1: --algorithm cannot be combined with Automaton IR analysis input" if explicit return value end return build_analysis_automaton(value, algorithm, explicit) if value.is_a?(IR::Grammar) raise Ibex::Error, "#{path}:1:1: analysis does not accept Lexer IR" end build_analysis_automaton(normalize_grammar_path(path), algorithm, explicit) end |
#run_diff_command(arguments) ⇒ Integer
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/ibex/cli/analysis.rb', line 22 def run_diff_command(arguments) settings = (arguments, "diff", operands: "OLD NEW") if settings[:help] @stdout.puts(settings.fetch(:help)) return 0 end paths = settings.fetch(:paths) raise Ibex::Error, "(diff):1:1: diff requires exactly two grammar or IR files" unless paths.length == 2 algorithm = settings.fetch(:algorithm) before = load_analysis_automaton(paths.fetch(0), algorithm, explicit: algo_set?(settings)) after = load_analysis_automaton(paths.fetch(1), algorithm, explicit: algo_set?(settings)) report = Diff.new(before, after).to_h write_analysis_report(report, settings.fetch(:format)) 0 end |
#run_metrics_command(arguments) ⇒ Integer
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/ibex/cli/analysis.rb', line 40 def run_metrics_command(arguments) settings = (arguments, "metrics", operands: "GRAMMAR") if settings[:help] @stdout.puts(settings.fetch(:help)) return 0 end paths = settings.fetch(:paths) raise Ibex::Error, "(metrics):1:1: metrics requires exactly one grammar or IR file" unless paths.length == 1 automaton = load_analysis_automaton(paths.fetch(0), settings.fetch(:algorithm), explicit: algo_set?(settings)) report = Metrics.new(automaton).to_h write_analysis_report(report, settings.fetch(:format)) 0 end |
#write_analysis_report(report, format) ⇒ void
This method returns an undefined value.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/ibex/cli/analysis.rb', line 109 def write_analysis_report(report, format) if format == "json" @stdout.puts(JSON.pretty_generate(report)) elsif report.fetch(:ibex_report) == "metrics" @stdout.puts("states=#{report.dig(:automaton, :states)} rules=#{report.dig(:grammar, :rules)} " \ "alternatives=#{report.dig(:grammar, :alternatives)}") else %i[symbols rules conflicts warnings].each do |section| values = report.fetch(section) @stdout.puts("#{section}: +#{values.fetch(:added).length} " \ "-#{values.fetch(:removed).length} ~#{values.fetch(:changed).length}") end end end |