Class: Ibex::RaccMigration::Checker
- Inherits:
-
Object
- Object
- Ibex::RaccMigration::Checker
- Defined in:
- lib/ibex/racc_migration/checker.rb,
sig/ibex/racc_migration/checker.rbs
Overview
Checks syntax, normalization, superclass, and runtime-coupling hazards. Semantic action code is treated as opaque data and never executed.
Constant Summary collapse
- RACC_REQUIRE =
%r{(?:require|require_relative)\s*\(?\s*["']racc(?:/parser)?["']}- RACC_CONSTANT =
/\bRacc::[A-Za-z_]\w*/
Instance Method Summary collapse
- #check(source, file:) ⇒ Report
- #error_location(message, fallback) ⇒ [ Frontend::Location, String ]
- #normalization_findings(ast) ⇒ Array[Finding]
- #sort_findings(findings) ⇒ Array[Finding]
- #superclass_findings(ast) ⇒ Array[Finding]
- #syntax_finding(diagnostic) ⇒ Finding
- #user_code_findings(ast) ⇒ Array[Finding]
Instance Method Details
#check(source, file:) ⇒ Report
13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/ibex/racc_migration/checker.rb', line 13 def check(source, file:) result = Frontend::Parser.new(source, file: file, mode: :default).parse_with_diagnostics findings = result.diagnostics.map { |diagnostic| syntax_finding(diagnostic) } ast = result.ast return Report.new(file: file, class_name: nil, findings: findings) unless ast findings.concat(superclass_findings(ast)) findings.concat(user_code_findings(ast)) findings.concat(normalization_findings(ast)) Report.new(file: file, class_name: ast.class_name, findings: sort_findings(findings)) end |
#error_location(message, fallback) ⇒ [ Frontend::Location, String ]
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ibex/racc_migration/checker.rb', line 98 def error_location(, fallback) match = .match(/\A(.+):(\d+):(\d+): (.*)\z/m) return [fallback, ] unless match [ Frontend::Location.new( file: match[1].to_s, line: Integer(match[2].to_s, 10), column: Integer(match[3].to_s, 10) ), match[4].to_s ] end |
#normalization_findings(ast) ⇒ Array[Finding]
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/ibex/racc_migration/checker.rb', line 81 def normalization_findings(ast) Normalizer.new(ast, mode: :default).normalize [] rescue Ibex::Error => e location, = error_location(e., ast.loc) [ Finding.new( code: "racc.normalization", severity: :error, message: , location: location, suggestion: "apply the diagnostic before generating either parser" ) ] end |
#sort_findings(findings) ⇒ Array[Finding]
113 114 115 116 117 118 119 |
# File 'lib/ibex/racc_migration/checker.rb', line 113 def sort_findings(findings) rank = { error: 0, warning: 1, info: 2 } findings.sort_by do |finding| location = finding.location [location&.file || "", location&.line || 0, location&.column || 0, rank.fetch(finding.severity), finding.code] end end |
#superclass_findings(ast) ⇒ Array[Finding]
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/ibex/racc_migration/checker.rb', line 40 def superclass_findings(ast) return [] unless ast.superclass&.start_with?("Racc::") [ Finding.new( code: "racc.runtime_superclass", severity: :error, message: "generated class inherits #{ast.superclass}", location: ast.loc, suggestion: "remove the explicit Racc superclass or generate with `--superclass=Ibex::Runtime::Parser`" ) ] end |
#syntax_finding(diagnostic) ⇒ Finding
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/ibex/racc_migration/checker.rb', line 28 def syntax_finding(diagnostic) Finding.new( code: "racc.syntax", severity: :error, message: diagnostic., location: diagnostic.location, suggestion: "keep the grammar in default mode, or adopt the reported extension explicitly " \ "with `pragma extended`" ) end |
#user_code_findings(ast) ⇒ Array[Finding]
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/ibex/racc_migration/checker.rb', line 55 def user_code_findings(ast) ast.user_code.values.flatten.flat_map do |chunk| findings = [] #: Array[Finding] if chunk.code.match?(RACC_REQUIRE) findings << Finding.new( code: "racc.runtime_require", severity: :warning, message: "user code requires the racc runtime", location: chunk.loc, suggestion: "remove this require after switching generated parsers to the Ibex runtime" ) end if chunk.code.match?(RACC_CONSTANT) findings << Finding.new( code: "racc.runtime_constant", severity: :warning, message: "user code references a Racc runtime constant", location: chunk.loc, suggestion: "replace the runtime-specific constant or keep an explicit compatibility adapter" ) end findings end end |